##// END OF EJS Templates
bisect: track the current changeset (issue3382)...
Bryan O'Sullivan -
r16647:14913fcb default
parent child Browse files
Show More
@@ -1,5726 +1,5748 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil, pvec
19 import random, setdiscovery, treediscovery, dagutil, pvec
20 import phases
20 import phases
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ] + templateopts
101 ] + templateopts
102
102
103 diffopts = [
103 diffopts = [
104 ('a', 'text', None, _('treat all files as text')),
104 ('a', 'text', None, _('treat all files as text')),
105 ('g', 'git', None, _('use git extended diff format')),
105 ('g', 'git', None, _('use git extended diff format')),
106 ('', 'nodates', None, _('omit dates from diff headers'))
106 ('', 'nodates', None, _('omit dates from diff headers'))
107 ]
107 ]
108
108
109 diffwsopts = [
109 diffwsopts = [
110 ('w', 'ignore-all-space', None,
110 ('w', 'ignore-all-space', None,
111 _('ignore white space when comparing lines')),
111 _('ignore white space when comparing lines')),
112 ('b', 'ignore-space-change', None,
112 ('b', 'ignore-space-change', None,
113 _('ignore changes in the amount of white space')),
113 _('ignore changes in the amount of white space')),
114 ('B', 'ignore-blank-lines', None,
114 ('B', 'ignore-blank-lines', None,
115 _('ignore changes whose lines are all blank')),
115 _('ignore changes whose lines are all blank')),
116 ]
116 ]
117
117
118 diffopts2 = [
118 diffopts2 = [
119 ('p', 'show-function', None, _('show which function each change is in')),
119 ('p', 'show-function', None, _('show which function each change is in')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ] + diffwsopts + [
121 ] + diffwsopts + [
122 ('U', 'unified', '',
122 ('U', 'unified', '',
123 _('number of lines of context to show'), _('NUM')),
123 _('number of lines of context to show'), _('NUM')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ]
125 ]
126
126
127 mergetoolopts = [
127 mergetoolopts = [
128 ('t', 'tool', '', _('specify merge tool')),
128 ('t', 'tool', '', _('specify merge tool')),
129 ]
129 ]
130
130
131 similarityopts = [
131 similarityopts = [
132 ('s', 'similarity', '',
132 ('s', 'similarity', '',
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 ]
134 ]
135
135
136 subrepoopts = [
136 subrepoopts = [
137 ('S', 'subrepos', None,
137 ('S', 'subrepos', None,
138 _('recurse into subrepositories'))
138 _('recurse into subrepositories'))
139 ]
139 ]
140
140
141 # Commands start here, listed alphabetically
141 # Commands start here, listed alphabetically
142
142
143 @command('^add',
143 @command('^add',
144 walkopts + subrepoopts + dryrunopts,
144 walkopts + subrepoopts + dryrunopts,
145 _('[OPTION]... [FILE]...'))
145 _('[OPTION]... [FILE]...'))
146 def add(ui, repo, *pats, **opts):
146 def add(ui, repo, *pats, **opts):
147 """add the specified files on the next commit
147 """add the specified files on the next commit
148
148
149 Schedule files to be version controlled and added to the
149 Schedule files to be version controlled and added to the
150 repository.
150 repository.
151
151
152 The files will be added to the repository at the next commit. To
152 The files will be added to the repository at the next commit. To
153 undo an add before that, see :hg:`forget`.
153 undo an add before that, see :hg:`forget`.
154
154
155 If no names are given, add all files to the repository.
155 If no names are given, add all files to the repository.
156
156
157 .. container:: verbose
157 .. container:: verbose
158
158
159 An example showing how new (unknown) files are added
159 An example showing how new (unknown) files are added
160 automatically by :hg:`add`::
160 automatically by :hg:`add`::
161
161
162 $ ls
162 $ ls
163 foo.c
163 foo.c
164 $ hg status
164 $ hg status
165 ? foo.c
165 ? foo.c
166 $ hg add
166 $ hg add
167 adding foo.c
167 adding foo.c
168 $ hg status
168 $ hg status
169 A foo.c
169 A foo.c
170
170
171 Returns 0 if all files are successfully added.
171 Returns 0 if all files are successfully added.
172 """
172 """
173
173
174 m = scmutil.match(repo[None], pats, opts)
174 m = scmutil.match(repo[None], pats, opts)
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 opts.get('subrepos'), prefix="", explicitonly=False)
176 opts.get('subrepos'), prefix="", explicitonly=False)
177 return rejected and 1 or 0
177 return rejected and 1 or 0
178
178
179 @command('addremove',
179 @command('addremove',
180 similarityopts + walkopts + dryrunopts,
180 similarityopts + walkopts + dryrunopts,
181 _('[OPTION]... [FILE]...'))
181 _('[OPTION]... [FILE]...'))
182 def addremove(ui, repo, *pats, **opts):
182 def addremove(ui, repo, *pats, **opts):
183 """add all new files, delete all missing files
183 """add all new files, delete all missing files
184
184
185 Add all new files and remove all missing files from the
185 Add all new files and remove all missing files from the
186 repository.
186 repository.
187
187
188 New files are ignored if they match any of the patterns in
188 New files are ignored if they match any of the patterns in
189 ``.hgignore``. As with add, these changes take effect at the next
189 ``.hgignore``. As with add, these changes take effect at the next
190 commit.
190 commit.
191
191
192 Use the -s/--similarity option to detect renamed files. With a
192 Use the -s/--similarity option to detect renamed files. With a
193 parameter greater than 0, this compares every removed file with
193 parameter greater than 0, this compares every removed file with
194 every added file and records those similar enough as renames. This
194 every added file and records those similar enough as renames. 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. Detecting renamed files this way
196 be identical) as its parameter. Detecting renamed files this way
197 can be expensive. After using this option, :hg:`status -C` can be
197 can be expensive. After using this option, :hg:`status -C` can be
198 used to check which files were identified as moved or renamed.
198 used to check which files were identified as moved or renamed.
199 If this option is not specified, only renames of identical files
199 If this option is not specified, only renames of identical files
200 are detected.
200 are detected.
201
201
202 Returns 0 if all files are successfully added.
202 Returns 0 if all files are successfully added.
203 """
203 """
204 try:
204 try:
205 sim = float(opts.get('similarity') or 100)
205 sim = float(opts.get('similarity') or 100)
206 except ValueError:
206 except ValueError:
207 raise util.Abort(_('similarity must be a number'))
207 raise util.Abort(_('similarity must be a number'))
208 if sim < 0 or sim > 100:
208 if sim < 0 or sim > 100:
209 raise util.Abort(_('similarity must be between 0 and 100'))
209 raise util.Abort(_('similarity must be between 0 and 100'))
210 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
210 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211
211
212 @command('^annotate|blame',
212 @command('^annotate|blame',
213 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
213 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 ('', 'follow', None,
214 ('', 'follow', None,
215 _('follow copies/renames and list the filename (DEPRECATED)')),
215 _('follow copies/renames and list the filename (DEPRECATED)')),
216 ('', 'no-follow', None, _("don't follow copies and renames")),
216 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('a', 'text', None, _('treat all files as text')),
217 ('a', 'text', None, _('treat all files as text')),
218 ('u', 'user', None, _('list the author (long with -v)')),
218 ('u', 'user', None, _('list the author (long with -v)')),
219 ('f', 'file', None, _('list the filename')),
219 ('f', 'file', None, _('list the filename')),
220 ('d', 'date', None, _('list the date (short with -q)')),
220 ('d', 'date', None, _('list the date (short with -q)')),
221 ('n', 'number', None, _('list the revision number (default)')),
221 ('n', 'number', None, _('list the revision number (default)')),
222 ('c', 'changeset', None, _('list the changeset')),
222 ('c', 'changeset', None, _('list the changeset')),
223 ('l', 'line-number', None, _('show line number at the first appearance'))
223 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ] + diffwsopts + walkopts,
224 ] + diffwsopts + walkopts,
225 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
225 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 def annotate(ui, repo, *pats, **opts):
226 def annotate(ui, repo, *pats, **opts):
227 """show changeset information by line for each file
227 """show changeset information by line for each file
228
228
229 List changes in files, showing the revision id responsible for
229 List changes in files, showing the revision id responsible for
230 each line
230 each line
231
231
232 This command is useful for discovering when a change was made and
232 This command is useful for discovering when a change was made and
233 by whom.
233 by whom.
234
234
235 Without the -a/--text option, annotate will avoid processing files
235 Without the -a/--text option, annotate will avoid processing files
236 it detects as binary. With -a, annotate will annotate the file
236 it detects as binary. With -a, annotate will annotate the file
237 anyway, although the results will probably be neither useful
237 anyway, although the results will probably be neither useful
238 nor desirable.
238 nor desirable.
239
239
240 Returns 0 on success.
240 Returns 0 on success.
241 """
241 """
242 if opts.get('follow'):
242 if opts.get('follow'):
243 # --follow is deprecated and now just an alias for -f/--file
243 # --follow is deprecated and now just an alias for -f/--file
244 # to mimic the behavior of Mercurial before version 1.5
244 # to mimic the behavior of Mercurial before version 1.5
245 opts['file'] = True
245 opts['file'] = True
246
246
247 datefunc = ui.quiet and util.shortdate or util.datestr
247 datefunc = ui.quiet and util.shortdate or util.datestr
248 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
248 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249
249
250 if not pats:
250 if not pats:
251 raise util.Abort(_('at least one filename or pattern is required'))
251 raise util.Abort(_('at least one filename or pattern is required'))
252
252
253 hexfn = ui.debugflag and hex or short
253 hexfn = ui.debugflag and hex or short
254
254
255 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
255 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 ('number', ' ', lambda x: str(x[0].rev())),
256 ('number', ' ', lambda x: str(x[0].rev())),
257 ('changeset', ' ', lambda x: hexfn(x[0].node())),
257 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('date', ' ', getdate),
258 ('date', ' ', getdate),
259 ('file', ' ', lambda x: x[0].path()),
259 ('file', ' ', lambda x: x[0].path()),
260 ('line_number', ':', lambda x: str(x[1])),
260 ('line_number', ':', lambda x: str(x[1])),
261 ]
261 ]
262
262
263 if (not opts.get('user') and not opts.get('changeset')
263 if (not opts.get('user') and not opts.get('changeset')
264 and not opts.get('date') and not opts.get('file')):
264 and not opts.get('date') and not opts.get('file')):
265 opts['number'] = True
265 opts['number'] = True
266
266
267 linenumber = opts.get('line_number') is not None
267 linenumber = opts.get('line_number') is not None
268 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
268 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 raise util.Abort(_('at least one of -n/-c is required for -l'))
269 raise util.Abort(_('at least one of -n/-c is required for -l'))
270
270
271 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
271 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
272 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273
273
274 def bad(x, y):
274 def bad(x, y):
275 raise util.Abort("%s: %s" % (x, y))
275 raise util.Abort("%s: %s" % (x, y))
276
276
277 ctx = scmutil.revsingle(repo, opts.get('rev'))
277 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 m = scmutil.match(ctx, pats, opts)
278 m = scmutil.match(ctx, pats, opts)
279 m.bad = bad
279 m.bad = bad
280 follow = not opts.get('no_follow')
280 follow = not opts.get('no_follow')
281 diffopts = patch.diffopts(ui, opts, section='annotate')
281 diffopts = patch.diffopts(ui, opts, section='annotate')
282 for abs in ctx.walk(m):
282 for abs in ctx.walk(m):
283 fctx = ctx[abs]
283 fctx = ctx[abs]
284 if not opts.get('text') and util.binary(fctx.data()):
284 if not opts.get('text') and util.binary(fctx.data()):
285 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
285 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 continue
286 continue
287
287
288 lines = fctx.annotate(follow=follow, linenumber=linenumber,
288 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 diffopts=diffopts)
289 diffopts=diffopts)
290 pieces = []
290 pieces = []
291
291
292 for f, sep in funcmap:
292 for f, sep in funcmap:
293 l = [f(n) for n, dummy in lines]
293 l = [f(n) for n, dummy in lines]
294 if l:
294 if l:
295 sized = [(x, encoding.colwidth(x)) for x in l]
295 sized = [(x, encoding.colwidth(x)) for x in l]
296 ml = max([w for x, w in sized])
296 ml = max([w for x, w in sized])
297 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
297 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 for x, w in sized])
298 for x, w in sized])
299
299
300 if pieces:
300 if pieces:
301 for p, l in zip(zip(*pieces), lines):
301 for p, l in zip(zip(*pieces), lines):
302 ui.write("%s: %s" % ("".join(p), l[1]))
302 ui.write("%s: %s" % ("".join(p), l[1]))
303
303
304 if lines and not lines[-1][1].endswith('\n'):
304 if lines and not lines[-1][1].endswith('\n'):
305 ui.write('\n')
305 ui.write('\n')
306
306
307 @command('archive',
307 @command('archive',
308 [('', 'no-decode', None, _('do not pass files through decoders')),
308 [('', 'no-decode', None, _('do not pass files through decoders')),
309 ('p', 'prefix', '', _('directory prefix for files in archive'),
309 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 _('PREFIX')),
310 _('PREFIX')),
311 ('r', 'rev', '', _('revision to distribute'), _('REV')),
311 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
312 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ] + subrepoopts + walkopts,
313 ] + subrepoopts + walkopts,
314 _('[OPTION]... DEST'))
314 _('[OPTION]... DEST'))
315 def archive(ui, repo, dest, **opts):
315 def archive(ui, repo, dest, **opts):
316 '''create an unversioned archive of a repository revision
316 '''create an unversioned archive of a repository revision
317
317
318 By default, the revision used is the parent of the working
318 By default, the revision used is the parent of the working
319 directory; use -r/--rev to specify a different revision.
319 directory; use -r/--rev to specify a different revision.
320
320
321 The archive type is automatically detected based on file
321 The archive type is automatically detected based on file
322 extension (or override using -t/--type).
322 extension (or override using -t/--type).
323
323
324 .. container:: verbose
324 .. container:: verbose
325
325
326 Examples:
326 Examples:
327
327
328 - create a zip file containing the 1.0 release::
328 - create a zip file containing the 1.0 release::
329
329
330 hg archive -r 1.0 project-1.0.zip
330 hg archive -r 1.0 project-1.0.zip
331
331
332 - create a tarball excluding .hg files::
332 - create a tarball excluding .hg files::
333
333
334 hg archive project.tar.gz -X ".hg*"
334 hg archive project.tar.gz -X ".hg*"
335
335
336 Valid types are:
336 Valid types are:
337
337
338 :``files``: a directory full of files (default)
338 :``files``: a directory full of files (default)
339 :``tar``: tar archive, uncompressed
339 :``tar``: tar archive, uncompressed
340 :``tbz2``: tar archive, compressed using bzip2
340 :``tbz2``: tar archive, compressed using bzip2
341 :``tgz``: tar archive, compressed using gzip
341 :``tgz``: tar archive, compressed using gzip
342 :``uzip``: zip archive, uncompressed
342 :``uzip``: zip archive, uncompressed
343 :``zip``: zip archive, compressed using deflate
343 :``zip``: zip archive, compressed using deflate
344
344
345 The exact name of the destination archive or directory is given
345 The exact name of the destination archive or directory is given
346 using a format string; see :hg:`help export` for details.
346 using a format string; see :hg:`help export` for details.
347
347
348 Each member added to an archive file has a directory prefix
348 Each member added to an archive file has a directory prefix
349 prepended. Use -p/--prefix to specify a format string for the
349 prepended. Use -p/--prefix to specify a format string for the
350 prefix. The default is the basename of the archive, with suffixes
350 prefix. The default is the basename of the archive, with suffixes
351 removed.
351 removed.
352
352
353 Returns 0 on success.
353 Returns 0 on success.
354 '''
354 '''
355
355
356 ctx = scmutil.revsingle(repo, opts.get('rev'))
356 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 if not ctx:
357 if not ctx:
358 raise util.Abort(_('no working directory: please specify a revision'))
358 raise util.Abort(_('no working directory: please specify a revision'))
359 node = ctx.node()
359 node = ctx.node()
360 dest = cmdutil.makefilename(repo, dest, node)
360 dest = cmdutil.makefilename(repo, dest, node)
361 if os.path.realpath(dest) == repo.root:
361 if os.path.realpath(dest) == repo.root:
362 raise util.Abort(_('repository root cannot be destination'))
362 raise util.Abort(_('repository root cannot be destination'))
363
363
364 kind = opts.get('type') or archival.guesskind(dest) or 'files'
364 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 prefix = opts.get('prefix')
365 prefix = opts.get('prefix')
366
366
367 if dest == '-':
367 if dest == '-':
368 if kind == 'files':
368 if kind == 'files':
369 raise util.Abort(_('cannot archive plain files to stdout'))
369 raise util.Abort(_('cannot archive plain files to stdout'))
370 dest = cmdutil.makefileobj(repo, dest)
370 dest = cmdutil.makefileobj(repo, dest)
371 if not prefix:
371 if not prefix:
372 prefix = os.path.basename(repo.root) + '-%h'
372 prefix = os.path.basename(repo.root) + '-%h'
373
373
374 prefix = cmdutil.makefilename(repo, prefix, node)
374 prefix = cmdutil.makefilename(repo, prefix, node)
375 matchfn = scmutil.match(ctx, [], opts)
375 matchfn = scmutil.match(ctx, [], opts)
376 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
376 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 matchfn, prefix, subrepos=opts.get('subrepos'))
377 matchfn, prefix, subrepos=opts.get('subrepos'))
378
378
379 @command('backout',
379 @command('backout',
380 [('', 'merge', None, _('merge with old dirstate parent after backout')),
380 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 ('', 'parent', '',
381 ('', 'parent', '',
382 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
382 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 ('r', 'rev', '', _('revision to backout'), _('REV')),
383 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ] + mergetoolopts + walkopts + commitopts + commitopts2,
384 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 _('[OPTION]... [-r] REV'))
385 _('[OPTION]... [-r] REV'))
386 def backout(ui, repo, node=None, rev=None, **opts):
386 def backout(ui, repo, node=None, rev=None, **opts):
387 '''reverse effect of earlier changeset
387 '''reverse effect of earlier changeset
388
388
389 Prepare a new changeset with the effect of REV undone in the
389 Prepare a new changeset with the effect of REV undone in the
390 current working directory.
390 current working directory.
391
391
392 If REV is the parent of the working directory, then this new changeset
392 If REV is the parent of the working directory, then this new changeset
393 is committed automatically. Otherwise, hg needs to merge the
393 is committed automatically. Otherwise, hg needs to merge the
394 changes and the merged result is left uncommitted.
394 changes and the merged result is left uncommitted.
395
395
396 .. note::
396 .. note::
397 backout cannot be used to fix either an unwanted or
397 backout cannot be used to fix either an unwanted or
398 incorrect merge.
398 incorrect merge.
399
399
400 .. container:: verbose
400 .. container:: verbose
401
401
402 By default, the pending changeset will have one parent,
402 By default, the pending changeset will have one parent,
403 maintaining a linear history. With --merge, the pending
403 maintaining a linear history. With --merge, the pending
404 changeset will instead have two parents: the old parent of the
404 changeset will instead have two parents: the old parent of the
405 working directory and a new child of REV that simply undoes REV.
405 working directory and a new child of REV that simply undoes REV.
406
406
407 Before version 1.7, the behavior without --merge was equivalent
407 Before version 1.7, the behavior without --merge was equivalent
408 to specifying --merge followed by :hg:`update --clean .` to
408 to specifying --merge followed by :hg:`update --clean .` to
409 cancel the merge and leave the child of REV as a head to be
409 cancel the merge and leave the child of REV as a head to be
410 merged separately.
410 merged separately.
411
411
412 See :hg:`help dates` for a list of formats valid for -d/--date.
412 See :hg:`help dates` for a list of formats valid for -d/--date.
413
413
414 Returns 0 on success.
414 Returns 0 on success.
415 '''
415 '''
416 if rev and node:
416 if rev and node:
417 raise util.Abort(_("please specify just one revision"))
417 raise util.Abort(_("please specify just one revision"))
418
418
419 if not rev:
419 if not rev:
420 rev = node
420 rev = node
421
421
422 if not rev:
422 if not rev:
423 raise util.Abort(_("please specify a revision to backout"))
423 raise util.Abort(_("please specify a revision to backout"))
424
424
425 date = opts.get('date')
425 date = opts.get('date')
426 if date:
426 if date:
427 opts['date'] = util.parsedate(date)
427 opts['date'] = util.parsedate(date)
428
428
429 cmdutil.bailifchanged(repo)
429 cmdutil.bailifchanged(repo)
430 node = scmutil.revsingle(repo, rev).node()
430 node = scmutil.revsingle(repo, rev).node()
431
431
432 op1, op2 = repo.dirstate.parents()
432 op1, op2 = repo.dirstate.parents()
433 a = repo.changelog.ancestor(op1, node)
433 a = repo.changelog.ancestor(op1, node)
434 if a != node:
434 if a != node:
435 raise util.Abort(_('cannot backout change on a different branch'))
435 raise util.Abort(_('cannot backout change on a different branch'))
436
436
437 p1, p2 = repo.changelog.parents(node)
437 p1, p2 = repo.changelog.parents(node)
438 if p1 == nullid:
438 if p1 == nullid:
439 raise util.Abort(_('cannot backout a change with no parents'))
439 raise util.Abort(_('cannot backout a change with no parents'))
440 if p2 != nullid:
440 if p2 != nullid:
441 if not opts.get('parent'):
441 if not opts.get('parent'):
442 raise util.Abort(_('cannot backout a merge changeset'))
442 raise util.Abort(_('cannot backout a merge changeset'))
443 p = repo.lookup(opts['parent'])
443 p = repo.lookup(opts['parent'])
444 if p not in (p1, p2):
444 if p not in (p1, p2):
445 raise util.Abort(_('%s is not a parent of %s') %
445 raise util.Abort(_('%s is not a parent of %s') %
446 (short(p), short(node)))
446 (short(p), short(node)))
447 parent = p
447 parent = p
448 else:
448 else:
449 if opts.get('parent'):
449 if opts.get('parent'):
450 raise util.Abort(_('cannot use --parent on non-merge changeset'))
450 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 parent = p1
451 parent = p1
452
452
453 # the backout should appear on the same branch
453 # the backout should appear on the same branch
454 wlock = repo.wlock()
454 wlock = repo.wlock()
455 try:
455 try:
456 branch = repo.dirstate.branch()
456 branch = repo.dirstate.branch()
457 hg.clean(repo, node, show_stats=False)
457 hg.clean(repo, node, show_stats=False)
458 repo.dirstate.setbranch(branch)
458 repo.dirstate.setbranch(branch)
459 revert_opts = opts.copy()
459 revert_opts = opts.copy()
460 revert_opts['date'] = None
460 revert_opts['date'] = None
461 revert_opts['all'] = True
461 revert_opts['all'] = True
462 revert_opts['rev'] = hex(parent)
462 revert_opts['rev'] = hex(parent)
463 revert_opts['no_backup'] = None
463 revert_opts['no_backup'] = None
464 revert(ui, repo, **revert_opts)
464 revert(ui, repo, **revert_opts)
465 if not opts.get('merge') and op1 != node:
465 if not opts.get('merge') and op1 != node:
466 try:
466 try:
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 return hg.update(repo, op1)
468 return hg.update(repo, op1)
469 finally:
469 finally:
470 ui.setconfig('ui', 'forcemerge', '')
470 ui.setconfig('ui', 'forcemerge', '')
471
471
472 commit_opts = opts.copy()
472 commit_opts = opts.copy()
473 commit_opts['addremove'] = False
473 commit_opts['addremove'] = False
474 if not commit_opts['message'] and not commit_opts['logfile']:
474 if not commit_opts['message'] and not commit_opts['logfile']:
475 # we don't translate commit messages
475 # we don't translate commit messages
476 commit_opts['message'] = "Backed out changeset %s" % short(node)
476 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['force_editor'] = True
477 commit_opts['force_editor'] = True
478 commit(ui, repo, **commit_opts)
478 commit(ui, repo, **commit_opts)
479 def nice(node):
479 def nice(node):
480 return '%d:%s' % (repo.changelog.rev(node), short(node))
480 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 ui.status(_('changeset %s backs out changeset %s\n') %
481 ui.status(_('changeset %s backs out changeset %s\n') %
482 (nice(repo.changelog.tip()), nice(node)))
482 (nice(repo.changelog.tip()), nice(node)))
483 if opts.get('merge') and op1 != node:
483 if opts.get('merge') and op1 != node:
484 hg.clean(repo, op1, show_stats=False)
484 hg.clean(repo, op1, show_stats=False)
485 ui.status(_('merging with changeset %s\n')
485 ui.status(_('merging with changeset %s\n')
486 % nice(repo.changelog.tip()))
486 % nice(repo.changelog.tip()))
487 try:
487 try:
488 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
488 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 return hg.merge(repo, hex(repo.changelog.tip()))
489 return hg.merge(repo, hex(repo.changelog.tip()))
490 finally:
490 finally:
491 ui.setconfig('ui', 'forcemerge', '')
491 ui.setconfig('ui', 'forcemerge', '')
492 finally:
492 finally:
493 wlock.release()
493 wlock.release()
494 return 0
494 return 0
495
495
496 @command('bisect',
496 @command('bisect',
497 [('r', 'reset', False, _('reset bisect state')),
497 [('r', 'reset', False, _('reset bisect state')),
498 ('g', 'good', False, _('mark changeset good')),
498 ('g', 'good', False, _('mark changeset good')),
499 ('b', 'bad', False, _('mark changeset bad')),
499 ('b', 'bad', False, _('mark changeset bad')),
500 ('s', 'skip', False, _('skip testing changeset')),
500 ('s', 'skip', False, _('skip testing changeset')),
501 ('e', 'extend', False, _('extend the bisect range')),
501 ('e', 'extend', False, _('extend the bisect range')),
502 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
502 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('U', 'noupdate', False, _('do not update to target'))],
503 ('U', 'noupdate', False, _('do not update to target'))],
504 _("[-gbsr] [-U] [-c CMD] [REV]"))
504 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 def bisect(ui, repo, rev=None, extra=None, command=None,
505 def bisect(ui, repo, rev=None, extra=None, command=None,
506 reset=None, good=None, bad=None, skip=None, extend=None,
506 reset=None, good=None, bad=None, skip=None, extend=None,
507 noupdate=None):
507 noupdate=None):
508 """subdivision search of changesets
508 """subdivision search of changesets
509
509
510 This command helps to find changesets which introduce problems. To
510 This command helps to find changesets which introduce problems. To
511 use, mark the earliest changeset you know exhibits the problem as
511 use, mark the earliest changeset you know exhibits the problem as
512 bad, then mark the latest changeset which is free from the problem
512 bad, then mark the latest changeset which is free from the problem
513 as good. Bisect will update your working directory to a revision
513 as good. Bisect will update your working directory to a revision
514 for testing (unless the -U/--noupdate option is specified). Once
514 for testing (unless the -U/--noupdate option is specified). Once
515 you have performed tests, mark the working directory as good or
515 you have performed tests, mark the working directory as good or
516 bad, and bisect will either update to another candidate changeset
516 bad, and bisect will either update to another candidate changeset
517 or announce that it has found the bad revision.
517 or announce that it has found the bad revision.
518
518
519 As a shortcut, you can also use the revision argument to mark a
519 As a shortcut, you can also use the revision argument to mark a
520 revision as good or bad without checking it out first.
520 revision as good or bad without checking it out first.
521
521
522 If you supply a command, it will be used for automatic bisection.
522 If you supply a command, it will be used for automatic bisection.
523 Its exit status will be used to mark revisions as good or bad:
523 Its exit status will be used to mark revisions as good or bad:
524 status 0 means good, 125 means to skip the revision, 127
524 status 0 means good, 125 means to skip the revision, 127
525 (command not found) will abort the bisection, and any other
525 (command not found) will abort the bisection, and any other
526 non-zero exit status means the revision is bad.
526 non-zero exit status means the revision is bad.
527
527
528 .. container:: verbose
528 .. container:: verbose
529
529
530 Some examples:
530 Some examples:
531
531
532 - start a bisection with known bad revision 12, and good revision 34::
532 - start a bisection with known bad revision 12, and good revision 34::
533
533
534 hg bisect --bad 34
534 hg bisect --bad 34
535 hg bisect --good 12
535 hg bisect --good 12
536
536
537 - advance the current bisection by marking current revision as good or
537 - advance the current bisection by marking current revision as good or
538 bad::
538 bad::
539
539
540 hg bisect --good
540 hg bisect --good
541 hg bisect --bad
541 hg bisect --bad
542
542
543 - mark the current revision, or a known revision, to be skipped (eg. if
543 - mark the current revision, or a known revision, to be skipped (eg. if
544 that revision is not usable because of another issue)::
544 that revision is not usable because of another issue)::
545
545
546 hg bisect --skip
546 hg bisect --skip
547 hg bisect --skip 23
547 hg bisect --skip 23
548
548
549 - forget the current bisection::
549 - forget the current bisection::
550
550
551 hg bisect --reset
551 hg bisect --reset
552
552
553 - use 'make && make tests' to automatically find the first broken
553 - use 'make && make tests' to automatically find the first broken
554 revision::
554 revision::
555
555
556 hg bisect --reset
556 hg bisect --reset
557 hg bisect --bad 34
557 hg bisect --bad 34
558 hg bisect --good 12
558 hg bisect --good 12
559 hg bisect --command 'make && make tests'
559 hg bisect --command 'make && make tests'
560
560
561 - see all changesets whose states are already known in the current
561 - see all changesets whose states are already known in the current
562 bisection::
562 bisection::
563
563
564 hg log -r "bisect(pruned)"
564 hg log -r "bisect(pruned)"
565
565
566 - see the changeset currently being bisected (especially useful
567 if running with -U/--noupdate)::
568
569 hg log -r "bisect(current)"
570
566 - see all changesets that took part in the current bisection::
571 - see all changesets that took part in the current bisection::
567
572
568 hg log -r "bisect(range)"
573 hg log -r "bisect(range)"
569
574
570 - with the graphlog extension, you can even get a nice graph::
575 - with the graphlog extension, you can even get a nice graph::
571
576
572 hg log --graph -r "bisect(range)"
577 hg log --graph -r "bisect(range)"
573
578
574 See :hg:`help revsets` for more about the `bisect()` keyword.
579 See :hg:`help revsets` for more about the `bisect()` keyword.
575
580
576 Returns 0 on success.
581 Returns 0 on success.
577 """
582 """
578 def extendbisectrange(nodes, good):
583 def extendbisectrange(nodes, good):
579 # bisect is incomplete when it ends on a merge node and
584 # bisect is incomplete when it ends on a merge node and
580 # one of the parent was not checked.
585 # one of the parent was not checked.
581 parents = repo[nodes[0]].parents()
586 parents = repo[nodes[0]].parents()
582 if len(parents) > 1:
587 if len(parents) > 1:
583 side = good and state['bad'] or state['good']
588 side = good and state['bad'] or state['good']
584 num = len(set(i.node() for i in parents) & set(side))
589 num = len(set(i.node() for i in parents) & set(side))
585 if num == 1:
590 if num == 1:
586 return parents[0].ancestor(parents[1])
591 return parents[0].ancestor(parents[1])
587 return None
592 return None
588
593
589 def print_result(nodes, good):
594 def print_result(nodes, good):
590 displayer = cmdutil.show_changeset(ui, repo, {})
595 displayer = cmdutil.show_changeset(ui, repo, {})
591 if len(nodes) == 1:
596 if len(nodes) == 1:
592 # narrowed it down to a single revision
597 # narrowed it down to a single revision
593 if good:
598 if good:
594 ui.write(_("The first good revision is:\n"))
599 ui.write(_("The first good revision is:\n"))
595 else:
600 else:
596 ui.write(_("The first bad revision is:\n"))
601 ui.write(_("The first bad revision is:\n"))
597 displayer.show(repo[nodes[0]])
602 displayer.show(repo[nodes[0]])
598 extendnode = extendbisectrange(nodes, good)
603 extendnode = extendbisectrange(nodes, good)
599 if extendnode is not None:
604 if extendnode is not None:
600 ui.write(_('Not all ancestors of this changeset have been'
605 ui.write(_('Not all ancestors of this changeset have been'
601 ' checked.\nUse bisect --extend to continue the '
606 ' checked.\nUse bisect --extend to continue the '
602 'bisection from\nthe common ancestor, %s.\n')
607 'bisection from\nthe common ancestor, %s.\n')
603 % extendnode)
608 % extendnode)
604 else:
609 else:
605 # multiple possible revisions
610 # multiple possible revisions
606 if good:
611 if good:
607 ui.write(_("Due to skipped revisions, the first "
612 ui.write(_("Due to skipped revisions, the first "
608 "good revision could be any of:\n"))
613 "good revision could be any of:\n"))
609 else:
614 else:
610 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
611 "bad revision could be any of:\n"))
616 "bad revision could be any of:\n"))
612 for n in nodes:
617 for n in nodes:
613 displayer.show(repo[n])
618 displayer.show(repo[n])
614 displayer.close()
619 displayer.close()
615
620
616 def check_state(state, interactive=True):
621 def check_state(state, interactive=True):
617 if not state['good'] or not state['bad']:
622 if not state['good'] or not state['bad']:
618 if (good or bad or skip or reset) and interactive:
623 if (good or bad or skip or reset) and interactive:
619 return
624 return
620 if not state['good']:
625 if not state['good']:
621 raise util.Abort(_('cannot bisect (no known good revisions)'))
626 raise util.Abort(_('cannot bisect (no known good revisions)'))
622 else:
627 else:
623 raise util.Abort(_('cannot bisect (no known bad revisions)'))
628 raise util.Abort(_('cannot bisect (no known bad revisions)'))
624 return True
629 return True
625
630
626 # backward compatibility
631 # backward compatibility
627 if rev in "good bad reset init".split():
632 if rev in "good bad reset init".split():
628 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
633 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
629 cmd, rev, extra = rev, extra, None
634 cmd, rev, extra = rev, extra, None
630 if cmd == "good":
635 if cmd == "good":
631 good = True
636 good = True
632 elif cmd == "bad":
637 elif cmd == "bad":
633 bad = True
638 bad = True
634 else:
639 else:
635 reset = True
640 reset = True
636 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
641 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
637 raise util.Abort(_('incompatible arguments'))
642 raise util.Abort(_('incompatible arguments'))
638
643
639 if reset:
644 if reset:
640 p = repo.join("bisect.state")
645 p = repo.join("bisect.state")
641 if os.path.exists(p):
646 if os.path.exists(p):
642 os.unlink(p)
647 os.unlink(p)
643 return
648 return
644
649
645 state = hbisect.load_state(repo)
650 state = hbisect.load_state(repo)
646
651
647 if command:
652 if command:
648 changesets = 1
653 changesets = 1
649 try:
654 try:
655 node = state['current'][0]
656 except LookupError:
657 if noupdate:
658 raise util.Abort(_('current bisect revision is unknown - '
659 'start a new bisect to fix'))
660 node, p2 = repo.dirstate.parents()
661 if p2 != nullid:
662 raise util.Abort(_('current bisect revision is a merge'))
663 try:
650 while changesets:
664 while changesets:
651 # update state
665 # update state
666 state['current'] = [node]
652 hbisect.save_state(repo, state)
667 hbisect.save_state(repo, state)
653 status = util.system(command, out=ui.fout)
668 status = util.system(command, out=ui.fout)
654 if status == 125:
669 if status == 125:
655 transition = "skip"
670 transition = "skip"
656 elif status == 0:
671 elif status == 0:
657 transition = "good"
672 transition = "good"
658 # status < 0 means process was killed
673 # status < 0 means process was killed
659 elif status == 127:
674 elif status == 127:
660 raise util.Abort(_("failed to execute %s") % command)
675 raise util.Abort(_("failed to execute %s") % command)
661 elif status < 0:
676 elif status < 0:
662 raise util.Abort(_("%s killed") % command)
677 raise util.Abort(_("%s killed") % command)
663 else:
678 else:
664 transition = "bad"
679 transition = "bad"
665 ctx = scmutil.revsingle(repo, rev)
680 ctx = scmutil.revsingle(repo, rev, node)
666 rev = None # clear for future iterations
681 rev = None # clear for future iterations
667 state[transition].append(ctx.node())
682 state[transition].append(ctx.node())
668 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
683 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
669 check_state(state, interactive=False)
684 check_state(state, interactive=False)
670 # bisect
685 # bisect
671 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
686 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
672 # update to next check
687 # update to next check
688 node = nodes[0]
689 if not noupdate:
673 cmdutil.bailifchanged(repo)
690 cmdutil.bailifchanged(repo)
674 hg.clean(repo, nodes[0], show_stats=False)
691 hg.clean(repo, node, show_stats=False)
675 finally:
692 finally:
693 state['current'] = [node]
676 hbisect.save_state(repo, state)
694 hbisect.save_state(repo, state)
677 print_result(nodes, good)
695 print_result(nodes, good)
678 return
696 return
679
697
680 # update state
698 # update state
681
699
682 if rev:
700 if rev:
683 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
701 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
684 else:
702 else:
685 nodes = [repo.lookup('.')]
703 nodes = [repo.lookup('.')]
686
704
687 if good or bad or skip:
705 if good or bad or skip:
688 if good:
706 if good:
689 state['good'] += nodes
707 state['good'] += nodes
690 elif bad:
708 elif bad:
691 state['bad'] += nodes
709 state['bad'] += nodes
692 elif skip:
710 elif skip:
693 state['skip'] += nodes
711 state['skip'] += nodes
694 hbisect.save_state(repo, state)
712 hbisect.save_state(repo, state)
695
713
696 if not check_state(state):
714 if not check_state(state):
697 return
715 return
698
716
699 # actually bisect
717 # actually bisect
700 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
718 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
701 if extend:
719 if extend:
702 if not changesets:
720 if not changesets:
703 extendnode = extendbisectrange(nodes, good)
721 extendnode = extendbisectrange(nodes, good)
704 if extendnode is not None:
722 if extendnode is not None:
705 ui.write(_("Extending search to changeset %d:%s\n"
723 ui.write(_("Extending search to changeset %d:%s\n"
706 % (extendnode.rev(), extendnode)))
724 % (extendnode.rev(), extendnode)))
725 state['current'] = [extendnode.node()]
726 hbisect.save_state(repo, state)
707 if noupdate:
727 if noupdate:
708 return
728 return
709 cmdutil.bailifchanged(repo)
729 cmdutil.bailifchanged(repo)
710 return hg.clean(repo, extendnode.node())
730 return hg.clean(repo, extendnode.node())
711 raise util.Abort(_("nothing to extend"))
731 raise util.Abort(_("nothing to extend"))
712
732
713 if changesets == 0:
733 if changesets == 0:
714 print_result(nodes, good)
734 print_result(nodes, good)
715 else:
735 else:
716 assert len(nodes) == 1 # only a single node can be tested next
736 assert len(nodes) == 1 # only a single node can be tested next
717 node = nodes[0]
737 node = nodes[0]
718 # compute the approximate number of remaining tests
738 # compute the approximate number of remaining tests
719 tests, size = 0, 2
739 tests, size = 0, 2
720 while size <= changesets:
740 while size <= changesets:
721 tests, size = tests + 1, size * 2
741 tests, size = tests + 1, size * 2
722 rev = repo.changelog.rev(node)
742 rev = repo.changelog.rev(node)
723 ui.write(_("Testing changeset %d:%s "
743 ui.write(_("Testing changeset %d:%s "
724 "(%d changesets remaining, ~%d tests)\n")
744 "(%d changesets remaining, ~%d tests)\n")
725 % (rev, short(node), changesets, tests))
745 % (rev, short(node), changesets, tests))
746 state['current'] = [node]
747 hbisect.save_state(repo, state)
726 if not noupdate:
748 if not noupdate:
727 cmdutil.bailifchanged(repo)
749 cmdutil.bailifchanged(repo)
728 return hg.clean(repo, node)
750 return hg.clean(repo, node)
729
751
730 @command('bookmarks',
752 @command('bookmarks',
731 [('f', 'force', False, _('force')),
753 [('f', 'force', False, _('force')),
732 ('r', 'rev', '', _('revision'), _('REV')),
754 ('r', 'rev', '', _('revision'), _('REV')),
733 ('d', 'delete', False, _('delete a given bookmark')),
755 ('d', 'delete', False, _('delete a given bookmark')),
734 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
756 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
735 ('i', 'inactive', False, _('mark a bookmark inactive'))],
757 ('i', 'inactive', False, _('mark a bookmark inactive'))],
736 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
758 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
737 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
759 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
738 rename=None, inactive=False):
760 rename=None, inactive=False):
739 '''track a line of development with movable markers
761 '''track a line of development with movable markers
740
762
741 Bookmarks are pointers to certain commits that move when committing.
763 Bookmarks are pointers to certain commits that move when committing.
742 Bookmarks are local. They can be renamed, copied and deleted. It is
764 Bookmarks are local. They can be renamed, copied and deleted. It is
743 possible to use :hg:`merge NAME` to merge from a given bookmark, and
765 possible to use :hg:`merge NAME` to merge from a given bookmark, and
744 :hg:`update NAME` to update to a given bookmark.
766 :hg:`update NAME` to update to a given bookmark.
745
767
746 You can use :hg:`bookmark NAME` to set a bookmark on the working
768 You can use :hg:`bookmark NAME` to set a bookmark on the working
747 directory's parent revision with the given name. If you specify
769 directory's parent revision with the given name. If you specify
748 a revision using -r REV (where REV may be an existing bookmark),
770 a revision using -r REV (where REV may be an existing bookmark),
749 the bookmark is assigned to that revision.
771 the bookmark is assigned to that revision.
750
772
751 Bookmarks can be pushed and pulled between repositories (see :hg:`help
773 Bookmarks can be pushed and pulled between repositories (see :hg:`help
752 push` and :hg:`help pull`). This requires both the local and remote
774 push` and :hg:`help pull`). This requires both the local and remote
753 repositories to support bookmarks. For versions prior to 1.8, this means
775 repositories to support bookmarks. For versions prior to 1.8, this means
754 the bookmarks extension must be enabled.
776 the bookmarks extension must be enabled.
755
777
756 With -i/--inactive, the new bookmark will not be made the active
778 With -i/--inactive, the new bookmark will not be made the active
757 bookmark. If -r/--rev is given, the new bookmark will not be made
779 bookmark. If -r/--rev is given, the new bookmark will not be made
758 active even if -i/--inactive is not given. If no NAME is given, the
780 active even if -i/--inactive is not given. If no NAME is given, the
759 current active bookmark will be marked inactive.
781 current active bookmark will be marked inactive.
760 '''
782 '''
761 hexfn = ui.debugflag and hex or short
783 hexfn = ui.debugflag and hex or short
762 marks = repo._bookmarks
784 marks = repo._bookmarks
763 cur = repo.changectx('.').node()
785 cur = repo.changectx('.').node()
764
786
765 if delete:
787 if delete:
766 if mark is None:
788 if mark is None:
767 raise util.Abort(_("bookmark name required"))
789 raise util.Abort(_("bookmark name required"))
768 if mark not in marks:
790 if mark not in marks:
769 raise util.Abort(_("bookmark '%s' does not exist") % mark)
791 raise util.Abort(_("bookmark '%s' does not exist") % mark)
770 if mark == repo._bookmarkcurrent:
792 if mark == repo._bookmarkcurrent:
771 bookmarks.setcurrent(repo, None)
793 bookmarks.setcurrent(repo, None)
772 del marks[mark]
794 del marks[mark]
773 bookmarks.write(repo)
795 bookmarks.write(repo)
774 return
796 return
775
797
776 if rename:
798 if rename:
777 if rename not in marks:
799 if rename not in marks:
778 raise util.Abort(_("bookmark '%s' does not exist") % rename)
800 raise util.Abort(_("bookmark '%s' does not exist") % rename)
779 if mark in marks and not force:
801 if mark in marks and not force:
780 raise util.Abort(_("bookmark '%s' already exists "
802 raise util.Abort(_("bookmark '%s' already exists "
781 "(use -f to force)") % mark)
803 "(use -f to force)") % mark)
782 if mark is None:
804 if mark is None:
783 raise util.Abort(_("new bookmark name required"))
805 raise util.Abort(_("new bookmark name required"))
784 marks[mark] = marks[rename]
806 marks[mark] = marks[rename]
785 if repo._bookmarkcurrent == rename and not inactive:
807 if repo._bookmarkcurrent == rename and not inactive:
786 bookmarks.setcurrent(repo, mark)
808 bookmarks.setcurrent(repo, mark)
787 del marks[rename]
809 del marks[rename]
788 bookmarks.write(repo)
810 bookmarks.write(repo)
789 return
811 return
790
812
791 if mark is not None:
813 if mark is not None:
792 if "\n" in mark:
814 if "\n" in mark:
793 raise util.Abort(_("bookmark name cannot contain newlines"))
815 raise util.Abort(_("bookmark name cannot contain newlines"))
794 mark = mark.strip()
816 mark = mark.strip()
795 if not mark:
817 if not mark:
796 raise util.Abort(_("bookmark names cannot consist entirely of "
818 raise util.Abort(_("bookmark names cannot consist entirely of "
797 "whitespace"))
819 "whitespace"))
798 if inactive and mark == repo._bookmarkcurrent:
820 if inactive and mark == repo._bookmarkcurrent:
799 bookmarks.setcurrent(repo, None)
821 bookmarks.setcurrent(repo, None)
800 return
822 return
801 if mark in marks and not force:
823 if mark in marks and not force:
802 raise util.Abort(_("bookmark '%s' already exists "
824 raise util.Abort(_("bookmark '%s' already exists "
803 "(use -f to force)") % mark)
825 "(use -f to force)") % mark)
804 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
826 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
805 and not force):
827 and not force):
806 raise util.Abort(
828 raise util.Abort(
807 _("a bookmark cannot have the name of an existing branch"))
829 _("a bookmark cannot have the name of an existing branch"))
808 if rev:
830 if rev:
809 marks[mark] = repo.lookup(rev)
831 marks[mark] = repo.lookup(rev)
810 else:
832 else:
811 marks[mark] = cur
833 marks[mark] = cur
812 if not inactive and cur == marks[mark]:
834 if not inactive and cur == marks[mark]:
813 bookmarks.setcurrent(repo, mark)
835 bookmarks.setcurrent(repo, mark)
814 bookmarks.write(repo)
836 bookmarks.write(repo)
815 return
837 return
816
838
817 if mark is None:
839 if mark is None:
818 if rev:
840 if rev:
819 raise util.Abort(_("bookmark name required"))
841 raise util.Abort(_("bookmark name required"))
820 if len(marks) == 0:
842 if len(marks) == 0:
821 ui.status(_("no bookmarks set\n"))
843 ui.status(_("no bookmarks set\n"))
822 else:
844 else:
823 for bmark, n in sorted(marks.iteritems()):
845 for bmark, n in sorted(marks.iteritems()):
824 current = repo._bookmarkcurrent
846 current = repo._bookmarkcurrent
825 if bmark == current and n == cur:
847 if bmark == current and n == cur:
826 prefix, label = '*', 'bookmarks.current'
848 prefix, label = '*', 'bookmarks.current'
827 else:
849 else:
828 prefix, label = ' ', ''
850 prefix, label = ' ', ''
829
851
830 if ui.quiet:
852 if ui.quiet:
831 ui.write("%s\n" % bmark, label=label)
853 ui.write("%s\n" % bmark, label=label)
832 else:
854 else:
833 ui.write(" %s %-25s %d:%s\n" % (
855 ui.write(" %s %-25s %d:%s\n" % (
834 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
856 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
835 label=label)
857 label=label)
836 return
858 return
837
859
838 @command('branch',
860 @command('branch',
839 [('f', 'force', None,
861 [('f', 'force', None,
840 _('set branch name even if it shadows an existing branch')),
862 _('set branch name even if it shadows an existing branch')),
841 ('C', 'clean', None, _('reset branch name to parent branch name'))],
863 ('C', 'clean', None, _('reset branch name to parent branch name'))],
842 _('[-fC] [NAME]'))
864 _('[-fC] [NAME]'))
843 def branch(ui, repo, label=None, **opts):
865 def branch(ui, repo, label=None, **opts):
844 """set or show the current branch name
866 """set or show the current branch name
845
867
846 .. note::
868 .. note::
847 Branch names are permanent and global. Use :hg:`bookmark` to create a
869 Branch names are permanent and global. Use :hg:`bookmark` to create a
848 light-weight bookmark instead. See :hg:`help glossary` for more
870 light-weight bookmark instead. See :hg:`help glossary` for more
849 information about named branches and bookmarks.
871 information about named branches and bookmarks.
850
872
851 With no argument, show the current branch name. With one argument,
873 With no argument, show the current branch name. With one argument,
852 set the working directory branch name (the branch will not exist
874 set the working directory branch name (the branch will not exist
853 in the repository until the next commit). Standard practice
875 in the repository until the next commit). Standard practice
854 recommends that primary development take place on the 'default'
876 recommends that primary development take place on the 'default'
855 branch.
877 branch.
856
878
857 Unless -f/--force is specified, branch will not let you set a
879 Unless -f/--force is specified, branch will not let you set a
858 branch name that already exists, even if it's inactive.
880 branch name that already exists, even if it's inactive.
859
881
860 Use -C/--clean to reset the working directory branch to that of
882 Use -C/--clean to reset the working directory branch to that of
861 the parent of the working directory, negating a previous branch
883 the parent of the working directory, negating a previous branch
862 change.
884 change.
863
885
864 Use the command :hg:`update` to switch to an existing branch. Use
886 Use the command :hg:`update` to switch to an existing branch. Use
865 :hg:`commit --close-branch` to mark this branch as closed.
887 :hg:`commit --close-branch` to mark this branch as closed.
866
888
867 Returns 0 on success.
889 Returns 0 on success.
868 """
890 """
869 if not opts.get('clean') and not label:
891 if not opts.get('clean') and not label:
870 ui.write("%s\n" % repo.dirstate.branch())
892 ui.write("%s\n" % repo.dirstate.branch())
871 return
893 return
872
894
873 wlock = repo.wlock()
895 wlock = repo.wlock()
874 try:
896 try:
875 if opts.get('clean'):
897 if opts.get('clean'):
876 label = repo[None].p1().branch()
898 label = repo[None].p1().branch()
877 repo.dirstate.setbranch(label)
899 repo.dirstate.setbranch(label)
878 ui.status(_('reset working directory to branch %s\n') % label)
900 ui.status(_('reset working directory to branch %s\n') % label)
879 elif label:
901 elif label:
880 if not opts.get('force') and label in repo.branchtags():
902 if not opts.get('force') and label in repo.branchtags():
881 if label not in [p.branch() for p in repo.parents()]:
903 if label not in [p.branch() for p in repo.parents()]:
882 raise util.Abort(_('a branch of the same name already'
904 raise util.Abort(_('a branch of the same name already'
883 ' exists'),
905 ' exists'),
884 # i18n: "it" refers to an existing branch
906 # i18n: "it" refers to an existing branch
885 hint=_("use 'hg update' to switch to it"))
907 hint=_("use 'hg update' to switch to it"))
886 repo.dirstate.setbranch(label)
908 repo.dirstate.setbranch(label)
887 ui.status(_('marked working directory as branch %s\n') % label)
909 ui.status(_('marked working directory as branch %s\n') % label)
888 ui.status(_('(branches are permanent and global, '
910 ui.status(_('(branches are permanent and global, '
889 'did you want a bookmark?)\n'))
911 'did you want a bookmark?)\n'))
890 finally:
912 finally:
891 wlock.release()
913 wlock.release()
892
914
893 @command('branches',
915 @command('branches',
894 [('a', 'active', False, _('show only branches that have unmerged heads')),
916 [('a', 'active', False, _('show only branches that have unmerged heads')),
895 ('c', 'closed', False, _('show normal and closed branches'))],
917 ('c', 'closed', False, _('show normal and closed branches'))],
896 _('[-ac]'))
918 _('[-ac]'))
897 def branches(ui, repo, active=False, closed=False):
919 def branches(ui, repo, active=False, closed=False):
898 """list repository named branches
920 """list repository named branches
899
921
900 List the repository's named branches, indicating which ones are
922 List the repository's named branches, indicating which ones are
901 inactive. If -c/--closed is specified, also list branches which have
923 inactive. If -c/--closed is specified, also list branches which have
902 been marked closed (see :hg:`commit --close-branch`).
924 been marked closed (see :hg:`commit --close-branch`).
903
925
904 If -a/--active is specified, only show active branches. A branch
926 If -a/--active is specified, only show active branches. A branch
905 is considered active if it contains repository heads.
927 is considered active if it contains repository heads.
906
928
907 Use the command :hg:`update` to switch to an existing branch.
929 Use the command :hg:`update` to switch to an existing branch.
908
930
909 Returns 0.
931 Returns 0.
910 """
932 """
911
933
912 hexfunc = ui.debugflag and hex or short
934 hexfunc = ui.debugflag and hex or short
913 activebranches = [repo[n].branch() for n in repo.heads()]
935 activebranches = [repo[n].branch() for n in repo.heads()]
914 def testactive(tag, node):
936 def testactive(tag, node):
915 realhead = tag in activebranches
937 realhead = tag in activebranches
916 open = node in repo.branchheads(tag, closed=False)
938 open = node in repo.branchheads(tag, closed=False)
917 return realhead and open
939 return realhead and open
918 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
940 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
919 for tag, node in repo.branchtags().items()],
941 for tag, node in repo.branchtags().items()],
920 reverse=True)
942 reverse=True)
921
943
922 for isactive, node, tag in branches:
944 for isactive, node, tag in branches:
923 if (not active) or isactive:
945 if (not active) or isactive:
924 hn = repo.lookup(node)
946 hn = repo.lookup(node)
925 if isactive:
947 if isactive:
926 label = 'branches.active'
948 label = 'branches.active'
927 notice = ''
949 notice = ''
928 elif hn not in repo.branchheads(tag, closed=False):
950 elif hn not in repo.branchheads(tag, closed=False):
929 if not closed:
951 if not closed:
930 continue
952 continue
931 label = 'branches.closed'
953 label = 'branches.closed'
932 notice = _(' (closed)')
954 notice = _(' (closed)')
933 else:
955 else:
934 label = 'branches.inactive'
956 label = 'branches.inactive'
935 notice = _(' (inactive)')
957 notice = _(' (inactive)')
936 if tag == repo.dirstate.branch():
958 if tag == repo.dirstate.branch():
937 label = 'branches.current'
959 label = 'branches.current'
938 rev = str(node).rjust(31 - encoding.colwidth(tag))
960 rev = str(node).rjust(31 - encoding.colwidth(tag))
939 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
961 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
940 tag = ui.label(tag, label)
962 tag = ui.label(tag, label)
941 if ui.quiet:
963 if ui.quiet:
942 ui.write("%s\n" % tag)
964 ui.write("%s\n" % tag)
943 else:
965 else:
944 ui.write("%s %s%s\n" % (tag, rev, notice))
966 ui.write("%s %s%s\n" % (tag, rev, notice))
945
967
946 @command('bundle',
968 @command('bundle',
947 [('f', 'force', None, _('run even when the destination is unrelated')),
969 [('f', 'force', None, _('run even when the destination is unrelated')),
948 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
970 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
949 _('REV')),
971 _('REV')),
950 ('b', 'branch', [], _('a specific branch you would like to bundle'),
972 ('b', 'branch', [], _('a specific branch you would like to bundle'),
951 _('BRANCH')),
973 _('BRANCH')),
952 ('', 'base', [],
974 ('', 'base', [],
953 _('a base changeset assumed to be available at the destination'),
975 _('a base changeset assumed to be available at the destination'),
954 _('REV')),
976 _('REV')),
955 ('a', 'all', None, _('bundle all changesets in the repository')),
977 ('a', 'all', None, _('bundle all changesets in the repository')),
956 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
978 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
957 ] + remoteopts,
979 ] + remoteopts,
958 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
980 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
959 def bundle(ui, repo, fname, dest=None, **opts):
981 def bundle(ui, repo, fname, dest=None, **opts):
960 """create a changegroup file
982 """create a changegroup file
961
983
962 Generate a compressed changegroup file collecting changesets not
984 Generate a compressed changegroup file collecting changesets not
963 known to be in another repository.
985 known to be in another repository.
964
986
965 If you omit the destination repository, then hg assumes the
987 If you omit the destination repository, then hg assumes the
966 destination will have all the nodes you specify with --base
988 destination will have all the nodes you specify with --base
967 parameters. To create a bundle containing all changesets, use
989 parameters. To create a bundle containing all changesets, use
968 -a/--all (or --base null).
990 -a/--all (or --base null).
969
991
970 You can change compression method with the -t/--type option.
992 You can change compression method with the -t/--type option.
971 The available compression methods are: none, bzip2, and
993 The available compression methods are: none, bzip2, and
972 gzip (by default, bundles are compressed using bzip2).
994 gzip (by default, bundles are compressed using bzip2).
973
995
974 The bundle file can then be transferred using conventional means
996 The bundle file can then be transferred using conventional means
975 and applied to another repository with the unbundle or pull
997 and applied to another repository with the unbundle or pull
976 command. This is useful when direct push and pull are not
998 command. This is useful when direct push and pull are not
977 available or when exporting an entire repository is undesirable.
999 available or when exporting an entire repository is undesirable.
978
1000
979 Applying bundles preserves all changeset contents including
1001 Applying bundles preserves all changeset contents including
980 permissions, copy/rename information, and revision history.
1002 permissions, copy/rename information, and revision history.
981
1003
982 Returns 0 on success, 1 if no changes found.
1004 Returns 0 on success, 1 if no changes found.
983 """
1005 """
984 revs = None
1006 revs = None
985 if 'rev' in opts:
1007 if 'rev' in opts:
986 revs = scmutil.revrange(repo, opts['rev'])
1008 revs = scmutil.revrange(repo, opts['rev'])
987
1009
988 bundletype = opts.get('type', 'bzip2').lower()
1010 bundletype = opts.get('type', 'bzip2').lower()
989 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1011 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
990 bundletype = btypes.get(bundletype)
1012 bundletype = btypes.get(bundletype)
991 if bundletype not in changegroup.bundletypes:
1013 if bundletype not in changegroup.bundletypes:
992 raise util.Abort(_('unknown bundle type specified with --type'))
1014 raise util.Abort(_('unknown bundle type specified with --type'))
993
1015
994 if opts.get('all'):
1016 if opts.get('all'):
995 base = ['null']
1017 base = ['null']
996 else:
1018 else:
997 base = scmutil.revrange(repo, opts.get('base'))
1019 base = scmutil.revrange(repo, opts.get('base'))
998 if base:
1020 if base:
999 if dest:
1021 if dest:
1000 raise util.Abort(_("--base is incompatible with specifying "
1022 raise util.Abort(_("--base is incompatible with specifying "
1001 "a destination"))
1023 "a destination"))
1002 common = [repo.lookup(rev) for rev in base]
1024 common = [repo.lookup(rev) for rev in base]
1003 heads = revs and map(repo.lookup, revs) or revs
1025 heads = revs and map(repo.lookup, revs) or revs
1004 cg = repo.getbundle('bundle', heads=heads, common=common)
1026 cg = repo.getbundle('bundle', heads=heads, common=common)
1005 outgoing = None
1027 outgoing = None
1006 else:
1028 else:
1007 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1029 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1008 dest, branches = hg.parseurl(dest, opts.get('branch'))
1030 dest, branches = hg.parseurl(dest, opts.get('branch'))
1009 other = hg.peer(repo, opts, dest)
1031 other = hg.peer(repo, opts, dest)
1010 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1032 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1011 heads = revs and map(repo.lookup, revs) or revs
1033 heads = revs and map(repo.lookup, revs) or revs
1012 outgoing = discovery.findcommonoutgoing(repo, other,
1034 outgoing = discovery.findcommonoutgoing(repo, other,
1013 onlyheads=heads,
1035 onlyheads=heads,
1014 force=opts.get('force'))
1036 force=opts.get('force'))
1015 cg = repo.getlocalbundle('bundle', outgoing)
1037 cg = repo.getlocalbundle('bundle', outgoing)
1016 if not cg:
1038 if not cg:
1017 scmutil.nochangesfound(ui, outgoing and outgoing.excluded)
1039 scmutil.nochangesfound(ui, outgoing and outgoing.excluded)
1018 return 1
1040 return 1
1019
1041
1020 changegroup.writebundle(cg, fname, bundletype)
1042 changegroup.writebundle(cg, fname, bundletype)
1021
1043
1022 @command('cat',
1044 @command('cat',
1023 [('o', 'output', '',
1045 [('o', 'output', '',
1024 _('print output to file with formatted name'), _('FORMAT')),
1046 _('print output to file with formatted name'), _('FORMAT')),
1025 ('r', 'rev', '', _('print the given revision'), _('REV')),
1047 ('r', 'rev', '', _('print the given revision'), _('REV')),
1026 ('', 'decode', None, _('apply any matching decode filter')),
1048 ('', 'decode', None, _('apply any matching decode filter')),
1027 ] + walkopts,
1049 ] + walkopts,
1028 _('[OPTION]... FILE...'))
1050 _('[OPTION]... FILE...'))
1029 def cat(ui, repo, file1, *pats, **opts):
1051 def cat(ui, repo, file1, *pats, **opts):
1030 """output the current or given revision of files
1052 """output the current or given revision of files
1031
1053
1032 Print the specified files as they were at the given revision. If
1054 Print the specified files as they were at the given revision. If
1033 no revision is given, the parent of the working directory is used,
1055 no revision is given, the parent of the working directory is used,
1034 or tip if no revision is checked out.
1056 or tip if no revision is checked out.
1035
1057
1036 Output may be to a file, in which case the name of the file is
1058 Output may be to a file, in which case the name of the file is
1037 given using a format string. The formatting rules are the same as
1059 given using a format string. The formatting rules are the same as
1038 for the export command, with the following additions:
1060 for the export command, with the following additions:
1039
1061
1040 :``%s``: basename of file being printed
1062 :``%s``: basename of file being printed
1041 :``%d``: dirname of file being printed, or '.' if in repository root
1063 :``%d``: dirname of file being printed, or '.' if in repository root
1042 :``%p``: root-relative path name of file being printed
1064 :``%p``: root-relative path name of file being printed
1043
1065
1044 Returns 0 on success.
1066 Returns 0 on success.
1045 """
1067 """
1046 ctx = scmutil.revsingle(repo, opts.get('rev'))
1068 ctx = scmutil.revsingle(repo, opts.get('rev'))
1047 err = 1
1069 err = 1
1048 m = scmutil.match(ctx, (file1,) + pats, opts)
1070 m = scmutil.match(ctx, (file1,) + pats, opts)
1049 for abs in ctx.walk(m):
1071 for abs in ctx.walk(m):
1050 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1072 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1051 pathname=abs)
1073 pathname=abs)
1052 data = ctx[abs].data()
1074 data = ctx[abs].data()
1053 if opts.get('decode'):
1075 if opts.get('decode'):
1054 data = repo.wwritedata(abs, data)
1076 data = repo.wwritedata(abs, data)
1055 fp.write(data)
1077 fp.write(data)
1056 fp.close()
1078 fp.close()
1057 err = 0
1079 err = 0
1058 return err
1080 return err
1059
1081
1060 @command('^clone',
1082 @command('^clone',
1061 [('U', 'noupdate', None,
1083 [('U', 'noupdate', None,
1062 _('the clone will include an empty working copy (only a repository)')),
1084 _('the clone will include an empty working copy (only a repository)')),
1063 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1085 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1064 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1086 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1065 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1087 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1066 ('', 'pull', None, _('use pull protocol to copy metadata')),
1088 ('', 'pull', None, _('use pull protocol to copy metadata')),
1067 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1089 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1068 ] + remoteopts,
1090 ] + remoteopts,
1069 _('[OPTION]... SOURCE [DEST]'))
1091 _('[OPTION]... SOURCE [DEST]'))
1070 def clone(ui, source, dest=None, **opts):
1092 def clone(ui, source, dest=None, **opts):
1071 """make a copy of an existing repository
1093 """make a copy of an existing repository
1072
1094
1073 Create a copy of an existing repository in a new directory.
1095 Create a copy of an existing repository in a new directory.
1074
1096
1075 If no destination directory name is specified, it defaults to the
1097 If no destination directory name is specified, it defaults to the
1076 basename of the source.
1098 basename of the source.
1077
1099
1078 The location of the source is added to the new repository's
1100 The location of the source is added to the new repository's
1079 ``.hg/hgrc`` file, as the default to be used for future pulls.
1101 ``.hg/hgrc`` file, as the default to be used for future pulls.
1080
1102
1081 Only local paths and ``ssh://`` URLs are supported as
1103 Only local paths and ``ssh://`` URLs are supported as
1082 destinations. For ``ssh://`` destinations, no working directory or
1104 destinations. For ``ssh://`` destinations, no working directory or
1083 ``.hg/hgrc`` will be created on the remote side.
1105 ``.hg/hgrc`` will be created on the remote side.
1084
1106
1085 To pull only a subset of changesets, specify one or more revisions
1107 To pull only a subset of changesets, specify one or more revisions
1086 identifiers with -r/--rev or branches with -b/--branch. The
1108 identifiers with -r/--rev or branches with -b/--branch. The
1087 resulting clone will contain only the specified changesets and
1109 resulting clone will contain only the specified changesets and
1088 their ancestors. These options (or 'clone src#rev dest') imply
1110 their ancestors. These options (or 'clone src#rev dest') imply
1089 --pull, even for local source repositories. Note that specifying a
1111 --pull, even for local source repositories. Note that specifying a
1090 tag will include the tagged changeset but not the changeset
1112 tag will include the tagged changeset but not the changeset
1091 containing the tag.
1113 containing the tag.
1092
1114
1093 To check out a particular version, use -u/--update, or
1115 To check out a particular version, use -u/--update, or
1094 -U/--noupdate to create a clone with no working directory.
1116 -U/--noupdate to create a clone with no working directory.
1095
1117
1096 .. container:: verbose
1118 .. container:: verbose
1097
1119
1098 For efficiency, hardlinks are used for cloning whenever the
1120 For efficiency, hardlinks are used for cloning whenever the
1099 source and destination are on the same filesystem (note this
1121 source and destination are on the same filesystem (note this
1100 applies only to the repository data, not to the working
1122 applies only to the repository data, not to the working
1101 directory). Some filesystems, such as AFS, implement hardlinking
1123 directory). Some filesystems, such as AFS, implement hardlinking
1102 incorrectly, but do not report errors. In these cases, use the
1124 incorrectly, but do not report errors. In these cases, use the
1103 --pull option to avoid hardlinking.
1125 --pull option to avoid hardlinking.
1104
1126
1105 In some cases, you can clone repositories and the working
1127 In some cases, you can clone repositories and the working
1106 directory using full hardlinks with ::
1128 directory using full hardlinks with ::
1107
1129
1108 $ cp -al REPO REPOCLONE
1130 $ cp -al REPO REPOCLONE
1109
1131
1110 This is the fastest way to clone, but it is not always safe. The
1132 This is the fastest way to clone, but it is not always safe. The
1111 operation is not atomic (making sure REPO is not modified during
1133 operation is not atomic (making sure REPO is not modified during
1112 the operation is up to you) and you have to make sure your
1134 the operation is up to you) and you have to make sure your
1113 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1135 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1114 so). Also, this is not compatible with certain extensions that
1136 so). Also, this is not compatible with certain extensions that
1115 place their metadata under the .hg directory, such as mq.
1137 place their metadata under the .hg directory, such as mq.
1116
1138
1117 Mercurial will update the working directory to the first applicable
1139 Mercurial will update the working directory to the first applicable
1118 revision from this list:
1140 revision from this list:
1119
1141
1120 a) null if -U or the source repository has no changesets
1142 a) null if -U or the source repository has no changesets
1121 b) if -u . and the source repository is local, the first parent of
1143 b) if -u . and the source repository is local, the first parent of
1122 the source repository's working directory
1144 the source repository's working directory
1123 c) the changeset specified with -u (if a branch name, this means the
1145 c) the changeset specified with -u (if a branch name, this means the
1124 latest head of that branch)
1146 latest head of that branch)
1125 d) the changeset specified with -r
1147 d) the changeset specified with -r
1126 e) the tipmost head specified with -b
1148 e) the tipmost head specified with -b
1127 f) the tipmost head specified with the url#branch source syntax
1149 f) the tipmost head specified with the url#branch source syntax
1128 g) the tipmost head of the default branch
1150 g) the tipmost head of the default branch
1129 h) tip
1151 h) tip
1130
1152
1131 Examples:
1153 Examples:
1132
1154
1133 - clone a remote repository to a new directory named hg/::
1155 - clone a remote repository to a new directory named hg/::
1134
1156
1135 hg clone http://selenic.com/hg
1157 hg clone http://selenic.com/hg
1136
1158
1137 - create a lightweight local clone::
1159 - create a lightweight local clone::
1138
1160
1139 hg clone project/ project-feature/
1161 hg clone project/ project-feature/
1140
1162
1141 - clone from an absolute path on an ssh server (note double-slash)::
1163 - clone from an absolute path on an ssh server (note double-slash)::
1142
1164
1143 hg clone ssh://user@server//home/projects/alpha/
1165 hg clone ssh://user@server//home/projects/alpha/
1144
1166
1145 - do a high-speed clone over a LAN while checking out a
1167 - do a high-speed clone over a LAN while checking out a
1146 specified version::
1168 specified version::
1147
1169
1148 hg clone --uncompressed http://server/repo -u 1.5
1170 hg clone --uncompressed http://server/repo -u 1.5
1149
1171
1150 - create a repository without changesets after a particular revision::
1172 - create a repository without changesets after a particular revision::
1151
1173
1152 hg clone -r 04e544 experimental/ good/
1174 hg clone -r 04e544 experimental/ good/
1153
1175
1154 - clone (and track) a particular named branch::
1176 - clone (and track) a particular named branch::
1155
1177
1156 hg clone http://selenic.com/hg#stable
1178 hg clone http://selenic.com/hg#stable
1157
1179
1158 See :hg:`help urls` for details on specifying URLs.
1180 See :hg:`help urls` for details on specifying URLs.
1159
1181
1160 Returns 0 on success.
1182 Returns 0 on success.
1161 """
1183 """
1162 if opts.get('noupdate') and opts.get('updaterev'):
1184 if opts.get('noupdate') and opts.get('updaterev'):
1163 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1185 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1164
1186
1165 r = hg.clone(ui, opts, source, dest,
1187 r = hg.clone(ui, opts, source, dest,
1166 pull=opts.get('pull'),
1188 pull=opts.get('pull'),
1167 stream=opts.get('uncompressed'),
1189 stream=opts.get('uncompressed'),
1168 rev=opts.get('rev'),
1190 rev=opts.get('rev'),
1169 update=opts.get('updaterev') or not opts.get('noupdate'),
1191 update=opts.get('updaterev') or not opts.get('noupdate'),
1170 branch=opts.get('branch'))
1192 branch=opts.get('branch'))
1171
1193
1172 return r is None
1194 return r is None
1173
1195
1174 @command('^commit|ci',
1196 @command('^commit|ci',
1175 [('A', 'addremove', None,
1197 [('A', 'addremove', None,
1176 _('mark new/missing files as added/removed before committing')),
1198 _('mark new/missing files as added/removed before committing')),
1177 ('', 'close-branch', None,
1199 ('', 'close-branch', None,
1178 _('mark a branch as closed, hiding it from the branch list')),
1200 _('mark a branch as closed, hiding it from the branch list')),
1179 ('', 'amend', None, _('amend the parent of the working dir')),
1201 ('', 'amend', None, _('amend the parent of the working dir')),
1180 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1202 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1181 _('[OPTION]... [FILE]...'))
1203 _('[OPTION]... [FILE]...'))
1182 def commit(ui, repo, *pats, **opts):
1204 def commit(ui, repo, *pats, **opts):
1183 """commit the specified files or all outstanding changes
1205 """commit the specified files or all outstanding changes
1184
1206
1185 Commit changes to the given files into the repository. Unlike a
1207 Commit changes to the given files into the repository. Unlike a
1186 centralized SCM, this operation is a local operation. See
1208 centralized SCM, this operation is a local operation. See
1187 :hg:`push` for a way to actively distribute your changes.
1209 :hg:`push` for a way to actively distribute your changes.
1188
1210
1189 If a list of files is omitted, all changes reported by :hg:`status`
1211 If a list of files is omitted, all changes reported by :hg:`status`
1190 will be committed.
1212 will be committed.
1191
1213
1192 If you are committing the result of a merge, do not provide any
1214 If you are committing the result of a merge, do not provide any
1193 filenames or -I/-X filters.
1215 filenames or -I/-X filters.
1194
1216
1195 If no commit message is specified, Mercurial starts your
1217 If no commit message is specified, Mercurial starts your
1196 configured editor where you can enter a message. In case your
1218 configured editor where you can enter a message. In case your
1197 commit fails, you will find a backup of your message in
1219 commit fails, you will find a backup of your message in
1198 ``.hg/last-message.txt``.
1220 ``.hg/last-message.txt``.
1199
1221
1200 The --amend flag can be used to amend the parent of the
1222 The --amend flag can be used to amend the parent of the
1201 working directory with a new commit that contains the changes
1223 working directory with a new commit that contains the changes
1202 in the parent in addition to those currently reported by :hg:`status`,
1224 in the parent in addition to those currently reported by :hg:`status`,
1203 if there are any. The old commit is stored in a backup bundle in
1225 if there are any. The old commit is stored in a backup bundle in
1204 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1226 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1205 on how to restore it).
1227 on how to restore it).
1206
1228
1207 Message, user and date are taken from the amended commit unless
1229 Message, user and date are taken from the amended commit unless
1208 specified. When a message isn't specified on the command line,
1230 specified. When a message isn't specified on the command line,
1209 the editor will open with the message of the amended commit.
1231 the editor will open with the message of the amended commit.
1210
1232
1211 It is not possible to amend public changesets (see :hg:`help phases`)
1233 It is not possible to amend public changesets (see :hg:`help phases`)
1212 or changesets that have children.
1234 or changesets that have children.
1213
1235
1214 See :hg:`help dates` for a list of formats valid for -d/--date.
1236 See :hg:`help dates` for a list of formats valid for -d/--date.
1215
1237
1216 Returns 0 on success, 1 if nothing changed.
1238 Returns 0 on success, 1 if nothing changed.
1217 """
1239 """
1218 if opts.get('subrepos'):
1240 if opts.get('subrepos'):
1219 # Let --subrepos on the command line overide config setting.
1241 # Let --subrepos on the command line overide config setting.
1220 ui.setconfig('ui', 'commitsubrepos', True)
1242 ui.setconfig('ui', 'commitsubrepos', True)
1221
1243
1222 extra = {}
1244 extra = {}
1223 if opts.get('close_branch'):
1245 if opts.get('close_branch'):
1224 if repo['.'].node() not in repo.branchheads():
1246 if repo['.'].node() not in repo.branchheads():
1225 # The topo heads set is included in the branch heads set of the
1247 # The topo heads set is included in the branch heads set of the
1226 # current branch, so it's sufficient to test branchheads
1248 # current branch, so it's sufficient to test branchheads
1227 raise util.Abort(_('can only close branch heads'))
1249 raise util.Abort(_('can only close branch heads'))
1228 extra['close'] = 1
1250 extra['close'] = 1
1229
1251
1230 branch = repo[None].branch()
1252 branch = repo[None].branch()
1231 bheads = repo.branchheads(branch)
1253 bheads = repo.branchheads(branch)
1232
1254
1233 if opts.get('amend'):
1255 if opts.get('amend'):
1234 if ui.configbool('ui', 'commitsubrepos'):
1256 if ui.configbool('ui', 'commitsubrepos'):
1235 raise util.Abort(_('cannot amend recursively'))
1257 raise util.Abort(_('cannot amend recursively'))
1236
1258
1237 old = repo['.']
1259 old = repo['.']
1238 if old.phase() == phases.public:
1260 if old.phase() == phases.public:
1239 raise util.Abort(_('cannot amend public changesets'))
1261 raise util.Abort(_('cannot amend public changesets'))
1240 if len(old.parents()) > 1:
1262 if len(old.parents()) > 1:
1241 raise util.Abort(_('cannot amend merge changesets'))
1263 raise util.Abort(_('cannot amend merge changesets'))
1242 if len(repo[None].parents()) > 1:
1264 if len(repo[None].parents()) > 1:
1243 raise util.Abort(_('cannot amend while merging'))
1265 raise util.Abort(_('cannot amend while merging'))
1244 if old.children():
1266 if old.children():
1245 raise util.Abort(_('cannot amend changeset with children'))
1267 raise util.Abort(_('cannot amend changeset with children'))
1246
1268
1247 e = cmdutil.commiteditor
1269 e = cmdutil.commiteditor
1248 if opts.get('force_editor'):
1270 if opts.get('force_editor'):
1249 e = cmdutil.commitforceeditor
1271 e = cmdutil.commitforceeditor
1250
1272
1251 def commitfunc(ui, repo, message, match, opts):
1273 def commitfunc(ui, repo, message, match, opts):
1252 editor = e
1274 editor = e
1253 # message contains text from -m or -l, if it's empty,
1275 # message contains text from -m or -l, if it's empty,
1254 # open the editor with the old message
1276 # open the editor with the old message
1255 if not message:
1277 if not message:
1256 message = old.description()
1278 message = old.description()
1257 editor = cmdutil.commitforceeditor
1279 editor = cmdutil.commitforceeditor
1258 return repo.commit(message,
1280 return repo.commit(message,
1259 opts.get('user') or old.user(),
1281 opts.get('user') or old.user(),
1260 opts.get('date') or old.date(),
1282 opts.get('date') or old.date(),
1261 match,
1283 match,
1262 editor=editor,
1284 editor=editor,
1263 extra=extra)
1285 extra=extra)
1264
1286
1265 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1287 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1266 if node == old.node():
1288 if node == old.node():
1267 ui.status(_("nothing changed\n"))
1289 ui.status(_("nothing changed\n"))
1268 return 1
1290 return 1
1269 else:
1291 else:
1270 e = cmdutil.commiteditor
1292 e = cmdutil.commiteditor
1271 if opts.get('force_editor'):
1293 if opts.get('force_editor'):
1272 e = cmdutil.commitforceeditor
1294 e = cmdutil.commitforceeditor
1273
1295
1274 def commitfunc(ui, repo, message, match, opts):
1296 def commitfunc(ui, repo, message, match, opts):
1275 return repo.commit(message, opts.get('user'), opts.get('date'),
1297 return repo.commit(message, opts.get('user'), opts.get('date'),
1276 match, editor=e, extra=extra)
1298 match, editor=e, extra=extra)
1277
1299
1278 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1300 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1279
1301
1280 if not node:
1302 if not node:
1281 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1303 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1282 if stat[3]:
1304 if stat[3]:
1283 ui.status(_("nothing changed (%d missing files, see "
1305 ui.status(_("nothing changed (%d missing files, see "
1284 "'hg status')\n") % len(stat[3]))
1306 "'hg status')\n") % len(stat[3]))
1285 else:
1307 else:
1286 ui.status(_("nothing changed\n"))
1308 ui.status(_("nothing changed\n"))
1287 return 1
1309 return 1
1288
1310
1289 ctx = repo[node]
1311 ctx = repo[node]
1290 parents = ctx.parents()
1312 parents = ctx.parents()
1291
1313
1292 if (not opts.get('amend') and bheads and node not in bheads and not
1314 if (not opts.get('amend') and bheads and node not in bheads and not
1293 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1315 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1294 ui.status(_('created new head\n'))
1316 ui.status(_('created new head\n'))
1295 # The message is not printed for initial roots. For the other
1317 # The message is not printed for initial roots. For the other
1296 # changesets, it is printed in the following situations:
1318 # changesets, it is printed in the following situations:
1297 #
1319 #
1298 # Par column: for the 2 parents with ...
1320 # Par column: for the 2 parents with ...
1299 # N: null or no parent
1321 # N: null or no parent
1300 # B: parent is on another named branch
1322 # B: parent is on another named branch
1301 # C: parent is a regular non head changeset
1323 # C: parent is a regular non head changeset
1302 # H: parent was a branch head of the current branch
1324 # H: parent was a branch head of the current branch
1303 # Msg column: whether we print "created new head" message
1325 # Msg column: whether we print "created new head" message
1304 # In the following, it is assumed that there already exists some
1326 # In the following, it is assumed that there already exists some
1305 # initial branch heads of the current branch, otherwise nothing is
1327 # initial branch heads of the current branch, otherwise nothing is
1306 # printed anyway.
1328 # printed anyway.
1307 #
1329 #
1308 # Par Msg Comment
1330 # Par Msg Comment
1309 # NN y additional topo root
1331 # NN y additional topo root
1310 #
1332 #
1311 # BN y additional branch root
1333 # BN y additional branch root
1312 # CN y additional topo head
1334 # CN y additional topo head
1313 # HN n usual case
1335 # HN n usual case
1314 #
1336 #
1315 # BB y weird additional branch root
1337 # BB y weird additional branch root
1316 # CB y branch merge
1338 # CB y branch merge
1317 # HB n merge with named branch
1339 # HB n merge with named branch
1318 #
1340 #
1319 # CC y additional head from merge
1341 # CC y additional head from merge
1320 # CH n merge with a head
1342 # CH n merge with a head
1321 #
1343 #
1322 # HH n head merge: head count decreases
1344 # HH n head merge: head count decreases
1323
1345
1324 if not opts.get('close_branch'):
1346 if not opts.get('close_branch'):
1325 for r in parents:
1347 for r in parents:
1326 if r.extra().get('close') and r.branch() == branch:
1348 if r.extra().get('close') and r.branch() == branch:
1327 ui.status(_('reopening closed branch head %d\n') % r)
1349 ui.status(_('reopening closed branch head %d\n') % r)
1328
1350
1329 if ui.debugflag:
1351 if ui.debugflag:
1330 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1352 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1331 elif ui.verbose:
1353 elif ui.verbose:
1332 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1354 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1333
1355
1334 @command('copy|cp',
1356 @command('copy|cp',
1335 [('A', 'after', None, _('record a copy that has already occurred')),
1357 [('A', 'after', None, _('record a copy that has already occurred')),
1336 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1358 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1337 ] + walkopts + dryrunopts,
1359 ] + walkopts + dryrunopts,
1338 _('[OPTION]... [SOURCE]... DEST'))
1360 _('[OPTION]... [SOURCE]... DEST'))
1339 def copy(ui, repo, *pats, **opts):
1361 def copy(ui, repo, *pats, **opts):
1340 """mark files as copied for the next commit
1362 """mark files as copied for the next commit
1341
1363
1342 Mark dest as having copies of source files. If dest is a
1364 Mark dest as having copies of source files. If dest is a
1343 directory, copies are put in that directory. If dest is a file,
1365 directory, copies are put in that directory. If dest is a file,
1344 the source must be a single file.
1366 the source must be a single file.
1345
1367
1346 By default, this command copies the contents of files as they
1368 By default, this command copies the contents of files as they
1347 exist in the working directory. If invoked with -A/--after, the
1369 exist in the working directory. If invoked with -A/--after, the
1348 operation is recorded, but no copying is performed.
1370 operation is recorded, but no copying is performed.
1349
1371
1350 This command takes effect with the next commit. To undo a copy
1372 This command takes effect with the next commit. To undo a copy
1351 before that, see :hg:`revert`.
1373 before that, see :hg:`revert`.
1352
1374
1353 Returns 0 on success, 1 if errors are encountered.
1375 Returns 0 on success, 1 if errors are encountered.
1354 """
1376 """
1355 wlock = repo.wlock(False)
1377 wlock = repo.wlock(False)
1356 try:
1378 try:
1357 return cmdutil.copy(ui, repo, pats, opts)
1379 return cmdutil.copy(ui, repo, pats, opts)
1358 finally:
1380 finally:
1359 wlock.release()
1381 wlock.release()
1360
1382
1361 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1383 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1362 def debugancestor(ui, repo, *args):
1384 def debugancestor(ui, repo, *args):
1363 """find the ancestor revision of two revisions in a given index"""
1385 """find the ancestor revision of two revisions in a given index"""
1364 if len(args) == 3:
1386 if len(args) == 3:
1365 index, rev1, rev2 = args
1387 index, rev1, rev2 = args
1366 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1388 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1367 lookup = r.lookup
1389 lookup = r.lookup
1368 elif len(args) == 2:
1390 elif len(args) == 2:
1369 if not repo:
1391 if not repo:
1370 raise util.Abort(_("there is no Mercurial repository here "
1392 raise util.Abort(_("there is no Mercurial repository here "
1371 "(.hg not found)"))
1393 "(.hg not found)"))
1372 rev1, rev2 = args
1394 rev1, rev2 = args
1373 r = repo.changelog
1395 r = repo.changelog
1374 lookup = repo.lookup
1396 lookup = repo.lookup
1375 else:
1397 else:
1376 raise util.Abort(_('either two or three arguments required'))
1398 raise util.Abort(_('either two or three arguments required'))
1377 a = r.ancestor(lookup(rev1), lookup(rev2))
1399 a = r.ancestor(lookup(rev1), lookup(rev2))
1378 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1400 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1379
1401
1380 @command('debugbuilddag',
1402 @command('debugbuilddag',
1381 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1403 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1382 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1404 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1383 ('n', 'new-file', None, _('add new file at each rev'))],
1405 ('n', 'new-file', None, _('add new file at each rev'))],
1384 _('[OPTION]... [TEXT]'))
1406 _('[OPTION]... [TEXT]'))
1385 def debugbuilddag(ui, repo, text=None,
1407 def debugbuilddag(ui, repo, text=None,
1386 mergeable_file=False,
1408 mergeable_file=False,
1387 overwritten_file=False,
1409 overwritten_file=False,
1388 new_file=False):
1410 new_file=False):
1389 """builds a repo with a given DAG from scratch in the current empty repo
1411 """builds a repo with a given DAG from scratch in the current empty repo
1390
1412
1391 The description of the DAG is read from stdin if not given on the
1413 The description of the DAG is read from stdin if not given on the
1392 command line.
1414 command line.
1393
1415
1394 Elements:
1416 Elements:
1395
1417
1396 - "+n" is a linear run of n nodes based on the current default parent
1418 - "+n" is a linear run of n nodes based on the current default parent
1397 - "." is a single node based on the current default parent
1419 - "." is a single node based on the current default parent
1398 - "$" resets the default parent to null (implied at the start);
1420 - "$" resets the default parent to null (implied at the start);
1399 otherwise the default parent is always the last node created
1421 otherwise the default parent is always the last node created
1400 - "<p" sets the default parent to the backref p
1422 - "<p" sets the default parent to the backref p
1401 - "*p" is a fork at parent p, which is a backref
1423 - "*p" is a fork at parent p, which is a backref
1402 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1424 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1403 - "/p2" is a merge of the preceding node and p2
1425 - "/p2" is a merge of the preceding node and p2
1404 - ":tag" defines a local tag for the preceding node
1426 - ":tag" defines a local tag for the preceding node
1405 - "@branch" sets the named branch for subsequent nodes
1427 - "@branch" sets the named branch for subsequent nodes
1406 - "#...\\n" is a comment up to the end of the line
1428 - "#...\\n" is a comment up to the end of the line
1407
1429
1408 Whitespace between the above elements is ignored.
1430 Whitespace between the above elements is ignored.
1409
1431
1410 A backref is either
1432 A backref is either
1411
1433
1412 - a number n, which references the node curr-n, where curr is the current
1434 - a number n, which references the node curr-n, where curr is the current
1413 node, or
1435 node, or
1414 - the name of a local tag you placed earlier using ":tag", or
1436 - the name of a local tag you placed earlier using ":tag", or
1415 - empty to denote the default parent.
1437 - empty to denote the default parent.
1416
1438
1417 All string valued-elements are either strictly alphanumeric, or must
1439 All string valued-elements are either strictly alphanumeric, or must
1418 be enclosed in double quotes ("..."), with "\\" as escape character.
1440 be enclosed in double quotes ("..."), with "\\" as escape character.
1419 """
1441 """
1420
1442
1421 if text is None:
1443 if text is None:
1422 ui.status(_("reading DAG from stdin\n"))
1444 ui.status(_("reading DAG from stdin\n"))
1423 text = ui.fin.read()
1445 text = ui.fin.read()
1424
1446
1425 cl = repo.changelog
1447 cl = repo.changelog
1426 if len(cl) > 0:
1448 if len(cl) > 0:
1427 raise util.Abort(_('repository is not empty'))
1449 raise util.Abort(_('repository is not empty'))
1428
1450
1429 # determine number of revs in DAG
1451 # determine number of revs in DAG
1430 total = 0
1452 total = 0
1431 for type, data in dagparser.parsedag(text):
1453 for type, data in dagparser.parsedag(text):
1432 if type == 'n':
1454 if type == 'n':
1433 total += 1
1455 total += 1
1434
1456
1435 if mergeable_file:
1457 if mergeable_file:
1436 linesperrev = 2
1458 linesperrev = 2
1437 # make a file with k lines per rev
1459 # make a file with k lines per rev
1438 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1460 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1439 initialmergedlines.append("")
1461 initialmergedlines.append("")
1440
1462
1441 tags = []
1463 tags = []
1442
1464
1443 lock = tr = None
1465 lock = tr = None
1444 try:
1466 try:
1445 lock = repo.lock()
1467 lock = repo.lock()
1446 tr = repo.transaction("builddag")
1468 tr = repo.transaction("builddag")
1447
1469
1448 at = -1
1470 at = -1
1449 atbranch = 'default'
1471 atbranch = 'default'
1450 nodeids = []
1472 nodeids = []
1451 id = 0
1473 id = 0
1452 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1474 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1453 for type, data in dagparser.parsedag(text):
1475 for type, data in dagparser.parsedag(text):
1454 if type == 'n':
1476 if type == 'n':
1455 ui.note('node %s\n' % str(data))
1477 ui.note('node %s\n' % str(data))
1456 id, ps = data
1478 id, ps = data
1457
1479
1458 files = []
1480 files = []
1459 fctxs = {}
1481 fctxs = {}
1460
1482
1461 p2 = None
1483 p2 = None
1462 if mergeable_file:
1484 if mergeable_file:
1463 fn = "mf"
1485 fn = "mf"
1464 p1 = repo[ps[0]]
1486 p1 = repo[ps[0]]
1465 if len(ps) > 1:
1487 if len(ps) > 1:
1466 p2 = repo[ps[1]]
1488 p2 = repo[ps[1]]
1467 pa = p1.ancestor(p2)
1489 pa = p1.ancestor(p2)
1468 base, local, other = [x[fn].data() for x in pa, p1, p2]
1490 base, local, other = [x[fn].data() for x in pa, p1, p2]
1469 m3 = simplemerge.Merge3Text(base, local, other)
1491 m3 = simplemerge.Merge3Text(base, local, other)
1470 ml = [l.strip() for l in m3.merge_lines()]
1492 ml = [l.strip() for l in m3.merge_lines()]
1471 ml.append("")
1493 ml.append("")
1472 elif at > 0:
1494 elif at > 0:
1473 ml = p1[fn].data().split("\n")
1495 ml = p1[fn].data().split("\n")
1474 else:
1496 else:
1475 ml = initialmergedlines
1497 ml = initialmergedlines
1476 ml[id * linesperrev] += " r%i" % id
1498 ml[id * linesperrev] += " r%i" % id
1477 mergedtext = "\n".join(ml)
1499 mergedtext = "\n".join(ml)
1478 files.append(fn)
1500 files.append(fn)
1479 fctxs[fn] = context.memfilectx(fn, mergedtext)
1501 fctxs[fn] = context.memfilectx(fn, mergedtext)
1480
1502
1481 if overwritten_file:
1503 if overwritten_file:
1482 fn = "of"
1504 fn = "of"
1483 files.append(fn)
1505 files.append(fn)
1484 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1506 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1485
1507
1486 if new_file:
1508 if new_file:
1487 fn = "nf%i" % id
1509 fn = "nf%i" % id
1488 files.append(fn)
1510 files.append(fn)
1489 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1511 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1490 if len(ps) > 1:
1512 if len(ps) > 1:
1491 if not p2:
1513 if not p2:
1492 p2 = repo[ps[1]]
1514 p2 = repo[ps[1]]
1493 for fn in p2:
1515 for fn in p2:
1494 if fn.startswith("nf"):
1516 if fn.startswith("nf"):
1495 files.append(fn)
1517 files.append(fn)
1496 fctxs[fn] = p2[fn]
1518 fctxs[fn] = p2[fn]
1497
1519
1498 def fctxfn(repo, cx, path):
1520 def fctxfn(repo, cx, path):
1499 return fctxs.get(path)
1521 return fctxs.get(path)
1500
1522
1501 if len(ps) == 0 or ps[0] < 0:
1523 if len(ps) == 0 or ps[0] < 0:
1502 pars = [None, None]
1524 pars = [None, None]
1503 elif len(ps) == 1:
1525 elif len(ps) == 1:
1504 pars = [nodeids[ps[0]], None]
1526 pars = [nodeids[ps[0]], None]
1505 else:
1527 else:
1506 pars = [nodeids[p] for p in ps]
1528 pars = [nodeids[p] for p in ps]
1507 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1529 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1508 date=(id, 0),
1530 date=(id, 0),
1509 user="debugbuilddag",
1531 user="debugbuilddag",
1510 extra={'branch': atbranch})
1532 extra={'branch': atbranch})
1511 nodeid = repo.commitctx(cx)
1533 nodeid = repo.commitctx(cx)
1512 nodeids.append(nodeid)
1534 nodeids.append(nodeid)
1513 at = id
1535 at = id
1514 elif type == 'l':
1536 elif type == 'l':
1515 id, name = data
1537 id, name = data
1516 ui.note('tag %s\n' % name)
1538 ui.note('tag %s\n' % name)
1517 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1539 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1518 elif type == 'a':
1540 elif type == 'a':
1519 ui.note('branch %s\n' % data)
1541 ui.note('branch %s\n' % data)
1520 atbranch = data
1542 atbranch = data
1521 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1543 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1522 tr.close()
1544 tr.close()
1523
1545
1524 if tags:
1546 if tags:
1525 repo.opener.write("localtags", "".join(tags))
1547 repo.opener.write("localtags", "".join(tags))
1526 finally:
1548 finally:
1527 ui.progress(_('building'), None)
1549 ui.progress(_('building'), None)
1528 release(tr, lock)
1550 release(tr, lock)
1529
1551
1530 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1552 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1531 def debugbundle(ui, bundlepath, all=None, **opts):
1553 def debugbundle(ui, bundlepath, all=None, **opts):
1532 """lists the contents of a bundle"""
1554 """lists the contents of a bundle"""
1533 f = url.open(ui, bundlepath)
1555 f = url.open(ui, bundlepath)
1534 try:
1556 try:
1535 gen = changegroup.readbundle(f, bundlepath)
1557 gen = changegroup.readbundle(f, bundlepath)
1536 if all:
1558 if all:
1537 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1559 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1538
1560
1539 def showchunks(named):
1561 def showchunks(named):
1540 ui.write("\n%s\n" % named)
1562 ui.write("\n%s\n" % named)
1541 chain = None
1563 chain = None
1542 while True:
1564 while True:
1543 chunkdata = gen.deltachunk(chain)
1565 chunkdata = gen.deltachunk(chain)
1544 if not chunkdata:
1566 if not chunkdata:
1545 break
1567 break
1546 node = chunkdata['node']
1568 node = chunkdata['node']
1547 p1 = chunkdata['p1']
1569 p1 = chunkdata['p1']
1548 p2 = chunkdata['p2']
1570 p2 = chunkdata['p2']
1549 cs = chunkdata['cs']
1571 cs = chunkdata['cs']
1550 deltabase = chunkdata['deltabase']
1572 deltabase = chunkdata['deltabase']
1551 delta = chunkdata['delta']
1573 delta = chunkdata['delta']
1552 ui.write("%s %s %s %s %s %s\n" %
1574 ui.write("%s %s %s %s %s %s\n" %
1553 (hex(node), hex(p1), hex(p2),
1575 (hex(node), hex(p1), hex(p2),
1554 hex(cs), hex(deltabase), len(delta)))
1576 hex(cs), hex(deltabase), len(delta)))
1555 chain = node
1577 chain = node
1556
1578
1557 chunkdata = gen.changelogheader()
1579 chunkdata = gen.changelogheader()
1558 showchunks("changelog")
1580 showchunks("changelog")
1559 chunkdata = gen.manifestheader()
1581 chunkdata = gen.manifestheader()
1560 showchunks("manifest")
1582 showchunks("manifest")
1561 while True:
1583 while True:
1562 chunkdata = gen.filelogheader()
1584 chunkdata = gen.filelogheader()
1563 if not chunkdata:
1585 if not chunkdata:
1564 break
1586 break
1565 fname = chunkdata['filename']
1587 fname = chunkdata['filename']
1566 showchunks(fname)
1588 showchunks(fname)
1567 else:
1589 else:
1568 chunkdata = gen.changelogheader()
1590 chunkdata = gen.changelogheader()
1569 chain = None
1591 chain = None
1570 while True:
1592 while True:
1571 chunkdata = gen.deltachunk(chain)
1593 chunkdata = gen.deltachunk(chain)
1572 if not chunkdata:
1594 if not chunkdata:
1573 break
1595 break
1574 node = chunkdata['node']
1596 node = chunkdata['node']
1575 ui.write("%s\n" % hex(node))
1597 ui.write("%s\n" % hex(node))
1576 chain = node
1598 chain = node
1577 finally:
1599 finally:
1578 f.close()
1600 f.close()
1579
1601
1580 @command('debugcheckstate', [], '')
1602 @command('debugcheckstate', [], '')
1581 def debugcheckstate(ui, repo):
1603 def debugcheckstate(ui, repo):
1582 """validate the correctness of the current dirstate"""
1604 """validate the correctness of the current dirstate"""
1583 parent1, parent2 = repo.dirstate.parents()
1605 parent1, parent2 = repo.dirstate.parents()
1584 m1 = repo[parent1].manifest()
1606 m1 = repo[parent1].manifest()
1585 m2 = repo[parent2].manifest()
1607 m2 = repo[parent2].manifest()
1586 errors = 0
1608 errors = 0
1587 for f in repo.dirstate:
1609 for f in repo.dirstate:
1588 state = repo.dirstate[f]
1610 state = repo.dirstate[f]
1589 if state in "nr" and f not in m1:
1611 if state in "nr" and f not in m1:
1590 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1612 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1591 errors += 1
1613 errors += 1
1592 if state in "a" and f in m1:
1614 if state in "a" and f in m1:
1593 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1615 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1594 errors += 1
1616 errors += 1
1595 if state in "m" and f not in m1 and f not in m2:
1617 if state in "m" and f not in m1 and f not in m2:
1596 ui.warn(_("%s in state %s, but not in either manifest\n") %
1618 ui.warn(_("%s in state %s, but not in either manifest\n") %
1597 (f, state))
1619 (f, state))
1598 errors += 1
1620 errors += 1
1599 for f in m1:
1621 for f in m1:
1600 state = repo.dirstate[f]
1622 state = repo.dirstate[f]
1601 if state not in "nrm":
1623 if state not in "nrm":
1602 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1624 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1603 errors += 1
1625 errors += 1
1604 if errors:
1626 if errors:
1605 error = _(".hg/dirstate inconsistent with current parent's manifest")
1627 error = _(".hg/dirstate inconsistent with current parent's manifest")
1606 raise util.Abort(error)
1628 raise util.Abort(error)
1607
1629
1608 @command('debugcommands', [], _('[COMMAND]'))
1630 @command('debugcommands', [], _('[COMMAND]'))
1609 def debugcommands(ui, cmd='', *args):
1631 def debugcommands(ui, cmd='', *args):
1610 """list all available commands and options"""
1632 """list all available commands and options"""
1611 for cmd, vals in sorted(table.iteritems()):
1633 for cmd, vals in sorted(table.iteritems()):
1612 cmd = cmd.split('|')[0].strip('^')
1634 cmd = cmd.split('|')[0].strip('^')
1613 opts = ', '.join([i[1] for i in vals[1]])
1635 opts = ', '.join([i[1] for i in vals[1]])
1614 ui.write('%s: %s\n' % (cmd, opts))
1636 ui.write('%s: %s\n' % (cmd, opts))
1615
1637
1616 @command('debugcomplete',
1638 @command('debugcomplete',
1617 [('o', 'options', None, _('show the command options'))],
1639 [('o', 'options', None, _('show the command options'))],
1618 _('[-o] CMD'))
1640 _('[-o] CMD'))
1619 def debugcomplete(ui, cmd='', **opts):
1641 def debugcomplete(ui, cmd='', **opts):
1620 """returns the completion list associated with the given command"""
1642 """returns the completion list associated with the given command"""
1621
1643
1622 if opts.get('options'):
1644 if opts.get('options'):
1623 options = []
1645 options = []
1624 otables = [globalopts]
1646 otables = [globalopts]
1625 if cmd:
1647 if cmd:
1626 aliases, entry = cmdutil.findcmd(cmd, table, False)
1648 aliases, entry = cmdutil.findcmd(cmd, table, False)
1627 otables.append(entry[1])
1649 otables.append(entry[1])
1628 for t in otables:
1650 for t in otables:
1629 for o in t:
1651 for o in t:
1630 if "(DEPRECATED)" in o[3]:
1652 if "(DEPRECATED)" in o[3]:
1631 continue
1653 continue
1632 if o[0]:
1654 if o[0]:
1633 options.append('-%s' % o[0])
1655 options.append('-%s' % o[0])
1634 options.append('--%s' % o[1])
1656 options.append('--%s' % o[1])
1635 ui.write("%s\n" % "\n".join(options))
1657 ui.write("%s\n" % "\n".join(options))
1636 return
1658 return
1637
1659
1638 cmdlist = cmdutil.findpossible(cmd, table)
1660 cmdlist = cmdutil.findpossible(cmd, table)
1639 if ui.verbose:
1661 if ui.verbose:
1640 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1662 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1641 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1663 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1642
1664
1643 @command('debugdag',
1665 @command('debugdag',
1644 [('t', 'tags', None, _('use tags as labels')),
1666 [('t', 'tags', None, _('use tags as labels')),
1645 ('b', 'branches', None, _('annotate with branch names')),
1667 ('b', 'branches', None, _('annotate with branch names')),
1646 ('', 'dots', None, _('use dots for runs')),
1668 ('', 'dots', None, _('use dots for runs')),
1647 ('s', 'spaces', None, _('separate elements by spaces'))],
1669 ('s', 'spaces', None, _('separate elements by spaces'))],
1648 _('[OPTION]... [FILE [REV]...]'))
1670 _('[OPTION]... [FILE [REV]...]'))
1649 def debugdag(ui, repo, file_=None, *revs, **opts):
1671 def debugdag(ui, repo, file_=None, *revs, **opts):
1650 """format the changelog or an index DAG as a concise textual description
1672 """format the changelog or an index DAG as a concise textual description
1651
1673
1652 If you pass a revlog index, the revlog's DAG is emitted. If you list
1674 If you pass a revlog index, the revlog's DAG is emitted. If you list
1653 revision numbers, they get labelled in the output as rN.
1675 revision numbers, they get labelled in the output as rN.
1654
1676
1655 Otherwise, the changelog DAG of the current repo is emitted.
1677 Otherwise, the changelog DAG of the current repo is emitted.
1656 """
1678 """
1657 spaces = opts.get('spaces')
1679 spaces = opts.get('spaces')
1658 dots = opts.get('dots')
1680 dots = opts.get('dots')
1659 if file_:
1681 if file_:
1660 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1682 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1661 revs = set((int(r) for r in revs))
1683 revs = set((int(r) for r in revs))
1662 def events():
1684 def events():
1663 for r in rlog:
1685 for r in rlog:
1664 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1686 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1665 if r in revs:
1687 if r in revs:
1666 yield 'l', (r, "r%i" % r)
1688 yield 'l', (r, "r%i" % r)
1667 elif repo:
1689 elif repo:
1668 cl = repo.changelog
1690 cl = repo.changelog
1669 tags = opts.get('tags')
1691 tags = opts.get('tags')
1670 branches = opts.get('branches')
1692 branches = opts.get('branches')
1671 if tags:
1693 if tags:
1672 labels = {}
1694 labels = {}
1673 for l, n in repo.tags().items():
1695 for l, n in repo.tags().items():
1674 labels.setdefault(cl.rev(n), []).append(l)
1696 labels.setdefault(cl.rev(n), []).append(l)
1675 def events():
1697 def events():
1676 b = "default"
1698 b = "default"
1677 for r in cl:
1699 for r in cl:
1678 if branches:
1700 if branches:
1679 newb = cl.read(cl.node(r))[5]['branch']
1701 newb = cl.read(cl.node(r))[5]['branch']
1680 if newb != b:
1702 if newb != b:
1681 yield 'a', newb
1703 yield 'a', newb
1682 b = newb
1704 b = newb
1683 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1705 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1684 if tags:
1706 if tags:
1685 ls = labels.get(r)
1707 ls = labels.get(r)
1686 if ls:
1708 if ls:
1687 for l in ls:
1709 for l in ls:
1688 yield 'l', (r, l)
1710 yield 'l', (r, l)
1689 else:
1711 else:
1690 raise util.Abort(_('need repo for changelog dag'))
1712 raise util.Abort(_('need repo for changelog dag'))
1691
1713
1692 for line in dagparser.dagtextlines(events(),
1714 for line in dagparser.dagtextlines(events(),
1693 addspaces=spaces,
1715 addspaces=spaces,
1694 wraplabels=True,
1716 wraplabels=True,
1695 wrapannotations=True,
1717 wrapannotations=True,
1696 wrapnonlinear=dots,
1718 wrapnonlinear=dots,
1697 usedots=dots,
1719 usedots=dots,
1698 maxlinewidth=70):
1720 maxlinewidth=70):
1699 ui.write(line)
1721 ui.write(line)
1700 ui.write("\n")
1722 ui.write("\n")
1701
1723
1702 @command('debugdata',
1724 @command('debugdata',
1703 [('c', 'changelog', False, _('open changelog')),
1725 [('c', 'changelog', False, _('open changelog')),
1704 ('m', 'manifest', False, _('open manifest'))],
1726 ('m', 'manifest', False, _('open manifest'))],
1705 _('-c|-m|FILE REV'))
1727 _('-c|-m|FILE REV'))
1706 def debugdata(ui, repo, file_, rev = None, **opts):
1728 def debugdata(ui, repo, file_, rev = None, **opts):
1707 """dump the contents of a data file revision"""
1729 """dump the contents of a data file revision"""
1708 if opts.get('changelog') or opts.get('manifest'):
1730 if opts.get('changelog') or opts.get('manifest'):
1709 file_, rev = None, file_
1731 file_, rev = None, file_
1710 elif rev is None:
1732 elif rev is None:
1711 raise error.CommandError('debugdata', _('invalid arguments'))
1733 raise error.CommandError('debugdata', _('invalid arguments'))
1712 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1734 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1713 try:
1735 try:
1714 ui.write(r.revision(r.lookup(rev)))
1736 ui.write(r.revision(r.lookup(rev)))
1715 except KeyError:
1737 except KeyError:
1716 raise util.Abort(_('invalid revision identifier %s') % rev)
1738 raise util.Abort(_('invalid revision identifier %s') % rev)
1717
1739
1718 @command('debugdate',
1740 @command('debugdate',
1719 [('e', 'extended', None, _('try extended date formats'))],
1741 [('e', 'extended', None, _('try extended date formats'))],
1720 _('[-e] DATE [RANGE]'))
1742 _('[-e] DATE [RANGE]'))
1721 def debugdate(ui, date, range=None, **opts):
1743 def debugdate(ui, date, range=None, **opts):
1722 """parse and display a date"""
1744 """parse and display a date"""
1723 if opts["extended"]:
1745 if opts["extended"]:
1724 d = util.parsedate(date, util.extendeddateformats)
1746 d = util.parsedate(date, util.extendeddateformats)
1725 else:
1747 else:
1726 d = util.parsedate(date)
1748 d = util.parsedate(date)
1727 ui.write("internal: %s %s\n" % d)
1749 ui.write("internal: %s %s\n" % d)
1728 ui.write("standard: %s\n" % util.datestr(d))
1750 ui.write("standard: %s\n" % util.datestr(d))
1729 if range:
1751 if range:
1730 m = util.matchdate(range)
1752 m = util.matchdate(range)
1731 ui.write("match: %s\n" % m(d[0]))
1753 ui.write("match: %s\n" % m(d[0]))
1732
1754
1733 @command('debugdiscovery',
1755 @command('debugdiscovery',
1734 [('', 'old', None, _('use old-style discovery')),
1756 [('', 'old', None, _('use old-style discovery')),
1735 ('', 'nonheads', None,
1757 ('', 'nonheads', None,
1736 _('use old-style discovery with non-heads included')),
1758 _('use old-style discovery with non-heads included')),
1737 ] + remoteopts,
1759 ] + remoteopts,
1738 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1760 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1739 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1761 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1740 """runs the changeset discovery protocol in isolation"""
1762 """runs the changeset discovery protocol in isolation"""
1741 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1763 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1742 remote = hg.peer(repo, opts, remoteurl)
1764 remote = hg.peer(repo, opts, remoteurl)
1743 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1765 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1744
1766
1745 # make sure tests are repeatable
1767 # make sure tests are repeatable
1746 random.seed(12323)
1768 random.seed(12323)
1747
1769
1748 def doit(localheads, remoteheads):
1770 def doit(localheads, remoteheads):
1749 if opts.get('old'):
1771 if opts.get('old'):
1750 if localheads:
1772 if localheads:
1751 raise util.Abort('cannot use localheads with old style discovery')
1773 raise util.Abort('cannot use localheads with old style discovery')
1752 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1774 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1753 force=True)
1775 force=True)
1754 common = set(common)
1776 common = set(common)
1755 if not opts.get('nonheads'):
1777 if not opts.get('nonheads'):
1756 ui.write("unpruned common: %s\n" % " ".join([short(n)
1778 ui.write("unpruned common: %s\n" % " ".join([short(n)
1757 for n in common]))
1779 for n in common]))
1758 dag = dagutil.revlogdag(repo.changelog)
1780 dag = dagutil.revlogdag(repo.changelog)
1759 all = dag.ancestorset(dag.internalizeall(common))
1781 all = dag.ancestorset(dag.internalizeall(common))
1760 common = dag.externalizeall(dag.headsetofconnecteds(all))
1782 common = dag.externalizeall(dag.headsetofconnecteds(all))
1761 else:
1783 else:
1762 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1784 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1763 common = set(common)
1785 common = set(common)
1764 rheads = set(hds)
1786 rheads = set(hds)
1765 lheads = set(repo.heads())
1787 lheads = set(repo.heads())
1766 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1788 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1767 if lheads <= common:
1789 if lheads <= common:
1768 ui.write("local is subset\n")
1790 ui.write("local is subset\n")
1769 elif rheads <= common:
1791 elif rheads <= common:
1770 ui.write("remote is subset\n")
1792 ui.write("remote is subset\n")
1771
1793
1772 serverlogs = opts.get('serverlog')
1794 serverlogs = opts.get('serverlog')
1773 if serverlogs:
1795 if serverlogs:
1774 for filename in serverlogs:
1796 for filename in serverlogs:
1775 logfile = open(filename, 'r')
1797 logfile = open(filename, 'r')
1776 try:
1798 try:
1777 line = logfile.readline()
1799 line = logfile.readline()
1778 while line:
1800 while line:
1779 parts = line.strip().split(';')
1801 parts = line.strip().split(';')
1780 op = parts[1]
1802 op = parts[1]
1781 if op == 'cg':
1803 if op == 'cg':
1782 pass
1804 pass
1783 elif op == 'cgss':
1805 elif op == 'cgss':
1784 doit(parts[2].split(' '), parts[3].split(' '))
1806 doit(parts[2].split(' '), parts[3].split(' '))
1785 elif op == 'unb':
1807 elif op == 'unb':
1786 doit(parts[3].split(' '), parts[2].split(' '))
1808 doit(parts[3].split(' '), parts[2].split(' '))
1787 line = logfile.readline()
1809 line = logfile.readline()
1788 finally:
1810 finally:
1789 logfile.close()
1811 logfile.close()
1790
1812
1791 else:
1813 else:
1792 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1814 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1793 opts.get('remote_head'))
1815 opts.get('remote_head'))
1794 localrevs = opts.get('local_head')
1816 localrevs = opts.get('local_head')
1795 doit(localrevs, remoterevs)
1817 doit(localrevs, remoterevs)
1796
1818
1797 @command('debugfileset', [], ('REVSPEC'))
1819 @command('debugfileset', [], ('REVSPEC'))
1798 def debugfileset(ui, repo, expr):
1820 def debugfileset(ui, repo, expr):
1799 '''parse and apply a fileset specification'''
1821 '''parse and apply a fileset specification'''
1800 if ui.verbose:
1822 if ui.verbose:
1801 tree = fileset.parse(expr)[0]
1823 tree = fileset.parse(expr)[0]
1802 ui.note(tree, "\n")
1824 ui.note(tree, "\n")
1803
1825
1804 for f in fileset.getfileset(repo[None], expr):
1826 for f in fileset.getfileset(repo[None], expr):
1805 ui.write("%s\n" % f)
1827 ui.write("%s\n" % f)
1806
1828
1807 @command('debugfsinfo', [], _('[PATH]'))
1829 @command('debugfsinfo', [], _('[PATH]'))
1808 def debugfsinfo(ui, path = "."):
1830 def debugfsinfo(ui, path = "."):
1809 """show information detected about current filesystem"""
1831 """show information detected about current filesystem"""
1810 util.writefile('.debugfsinfo', '')
1832 util.writefile('.debugfsinfo', '')
1811 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1833 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1812 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1834 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1813 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1835 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1814 and 'yes' or 'no'))
1836 and 'yes' or 'no'))
1815 os.unlink('.debugfsinfo')
1837 os.unlink('.debugfsinfo')
1816
1838
1817 @command('debuggetbundle',
1839 @command('debuggetbundle',
1818 [('H', 'head', [], _('id of head node'), _('ID')),
1840 [('H', 'head', [], _('id of head node'), _('ID')),
1819 ('C', 'common', [], _('id of common node'), _('ID')),
1841 ('C', 'common', [], _('id of common node'), _('ID')),
1820 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1842 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1821 _('REPO FILE [-H|-C ID]...'))
1843 _('REPO FILE [-H|-C ID]...'))
1822 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1844 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1823 """retrieves a bundle from a repo
1845 """retrieves a bundle from a repo
1824
1846
1825 Every ID must be a full-length hex node id string. Saves the bundle to the
1847 Every ID must be a full-length hex node id string. Saves the bundle to the
1826 given file.
1848 given file.
1827 """
1849 """
1828 repo = hg.peer(ui, opts, repopath)
1850 repo = hg.peer(ui, opts, repopath)
1829 if not repo.capable('getbundle'):
1851 if not repo.capable('getbundle'):
1830 raise util.Abort("getbundle() not supported by target repository")
1852 raise util.Abort("getbundle() not supported by target repository")
1831 args = {}
1853 args = {}
1832 if common:
1854 if common:
1833 args['common'] = [bin(s) for s in common]
1855 args['common'] = [bin(s) for s in common]
1834 if head:
1856 if head:
1835 args['heads'] = [bin(s) for s in head]
1857 args['heads'] = [bin(s) for s in head]
1836 bundle = repo.getbundle('debug', **args)
1858 bundle = repo.getbundle('debug', **args)
1837
1859
1838 bundletype = opts.get('type', 'bzip2').lower()
1860 bundletype = opts.get('type', 'bzip2').lower()
1839 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1861 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1840 bundletype = btypes.get(bundletype)
1862 bundletype = btypes.get(bundletype)
1841 if bundletype not in changegroup.bundletypes:
1863 if bundletype not in changegroup.bundletypes:
1842 raise util.Abort(_('unknown bundle type specified with --type'))
1864 raise util.Abort(_('unknown bundle type specified with --type'))
1843 changegroup.writebundle(bundle, bundlepath, bundletype)
1865 changegroup.writebundle(bundle, bundlepath, bundletype)
1844
1866
1845 @command('debugignore', [], '')
1867 @command('debugignore', [], '')
1846 def debugignore(ui, repo, *values, **opts):
1868 def debugignore(ui, repo, *values, **opts):
1847 """display the combined ignore pattern"""
1869 """display the combined ignore pattern"""
1848 ignore = repo.dirstate._ignore
1870 ignore = repo.dirstate._ignore
1849 includepat = getattr(ignore, 'includepat', None)
1871 includepat = getattr(ignore, 'includepat', None)
1850 if includepat is not None:
1872 if includepat is not None:
1851 ui.write("%s\n" % includepat)
1873 ui.write("%s\n" % includepat)
1852 else:
1874 else:
1853 raise util.Abort(_("no ignore patterns found"))
1875 raise util.Abort(_("no ignore patterns found"))
1854
1876
1855 @command('debugindex',
1877 @command('debugindex',
1856 [('c', 'changelog', False, _('open changelog')),
1878 [('c', 'changelog', False, _('open changelog')),
1857 ('m', 'manifest', False, _('open manifest')),
1879 ('m', 'manifest', False, _('open manifest')),
1858 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1880 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1859 _('[-f FORMAT] -c|-m|FILE'))
1881 _('[-f FORMAT] -c|-m|FILE'))
1860 def debugindex(ui, repo, file_ = None, **opts):
1882 def debugindex(ui, repo, file_ = None, **opts):
1861 """dump the contents of an index file"""
1883 """dump the contents of an index file"""
1862 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1884 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1863 format = opts.get('format', 0)
1885 format = opts.get('format', 0)
1864 if format not in (0, 1):
1886 if format not in (0, 1):
1865 raise util.Abort(_("unknown format %d") % format)
1887 raise util.Abort(_("unknown format %d") % format)
1866
1888
1867 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1889 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1868 if generaldelta:
1890 if generaldelta:
1869 basehdr = ' delta'
1891 basehdr = ' delta'
1870 else:
1892 else:
1871 basehdr = ' base'
1893 basehdr = ' base'
1872
1894
1873 if format == 0:
1895 if format == 0:
1874 ui.write(" rev offset length " + basehdr + " linkrev"
1896 ui.write(" rev offset length " + basehdr + " linkrev"
1875 " nodeid p1 p2\n")
1897 " nodeid p1 p2\n")
1876 elif format == 1:
1898 elif format == 1:
1877 ui.write(" rev flag offset length"
1899 ui.write(" rev flag offset length"
1878 " size " + basehdr + " link p1 p2 nodeid\n")
1900 " size " + basehdr + " link p1 p2 nodeid\n")
1879
1901
1880 for i in r:
1902 for i in r:
1881 node = r.node(i)
1903 node = r.node(i)
1882 if generaldelta:
1904 if generaldelta:
1883 base = r.deltaparent(i)
1905 base = r.deltaparent(i)
1884 else:
1906 else:
1885 base = r.chainbase(i)
1907 base = r.chainbase(i)
1886 if format == 0:
1908 if format == 0:
1887 try:
1909 try:
1888 pp = r.parents(node)
1910 pp = r.parents(node)
1889 except:
1911 except:
1890 pp = [nullid, nullid]
1912 pp = [nullid, nullid]
1891 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1913 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1892 i, r.start(i), r.length(i), base, r.linkrev(i),
1914 i, r.start(i), r.length(i), base, r.linkrev(i),
1893 short(node), short(pp[0]), short(pp[1])))
1915 short(node), short(pp[0]), short(pp[1])))
1894 elif format == 1:
1916 elif format == 1:
1895 pr = r.parentrevs(i)
1917 pr = r.parentrevs(i)
1896 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1918 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1897 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1919 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1898 base, r.linkrev(i), pr[0], pr[1], short(node)))
1920 base, r.linkrev(i), pr[0], pr[1], short(node)))
1899
1921
1900 @command('debugindexdot', [], _('FILE'))
1922 @command('debugindexdot', [], _('FILE'))
1901 def debugindexdot(ui, repo, file_):
1923 def debugindexdot(ui, repo, file_):
1902 """dump an index DAG as a graphviz dot file"""
1924 """dump an index DAG as a graphviz dot file"""
1903 r = None
1925 r = None
1904 if repo:
1926 if repo:
1905 filelog = repo.file(file_)
1927 filelog = repo.file(file_)
1906 if len(filelog):
1928 if len(filelog):
1907 r = filelog
1929 r = filelog
1908 if not r:
1930 if not r:
1909 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1931 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1910 ui.write("digraph G {\n")
1932 ui.write("digraph G {\n")
1911 for i in r:
1933 for i in r:
1912 node = r.node(i)
1934 node = r.node(i)
1913 pp = r.parents(node)
1935 pp = r.parents(node)
1914 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1936 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1915 if pp[1] != nullid:
1937 if pp[1] != nullid:
1916 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1938 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1917 ui.write("}\n")
1939 ui.write("}\n")
1918
1940
1919 @command('debuginstall', [], '')
1941 @command('debuginstall', [], '')
1920 def debuginstall(ui):
1942 def debuginstall(ui):
1921 '''test Mercurial installation
1943 '''test Mercurial installation
1922
1944
1923 Returns 0 on success.
1945 Returns 0 on success.
1924 '''
1946 '''
1925
1947
1926 def writetemp(contents):
1948 def writetemp(contents):
1927 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1949 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1928 f = os.fdopen(fd, "wb")
1950 f = os.fdopen(fd, "wb")
1929 f.write(contents)
1951 f.write(contents)
1930 f.close()
1952 f.close()
1931 return name
1953 return name
1932
1954
1933 problems = 0
1955 problems = 0
1934
1956
1935 # encoding
1957 # encoding
1936 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1958 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1937 try:
1959 try:
1938 encoding.fromlocal("test")
1960 encoding.fromlocal("test")
1939 except util.Abort, inst:
1961 except util.Abort, inst:
1940 ui.write(" %s\n" % inst)
1962 ui.write(" %s\n" % inst)
1941 ui.write(_(" (check that your locale is properly set)\n"))
1963 ui.write(_(" (check that your locale is properly set)\n"))
1942 problems += 1
1964 problems += 1
1943
1965
1944 # compiled modules
1966 # compiled modules
1945 ui.status(_("Checking installed modules (%s)...\n")
1967 ui.status(_("Checking installed modules (%s)...\n")
1946 % os.path.dirname(__file__))
1968 % os.path.dirname(__file__))
1947 try:
1969 try:
1948 import bdiff, mpatch, base85, osutil
1970 import bdiff, mpatch, base85, osutil
1949 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1971 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1950 except Exception, inst:
1972 except Exception, inst:
1951 ui.write(" %s\n" % inst)
1973 ui.write(" %s\n" % inst)
1952 ui.write(_(" One or more extensions could not be found"))
1974 ui.write(_(" One or more extensions could not be found"))
1953 ui.write(_(" (check that you compiled the extensions)\n"))
1975 ui.write(_(" (check that you compiled the extensions)\n"))
1954 problems += 1
1976 problems += 1
1955
1977
1956 # templates
1978 # templates
1957 import templater
1979 import templater
1958 p = templater.templatepath()
1980 p = templater.templatepath()
1959 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1981 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1960 try:
1982 try:
1961 templater.templater(templater.templatepath("map-cmdline.default"))
1983 templater.templater(templater.templatepath("map-cmdline.default"))
1962 except Exception, inst:
1984 except Exception, inst:
1963 ui.write(" %s\n" % inst)
1985 ui.write(" %s\n" % inst)
1964 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1986 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1965 problems += 1
1987 problems += 1
1966
1988
1967 # editor
1989 # editor
1968 ui.status(_("Checking commit editor...\n"))
1990 ui.status(_("Checking commit editor...\n"))
1969 editor = ui.geteditor()
1991 editor = ui.geteditor()
1970 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1992 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1971 if not cmdpath:
1993 if not cmdpath:
1972 if editor == 'vi':
1994 if editor == 'vi':
1973 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1995 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1974 ui.write(_(" (specify a commit editor in your configuration"
1996 ui.write(_(" (specify a commit editor in your configuration"
1975 " file)\n"))
1997 " file)\n"))
1976 else:
1998 else:
1977 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1999 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1978 ui.write(_(" (specify a commit editor in your configuration"
2000 ui.write(_(" (specify a commit editor in your configuration"
1979 " file)\n"))
2001 " file)\n"))
1980 problems += 1
2002 problems += 1
1981
2003
1982 # check username
2004 # check username
1983 ui.status(_("Checking username...\n"))
2005 ui.status(_("Checking username...\n"))
1984 try:
2006 try:
1985 ui.username()
2007 ui.username()
1986 except util.Abort, e:
2008 except util.Abort, e:
1987 ui.write(" %s\n" % e)
2009 ui.write(" %s\n" % e)
1988 ui.write(_(" (specify a username in your configuration file)\n"))
2010 ui.write(_(" (specify a username in your configuration file)\n"))
1989 problems += 1
2011 problems += 1
1990
2012
1991 if not problems:
2013 if not problems:
1992 ui.status(_("No problems detected\n"))
2014 ui.status(_("No problems detected\n"))
1993 else:
2015 else:
1994 ui.write(_("%s problems detected,"
2016 ui.write(_("%s problems detected,"
1995 " please check your install!\n") % problems)
2017 " please check your install!\n") % problems)
1996
2018
1997 return problems
2019 return problems
1998
2020
1999 @command('debugknown', [], _('REPO ID...'))
2021 @command('debugknown', [], _('REPO ID...'))
2000 def debugknown(ui, repopath, *ids, **opts):
2022 def debugknown(ui, repopath, *ids, **opts):
2001 """test whether node ids are known to a repo
2023 """test whether node ids are known to a repo
2002
2024
2003 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
2025 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
2004 indicating unknown/known.
2026 indicating unknown/known.
2005 """
2027 """
2006 repo = hg.peer(ui, opts, repopath)
2028 repo = hg.peer(ui, opts, repopath)
2007 if not repo.capable('known'):
2029 if not repo.capable('known'):
2008 raise util.Abort("known() not supported by target repository")
2030 raise util.Abort("known() not supported by target repository")
2009 flags = repo.known([bin(s) for s in ids])
2031 flags = repo.known([bin(s) for s in ids])
2010 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2032 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2011
2033
2012 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2034 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2013 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2035 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2014 '''access the pushkey key/value protocol
2036 '''access the pushkey key/value protocol
2015
2037
2016 With two args, list the keys in the given namespace.
2038 With two args, list the keys in the given namespace.
2017
2039
2018 With five args, set a key to new if it currently is set to old.
2040 With five args, set a key to new if it currently is set to old.
2019 Reports success or failure.
2041 Reports success or failure.
2020 '''
2042 '''
2021
2043
2022 target = hg.peer(ui, {}, repopath)
2044 target = hg.peer(ui, {}, repopath)
2023 if keyinfo:
2045 if keyinfo:
2024 key, old, new = keyinfo
2046 key, old, new = keyinfo
2025 r = target.pushkey(namespace, key, old, new)
2047 r = target.pushkey(namespace, key, old, new)
2026 ui.status(str(r) + '\n')
2048 ui.status(str(r) + '\n')
2027 return not r
2049 return not r
2028 else:
2050 else:
2029 for k, v in target.listkeys(namespace).iteritems():
2051 for k, v in target.listkeys(namespace).iteritems():
2030 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2052 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2031 v.encode('string-escape')))
2053 v.encode('string-escape')))
2032
2054
2033 @command('debugpvec', [], _('A B'))
2055 @command('debugpvec', [], _('A B'))
2034 def debugpvec(ui, repo, a, b=None):
2056 def debugpvec(ui, repo, a, b=None):
2035 ca = scmutil.revsingle(repo, a)
2057 ca = scmutil.revsingle(repo, a)
2036 cb = scmutil.revsingle(repo, b)
2058 cb = scmutil.revsingle(repo, b)
2037 pa = pvec.ctxpvec(ca)
2059 pa = pvec.ctxpvec(ca)
2038 pb = pvec.ctxpvec(cb)
2060 pb = pvec.ctxpvec(cb)
2039 if pa == pb:
2061 if pa == pb:
2040 rel = "="
2062 rel = "="
2041 elif pa > pb:
2063 elif pa > pb:
2042 rel = ">"
2064 rel = ">"
2043 elif pa < pb:
2065 elif pa < pb:
2044 rel = "<"
2066 rel = "<"
2045 elif pa | pb:
2067 elif pa | pb:
2046 rel = "|"
2068 rel = "|"
2047 ui.write(_("a: %s\n") % pa)
2069 ui.write(_("a: %s\n") % pa)
2048 ui.write(_("b: %s\n") % pb)
2070 ui.write(_("b: %s\n") % pb)
2049 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2071 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2050 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2072 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2051 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2073 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2052 pa.distance(pb), rel))
2074 pa.distance(pb), rel))
2053
2075
2054 @command('debugrebuildstate',
2076 @command('debugrebuildstate',
2055 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2077 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2056 _('[-r REV] [REV]'))
2078 _('[-r REV] [REV]'))
2057 def debugrebuildstate(ui, repo, rev="tip"):
2079 def debugrebuildstate(ui, repo, rev="tip"):
2058 """rebuild the dirstate as it would look like for the given revision"""
2080 """rebuild the dirstate as it would look like for the given revision"""
2059 ctx = scmutil.revsingle(repo, rev)
2081 ctx = scmutil.revsingle(repo, rev)
2060 wlock = repo.wlock()
2082 wlock = repo.wlock()
2061 try:
2083 try:
2062 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2084 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2063 finally:
2085 finally:
2064 wlock.release()
2086 wlock.release()
2065
2087
2066 @command('debugrename',
2088 @command('debugrename',
2067 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2089 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2068 _('[-r REV] FILE'))
2090 _('[-r REV] FILE'))
2069 def debugrename(ui, repo, file1, *pats, **opts):
2091 def debugrename(ui, repo, file1, *pats, **opts):
2070 """dump rename information"""
2092 """dump rename information"""
2071
2093
2072 ctx = scmutil.revsingle(repo, opts.get('rev'))
2094 ctx = scmutil.revsingle(repo, opts.get('rev'))
2073 m = scmutil.match(ctx, (file1,) + pats, opts)
2095 m = scmutil.match(ctx, (file1,) + pats, opts)
2074 for abs in ctx.walk(m):
2096 for abs in ctx.walk(m):
2075 fctx = ctx[abs]
2097 fctx = ctx[abs]
2076 o = fctx.filelog().renamed(fctx.filenode())
2098 o = fctx.filelog().renamed(fctx.filenode())
2077 rel = m.rel(abs)
2099 rel = m.rel(abs)
2078 if o:
2100 if o:
2079 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2101 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2080 else:
2102 else:
2081 ui.write(_("%s not renamed\n") % rel)
2103 ui.write(_("%s not renamed\n") % rel)
2082
2104
2083 @command('debugrevlog',
2105 @command('debugrevlog',
2084 [('c', 'changelog', False, _('open changelog')),
2106 [('c', 'changelog', False, _('open changelog')),
2085 ('m', 'manifest', False, _('open manifest')),
2107 ('m', 'manifest', False, _('open manifest')),
2086 ('d', 'dump', False, _('dump index data'))],
2108 ('d', 'dump', False, _('dump index data'))],
2087 _('-c|-m|FILE'))
2109 _('-c|-m|FILE'))
2088 def debugrevlog(ui, repo, file_ = None, **opts):
2110 def debugrevlog(ui, repo, file_ = None, **opts):
2089 """show data and statistics about a revlog"""
2111 """show data and statistics about a revlog"""
2090 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2112 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2091
2113
2092 if opts.get("dump"):
2114 if opts.get("dump"):
2093 numrevs = len(r)
2115 numrevs = len(r)
2094 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2116 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2095 " rawsize totalsize compression heads\n")
2117 " rawsize totalsize compression heads\n")
2096 ts = 0
2118 ts = 0
2097 heads = set()
2119 heads = set()
2098 for rev in xrange(numrevs):
2120 for rev in xrange(numrevs):
2099 dbase = r.deltaparent(rev)
2121 dbase = r.deltaparent(rev)
2100 if dbase == -1:
2122 if dbase == -1:
2101 dbase = rev
2123 dbase = rev
2102 cbase = r.chainbase(rev)
2124 cbase = r.chainbase(rev)
2103 p1, p2 = r.parentrevs(rev)
2125 p1, p2 = r.parentrevs(rev)
2104 rs = r.rawsize(rev)
2126 rs = r.rawsize(rev)
2105 ts = ts + rs
2127 ts = ts + rs
2106 heads -= set(r.parentrevs(rev))
2128 heads -= set(r.parentrevs(rev))
2107 heads.add(rev)
2129 heads.add(rev)
2108 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2130 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2109 (rev, p1, p2, r.start(rev), r.end(rev),
2131 (rev, p1, p2, r.start(rev), r.end(rev),
2110 r.start(dbase), r.start(cbase),
2132 r.start(dbase), r.start(cbase),
2111 r.start(p1), r.start(p2),
2133 r.start(p1), r.start(p2),
2112 rs, ts, ts / r.end(rev), len(heads)))
2134 rs, ts, ts / r.end(rev), len(heads)))
2113 return 0
2135 return 0
2114
2136
2115 v = r.version
2137 v = r.version
2116 format = v & 0xFFFF
2138 format = v & 0xFFFF
2117 flags = []
2139 flags = []
2118 gdelta = False
2140 gdelta = False
2119 if v & revlog.REVLOGNGINLINEDATA:
2141 if v & revlog.REVLOGNGINLINEDATA:
2120 flags.append('inline')
2142 flags.append('inline')
2121 if v & revlog.REVLOGGENERALDELTA:
2143 if v & revlog.REVLOGGENERALDELTA:
2122 gdelta = True
2144 gdelta = True
2123 flags.append('generaldelta')
2145 flags.append('generaldelta')
2124 if not flags:
2146 if not flags:
2125 flags = ['(none)']
2147 flags = ['(none)']
2126
2148
2127 nummerges = 0
2149 nummerges = 0
2128 numfull = 0
2150 numfull = 0
2129 numprev = 0
2151 numprev = 0
2130 nump1 = 0
2152 nump1 = 0
2131 nump2 = 0
2153 nump2 = 0
2132 numother = 0
2154 numother = 0
2133 nump1prev = 0
2155 nump1prev = 0
2134 nump2prev = 0
2156 nump2prev = 0
2135 chainlengths = []
2157 chainlengths = []
2136
2158
2137 datasize = [None, 0, 0L]
2159 datasize = [None, 0, 0L]
2138 fullsize = [None, 0, 0L]
2160 fullsize = [None, 0, 0L]
2139 deltasize = [None, 0, 0L]
2161 deltasize = [None, 0, 0L]
2140
2162
2141 def addsize(size, l):
2163 def addsize(size, l):
2142 if l[0] is None or size < l[0]:
2164 if l[0] is None or size < l[0]:
2143 l[0] = size
2165 l[0] = size
2144 if size > l[1]:
2166 if size > l[1]:
2145 l[1] = size
2167 l[1] = size
2146 l[2] += size
2168 l[2] += size
2147
2169
2148 numrevs = len(r)
2170 numrevs = len(r)
2149 for rev in xrange(numrevs):
2171 for rev in xrange(numrevs):
2150 p1, p2 = r.parentrevs(rev)
2172 p1, p2 = r.parentrevs(rev)
2151 delta = r.deltaparent(rev)
2173 delta = r.deltaparent(rev)
2152 if format > 0:
2174 if format > 0:
2153 addsize(r.rawsize(rev), datasize)
2175 addsize(r.rawsize(rev), datasize)
2154 if p2 != nullrev:
2176 if p2 != nullrev:
2155 nummerges += 1
2177 nummerges += 1
2156 size = r.length(rev)
2178 size = r.length(rev)
2157 if delta == nullrev:
2179 if delta == nullrev:
2158 chainlengths.append(0)
2180 chainlengths.append(0)
2159 numfull += 1
2181 numfull += 1
2160 addsize(size, fullsize)
2182 addsize(size, fullsize)
2161 else:
2183 else:
2162 chainlengths.append(chainlengths[delta] + 1)
2184 chainlengths.append(chainlengths[delta] + 1)
2163 addsize(size, deltasize)
2185 addsize(size, deltasize)
2164 if delta == rev - 1:
2186 if delta == rev - 1:
2165 numprev += 1
2187 numprev += 1
2166 if delta == p1:
2188 if delta == p1:
2167 nump1prev += 1
2189 nump1prev += 1
2168 elif delta == p2:
2190 elif delta == p2:
2169 nump2prev += 1
2191 nump2prev += 1
2170 elif delta == p1:
2192 elif delta == p1:
2171 nump1 += 1
2193 nump1 += 1
2172 elif delta == p2:
2194 elif delta == p2:
2173 nump2 += 1
2195 nump2 += 1
2174 elif delta != nullrev:
2196 elif delta != nullrev:
2175 numother += 1
2197 numother += 1
2176
2198
2177 numdeltas = numrevs - numfull
2199 numdeltas = numrevs - numfull
2178 numoprev = numprev - nump1prev - nump2prev
2200 numoprev = numprev - nump1prev - nump2prev
2179 totalrawsize = datasize[2]
2201 totalrawsize = datasize[2]
2180 datasize[2] /= numrevs
2202 datasize[2] /= numrevs
2181 fulltotal = fullsize[2]
2203 fulltotal = fullsize[2]
2182 fullsize[2] /= numfull
2204 fullsize[2] /= numfull
2183 deltatotal = deltasize[2]
2205 deltatotal = deltasize[2]
2184 deltasize[2] /= numrevs - numfull
2206 deltasize[2] /= numrevs - numfull
2185 totalsize = fulltotal + deltatotal
2207 totalsize = fulltotal + deltatotal
2186 avgchainlen = sum(chainlengths) / numrevs
2208 avgchainlen = sum(chainlengths) / numrevs
2187 compratio = totalrawsize / totalsize
2209 compratio = totalrawsize / totalsize
2188
2210
2189 basedfmtstr = '%%%dd\n'
2211 basedfmtstr = '%%%dd\n'
2190 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2212 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2191
2213
2192 def dfmtstr(max):
2214 def dfmtstr(max):
2193 return basedfmtstr % len(str(max))
2215 return basedfmtstr % len(str(max))
2194 def pcfmtstr(max, padding=0):
2216 def pcfmtstr(max, padding=0):
2195 return basepcfmtstr % (len(str(max)), ' ' * padding)
2217 return basepcfmtstr % (len(str(max)), ' ' * padding)
2196
2218
2197 def pcfmt(value, total):
2219 def pcfmt(value, total):
2198 return (value, 100 * float(value) / total)
2220 return (value, 100 * float(value) / total)
2199
2221
2200 ui.write('format : %d\n' % format)
2222 ui.write('format : %d\n' % format)
2201 ui.write('flags : %s\n' % ', '.join(flags))
2223 ui.write('flags : %s\n' % ', '.join(flags))
2202
2224
2203 ui.write('\n')
2225 ui.write('\n')
2204 fmt = pcfmtstr(totalsize)
2226 fmt = pcfmtstr(totalsize)
2205 fmt2 = dfmtstr(totalsize)
2227 fmt2 = dfmtstr(totalsize)
2206 ui.write('revisions : ' + fmt2 % numrevs)
2228 ui.write('revisions : ' + fmt2 % numrevs)
2207 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2229 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2208 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2230 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2209 ui.write('revisions : ' + fmt2 % numrevs)
2231 ui.write('revisions : ' + fmt2 % numrevs)
2210 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2232 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2211 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2233 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2212 ui.write('revision size : ' + fmt2 % totalsize)
2234 ui.write('revision size : ' + fmt2 % totalsize)
2213 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2235 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2214 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2236 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2215
2237
2216 ui.write('\n')
2238 ui.write('\n')
2217 fmt = dfmtstr(max(avgchainlen, compratio))
2239 fmt = dfmtstr(max(avgchainlen, compratio))
2218 ui.write('avg chain length : ' + fmt % avgchainlen)
2240 ui.write('avg chain length : ' + fmt % avgchainlen)
2219 ui.write('compression ratio : ' + fmt % compratio)
2241 ui.write('compression ratio : ' + fmt % compratio)
2220
2242
2221 if format > 0:
2243 if format > 0:
2222 ui.write('\n')
2244 ui.write('\n')
2223 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2245 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2224 % tuple(datasize))
2246 % tuple(datasize))
2225 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2247 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2226 % tuple(fullsize))
2248 % tuple(fullsize))
2227 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2249 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2228 % tuple(deltasize))
2250 % tuple(deltasize))
2229
2251
2230 if numdeltas > 0:
2252 if numdeltas > 0:
2231 ui.write('\n')
2253 ui.write('\n')
2232 fmt = pcfmtstr(numdeltas)
2254 fmt = pcfmtstr(numdeltas)
2233 fmt2 = pcfmtstr(numdeltas, 4)
2255 fmt2 = pcfmtstr(numdeltas, 4)
2234 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2256 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2235 if numprev > 0:
2257 if numprev > 0:
2236 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2258 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2237 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2259 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2238 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2260 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2239 if gdelta:
2261 if gdelta:
2240 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2262 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2241 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2263 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2242 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2264 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2243
2265
2244 @command('debugrevspec', [], ('REVSPEC'))
2266 @command('debugrevspec', [], ('REVSPEC'))
2245 def debugrevspec(ui, repo, expr):
2267 def debugrevspec(ui, repo, expr):
2246 """parse and apply a revision specification
2268 """parse and apply a revision specification
2247
2269
2248 Use --verbose to print the parsed tree before and after aliases
2270 Use --verbose to print the parsed tree before and after aliases
2249 expansion.
2271 expansion.
2250 """
2272 """
2251 if ui.verbose:
2273 if ui.verbose:
2252 tree = revset.parse(expr)[0]
2274 tree = revset.parse(expr)[0]
2253 ui.note(revset.prettyformat(tree), "\n")
2275 ui.note(revset.prettyformat(tree), "\n")
2254 newtree = revset.findaliases(ui, tree)
2276 newtree = revset.findaliases(ui, tree)
2255 if newtree != tree:
2277 if newtree != tree:
2256 ui.note(revset.prettyformat(newtree), "\n")
2278 ui.note(revset.prettyformat(newtree), "\n")
2257 func = revset.match(ui, expr)
2279 func = revset.match(ui, expr)
2258 for c in func(repo, range(len(repo))):
2280 for c in func(repo, range(len(repo))):
2259 ui.write("%s\n" % c)
2281 ui.write("%s\n" % c)
2260
2282
2261 @command('debugsetparents', [], _('REV1 [REV2]'))
2283 @command('debugsetparents', [], _('REV1 [REV2]'))
2262 def debugsetparents(ui, repo, rev1, rev2=None):
2284 def debugsetparents(ui, repo, rev1, rev2=None):
2263 """manually set the parents of the current working directory
2285 """manually set the parents of the current working directory
2264
2286
2265 This is useful for writing repository conversion tools, but should
2287 This is useful for writing repository conversion tools, but should
2266 be used with care.
2288 be used with care.
2267
2289
2268 Returns 0 on success.
2290 Returns 0 on success.
2269 """
2291 """
2270
2292
2271 r1 = scmutil.revsingle(repo, rev1).node()
2293 r1 = scmutil.revsingle(repo, rev1).node()
2272 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2294 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2273
2295
2274 wlock = repo.wlock()
2296 wlock = repo.wlock()
2275 try:
2297 try:
2276 repo.setparents(r1, r2)
2298 repo.setparents(r1, r2)
2277 finally:
2299 finally:
2278 wlock.release()
2300 wlock.release()
2279
2301
2280 @command('debugstate',
2302 @command('debugstate',
2281 [('', 'nodates', None, _('do not display the saved mtime')),
2303 [('', 'nodates', None, _('do not display the saved mtime')),
2282 ('', 'datesort', None, _('sort by saved mtime'))],
2304 ('', 'datesort', None, _('sort by saved mtime'))],
2283 _('[OPTION]...'))
2305 _('[OPTION]...'))
2284 def debugstate(ui, repo, nodates=None, datesort=None):
2306 def debugstate(ui, repo, nodates=None, datesort=None):
2285 """show the contents of the current dirstate"""
2307 """show the contents of the current dirstate"""
2286 timestr = ""
2308 timestr = ""
2287 showdate = not nodates
2309 showdate = not nodates
2288 if datesort:
2310 if datesort:
2289 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2311 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2290 else:
2312 else:
2291 keyfunc = None # sort by filename
2313 keyfunc = None # sort by filename
2292 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2314 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2293 if showdate:
2315 if showdate:
2294 if ent[3] == -1:
2316 if ent[3] == -1:
2295 # Pad or slice to locale representation
2317 # Pad or slice to locale representation
2296 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2318 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2297 time.localtime(0)))
2319 time.localtime(0)))
2298 timestr = 'unset'
2320 timestr = 'unset'
2299 timestr = (timestr[:locale_len] +
2321 timestr = (timestr[:locale_len] +
2300 ' ' * (locale_len - len(timestr)))
2322 ' ' * (locale_len - len(timestr)))
2301 else:
2323 else:
2302 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2324 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2303 time.localtime(ent[3]))
2325 time.localtime(ent[3]))
2304 if ent[1] & 020000:
2326 if ent[1] & 020000:
2305 mode = 'lnk'
2327 mode = 'lnk'
2306 else:
2328 else:
2307 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2329 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2308 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2330 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2309 for f in repo.dirstate.copies():
2331 for f in repo.dirstate.copies():
2310 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2332 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2311
2333
2312 @command('debugsub',
2334 @command('debugsub',
2313 [('r', 'rev', '',
2335 [('r', 'rev', '',
2314 _('revision to check'), _('REV'))],
2336 _('revision to check'), _('REV'))],
2315 _('[-r REV] [REV]'))
2337 _('[-r REV] [REV]'))
2316 def debugsub(ui, repo, rev=None):
2338 def debugsub(ui, repo, rev=None):
2317 ctx = scmutil.revsingle(repo, rev, None)
2339 ctx = scmutil.revsingle(repo, rev, None)
2318 for k, v in sorted(ctx.substate.items()):
2340 for k, v in sorted(ctx.substate.items()):
2319 ui.write('path %s\n' % k)
2341 ui.write('path %s\n' % k)
2320 ui.write(' source %s\n' % v[0])
2342 ui.write(' source %s\n' % v[0])
2321 ui.write(' revision %s\n' % v[1])
2343 ui.write(' revision %s\n' % v[1])
2322
2344
2323 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2345 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2324 def debugwalk(ui, repo, *pats, **opts):
2346 def debugwalk(ui, repo, *pats, **opts):
2325 """show how files match on given patterns"""
2347 """show how files match on given patterns"""
2326 m = scmutil.match(repo[None], pats, opts)
2348 m = scmutil.match(repo[None], pats, opts)
2327 items = list(repo.walk(m))
2349 items = list(repo.walk(m))
2328 if not items:
2350 if not items:
2329 return
2351 return
2330 fmt = 'f %%-%ds %%-%ds %%s' % (
2352 fmt = 'f %%-%ds %%-%ds %%s' % (
2331 max([len(abs) for abs in items]),
2353 max([len(abs) for abs in items]),
2332 max([len(m.rel(abs)) for abs in items]))
2354 max([len(m.rel(abs)) for abs in items]))
2333 for abs in items:
2355 for abs in items:
2334 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2356 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2335 ui.write("%s\n" % line.rstrip())
2357 ui.write("%s\n" % line.rstrip())
2336
2358
2337 @command('debugwireargs',
2359 @command('debugwireargs',
2338 [('', 'three', '', 'three'),
2360 [('', 'three', '', 'three'),
2339 ('', 'four', '', 'four'),
2361 ('', 'four', '', 'four'),
2340 ('', 'five', '', 'five'),
2362 ('', 'five', '', 'five'),
2341 ] + remoteopts,
2363 ] + remoteopts,
2342 _('REPO [OPTIONS]... [ONE [TWO]]'))
2364 _('REPO [OPTIONS]... [ONE [TWO]]'))
2343 def debugwireargs(ui, repopath, *vals, **opts):
2365 def debugwireargs(ui, repopath, *vals, **opts):
2344 repo = hg.peer(ui, opts, repopath)
2366 repo = hg.peer(ui, opts, repopath)
2345 for opt in remoteopts:
2367 for opt in remoteopts:
2346 del opts[opt[1]]
2368 del opts[opt[1]]
2347 args = {}
2369 args = {}
2348 for k, v in opts.iteritems():
2370 for k, v in opts.iteritems():
2349 if v:
2371 if v:
2350 args[k] = v
2372 args[k] = v
2351 # run twice to check that we don't mess up the stream for the next command
2373 # run twice to check that we don't mess up the stream for the next command
2352 res1 = repo.debugwireargs(*vals, **args)
2374 res1 = repo.debugwireargs(*vals, **args)
2353 res2 = repo.debugwireargs(*vals, **args)
2375 res2 = repo.debugwireargs(*vals, **args)
2354 ui.write("%s\n" % res1)
2376 ui.write("%s\n" % res1)
2355 if res1 != res2:
2377 if res1 != res2:
2356 ui.warn("%s\n" % res2)
2378 ui.warn("%s\n" % res2)
2357
2379
2358 @command('^diff',
2380 @command('^diff',
2359 [('r', 'rev', [], _('revision'), _('REV')),
2381 [('r', 'rev', [], _('revision'), _('REV')),
2360 ('c', 'change', '', _('change made by revision'), _('REV'))
2382 ('c', 'change', '', _('change made by revision'), _('REV'))
2361 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2383 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2362 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2384 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2363 def diff(ui, repo, *pats, **opts):
2385 def diff(ui, repo, *pats, **opts):
2364 """diff repository (or selected files)
2386 """diff repository (or selected files)
2365
2387
2366 Show differences between revisions for the specified files.
2388 Show differences between revisions for the specified files.
2367
2389
2368 Differences between files are shown using the unified diff format.
2390 Differences between files are shown using the unified diff format.
2369
2391
2370 .. note::
2392 .. note::
2371 diff may generate unexpected results for merges, as it will
2393 diff may generate unexpected results for merges, as it will
2372 default to comparing against the working directory's first
2394 default to comparing against the working directory's first
2373 parent changeset if no revisions are specified.
2395 parent changeset if no revisions are specified.
2374
2396
2375 When two revision arguments are given, then changes are shown
2397 When two revision arguments are given, then changes are shown
2376 between those revisions. If only one revision is specified then
2398 between those revisions. If only one revision is specified then
2377 that revision is compared to the working directory, and, when no
2399 that revision is compared to the working directory, and, when no
2378 revisions are specified, the working directory files are compared
2400 revisions are specified, the working directory files are compared
2379 to its parent.
2401 to its parent.
2380
2402
2381 Alternatively you can specify -c/--change with a revision to see
2403 Alternatively you can specify -c/--change with a revision to see
2382 the changes in that changeset relative to its first parent.
2404 the changes in that changeset relative to its first parent.
2383
2405
2384 Without the -a/--text option, diff will avoid generating diffs of
2406 Without the -a/--text option, diff will avoid generating diffs of
2385 files it detects as binary. With -a, diff will generate a diff
2407 files it detects as binary. With -a, diff will generate a diff
2386 anyway, probably with undesirable results.
2408 anyway, probably with undesirable results.
2387
2409
2388 Use the -g/--git option to generate diffs in the git extended diff
2410 Use the -g/--git option to generate diffs in the git extended diff
2389 format. For more information, read :hg:`help diffs`.
2411 format. For more information, read :hg:`help diffs`.
2390
2412
2391 .. container:: verbose
2413 .. container:: verbose
2392
2414
2393 Examples:
2415 Examples:
2394
2416
2395 - compare a file in the current working directory to its parent::
2417 - compare a file in the current working directory to its parent::
2396
2418
2397 hg diff foo.c
2419 hg diff foo.c
2398
2420
2399 - compare two historical versions of a directory, with rename info::
2421 - compare two historical versions of a directory, with rename info::
2400
2422
2401 hg diff --git -r 1.0:1.2 lib/
2423 hg diff --git -r 1.0:1.2 lib/
2402
2424
2403 - get change stats relative to the last change on some date::
2425 - get change stats relative to the last change on some date::
2404
2426
2405 hg diff --stat -r "date('may 2')"
2427 hg diff --stat -r "date('may 2')"
2406
2428
2407 - diff all newly-added files that contain a keyword::
2429 - diff all newly-added files that contain a keyword::
2408
2430
2409 hg diff "set:added() and grep(GNU)"
2431 hg diff "set:added() and grep(GNU)"
2410
2432
2411 - compare a revision and its parents::
2433 - compare a revision and its parents::
2412
2434
2413 hg diff -c 9353 # compare against first parent
2435 hg diff -c 9353 # compare against first parent
2414 hg diff -r 9353^:9353 # same using revset syntax
2436 hg diff -r 9353^:9353 # same using revset syntax
2415 hg diff -r 9353^2:9353 # compare against the second parent
2437 hg diff -r 9353^2:9353 # compare against the second parent
2416
2438
2417 Returns 0 on success.
2439 Returns 0 on success.
2418 """
2440 """
2419
2441
2420 revs = opts.get('rev')
2442 revs = opts.get('rev')
2421 change = opts.get('change')
2443 change = opts.get('change')
2422 stat = opts.get('stat')
2444 stat = opts.get('stat')
2423 reverse = opts.get('reverse')
2445 reverse = opts.get('reverse')
2424
2446
2425 if revs and change:
2447 if revs and change:
2426 msg = _('cannot specify --rev and --change at the same time')
2448 msg = _('cannot specify --rev and --change at the same time')
2427 raise util.Abort(msg)
2449 raise util.Abort(msg)
2428 elif change:
2450 elif change:
2429 node2 = scmutil.revsingle(repo, change, None).node()
2451 node2 = scmutil.revsingle(repo, change, None).node()
2430 node1 = repo[node2].p1().node()
2452 node1 = repo[node2].p1().node()
2431 else:
2453 else:
2432 node1, node2 = scmutil.revpair(repo, revs)
2454 node1, node2 = scmutil.revpair(repo, revs)
2433
2455
2434 if reverse:
2456 if reverse:
2435 node1, node2 = node2, node1
2457 node1, node2 = node2, node1
2436
2458
2437 diffopts = patch.diffopts(ui, opts)
2459 diffopts = patch.diffopts(ui, opts)
2438 m = scmutil.match(repo[node2], pats, opts)
2460 m = scmutil.match(repo[node2], pats, opts)
2439 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2461 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2440 listsubrepos=opts.get('subrepos'))
2462 listsubrepos=opts.get('subrepos'))
2441
2463
2442 @command('^export',
2464 @command('^export',
2443 [('o', 'output', '',
2465 [('o', 'output', '',
2444 _('print output to file with formatted name'), _('FORMAT')),
2466 _('print output to file with formatted name'), _('FORMAT')),
2445 ('', 'switch-parent', None, _('diff against the second parent')),
2467 ('', 'switch-parent', None, _('diff against the second parent')),
2446 ('r', 'rev', [], _('revisions to export'), _('REV')),
2468 ('r', 'rev', [], _('revisions to export'), _('REV')),
2447 ] + diffopts,
2469 ] + diffopts,
2448 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2470 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2449 def export(ui, repo, *changesets, **opts):
2471 def export(ui, repo, *changesets, **opts):
2450 """dump the header and diffs for one or more changesets
2472 """dump the header and diffs for one or more changesets
2451
2473
2452 Print the changeset header and diffs for one or more revisions.
2474 Print the changeset header and diffs for one or more revisions.
2453
2475
2454 The information shown in the changeset header is: author, date,
2476 The information shown in the changeset header is: author, date,
2455 branch name (if non-default), changeset hash, parent(s) and commit
2477 branch name (if non-default), changeset hash, parent(s) and commit
2456 comment.
2478 comment.
2457
2479
2458 .. note::
2480 .. note::
2459 export may generate unexpected diff output for merge
2481 export may generate unexpected diff output for merge
2460 changesets, as it will compare the merge changeset against its
2482 changesets, as it will compare the merge changeset against its
2461 first parent only.
2483 first parent only.
2462
2484
2463 Output may be to a file, in which case the name of the file is
2485 Output may be to a file, in which case the name of the file is
2464 given using a format string. The formatting rules are as follows:
2486 given using a format string. The formatting rules are as follows:
2465
2487
2466 :``%%``: literal "%" character
2488 :``%%``: literal "%" character
2467 :``%H``: changeset hash (40 hexadecimal digits)
2489 :``%H``: changeset hash (40 hexadecimal digits)
2468 :``%N``: number of patches being generated
2490 :``%N``: number of patches being generated
2469 :``%R``: changeset revision number
2491 :``%R``: changeset revision number
2470 :``%b``: basename of the exporting repository
2492 :``%b``: basename of the exporting repository
2471 :``%h``: short-form changeset hash (12 hexadecimal digits)
2493 :``%h``: short-form changeset hash (12 hexadecimal digits)
2472 :``%m``: first line of the commit message (only alphanumeric characters)
2494 :``%m``: first line of the commit message (only alphanumeric characters)
2473 :``%n``: zero-padded sequence number, starting at 1
2495 :``%n``: zero-padded sequence number, starting at 1
2474 :``%r``: zero-padded changeset revision number
2496 :``%r``: zero-padded changeset revision number
2475
2497
2476 Without the -a/--text option, export will avoid generating diffs
2498 Without the -a/--text option, export will avoid generating diffs
2477 of files it detects as binary. With -a, export will generate a
2499 of files it detects as binary. With -a, export will generate a
2478 diff anyway, probably with undesirable results.
2500 diff anyway, probably with undesirable results.
2479
2501
2480 Use the -g/--git option to generate diffs in the git extended diff
2502 Use the -g/--git option to generate diffs in the git extended diff
2481 format. See :hg:`help diffs` for more information.
2503 format. See :hg:`help diffs` for more information.
2482
2504
2483 With the --switch-parent option, the diff will be against the
2505 With the --switch-parent option, the diff will be against the
2484 second parent. It can be useful to review a merge.
2506 second parent. It can be useful to review a merge.
2485
2507
2486 .. container:: verbose
2508 .. container:: verbose
2487
2509
2488 Examples:
2510 Examples:
2489
2511
2490 - use export and import to transplant a bugfix to the current
2512 - use export and import to transplant a bugfix to the current
2491 branch::
2513 branch::
2492
2514
2493 hg export -r 9353 | hg import -
2515 hg export -r 9353 | hg import -
2494
2516
2495 - export all the changesets between two revisions to a file with
2517 - export all the changesets between two revisions to a file with
2496 rename information::
2518 rename information::
2497
2519
2498 hg export --git -r 123:150 > changes.txt
2520 hg export --git -r 123:150 > changes.txt
2499
2521
2500 - split outgoing changes into a series of patches with
2522 - split outgoing changes into a series of patches with
2501 descriptive names::
2523 descriptive names::
2502
2524
2503 hg export -r "outgoing()" -o "%n-%m.patch"
2525 hg export -r "outgoing()" -o "%n-%m.patch"
2504
2526
2505 Returns 0 on success.
2527 Returns 0 on success.
2506 """
2528 """
2507 changesets += tuple(opts.get('rev', []))
2529 changesets += tuple(opts.get('rev', []))
2508 revs = scmutil.revrange(repo, changesets)
2530 revs = scmutil.revrange(repo, changesets)
2509 if not revs:
2531 if not revs:
2510 raise util.Abort(_("export requires at least one changeset"))
2532 raise util.Abort(_("export requires at least one changeset"))
2511 if len(revs) > 1:
2533 if len(revs) > 1:
2512 ui.note(_('exporting patches:\n'))
2534 ui.note(_('exporting patches:\n'))
2513 else:
2535 else:
2514 ui.note(_('exporting patch:\n'))
2536 ui.note(_('exporting patch:\n'))
2515 cmdutil.export(repo, revs, template=opts.get('output'),
2537 cmdutil.export(repo, revs, template=opts.get('output'),
2516 switch_parent=opts.get('switch_parent'),
2538 switch_parent=opts.get('switch_parent'),
2517 opts=patch.diffopts(ui, opts))
2539 opts=patch.diffopts(ui, opts))
2518
2540
2519 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2541 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2520 def forget(ui, repo, *pats, **opts):
2542 def forget(ui, repo, *pats, **opts):
2521 """forget the specified files on the next commit
2543 """forget the specified files on the next commit
2522
2544
2523 Mark the specified files so they will no longer be tracked
2545 Mark the specified files so they will no longer be tracked
2524 after the next commit.
2546 after the next commit.
2525
2547
2526 This only removes files from the current branch, not from the
2548 This only removes files from the current branch, not from the
2527 entire project history, and it does not delete them from the
2549 entire project history, and it does not delete them from the
2528 working directory.
2550 working directory.
2529
2551
2530 To undo a forget before the next commit, see :hg:`add`.
2552 To undo a forget before the next commit, see :hg:`add`.
2531
2553
2532 .. container:: verbose
2554 .. container:: verbose
2533
2555
2534 Examples:
2556 Examples:
2535
2557
2536 - forget newly-added binary files::
2558 - forget newly-added binary files::
2537
2559
2538 hg forget "set:added() and binary()"
2560 hg forget "set:added() and binary()"
2539
2561
2540 - forget files that would be excluded by .hgignore::
2562 - forget files that would be excluded by .hgignore::
2541
2563
2542 hg forget "set:hgignore()"
2564 hg forget "set:hgignore()"
2543
2565
2544 Returns 0 on success.
2566 Returns 0 on success.
2545 """
2567 """
2546
2568
2547 if not pats:
2569 if not pats:
2548 raise util.Abort(_('no files specified'))
2570 raise util.Abort(_('no files specified'))
2549
2571
2550 m = scmutil.match(repo[None], pats, opts)
2572 m = scmutil.match(repo[None], pats, opts)
2551 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2573 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2552 return rejected and 1 or 0
2574 return rejected and 1 or 0
2553
2575
2554 @command(
2576 @command(
2555 'graft',
2577 'graft',
2556 [('c', 'continue', False, _('resume interrupted graft')),
2578 [('c', 'continue', False, _('resume interrupted graft')),
2557 ('e', 'edit', False, _('invoke editor on commit messages')),
2579 ('e', 'edit', False, _('invoke editor on commit messages')),
2558 ('D', 'currentdate', False,
2580 ('D', 'currentdate', False,
2559 _('record the current date as commit date')),
2581 _('record the current date as commit date')),
2560 ('U', 'currentuser', False,
2582 ('U', 'currentuser', False,
2561 _('record the current user as committer'), _('DATE'))]
2583 _('record the current user as committer'), _('DATE'))]
2562 + commitopts2 + mergetoolopts + dryrunopts,
2584 + commitopts2 + mergetoolopts + dryrunopts,
2563 _('[OPTION]... REVISION...'))
2585 _('[OPTION]... REVISION...'))
2564 def graft(ui, repo, *revs, **opts):
2586 def graft(ui, repo, *revs, **opts):
2565 '''copy changes from other branches onto the current branch
2587 '''copy changes from other branches onto the current branch
2566
2588
2567 This command uses Mercurial's merge logic to copy individual
2589 This command uses Mercurial's merge logic to copy individual
2568 changes from other branches without merging branches in the
2590 changes from other branches without merging branches in the
2569 history graph. This is sometimes known as 'backporting' or
2591 history graph. This is sometimes known as 'backporting' or
2570 'cherry-picking'. By default, graft will copy user, date, and
2592 'cherry-picking'. By default, graft will copy user, date, and
2571 description from the source changesets.
2593 description from the source changesets.
2572
2594
2573 Changesets that are ancestors of the current revision, that have
2595 Changesets that are ancestors of the current revision, that have
2574 already been grafted, or that are merges will be skipped.
2596 already been grafted, or that are merges will be skipped.
2575
2597
2576 If a graft merge results in conflicts, the graft process is
2598 If a graft merge results in conflicts, the graft process is
2577 interrupted so that the current merge can be manually resolved.
2599 interrupted so that the current merge can be manually resolved.
2578 Once all conflicts are addressed, the graft process can be
2600 Once all conflicts are addressed, the graft process can be
2579 continued with the -c/--continue option.
2601 continued with the -c/--continue option.
2580
2602
2581 .. note::
2603 .. note::
2582 The -c/--continue option does not reapply earlier options.
2604 The -c/--continue option does not reapply earlier options.
2583
2605
2584 .. container:: verbose
2606 .. container:: verbose
2585
2607
2586 Examples:
2608 Examples:
2587
2609
2588 - copy a single change to the stable branch and edit its description::
2610 - copy a single change to the stable branch and edit its description::
2589
2611
2590 hg update stable
2612 hg update stable
2591 hg graft --edit 9393
2613 hg graft --edit 9393
2592
2614
2593 - graft a range of changesets with one exception, updating dates::
2615 - graft a range of changesets with one exception, updating dates::
2594
2616
2595 hg graft -D "2085::2093 and not 2091"
2617 hg graft -D "2085::2093 and not 2091"
2596
2618
2597 - continue a graft after resolving conflicts::
2619 - continue a graft after resolving conflicts::
2598
2620
2599 hg graft -c
2621 hg graft -c
2600
2622
2601 - show the source of a grafted changeset::
2623 - show the source of a grafted changeset::
2602
2624
2603 hg log --debug -r tip
2625 hg log --debug -r tip
2604
2626
2605 Returns 0 on successful completion.
2627 Returns 0 on successful completion.
2606 '''
2628 '''
2607
2629
2608 if not opts.get('user') and opts.get('currentuser'):
2630 if not opts.get('user') and opts.get('currentuser'):
2609 opts['user'] = ui.username()
2631 opts['user'] = ui.username()
2610 if not opts.get('date') and opts.get('currentdate'):
2632 if not opts.get('date') and opts.get('currentdate'):
2611 opts['date'] = "%d %d" % util.makedate()
2633 opts['date'] = "%d %d" % util.makedate()
2612
2634
2613 editor = None
2635 editor = None
2614 if opts.get('edit'):
2636 if opts.get('edit'):
2615 editor = cmdutil.commitforceeditor
2637 editor = cmdutil.commitforceeditor
2616
2638
2617 cont = False
2639 cont = False
2618 if opts['continue']:
2640 if opts['continue']:
2619 cont = True
2641 cont = True
2620 if revs:
2642 if revs:
2621 raise util.Abort(_("can't specify --continue and revisions"))
2643 raise util.Abort(_("can't specify --continue and revisions"))
2622 # read in unfinished revisions
2644 # read in unfinished revisions
2623 try:
2645 try:
2624 nodes = repo.opener.read('graftstate').splitlines()
2646 nodes = repo.opener.read('graftstate').splitlines()
2625 revs = [repo[node].rev() for node in nodes]
2647 revs = [repo[node].rev() for node in nodes]
2626 except IOError, inst:
2648 except IOError, inst:
2627 if inst.errno != errno.ENOENT:
2649 if inst.errno != errno.ENOENT:
2628 raise
2650 raise
2629 raise util.Abort(_("no graft state found, can't continue"))
2651 raise util.Abort(_("no graft state found, can't continue"))
2630 else:
2652 else:
2631 cmdutil.bailifchanged(repo)
2653 cmdutil.bailifchanged(repo)
2632 if not revs:
2654 if not revs:
2633 raise util.Abort(_('no revisions specified'))
2655 raise util.Abort(_('no revisions specified'))
2634 revs = scmutil.revrange(repo, revs)
2656 revs = scmutil.revrange(repo, revs)
2635
2657
2636 # check for merges
2658 # check for merges
2637 for rev in repo.revs('%ld and merge()', revs):
2659 for rev in repo.revs('%ld and merge()', revs):
2638 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2660 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2639 revs.remove(rev)
2661 revs.remove(rev)
2640 if not revs:
2662 if not revs:
2641 return -1
2663 return -1
2642
2664
2643 # check for ancestors of dest branch
2665 # check for ancestors of dest branch
2644 for rev in repo.revs('::. and %ld', revs):
2666 for rev in repo.revs('::. and %ld', revs):
2645 ui.warn(_('skipping ancestor revision %s\n') % rev)
2667 ui.warn(_('skipping ancestor revision %s\n') % rev)
2646 revs.remove(rev)
2668 revs.remove(rev)
2647 if not revs:
2669 if not revs:
2648 return -1
2670 return -1
2649
2671
2650 # analyze revs for earlier grafts
2672 # analyze revs for earlier grafts
2651 ids = {}
2673 ids = {}
2652 for ctx in repo.set("%ld", revs):
2674 for ctx in repo.set("%ld", revs):
2653 ids[ctx.hex()] = ctx.rev()
2675 ids[ctx.hex()] = ctx.rev()
2654 n = ctx.extra().get('source')
2676 n = ctx.extra().get('source')
2655 if n:
2677 if n:
2656 ids[n] = ctx.rev()
2678 ids[n] = ctx.rev()
2657
2679
2658 # check ancestors for earlier grafts
2680 # check ancestors for earlier grafts
2659 ui.debug('scanning for duplicate grafts\n')
2681 ui.debug('scanning for duplicate grafts\n')
2660 for ctx in repo.set("::. - ::%ld", revs):
2682 for ctx in repo.set("::. - ::%ld", revs):
2661 n = ctx.extra().get('source')
2683 n = ctx.extra().get('source')
2662 if n in ids:
2684 if n in ids:
2663 r = repo[n].rev()
2685 r = repo[n].rev()
2664 if r in revs:
2686 if r in revs:
2665 ui.warn(_('skipping already grafted revision %s\n') % r)
2687 ui.warn(_('skipping already grafted revision %s\n') % r)
2666 revs.remove(r)
2688 revs.remove(r)
2667 elif ids[n] in revs:
2689 elif ids[n] in revs:
2668 ui.warn(_('skipping already grafted revision %s '
2690 ui.warn(_('skipping already grafted revision %s '
2669 '(same origin %d)\n') % (ids[n], r))
2691 '(same origin %d)\n') % (ids[n], r))
2670 revs.remove(ids[n])
2692 revs.remove(ids[n])
2671 elif ctx.hex() in ids:
2693 elif ctx.hex() in ids:
2672 r = ids[ctx.hex()]
2694 r = ids[ctx.hex()]
2673 ui.warn(_('skipping already grafted revision %s '
2695 ui.warn(_('skipping already grafted revision %s '
2674 '(was grafted from %d)\n') % (r, ctx.rev()))
2696 '(was grafted from %d)\n') % (r, ctx.rev()))
2675 revs.remove(r)
2697 revs.remove(r)
2676 if not revs:
2698 if not revs:
2677 return -1
2699 return -1
2678
2700
2679 wlock = repo.wlock()
2701 wlock = repo.wlock()
2680 try:
2702 try:
2681 for pos, ctx in enumerate(repo.set("%ld", revs)):
2703 for pos, ctx in enumerate(repo.set("%ld", revs)):
2682 current = repo['.']
2704 current = repo['.']
2683
2705
2684 ui.status(_('grafting revision %s\n') % ctx.rev())
2706 ui.status(_('grafting revision %s\n') % ctx.rev())
2685 if opts.get('dry_run'):
2707 if opts.get('dry_run'):
2686 continue
2708 continue
2687
2709
2688 # we don't merge the first commit when continuing
2710 # we don't merge the first commit when continuing
2689 if not cont:
2711 if not cont:
2690 # perform the graft merge with p1(rev) as 'ancestor'
2712 # perform the graft merge with p1(rev) as 'ancestor'
2691 try:
2713 try:
2692 # ui.forcemerge is an internal variable, do not document
2714 # ui.forcemerge is an internal variable, do not document
2693 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2715 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2694 stats = mergemod.update(repo, ctx.node(), True, True, False,
2716 stats = mergemod.update(repo, ctx.node(), True, True, False,
2695 ctx.p1().node())
2717 ctx.p1().node())
2696 finally:
2718 finally:
2697 ui.setconfig('ui', 'forcemerge', '')
2719 ui.setconfig('ui', 'forcemerge', '')
2698 # drop the second merge parent
2720 # drop the second merge parent
2699 repo.setparents(current.node(), nullid)
2721 repo.setparents(current.node(), nullid)
2700 repo.dirstate.write()
2722 repo.dirstate.write()
2701 # fix up dirstate for copies and renames
2723 # fix up dirstate for copies and renames
2702 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2724 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2703 # report any conflicts
2725 # report any conflicts
2704 if stats and stats[3] > 0:
2726 if stats and stats[3] > 0:
2705 # write out state for --continue
2727 # write out state for --continue
2706 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2728 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2707 repo.opener.write('graftstate', ''.join(nodelines))
2729 repo.opener.write('graftstate', ''.join(nodelines))
2708 raise util.Abort(
2730 raise util.Abort(
2709 _("unresolved conflicts, can't continue"),
2731 _("unresolved conflicts, can't continue"),
2710 hint=_('use hg resolve and hg graft --continue'))
2732 hint=_('use hg resolve and hg graft --continue'))
2711 else:
2733 else:
2712 cont = False
2734 cont = False
2713
2735
2714 # commit
2736 # commit
2715 source = ctx.extra().get('source')
2737 source = ctx.extra().get('source')
2716 if not source:
2738 if not source:
2717 source = ctx.hex()
2739 source = ctx.hex()
2718 extra = {'source': source}
2740 extra = {'source': source}
2719 user = ctx.user()
2741 user = ctx.user()
2720 if opts.get('user'):
2742 if opts.get('user'):
2721 user = opts['user']
2743 user = opts['user']
2722 date = ctx.date()
2744 date = ctx.date()
2723 if opts.get('date'):
2745 if opts.get('date'):
2724 date = opts['date']
2746 date = opts['date']
2725 node = repo.commit(text=ctx.description(), user=user,
2747 node = repo.commit(text=ctx.description(), user=user,
2726 date=date, extra=extra, editor=editor)
2748 date=date, extra=extra, editor=editor)
2727 if node is None:
2749 if node is None:
2728 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2750 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2729 finally:
2751 finally:
2730 wlock.release()
2752 wlock.release()
2731
2753
2732 # remove state when we complete successfully
2754 # remove state when we complete successfully
2733 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2755 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2734 util.unlinkpath(repo.join('graftstate'))
2756 util.unlinkpath(repo.join('graftstate'))
2735
2757
2736 return 0
2758 return 0
2737
2759
2738 @command('grep',
2760 @command('grep',
2739 [('0', 'print0', None, _('end fields with NUL')),
2761 [('0', 'print0', None, _('end fields with NUL')),
2740 ('', 'all', None, _('print all revisions that match')),
2762 ('', 'all', None, _('print all revisions that match')),
2741 ('a', 'text', None, _('treat all files as text')),
2763 ('a', 'text', None, _('treat all files as text')),
2742 ('f', 'follow', None,
2764 ('f', 'follow', None,
2743 _('follow changeset history,'
2765 _('follow changeset history,'
2744 ' or file history across copies and renames')),
2766 ' or file history across copies and renames')),
2745 ('i', 'ignore-case', None, _('ignore case when matching')),
2767 ('i', 'ignore-case', None, _('ignore case when matching')),
2746 ('l', 'files-with-matches', None,
2768 ('l', 'files-with-matches', None,
2747 _('print only filenames and revisions that match')),
2769 _('print only filenames and revisions that match')),
2748 ('n', 'line-number', None, _('print matching line numbers')),
2770 ('n', 'line-number', None, _('print matching line numbers')),
2749 ('r', 'rev', [],
2771 ('r', 'rev', [],
2750 _('only search files changed within revision range'), _('REV')),
2772 _('only search files changed within revision range'), _('REV')),
2751 ('u', 'user', None, _('list the author (long with -v)')),
2773 ('u', 'user', None, _('list the author (long with -v)')),
2752 ('d', 'date', None, _('list the date (short with -q)')),
2774 ('d', 'date', None, _('list the date (short with -q)')),
2753 ] + walkopts,
2775 ] + walkopts,
2754 _('[OPTION]... PATTERN [FILE]...'))
2776 _('[OPTION]... PATTERN [FILE]...'))
2755 def grep(ui, repo, pattern, *pats, **opts):
2777 def grep(ui, repo, pattern, *pats, **opts):
2756 """search for a pattern in specified files and revisions
2778 """search for a pattern in specified files and revisions
2757
2779
2758 Search revisions of files for a regular expression.
2780 Search revisions of files for a regular expression.
2759
2781
2760 This command behaves differently than Unix grep. It only accepts
2782 This command behaves differently than Unix grep. It only accepts
2761 Python/Perl regexps. It searches repository history, not the
2783 Python/Perl regexps. It searches repository history, not the
2762 working directory. It always prints the revision number in which a
2784 working directory. It always prints the revision number in which a
2763 match appears.
2785 match appears.
2764
2786
2765 By default, grep only prints output for the first revision of a
2787 By default, grep only prints output for the first revision of a
2766 file in which it finds a match. To get it to print every revision
2788 file in which it finds a match. To get it to print every revision
2767 that contains a change in match status ("-" for a match that
2789 that contains a change in match status ("-" for a match that
2768 becomes a non-match, or "+" for a non-match that becomes a match),
2790 becomes a non-match, or "+" for a non-match that becomes a match),
2769 use the --all flag.
2791 use the --all flag.
2770
2792
2771 Returns 0 if a match is found, 1 otherwise.
2793 Returns 0 if a match is found, 1 otherwise.
2772 """
2794 """
2773 reflags = re.M
2795 reflags = re.M
2774 if opts.get('ignore_case'):
2796 if opts.get('ignore_case'):
2775 reflags |= re.I
2797 reflags |= re.I
2776 try:
2798 try:
2777 regexp = re.compile(pattern, reflags)
2799 regexp = re.compile(pattern, reflags)
2778 except re.error, inst:
2800 except re.error, inst:
2779 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2801 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2780 return 1
2802 return 1
2781 sep, eol = ':', '\n'
2803 sep, eol = ':', '\n'
2782 if opts.get('print0'):
2804 if opts.get('print0'):
2783 sep = eol = '\0'
2805 sep = eol = '\0'
2784
2806
2785 getfile = util.lrucachefunc(repo.file)
2807 getfile = util.lrucachefunc(repo.file)
2786
2808
2787 def matchlines(body):
2809 def matchlines(body):
2788 begin = 0
2810 begin = 0
2789 linenum = 0
2811 linenum = 0
2790 while True:
2812 while True:
2791 match = regexp.search(body, begin)
2813 match = regexp.search(body, begin)
2792 if not match:
2814 if not match:
2793 break
2815 break
2794 mstart, mend = match.span()
2816 mstart, mend = match.span()
2795 linenum += body.count('\n', begin, mstart) + 1
2817 linenum += body.count('\n', begin, mstart) + 1
2796 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2818 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2797 begin = body.find('\n', mend) + 1 or len(body) + 1
2819 begin = body.find('\n', mend) + 1 or len(body) + 1
2798 lend = begin - 1
2820 lend = begin - 1
2799 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2821 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2800
2822
2801 class linestate(object):
2823 class linestate(object):
2802 def __init__(self, line, linenum, colstart, colend):
2824 def __init__(self, line, linenum, colstart, colend):
2803 self.line = line
2825 self.line = line
2804 self.linenum = linenum
2826 self.linenum = linenum
2805 self.colstart = colstart
2827 self.colstart = colstart
2806 self.colend = colend
2828 self.colend = colend
2807
2829
2808 def __hash__(self):
2830 def __hash__(self):
2809 return hash((self.linenum, self.line))
2831 return hash((self.linenum, self.line))
2810
2832
2811 def __eq__(self, other):
2833 def __eq__(self, other):
2812 return self.line == other.line
2834 return self.line == other.line
2813
2835
2814 matches = {}
2836 matches = {}
2815 copies = {}
2837 copies = {}
2816 def grepbody(fn, rev, body):
2838 def grepbody(fn, rev, body):
2817 matches[rev].setdefault(fn, [])
2839 matches[rev].setdefault(fn, [])
2818 m = matches[rev][fn]
2840 m = matches[rev][fn]
2819 for lnum, cstart, cend, line in matchlines(body):
2841 for lnum, cstart, cend, line in matchlines(body):
2820 s = linestate(line, lnum, cstart, cend)
2842 s = linestate(line, lnum, cstart, cend)
2821 m.append(s)
2843 m.append(s)
2822
2844
2823 def difflinestates(a, b):
2845 def difflinestates(a, b):
2824 sm = difflib.SequenceMatcher(None, a, b)
2846 sm = difflib.SequenceMatcher(None, a, b)
2825 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2847 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2826 if tag == 'insert':
2848 if tag == 'insert':
2827 for i in xrange(blo, bhi):
2849 for i in xrange(blo, bhi):
2828 yield ('+', b[i])
2850 yield ('+', b[i])
2829 elif tag == 'delete':
2851 elif tag == 'delete':
2830 for i in xrange(alo, ahi):
2852 for i in xrange(alo, ahi):
2831 yield ('-', a[i])
2853 yield ('-', a[i])
2832 elif tag == 'replace':
2854 elif tag == 'replace':
2833 for i in xrange(alo, ahi):
2855 for i in xrange(alo, ahi):
2834 yield ('-', a[i])
2856 yield ('-', a[i])
2835 for i in xrange(blo, bhi):
2857 for i in xrange(blo, bhi):
2836 yield ('+', b[i])
2858 yield ('+', b[i])
2837
2859
2838 def display(fn, ctx, pstates, states):
2860 def display(fn, ctx, pstates, states):
2839 rev = ctx.rev()
2861 rev = ctx.rev()
2840 datefunc = ui.quiet and util.shortdate or util.datestr
2862 datefunc = ui.quiet and util.shortdate or util.datestr
2841 found = False
2863 found = False
2842 filerevmatches = {}
2864 filerevmatches = {}
2843 def binary():
2865 def binary():
2844 flog = getfile(fn)
2866 flog = getfile(fn)
2845 return util.binary(flog.read(ctx.filenode(fn)))
2867 return util.binary(flog.read(ctx.filenode(fn)))
2846
2868
2847 if opts.get('all'):
2869 if opts.get('all'):
2848 iter = difflinestates(pstates, states)
2870 iter = difflinestates(pstates, states)
2849 else:
2871 else:
2850 iter = [('', l) for l in states]
2872 iter = [('', l) for l in states]
2851 for change, l in iter:
2873 for change, l in iter:
2852 cols = [fn, str(rev)]
2874 cols = [fn, str(rev)]
2853 before, match, after = None, None, None
2875 before, match, after = None, None, None
2854 if opts.get('line_number'):
2876 if opts.get('line_number'):
2855 cols.append(str(l.linenum))
2877 cols.append(str(l.linenum))
2856 if opts.get('all'):
2878 if opts.get('all'):
2857 cols.append(change)
2879 cols.append(change)
2858 if opts.get('user'):
2880 if opts.get('user'):
2859 cols.append(ui.shortuser(ctx.user()))
2881 cols.append(ui.shortuser(ctx.user()))
2860 if opts.get('date'):
2882 if opts.get('date'):
2861 cols.append(datefunc(ctx.date()))
2883 cols.append(datefunc(ctx.date()))
2862 if opts.get('files_with_matches'):
2884 if opts.get('files_with_matches'):
2863 c = (fn, rev)
2885 c = (fn, rev)
2864 if c in filerevmatches:
2886 if c in filerevmatches:
2865 continue
2887 continue
2866 filerevmatches[c] = 1
2888 filerevmatches[c] = 1
2867 else:
2889 else:
2868 before = l.line[:l.colstart]
2890 before = l.line[:l.colstart]
2869 match = l.line[l.colstart:l.colend]
2891 match = l.line[l.colstart:l.colend]
2870 after = l.line[l.colend:]
2892 after = l.line[l.colend:]
2871 ui.write(sep.join(cols))
2893 ui.write(sep.join(cols))
2872 if before is not None:
2894 if before is not None:
2873 if not opts.get('text') and binary():
2895 if not opts.get('text') and binary():
2874 ui.write(sep + " Binary file matches")
2896 ui.write(sep + " Binary file matches")
2875 else:
2897 else:
2876 ui.write(sep + before)
2898 ui.write(sep + before)
2877 ui.write(match, label='grep.match')
2899 ui.write(match, label='grep.match')
2878 ui.write(after)
2900 ui.write(after)
2879 ui.write(eol)
2901 ui.write(eol)
2880 found = True
2902 found = True
2881 return found
2903 return found
2882
2904
2883 skip = {}
2905 skip = {}
2884 revfiles = {}
2906 revfiles = {}
2885 matchfn = scmutil.match(repo[None], pats, opts)
2907 matchfn = scmutil.match(repo[None], pats, opts)
2886 found = False
2908 found = False
2887 follow = opts.get('follow')
2909 follow = opts.get('follow')
2888
2910
2889 def prep(ctx, fns):
2911 def prep(ctx, fns):
2890 rev = ctx.rev()
2912 rev = ctx.rev()
2891 pctx = ctx.p1()
2913 pctx = ctx.p1()
2892 parent = pctx.rev()
2914 parent = pctx.rev()
2893 matches.setdefault(rev, {})
2915 matches.setdefault(rev, {})
2894 matches.setdefault(parent, {})
2916 matches.setdefault(parent, {})
2895 files = revfiles.setdefault(rev, [])
2917 files = revfiles.setdefault(rev, [])
2896 for fn in fns:
2918 for fn in fns:
2897 flog = getfile(fn)
2919 flog = getfile(fn)
2898 try:
2920 try:
2899 fnode = ctx.filenode(fn)
2921 fnode = ctx.filenode(fn)
2900 except error.LookupError:
2922 except error.LookupError:
2901 continue
2923 continue
2902
2924
2903 copied = flog.renamed(fnode)
2925 copied = flog.renamed(fnode)
2904 copy = follow and copied and copied[0]
2926 copy = follow and copied and copied[0]
2905 if copy:
2927 if copy:
2906 copies.setdefault(rev, {})[fn] = copy
2928 copies.setdefault(rev, {})[fn] = copy
2907 if fn in skip:
2929 if fn in skip:
2908 if copy:
2930 if copy:
2909 skip[copy] = True
2931 skip[copy] = True
2910 continue
2932 continue
2911 files.append(fn)
2933 files.append(fn)
2912
2934
2913 if fn not in matches[rev]:
2935 if fn not in matches[rev]:
2914 grepbody(fn, rev, flog.read(fnode))
2936 grepbody(fn, rev, flog.read(fnode))
2915
2937
2916 pfn = copy or fn
2938 pfn = copy or fn
2917 if pfn not in matches[parent]:
2939 if pfn not in matches[parent]:
2918 try:
2940 try:
2919 fnode = pctx.filenode(pfn)
2941 fnode = pctx.filenode(pfn)
2920 grepbody(pfn, parent, flog.read(fnode))
2942 grepbody(pfn, parent, flog.read(fnode))
2921 except error.LookupError:
2943 except error.LookupError:
2922 pass
2944 pass
2923
2945
2924 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2946 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2925 rev = ctx.rev()
2947 rev = ctx.rev()
2926 parent = ctx.p1().rev()
2948 parent = ctx.p1().rev()
2927 for fn in sorted(revfiles.get(rev, [])):
2949 for fn in sorted(revfiles.get(rev, [])):
2928 states = matches[rev][fn]
2950 states = matches[rev][fn]
2929 copy = copies.get(rev, {}).get(fn)
2951 copy = copies.get(rev, {}).get(fn)
2930 if fn in skip:
2952 if fn in skip:
2931 if copy:
2953 if copy:
2932 skip[copy] = True
2954 skip[copy] = True
2933 continue
2955 continue
2934 pstates = matches.get(parent, {}).get(copy or fn, [])
2956 pstates = matches.get(parent, {}).get(copy or fn, [])
2935 if pstates or states:
2957 if pstates or states:
2936 r = display(fn, ctx, pstates, states)
2958 r = display(fn, ctx, pstates, states)
2937 found = found or r
2959 found = found or r
2938 if r and not opts.get('all'):
2960 if r and not opts.get('all'):
2939 skip[fn] = True
2961 skip[fn] = True
2940 if copy:
2962 if copy:
2941 skip[copy] = True
2963 skip[copy] = True
2942 del matches[rev]
2964 del matches[rev]
2943 del revfiles[rev]
2965 del revfiles[rev]
2944
2966
2945 return not found
2967 return not found
2946
2968
2947 @command('heads',
2969 @command('heads',
2948 [('r', 'rev', '',
2970 [('r', 'rev', '',
2949 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2971 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2950 ('t', 'topo', False, _('show topological heads only')),
2972 ('t', 'topo', False, _('show topological heads only')),
2951 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2973 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2952 ('c', 'closed', False, _('show normal and closed branch heads')),
2974 ('c', 'closed', False, _('show normal and closed branch heads')),
2953 ] + templateopts,
2975 ] + templateopts,
2954 _('[-ac] [-r STARTREV] [REV]...'))
2976 _('[-ac] [-r STARTREV] [REV]...'))
2955 def heads(ui, repo, *branchrevs, **opts):
2977 def heads(ui, repo, *branchrevs, **opts):
2956 """show current repository heads or show branch heads
2978 """show current repository heads or show branch heads
2957
2979
2958 With no arguments, show all repository branch heads.
2980 With no arguments, show all repository branch heads.
2959
2981
2960 Repository "heads" are changesets with no child changesets. They are
2982 Repository "heads" are changesets with no child changesets. They are
2961 where development generally takes place and are the usual targets
2983 where development generally takes place and are the usual targets
2962 for update and merge operations. Branch heads are changesets that have
2984 for update and merge operations. Branch heads are changesets that have
2963 no child changeset on the same branch.
2985 no child changeset on the same branch.
2964
2986
2965 If one or more REVs are given, only branch heads on the branches
2987 If one or more REVs are given, only branch heads on the branches
2966 associated with the specified changesets are shown. This means
2988 associated with the specified changesets are shown. This means
2967 that you can use :hg:`heads foo` to see the heads on a branch
2989 that you can use :hg:`heads foo` to see the heads on a branch
2968 named ``foo``.
2990 named ``foo``.
2969
2991
2970 If -c/--closed is specified, also show branch heads marked closed
2992 If -c/--closed is specified, also show branch heads marked closed
2971 (see :hg:`commit --close-branch`).
2993 (see :hg:`commit --close-branch`).
2972
2994
2973 If STARTREV is specified, only those heads that are descendants of
2995 If STARTREV is specified, only those heads that are descendants of
2974 STARTREV will be displayed.
2996 STARTREV will be displayed.
2975
2997
2976 If -t/--topo is specified, named branch mechanics will be ignored and only
2998 If -t/--topo is specified, named branch mechanics will be ignored and only
2977 changesets without children will be shown.
2999 changesets without children will be shown.
2978
3000
2979 Returns 0 if matching heads are found, 1 if not.
3001 Returns 0 if matching heads are found, 1 if not.
2980 """
3002 """
2981
3003
2982 start = None
3004 start = None
2983 if 'rev' in opts:
3005 if 'rev' in opts:
2984 start = scmutil.revsingle(repo, opts['rev'], None).node()
3006 start = scmutil.revsingle(repo, opts['rev'], None).node()
2985
3007
2986 if opts.get('topo'):
3008 if opts.get('topo'):
2987 heads = [repo[h] for h in repo.heads(start)]
3009 heads = [repo[h] for h in repo.heads(start)]
2988 else:
3010 else:
2989 heads = []
3011 heads = []
2990 for branch in repo.branchmap():
3012 for branch in repo.branchmap():
2991 heads += repo.branchheads(branch, start, opts.get('closed'))
3013 heads += repo.branchheads(branch, start, opts.get('closed'))
2992 heads = [repo[h] for h in heads]
3014 heads = [repo[h] for h in heads]
2993
3015
2994 if branchrevs:
3016 if branchrevs:
2995 branches = set(repo[br].branch() for br in branchrevs)
3017 branches = set(repo[br].branch() for br in branchrevs)
2996 heads = [h for h in heads if h.branch() in branches]
3018 heads = [h for h in heads if h.branch() in branches]
2997
3019
2998 if opts.get('active') and branchrevs:
3020 if opts.get('active') and branchrevs:
2999 dagheads = repo.heads(start)
3021 dagheads = repo.heads(start)
3000 heads = [h for h in heads if h.node() in dagheads]
3022 heads = [h for h in heads if h.node() in dagheads]
3001
3023
3002 if branchrevs:
3024 if branchrevs:
3003 haveheads = set(h.branch() for h in heads)
3025 haveheads = set(h.branch() for h in heads)
3004 if branches - haveheads:
3026 if branches - haveheads:
3005 headless = ', '.join(b for b in branches - haveheads)
3027 headless = ', '.join(b for b in branches - haveheads)
3006 msg = _('no open branch heads found on branches %s')
3028 msg = _('no open branch heads found on branches %s')
3007 if opts.get('rev'):
3029 if opts.get('rev'):
3008 msg += _(' (started at %s)') % opts['rev']
3030 msg += _(' (started at %s)') % opts['rev']
3009 ui.warn((msg + '\n') % headless)
3031 ui.warn((msg + '\n') % headless)
3010
3032
3011 if not heads:
3033 if not heads:
3012 return 1
3034 return 1
3013
3035
3014 heads = sorted(heads, key=lambda x: -x.rev())
3036 heads = sorted(heads, key=lambda x: -x.rev())
3015 displayer = cmdutil.show_changeset(ui, repo, opts)
3037 displayer = cmdutil.show_changeset(ui, repo, opts)
3016 for ctx in heads:
3038 for ctx in heads:
3017 displayer.show(ctx)
3039 displayer.show(ctx)
3018 displayer.close()
3040 displayer.close()
3019
3041
3020 @command('help',
3042 @command('help',
3021 [('e', 'extension', None, _('show only help for extensions')),
3043 [('e', 'extension', None, _('show only help for extensions')),
3022 ('c', 'command', None, _('show only help for commands'))],
3044 ('c', 'command', None, _('show only help for commands'))],
3023 _('[-ec] [TOPIC]'))
3045 _('[-ec] [TOPIC]'))
3024 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3046 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3025 """show help for a given topic or a help overview
3047 """show help for a given topic or a help overview
3026
3048
3027 With no arguments, print a list of commands with short help messages.
3049 With no arguments, print a list of commands with short help messages.
3028
3050
3029 Given a topic, extension, or command name, print help for that
3051 Given a topic, extension, or command name, print help for that
3030 topic.
3052 topic.
3031
3053
3032 Returns 0 if successful.
3054 Returns 0 if successful.
3033 """
3055 """
3034
3056
3035 textwidth = min(ui.termwidth(), 80) - 2
3057 textwidth = min(ui.termwidth(), 80) - 2
3036
3058
3037 def optrst(options):
3059 def optrst(options):
3038 data = []
3060 data = []
3039 multioccur = False
3061 multioccur = False
3040 for option in options:
3062 for option in options:
3041 if len(option) == 5:
3063 if len(option) == 5:
3042 shortopt, longopt, default, desc, optlabel = option
3064 shortopt, longopt, default, desc, optlabel = option
3043 else:
3065 else:
3044 shortopt, longopt, default, desc = option
3066 shortopt, longopt, default, desc = option
3045 optlabel = _("VALUE") # default label
3067 optlabel = _("VALUE") # default label
3046
3068
3047 if _("DEPRECATED") in desc and not ui.verbose:
3069 if _("DEPRECATED") in desc and not ui.verbose:
3048 continue
3070 continue
3049
3071
3050 so = ''
3072 so = ''
3051 if shortopt:
3073 if shortopt:
3052 so = '-' + shortopt
3074 so = '-' + shortopt
3053 lo = '--' + longopt
3075 lo = '--' + longopt
3054 if default:
3076 if default:
3055 desc += _(" (default: %s)") % default
3077 desc += _(" (default: %s)") % default
3056
3078
3057 if isinstance(default, list):
3079 if isinstance(default, list):
3058 lo += " %s [+]" % optlabel
3080 lo += " %s [+]" % optlabel
3059 multioccur = True
3081 multioccur = True
3060 elif (default is not None) and not isinstance(default, bool):
3082 elif (default is not None) and not isinstance(default, bool):
3061 lo += " %s" % optlabel
3083 lo += " %s" % optlabel
3062
3084
3063 data.append((so, lo, desc))
3085 data.append((so, lo, desc))
3064
3086
3065 rst = minirst.maketable(data, 1)
3087 rst = minirst.maketable(data, 1)
3066
3088
3067 if multioccur:
3089 if multioccur:
3068 rst += _("\n[+] marked option can be specified multiple times\n")
3090 rst += _("\n[+] marked option can be specified multiple times\n")
3069
3091
3070 return rst
3092 return rst
3071
3093
3072 # list all option lists
3094 # list all option lists
3073 def opttext(optlist, width):
3095 def opttext(optlist, width):
3074 rst = ''
3096 rst = ''
3075 if not optlist:
3097 if not optlist:
3076 return ''
3098 return ''
3077
3099
3078 for title, options in optlist:
3100 for title, options in optlist:
3079 rst += '\n%s\n' % title
3101 rst += '\n%s\n' % title
3080 if options:
3102 if options:
3081 rst += "\n"
3103 rst += "\n"
3082 rst += optrst(options)
3104 rst += optrst(options)
3083 rst += '\n'
3105 rst += '\n'
3084
3106
3085 return '\n' + minirst.format(rst, width)
3107 return '\n' + minirst.format(rst, width)
3086
3108
3087 def addglobalopts(optlist, aliases):
3109 def addglobalopts(optlist, aliases):
3088 if ui.quiet:
3110 if ui.quiet:
3089 return []
3111 return []
3090
3112
3091 if ui.verbose:
3113 if ui.verbose:
3092 optlist.append((_("global options:"), globalopts))
3114 optlist.append((_("global options:"), globalopts))
3093 if name == 'shortlist':
3115 if name == 'shortlist':
3094 optlist.append((_('use "hg help" for the full list '
3116 optlist.append((_('use "hg help" for the full list '
3095 'of commands'), ()))
3117 'of commands'), ()))
3096 else:
3118 else:
3097 if name == 'shortlist':
3119 if name == 'shortlist':
3098 msg = _('use "hg help" for the full list of commands '
3120 msg = _('use "hg help" for the full list of commands '
3099 'or "hg -v" for details')
3121 'or "hg -v" for details')
3100 elif name and not full:
3122 elif name and not full:
3101 msg = _('use "hg help %s" to show the full help text') % name
3123 msg = _('use "hg help %s" to show the full help text') % name
3102 elif aliases:
3124 elif aliases:
3103 msg = _('use "hg -v help%s" to show builtin aliases and '
3125 msg = _('use "hg -v help%s" to show builtin aliases and '
3104 'global options') % (name and " " + name or "")
3126 'global options') % (name and " " + name or "")
3105 else:
3127 else:
3106 msg = _('use "hg -v help %s" to show more info') % name
3128 msg = _('use "hg -v help %s" to show more info') % name
3107 optlist.append((msg, ()))
3129 optlist.append((msg, ()))
3108
3130
3109 def helpcmd(name):
3131 def helpcmd(name):
3110 try:
3132 try:
3111 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3133 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3112 except error.AmbiguousCommand, inst:
3134 except error.AmbiguousCommand, inst:
3113 # py3k fix: except vars can't be used outside the scope of the
3135 # py3k fix: except vars can't be used outside the scope of the
3114 # except block, nor can be used inside a lambda. python issue4617
3136 # except block, nor can be used inside a lambda. python issue4617
3115 prefix = inst.args[0]
3137 prefix = inst.args[0]
3116 select = lambda c: c.lstrip('^').startswith(prefix)
3138 select = lambda c: c.lstrip('^').startswith(prefix)
3117 helplist(select)
3139 helplist(select)
3118 return
3140 return
3119
3141
3120 # check if it's an invalid alias and display its error if it is
3142 # check if it's an invalid alias and display its error if it is
3121 if getattr(entry[0], 'badalias', False):
3143 if getattr(entry[0], 'badalias', False):
3122 if not unknowncmd:
3144 if not unknowncmd:
3123 entry[0](ui)
3145 entry[0](ui)
3124 return
3146 return
3125
3147
3126 rst = ""
3148 rst = ""
3127
3149
3128 # synopsis
3150 # synopsis
3129 if len(entry) > 2:
3151 if len(entry) > 2:
3130 if entry[2].startswith('hg'):
3152 if entry[2].startswith('hg'):
3131 rst += "%s\n" % entry[2]
3153 rst += "%s\n" % entry[2]
3132 else:
3154 else:
3133 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3155 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3134 else:
3156 else:
3135 rst += 'hg %s\n' % aliases[0]
3157 rst += 'hg %s\n' % aliases[0]
3136
3158
3137 # aliases
3159 # aliases
3138 if full and not ui.quiet and len(aliases) > 1:
3160 if full and not ui.quiet and len(aliases) > 1:
3139 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3161 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3140
3162
3141 # description
3163 # description
3142 doc = gettext(entry[0].__doc__)
3164 doc = gettext(entry[0].__doc__)
3143 if not doc:
3165 if not doc:
3144 doc = _("(no help text available)")
3166 doc = _("(no help text available)")
3145 if util.safehasattr(entry[0], 'definition'): # aliased command
3167 if util.safehasattr(entry[0], 'definition'): # aliased command
3146 if entry[0].definition.startswith('!'): # shell alias
3168 if entry[0].definition.startswith('!'): # shell alias
3147 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3169 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3148 else:
3170 else:
3149 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3171 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3150 if ui.quiet or not full:
3172 if ui.quiet or not full:
3151 doc = doc.splitlines()[0]
3173 doc = doc.splitlines()[0]
3152 rst += "\n" + doc + "\n"
3174 rst += "\n" + doc + "\n"
3153
3175
3154 # check if this command shadows a non-trivial (multi-line)
3176 # check if this command shadows a non-trivial (multi-line)
3155 # extension help text
3177 # extension help text
3156 try:
3178 try:
3157 mod = extensions.find(name)
3179 mod = extensions.find(name)
3158 doc = gettext(mod.__doc__) or ''
3180 doc = gettext(mod.__doc__) or ''
3159 if '\n' in doc.strip():
3181 if '\n' in doc.strip():
3160 msg = _('use "hg help -e %s" to show help for '
3182 msg = _('use "hg help -e %s" to show help for '
3161 'the %s extension') % (name, name)
3183 'the %s extension') % (name, name)
3162 rst += '\n%s\n' % msg
3184 rst += '\n%s\n' % msg
3163 except KeyError:
3185 except KeyError:
3164 pass
3186 pass
3165
3187
3166 # options
3188 # options
3167 if not ui.quiet and entry[1]:
3189 if not ui.quiet and entry[1]:
3168 rst += '\n'
3190 rst += '\n'
3169 rst += _("options:")
3191 rst += _("options:")
3170 rst += '\n\n'
3192 rst += '\n\n'
3171 rst += optrst(entry[1])
3193 rst += optrst(entry[1])
3172
3194
3173 if ui.verbose:
3195 if ui.verbose:
3174 rst += '\n'
3196 rst += '\n'
3175 rst += _("global options:")
3197 rst += _("global options:")
3176 rst += '\n\n'
3198 rst += '\n\n'
3177 rst += optrst(globalopts)
3199 rst += optrst(globalopts)
3178
3200
3179 keep = ui.verbose and ['verbose'] or []
3201 keep = ui.verbose and ['verbose'] or []
3180 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3202 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3181 ui.write(formatted)
3203 ui.write(formatted)
3182
3204
3183 if not ui.verbose:
3205 if not ui.verbose:
3184 if not full:
3206 if not full:
3185 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3207 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3186 % name)
3208 % name)
3187 elif not ui.quiet:
3209 elif not ui.quiet:
3188 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3210 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3189
3211
3190
3212
3191 def helplist(select=None):
3213 def helplist(select=None):
3192 # list of commands
3214 # list of commands
3193 if name == "shortlist":
3215 if name == "shortlist":
3194 header = _('basic commands:\n\n')
3216 header = _('basic commands:\n\n')
3195 else:
3217 else:
3196 header = _('list of commands:\n\n')
3218 header = _('list of commands:\n\n')
3197
3219
3198 h = {}
3220 h = {}
3199 cmds = {}
3221 cmds = {}
3200 for c, e in table.iteritems():
3222 for c, e in table.iteritems():
3201 f = c.split("|", 1)[0]
3223 f = c.split("|", 1)[0]
3202 if select and not select(f):
3224 if select and not select(f):
3203 continue
3225 continue
3204 if (not select and name != 'shortlist' and
3226 if (not select and name != 'shortlist' and
3205 e[0].__module__ != __name__):
3227 e[0].__module__ != __name__):
3206 continue
3228 continue
3207 if name == "shortlist" and not f.startswith("^"):
3229 if name == "shortlist" and not f.startswith("^"):
3208 continue
3230 continue
3209 f = f.lstrip("^")
3231 f = f.lstrip("^")
3210 if not ui.debugflag and f.startswith("debug"):
3232 if not ui.debugflag and f.startswith("debug"):
3211 continue
3233 continue
3212 doc = e[0].__doc__
3234 doc = e[0].__doc__
3213 if doc and 'DEPRECATED' in doc and not ui.verbose:
3235 if doc and 'DEPRECATED' in doc and not ui.verbose:
3214 continue
3236 continue
3215 doc = gettext(doc)
3237 doc = gettext(doc)
3216 if not doc:
3238 if not doc:
3217 doc = _("(no help text available)")
3239 doc = _("(no help text available)")
3218 h[f] = doc.splitlines()[0].rstrip()
3240 h[f] = doc.splitlines()[0].rstrip()
3219 cmds[f] = c.lstrip("^")
3241 cmds[f] = c.lstrip("^")
3220
3242
3221 if not h:
3243 if not h:
3222 ui.status(_('no commands defined\n'))
3244 ui.status(_('no commands defined\n'))
3223 return
3245 return
3224
3246
3225 ui.status(header)
3247 ui.status(header)
3226 fns = sorted(h)
3248 fns = sorted(h)
3227 m = max(map(len, fns))
3249 m = max(map(len, fns))
3228 for f in fns:
3250 for f in fns:
3229 if ui.verbose:
3251 if ui.verbose:
3230 commands = cmds[f].replace("|",", ")
3252 commands = cmds[f].replace("|",", ")
3231 ui.write(" %s:\n %s\n"%(commands, h[f]))
3253 ui.write(" %s:\n %s\n"%(commands, h[f]))
3232 else:
3254 else:
3233 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3255 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3234 initindent=' %-*s ' % (m, f),
3256 initindent=' %-*s ' % (m, f),
3235 hangindent=' ' * (m + 4))))
3257 hangindent=' ' * (m + 4))))
3236
3258
3237 if not name:
3259 if not name:
3238 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3260 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3239 if text:
3261 if text:
3240 ui.write("\n%s" % minirst.format(text, textwidth))
3262 ui.write("\n%s" % minirst.format(text, textwidth))
3241
3263
3242 ui.write(_("\nadditional help topics:\n\n"))
3264 ui.write(_("\nadditional help topics:\n\n"))
3243 topics = []
3265 topics = []
3244 for names, header, doc in help.helptable:
3266 for names, header, doc in help.helptable:
3245 topics.append((sorted(names, key=len, reverse=True)[0], header))
3267 topics.append((sorted(names, key=len, reverse=True)[0], header))
3246 topics_len = max([len(s[0]) for s in topics])
3268 topics_len = max([len(s[0]) for s in topics])
3247 for t, desc in topics:
3269 for t, desc in topics:
3248 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3270 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3249
3271
3250 optlist = []
3272 optlist = []
3251 addglobalopts(optlist, True)
3273 addglobalopts(optlist, True)
3252 ui.write(opttext(optlist, textwidth))
3274 ui.write(opttext(optlist, textwidth))
3253
3275
3254 def helptopic(name):
3276 def helptopic(name):
3255 for names, header, doc in help.helptable:
3277 for names, header, doc in help.helptable:
3256 if name in names:
3278 if name in names:
3257 break
3279 break
3258 else:
3280 else:
3259 raise error.UnknownCommand(name)
3281 raise error.UnknownCommand(name)
3260
3282
3261 # description
3283 # description
3262 if not doc:
3284 if not doc:
3263 doc = _("(no help text available)")
3285 doc = _("(no help text available)")
3264 if util.safehasattr(doc, '__call__'):
3286 if util.safehasattr(doc, '__call__'):
3265 doc = doc()
3287 doc = doc()
3266
3288
3267 ui.write("%s\n\n" % header)
3289 ui.write("%s\n\n" % header)
3268 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3290 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3269 try:
3291 try:
3270 cmdutil.findcmd(name, table)
3292 cmdutil.findcmd(name, table)
3271 ui.write(_('\nuse "hg help -c %s" to see help for '
3293 ui.write(_('\nuse "hg help -c %s" to see help for '
3272 'the %s command\n') % (name, name))
3294 'the %s command\n') % (name, name))
3273 except error.UnknownCommand:
3295 except error.UnknownCommand:
3274 pass
3296 pass
3275
3297
3276 def helpext(name):
3298 def helpext(name):
3277 try:
3299 try:
3278 mod = extensions.find(name)
3300 mod = extensions.find(name)
3279 doc = gettext(mod.__doc__) or _('no help text available')
3301 doc = gettext(mod.__doc__) or _('no help text available')
3280 except KeyError:
3302 except KeyError:
3281 mod = None
3303 mod = None
3282 doc = extensions.disabledext(name)
3304 doc = extensions.disabledext(name)
3283 if not doc:
3305 if not doc:
3284 raise error.UnknownCommand(name)
3306 raise error.UnknownCommand(name)
3285
3307
3286 if '\n' not in doc:
3308 if '\n' not in doc:
3287 head, tail = doc, ""
3309 head, tail = doc, ""
3288 else:
3310 else:
3289 head, tail = doc.split('\n', 1)
3311 head, tail = doc.split('\n', 1)
3290 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3312 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3291 if tail:
3313 if tail:
3292 ui.write(minirst.format(tail, textwidth))
3314 ui.write(minirst.format(tail, textwidth))
3293 ui.status('\n')
3315 ui.status('\n')
3294
3316
3295 if mod:
3317 if mod:
3296 try:
3318 try:
3297 ct = mod.cmdtable
3319 ct = mod.cmdtable
3298 except AttributeError:
3320 except AttributeError:
3299 ct = {}
3321 ct = {}
3300 modcmds = set([c.split('|', 1)[0] for c in ct])
3322 modcmds = set([c.split('|', 1)[0] for c in ct])
3301 helplist(modcmds.__contains__)
3323 helplist(modcmds.__contains__)
3302 else:
3324 else:
3303 ui.write(_('use "hg help extensions" for information on enabling '
3325 ui.write(_('use "hg help extensions" for information on enabling '
3304 'extensions\n'))
3326 'extensions\n'))
3305
3327
3306 def helpextcmd(name):
3328 def helpextcmd(name):
3307 cmd, ext, mod = extensions.disabledcmd(ui, name,
3329 cmd, ext, mod = extensions.disabledcmd(ui, name,
3308 ui.configbool('ui', 'strict'))
3330 ui.configbool('ui', 'strict'))
3309 doc = gettext(mod.__doc__).splitlines()[0]
3331 doc = gettext(mod.__doc__).splitlines()[0]
3310
3332
3311 msg = help.listexts(_("'%s' is provided by the following "
3333 msg = help.listexts(_("'%s' is provided by the following "
3312 "extension:") % cmd, {ext: doc}, indent=4)
3334 "extension:") % cmd, {ext: doc}, indent=4)
3313 ui.write(minirst.format(msg, textwidth))
3335 ui.write(minirst.format(msg, textwidth))
3314 ui.write('\n')
3336 ui.write('\n')
3315 ui.write(_('use "hg help extensions" for information on enabling '
3337 ui.write(_('use "hg help extensions" for information on enabling '
3316 'extensions\n'))
3338 'extensions\n'))
3317
3339
3318 if name and name != 'shortlist':
3340 if name and name != 'shortlist':
3319 i = None
3341 i = None
3320 if unknowncmd:
3342 if unknowncmd:
3321 queries = (helpextcmd,)
3343 queries = (helpextcmd,)
3322 elif opts.get('extension'):
3344 elif opts.get('extension'):
3323 queries = (helpext,)
3345 queries = (helpext,)
3324 elif opts.get('command'):
3346 elif opts.get('command'):
3325 queries = (helpcmd,)
3347 queries = (helpcmd,)
3326 else:
3348 else:
3327 queries = (helptopic, helpcmd, helpext, helpextcmd)
3349 queries = (helptopic, helpcmd, helpext, helpextcmd)
3328 for f in queries:
3350 for f in queries:
3329 try:
3351 try:
3330 f(name)
3352 f(name)
3331 i = None
3353 i = None
3332 break
3354 break
3333 except error.UnknownCommand, inst:
3355 except error.UnknownCommand, inst:
3334 i = inst
3356 i = inst
3335 if i:
3357 if i:
3336 raise i
3358 raise i
3337 else:
3359 else:
3338 # program name
3360 # program name
3339 ui.status(_("Mercurial Distributed SCM\n"))
3361 ui.status(_("Mercurial Distributed SCM\n"))
3340 ui.status('\n')
3362 ui.status('\n')
3341 helplist()
3363 helplist()
3342
3364
3343
3365
3344 @command('identify|id',
3366 @command('identify|id',
3345 [('r', 'rev', '',
3367 [('r', 'rev', '',
3346 _('identify the specified revision'), _('REV')),
3368 _('identify the specified revision'), _('REV')),
3347 ('n', 'num', None, _('show local revision number')),
3369 ('n', 'num', None, _('show local revision number')),
3348 ('i', 'id', None, _('show global revision id')),
3370 ('i', 'id', None, _('show global revision id')),
3349 ('b', 'branch', None, _('show branch')),
3371 ('b', 'branch', None, _('show branch')),
3350 ('t', 'tags', None, _('show tags')),
3372 ('t', 'tags', None, _('show tags')),
3351 ('B', 'bookmarks', None, _('show bookmarks')),
3373 ('B', 'bookmarks', None, _('show bookmarks')),
3352 ] + remoteopts,
3374 ] + remoteopts,
3353 _('[-nibtB] [-r REV] [SOURCE]'))
3375 _('[-nibtB] [-r REV] [SOURCE]'))
3354 def identify(ui, repo, source=None, rev=None,
3376 def identify(ui, repo, source=None, rev=None,
3355 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3377 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3356 """identify the working copy or specified revision
3378 """identify the working copy or specified revision
3357
3379
3358 Print a summary identifying the repository state at REV using one or
3380 Print a summary identifying the repository state at REV using one or
3359 two parent hash identifiers, followed by a "+" if the working
3381 two parent hash identifiers, followed by a "+" if the working
3360 directory has uncommitted changes, the branch name (if not default),
3382 directory has uncommitted changes, the branch name (if not default),
3361 a list of tags, and a list of bookmarks.
3383 a list of tags, and a list of bookmarks.
3362
3384
3363 When REV is not given, print a summary of the current state of the
3385 When REV is not given, print a summary of the current state of the
3364 repository.
3386 repository.
3365
3387
3366 Specifying a path to a repository root or Mercurial bundle will
3388 Specifying a path to a repository root or Mercurial bundle will
3367 cause lookup to operate on that repository/bundle.
3389 cause lookup to operate on that repository/bundle.
3368
3390
3369 .. container:: verbose
3391 .. container:: verbose
3370
3392
3371 Examples:
3393 Examples:
3372
3394
3373 - generate a build identifier for the working directory::
3395 - generate a build identifier for the working directory::
3374
3396
3375 hg id --id > build-id.dat
3397 hg id --id > build-id.dat
3376
3398
3377 - find the revision corresponding to a tag::
3399 - find the revision corresponding to a tag::
3378
3400
3379 hg id -n -r 1.3
3401 hg id -n -r 1.3
3380
3402
3381 - check the most recent revision of a remote repository::
3403 - check the most recent revision of a remote repository::
3382
3404
3383 hg id -r tip http://selenic.com/hg/
3405 hg id -r tip http://selenic.com/hg/
3384
3406
3385 Returns 0 if successful.
3407 Returns 0 if successful.
3386 """
3408 """
3387
3409
3388 if not repo and not source:
3410 if not repo and not source:
3389 raise util.Abort(_("there is no Mercurial repository here "
3411 raise util.Abort(_("there is no Mercurial repository here "
3390 "(.hg not found)"))
3412 "(.hg not found)"))
3391
3413
3392 hexfunc = ui.debugflag and hex or short
3414 hexfunc = ui.debugflag and hex or short
3393 default = not (num or id or branch or tags or bookmarks)
3415 default = not (num or id or branch or tags or bookmarks)
3394 output = []
3416 output = []
3395 revs = []
3417 revs = []
3396
3418
3397 if source:
3419 if source:
3398 source, branches = hg.parseurl(ui.expandpath(source))
3420 source, branches = hg.parseurl(ui.expandpath(source))
3399 repo = hg.peer(ui, opts, source)
3421 repo = hg.peer(ui, opts, source)
3400 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3422 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3401
3423
3402 if not repo.local():
3424 if not repo.local():
3403 if num or branch or tags:
3425 if num or branch or tags:
3404 raise util.Abort(
3426 raise util.Abort(
3405 _("can't query remote revision number, branch, or tags"))
3427 _("can't query remote revision number, branch, or tags"))
3406 if not rev and revs:
3428 if not rev and revs:
3407 rev = revs[0]
3429 rev = revs[0]
3408 if not rev:
3430 if not rev:
3409 rev = "tip"
3431 rev = "tip"
3410
3432
3411 remoterev = repo.lookup(rev)
3433 remoterev = repo.lookup(rev)
3412 if default or id:
3434 if default or id:
3413 output = [hexfunc(remoterev)]
3435 output = [hexfunc(remoterev)]
3414
3436
3415 def getbms():
3437 def getbms():
3416 bms = []
3438 bms = []
3417
3439
3418 if 'bookmarks' in repo.listkeys('namespaces'):
3440 if 'bookmarks' in repo.listkeys('namespaces'):
3419 hexremoterev = hex(remoterev)
3441 hexremoterev = hex(remoterev)
3420 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3442 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3421 if bmr == hexremoterev]
3443 if bmr == hexremoterev]
3422
3444
3423 return bms
3445 return bms
3424
3446
3425 if bookmarks:
3447 if bookmarks:
3426 output.extend(getbms())
3448 output.extend(getbms())
3427 elif default and not ui.quiet:
3449 elif default and not ui.quiet:
3428 # multiple bookmarks for a single parent separated by '/'
3450 # multiple bookmarks for a single parent separated by '/'
3429 bm = '/'.join(getbms())
3451 bm = '/'.join(getbms())
3430 if bm:
3452 if bm:
3431 output.append(bm)
3453 output.append(bm)
3432 else:
3454 else:
3433 if not rev:
3455 if not rev:
3434 ctx = repo[None]
3456 ctx = repo[None]
3435 parents = ctx.parents()
3457 parents = ctx.parents()
3436 changed = ""
3458 changed = ""
3437 if default or id or num:
3459 if default or id or num:
3438 changed = util.any(repo.status()) and "+" or ""
3460 changed = util.any(repo.status()) and "+" or ""
3439 if default or id:
3461 if default or id:
3440 output = ["%s%s" %
3462 output = ["%s%s" %
3441 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3463 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3442 if num:
3464 if num:
3443 output.append("%s%s" %
3465 output.append("%s%s" %
3444 ('+'.join([str(p.rev()) for p in parents]), changed))
3466 ('+'.join([str(p.rev()) for p in parents]), changed))
3445 else:
3467 else:
3446 ctx = scmutil.revsingle(repo, rev)
3468 ctx = scmutil.revsingle(repo, rev)
3447 if default or id:
3469 if default or id:
3448 output = [hexfunc(ctx.node())]
3470 output = [hexfunc(ctx.node())]
3449 if num:
3471 if num:
3450 output.append(str(ctx.rev()))
3472 output.append(str(ctx.rev()))
3451
3473
3452 if default and not ui.quiet:
3474 if default and not ui.quiet:
3453 b = ctx.branch()
3475 b = ctx.branch()
3454 if b != 'default':
3476 if b != 'default':
3455 output.append("(%s)" % b)
3477 output.append("(%s)" % b)
3456
3478
3457 # multiple tags for a single parent separated by '/'
3479 # multiple tags for a single parent separated by '/'
3458 t = '/'.join(ctx.tags())
3480 t = '/'.join(ctx.tags())
3459 if t:
3481 if t:
3460 output.append(t)
3482 output.append(t)
3461
3483
3462 # multiple bookmarks for a single parent separated by '/'
3484 # multiple bookmarks for a single parent separated by '/'
3463 bm = '/'.join(ctx.bookmarks())
3485 bm = '/'.join(ctx.bookmarks())
3464 if bm:
3486 if bm:
3465 output.append(bm)
3487 output.append(bm)
3466 else:
3488 else:
3467 if branch:
3489 if branch:
3468 output.append(ctx.branch())
3490 output.append(ctx.branch())
3469
3491
3470 if tags:
3492 if tags:
3471 output.extend(ctx.tags())
3493 output.extend(ctx.tags())
3472
3494
3473 if bookmarks:
3495 if bookmarks:
3474 output.extend(ctx.bookmarks())
3496 output.extend(ctx.bookmarks())
3475
3497
3476 ui.write("%s\n" % ' '.join(output))
3498 ui.write("%s\n" % ' '.join(output))
3477
3499
3478 @command('import|patch',
3500 @command('import|patch',
3479 [('p', 'strip', 1,
3501 [('p', 'strip', 1,
3480 _('directory strip option for patch. This has the same '
3502 _('directory strip option for patch. This has the same '
3481 'meaning as the corresponding patch option'), _('NUM')),
3503 'meaning as the corresponding patch option'), _('NUM')),
3482 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3504 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3483 ('e', 'edit', False, _('invoke editor on commit messages')),
3505 ('e', 'edit', False, _('invoke editor on commit messages')),
3484 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3506 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3485 ('', 'no-commit', None,
3507 ('', 'no-commit', None,
3486 _("don't commit, just update the working directory")),
3508 _("don't commit, just update the working directory")),
3487 ('', 'bypass', None,
3509 ('', 'bypass', None,
3488 _("apply patch without touching the working directory")),
3510 _("apply patch without touching the working directory")),
3489 ('', 'exact', None,
3511 ('', 'exact', None,
3490 _('apply patch to the nodes from which it was generated')),
3512 _('apply patch to the nodes from which it was generated')),
3491 ('', 'import-branch', None,
3513 ('', 'import-branch', None,
3492 _('use any branch information in patch (implied by --exact)'))] +
3514 _('use any branch information in patch (implied by --exact)'))] +
3493 commitopts + commitopts2 + similarityopts,
3515 commitopts + commitopts2 + similarityopts,
3494 _('[OPTION]... PATCH...'))
3516 _('[OPTION]... PATCH...'))
3495 def import_(ui, repo, patch1=None, *patches, **opts):
3517 def import_(ui, repo, patch1=None, *patches, **opts):
3496 """import an ordered set of patches
3518 """import an ordered set of patches
3497
3519
3498 Import a list of patches and commit them individually (unless
3520 Import a list of patches and commit them individually (unless
3499 --no-commit is specified).
3521 --no-commit is specified).
3500
3522
3501 If there are outstanding changes in the working directory, import
3523 If there are outstanding changes in the working directory, import
3502 will abort unless given the -f/--force flag.
3524 will abort unless given the -f/--force flag.
3503
3525
3504 You can import a patch straight from a mail message. Even patches
3526 You can import a patch straight from a mail message. Even patches
3505 as attachments work (to use the body part, it must have type
3527 as attachments work (to use the body part, it must have type
3506 text/plain or text/x-patch). From and Subject headers of email
3528 text/plain or text/x-patch). From and Subject headers of email
3507 message are used as default committer and commit message. All
3529 message are used as default committer and commit message. All
3508 text/plain body parts before first diff are added to commit
3530 text/plain body parts before first diff are added to commit
3509 message.
3531 message.
3510
3532
3511 If the imported patch was generated by :hg:`export`, user and
3533 If the imported patch was generated by :hg:`export`, user and
3512 description from patch override values from message headers and
3534 description from patch override values from message headers and
3513 body. Values given on command line with -m/--message and -u/--user
3535 body. Values given on command line with -m/--message and -u/--user
3514 override these.
3536 override these.
3515
3537
3516 If --exact is specified, import will set the working directory to
3538 If --exact is specified, import will set the working directory to
3517 the parent of each patch before applying it, and will abort if the
3539 the parent of each patch before applying it, and will abort if the
3518 resulting changeset has a different ID than the one recorded in
3540 resulting changeset has a different ID than the one recorded in
3519 the patch. This may happen due to character set problems or other
3541 the patch. This may happen due to character set problems or other
3520 deficiencies in the text patch format.
3542 deficiencies in the text patch format.
3521
3543
3522 Use --bypass to apply and commit patches directly to the
3544 Use --bypass to apply and commit patches directly to the
3523 repository, not touching the working directory. Without --exact,
3545 repository, not touching the working directory. Without --exact,
3524 patches will be applied on top of the working directory parent
3546 patches will be applied on top of the working directory parent
3525 revision.
3547 revision.
3526
3548
3527 With -s/--similarity, hg will attempt to discover renames and
3549 With -s/--similarity, hg will attempt to discover renames and
3528 copies in the patch in the same way as :hg:`addremove`.
3550 copies in the patch in the same way as :hg:`addremove`.
3529
3551
3530 To read a patch from standard input, use "-" as the patch name. If
3552 To read a patch from standard input, use "-" as the patch name. If
3531 a URL is specified, the patch will be downloaded from it.
3553 a URL is specified, the patch will be downloaded from it.
3532 See :hg:`help dates` for a list of formats valid for -d/--date.
3554 See :hg:`help dates` for a list of formats valid for -d/--date.
3533
3555
3534 .. container:: verbose
3556 .. container:: verbose
3535
3557
3536 Examples:
3558 Examples:
3537
3559
3538 - import a traditional patch from a website and detect renames::
3560 - import a traditional patch from a website and detect renames::
3539
3561
3540 hg import -s 80 http://example.com/bugfix.patch
3562 hg import -s 80 http://example.com/bugfix.patch
3541
3563
3542 - import a changeset from an hgweb server::
3564 - import a changeset from an hgweb server::
3543
3565
3544 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3566 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3545
3567
3546 - import all the patches in an Unix-style mbox::
3568 - import all the patches in an Unix-style mbox::
3547
3569
3548 hg import incoming-patches.mbox
3570 hg import incoming-patches.mbox
3549
3571
3550 - attempt to exactly restore an exported changeset (not always
3572 - attempt to exactly restore an exported changeset (not always
3551 possible)::
3573 possible)::
3552
3574
3553 hg import --exact proposed-fix.patch
3575 hg import --exact proposed-fix.patch
3554
3576
3555 Returns 0 on success.
3577 Returns 0 on success.
3556 """
3578 """
3557
3579
3558 if not patch1:
3580 if not patch1:
3559 raise util.Abort(_('need at least one patch to import'))
3581 raise util.Abort(_('need at least one patch to import'))
3560
3582
3561 patches = (patch1,) + patches
3583 patches = (patch1,) + patches
3562
3584
3563 date = opts.get('date')
3585 date = opts.get('date')
3564 if date:
3586 if date:
3565 opts['date'] = util.parsedate(date)
3587 opts['date'] = util.parsedate(date)
3566
3588
3567 editor = cmdutil.commiteditor
3589 editor = cmdutil.commiteditor
3568 if opts.get('edit'):
3590 if opts.get('edit'):
3569 editor = cmdutil.commitforceeditor
3591 editor = cmdutil.commitforceeditor
3570
3592
3571 update = not opts.get('bypass')
3593 update = not opts.get('bypass')
3572 if not update and opts.get('no_commit'):
3594 if not update and opts.get('no_commit'):
3573 raise util.Abort(_('cannot use --no-commit with --bypass'))
3595 raise util.Abort(_('cannot use --no-commit with --bypass'))
3574 try:
3596 try:
3575 sim = float(opts.get('similarity') or 0)
3597 sim = float(opts.get('similarity') or 0)
3576 except ValueError:
3598 except ValueError:
3577 raise util.Abort(_('similarity must be a number'))
3599 raise util.Abort(_('similarity must be a number'))
3578 if sim < 0 or sim > 100:
3600 if sim < 0 or sim > 100:
3579 raise util.Abort(_('similarity must be between 0 and 100'))
3601 raise util.Abort(_('similarity must be between 0 and 100'))
3580 if sim and not update:
3602 if sim and not update:
3581 raise util.Abort(_('cannot use --similarity with --bypass'))
3603 raise util.Abort(_('cannot use --similarity with --bypass'))
3582
3604
3583 if (opts.get('exact') or not opts.get('force')) and update:
3605 if (opts.get('exact') or not opts.get('force')) and update:
3584 cmdutil.bailifchanged(repo)
3606 cmdutil.bailifchanged(repo)
3585
3607
3586 base = opts["base"]
3608 base = opts["base"]
3587 strip = opts["strip"]
3609 strip = opts["strip"]
3588 wlock = lock = tr = None
3610 wlock = lock = tr = None
3589 msgs = []
3611 msgs = []
3590
3612
3591 def checkexact(repo, n, nodeid):
3613 def checkexact(repo, n, nodeid):
3592 if opts.get('exact') and hex(n) != nodeid:
3614 if opts.get('exact') and hex(n) != nodeid:
3593 repo.rollback()
3615 repo.rollback()
3594 raise util.Abort(_('patch is damaged or loses information'))
3616 raise util.Abort(_('patch is damaged or loses information'))
3595
3617
3596 def tryone(ui, hunk, parents):
3618 def tryone(ui, hunk, parents):
3597 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3619 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3598 patch.extract(ui, hunk)
3620 patch.extract(ui, hunk)
3599
3621
3600 if not tmpname:
3622 if not tmpname:
3601 return (None, None)
3623 return (None, None)
3602 msg = _('applied to working directory')
3624 msg = _('applied to working directory')
3603
3625
3604 try:
3626 try:
3605 cmdline_message = cmdutil.logmessage(ui, opts)
3627 cmdline_message = cmdutil.logmessage(ui, opts)
3606 if cmdline_message:
3628 if cmdline_message:
3607 # pickup the cmdline msg
3629 # pickup the cmdline msg
3608 message = cmdline_message
3630 message = cmdline_message
3609 elif message:
3631 elif message:
3610 # pickup the patch msg
3632 # pickup the patch msg
3611 message = message.strip()
3633 message = message.strip()
3612 else:
3634 else:
3613 # launch the editor
3635 # launch the editor
3614 message = None
3636 message = None
3615 ui.debug('message:\n%s\n' % message)
3637 ui.debug('message:\n%s\n' % message)
3616
3638
3617 if len(parents) == 1:
3639 if len(parents) == 1:
3618 parents.append(repo[nullid])
3640 parents.append(repo[nullid])
3619 if opts.get('exact'):
3641 if opts.get('exact'):
3620 if not nodeid or not p1:
3642 if not nodeid or not p1:
3621 raise util.Abort(_('not a Mercurial patch'))
3643 raise util.Abort(_('not a Mercurial patch'))
3622 p1 = repo[p1]
3644 p1 = repo[p1]
3623 p2 = repo[p2 or nullid]
3645 p2 = repo[p2 or nullid]
3624 elif p2:
3646 elif p2:
3625 try:
3647 try:
3626 p1 = repo[p1]
3648 p1 = repo[p1]
3627 p2 = repo[p2]
3649 p2 = repo[p2]
3628 # Without any options, consider p2 only if the
3650 # Without any options, consider p2 only if the
3629 # patch is being applied on top of the recorded
3651 # patch is being applied on top of the recorded
3630 # first parent.
3652 # first parent.
3631 if p1 != parents[0]:
3653 if p1 != parents[0]:
3632 p1 = parents[0]
3654 p1 = parents[0]
3633 p2 = repo[nullid]
3655 p2 = repo[nullid]
3634 except error.RepoError:
3656 except error.RepoError:
3635 p1, p2 = parents
3657 p1, p2 = parents
3636 else:
3658 else:
3637 p1, p2 = parents
3659 p1, p2 = parents
3638
3660
3639 n = None
3661 n = None
3640 if update:
3662 if update:
3641 if p1 != parents[0]:
3663 if p1 != parents[0]:
3642 hg.clean(repo, p1.node())
3664 hg.clean(repo, p1.node())
3643 if p2 != parents[1]:
3665 if p2 != parents[1]:
3644 repo.setparents(p1.node(), p2.node())
3666 repo.setparents(p1.node(), p2.node())
3645
3667
3646 if opts.get('exact') or opts.get('import_branch'):
3668 if opts.get('exact') or opts.get('import_branch'):
3647 repo.dirstate.setbranch(branch or 'default')
3669 repo.dirstate.setbranch(branch or 'default')
3648
3670
3649 files = set()
3671 files = set()
3650 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3672 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3651 eolmode=None, similarity=sim / 100.0)
3673 eolmode=None, similarity=sim / 100.0)
3652 files = list(files)
3674 files = list(files)
3653 if opts.get('no_commit'):
3675 if opts.get('no_commit'):
3654 if message:
3676 if message:
3655 msgs.append(message)
3677 msgs.append(message)
3656 else:
3678 else:
3657 if opts.get('exact') or p2:
3679 if opts.get('exact') or p2:
3658 # If you got here, you either use --force and know what
3680 # If you got here, you either use --force and know what
3659 # you are doing or used --exact or a merge patch while
3681 # you are doing or used --exact or a merge patch while
3660 # being updated to its first parent.
3682 # being updated to its first parent.
3661 m = None
3683 m = None
3662 else:
3684 else:
3663 m = scmutil.matchfiles(repo, files or [])
3685 m = scmutil.matchfiles(repo, files or [])
3664 n = repo.commit(message, opts.get('user') or user,
3686 n = repo.commit(message, opts.get('user') or user,
3665 opts.get('date') or date, match=m,
3687 opts.get('date') or date, match=m,
3666 editor=editor)
3688 editor=editor)
3667 checkexact(repo, n, nodeid)
3689 checkexact(repo, n, nodeid)
3668 else:
3690 else:
3669 if opts.get('exact') or opts.get('import_branch'):
3691 if opts.get('exact') or opts.get('import_branch'):
3670 branch = branch or 'default'
3692 branch = branch or 'default'
3671 else:
3693 else:
3672 branch = p1.branch()
3694 branch = p1.branch()
3673 store = patch.filestore()
3695 store = patch.filestore()
3674 try:
3696 try:
3675 files = set()
3697 files = set()
3676 try:
3698 try:
3677 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3699 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3678 files, eolmode=None)
3700 files, eolmode=None)
3679 except patch.PatchError, e:
3701 except patch.PatchError, e:
3680 raise util.Abort(str(e))
3702 raise util.Abort(str(e))
3681 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3703 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3682 message,
3704 message,
3683 opts.get('user') or user,
3705 opts.get('user') or user,
3684 opts.get('date') or date,
3706 opts.get('date') or date,
3685 branch, files, store,
3707 branch, files, store,
3686 editor=cmdutil.commiteditor)
3708 editor=cmdutil.commiteditor)
3687 repo.savecommitmessage(memctx.description())
3709 repo.savecommitmessage(memctx.description())
3688 n = memctx.commit()
3710 n = memctx.commit()
3689 checkexact(repo, n, nodeid)
3711 checkexact(repo, n, nodeid)
3690 finally:
3712 finally:
3691 store.close()
3713 store.close()
3692 if n:
3714 if n:
3693 # i18n: refers to a short changeset id
3715 # i18n: refers to a short changeset id
3694 msg = _('created %s') % short(n)
3716 msg = _('created %s') % short(n)
3695 return (msg, n)
3717 return (msg, n)
3696 finally:
3718 finally:
3697 os.unlink(tmpname)
3719 os.unlink(tmpname)
3698
3720
3699 try:
3721 try:
3700 try:
3722 try:
3701 wlock = repo.wlock()
3723 wlock = repo.wlock()
3702 if not opts.get('no_commit'):
3724 if not opts.get('no_commit'):
3703 lock = repo.lock()
3725 lock = repo.lock()
3704 tr = repo.transaction('import')
3726 tr = repo.transaction('import')
3705 parents = repo.parents()
3727 parents = repo.parents()
3706 for patchurl in patches:
3728 for patchurl in patches:
3707 if patchurl == '-':
3729 if patchurl == '-':
3708 ui.status(_('applying patch from stdin\n'))
3730 ui.status(_('applying patch from stdin\n'))
3709 patchfile = ui.fin
3731 patchfile = ui.fin
3710 patchurl = 'stdin' # for error message
3732 patchurl = 'stdin' # for error message
3711 else:
3733 else:
3712 patchurl = os.path.join(base, patchurl)
3734 patchurl = os.path.join(base, patchurl)
3713 ui.status(_('applying %s\n') % patchurl)
3735 ui.status(_('applying %s\n') % patchurl)
3714 patchfile = url.open(ui, patchurl)
3736 patchfile = url.open(ui, patchurl)
3715
3737
3716 haspatch = False
3738 haspatch = False
3717 for hunk in patch.split(patchfile):
3739 for hunk in patch.split(patchfile):
3718 (msg, node) = tryone(ui, hunk, parents)
3740 (msg, node) = tryone(ui, hunk, parents)
3719 if msg:
3741 if msg:
3720 haspatch = True
3742 haspatch = True
3721 ui.note(msg + '\n')
3743 ui.note(msg + '\n')
3722 if update or opts.get('exact'):
3744 if update or opts.get('exact'):
3723 parents = repo.parents()
3745 parents = repo.parents()
3724 else:
3746 else:
3725 parents = [repo[node]]
3747 parents = [repo[node]]
3726
3748
3727 if not haspatch:
3749 if not haspatch:
3728 raise util.Abort(_('%s: no diffs found') % patchurl)
3750 raise util.Abort(_('%s: no diffs found') % patchurl)
3729
3751
3730 if tr:
3752 if tr:
3731 tr.close()
3753 tr.close()
3732 if msgs:
3754 if msgs:
3733 repo.savecommitmessage('\n* * *\n'.join(msgs))
3755 repo.savecommitmessage('\n* * *\n'.join(msgs))
3734 except:
3756 except:
3735 # wlock.release() indirectly calls dirstate.write(): since
3757 # wlock.release() indirectly calls dirstate.write(): since
3736 # we're crashing, we do not want to change the working dir
3758 # we're crashing, we do not want to change the working dir
3737 # parent after all, so make sure it writes nothing
3759 # parent after all, so make sure it writes nothing
3738 repo.dirstate.invalidate()
3760 repo.dirstate.invalidate()
3739 raise
3761 raise
3740 finally:
3762 finally:
3741 if tr:
3763 if tr:
3742 tr.release()
3764 tr.release()
3743 release(lock, wlock)
3765 release(lock, wlock)
3744
3766
3745 @command('incoming|in',
3767 @command('incoming|in',
3746 [('f', 'force', None,
3768 [('f', 'force', None,
3747 _('run even if remote repository is unrelated')),
3769 _('run even if remote repository is unrelated')),
3748 ('n', 'newest-first', None, _('show newest record first')),
3770 ('n', 'newest-first', None, _('show newest record first')),
3749 ('', 'bundle', '',
3771 ('', 'bundle', '',
3750 _('file to store the bundles into'), _('FILE')),
3772 _('file to store the bundles into'), _('FILE')),
3751 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3773 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3752 ('B', 'bookmarks', False, _("compare bookmarks")),
3774 ('B', 'bookmarks', False, _("compare bookmarks")),
3753 ('b', 'branch', [],
3775 ('b', 'branch', [],
3754 _('a specific branch you would like to pull'), _('BRANCH')),
3776 _('a specific branch you would like to pull'), _('BRANCH')),
3755 ] + logopts + remoteopts + subrepoopts,
3777 ] + logopts + remoteopts + subrepoopts,
3756 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3778 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3757 def incoming(ui, repo, source="default", **opts):
3779 def incoming(ui, repo, source="default", **opts):
3758 """show new changesets found in source
3780 """show new changesets found in source
3759
3781
3760 Show new changesets found in the specified path/URL or the default
3782 Show new changesets found in the specified path/URL or the default
3761 pull location. These are the changesets that would have been pulled
3783 pull location. These are the changesets that would have been pulled
3762 if a pull at the time you issued this command.
3784 if a pull at the time you issued this command.
3763
3785
3764 For remote repository, using --bundle avoids downloading the
3786 For remote repository, using --bundle avoids downloading the
3765 changesets twice if the incoming is followed by a pull.
3787 changesets twice if the incoming is followed by a pull.
3766
3788
3767 See pull for valid source format details.
3789 See pull for valid source format details.
3768
3790
3769 Returns 0 if there are incoming changes, 1 otherwise.
3791 Returns 0 if there are incoming changes, 1 otherwise.
3770 """
3792 """
3771 if opts.get('bundle') and opts.get('subrepos'):
3793 if opts.get('bundle') and opts.get('subrepos'):
3772 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3794 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3773
3795
3774 if opts.get('bookmarks'):
3796 if opts.get('bookmarks'):
3775 source, branches = hg.parseurl(ui.expandpath(source),
3797 source, branches = hg.parseurl(ui.expandpath(source),
3776 opts.get('branch'))
3798 opts.get('branch'))
3777 other = hg.peer(repo, opts, source)
3799 other = hg.peer(repo, opts, source)
3778 if 'bookmarks' not in other.listkeys('namespaces'):
3800 if 'bookmarks' not in other.listkeys('namespaces'):
3779 ui.warn(_("remote doesn't support bookmarks\n"))
3801 ui.warn(_("remote doesn't support bookmarks\n"))
3780 return 0
3802 return 0
3781 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3803 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3782 return bookmarks.diff(ui, repo, other)
3804 return bookmarks.diff(ui, repo, other)
3783
3805
3784 repo._subtoppath = ui.expandpath(source)
3806 repo._subtoppath = ui.expandpath(source)
3785 try:
3807 try:
3786 return hg.incoming(ui, repo, source, opts)
3808 return hg.incoming(ui, repo, source, opts)
3787 finally:
3809 finally:
3788 del repo._subtoppath
3810 del repo._subtoppath
3789
3811
3790
3812
3791 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3813 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3792 def init(ui, dest=".", **opts):
3814 def init(ui, dest=".", **opts):
3793 """create a new repository in the given directory
3815 """create a new repository in the given directory
3794
3816
3795 Initialize a new repository in the given directory. If the given
3817 Initialize a new repository in the given directory. If the given
3796 directory does not exist, it will be created.
3818 directory does not exist, it will be created.
3797
3819
3798 If no directory is given, the current directory is used.
3820 If no directory is given, the current directory is used.
3799
3821
3800 It is possible to specify an ``ssh://`` URL as the destination.
3822 It is possible to specify an ``ssh://`` URL as the destination.
3801 See :hg:`help urls` for more information.
3823 See :hg:`help urls` for more information.
3802
3824
3803 Returns 0 on success.
3825 Returns 0 on success.
3804 """
3826 """
3805 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3827 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3806
3828
3807 @command('locate',
3829 @command('locate',
3808 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3830 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3809 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3831 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3810 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3832 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3811 ] + walkopts,
3833 ] + walkopts,
3812 _('[OPTION]... [PATTERN]...'))
3834 _('[OPTION]... [PATTERN]...'))
3813 def locate(ui, repo, *pats, **opts):
3835 def locate(ui, repo, *pats, **opts):
3814 """locate files matching specific patterns
3836 """locate files matching specific patterns
3815
3837
3816 Print files under Mercurial control in the working directory whose
3838 Print files under Mercurial control in the working directory whose
3817 names match the given patterns.
3839 names match the given patterns.
3818
3840
3819 By default, this command searches all directories in the working
3841 By default, this command searches all directories in the working
3820 directory. To search just the current directory and its
3842 directory. To search just the current directory and its
3821 subdirectories, use "--include .".
3843 subdirectories, use "--include .".
3822
3844
3823 If no patterns are given to match, this command prints the names
3845 If no patterns are given to match, this command prints the names
3824 of all files under Mercurial control in the working directory.
3846 of all files under Mercurial control in the working directory.
3825
3847
3826 If you want to feed the output of this command into the "xargs"
3848 If you want to feed the output of this command into the "xargs"
3827 command, use the -0 option to both this command and "xargs". This
3849 command, use the -0 option to both this command and "xargs". This
3828 will avoid the problem of "xargs" treating single filenames that
3850 will avoid the problem of "xargs" treating single filenames that
3829 contain whitespace as multiple filenames.
3851 contain whitespace as multiple filenames.
3830
3852
3831 Returns 0 if a match is found, 1 otherwise.
3853 Returns 0 if a match is found, 1 otherwise.
3832 """
3854 """
3833 end = opts.get('print0') and '\0' or '\n'
3855 end = opts.get('print0') and '\0' or '\n'
3834 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3856 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3835
3857
3836 ret = 1
3858 ret = 1
3837 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3859 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3838 m.bad = lambda x, y: False
3860 m.bad = lambda x, y: False
3839 for abs in repo[rev].walk(m):
3861 for abs in repo[rev].walk(m):
3840 if not rev and abs not in repo.dirstate:
3862 if not rev and abs not in repo.dirstate:
3841 continue
3863 continue
3842 if opts.get('fullpath'):
3864 if opts.get('fullpath'):
3843 ui.write(repo.wjoin(abs), end)
3865 ui.write(repo.wjoin(abs), end)
3844 else:
3866 else:
3845 ui.write(((pats and m.rel(abs)) or abs), end)
3867 ui.write(((pats and m.rel(abs)) or abs), end)
3846 ret = 0
3868 ret = 0
3847
3869
3848 return ret
3870 return ret
3849
3871
3850 @command('^log|history',
3872 @command('^log|history',
3851 [('f', 'follow', None,
3873 [('f', 'follow', None,
3852 _('follow changeset history, or file history across copies and renames')),
3874 _('follow changeset history, or file history across copies and renames')),
3853 ('', 'follow-first', None,
3875 ('', 'follow-first', None,
3854 _('only follow the first parent of merge changesets (DEPRECATED)')),
3876 _('only follow the first parent of merge changesets (DEPRECATED)')),
3855 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3877 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3856 ('C', 'copies', None, _('show copied files')),
3878 ('C', 'copies', None, _('show copied files')),
3857 ('k', 'keyword', [],
3879 ('k', 'keyword', [],
3858 _('do case-insensitive search for a given text'), _('TEXT')),
3880 _('do case-insensitive search for a given text'), _('TEXT')),
3859 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3881 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3860 ('', 'removed', None, _('include revisions where files were removed')),
3882 ('', 'removed', None, _('include revisions where files were removed')),
3861 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3883 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3862 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3884 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3863 ('', 'only-branch', [],
3885 ('', 'only-branch', [],
3864 _('show only changesets within the given named branch (DEPRECATED)'),
3886 _('show only changesets within the given named branch (DEPRECATED)'),
3865 _('BRANCH')),
3887 _('BRANCH')),
3866 ('b', 'branch', [],
3888 ('b', 'branch', [],
3867 _('show changesets within the given named branch'), _('BRANCH')),
3889 _('show changesets within the given named branch'), _('BRANCH')),
3868 ('P', 'prune', [],
3890 ('P', 'prune', [],
3869 _('do not display revision or any of its ancestors'), _('REV')),
3891 _('do not display revision or any of its ancestors'), _('REV')),
3870 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3892 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3871 ] + logopts + walkopts,
3893 ] + logopts + walkopts,
3872 _('[OPTION]... [FILE]'))
3894 _('[OPTION]... [FILE]'))
3873 def log(ui, repo, *pats, **opts):
3895 def log(ui, repo, *pats, **opts):
3874 """show revision history of entire repository or files
3896 """show revision history of entire repository or files
3875
3897
3876 Print the revision history of the specified files or the entire
3898 Print the revision history of the specified files or the entire
3877 project.
3899 project.
3878
3900
3879 If no revision range is specified, the default is ``tip:0`` unless
3901 If no revision range is specified, the default is ``tip:0`` unless
3880 --follow is set, in which case the working directory parent is
3902 --follow is set, in which case the working directory parent is
3881 used as the starting revision.
3903 used as the starting revision.
3882
3904
3883 File history is shown without following rename or copy history of
3905 File history is shown without following rename or copy history of
3884 files. Use -f/--follow with a filename to follow history across
3906 files. Use -f/--follow with a filename to follow history across
3885 renames and copies. --follow without a filename will only show
3907 renames and copies. --follow without a filename will only show
3886 ancestors or descendants of the starting revision.
3908 ancestors or descendants of the starting revision.
3887
3909
3888 By default this command prints revision number and changeset id,
3910 By default this command prints revision number and changeset id,
3889 tags, non-trivial parents, user, date and time, and a summary for
3911 tags, non-trivial parents, user, date and time, and a summary for
3890 each commit. When the -v/--verbose switch is used, the list of
3912 each commit. When the -v/--verbose switch is used, the list of
3891 changed files and full commit message are shown.
3913 changed files and full commit message are shown.
3892
3914
3893 .. note::
3915 .. note::
3894 log -p/--patch may generate unexpected diff output for merge
3916 log -p/--patch may generate unexpected diff output for merge
3895 changesets, as it will only compare the merge changeset against
3917 changesets, as it will only compare the merge changeset against
3896 its first parent. Also, only files different from BOTH parents
3918 its first parent. Also, only files different from BOTH parents
3897 will appear in files:.
3919 will appear in files:.
3898
3920
3899 .. note::
3921 .. note::
3900 for performance reasons, log FILE may omit duplicate changes
3922 for performance reasons, log FILE may omit duplicate changes
3901 made on branches and will not show deletions. To see all
3923 made on branches and will not show deletions. To see all
3902 changes including duplicates and deletions, use the --removed
3924 changes including duplicates and deletions, use the --removed
3903 switch.
3925 switch.
3904
3926
3905 .. container:: verbose
3927 .. container:: verbose
3906
3928
3907 Some examples:
3929 Some examples:
3908
3930
3909 - changesets with full descriptions and file lists::
3931 - changesets with full descriptions and file lists::
3910
3932
3911 hg log -v
3933 hg log -v
3912
3934
3913 - changesets ancestral to the working directory::
3935 - changesets ancestral to the working directory::
3914
3936
3915 hg log -f
3937 hg log -f
3916
3938
3917 - last 10 commits on the current branch::
3939 - last 10 commits on the current branch::
3918
3940
3919 hg log -l 10 -b .
3941 hg log -l 10 -b .
3920
3942
3921 - changesets showing all modifications of a file, including removals::
3943 - changesets showing all modifications of a file, including removals::
3922
3944
3923 hg log --removed file.c
3945 hg log --removed file.c
3924
3946
3925 - all changesets that touch a directory, with diffs, excluding merges::
3947 - all changesets that touch a directory, with diffs, excluding merges::
3926
3948
3927 hg log -Mp lib/
3949 hg log -Mp lib/
3928
3950
3929 - all revision numbers that match a keyword::
3951 - all revision numbers that match a keyword::
3930
3952
3931 hg log -k bug --template "{rev}\\n"
3953 hg log -k bug --template "{rev}\\n"
3932
3954
3933 - check if a given changeset is included is a tagged release::
3955 - check if a given changeset is included is a tagged release::
3934
3956
3935 hg log -r "a21ccf and ancestor(1.9)"
3957 hg log -r "a21ccf and ancestor(1.9)"
3936
3958
3937 - find all changesets by some user in a date range::
3959 - find all changesets by some user in a date range::
3938
3960
3939 hg log -k alice -d "may 2008 to jul 2008"
3961 hg log -k alice -d "may 2008 to jul 2008"
3940
3962
3941 - summary of all changesets after the last tag::
3963 - summary of all changesets after the last tag::
3942
3964
3943 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3965 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3944
3966
3945 See :hg:`help dates` for a list of formats valid for -d/--date.
3967 See :hg:`help dates` for a list of formats valid for -d/--date.
3946
3968
3947 See :hg:`help revisions` and :hg:`help revsets` for more about
3969 See :hg:`help revisions` and :hg:`help revsets` for more about
3948 specifying revisions.
3970 specifying revisions.
3949
3971
3950 See :hg:`help templates` for more about pre-packaged styles and
3972 See :hg:`help templates` for more about pre-packaged styles and
3951 specifying custom templates.
3973 specifying custom templates.
3952
3974
3953 Returns 0 on success.
3975 Returns 0 on success.
3954 """
3976 """
3955
3977
3956 matchfn = scmutil.match(repo[None], pats, opts)
3978 matchfn = scmutil.match(repo[None], pats, opts)
3957 limit = cmdutil.loglimit(opts)
3979 limit = cmdutil.loglimit(opts)
3958 count = 0
3980 count = 0
3959
3981
3960 getrenamed, endrev = None, None
3982 getrenamed, endrev = None, None
3961 if opts.get('copies'):
3983 if opts.get('copies'):
3962 if opts.get('rev'):
3984 if opts.get('rev'):
3963 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3985 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3964 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3986 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3965
3987
3966 df = False
3988 df = False
3967 if opts["date"]:
3989 if opts["date"]:
3968 df = util.matchdate(opts["date"])
3990 df = util.matchdate(opts["date"])
3969
3991
3970 branches = opts.get('branch', []) + opts.get('only_branch', [])
3992 branches = opts.get('branch', []) + opts.get('only_branch', [])
3971 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3993 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3972
3994
3973 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3995 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3974 def prep(ctx, fns):
3996 def prep(ctx, fns):
3975 rev = ctx.rev()
3997 rev = ctx.rev()
3976 parents = [p for p in repo.changelog.parentrevs(rev)
3998 parents = [p for p in repo.changelog.parentrevs(rev)
3977 if p != nullrev]
3999 if p != nullrev]
3978 if opts.get('no_merges') and len(parents) == 2:
4000 if opts.get('no_merges') and len(parents) == 2:
3979 return
4001 return
3980 if opts.get('only_merges') and len(parents) != 2:
4002 if opts.get('only_merges') and len(parents) != 2:
3981 return
4003 return
3982 if opts.get('branch') and ctx.branch() not in opts['branch']:
4004 if opts.get('branch') and ctx.branch() not in opts['branch']:
3983 return
4005 return
3984 if not opts.get('hidden') and ctx.hidden():
4006 if not opts.get('hidden') and ctx.hidden():
3985 return
4007 return
3986 if df and not df(ctx.date()[0]):
4008 if df and not df(ctx.date()[0]):
3987 return
4009 return
3988
4010
3989 lower = encoding.lower
4011 lower = encoding.lower
3990 if opts.get('user'):
4012 if opts.get('user'):
3991 luser = lower(ctx.user())
4013 luser = lower(ctx.user())
3992 for k in [lower(x) for x in opts['user']]:
4014 for k in [lower(x) for x in opts['user']]:
3993 if (k in luser):
4015 if (k in luser):
3994 break
4016 break
3995 else:
4017 else:
3996 return
4018 return
3997 if opts.get('keyword'):
4019 if opts.get('keyword'):
3998 luser = lower(ctx.user())
4020 luser = lower(ctx.user())
3999 ldesc = lower(ctx.description())
4021 ldesc = lower(ctx.description())
4000 lfiles = lower(" ".join(ctx.files()))
4022 lfiles = lower(" ".join(ctx.files()))
4001 for k in [lower(x) for x in opts['keyword']]:
4023 for k in [lower(x) for x in opts['keyword']]:
4002 if (k in luser or k in ldesc or k in lfiles):
4024 if (k in luser or k in ldesc or k in lfiles):
4003 break
4025 break
4004 else:
4026 else:
4005 return
4027 return
4006
4028
4007 copies = None
4029 copies = None
4008 if getrenamed is not None and rev:
4030 if getrenamed is not None and rev:
4009 copies = []
4031 copies = []
4010 for fn in ctx.files():
4032 for fn in ctx.files():
4011 rename = getrenamed(fn, rev)
4033 rename = getrenamed(fn, rev)
4012 if rename:
4034 if rename:
4013 copies.append((fn, rename[0]))
4035 copies.append((fn, rename[0]))
4014
4036
4015 revmatchfn = None
4037 revmatchfn = None
4016 if opts.get('patch') or opts.get('stat'):
4038 if opts.get('patch') or opts.get('stat'):
4017 if opts.get('follow') or opts.get('follow_first'):
4039 if opts.get('follow') or opts.get('follow_first'):
4018 # note: this might be wrong when following through merges
4040 # note: this might be wrong when following through merges
4019 revmatchfn = scmutil.match(repo[None], fns, default='path')
4041 revmatchfn = scmutil.match(repo[None], fns, default='path')
4020 else:
4042 else:
4021 revmatchfn = matchfn
4043 revmatchfn = matchfn
4022
4044
4023 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4045 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4024
4046
4025 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4047 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4026 if count == limit:
4048 if count == limit:
4027 break
4049 break
4028 if displayer.flush(ctx.rev()):
4050 if displayer.flush(ctx.rev()):
4029 count += 1
4051 count += 1
4030 displayer.close()
4052 displayer.close()
4031
4053
4032 @command('manifest',
4054 @command('manifest',
4033 [('r', 'rev', '', _('revision to display'), _('REV')),
4055 [('r', 'rev', '', _('revision to display'), _('REV')),
4034 ('', 'all', False, _("list files from all revisions"))],
4056 ('', 'all', False, _("list files from all revisions"))],
4035 _('[-r REV]'))
4057 _('[-r REV]'))
4036 def manifest(ui, repo, node=None, rev=None, **opts):
4058 def manifest(ui, repo, node=None, rev=None, **opts):
4037 """output the current or given revision of the project manifest
4059 """output the current or given revision of the project manifest
4038
4060
4039 Print a list of version controlled files for the given revision.
4061 Print a list of version controlled files for the given revision.
4040 If no revision is given, the first parent of the working directory
4062 If no revision is given, the first parent of the working directory
4041 is used, or the null revision if no revision is checked out.
4063 is used, or the null revision if no revision is checked out.
4042
4064
4043 With -v, print file permissions, symlink and executable bits.
4065 With -v, print file permissions, symlink and executable bits.
4044 With --debug, print file revision hashes.
4066 With --debug, print file revision hashes.
4045
4067
4046 If option --all is specified, the list of all files from all revisions
4068 If option --all is specified, the list of all files from all revisions
4047 is printed. This includes deleted and renamed files.
4069 is printed. This includes deleted and renamed files.
4048
4070
4049 Returns 0 on success.
4071 Returns 0 on success.
4050 """
4072 """
4051 if opts.get('all'):
4073 if opts.get('all'):
4052 if rev or node:
4074 if rev or node:
4053 raise util.Abort(_("can't specify a revision with --all"))
4075 raise util.Abort(_("can't specify a revision with --all"))
4054
4076
4055 res = []
4077 res = []
4056 prefix = "data/"
4078 prefix = "data/"
4057 suffix = ".i"
4079 suffix = ".i"
4058 plen = len(prefix)
4080 plen = len(prefix)
4059 slen = len(suffix)
4081 slen = len(suffix)
4060 lock = repo.lock()
4082 lock = repo.lock()
4061 try:
4083 try:
4062 for fn, b, size in repo.store.datafiles():
4084 for fn, b, size in repo.store.datafiles():
4063 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4085 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4064 res.append(fn[plen:-slen])
4086 res.append(fn[plen:-slen])
4065 finally:
4087 finally:
4066 lock.release()
4088 lock.release()
4067 for f in sorted(res):
4089 for f in sorted(res):
4068 ui.write("%s\n" % f)
4090 ui.write("%s\n" % f)
4069 return
4091 return
4070
4092
4071 if rev and node:
4093 if rev and node:
4072 raise util.Abort(_("please specify just one revision"))
4094 raise util.Abort(_("please specify just one revision"))
4073
4095
4074 if not node:
4096 if not node:
4075 node = rev
4097 node = rev
4076
4098
4077 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4099 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4078 ctx = scmutil.revsingle(repo, node)
4100 ctx = scmutil.revsingle(repo, node)
4079 for f in ctx:
4101 for f in ctx:
4080 if ui.debugflag:
4102 if ui.debugflag:
4081 ui.write("%40s " % hex(ctx.manifest()[f]))
4103 ui.write("%40s " % hex(ctx.manifest()[f]))
4082 if ui.verbose:
4104 if ui.verbose:
4083 ui.write(decor[ctx.flags(f)])
4105 ui.write(decor[ctx.flags(f)])
4084 ui.write("%s\n" % f)
4106 ui.write("%s\n" % f)
4085
4107
4086 @command('^merge',
4108 @command('^merge',
4087 [('f', 'force', None, _('force a merge with outstanding changes')),
4109 [('f', 'force', None, _('force a merge with outstanding changes')),
4088 ('r', 'rev', '', _('revision to merge'), _('REV')),
4110 ('r', 'rev', '', _('revision to merge'), _('REV')),
4089 ('P', 'preview', None,
4111 ('P', 'preview', None,
4090 _('review revisions to merge (no merge is performed)'))
4112 _('review revisions to merge (no merge is performed)'))
4091 ] + mergetoolopts,
4113 ] + mergetoolopts,
4092 _('[-P] [-f] [[-r] REV]'))
4114 _('[-P] [-f] [[-r] REV]'))
4093 def merge(ui, repo, node=None, **opts):
4115 def merge(ui, repo, node=None, **opts):
4094 """merge working directory with another revision
4116 """merge working directory with another revision
4095
4117
4096 The current working directory is updated with all changes made in
4118 The current working directory is updated with all changes made in
4097 the requested revision since the last common predecessor revision.
4119 the requested revision since the last common predecessor revision.
4098
4120
4099 Files that changed between either parent are marked as changed for
4121 Files that changed between either parent are marked as changed for
4100 the next commit and a commit must be performed before any further
4122 the next commit and a commit must be performed before any further
4101 updates to the repository are allowed. The next commit will have
4123 updates to the repository are allowed. The next commit will have
4102 two parents.
4124 two parents.
4103
4125
4104 ``--tool`` can be used to specify the merge tool used for file
4126 ``--tool`` can be used to specify the merge tool used for file
4105 merges. It overrides the HGMERGE environment variable and your
4127 merges. It overrides the HGMERGE environment variable and your
4106 configuration files. See :hg:`help merge-tools` for options.
4128 configuration files. See :hg:`help merge-tools` for options.
4107
4129
4108 If no revision is specified, the working directory's parent is a
4130 If no revision is specified, the working directory's parent is a
4109 head revision, and the current branch contains exactly one other
4131 head revision, and the current branch contains exactly one other
4110 head, the other head is merged with by default. Otherwise, an
4132 head, the other head is merged with by default. Otherwise, an
4111 explicit revision with which to merge with must be provided.
4133 explicit revision with which to merge with must be provided.
4112
4134
4113 :hg:`resolve` must be used to resolve unresolved files.
4135 :hg:`resolve` must be used to resolve unresolved files.
4114
4136
4115 To undo an uncommitted merge, use :hg:`update --clean .` which
4137 To undo an uncommitted merge, use :hg:`update --clean .` which
4116 will check out a clean copy of the original merge parent, losing
4138 will check out a clean copy of the original merge parent, losing
4117 all changes.
4139 all changes.
4118
4140
4119 Returns 0 on success, 1 if there are unresolved files.
4141 Returns 0 on success, 1 if there are unresolved files.
4120 """
4142 """
4121
4143
4122 if opts.get('rev') and node:
4144 if opts.get('rev') and node:
4123 raise util.Abort(_("please specify just one revision"))
4145 raise util.Abort(_("please specify just one revision"))
4124 if not node:
4146 if not node:
4125 node = opts.get('rev')
4147 node = opts.get('rev')
4126
4148
4127 if not node:
4149 if not node:
4128 branch = repo[None].branch()
4150 branch = repo[None].branch()
4129 bheads = repo.branchheads(branch)
4151 bheads = repo.branchheads(branch)
4130 if len(bheads) > 2:
4152 if len(bheads) > 2:
4131 raise util.Abort(_("branch '%s' has %d heads - "
4153 raise util.Abort(_("branch '%s' has %d heads - "
4132 "please merge with an explicit rev")
4154 "please merge with an explicit rev")
4133 % (branch, len(bheads)),
4155 % (branch, len(bheads)),
4134 hint=_("run 'hg heads .' to see heads"))
4156 hint=_("run 'hg heads .' to see heads"))
4135
4157
4136 parent = repo.dirstate.p1()
4158 parent = repo.dirstate.p1()
4137 if len(bheads) == 1:
4159 if len(bheads) == 1:
4138 if len(repo.heads()) > 1:
4160 if len(repo.heads()) > 1:
4139 raise util.Abort(_("branch '%s' has one head - "
4161 raise util.Abort(_("branch '%s' has one head - "
4140 "please merge with an explicit rev")
4162 "please merge with an explicit rev")
4141 % branch,
4163 % branch,
4142 hint=_("run 'hg heads' to see all heads"))
4164 hint=_("run 'hg heads' to see all heads"))
4143 msg, hint = _('nothing to merge'), None
4165 msg, hint = _('nothing to merge'), None
4144 if parent != repo.lookup(branch):
4166 if parent != repo.lookup(branch):
4145 hint = _("use 'hg update' instead")
4167 hint = _("use 'hg update' instead")
4146 raise util.Abort(msg, hint=hint)
4168 raise util.Abort(msg, hint=hint)
4147
4169
4148 if parent not in bheads:
4170 if parent not in bheads:
4149 raise util.Abort(_('working directory not at a head revision'),
4171 raise util.Abort(_('working directory not at a head revision'),
4150 hint=_("use 'hg update' or merge with an "
4172 hint=_("use 'hg update' or merge with an "
4151 "explicit revision"))
4173 "explicit revision"))
4152 node = parent == bheads[0] and bheads[-1] or bheads[0]
4174 node = parent == bheads[0] and bheads[-1] or bheads[0]
4153 else:
4175 else:
4154 node = scmutil.revsingle(repo, node).node()
4176 node = scmutil.revsingle(repo, node).node()
4155
4177
4156 if opts.get('preview'):
4178 if opts.get('preview'):
4157 # find nodes that are ancestors of p2 but not of p1
4179 # find nodes that are ancestors of p2 but not of p1
4158 p1 = repo.lookup('.')
4180 p1 = repo.lookup('.')
4159 p2 = repo.lookup(node)
4181 p2 = repo.lookup(node)
4160 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4182 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4161
4183
4162 displayer = cmdutil.show_changeset(ui, repo, opts)
4184 displayer = cmdutil.show_changeset(ui, repo, opts)
4163 for node in nodes:
4185 for node in nodes:
4164 displayer.show(repo[node])
4186 displayer.show(repo[node])
4165 displayer.close()
4187 displayer.close()
4166 return 0
4188 return 0
4167
4189
4168 try:
4190 try:
4169 # ui.forcemerge is an internal variable, do not document
4191 # ui.forcemerge is an internal variable, do not document
4170 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4192 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4171 return hg.merge(repo, node, force=opts.get('force'))
4193 return hg.merge(repo, node, force=opts.get('force'))
4172 finally:
4194 finally:
4173 ui.setconfig('ui', 'forcemerge', '')
4195 ui.setconfig('ui', 'forcemerge', '')
4174
4196
4175 @command('outgoing|out',
4197 @command('outgoing|out',
4176 [('f', 'force', None, _('run even when the destination is unrelated')),
4198 [('f', 'force', None, _('run even when the destination is unrelated')),
4177 ('r', 'rev', [],
4199 ('r', 'rev', [],
4178 _('a changeset intended to be included in the destination'), _('REV')),
4200 _('a changeset intended to be included in the destination'), _('REV')),
4179 ('n', 'newest-first', None, _('show newest record first')),
4201 ('n', 'newest-first', None, _('show newest record first')),
4180 ('B', 'bookmarks', False, _('compare bookmarks')),
4202 ('B', 'bookmarks', False, _('compare bookmarks')),
4181 ('b', 'branch', [], _('a specific branch you would like to push'),
4203 ('b', 'branch', [], _('a specific branch you would like to push'),
4182 _('BRANCH')),
4204 _('BRANCH')),
4183 ] + logopts + remoteopts + subrepoopts,
4205 ] + logopts + remoteopts + subrepoopts,
4184 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4206 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4185 def outgoing(ui, repo, dest=None, **opts):
4207 def outgoing(ui, repo, dest=None, **opts):
4186 """show changesets not found in the destination
4208 """show changesets not found in the destination
4187
4209
4188 Show changesets not found in the specified destination repository
4210 Show changesets not found in the specified destination repository
4189 or the default push location. These are the changesets that would
4211 or the default push location. These are the changesets that would
4190 be pushed if a push was requested.
4212 be pushed if a push was requested.
4191
4213
4192 See pull for details of valid destination formats.
4214 See pull for details of valid destination formats.
4193
4215
4194 Returns 0 if there are outgoing changes, 1 otherwise.
4216 Returns 0 if there are outgoing changes, 1 otherwise.
4195 """
4217 """
4196
4218
4197 if opts.get('bookmarks'):
4219 if opts.get('bookmarks'):
4198 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4220 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4199 dest, branches = hg.parseurl(dest, opts.get('branch'))
4221 dest, branches = hg.parseurl(dest, opts.get('branch'))
4200 other = hg.peer(repo, opts, dest)
4222 other = hg.peer(repo, opts, dest)
4201 if 'bookmarks' not in other.listkeys('namespaces'):
4223 if 'bookmarks' not in other.listkeys('namespaces'):
4202 ui.warn(_("remote doesn't support bookmarks\n"))
4224 ui.warn(_("remote doesn't support bookmarks\n"))
4203 return 0
4225 return 0
4204 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4226 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4205 return bookmarks.diff(ui, other, repo)
4227 return bookmarks.diff(ui, other, repo)
4206
4228
4207 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4229 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4208 try:
4230 try:
4209 return hg.outgoing(ui, repo, dest, opts)
4231 return hg.outgoing(ui, repo, dest, opts)
4210 finally:
4232 finally:
4211 del repo._subtoppath
4233 del repo._subtoppath
4212
4234
4213 @command('parents',
4235 @command('parents',
4214 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4236 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4215 ] + templateopts,
4237 ] + templateopts,
4216 _('[-r REV] [FILE]'))
4238 _('[-r REV] [FILE]'))
4217 def parents(ui, repo, file_=None, **opts):
4239 def parents(ui, repo, file_=None, **opts):
4218 """show the parents of the working directory or revision
4240 """show the parents of the working directory or revision
4219
4241
4220 Print the working directory's parent revisions. If a revision is
4242 Print the working directory's parent revisions. If a revision is
4221 given via -r/--rev, the parent of that revision will be printed.
4243 given via -r/--rev, the parent of that revision will be printed.
4222 If a file argument is given, the revision in which the file was
4244 If a file argument is given, the revision in which the file was
4223 last changed (before the working directory revision or the
4245 last changed (before the working directory revision or the
4224 argument to --rev if given) is printed.
4246 argument to --rev if given) is printed.
4225
4247
4226 Returns 0 on success.
4248 Returns 0 on success.
4227 """
4249 """
4228
4250
4229 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4251 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4230
4252
4231 if file_:
4253 if file_:
4232 m = scmutil.match(ctx, (file_,), opts)
4254 m = scmutil.match(ctx, (file_,), opts)
4233 if m.anypats() or len(m.files()) != 1:
4255 if m.anypats() or len(m.files()) != 1:
4234 raise util.Abort(_('can only specify an explicit filename'))
4256 raise util.Abort(_('can only specify an explicit filename'))
4235 file_ = m.files()[0]
4257 file_ = m.files()[0]
4236 filenodes = []
4258 filenodes = []
4237 for cp in ctx.parents():
4259 for cp in ctx.parents():
4238 if not cp:
4260 if not cp:
4239 continue
4261 continue
4240 try:
4262 try:
4241 filenodes.append(cp.filenode(file_))
4263 filenodes.append(cp.filenode(file_))
4242 except error.LookupError:
4264 except error.LookupError:
4243 pass
4265 pass
4244 if not filenodes:
4266 if not filenodes:
4245 raise util.Abort(_("'%s' not found in manifest!") % file_)
4267 raise util.Abort(_("'%s' not found in manifest!") % file_)
4246 fl = repo.file(file_)
4268 fl = repo.file(file_)
4247 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4269 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4248 else:
4270 else:
4249 p = [cp.node() for cp in ctx.parents()]
4271 p = [cp.node() for cp in ctx.parents()]
4250
4272
4251 displayer = cmdutil.show_changeset(ui, repo, opts)
4273 displayer = cmdutil.show_changeset(ui, repo, opts)
4252 for n in p:
4274 for n in p:
4253 if n != nullid:
4275 if n != nullid:
4254 displayer.show(repo[n])
4276 displayer.show(repo[n])
4255 displayer.close()
4277 displayer.close()
4256
4278
4257 @command('paths', [], _('[NAME]'))
4279 @command('paths', [], _('[NAME]'))
4258 def paths(ui, repo, search=None):
4280 def paths(ui, repo, search=None):
4259 """show aliases for remote repositories
4281 """show aliases for remote repositories
4260
4282
4261 Show definition of symbolic path name NAME. If no name is given,
4283 Show definition of symbolic path name NAME. If no name is given,
4262 show definition of all available names.
4284 show definition of all available names.
4263
4285
4264 Option -q/--quiet suppresses all output when searching for NAME
4286 Option -q/--quiet suppresses all output when searching for NAME
4265 and shows only the path names when listing all definitions.
4287 and shows only the path names when listing all definitions.
4266
4288
4267 Path names are defined in the [paths] section of your
4289 Path names are defined in the [paths] section of your
4268 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4290 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4269 repository, ``.hg/hgrc`` is used, too.
4291 repository, ``.hg/hgrc`` is used, too.
4270
4292
4271 The path names ``default`` and ``default-push`` have a special
4293 The path names ``default`` and ``default-push`` have a special
4272 meaning. When performing a push or pull operation, they are used
4294 meaning. When performing a push or pull operation, they are used
4273 as fallbacks if no location is specified on the command-line.
4295 as fallbacks if no location is specified on the command-line.
4274 When ``default-push`` is set, it will be used for push and
4296 When ``default-push`` is set, it will be used for push and
4275 ``default`` will be used for pull; otherwise ``default`` is used
4297 ``default`` will be used for pull; otherwise ``default`` is used
4276 as the fallback for both. When cloning a repository, the clone
4298 as the fallback for both. When cloning a repository, the clone
4277 source is written as ``default`` in ``.hg/hgrc``. Note that
4299 source is written as ``default`` in ``.hg/hgrc``. Note that
4278 ``default`` and ``default-push`` apply to all inbound (e.g.
4300 ``default`` and ``default-push`` apply to all inbound (e.g.
4279 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4301 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4280 :hg:`bundle`) operations.
4302 :hg:`bundle`) operations.
4281
4303
4282 See :hg:`help urls` for more information.
4304 See :hg:`help urls` for more information.
4283
4305
4284 Returns 0 on success.
4306 Returns 0 on success.
4285 """
4307 """
4286 if search:
4308 if search:
4287 for name, path in ui.configitems("paths"):
4309 for name, path in ui.configitems("paths"):
4288 if name == search:
4310 if name == search:
4289 ui.status("%s\n" % util.hidepassword(path))
4311 ui.status("%s\n" % util.hidepassword(path))
4290 return
4312 return
4291 if not ui.quiet:
4313 if not ui.quiet:
4292 ui.warn(_("not found!\n"))
4314 ui.warn(_("not found!\n"))
4293 return 1
4315 return 1
4294 else:
4316 else:
4295 for name, path in ui.configitems("paths"):
4317 for name, path in ui.configitems("paths"):
4296 if ui.quiet:
4318 if ui.quiet:
4297 ui.write("%s\n" % name)
4319 ui.write("%s\n" % name)
4298 else:
4320 else:
4299 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4321 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4300
4322
4301 @command('^phase',
4323 @command('^phase',
4302 [('p', 'public', False, _('set changeset phase to public')),
4324 [('p', 'public', False, _('set changeset phase to public')),
4303 ('d', 'draft', False, _('set changeset phase to draft')),
4325 ('d', 'draft', False, _('set changeset phase to draft')),
4304 ('s', 'secret', False, _('set changeset phase to secret')),
4326 ('s', 'secret', False, _('set changeset phase to secret')),
4305 ('f', 'force', False, _('allow to move boundary backward')),
4327 ('f', 'force', False, _('allow to move boundary backward')),
4306 ('r', 'rev', [], _('target revision'), _('REV')),
4328 ('r', 'rev', [], _('target revision'), _('REV')),
4307 ],
4329 ],
4308 _('[-p|-d|-s] [-f] [-r] REV...'))
4330 _('[-p|-d|-s] [-f] [-r] REV...'))
4309 def phase(ui, repo, *revs, **opts):
4331 def phase(ui, repo, *revs, **opts):
4310 """set or show the current phase name
4332 """set or show the current phase name
4311
4333
4312 With no argument, show the phase name of specified revisions.
4334 With no argument, show the phase name of specified revisions.
4313
4335
4314 With one of -p/--public, -d/--draft or -s/--secret, change the
4336 With one of -p/--public, -d/--draft or -s/--secret, change the
4315 phase value of the specified revisions.
4337 phase value of the specified revisions.
4316
4338
4317 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4339 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4318 lower phase to an higher phase. Phases are ordered as follows::
4340 lower phase to an higher phase. Phases are ordered as follows::
4319
4341
4320 public < draft < secret
4342 public < draft < secret
4321
4343
4322 Return 0 on success, 1 if no phases were changed or some could not
4344 Return 0 on success, 1 if no phases were changed or some could not
4323 be changed.
4345 be changed.
4324 """
4346 """
4325 # search for a unique phase argument
4347 # search for a unique phase argument
4326 targetphase = None
4348 targetphase = None
4327 for idx, name in enumerate(phases.phasenames):
4349 for idx, name in enumerate(phases.phasenames):
4328 if opts[name]:
4350 if opts[name]:
4329 if targetphase is not None:
4351 if targetphase is not None:
4330 raise util.Abort(_('only one phase can be specified'))
4352 raise util.Abort(_('only one phase can be specified'))
4331 targetphase = idx
4353 targetphase = idx
4332
4354
4333 # look for specified revision
4355 # look for specified revision
4334 revs = list(revs)
4356 revs = list(revs)
4335 revs.extend(opts['rev'])
4357 revs.extend(opts['rev'])
4336 if not revs:
4358 if not revs:
4337 raise util.Abort(_('no revisions specified'))
4359 raise util.Abort(_('no revisions specified'))
4338
4360
4339 revs = scmutil.revrange(repo, revs)
4361 revs = scmutil.revrange(repo, revs)
4340
4362
4341 lock = None
4363 lock = None
4342 ret = 0
4364 ret = 0
4343 if targetphase is None:
4365 if targetphase is None:
4344 # display
4366 # display
4345 for r in revs:
4367 for r in revs:
4346 ctx = repo[r]
4368 ctx = repo[r]
4347 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4369 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4348 else:
4370 else:
4349 lock = repo.lock()
4371 lock = repo.lock()
4350 try:
4372 try:
4351 # set phase
4373 # set phase
4352 nodes = [ctx.node() for ctx in repo.set('%ld', revs)]
4374 nodes = [ctx.node() for ctx in repo.set('%ld', revs)]
4353 if not nodes:
4375 if not nodes:
4354 raise util.Abort(_('empty revision set'))
4376 raise util.Abort(_('empty revision set'))
4355 olddata = repo._phaserev[:]
4377 olddata = repo._phaserev[:]
4356 phases.advanceboundary(repo, targetphase, nodes)
4378 phases.advanceboundary(repo, targetphase, nodes)
4357 if opts['force']:
4379 if opts['force']:
4358 phases.retractboundary(repo, targetphase, nodes)
4380 phases.retractboundary(repo, targetphase, nodes)
4359 finally:
4381 finally:
4360 lock.release()
4382 lock.release()
4361 if olddata is not None:
4383 if olddata is not None:
4362 changes = 0
4384 changes = 0
4363 newdata = repo._phaserev
4385 newdata = repo._phaserev
4364 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4386 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4365 rejected = [n for n in nodes
4387 rejected = [n for n in nodes
4366 if newdata[repo[n].rev()] < targetphase]
4388 if newdata[repo[n].rev()] < targetphase]
4367 if rejected:
4389 if rejected:
4368 ui.warn(_('cannot move %i changesets to a more permissive '
4390 ui.warn(_('cannot move %i changesets to a more permissive '
4369 'phase, use --force\n') % len(rejected))
4391 'phase, use --force\n') % len(rejected))
4370 ret = 1
4392 ret = 1
4371 if changes:
4393 if changes:
4372 msg = _('phase changed for %i changesets\n') % changes
4394 msg = _('phase changed for %i changesets\n') % changes
4373 if ret:
4395 if ret:
4374 ui.status(msg)
4396 ui.status(msg)
4375 else:
4397 else:
4376 ui.note(msg)
4398 ui.note(msg)
4377 else:
4399 else:
4378 ui.warn(_('no phases changed\n'))
4400 ui.warn(_('no phases changed\n'))
4379 ret = 1
4401 ret = 1
4380 return ret
4402 return ret
4381
4403
4382 def postincoming(ui, repo, modheads, optupdate, checkout):
4404 def postincoming(ui, repo, modheads, optupdate, checkout):
4383 if modheads == 0:
4405 if modheads == 0:
4384 return
4406 return
4385 if optupdate:
4407 if optupdate:
4386 movemarkfrom = repo['.'].node()
4408 movemarkfrom = repo['.'].node()
4387 try:
4409 try:
4388 ret = hg.update(repo, checkout)
4410 ret = hg.update(repo, checkout)
4389 except util.Abort, inst:
4411 except util.Abort, inst:
4390 ui.warn(_("not updating: %s\n") % str(inst))
4412 ui.warn(_("not updating: %s\n") % str(inst))
4391 return 0
4413 return 0
4392 if not ret and not checkout:
4414 if not ret and not checkout:
4393 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4415 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4394 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4416 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4395 return ret
4417 return ret
4396 if modheads > 1:
4418 if modheads > 1:
4397 currentbranchheads = len(repo.branchheads())
4419 currentbranchheads = len(repo.branchheads())
4398 if currentbranchheads == modheads:
4420 if currentbranchheads == modheads:
4399 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4421 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4400 elif currentbranchheads > 1:
4422 elif currentbranchheads > 1:
4401 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4423 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4402 else:
4424 else:
4403 ui.status(_("(run 'hg heads' to see heads)\n"))
4425 ui.status(_("(run 'hg heads' to see heads)\n"))
4404 else:
4426 else:
4405 ui.status(_("(run 'hg update' to get a working copy)\n"))
4427 ui.status(_("(run 'hg update' to get a working copy)\n"))
4406
4428
4407 @command('^pull',
4429 @command('^pull',
4408 [('u', 'update', None,
4430 [('u', 'update', None,
4409 _('update to new branch head if changesets were pulled')),
4431 _('update to new branch head if changesets were pulled')),
4410 ('f', 'force', None, _('run even when remote repository is unrelated')),
4432 ('f', 'force', None, _('run even when remote repository is unrelated')),
4411 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4433 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4412 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4434 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4413 ('b', 'branch', [], _('a specific branch you would like to pull'),
4435 ('b', 'branch', [], _('a specific branch you would like to pull'),
4414 _('BRANCH')),
4436 _('BRANCH')),
4415 ] + remoteopts,
4437 ] + remoteopts,
4416 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4438 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4417 def pull(ui, repo, source="default", **opts):
4439 def pull(ui, repo, source="default", **opts):
4418 """pull changes from the specified source
4440 """pull changes from the specified source
4419
4441
4420 Pull changes from a remote repository to a local one.
4442 Pull changes from a remote repository to a local one.
4421
4443
4422 This finds all changes from the repository at the specified path
4444 This finds all changes from the repository at the specified path
4423 or URL and adds them to a local repository (the current one unless
4445 or URL and adds them to a local repository (the current one unless
4424 -R is specified). By default, this does not update the copy of the
4446 -R is specified). By default, this does not update the copy of the
4425 project in the working directory.
4447 project in the working directory.
4426
4448
4427 Use :hg:`incoming` if you want to see what would have been added
4449 Use :hg:`incoming` if you want to see what would have been added
4428 by a pull at the time you issued this command. If you then decide
4450 by a pull at the time you issued this command. If you then decide
4429 to add those changes to the repository, you should use :hg:`pull
4451 to add those changes to the repository, you should use :hg:`pull
4430 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4452 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4431
4453
4432 If SOURCE is omitted, the 'default' path will be used.
4454 If SOURCE is omitted, the 'default' path will be used.
4433 See :hg:`help urls` for more information.
4455 See :hg:`help urls` for more information.
4434
4456
4435 Returns 0 on success, 1 if an update had unresolved files.
4457 Returns 0 on success, 1 if an update had unresolved files.
4436 """
4458 """
4437 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4459 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4438 other = hg.peer(repo, opts, source)
4460 other = hg.peer(repo, opts, source)
4439 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4461 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4440 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4462 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4441
4463
4442 if opts.get('bookmark'):
4464 if opts.get('bookmark'):
4443 if not revs:
4465 if not revs:
4444 revs = []
4466 revs = []
4445 rb = other.listkeys('bookmarks')
4467 rb = other.listkeys('bookmarks')
4446 for b in opts['bookmark']:
4468 for b in opts['bookmark']:
4447 if b not in rb:
4469 if b not in rb:
4448 raise util.Abort(_('remote bookmark %s not found!') % b)
4470 raise util.Abort(_('remote bookmark %s not found!') % b)
4449 revs.append(rb[b])
4471 revs.append(rb[b])
4450
4472
4451 if revs:
4473 if revs:
4452 try:
4474 try:
4453 revs = [other.lookup(rev) for rev in revs]
4475 revs = [other.lookup(rev) for rev in revs]
4454 except error.CapabilityError:
4476 except error.CapabilityError:
4455 err = _("other repository doesn't support revision lookup, "
4477 err = _("other repository doesn't support revision lookup, "
4456 "so a rev cannot be specified.")
4478 "so a rev cannot be specified.")
4457 raise util.Abort(err)
4479 raise util.Abort(err)
4458
4480
4459 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4481 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4460 bookmarks.updatefromremote(ui, repo, other, source)
4482 bookmarks.updatefromremote(ui, repo, other, source)
4461 if checkout:
4483 if checkout:
4462 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4484 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4463 repo._subtoppath = source
4485 repo._subtoppath = source
4464 try:
4486 try:
4465 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4487 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4466
4488
4467 finally:
4489 finally:
4468 del repo._subtoppath
4490 del repo._subtoppath
4469
4491
4470 # update specified bookmarks
4492 # update specified bookmarks
4471 if opts.get('bookmark'):
4493 if opts.get('bookmark'):
4472 for b in opts['bookmark']:
4494 for b in opts['bookmark']:
4473 # explicit pull overrides local bookmark if any
4495 # explicit pull overrides local bookmark if any
4474 ui.status(_("importing bookmark %s\n") % b)
4496 ui.status(_("importing bookmark %s\n") % b)
4475 repo._bookmarks[b] = repo[rb[b]].node()
4497 repo._bookmarks[b] = repo[rb[b]].node()
4476 bookmarks.write(repo)
4498 bookmarks.write(repo)
4477
4499
4478 return ret
4500 return ret
4479
4501
4480 @command('^push',
4502 @command('^push',
4481 [('f', 'force', None, _('force push')),
4503 [('f', 'force', None, _('force push')),
4482 ('r', 'rev', [],
4504 ('r', 'rev', [],
4483 _('a changeset intended to be included in the destination'),
4505 _('a changeset intended to be included in the destination'),
4484 _('REV')),
4506 _('REV')),
4485 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4507 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4486 ('b', 'branch', [],
4508 ('b', 'branch', [],
4487 _('a specific branch you would like to push'), _('BRANCH')),
4509 _('a specific branch you would like to push'), _('BRANCH')),
4488 ('', 'new-branch', False, _('allow pushing a new branch')),
4510 ('', 'new-branch', False, _('allow pushing a new branch')),
4489 ] + remoteopts,
4511 ] + remoteopts,
4490 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4512 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4491 def push(ui, repo, dest=None, **opts):
4513 def push(ui, repo, dest=None, **opts):
4492 """push changes to the specified destination
4514 """push changes to the specified destination
4493
4515
4494 Push changesets from the local repository to the specified
4516 Push changesets from the local repository to the specified
4495 destination.
4517 destination.
4496
4518
4497 This operation is symmetrical to pull: it is identical to a pull
4519 This operation is symmetrical to pull: it is identical to a pull
4498 in the destination repository from the current one.
4520 in the destination repository from the current one.
4499
4521
4500 By default, push will not allow creation of new heads at the
4522 By default, push will not allow creation of new heads at the
4501 destination, since multiple heads would make it unclear which head
4523 destination, since multiple heads would make it unclear which head
4502 to use. In this situation, it is recommended to pull and merge
4524 to use. In this situation, it is recommended to pull and merge
4503 before pushing.
4525 before pushing.
4504
4526
4505 Use --new-branch if you want to allow push to create a new named
4527 Use --new-branch if you want to allow push to create a new named
4506 branch that is not present at the destination. This allows you to
4528 branch that is not present at the destination. This allows you to
4507 only create a new branch without forcing other changes.
4529 only create a new branch without forcing other changes.
4508
4530
4509 Use -f/--force to override the default behavior and push all
4531 Use -f/--force to override the default behavior and push all
4510 changesets on all branches.
4532 changesets on all branches.
4511
4533
4512 If -r/--rev is used, the specified revision and all its ancestors
4534 If -r/--rev is used, the specified revision and all its ancestors
4513 will be pushed to the remote repository.
4535 will be pushed to the remote repository.
4514
4536
4515 Please see :hg:`help urls` for important details about ``ssh://``
4537 Please see :hg:`help urls` for important details about ``ssh://``
4516 URLs. If DESTINATION is omitted, a default path will be used.
4538 URLs. If DESTINATION is omitted, a default path will be used.
4517
4539
4518 Returns 0 if push was successful, 1 if nothing to push.
4540 Returns 0 if push was successful, 1 if nothing to push.
4519 """
4541 """
4520
4542
4521 if opts.get('bookmark'):
4543 if opts.get('bookmark'):
4522 for b in opts['bookmark']:
4544 for b in opts['bookmark']:
4523 # translate -B options to -r so changesets get pushed
4545 # translate -B options to -r so changesets get pushed
4524 if b in repo._bookmarks:
4546 if b in repo._bookmarks:
4525 opts.setdefault('rev', []).append(b)
4547 opts.setdefault('rev', []).append(b)
4526 else:
4548 else:
4527 # if we try to push a deleted bookmark, translate it to null
4549 # if we try to push a deleted bookmark, translate it to null
4528 # this lets simultaneous -r, -b options continue working
4550 # this lets simultaneous -r, -b options continue working
4529 opts.setdefault('rev', []).append("null")
4551 opts.setdefault('rev', []).append("null")
4530
4552
4531 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4553 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4532 dest, branches = hg.parseurl(dest, opts.get('branch'))
4554 dest, branches = hg.parseurl(dest, opts.get('branch'))
4533 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4555 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4534 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4556 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4535 other = hg.peer(repo, opts, dest)
4557 other = hg.peer(repo, opts, dest)
4536 if revs:
4558 if revs:
4537 revs = [repo.lookup(rev) for rev in revs]
4559 revs = [repo.lookup(rev) for rev in revs]
4538
4560
4539 repo._subtoppath = dest
4561 repo._subtoppath = dest
4540 try:
4562 try:
4541 # push subrepos depth-first for coherent ordering
4563 # push subrepos depth-first for coherent ordering
4542 c = repo['']
4564 c = repo['']
4543 subs = c.substate # only repos that are committed
4565 subs = c.substate # only repos that are committed
4544 for s in sorted(subs):
4566 for s in sorted(subs):
4545 if c.sub(s).push(opts) == 0:
4567 if c.sub(s).push(opts) == 0:
4546 return False
4568 return False
4547 finally:
4569 finally:
4548 del repo._subtoppath
4570 del repo._subtoppath
4549 result = repo.push(other, opts.get('force'), revs=revs,
4571 result = repo.push(other, opts.get('force'), revs=revs,
4550 newbranch=opts.get('new_branch'))
4572 newbranch=opts.get('new_branch'))
4551
4573
4552 result = not result
4574 result = not result
4553
4575
4554 if opts.get('bookmark'):
4576 if opts.get('bookmark'):
4555 rb = other.listkeys('bookmarks')
4577 rb = other.listkeys('bookmarks')
4556 for b in opts['bookmark']:
4578 for b in opts['bookmark']:
4557 # explicit push overrides remote bookmark if any
4579 # explicit push overrides remote bookmark if any
4558 if b in repo._bookmarks:
4580 if b in repo._bookmarks:
4559 ui.status(_("exporting bookmark %s\n") % b)
4581 ui.status(_("exporting bookmark %s\n") % b)
4560 new = repo[b].hex()
4582 new = repo[b].hex()
4561 elif b in rb:
4583 elif b in rb:
4562 ui.status(_("deleting remote bookmark %s\n") % b)
4584 ui.status(_("deleting remote bookmark %s\n") % b)
4563 new = '' # delete
4585 new = '' # delete
4564 else:
4586 else:
4565 ui.warn(_('bookmark %s does not exist on the local '
4587 ui.warn(_('bookmark %s does not exist on the local '
4566 'or remote repository!\n') % b)
4588 'or remote repository!\n') % b)
4567 return 2
4589 return 2
4568 old = rb.get(b, '')
4590 old = rb.get(b, '')
4569 r = other.pushkey('bookmarks', b, old, new)
4591 r = other.pushkey('bookmarks', b, old, new)
4570 if not r:
4592 if not r:
4571 ui.warn(_('updating bookmark %s failed!\n') % b)
4593 ui.warn(_('updating bookmark %s failed!\n') % b)
4572 if not result:
4594 if not result:
4573 result = 2
4595 result = 2
4574
4596
4575 return result
4597 return result
4576
4598
4577 @command('recover', [])
4599 @command('recover', [])
4578 def recover(ui, repo):
4600 def recover(ui, repo):
4579 """roll back an interrupted transaction
4601 """roll back an interrupted transaction
4580
4602
4581 Recover from an interrupted commit or pull.
4603 Recover from an interrupted commit or pull.
4582
4604
4583 This command tries to fix the repository status after an
4605 This command tries to fix the repository status after an
4584 interrupted operation. It should only be necessary when Mercurial
4606 interrupted operation. It should only be necessary when Mercurial
4585 suggests it.
4607 suggests it.
4586
4608
4587 Returns 0 if successful, 1 if nothing to recover or verify fails.
4609 Returns 0 if successful, 1 if nothing to recover or verify fails.
4588 """
4610 """
4589 if repo.recover():
4611 if repo.recover():
4590 return hg.verify(repo)
4612 return hg.verify(repo)
4591 return 1
4613 return 1
4592
4614
4593 @command('^remove|rm',
4615 @command('^remove|rm',
4594 [('A', 'after', None, _('record delete for missing files')),
4616 [('A', 'after', None, _('record delete for missing files')),
4595 ('f', 'force', None,
4617 ('f', 'force', None,
4596 _('remove (and delete) file even if added or modified')),
4618 _('remove (and delete) file even if added or modified')),
4597 ] + walkopts,
4619 ] + walkopts,
4598 _('[OPTION]... FILE...'))
4620 _('[OPTION]... FILE...'))
4599 def remove(ui, repo, *pats, **opts):
4621 def remove(ui, repo, *pats, **opts):
4600 """remove the specified files on the next commit
4622 """remove the specified files on the next commit
4601
4623
4602 Schedule the indicated files for removal from the current branch.
4624 Schedule the indicated files for removal from the current branch.
4603
4625
4604 This command schedules the files to be removed at the next commit.
4626 This command schedules the files to be removed at the next commit.
4605 To undo a remove before that, see :hg:`revert`. To undo added
4627 To undo a remove before that, see :hg:`revert`. To undo added
4606 files, see :hg:`forget`.
4628 files, see :hg:`forget`.
4607
4629
4608 .. container:: verbose
4630 .. container:: verbose
4609
4631
4610 -A/--after can be used to remove only files that have already
4632 -A/--after can be used to remove only files that have already
4611 been deleted, -f/--force can be used to force deletion, and -Af
4633 been deleted, -f/--force can be used to force deletion, and -Af
4612 can be used to remove files from the next revision without
4634 can be used to remove files from the next revision without
4613 deleting them from the working directory.
4635 deleting them from the working directory.
4614
4636
4615 The following table details the behavior of remove for different
4637 The following table details the behavior of remove for different
4616 file states (columns) and option combinations (rows). The file
4638 file states (columns) and option combinations (rows). The file
4617 states are Added [A], Clean [C], Modified [M] and Missing [!]
4639 states are Added [A], Clean [C], Modified [M] and Missing [!]
4618 (as reported by :hg:`status`). The actions are Warn, Remove
4640 (as reported by :hg:`status`). The actions are Warn, Remove
4619 (from branch) and Delete (from disk):
4641 (from branch) and Delete (from disk):
4620
4642
4621 ======= == == == ==
4643 ======= == == == ==
4622 A C M !
4644 A C M !
4623 ======= == == == ==
4645 ======= == == == ==
4624 none W RD W R
4646 none W RD W R
4625 -f R RD RD R
4647 -f R RD RD R
4626 -A W W W R
4648 -A W W W R
4627 -Af R R R R
4649 -Af R R R R
4628 ======= == == == ==
4650 ======= == == == ==
4629
4651
4630 Note that remove never deletes files in Added [A] state from the
4652 Note that remove never deletes files in Added [A] state from the
4631 working directory, not even if option --force is specified.
4653 working directory, not even if option --force is specified.
4632
4654
4633 Returns 0 on success, 1 if any warnings encountered.
4655 Returns 0 on success, 1 if any warnings encountered.
4634 """
4656 """
4635
4657
4636 ret = 0
4658 ret = 0
4637 after, force = opts.get('after'), opts.get('force')
4659 after, force = opts.get('after'), opts.get('force')
4638 if not pats and not after:
4660 if not pats and not after:
4639 raise util.Abort(_('no files specified'))
4661 raise util.Abort(_('no files specified'))
4640
4662
4641 m = scmutil.match(repo[None], pats, opts)
4663 m = scmutil.match(repo[None], pats, opts)
4642 s = repo.status(match=m, clean=True)
4664 s = repo.status(match=m, clean=True)
4643 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4665 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4644
4666
4645 for f in m.files():
4667 for f in m.files():
4646 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4668 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4647 if os.path.exists(m.rel(f)):
4669 if os.path.exists(m.rel(f)):
4648 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4670 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4649 ret = 1
4671 ret = 1
4650
4672
4651 if force:
4673 if force:
4652 list = modified + deleted + clean + added
4674 list = modified + deleted + clean + added
4653 elif after:
4675 elif after:
4654 list = deleted
4676 list = deleted
4655 for f in modified + added + clean:
4677 for f in modified + added + clean:
4656 ui.warn(_('not removing %s: file still exists (use -f'
4678 ui.warn(_('not removing %s: file still exists (use -f'
4657 ' to force removal)\n') % m.rel(f))
4679 ' to force removal)\n') % m.rel(f))
4658 ret = 1
4680 ret = 1
4659 else:
4681 else:
4660 list = deleted + clean
4682 list = deleted + clean
4661 for f in modified:
4683 for f in modified:
4662 ui.warn(_('not removing %s: file is modified (use -f'
4684 ui.warn(_('not removing %s: file is modified (use -f'
4663 ' to force removal)\n') % m.rel(f))
4685 ' to force removal)\n') % m.rel(f))
4664 ret = 1
4686 ret = 1
4665 for f in added:
4687 for f in added:
4666 ui.warn(_('not removing %s: file has been marked for add'
4688 ui.warn(_('not removing %s: file has been marked for add'
4667 ' (use forget to undo)\n') % m.rel(f))
4689 ' (use forget to undo)\n') % m.rel(f))
4668 ret = 1
4690 ret = 1
4669
4691
4670 for f in sorted(list):
4692 for f in sorted(list):
4671 if ui.verbose or not m.exact(f):
4693 if ui.verbose or not m.exact(f):
4672 ui.status(_('removing %s\n') % m.rel(f))
4694 ui.status(_('removing %s\n') % m.rel(f))
4673
4695
4674 wlock = repo.wlock()
4696 wlock = repo.wlock()
4675 try:
4697 try:
4676 if not after:
4698 if not after:
4677 for f in list:
4699 for f in list:
4678 if f in added:
4700 if f in added:
4679 continue # we never unlink added files on remove
4701 continue # we never unlink added files on remove
4680 try:
4702 try:
4681 util.unlinkpath(repo.wjoin(f))
4703 util.unlinkpath(repo.wjoin(f))
4682 except OSError, inst:
4704 except OSError, inst:
4683 if inst.errno != errno.ENOENT:
4705 if inst.errno != errno.ENOENT:
4684 raise
4706 raise
4685 repo[None].forget(list)
4707 repo[None].forget(list)
4686 finally:
4708 finally:
4687 wlock.release()
4709 wlock.release()
4688
4710
4689 return ret
4711 return ret
4690
4712
4691 @command('rename|move|mv',
4713 @command('rename|move|mv',
4692 [('A', 'after', None, _('record a rename that has already occurred')),
4714 [('A', 'after', None, _('record a rename that has already occurred')),
4693 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4715 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4694 ] + walkopts + dryrunopts,
4716 ] + walkopts + dryrunopts,
4695 _('[OPTION]... SOURCE... DEST'))
4717 _('[OPTION]... SOURCE... DEST'))
4696 def rename(ui, repo, *pats, **opts):
4718 def rename(ui, repo, *pats, **opts):
4697 """rename files; equivalent of copy + remove
4719 """rename files; equivalent of copy + remove
4698
4720
4699 Mark dest as copies of sources; mark sources for deletion. If dest
4721 Mark dest as copies of sources; mark sources for deletion. If dest
4700 is a directory, copies are put in that directory. If dest is a
4722 is a directory, copies are put in that directory. If dest is a
4701 file, there can only be one source.
4723 file, there can only be one source.
4702
4724
4703 By default, this command copies the contents of files as they
4725 By default, this command copies the contents of files as they
4704 exist in the working directory. If invoked with -A/--after, the
4726 exist in the working directory. If invoked with -A/--after, the
4705 operation is recorded, but no copying is performed.
4727 operation is recorded, but no copying is performed.
4706
4728
4707 This command takes effect at the next commit. To undo a rename
4729 This command takes effect at the next commit. To undo a rename
4708 before that, see :hg:`revert`.
4730 before that, see :hg:`revert`.
4709
4731
4710 Returns 0 on success, 1 if errors are encountered.
4732 Returns 0 on success, 1 if errors are encountered.
4711 """
4733 """
4712 wlock = repo.wlock(False)
4734 wlock = repo.wlock(False)
4713 try:
4735 try:
4714 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4736 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4715 finally:
4737 finally:
4716 wlock.release()
4738 wlock.release()
4717
4739
4718 @command('resolve',
4740 @command('resolve',
4719 [('a', 'all', None, _('select all unresolved files')),
4741 [('a', 'all', None, _('select all unresolved files')),
4720 ('l', 'list', None, _('list state of files needing merge')),
4742 ('l', 'list', None, _('list state of files needing merge')),
4721 ('m', 'mark', None, _('mark files as resolved')),
4743 ('m', 'mark', None, _('mark files as resolved')),
4722 ('u', 'unmark', None, _('mark files as unresolved')),
4744 ('u', 'unmark', None, _('mark files as unresolved')),
4723 ('n', 'no-status', None, _('hide status prefix'))]
4745 ('n', 'no-status', None, _('hide status prefix'))]
4724 + mergetoolopts + walkopts,
4746 + mergetoolopts + walkopts,
4725 _('[OPTION]... [FILE]...'))
4747 _('[OPTION]... [FILE]...'))
4726 def resolve(ui, repo, *pats, **opts):
4748 def resolve(ui, repo, *pats, **opts):
4727 """redo merges or set/view the merge status of files
4749 """redo merges or set/view the merge status of files
4728
4750
4729 Merges with unresolved conflicts are often the result of
4751 Merges with unresolved conflicts are often the result of
4730 non-interactive merging using the ``internal:merge`` configuration
4752 non-interactive merging using the ``internal:merge`` configuration
4731 setting, or a command-line merge tool like ``diff3``. The resolve
4753 setting, or a command-line merge tool like ``diff3``. The resolve
4732 command is used to manage the files involved in a merge, after
4754 command is used to manage the files involved in a merge, after
4733 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4755 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4734 working directory must have two parents). See :hg:`help
4756 working directory must have two parents). See :hg:`help
4735 merge-tools` for information on configuring merge tools.
4757 merge-tools` for information on configuring merge tools.
4736
4758
4737 The resolve command can be used in the following ways:
4759 The resolve command can be used in the following ways:
4738
4760
4739 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4761 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4740 files, discarding any previous merge attempts. Re-merging is not
4762 files, discarding any previous merge attempts. Re-merging is not
4741 performed for files already marked as resolved. Use ``--all/-a``
4763 performed for files already marked as resolved. Use ``--all/-a``
4742 to select all unresolved files. ``--tool`` can be used to specify
4764 to select all unresolved files. ``--tool`` can be used to specify
4743 the merge tool used for the given files. It overrides the HGMERGE
4765 the merge tool used for the given files. It overrides the HGMERGE
4744 environment variable and your configuration files. Previous file
4766 environment variable and your configuration files. Previous file
4745 contents are saved with a ``.orig`` suffix.
4767 contents are saved with a ``.orig`` suffix.
4746
4768
4747 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4769 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4748 (e.g. after having manually fixed-up the files). The default is
4770 (e.g. after having manually fixed-up the files). The default is
4749 to mark all unresolved files.
4771 to mark all unresolved files.
4750
4772
4751 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4773 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4752 default is to mark all resolved files.
4774 default is to mark all resolved files.
4753
4775
4754 - :hg:`resolve -l`: list files which had or still have conflicts.
4776 - :hg:`resolve -l`: list files which had or still have conflicts.
4755 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4777 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4756
4778
4757 Note that Mercurial will not let you commit files with unresolved
4779 Note that Mercurial will not let you commit files with unresolved
4758 merge conflicts. You must use :hg:`resolve -m ...` before you can
4780 merge conflicts. You must use :hg:`resolve -m ...` before you can
4759 commit after a conflicting merge.
4781 commit after a conflicting merge.
4760
4782
4761 Returns 0 on success, 1 if any files fail a resolve attempt.
4783 Returns 0 on success, 1 if any files fail a resolve attempt.
4762 """
4784 """
4763
4785
4764 all, mark, unmark, show, nostatus = \
4786 all, mark, unmark, show, nostatus = \
4765 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4787 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4766
4788
4767 if (show and (mark or unmark)) or (mark and unmark):
4789 if (show and (mark or unmark)) or (mark and unmark):
4768 raise util.Abort(_("too many options specified"))
4790 raise util.Abort(_("too many options specified"))
4769 if pats and all:
4791 if pats and all:
4770 raise util.Abort(_("can't specify --all and patterns"))
4792 raise util.Abort(_("can't specify --all and patterns"))
4771 if not (all or pats or show or mark or unmark):
4793 if not (all or pats or show or mark or unmark):
4772 raise util.Abort(_('no files or directories specified; '
4794 raise util.Abort(_('no files or directories specified; '
4773 'use --all to remerge all files'))
4795 'use --all to remerge all files'))
4774
4796
4775 ms = mergemod.mergestate(repo)
4797 ms = mergemod.mergestate(repo)
4776 m = scmutil.match(repo[None], pats, opts)
4798 m = scmutil.match(repo[None], pats, opts)
4777 ret = 0
4799 ret = 0
4778
4800
4779 for f in ms:
4801 for f in ms:
4780 if m(f):
4802 if m(f):
4781 if show:
4803 if show:
4782 if nostatus:
4804 if nostatus:
4783 ui.write("%s\n" % f)
4805 ui.write("%s\n" % f)
4784 else:
4806 else:
4785 ui.write("%s %s\n" % (ms[f].upper(), f),
4807 ui.write("%s %s\n" % (ms[f].upper(), f),
4786 label='resolve.' +
4808 label='resolve.' +
4787 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4809 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4788 elif mark:
4810 elif mark:
4789 ms.mark(f, "r")
4811 ms.mark(f, "r")
4790 elif unmark:
4812 elif unmark:
4791 ms.mark(f, "u")
4813 ms.mark(f, "u")
4792 else:
4814 else:
4793 wctx = repo[None]
4815 wctx = repo[None]
4794 mctx = wctx.parents()[-1]
4816 mctx = wctx.parents()[-1]
4795
4817
4796 # backup pre-resolve (merge uses .orig for its own purposes)
4818 # backup pre-resolve (merge uses .orig for its own purposes)
4797 a = repo.wjoin(f)
4819 a = repo.wjoin(f)
4798 util.copyfile(a, a + ".resolve")
4820 util.copyfile(a, a + ".resolve")
4799
4821
4800 try:
4822 try:
4801 # resolve file
4823 # resolve file
4802 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4824 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4803 if ms.resolve(f, wctx, mctx):
4825 if ms.resolve(f, wctx, mctx):
4804 ret = 1
4826 ret = 1
4805 finally:
4827 finally:
4806 ui.setconfig('ui', 'forcemerge', '')
4828 ui.setconfig('ui', 'forcemerge', '')
4807
4829
4808 # replace filemerge's .orig file with our resolve file
4830 # replace filemerge's .orig file with our resolve file
4809 util.rename(a + ".resolve", a + ".orig")
4831 util.rename(a + ".resolve", a + ".orig")
4810
4832
4811 ms.commit()
4833 ms.commit()
4812 return ret
4834 return ret
4813
4835
4814 @command('revert',
4836 @command('revert',
4815 [('a', 'all', None, _('revert all changes when no arguments given')),
4837 [('a', 'all', None, _('revert all changes when no arguments given')),
4816 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4838 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4817 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4839 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4818 ('C', 'no-backup', None, _('do not save backup copies of files')),
4840 ('C', 'no-backup', None, _('do not save backup copies of files')),
4819 ] + walkopts + dryrunopts,
4841 ] + walkopts + dryrunopts,
4820 _('[OPTION]... [-r REV] [NAME]...'))
4842 _('[OPTION]... [-r REV] [NAME]...'))
4821 def revert(ui, repo, *pats, **opts):
4843 def revert(ui, repo, *pats, **opts):
4822 """restore files to their checkout state
4844 """restore files to their checkout state
4823
4845
4824 .. note::
4846 .. note::
4825 To check out earlier revisions, you should use :hg:`update REV`.
4847 To check out earlier revisions, you should use :hg:`update REV`.
4826 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4848 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4827
4849
4828 With no revision specified, revert the specified files or directories
4850 With no revision specified, revert the specified files or directories
4829 to the contents they had in the parent of the working directory.
4851 to the contents they had in the parent of the working directory.
4830 This restores the contents of files to an unmodified
4852 This restores the contents of files to an unmodified
4831 state and unschedules adds, removes, copies, and renames. If the
4853 state and unschedules adds, removes, copies, and renames. If the
4832 working directory has two parents, you must explicitly specify a
4854 working directory has two parents, you must explicitly specify a
4833 revision.
4855 revision.
4834
4856
4835 Using the -r/--rev or -d/--date options, revert the given files or
4857 Using the -r/--rev or -d/--date options, revert the given files or
4836 directories to their states as of a specific revision. Because
4858 directories to their states as of a specific revision. Because
4837 revert does not change the working directory parents, this will
4859 revert does not change the working directory parents, this will
4838 cause these files to appear modified. This can be helpful to "back
4860 cause these files to appear modified. This can be helpful to "back
4839 out" some or all of an earlier change. See :hg:`backout` for a
4861 out" some or all of an earlier change. See :hg:`backout` for a
4840 related method.
4862 related method.
4841
4863
4842 Modified files are saved with a .orig suffix before reverting.
4864 Modified files are saved with a .orig suffix before reverting.
4843 To disable these backups, use --no-backup.
4865 To disable these backups, use --no-backup.
4844
4866
4845 See :hg:`help dates` for a list of formats valid for -d/--date.
4867 See :hg:`help dates` for a list of formats valid for -d/--date.
4846
4868
4847 Returns 0 on success.
4869 Returns 0 on success.
4848 """
4870 """
4849
4871
4850 if opts.get("date"):
4872 if opts.get("date"):
4851 if opts.get("rev"):
4873 if opts.get("rev"):
4852 raise util.Abort(_("you can't specify a revision and a date"))
4874 raise util.Abort(_("you can't specify a revision and a date"))
4853 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4875 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4854
4876
4855 parent, p2 = repo.dirstate.parents()
4877 parent, p2 = repo.dirstate.parents()
4856 if not opts.get('rev') and p2 != nullid:
4878 if not opts.get('rev') and p2 != nullid:
4857 # revert after merge is a trap for new users (issue2915)
4879 # revert after merge is a trap for new users (issue2915)
4858 raise util.Abort(_('uncommitted merge with no revision specified'),
4880 raise util.Abort(_('uncommitted merge with no revision specified'),
4859 hint=_('use "hg update" or see "hg help revert"'))
4881 hint=_('use "hg update" or see "hg help revert"'))
4860
4882
4861 ctx = scmutil.revsingle(repo, opts.get('rev'))
4883 ctx = scmutil.revsingle(repo, opts.get('rev'))
4862
4884
4863 if not pats and not opts.get('all'):
4885 if not pats and not opts.get('all'):
4864 msg = _("no files or directories specified")
4886 msg = _("no files or directories specified")
4865 if p2 != nullid:
4887 if p2 != nullid:
4866 hint = _("uncommitted merge, use --all to discard all changes,"
4888 hint = _("uncommitted merge, use --all to discard all changes,"
4867 " or 'hg update -C .' to abort the merge")
4889 " or 'hg update -C .' to abort the merge")
4868 raise util.Abort(msg, hint=hint)
4890 raise util.Abort(msg, hint=hint)
4869 dirty = util.any(repo.status())
4891 dirty = util.any(repo.status())
4870 node = ctx.node()
4892 node = ctx.node()
4871 if node != parent:
4893 if node != parent:
4872 if dirty:
4894 if dirty:
4873 hint = _("uncommitted changes, use --all to discard all"
4895 hint = _("uncommitted changes, use --all to discard all"
4874 " changes, or 'hg update %s' to update") % ctx.rev()
4896 " changes, or 'hg update %s' to update") % ctx.rev()
4875 else:
4897 else:
4876 hint = _("use --all to revert all files,"
4898 hint = _("use --all to revert all files,"
4877 " or 'hg update %s' to update") % ctx.rev()
4899 " or 'hg update %s' to update") % ctx.rev()
4878 elif dirty:
4900 elif dirty:
4879 hint = _("uncommitted changes, use --all to discard all changes")
4901 hint = _("uncommitted changes, use --all to discard all changes")
4880 else:
4902 else:
4881 hint = _("use --all to revert all files")
4903 hint = _("use --all to revert all files")
4882 raise util.Abort(msg, hint=hint)
4904 raise util.Abort(msg, hint=hint)
4883
4905
4884 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4906 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4885
4907
4886 @command('rollback', dryrunopts +
4908 @command('rollback', dryrunopts +
4887 [('f', 'force', False, _('ignore safety measures'))])
4909 [('f', 'force', False, _('ignore safety measures'))])
4888 def rollback(ui, repo, **opts):
4910 def rollback(ui, repo, **opts):
4889 """roll back the last transaction (dangerous)
4911 """roll back the last transaction (dangerous)
4890
4912
4891 This command should be used with care. There is only one level of
4913 This command should be used with care. There is only one level of
4892 rollback, and there is no way to undo a rollback. It will also
4914 rollback, and there is no way to undo a rollback. It will also
4893 restore the dirstate at the time of the last transaction, losing
4915 restore the dirstate at the time of the last transaction, losing
4894 any dirstate changes since that time. This command does not alter
4916 any dirstate changes since that time. This command does not alter
4895 the working directory.
4917 the working directory.
4896
4918
4897 Transactions are used to encapsulate the effects of all commands
4919 Transactions are used to encapsulate the effects of all commands
4898 that create new changesets or propagate existing changesets into a
4920 that create new changesets or propagate existing changesets into a
4899 repository. For example, the following commands are transactional,
4921 repository. For example, the following commands are transactional,
4900 and their effects can be rolled back:
4922 and their effects can be rolled back:
4901
4923
4902 - commit
4924 - commit
4903 - import
4925 - import
4904 - pull
4926 - pull
4905 - push (with this repository as the destination)
4927 - push (with this repository as the destination)
4906 - unbundle
4928 - unbundle
4907
4929
4908 To avoid permanent data loss, rollback will refuse to rollback a
4930 To avoid permanent data loss, rollback will refuse to rollback a
4909 commit transaction if it isn't checked out. Use --force to
4931 commit transaction if it isn't checked out. Use --force to
4910 override this protection.
4932 override this protection.
4911
4933
4912 This command is not intended for use on public repositories. Once
4934 This command is not intended for use on public repositories. Once
4913 changes are visible for pull by other users, rolling a transaction
4935 changes are visible for pull by other users, rolling a transaction
4914 back locally is ineffective (someone else may already have pulled
4936 back locally is ineffective (someone else may already have pulled
4915 the changes). Furthermore, a race is possible with readers of the
4937 the changes). Furthermore, a race is possible with readers of the
4916 repository; for example an in-progress pull from the repository
4938 repository; for example an in-progress pull from the repository
4917 may fail if a rollback is performed.
4939 may fail if a rollback is performed.
4918
4940
4919 Returns 0 on success, 1 if no rollback data is available.
4941 Returns 0 on success, 1 if no rollback data is available.
4920 """
4942 """
4921 return repo.rollback(dryrun=opts.get('dry_run'),
4943 return repo.rollback(dryrun=opts.get('dry_run'),
4922 force=opts.get('force'))
4944 force=opts.get('force'))
4923
4945
4924 @command('root', [])
4946 @command('root', [])
4925 def root(ui, repo):
4947 def root(ui, repo):
4926 """print the root (top) of the current working directory
4948 """print the root (top) of the current working directory
4927
4949
4928 Print the root directory of the current repository.
4950 Print the root directory of the current repository.
4929
4951
4930 Returns 0 on success.
4952 Returns 0 on success.
4931 """
4953 """
4932 ui.write(repo.root + "\n")
4954 ui.write(repo.root + "\n")
4933
4955
4934 @command('^serve',
4956 @command('^serve',
4935 [('A', 'accesslog', '', _('name of access log file to write to'),
4957 [('A', 'accesslog', '', _('name of access log file to write to'),
4936 _('FILE')),
4958 _('FILE')),
4937 ('d', 'daemon', None, _('run server in background')),
4959 ('d', 'daemon', None, _('run server in background')),
4938 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4960 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4939 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4961 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4940 # use string type, then we can check if something was passed
4962 # use string type, then we can check if something was passed
4941 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4963 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4942 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4964 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4943 _('ADDR')),
4965 _('ADDR')),
4944 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4966 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4945 _('PREFIX')),
4967 _('PREFIX')),
4946 ('n', 'name', '',
4968 ('n', 'name', '',
4947 _('name to show in web pages (default: working directory)'), _('NAME')),
4969 _('name to show in web pages (default: working directory)'), _('NAME')),
4948 ('', 'web-conf', '',
4970 ('', 'web-conf', '',
4949 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4971 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4950 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4972 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4951 _('FILE')),
4973 _('FILE')),
4952 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4974 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4953 ('', 'stdio', None, _('for remote clients')),
4975 ('', 'stdio', None, _('for remote clients')),
4954 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4976 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4955 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4977 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4956 ('', 'style', '', _('template style to use'), _('STYLE')),
4978 ('', 'style', '', _('template style to use'), _('STYLE')),
4957 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4979 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4958 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4980 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4959 _('[OPTION]...'))
4981 _('[OPTION]...'))
4960 def serve(ui, repo, **opts):
4982 def serve(ui, repo, **opts):
4961 """start stand-alone webserver
4983 """start stand-alone webserver
4962
4984
4963 Start a local HTTP repository browser and pull server. You can use
4985 Start a local HTTP repository browser and pull server. You can use
4964 this for ad-hoc sharing and browsing of repositories. It is
4986 this for ad-hoc sharing and browsing of repositories. It is
4965 recommended to use a real web server to serve a repository for
4987 recommended to use a real web server to serve a repository for
4966 longer periods of time.
4988 longer periods of time.
4967
4989
4968 Please note that the server does not implement access control.
4990 Please note that the server does not implement access control.
4969 This means that, by default, anybody can read from the server and
4991 This means that, by default, anybody can read from the server and
4970 nobody can write to it by default. Set the ``web.allow_push``
4992 nobody can write to it by default. Set the ``web.allow_push``
4971 option to ``*`` to allow everybody to push to the server. You
4993 option to ``*`` to allow everybody to push to the server. You
4972 should use a real web server if you need to authenticate users.
4994 should use a real web server if you need to authenticate users.
4973
4995
4974 By default, the server logs accesses to stdout and errors to
4996 By default, the server logs accesses to stdout and errors to
4975 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4997 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4976 files.
4998 files.
4977
4999
4978 To have the server choose a free port number to listen on, specify
5000 To have the server choose a free port number to listen on, specify
4979 a port number of 0; in this case, the server will print the port
5001 a port number of 0; in this case, the server will print the port
4980 number it uses.
5002 number it uses.
4981
5003
4982 Returns 0 on success.
5004 Returns 0 on success.
4983 """
5005 """
4984
5006
4985 if opts["stdio"] and opts["cmdserver"]:
5007 if opts["stdio"] and opts["cmdserver"]:
4986 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5008 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4987
5009
4988 def checkrepo():
5010 def checkrepo():
4989 if repo is None:
5011 if repo is None:
4990 raise error.RepoError(_("There is no Mercurial repository here"
5012 raise error.RepoError(_("There is no Mercurial repository here"
4991 " (.hg not found)"))
5013 " (.hg not found)"))
4992
5014
4993 if opts["stdio"]:
5015 if opts["stdio"]:
4994 checkrepo()
5016 checkrepo()
4995 s = sshserver.sshserver(ui, repo)
5017 s = sshserver.sshserver(ui, repo)
4996 s.serve_forever()
5018 s.serve_forever()
4997
5019
4998 if opts["cmdserver"]:
5020 if opts["cmdserver"]:
4999 checkrepo()
5021 checkrepo()
5000 s = commandserver.server(ui, repo, opts["cmdserver"])
5022 s = commandserver.server(ui, repo, opts["cmdserver"])
5001 return s.serve()
5023 return s.serve()
5002
5024
5003 # this way we can check if something was given in the command-line
5025 # this way we can check if something was given in the command-line
5004 if opts.get('port'):
5026 if opts.get('port'):
5005 opts['port'] = util.getport(opts.get('port'))
5027 opts['port'] = util.getport(opts.get('port'))
5006
5028
5007 baseui = repo and repo.baseui or ui
5029 baseui = repo and repo.baseui or ui
5008 optlist = ("name templates style address port prefix ipv6"
5030 optlist = ("name templates style address port prefix ipv6"
5009 " accesslog errorlog certificate encoding")
5031 " accesslog errorlog certificate encoding")
5010 for o in optlist.split():
5032 for o in optlist.split():
5011 val = opts.get(o, '')
5033 val = opts.get(o, '')
5012 if val in (None, ''): # should check against default options instead
5034 if val in (None, ''): # should check against default options instead
5013 continue
5035 continue
5014 baseui.setconfig("web", o, val)
5036 baseui.setconfig("web", o, val)
5015 if repo and repo.ui != baseui:
5037 if repo and repo.ui != baseui:
5016 repo.ui.setconfig("web", o, val)
5038 repo.ui.setconfig("web", o, val)
5017
5039
5018 o = opts.get('web_conf') or opts.get('webdir_conf')
5040 o = opts.get('web_conf') or opts.get('webdir_conf')
5019 if not o:
5041 if not o:
5020 if not repo:
5042 if not repo:
5021 raise error.RepoError(_("There is no Mercurial repository"
5043 raise error.RepoError(_("There is no Mercurial repository"
5022 " here (.hg not found)"))
5044 " here (.hg not found)"))
5023 o = repo.root
5045 o = repo.root
5024
5046
5025 app = hgweb.hgweb(o, baseui=ui)
5047 app = hgweb.hgweb(o, baseui=ui)
5026
5048
5027 class service(object):
5049 class service(object):
5028 def init(self):
5050 def init(self):
5029 util.setsignalhandler()
5051 util.setsignalhandler()
5030 self.httpd = hgweb.server.create_server(ui, app)
5052 self.httpd = hgweb.server.create_server(ui, app)
5031
5053
5032 if opts['port'] and not ui.verbose:
5054 if opts['port'] and not ui.verbose:
5033 return
5055 return
5034
5056
5035 if self.httpd.prefix:
5057 if self.httpd.prefix:
5036 prefix = self.httpd.prefix.strip('/') + '/'
5058 prefix = self.httpd.prefix.strip('/') + '/'
5037 else:
5059 else:
5038 prefix = ''
5060 prefix = ''
5039
5061
5040 port = ':%d' % self.httpd.port
5062 port = ':%d' % self.httpd.port
5041 if port == ':80':
5063 if port == ':80':
5042 port = ''
5064 port = ''
5043
5065
5044 bindaddr = self.httpd.addr
5066 bindaddr = self.httpd.addr
5045 if bindaddr == '0.0.0.0':
5067 if bindaddr == '0.0.0.0':
5046 bindaddr = '*'
5068 bindaddr = '*'
5047 elif ':' in bindaddr: # IPv6
5069 elif ':' in bindaddr: # IPv6
5048 bindaddr = '[%s]' % bindaddr
5070 bindaddr = '[%s]' % bindaddr
5049
5071
5050 fqaddr = self.httpd.fqaddr
5072 fqaddr = self.httpd.fqaddr
5051 if ':' in fqaddr:
5073 if ':' in fqaddr:
5052 fqaddr = '[%s]' % fqaddr
5074 fqaddr = '[%s]' % fqaddr
5053 if opts['port']:
5075 if opts['port']:
5054 write = ui.status
5076 write = ui.status
5055 else:
5077 else:
5056 write = ui.write
5078 write = ui.write
5057 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5079 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5058 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5080 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5059
5081
5060 def run(self):
5082 def run(self):
5061 self.httpd.serve_forever()
5083 self.httpd.serve_forever()
5062
5084
5063 service = service()
5085 service = service()
5064
5086
5065 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5087 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5066
5088
5067 @command('showconfig|debugconfig',
5089 @command('showconfig|debugconfig',
5068 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5090 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5069 _('[-u] [NAME]...'))
5091 _('[-u] [NAME]...'))
5070 def showconfig(ui, repo, *values, **opts):
5092 def showconfig(ui, repo, *values, **opts):
5071 """show combined config settings from all hgrc files
5093 """show combined config settings from all hgrc files
5072
5094
5073 With no arguments, print names and values of all config items.
5095 With no arguments, print names and values of all config items.
5074
5096
5075 With one argument of the form section.name, print just the value
5097 With one argument of the form section.name, print just the value
5076 of that config item.
5098 of that config item.
5077
5099
5078 With multiple arguments, print names and values of all config
5100 With multiple arguments, print names and values of all config
5079 items with matching section names.
5101 items with matching section names.
5080
5102
5081 With --debug, the source (filename and line number) is printed
5103 With --debug, the source (filename and line number) is printed
5082 for each config item.
5104 for each config item.
5083
5105
5084 Returns 0 on success.
5106 Returns 0 on success.
5085 """
5107 """
5086
5108
5087 for f in scmutil.rcpath():
5109 for f in scmutil.rcpath():
5088 ui.debug('read config from: %s\n' % f)
5110 ui.debug('read config from: %s\n' % f)
5089 untrusted = bool(opts.get('untrusted'))
5111 untrusted = bool(opts.get('untrusted'))
5090 if values:
5112 if values:
5091 sections = [v for v in values if '.' not in v]
5113 sections = [v for v in values if '.' not in v]
5092 items = [v for v in values if '.' in v]
5114 items = [v for v in values if '.' in v]
5093 if len(items) > 1 or items and sections:
5115 if len(items) > 1 or items and sections:
5094 raise util.Abort(_('only one config item permitted'))
5116 raise util.Abort(_('only one config item permitted'))
5095 for section, name, value in ui.walkconfig(untrusted=untrusted):
5117 for section, name, value in ui.walkconfig(untrusted=untrusted):
5096 value = str(value).replace('\n', '\\n')
5118 value = str(value).replace('\n', '\\n')
5097 sectname = section + '.' + name
5119 sectname = section + '.' + name
5098 if values:
5120 if values:
5099 for v in values:
5121 for v in values:
5100 if v == section:
5122 if v == section:
5101 ui.debug('%s: ' %
5123 ui.debug('%s: ' %
5102 ui.configsource(section, name, untrusted))
5124 ui.configsource(section, name, untrusted))
5103 ui.write('%s=%s\n' % (sectname, value))
5125 ui.write('%s=%s\n' % (sectname, value))
5104 elif v == sectname:
5126 elif v == sectname:
5105 ui.debug('%s: ' %
5127 ui.debug('%s: ' %
5106 ui.configsource(section, name, untrusted))
5128 ui.configsource(section, name, untrusted))
5107 ui.write(value, '\n')
5129 ui.write(value, '\n')
5108 else:
5130 else:
5109 ui.debug('%s: ' %
5131 ui.debug('%s: ' %
5110 ui.configsource(section, name, untrusted))
5132 ui.configsource(section, name, untrusted))
5111 ui.write('%s=%s\n' % (sectname, value))
5133 ui.write('%s=%s\n' % (sectname, value))
5112
5134
5113 @command('^status|st',
5135 @command('^status|st',
5114 [('A', 'all', None, _('show status of all files')),
5136 [('A', 'all', None, _('show status of all files')),
5115 ('m', 'modified', None, _('show only modified files')),
5137 ('m', 'modified', None, _('show only modified files')),
5116 ('a', 'added', None, _('show only added files')),
5138 ('a', 'added', None, _('show only added files')),
5117 ('r', 'removed', None, _('show only removed files')),
5139 ('r', 'removed', None, _('show only removed files')),
5118 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5140 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5119 ('c', 'clean', None, _('show only files without changes')),
5141 ('c', 'clean', None, _('show only files without changes')),
5120 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5142 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5121 ('i', 'ignored', None, _('show only ignored files')),
5143 ('i', 'ignored', None, _('show only ignored files')),
5122 ('n', 'no-status', None, _('hide status prefix')),
5144 ('n', 'no-status', None, _('hide status prefix')),
5123 ('C', 'copies', None, _('show source of copied files')),
5145 ('C', 'copies', None, _('show source of copied files')),
5124 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5146 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5125 ('', 'rev', [], _('show difference from revision'), _('REV')),
5147 ('', 'rev', [], _('show difference from revision'), _('REV')),
5126 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5148 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5127 ] + walkopts + subrepoopts,
5149 ] + walkopts + subrepoopts,
5128 _('[OPTION]... [FILE]...'))
5150 _('[OPTION]... [FILE]...'))
5129 def status(ui, repo, *pats, **opts):
5151 def status(ui, repo, *pats, **opts):
5130 """show changed files in the working directory
5152 """show changed files in the working directory
5131
5153
5132 Show status of files in the repository. If names are given, only
5154 Show status of files in the repository. If names are given, only
5133 files that match are shown. Files that are clean or ignored or
5155 files that match are shown. Files that are clean or ignored or
5134 the source of a copy/move operation, are not listed unless
5156 the source of a copy/move operation, are not listed unless
5135 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5157 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5136 Unless options described with "show only ..." are given, the
5158 Unless options described with "show only ..." are given, the
5137 options -mardu are used.
5159 options -mardu are used.
5138
5160
5139 Option -q/--quiet hides untracked (unknown and ignored) files
5161 Option -q/--quiet hides untracked (unknown and ignored) files
5140 unless explicitly requested with -u/--unknown or -i/--ignored.
5162 unless explicitly requested with -u/--unknown or -i/--ignored.
5141
5163
5142 .. note::
5164 .. note::
5143 status may appear to disagree with diff if permissions have
5165 status may appear to disagree with diff if permissions have
5144 changed or a merge has occurred. The standard diff format does
5166 changed or a merge has occurred. The standard diff format does
5145 not report permission changes and diff only reports changes
5167 not report permission changes and diff only reports changes
5146 relative to one merge parent.
5168 relative to one merge parent.
5147
5169
5148 If one revision is given, it is used as the base revision.
5170 If one revision is given, it is used as the base revision.
5149 If two revisions are given, the differences between them are
5171 If two revisions are given, the differences between them are
5150 shown. The --change option can also be used as a shortcut to list
5172 shown. The --change option can also be used as a shortcut to list
5151 the changed files of a revision from its first parent.
5173 the changed files of a revision from its first parent.
5152
5174
5153 The codes used to show the status of files are::
5175 The codes used to show the status of files are::
5154
5176
5155 M = modified
5177 M = modified
5156 A = added
5178 A = added
5157 R = removed
5179 R = removed
5158 C = clean
5180 C = clean
5159 ! = missing (deleted by non-hg command, but still tracked)
5181 ! = missing (deleted by non-hg command, but still tracked)
5160 ? = not tracked
5182 ? = not tracked
5161 I = ignored
5183 I = ignored
5162 = origin of the previous file listed as A (added)
5184 = origin of the previous file listed as A (added)
5163
5185
5164 .. container:: verbose
5186 .. container:: verbose
5165
5187
5166 Examples:
5188 Examples:
5167
5189
5168 - show changes in the working directory relative to a
5190 - show changes in the working directory relative to a
5169 changeset::
5191 changeset::
5170
5192
5171 hg status --rev 9353
5193 hg status --rev 9353
5172
5194
5173 - show all changes including copies in an existing changeset::
5195 - show all changes including copies in an existing changeset::
5174
5196
5175 hg status --copies --change 9353
5197 hg status --copies --change 9353
5176
5198
5177 - get a NUL separated list of added files, suitable for xargs::
5199 - get a NUL separated list of added files, suitable for xargs::
5178
5200
5179 hg status -an0
5201 hg status -an0
5180
5202
5181 Returns 0 on success.
5203 Returns 0 on success.
5182 """
5204 """
5183
5205
5184 revs = opts.get('rev')
5206 revs = opts.get('rev')
5185 change = opts.get('change')
5207 change = opts.get('change')
5186
5208
5187 if revs and change:
5209 if revs and change:
5188 msg = _('cannot specify --rev and --change at the same time')
5210 msg = _('cannot specify --rev and --change at the same time')
5189 raise util.Abort(msg)
5211 raise util.Abort(msg)
5190 elif change:
5212 elif change:
5191 node2 = scmutil.revsingle(repo, change, None).node()
5213 node2 = scmutil.revsingle(repo, change, None).node()
5192 node1 = repo[node2].p1().node()
5214 node1 = repo[node2].p1().node()
5193 else:
5215 else:
5194 node1, node2 = scmutil.revpair(repo, revs)
5216 node1, node2 = scmutil.revpair(repo, revs)
5195
5217
5196 cwd = (pats and repo.getcwd()) or ''
5218 cwd = (pats and repo.getcwd()) or ''
5197 end = opts.get('print0') and '\0' or '\n'
5219 end = opts.get('print0') and '\0' or '\n'
5198 copy = {}
5220 copy = {}
5199 states = 'modified added removed deleted unknown ignored clean'.split()
5221 states = 'modified added removed deleted unknown ignored clean'.split()
5200 show = [k for k in states if opts.get(k)]
5222 show = [k for k in states if opts.get(k)]
5201 if opts.get('all'):
5223 if opts.get('all'):
5202 show += ui.quiet and (states[:4] + ['clean']) or states
5224 show += ui.quiet and (states[:4] + ['clean']) or states
5203 if not show:
5225 if not show:
5204 show = ui.quiet and states[:4] or states[:5]
5226 show = ui.quiet and states[:4] or states[:5]
5205
5227
5206 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5228 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5207 'ignored' in show, 'clean' in show, 'unknown' in show,
5229 'ignored' in show, 'clean' in show, 'unknown' in show,
5208 opts.get('subrepos'))
5230 opts.get('subrepos'))
5209 changestates = zip(states, 'MAR!?IC', stat)
5231 changestates = zip(states, 'MAR!?IC', stat)
5210
5232
5211 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5233 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5212 copy = copies.pathcopies(repo[node1], repo[node2])
5234 copy = copies.pathcopies(repo[node1], repo[node2])
5213
5235
5214 fm = ui.formatter('status', opts)
5236 fm = ui.formatter('status', opts)
5215 format = '%s %s' + end
5237 format = '%s %s' + end
5216 if opts.get('no_status'):
5238 if opts.get('no_status'):
5217 format = '%.0s%s' + end
5239 format = '%.0s%s' + end
5218
5240
5219 for state, char, files in changestates:
5241 for state, char, files in changestates:
5220 if state in show:
5242 if state in show:
5221 label = 'status.' + state
5243 label = 'status.' + state
5222 for f in files:
5244 for f in files:
5223 fm.startitem()
5245 fm.startitem()
5224 fm.write("status path", format, char,
5246 fm.write("status path", format, char,
5225 repo.pathto(f, cwd), label=label)
5247 repo.pathto(f, cwd), label=label)
5226 if f in copy:
5248 if f in copy:
5227 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5249 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5228 label='status.copied')
5250 label='status.copied')
5229 fm.end()
5251 fm.end()
5230
5252
5231 @command('^summary|sum',
5253 @command('^summary|sum',
5232 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5254 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5233 def summary(ui, repo, **opts):
5255 def summary(ui, repo, **opts):
5234 """summarize working directory state
5256 """summarize working directory state
5235
5257
5236 This generates a brief summary of the working directory state,
5258 This generates a brief summary of the working directory state,
5237 including parents, branch, commit status, and available updates.
5259 including parents, branch, commit status, and available updates.
5238
5260
5239 With the --remote option, this will check the default paths for
5261 With the --remote option, this will check the default paths for
5240 incoming and outgoing changes. This can be time-consuming.
5262 incoming and outgoing changes. This can be time-consuming.
5241
5263
5242 Returns 0 on success.
5264 Returns 0 on success.
5243 """
5265 """
5244
5266
5245 ctx = repo[None]
5267 ctx = repo[None]
5246 parents = ctx.parents()
5268 parents = ctx.parents()
5247 pnode = parents[0].node()
5269 pnode = parents[0].node()
5248 marks = []
5270 marks = []
5249
5271
5250 for p in parents:
5272 for p in parents:
5251 # label with log.changeset (instead of log.parent) since this
5273 # label with log.changeset (instead of log.parent) since this
5252 # shows a working directory parent *changeset*:
5274 # shows a working directory parent *changeset*:
5253 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5275 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5254 label='log.changeset')
5276 label='log.changeset')
5255 ui.write(' '.join(p.tags()), label='log.tag')
5277 ui.write(' '.join(p.tags()), label='log.tag')
5256 if p.bookmarks():
5278 if p.bookmarks():
5257 marks.extend(p.bookmarks())
5279 marks.extend(p.bookmarks())
5258 if p.rev() == -1:
5280 if p.rev() == -1:
5259 if not len(repo):
5281 if not len(repo):
5260 ui.write(_(' (empty repository)'))
5282 ui.write(_(' (empty repository)'))
5261 else:
5283 else:
5262 ui.write(_(' (no revision checked out)'))
5284 ui.write(_(' (no revision checked out)'))
5263 ui.write('\n')
5285 ui.write('\n')
5264 if p.description():
5286 if p.description():
5265 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5287 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5266 label='log.summary')
5288 label='log.summary')
5267
5289
5268 branch = ctx.branch()
5290 branch = ctx.branch()
5269 bheads = repo.branchheads(branch)
5291 bheads = repo.branchheads(branch)
5270 m = _('branch: %s\n') % branch
5292 m = _('branch: %s\n') % branch
5271 if branch != 'default':
5293 if branch != 'default':
5272 ui.write(m, label='log.branch')
5294 ui.write(m, label='log.branch')
5273 else:
5295 else:
5274 ui.status(m, label='log.branch')
5296 ui.status(m, label='log.branch')
5275
5297
5276 if marks:
5298 if marks:
5277 current = repo._bookmarkcurrent
5299 current = repo._bookmarkcurrent
5278 ui.write(_('bookmarks:'), label='log.bookmark')
5300 ui.write(_('bookmarks:'), label='log.bookmark')
5279 if current is not None:
5301 if current is not None:
5280 try:
5302 try:
5281 marks.remove(current)
5303 marks.remove(current)
5282 ui.write(' *' + current, label='bookmarks.current')
5304 ui.write(' *' + current, label='bookmarks.current')
5283 except ValueError:
5305 except ValueError:
5284 # current bookmark not in parent ctx marks
5306 # current bookmark not in parent ctx marks
5285 pass
5307 pass
5286 for m in marks:
5308 for m in marks:
5287 ui.write(' ' + m, label='log.bookmark')
5309 ui.write(' ' + m, label='log.bookmark')
5288 ui.write('\n', label='log.bookmark')
5310 ui.write('\n', label='log.bookmark')
5289
5311
5290 st = list(repo.status(unknown=True))[:6]
5312 st = list(repo.status(unknown=True))[:6]
5291
5313
5292 c = repo.dirstate.copies()
5314 c = repo.dirstate.copies()
5293 copied, renamed = [], []
5315 copied, renamed = [], []
5294 for d, s in c.iteritems():
5316 for d, s in c.iteritems():
5295 if s in st[2]:
5317 if s in st[2]:
5296 st[2].remove(s)
5318 st[2].remove(s)
5297 renamed.append(d)
5319 renamed.append(d)
5298 else:
5320 else:
5299 copied.append(d)
5321 copied.append(d)
5300 if d in st[1]:
5322 if d in st[1]:
5301 st[1].remove(d)
5323 st[1].remove(d)
5302 st.insert(3, renamed)
5324 st.insert(3, renamed)
5303 st.insert(4, copied)
5325 st.insert(4, copied)
5304
5326
5305 ms = mergemod.mergestate(repo)
5327 ms = mergemod.mergestate(repo)
5306 st.append([f for f in ms if ms[f] == 'u'])
5328 st.append([f for f in ms if ms[f] == 'u'])
5307
5329
5308 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5330 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5309 st.append(subs)
5331 st.append(subs)
5310
5332
5311 labels = [ui.label(_('%d modified'), 'status.modified'),
5333 labels = [ui.label(_('%d modified'), 'status.modified'),
5312 ui.label(_('%d added'), 'status.added'),
5334 ui.label(_('%d added'), 'status.added'),
5313 ui.label(_('%d removed'), 'status.removed'),
5335 ui.label(_('%d removed'), 'status.removed'),
5314 ui.label(_('%d renamed'), 'status.copied'),
5336 ui.label(_('%d renamed'), 'status.copied'),
5315 ui.label(_('%d copied'), 'status.copied'),
5337 ui.label(_('%d copied'), 'status.copied'),
5316 ui.label(_('%d deleted'), 'status.deleted'),
5338 ui.label(_('%d deleted'), 'status.deleted'),
5317 ui.label(_('%d unknown'), 'status.unknown'),
5339 ui.label(_('%d unknown'), 'status.unknown'),
5318 ui.label(_('%d ignored'), 'status.ignored'),
5340 ui.label(_('%d ignored'), 'status.ignored'),
5319 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5341 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5320 ui.label(_('%d subrepos'), 'status.modified')]
5342 ui.label(_('%d subrepos'), 'status.modified')]
5321 t = []
5343 t = []
5322 for s, l in zip(st, labels):
5344 for s, l in zip(st, labels):
5323 if s:
5345 if s:
5324 t.append(l % len(s))
5346 t.append(l % len(s))
5325
5347
5326 t = ', '.join(t)
5348 t = ', '.join(t)
5327 cleanworkdir = False
5349 cleanworkdir = False
5328
5350
5329 if len(parents) > 1:
5351 if len(parents) > 1:
5330 t += _(' (merge)')
5352 t += _(' (merge)')
5331 elif branch != parents[0].branch():
5353 elif branch != parents[0].branch():
5332 t += _(' (new branch)')
5354 t += _(' (new branch)')
5333 elif (parents[0].extra().get('close') and
5355 elif (parents[0].extra().get('close') and
5334 pnode in repo.branchheads(branch, closed=True)):
5356 pnode in repo.branchheads(branch, closed=True)):
5335 t += _(' (head closed)')
5357 t += _(' (head closed)')
5336 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5358 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5337 t += _(' (clean)')
5359 t += _(' (clean)')
5338 cleanworkdir = True
5360 cleanworkdir = True
5339 elif pnode not in bheads:
5361 elif pnode not in bheads:
5340 t += _(' (new branch head)')
5362 t += _(' (new branch head)')
5341
5363
5342 if cleanworkdir:
5364 if cleanworkdir:
5343 ui.status(_('commit: %s\n') % t.strip())
5365 ui.status(_('commit: %s\n') % t.strip())
5344 else:
5366 else:
5345 ui.write(_('commit: %s\n') % t.strip())
5367 ui.write(_('commit: %s\n') % t.strip())
5346
5368
5347 # all ancestors of branch heads - all ancestors of parent = new csets
5369 # all ancestors of branch heads - all ancestors of parent = new csets
5348 new = [0] * len(repo)
5370 new = [0] * len(repo)
5349 cl = repo.changelog
5371 cl = repo.changelog
5350 for a in [cl.rev(n) for n in bheads]:
5372 for a in [cl.rev(n) for n in bheads]:
5351 new[a] = 1
5373 new[a] = 1
5352 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5374 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5353 new[a] = 1
5375 new[a] = 1
5354 for a in [p.rev() for p in parents]:
5376 for a in [p.rev() for p in parents]:
5355 if a >= 0:
5377 if a >= 0:
5356 new[a] = 0
5378 new[a] = 0
5357 for a in cl.ancestors(*[p.rev() for p in parents]):
5379 for a in cl.ancestors(*[p.rev() for p in parents]):
5358 new[a] = 0
5380 new[a] = 0
5359 new = sum(new)
5381 new = sum(new)
5360
5382
5361 if new == 0:
5383 if new == 0:
5362 ui.status(_('update: (current)\n'))
5384 ui.status(_('update: (current)\n'))
5363 elif pnode not in bheads:
5385 elif pnode not in bheads:
5364 ui.write(_('update: %d new changesets (update)\n') % new)
5386 ui.write(_('update: %d new changesets (update)\n') % new)
5365 else:
5387 else:
5366 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5388 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5367 (new, len(bheads)))
5389 (new, len(bheads)))
5368
5390
5369 if opts.get('remote'):
5391 if opts.get('remote'):
5370 t = []
5392 t = []
5371 source, branches = hg.parseurl(ui.expandpath('default'))
5393 source, branches = hg.parseurl(ui.expandpath('default'))
5372 other = hg.peer(repo, {}, source)
5394 other = hg.peer(repo, {}, source)
5373 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5395 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5374 ui.debug('comparing with %s\n' % util.hidepassword(source))
5396 ui.debug('comparing with %s\n' % util.hidepassword(source))
5375 repo.ui.pushbuffer()
5397 repo.ui.pushbuffer()
5376 commoninc = discovery.findcommonincoming(repo, other)
5398 commoninc = discovery.findcommonincoming(repo, other)
5377 _common, incoming, _rheads = commoninc
5399 _common, incoming, _rheads = commoninc
5378 repo.ui.popbuffer()
5400 repo.ui.popbuffer()
5379 if incoming:
5401 if incoming:
5380 t.append(_('1 or more incoming'))
5402 t.append(_('1 or more incoming'))
5381
5403
5382 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5404 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5383 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5405 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5384 if source != dest:
5406 if source != dest:
5385 other = hg.peer(repo, {}, dest)
5407 other = hg.peer(repo, {}, dest)
5386 commoninc = None
5408 commoninc = None
5387 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5409 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5388 repo.ui.pushbuffer()
5410 repo.ui.pushbuffer()
5389 outgoing = discovery.findcommonoutgoing(repo, other,
5411 outgoing = discovery.findcommonoutgoing(repo, other,
5390 commoninc=commoninc)
5412 commoninc=commoninc)
5391 repo.ui.popbuffer()
5413 repo.ui.popbuffer()
5392 o = outgoing.missing
5414 o = outgoing.missing
5393 if o:
5415 if o:
5394 t.append(_('%d outgoing') % len(o))
5416 t.append(_('%d outgoing') % len(o))
5395 if 'bookmarks' in other.listkeys('namespaces'):
5417 if 'bookmarks' in other.listkeys('namespaces'):
5396 lmarks = repo.listkeys('bookmarks')
5418 lmarks = repo.listkeys('bookmarks')
5397 rmarks = other.listkeys('bookmarks')
5419 rmarks = other.listkeys('bookmarks')
5398 diff = set(rmarks) - set(lmarks)
5420 diff = set(rmarks) - set(lmarks)
5399 if len(diff) > 0:
5421 if len(diff) > 0:
5400 t.append(_('%d incoming bookmarks') % len(diff))
5422 t.append(_('%d incoming bookmarks') % len(diff))
5401 diff = set(lmarks) - set(rmarks)
5423 diff = set(lmarks) - set(rmarks)
5402 if len(diff) > 0:
5424 if len(diff) > 0:
5403 t.append(_('%d outgoing bookmarks') % len(diff))
5425 t.append(_('%d outgoing bookmarks') % len(diff))
5404
5426
5405 if t:
5427 if t:
5406 ui.write(_('remote: %s\n') % (', '.join(t)))
5428 ui.write(_('remote: %s\n') % (', '.join(t)))
5407 else:
5429 else:
5408 ui.status(_('remote: (synced)\n'))
5430 ui.status(_('remote: (synced)\n'))
5409
5431
5410 @command('tag',
5432 @command('tag',
5411 [('f', 'force', None, _('force tag')),
5433 [('f', 'force', None, _('force tag')),
5412 ('l', 'local', None, _('make the tag local')),
5434 ('l', 'local', None, _('make the tag local')),
5413 ('r', 'rev', '', _('revision to tag'), _('REV')),
5435 ('r', 'rev', '', _('revision to tag'), _('REV')),
5414 ('', 'remove', None, _('remove a tag')),
5436 ('', 'remove', None, _('remove a tag')),
5415 # -l/--local is already there, commitopts cannot be used
5437 # -l/--local is already there, commitopts cannot be used
5416 ('e', 'edit', None, _('edit commit message')),
5438 ('e', 'edit', None, _('edit commit message')),
5417 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5439 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5418 ] + commitopts2,
5440 ] + commitopts2,
5419 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5441 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5420 def tag(ui, repo, name1, *names, **opts):
5442 def tag(ui, repo, name1, *names, **opts):
5421 """add one or more tags for the current or given revision
5443 """add one or more tags for the current or given revision
5422
5444
5423 Name a particular revision using <name>.
5445 Name a particular revision using <name>.
5424
5446
5425 Tags are used to name particular revisions of the repository and are
5447 Tags are used to name particular revisions of the repository and are
5426 very useful to compare different revisions, to go back to significant
5448 very useful to compare different revisions, to go back to significant
5427 earlier versions or to mark branch points as releases, etc. Changing
5449 earlier versions or to mark branch points as releases, etc. Changing
5428 an existing tag is normally disallowed; use -f/--force to override.
5450 an existing tag is normally disallowed; use -f/--force to override.
5429
5451
5430 If no revision is given, the parent of the working directory is
5452 If no revision is given, the parent of the working directory is
5431 used, or tip if no revision is checked out.
5453 used, or tip if no revision is checked out.
5432
5454
5433 To facilitate version control, distribution, and merging of tags,
5455 To facilitate version control, distribution, and merging of tags,
5434 they are stored as a file named ".hgtags" which is managed similarly
5456 they are stored as a file named ".hgtags" which is managed similarly
5435 to other project files and can be hand-edited if necessary. This
5457 to other project files and can be hand-edited if necessary. This
5436 also means that tagging creates a new commit. The file
5458 also means that tagging creates a new commit. The file
5437 ".hg/localtags" is used for local tags (not shared among
5459 ".hg/localtags" is used for local tags (not shared among
5438 repositories).
5460 repositories).
5439
5461
5440 Tag commits are usually made at the head of a branch. If the parent
5462 Tag commits are usually made at the head of a branch. If the parent
5441 of the working directory is not a branch head, :hg:`tag` aborts; use
5463 of the working directory is not a branch head, :hg:`tag` aborts; use
5442 -f/--force to force the tag commit to be based on a non-head
5464 -f/--force to force the tag commit to be based on a non-head
5443 changeset.
5465 changeset.
5444
5466
5445 See :hg:`help dates` for a list of formats valid for -d/--date.
5467 See :hg:`help dates` for a list of formats valid for -d/--date.
5446
5468
5447 Since tag names have priority over branch names during revision
5469 Since tag names have priority over branch names during revision
5448 lookup, using an existing branch name as a tag name is discouraged.
5470 lookup, using an existing branch name as a tag name is discouraged.
5449
5471
5450 Returns 0 on success.
5472 Returns 0 on success.
5451 """
5473 """
5452 wlock = lock = None
5474 wlock = lock = None
5453 try:
5475 try:
5454 wlock = repo.wlock()
5476 wlock = repo.wlock()
5455 lock = repo.lock()
5477 lock = repo.lock()
5456 rev_ = "."
5478 rev_ = "."
5457 names = [t.strip() for t in (name1,) + names]
5479 names = [t.strip() for t in (name1,) + names]
5458 if len(names) != len(set(names)):
5480 if len(names) != len(set(names)):
5459 raise util.Abort(_('tag names must be unique'))
5481 raise util.Abort(_('tag names must be unique'))
5460 for n in names:
5482 for n in names:
5461 if n in ['tip', '.', 'null']:
5483 if n in ['tip', '.', 'null']:
5462 raise util.Abort(_("the name '%s' is reserved") % n)
5484 raise util.Abort(_("the name '%s' is reserved") % n)
5463 if not n:
5485 if not n:
5464 raise util.Abort(_('tag names cannot consist entirely of '
5486 raise util.Abort(_('tag names cannot consist entirely of '
5465 'whitespace'))
5487 'whitespace'))
5466 if opts.get('rev') and opts.get('remove'):
5488 if opts.get('rev') and opts.get('remove'):
5467 raise util.Abort(_("--rev and --remove are incompatible"))
5489 raise util.Abort(_("--rev and --remove are incompatible"))
5468 if opts.get('rev'):
5490 if opts.get('rev'):
5469 rev_ = opts['rev']
5491 rev_ = opts['rev']
5470 message = opts.get('message')
5492 message = opts.get('message')
5471 if opts.get('remove'):
5493 if opts.get('remove'):
5472 expectedtype = opts.get('local') and 'local' or 'global'
5494 expectedtype = opts.get('local') and 'local' or 'global'
5473 for n in names:
5495 for n in names:
5474 if not repo.tagtype(n):
5496 if not repo.tagtype(n):
5475 raise util.Abort(_("tag '%s' does not exist") % n)
5497 raise util.Abort(_("tag '%s' does not exist") % n)
5476 if repo.tagtype(n) != expectedtype:
5498 if repo.tagtype(n) != expectedtype:
5477 if expectedtype == 'global':
5499 if expectedtype == 'global':
5478 raise util.Abort(_("tag '%s' is not a global tag") % n)
5500 raise util.Abort(_("tag '%s' is not a global tag") % n)
5479 else:
5501 else:
5480 raise util.Abort(_("tag '%s' is not a local tag") % n)
5502 raise util.Abort(_("tag '%s' is not a local tag") % n)
5481 rev_ = nullid
5503 rev_ = nullid
5482 if not message:
5504 if not message:
5483 # we don't translate commit messages
5505 # we don't translate commit messages
5484 message = 'Removed tag %s' % ', '.join(names)
5506 message = 'Removed tag %s' % ', '.join(names)
5485 elif not opts.get('force'):
5507 elif not opts.get('force'):
5486 for n in names:
5508 for n in names:
5487 if n in repo.tags():
5509 if n in repo.tags():
5488 raise util.Abort(_("tag '%s' already exists "
5510 raise util.Abort(_("tag '%s' already exists "
5489 "(use -f to force)") % n)
5511 "(use -f to force)") % n)
5490 if not opts.get('local'):
5512 if not opts.get('local'):
5491 p1, p2 = repo.dirstate.parents()
5513 p1, p2 = repo.dirstate.parents()
5492 if p2 != nullid:
5514 if p2 != nullid:
5493 raise util.Abort(_('uncommitted merge'))
5515 raise util.Abort(_('uncommitted merge'))
5494 bheads = repo.branchheads()
5516 bheads = repo.branchheads()
5495 if not opts.get('force') and bheads and p1 not in bheads:
5517 if not opts.get('force') and bheads and p1 not in bheads:
5496 raise util.Abort(_('not at a branch head (use -f to force)'))
5518 raise util.Abort(_('not at a branch head (use -f to force)'))
5497 r = scmutil.revsingle(repo, rev_).node()
5519 r = scmutil.revsingle(repo, rev_).node()
5498
5520
5499 if not message:
5521 if not message:
5500 # we don't translate commit messages
5522 # we don't translate commit messages
5501 message = ('Added tag %s for changeset %s' %
5523 message = ('Added tag %s for changeset %s' %
5502 (', '.join(names), short(r)))
5524 (', '.join(names), short(r)))
5503
5525
5504 date = opts.get('date')
5526 date = opts.get('date')
5505 if date:
5527 if date:
5506 date = util.parsedate(date)
5528 date = util.parsedate(date)
5507
5529
5508 if opts.get('edit'):
5530 if opts.get('edit'):
5509 message = ui.edit(message, ui.username())
5531 message = ui.edit(message, ui.username())
5510
5532
5511 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5533 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5512 finally:
5534 finally:
5513 release(lock, wlock)
5535 release(lock, wlock)
5514
5536
5515 @command('tags', [], '')
5537 @command('tags', [], '')
5516 def tags(ui, repo):
5538 def tags(ui, repo):
5517 """list repository tags
5539 """list repository tags
5518
5540
5519 This lists both regular and local tags. When the -v/--verbose
5541 This lists both regular and local tags. When the -v/--verbose
5520 switch is used, a third column "local" is printed for local tags.
5542 switch is used, a third column "local" is printed for local tags.
5521
5543
5522 Returns 0 on success.
5544 Returns 0 on success.
5523 """
5545 """
5524
5546
5525 hexfunc = ui.debugflag and hex or short
5547 hexfunc = ui.debugflag and hex or short
5526 tagtype = ""
5548 tagtype = ""
5527
5549
5528 for t, n in reversed(repo.tagslist()):
5550 for t, n in reversed(repo.tagslist()):
5529 if ui.quiet:
5551 if ui.quiet:
5530 ui.write("%s\n" % t, label='tags.normal')
5552 ui.write("%s\n" % t, label='tags.normal')
5531 continue
5553 continue
5532
5554
5533 hn = hexfunc(n)
5555 hn = hexfunc(n)
5534 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5556 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5535 rev = ui.label(r, 'log.changeset')
5557 rev = ui.label(r, 'log.changeset')
5536 spaces = " " * (30 - encoding.colwidth(t))
5558 spaces = " " * (30 - encoding.colwidth(t))
5537
5559
5538 tag = ui.label(t, 'tags.normal')
5560 tag = ui.label(t, 'tags.normal')
5539 if ui.verbose:
5561 if ui.verbose:
5540 if repo.tagtype(t) == 'local':
5562 if repo.tagtype(t) == 'local':
5541 tagtype = " local"
5563 tagtype = " local"
5542 tag = ui.label(t, 'tags.local')
5564 tag = ui.label(t, 'tags.local')
5543 else:
5565 else:
5544 tagtype = ""
5566 tagtype = ""
5545 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5567 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5546
5568
5547 @command('tip',
5569 @command('tip',
5548 [('p', 'patch', None, _('show patch')),
5570 [('p', 'patch', None, _('show patch')),
5549 ('g', 'git', None, _('use git extended diff format')),
5571 ('g', 'git', None, _('use git extended diff format')),
5550 ] + templateopts,
5572 ] + templateopts,
5551 _('[-p] [-g]'))
5573 _('[-p] [-g]'))
5552 def tip(ui, repo, **opts):
5574 def tip(ui, repo, **opts):
5553 """show the tip revision
5575 """show the tip revision
5554
5576
5555 The tip revision (usually just called the tip) is the changeset
5577 The tip revision (usually just called the tip) is the changeset
5556 most recently added to the repository (and therefore the most
5578 most recently added to the repository (and therefore the most
5557 recently changed head).
5579 recently changed head).
5558
5580
5559 If you have just made a commit, that commit will be the tip. If
5581 If you have just made a commit, that commit will be the tip. If
5560 you have just pulled changes from another repository, the tip of
5582 you have just pulled changes from another repository, the tip of
5561 that repository becomes the current tip. The "tip" tag is special
5583 that repository becomes the current tip. The "tip" tag is special
5562 and cannot be renamed or assigned to a different changeset.
5584 and cannot be renamed or assigned to a different changeset.
5563
5585
5564 Returns 0 on success.
5586 Returns 0 on success.
5565 """
5587 """
5566 displayer = cmdutil.show_changeset(ui, repo, opts)
5588 displayer = cmdutil.show_changeset(ui, repo, opts)
5567 displayer.show(repo[len(repo) - 1])
5589 displayer.show(repo[len(repo) - 1])
5568 displayer.close()
5590 displayer.close()
5569
5591
5570 @command('unbundle',
5592 @command('unbundle',
5571 [('u', 'update', None,
5593 [('u', 'update', None,
5572 _('update to new branch head if changesets were unbundled'))],
5594 _('update to new branch head if changesets were unbundled'))],
5573 _('[-u] FILE...'))
5595 _('[-u] FILE...'))
5574 def unbundle(ui, repo, fname1, *fnames, **opts):
5596 def unbundle(ui, repo, fname1, *fnames, **opts):
5575 """apply one or more changegroup files
5597 """apply one or more changegroup files
5576
5598
5577 Apply one or more compressed changegroup files generated by the
5599 Apply one or more compressed changegroup files generated by the
5578 bundle command.
5600 bundle command.
5579
5601
5580 Returns 0 on success, 1 if an update has unresolved files.
5602 Returns 0 on success, 1 if an update has unresolved files.
5581 """
5603 """
5582 fnames = (fname1,) + fnames
5604 fnames = (fname1,) + fnames
5583
5605
5584 lock = repo.lock()
5606 lock = repo.lock()
5585 wc = repo['.']
5607 wc = repo['.']
5586 try:
5608 try:
5587 for fname in fnames:
5609 for fname in fnames:
5588 f = url.open(ui, fname)
5610 f = url.open(ui, fname)
5589 gen = changegroup.readbundle(f, fname)
5611 gen = changegroup.readbundle(f, fname)
5590 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5612 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5591 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5613 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5592 finally:
5614 finally:
5593 lock.release()
5615 lock.release()
5594 return postincoming(ui, repo, modheads, opts.get('update'), None)
5616 return postincoming(ui, repo, modheads, opts.get('update'), None)
5595
5617
5596 @command('^update|up|checkout|co',
5618 @command('^update|up|checkout|co',
5597 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5619 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5598 ('c', 'check', None,
5620 ('c', 'check', None,
5599 _('update across branches if no uncommitted changes')),
5621 _('update across branches if no uncommitted changes')),
5600 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5622 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5601 ('r', 'rev', '', _('revision'), _('REV'))],
5623 ('r', 'rev', '', _('revision'), _('REV'))],
5602 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5624 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5603 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5625 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5604 """update working directory (or switch revisions)
5626 """update working directory (or switch revisions)
5605
5627
5606 Update the repository's working directory to the specified
5628 Update the repository's working directory to the specified
5607 changeset. If no changeset is specified, update to the tip of the
5629 changeset. If no changeset is specified, update to the tip of the
5608 current named branch and move the current bookmark (see :hg:`help
5630 current named branch and move the current bookmark (see :hg:`help
5609 bookmarks`).
5631 bookmarks`).
5610
5632
5611 If the changeset is not a descendant of the working directory's
5633 If the changeset is not a descendant of the working directory's
5612 parent, the update is aborted. With the -c/--check option, the
5634 parent, the update is aborted. With the -c/--check option, the
5613 working directory is checked for uncommitted changes; if none are
5635 working directory is checked for uncommitted changes; if none are
5614 found, the working directory is updated to the specified
5636 found, the working directory is updated to the specified
5615 changeset.
5637 changeset.
5616
5638
5617 Update sets the working directory's parent revison to the specified
5639 Update sets the working directory's parent revison to the specified
5618 changeset (see :hg:`help parents`).
5640 changeset (see :hg:`help parents`).
5619
5641
5620 The following rules apply when the working directory contains
5642 The following rules apply when the working directory contains
5621 uncommitted changes:
5643 uncommitted changes:
5622
5644
5623 1. If neither -c/--check nor -C/--clean is specified, and if
5645 1. If neither -c/--check nor -C/--clean is specified, and if
5624 the requested changeset is an ancestor or descendant of
5646 the requested changeset is an ancestor or descendant of
5625 the working directory's parent, the uncommitted changes
5647 the working directory's parent, the uncommitted changes
5626 are merged into the requested changeset and the merged
5648 are merged into the requested changeset and the merged
5627 result is left uncommitted. If the requested changeset is
5649 result is left uncommitted. If the requested changeset is
5628 not an ancestor or descendant (that is, it is on another
5650 not an ancestor or descendant (that is, it is on another
5629 branch), the update is aborted and the uncommitted changes
5651 branch), the update is aborted and the uncommitted changes
5630 are preserved.
5652 are preserved.
5631
5653
5632 2. With the -c/--check option, the update is aborted and the
5654 2. With the -c/--check option, the update is aborted and the
5633 uncommitted changes are preserved.
5655 uncommitted changes are preserved.
5634
5656
5635 3. With the -C/--clean option, uncommitted changes are discarded and
5657 3. With the -C/--clean option, uncommitted changes are discarded and
5636 the working directory is updated to the requested changeset.
5658 the working directory is updated to the requested changeset.
5637
5659
5638 Use null as the changeset to remove the working directory (like
5660 Use null as the changeset to remove the working directory (like
5639 :hg:`clone -U`).
5661 :hg:`clone -U`).
5640
5662
5641 If you want to revert just one file to an older revision, use
5663 If you want to revert just one file to an older revision, use
5642 :hg:`revert [-r REV] NAME`.
5664 :hg:`revert [-r REV] NAME`.
5643
5665
5644 See :hg:`help dates` for a list of formats valid for -d/--date.
5666 See :hg:`help dates` for a list of formats valid for -d/--date.
5645
5667
5646 Returns 0 on success, 1 if there are unresolved files.
5668 Returns 0 on success, 1 if there are unresolved files.
5647 """
5669 """
5648 if rev and node:
5670 if rev and node:
5649 raise util.Abort(_("please specify just one revision"))
5671 raise util.Abort(_("please specify just one revision"))
5650
5672
5651 if rev is None or rev == '':
5673 if rev is None or rev == '':
5652 rev = node
5674 rev = node
5653
5675
5654 # with no argument, we also move the current bookmark, if any
5676 # with no argument, we also move the current bookmark, if any
5655 movemarkfrom = None
5677 movemarkfrom = None
5656 if rev is None or node == '':
5678 if rev is None or node == '':
5657 movemarkfrom = repo['.'].node()
5679 movemarkfrom = repo['.'].node()
5658
5680
5659 # if we defined a bookmark, we have to remember the original bookmark name
5681 # if we defined a bookmark, we have to remember the original bookmark name
5660 brev = rev
5682 brev = rev
5661 rev = scmutil.revsingle(repo, rev, rev).rev()
5683 rev = scmutil.revsingle(repo, rev, rev).rev()
5662
5684
5663 if check and clean:
5685 if check and clean:
5664 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5686 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5665
5687
5666 if date:
5688 if date:
5667 if rev is not None:
5689 if rev is not None:
5668 raise util.Abort(_("you can't specify a revision and a date"))
5690 raise util.Abort(_("you can't specify a revision and a date"))
5669 rev = cmdutil.finddate(ui, repo, date)
5691 rev = cmdutil.finddate(ui, repo, date)
5670
5692
5671 if check:
5693 if check:
5672 c = repo[None]
5694 c = repo[None]
5673 if c.dirty(merge=False, branch=False):
5695 if c.dirty(merge=False, branch=False):
5674 raise util.Abort(_("uncommitted local changes"))
5696 raise util.Abort(_("uncommitted local changes"))
5675 if rev is None:
5697 if rev is None:
5676 rev = repo[repo[None].branch()].rev()
5698 rev = repo[repo[None].branch()].rev()
5677 mergemod._checkunknown(repo, repo[None], repo[rev])
5699 mergemod._checkunknown(repo, repo[None], repo[rev])
5678
5700
5679 if clean:
5701 if clean:
5680 ret = hg.clean(repo, rev)
5702 ret = hg.clean(repo, rev)
5681 else:
5703 else:
5682 ret = hg.update(repo, rev)
5704 ret = hg.update(repo, rev)
5683
5705
5684 if not ret and movemarkfrom:
5706 if not ret and movemarkfrom:
5685 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5707 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5686 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5708 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5687 elif brev in repo._bookmarks:
5709 elif brev in repo._bookmarks:
5688 bookmarks.setcurrent(repo, brev)
5710 bookmarks.setcurrent(repo, brev)
5689 elif brev:
5711 elif brev:
5690 bookmarks.unsetcurrent(repo)
5712 bookmarks.unsetcurrent(repo)
5691
5713
5692 return ret
5714 return ret
5693
5715
5694 @command('verify', [])
5716 @command('verify', [])
5695 def verify(ui, repo):
5717 def verify(ui, repo):
5696 """verify the integrity of the repository
5718 """verify the integrity of the repository
5697
5719
5698 Verify the integrity of the current repository.
5720 Verify the integrity of the current repository.
5699
5721
5700 This will perform an extensive check of the repository's
5722 This will perform an extensive check of the repository's
5701 integrity, validating the hashes and checksums of each entry in
5723 integrity, validating the hashes and checksums of each entry in
5702 the changelog, manifest, and tracked files, as well as the
5724 the changelog, manifest, and tracked files, as well as the
5703 integrity of their crosslinks and indices.
5725 integrity of their crosslinks and indices.
5704
5726
5705 Returns 0 on success, 1 if errors are encountered.
5727 Returns 0 on success, 1 if errors are encountered.
5706 """
5728 """
5707 return hg.verify(repo)
5729 return hg.verify(repo)
5708
5730
5709 @command('version', [])
5731 @command('version', [])
5710 def version_(ui):
5732 def version_(ui):
5711 """output version and copyright information"""
5733 """output version and copyright information"""
5712 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5734 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5713 % util.version())
5735 % util.version())
5714 ui.status(_(
5736 ui.status(_(
5715 "(see http://mercurial.selenic.com for more information)\n"
5737 "(see http://mercurial.selenic.com for more information)\n"
5716 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5738 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5717 "This is free software; see the source for copying conditions. "
5739 "This is free software; see the source for copying conditions. "
5718 "There is NO\nwarranty; "
5740 "There is NO\nwarranty; "
5719 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5741 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5720 ))
5742 ))
5721
5743
5722 norepo = ("clone init version help debugcommands debugcomplete"
5744 norepo = ("clone init version help debugcommands debugcomplete"
5723 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5745 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5724 " debugknown debuggetbundle debugbundle")
5746 " debugknown debuggetbundle debugbundle")
5725 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5747 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5726 " debugdata debugindex debugindexdot debugrevlog")
5748 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,257 +1,258 b''
1 # changelog bisection for mercurial
1 # changelog bisection for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall
3 # Copyright 2007 Matt Mackall
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
5 #
5 #
6 # Inspired by git bisect, extension skeleton taken from mq.py.
6 # Inspired by git bisect, extension skeleton taken from mq.py.
7 #
7 #
8 # This software may be used and distributed according to the terms of the
8 # This software may be used and distributed according to the terms of the
9 # GNU General Public License version 2 or any later version.
9 # GNU General Public License version 2 or any later version.
10
10
11 import os, error
11 import os, error
12 from i18n import _
12 from i18n import _
13 from node import short, hex
13 from node import short, hex
14 import util
14 import util
15
15
16 def bisect(changelog, state):
16 def bisect(changelog, state):
17 """find the next node (if any) for testing during a bisect search.
17 """find the next node (if any) for testing during a bisect search.
18 returns a (nodes, number, good) tuple.
18 returns a (nodes, number, good) tuple.
19
19
20 'nodes' is the final result of the bisect if 'number' is 0.
20 'nodes' is the final result of the bisect if 'number' is 0.
21 Otherwise 'number' indicates the remaining possible candidates for
21 Otherwise 'number' indicates the remaining possible candidates for
22 the search and 'nodes' contains the next bisect target.
22 the search and 'nodes' contains the next bisect target.
23 'good' is True if bisect is searching for a first good changeset, False
23 'good' is True if bisect is searching for a first good changeset, False
24 if searching for a first bad one.
24 if searching for a first bad one.
25 """
25 """
26
26
27 clparents = changelog.parentrevs
27 clparents = changelog.parentrevs
28 skip = set([changelog.rev(n) for n in state['skip']])
28 skip = set([changelog.rev(n) for n in state['skip']])
29
29
30 def buildancestors(bad, good):
30 def buildancestors(bad, good):
31 # only the earliest bad revision matters
31 # only the earliest bad revision matters
32 badrev = min([changelog.rev(n) for n in bad])
32 badrev = min([changelog.rev(n) for n in bad])
33 goodrevs = [changelog.rev(n) for n in good]
33 goodrevs = [changelog.rev(n) for n in good]
34 goodrev = min(goodrevs)
34 goodrev = min(goodrevs)
35 # build visit array
35 # build visit array
36 ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
36 ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
37
37
38 # set nodes descended from goodrevs
38 # set nodes descended from goodrevs
39 for rev in goodrevs:
39 for rev in goodrevs:
40 ancestors[rev] = []
40 ancestors[rev] = []
41 for rev in xrange(goodrev + 1, len(changelog)):
41 for rev in xrange(goodrev + 1, len(changelog)):
42 for prev in clparents(rev):
42 for prev in clparents(rev):
43 if ancestors[prev] == []:
43 if ancestors[prev] == []:
44 ancestors[rev] = []
44 ancestors[rev] = []
45
45
46 # clear good revs from array
46 # clear good revs from array
47 for rev in goodrevs:
47 for rev in goodrevs:
48 ancestors[rev] = None
48 ancestors[rev] = None
49 for rev in xrange(len(changelog), goodrev, -1):
49 for rev in xrange(len(changelog), goodrev, -1):
50 if ancestors[rev] is None:
50 if ancestors[rev] is None:
51 for prev in clparents(rev):
51 for prev in clparents(rev):
52 ancestors[prev] = None
52 ancestors[prev] = None
53
53
54 if ancestors[badrev] is None:
54 if ancestors[badrev] is None:
55 return badrev, None
55 return badrev, None
56 return badrev, ancestors
56 return badrev, ancestors
57
57
58 good = False
58 good = False
59 badrev, ancestors = buildancestors(state['bad'], state['good'])
59 badrev, ancestors = buildancestors(state['bad'], state['good'])
60 if not ancestors: # looking for bad to good transition?
60 if not ancestors: # looking for bad to good transition?
61 good = True
61 good = True
62 badrev, ancestors = buildancestors(state['good'], state['bad'])
62 badrev, ancestors = buildancestors(state['good'], state['bad'])
63 bad = changelog.node(badrev)
63 bad = changelog.node(badrev)
64 if not ancestors: # now we're confused
64 if not ancestors: # now we're confused
65 if len(state['bad']) == 1 and len(state['good']) == 1:
65 if len(state['bad']) == 1 and len(state['good']) == 1:
66 raise util.Abort(_("starting revisions are not directly related"))
66 raise util.Abort(_("starting revisions are not directly related"))
67 raise util.Abort(_("inconsistent state, %s:%s is good and bad")
67 raise util.Abort(_("inconsistent state, %s:%s is good and bad")
68 % (badrev, short(bad)))
68 % (badrev, short(bad)))
69
69
70 # build children dict
70 # build children dict
71 children = {}
71 children = {}
72 visit = [badrev]
72 visit = [badrev]
73 candidates = []
73 candidates = []
74 while visit:
74 while visit:
75 rev = visit.pop(0)
75 rev = visit.pop(0)
76 if ancestors[rev] == []:
76 if ancestors[rev] == []:
77 candidates.append(rev)
77 candidates.append(rev)
78 for prev in clparents(rev):
78 for prev in clparents(rev):
79 if prev != -1:
79 if prev != -1:
80 if prev in children:
80 if prev in children:
81 children[prev].append(rev)
81 children[prev].append(rev)
82 else:
82 else:
83 children[prev] = [rev]
83 children[prev] = [rev]
84 visit.append(prev)
84 visit.append(prev)
85
85
86 candidates.sort()
86 candidates.sort()
87 # have we narrowed it down to one entry?
87 # have we narrowed it down to one entry?
88 # or have all other possible candidates besides 'bad' have been skipped?
88 # or have all other possible candidates besides 'bad' have been skipped?
89 tot = len(candidates)
89 tot = len(candidates)
90 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
90 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
91 if tot == 1 or not unskipped:
91 if tot == 1 or not unskipped:
92 return ([changelog.node(rev) for rev in candidates], 0, good)
92 return ([changelog.node(rev) for rev in candidates], 0, good)
93 perfect = tot // 2
93 perfect = tot // 2
94
94
95 # find the best node to test
95 # find the best node to test
96 best_rev = None
96 best_rev = None
97 best_len = -1
97 best_len = -1
98 poison = set()
98 poison = set()
99 for rev in candidates:
99 for rev in candidates:
100 if rev in poison:
100 if rev in poison:
101 # poison children
101 # poison children
102 poison.update(children.get(rev, []))
102 poison.update(children.get(rev, []))
103 continue
103 continue
104
104
105 a = ancestors[rev] or [rev]
105 a = ancestors[rev] or [rev]
106 ancestors[rev] = None
106 ancestors[rev] = None
107
107
108 x = len(a) # number of ancestors
108 x = len(a) # number of ancestors
109 y = tot - x # number of non-ancestors
109 y = tot - x # number of non-ancestors
110 value = min(x, y) # how good is this test?
110 value = min(x, y) # how good is this test?
111 if value > best_len and rev not in skip:
111 if value > best_len and rev not in skip:
112 best_len = value
112 best_len = value
113 best_rev = rev
113 best_rev = rev
114 if value == perfect: # found a perfect candidate? quit early
114 if value == perfect: # found a perfect candidate? quit early
115 break
115 break
116
116
117 if y < perfect and rev not in skip: # all downhill from here?
117 if y < perfect and rev not in skip: # all downhill from here?
118 # poison children
118 # poison children
119 poison.update(children.get(rev, []))
119 poison.update(children.get(rev, []))
120 continue
120 continue
121
121
122 for c in children.get(rev, []):
122 for c in children.get(rev, []):
123 if ancestors[c]:
123 if ancestors[c]:
124 ancestors[c] = list(set(ancestors[c] + a))
124 ancestors[c] = list(set(ancestors[c] + a))
125 else:
125 else:
126 ancestors[c] = a + [c]
126 ancestors[c] = a + [c]
127
127
128 assert best_rev is not None
128 assert best_rev is not None
129 best_node = changelog.node(best_rev)
129 best_node = changelog.node(best_rev)
130
130
131 return ([best_node], tot, good)
131 return ([best_node], tot, good)
132
132
133
133
134 def load_state(repo):
134 def load_state(repo):
135 state = {'good': [], 'bad': [], 'skip': []}
135 state = {'current': [], 'good': [], 'bad': [], 'skip': []}
136 if os.path.exists(repo.join("bisect.state")):
136 if os.path.exists(repo.join("bisect.state")):
137 for l in repo.opener("bisect.state"):
137 for l in repo.opener("bisect.state"):
138 kind, node = l[:-1].split()
138 kind, node = l[:-1].split()
139 node = repo.lookup(node)
139 node = repo.lookup(node)
140 if kind not in state:
140 if kind not in state:
141 raise util.Abort(_("unknown bisect kind %s") % kind)
141 raise util.Abort(_("unknown bisect kind %s") % kind)
142 state[kind].append(node)
142 state[kind].append(node)
143 return state
143 return state
144
144
145
145
146 def save_state(repo, state):
146 def save_state(repo, state):
147 f = repo.opener("bisect.state", "w", atomictemp=True)
147 f = repo.opener("bisect.state", "w", atomictemp=True)
148 wlock = repo.wlock()
148 wlock = repo.wlock()
149 try:
149 try:
150 for kind in state:
150 for kind in state:
151 for node in state[kind]:
151 for node in state[kind]:
152 f.write("%s %s\n" % (kind, hex(node)))
152 f.write("%s %s\n" % (kind, hex(node)))
153 f.close()
153 f.close()
154 finally:
154 finally:
155 wlock.release()
155 wlock.release()
156
156
157 def get(repo, status):
157 def get(repo, status):
158 """
158 """
159 Return a list of revision(s) that match the given status:
159 Return a list of revision(s) that match the given status:
160
160
161 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
161 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
162 - ``goods``, ``bads`` : csets topologicaly good/bad
162 - ``goods``, ``bads`` : csets topologicaly good/bad
163 - ``range`` : csets taking part in the bisection
163 - ``range`` : csets taking part in the bisection
164 - ``pruned`` : csets that are goods, bads or skipped
164 - ``pruned`` : csets that are goods, bads or skipped
165 - ``untested`` : csets whose fate is yet unknown
165 - ``untested`` : csets whose fate is yet unknown
166 - ``ignored`` : csets ignored due to DAG topology
166 - ``ignored`` : csets ignored due to DAG topology
167 - ``current`` : the cset currently being bisected
167 """
168 """
168 state = load_state(repo)
169 state = load_state(repo)
169 if status in ('good', 'bad', 'skip'):
170 if status in ('good', 'bad', 'skip', 'current'):
170 return [repo.changelog.rev(n) for n in state[status]]
171 return map(repo.changelog.rev, state[status])
171 else:
172 else:
172 # In the floowing sets, we do *not* call 'bisect()' with more
173 # In the floowing sets, we do *not* call 'bisect()' with more
173 # than one level of recusrsion, because that can be very, very
174 # than one level of recusrsion, because that can be very, very
174 # time consuming. Instead, we always develop the expression as
175 # time consuming. Instead, we always develop the expression as
175 # much as possible.
176 # much as possible.
176
177
177 # 'range' is all csets that make the bisection:
178 # 'range' is all csets that make the bisection:
178 # - have a good ancestor and a bad descendant, or conversely
179 # - have a good ancestor and a bad descendant, or conversely
179 # that's because the bisection can go either way
180 # that's because the bisection can go either way
180 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
181 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
181
182
182 _t = repo.revs('bisect(good)::bisect(bad)')
183 _t = repo.revs('bisect(good)::bisect(bad)')
183 # The sets of topologically good or bad csets
184 # The sets of topologically good or bad csets
184 if len(_t) == 0:
185 if len(_t) == 0:
185 # Goods are topologically after bads
186 # Goods are topologically after bads
186 goods = 'bisect(good)::' # Pruned good csets
187 goods = 'bisect(good)::' # Pruned good csets
187 bads = '::bisect(bad)' # Pruned bad csets
188 bads = '::bisect(bad)' # Pruned bad csets
188 else:
189 else:
189 # Goods are topologically before bads
190 # Goods are topologically before bads
190 goods = '::bisect(good)' # Pruned good csets
191 goods = '::bisect(good)' # Pruned good csets
191 bads = 'bisect(bad)::' # Pruned bad csets
192 bads = 'bisect(bad)::' # Pruned bad csets
192
193
193 # 'pruned' is all csets whose fate is already known: good, bad, skip
194 # 'pruned' is all csets whose fate is already known: good, bad, skip
194 skips = 'bisect(skip)' # Pruned skipped csets
195 skips = 'bisect(skip)' # Pruned skipped csets
195 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips)
196 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips)
196
197
197 # 'untested' is all cset that are- in 'range', but not in 'pruned'
198 # 'untested' is all cset that are- in 'range', but not in 'pruned'
198 untested = '( (%s) - (%s) )' % (range, pruned)
199 untested = '( (%s) - (%s) )' % (range, pruned)
199
200
200 # 'ignored' is all csets that were not used during the bisection
201 # 'ignored' is all csets that were not used during the bisection
201 # due to DAG topology, but may however have had an impact.
202 # due to DAG topology, but may however have had an impact.
202 # Eg., a branch merged between bads and goods, but whose branch-
203 # Eg., a branch merged between bads and goods, but whose branch-
203 # point is out-side of the range.
204 # point is out-side of the range.
204 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors
205 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors
205 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors
206 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors
206 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range)
207 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range)
207
208
208 if status == 'range':
209 if status == 'range':
209 return repo.revs(range)
210 return repo.revs(range)
210 elif status == 'pruned':
211 elif status == 'pruned':
211 return repo.revs(pruned)
212 return repo.revs(pruned)
212 elif status == 'untested':
213 elif status == 'untested':
213 return repo.revs(untested)
214 return repo.revs(untested)
214 elif status == 'ignored':
215 elif status == 'ignored':
215 return repo.revs(ignored)
216 return repo.revs(ignored)
216 elif status == "goods":
217 elif status == "goods":
217 return repo.revs(goods)
218 return repo.revs(goods)
218 elif status == "bads":
219 elif status == "bads":
219 return repo.revs(bads)
220 return repo.revs(bads)
220 else:
221 else:
221 raise error.ParseError(_('invalid bisect state'))
222 raise error.ParseError(_('invalid bisect state'))
222
223
223 def label(repo, node):
224 def label(repo, node):
224 rev = repo.changelog.rev(node)
225 rev = repo.changelog.rev(node)
225
226
226 # Try explicit sets
227 # Try explicit sets
227 if rev in get(repo, 'good'):
228 if rev in get(repo, 'good'):
228 # i18n: bisect changeset status
229 # i18n: bisect changeset status
229 return _('good')
230 return _('good')
230 if rev in get(repo, 'bad'):
231 if rev in get(repo, 'bad'):
231 # i18n: bisect changeset status
232 # i18n: bisect changeset status
232 return _('bad')
233 return _('bad')
233 if rev in get(repo, 'skip'):
234 if rev in get(repo, 'skip'):
234 # i18n: bisect changeset status
235 # i18n: bisect changeset status
235 return _('skipped')
236 return _('skipped')
236 if rev in get(repo, 'untested'):
237 if rev in get(repo, 'untested') or rev in get(repo, 'current'):
237 # i18n: bisect changeset status
238 # i18n: bisect changeset status
238 return _('untested')
239 return _('untested')
239 if rev in get(repo, 'ignored'):
240 if rev in get(repo, 'ignored'):
240 # i18n: bisect changeset status
241 # i18n: bisect changeset status
241 return _('ignored')
242 return _('ignored')
242
243
243 # Try implicit sets
244 # Try implicit sets
244 if rev in get(repo, 'goods'):
245 if rev in get(repo, 'goods'):
245 # i18n: bisect changeset status
246 # i18n: bisect changeset status
246 return _('good (implicit)')
247 return _('good (implicit)')
247 if rev in get(repo, 'bads'):
248 if rev in get(repo, 'bads'):
248 # i18n: bisect changeset status
249 # i18n: bisect changeset status
249 return _('bad (implicit)')
250 return _('bad (implicit)')
250
251
251 return None
252 return None
252
253
253 def shortlabel(label):
254 def shortlabel(label):
254 if label:
255 if label:
255 return label[0].upper()
256 return label[0].upper()
256
257
257 return None
258 return None
@@ -1,1493 +1,1494 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery, hbisect, phases
9 import parser, util, error, discovery, hbisect, phases
10 import node
10 import node
11 import bookmarks as bookmarksmod
11 import bookmarks as bookmarksmod
12 import match as matchmod
12 import match as matchmod
13 from i18n import _
13 from i18n import _
14 import encoding
14 import encoding
15
15
16 def _revancestors(repo, revs, followfirst):
16 def _revancestors(repo, revs, followfirst):
17 """Like revlog.ancestors(), but supports followfirst."""
17 """Like revlog.ancestors(), but supports followfirst."""
18 cut = followfirst and 1 or None
18 cut = followfirst and 1 or None
19 cl = repo.changelog
19 cl = repo.changelog
20 visit = list(revs)
20 visit = list(revs)
21 seen = set([node.nullrev])
21 seen = set([node.nullrev])
22 while visit:
22 while visit:
23 for parent in cl.parentrevs(visit.pop(0))[:cut]:
23 for parent in cl.parentrevs(visit.pop(0))[:cut]:
24 if parent not in seen:
24 if parent not in seen:
25 visit.append(parent)
25 visit.append(parent)
26 seen.add(parent)
26 seen.add(parent)
27 yield parent
27 yield parent
28
28
29 def _revdescendants(repo, revs, followfirst):
29 def _revdescendants(repo, revs, followfirst):
30 """Like revlog.descendants() but supports followfirst."""
30 """Like revlog.descendants() but supports followfirst."""
31 cut = followfirst and 1 or None
31 cut = followfirst and 1 or None
32 cl = repo.changelog
32 cl = repo.changelog
33 first = min(revs)
33 first = min(revs)
34 nullrev = node.nullrev
34 nullrev = node.nullrev
35 if first == nullrev:
35 if first == nullrev:
36 # Are there nodes with a null first parent and a non-null
36 # Are there nodes with a null first parent and a non-null
37 # second one? Maybe. Do we care? Probably not.
37 # second one? Maybe. Do we care? Probably not.
38 for i in cl:
38 for i in cl:
39 yield i
39 yield i
40 return
40 return
41
41
42 seen = set(revs)
42 seen = set(revs)
43 for i in xrange(first + 1, len(cl)):
43 for i in xrange(first + 1, len(cl)):
44 for x in cl.parentrevs(i)[:cut]:
44 for x in cl.parentrevs(i)[:cut]:
45 if x != nullrev and x in seen:
45 if x != nullrev and x in seen:
46 seen.add(i)
46 seen.add(i)
47 yield i
47 yield i
48 break
48 break
49
49
50 elements = {
50 elements = {
51 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
51 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
52 "~": (18, None, ("ancestor", 18)),
52 "~": (18, None, ("ancestor", 18)),
53 "^": (18, None, ("parent", 18), ("parentpost", 18)),
53 "^": (18, None, ("parent", 18), ("parentpost", 18)),
54 "-": (5, ("negate", 19), ("minus", 5)),
54 "-": (5, ("negate", 19), ("minus", 5)),
55 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
55 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
56 ("dagrangepost", 17)),
56 ("dagrangepost", 17)),
57 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
57 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
58 ("dagrangepost", 17)),
58 ("dagrangepost", 17)),
59 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
59 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
60 "not": (10, ("not", 10)),
60 "not": (10, ("not", 10)),
61 "!": (10, ("not", 10)),
61 "!": (10, ("not", 10)),
62 "and": (5, None, ("and", 5)),
62 "and": (5, None, ("and", 5)),
63 "&": (5, None, ("and", 5)),
63 "&": (5, None, ("and", 5)),
64 "or": (4, None, ("or", 4)),
64 "or": (4, None, ("or", 4)),
65 "|": (4, None, ("or", 4)),
65 "|": (4, None, ("or", 4)),
66 "+": (4, None, ("or", 4)),
66 "+": (4, None, ("or", 4)),
67 ",": (2, None, ("list", 2)),
67 ",": (2, None, ("list", 2)),
68 ")": (0, None, None),
68 ")": (0, None, None),
69 "symbol": (0, ("symbol",), None),
69 "symbol": (0, ("symbol",), None),
70 "string": (0, ("string",), None),
70 "string": (0, ("string",), None),
71 "end": (0, None, None),
71 "end": (0, None, None),
72 }
72 }
73
73
74 keywords = set(['and', 'or', 'not'])
74 keywords = set(['and', 'or', 'not'])
75
75
76 def tokenize(program):
76 def tokenize(program):
77 pos, l = 0, len(program)
77 pos, l = 0, len(program)
78 while pos < l:
78 while pos < l:
79 c = program[pos]
79 c = program[pos]
80 if c.isspace(): # skip inter-token whitespace
80 if c.isspace(): # skip inter-token whitespace
81 pass
81 pass
82 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
82 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
83 yield ('::', None, pos)
83 yield ('::', None, pos)
84 pos += 1 # skip ahead
84 pos += 1 # skip ahead
85 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
85 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
86 yield ('..', None, pos)
86 yield ('..', None, pos)
87 pos += 1 # skip ahead
87 pos += 1 # skip ahead
88 elif c in "():,-|&+!~^": # handle simple operators
88 elif c in "():,-|&+!~^": # handle simple operators
89 yield (c, None, pos)
89 yield (c, None, pos)
90 elif (c in '"\'' or c == 'r' and
90 elif (c in '"\'' or c == 'r' and
91 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
91 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
92 if c == 'r':
92 if c == 'r':
93 pos += 1
93 pos += 1
94 c = program[pos]
94 c = program[pos]
95 decode = lambda x: x
95 decode = lambda x: x
96 else:
96 else:
97 decode = lambda x: x.decode('string-escape')
97 decode = lambda x: x.decode('string-escape')
98 pos += 1
98 pos += 1
99 s = pos
99 s = pos
100 while pos < l: # find closing quote
100 while pos < l: # find closing quote
101 d = program[pos]
101 d = program[pos]
102 if d == '\\': # skip over escaped characters
102 if d == '\\': # skip over escaped characters
103 pos += 2
103 pos += 2
104 continue
104 continue
105 if d == c:
105 if d == c:
106 yield ('string', decode(program[s:pos]), s)
106 yield ('string', decode(program[s:pos]), s)
107 break
107 break
108 pos += 1
108 pos += 1
109 else:
109 else:
110 raise error.ParseError(_("unterminated string"), s)
110 raise error.ParseError(_("unterminated string"), s)
111 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
111 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
112 s = pos
112 s = pos
113 pos += 1
113 pos += 1
114 while pos < l: # find end of symbol
114 while pos < l: # find end of symbol
115 d = program[pos]
115 d = program[pos]
116 if not (d.isalnum() or d in "._/" or ord(d) > 127):
116 if not (d.isalnum() or d in "._/" or ord(d) > 127):
117 break
117 break
118 if d == '.' and program[pos - 1] == '.': # special case for ..
118 if d == '.' and program[pos - 1] == '.': # special case for ..
119 pos -= 1
119 pos -= 1
120 break
120 break
121 pos += 1
121 pos += 1
122 sym = program[s:pos]
122 sym = program[s:pos]
123 if sym in keywords: # operator keywords
123 if sym in keywords: # operator keywords
124 yield (sym, None, s)
124 yield (sym, None, s)
125 else:
125 else:
126 yield ('symbol', sym, s)
126 yield ('symbol', sym, s)
127 pos -= 1
127 pos -= 1
128 else:
128 else:
129 raise error.ParseError(_("syntax error"), pos)
129 raise error.ParseError(_("syntax error"), pos)
130 pos += 1
130 pos += 1
131 yield ('end', None, pos)
131 yield ('end', None, pos)
132
132
133 # helpers
133 # helpers
134
134
135 def getstring(x, err):
135 def getstring(x, err):
136 if x and (x[0] == 'string' or x[0] == 'symbol'):
136 if x and (x[0] == 'string' or x[0] == 'symbol'):
137 return x[1]
137 return x[1]
138 raise error.ParseError(err)
138 raise error.ParseError(err)
139
139
140 def getlist(x):
140 def getlist(x):
141 if not x:
141 if not x:
142 return []
142 return []
143 if x[0] == 'list':
143 if x[0] == 'list':
144 return getlist(x[1]) + [x[2]]
144 return getlist(x[1]) + [x[2]]
145 return [x]
145 return [x]
146
146
147 def getargs(x, min, max, err):
147 def getargs(x, min, max, err):
148 l = getlist(x)
148 l = getlist(x)
149 if len(l) < min or (max >= 0 and len(l) > max):
149 if len(l) < min or (max >= 0 and len(l) > max):
150 raise error.ParseError(err)
150 raise error.ParseError(err)
151 return l
151 return l
152
152
153 def getset(repo, subset, x):
153 def getset(repo, subset, x):
154 if not x:
154 if not x:
155 raise error.ParseError(_("missing argument"))
155 raise error.ParseError(_("missing argument"))
156 return methods[x[0]](repo, subset, *x[1:])
156 return methods[x[0]](repo, subset, *x[1:])
157
157
158 # operator methods
158 # operator methods
159
159
160 def stringset(repo, subset, x):
160 def stringset(repo, subset, x):
161 x = repo[x].rev()
161 x = repo[x].rev()
162 if x == -1 and len(subset) == len(repo):
162 if x == -1 and len(subset) == len(repo):
163 return [-1]
163 return [-1]
164 if len(subset) == len(repo) or x in subset:
164 if len(subset) == len(repo) or x in subset:
165 return [x]
165 return [x]
166 return []
166 return []
167
167
168 def symbolset(repo, subset, x):
168 def symbolset(repo, subset, x):
169 if x in symbols:
169 if x in symbols:
170 raise error.ParseError(_("can't use %s here") % x)
170 raise error.ParseError(_("can't use %s here") % x)
171 return stringset(repo, subset, x)
171 return stringset(repo, subset, x)
172
172
173 def rangeset(repo, subset, x, y):
173 def rangeset(repo, subset, x, y):
174 m = getset(repo, subset, x)
174 m = getset(repo, subset, x)
175 if not m:
175 if not m:
176 m = getset(repo, range(len(repo)), x)
176 m = getset(repo, range(len(repo)), x)
177
177
178 n = getset(repo, subset, y)
178 n = getset(repo, subset, y)
179 if not n:
179 if not n:
180 n = getset(repo, range(len(repo)), y)
180 n = getset(repo, range(len(repo)), y)
181
181
182 if not m or not n:
182 if not m or not n:
183 return []
183 return []
184 m, n = m[0], n[-1]
184 m, n = m[0], n[-1]
185
185
186 if m < n:
186 if m < n:
187 r = range(m, n + 1)
187 r = range(m, n + 1)
188 else:
188 else:
189 r = range(m, n - 1, -1)
189 r = range(m, n - 1, -1)
190 s = set(subset)
190 s = set(subset)
191 return [x for x in r if x in s]
191 return [x for x in r if x in s]
192
192
193 def andset(repo, subset, x, y):
193 def andset(repo, subset, x, y):
194 return getset(repo, getset(repo, subset, x), y)
194 return getset(repo, getset(repo, subset, x), y)
195
195
196 def orset(repo, subset, x, y):
196 def orset(repo, subset, x, y):
197 xl = getset(repo, subset, x)
197 xl = getset(repo, subset, x)
198 s = set(xl)
198 s = set(xl)
199 yl = getset(repo, [r for r in subset if r not in s], y)
199 yl = getset(repo, [r for r in subset if r not in s], y)
200 return xl + yl
200 return xl + yl
201
201
202 def notset(repo, subset, x):
202 def notset(repo, subset, x):
203 s = set(getset(repo, subset, x))
203 s = set(getset(repo, subset, x))
204 return [r for r in subset if r not in s]
204 return [r for r in subset if r not in s]
205
205
206 def listset(repo, subset, a, b):
206 def listset(repo, subset, a, b):
207 raise error.ParseError(_("can't use a list in this context"))
207 raise error.ParseError(_("can't use a list in this context"))
208
208
209 def func(repo, subset, a, b):
209 def func(repo, subset, a, b):
210 if a[0] == 'symbol' and a[1] in symbols:
210 if a[0] == 'symbol' and a[1] in symbols:
211 return symbols[a[1]](repo, subset, b)
211 return symbols[a[1]](repo, subset, b)
212 raise error.ParseError(_("not a function: %s") % a[1])
212 raise error.ParseError(_("not a function: %s") % a[1])
213
213
214 # functions
214 # functions
215
215
216 def adds(repo, subset, x):
216 def adds(repo, subset, x):
217 """``adds(pattern)``
217 """``adds(pattern)``
218 Changesets that add a file matching pattern.
218 Changesets that add a file matching pattern.
219 """
219 """
220 # i18n: "adds" is a keyword
220 # i18n: "adds" is a keyword
221 pat = getstring(x, _("adds requires a pattern"))
221 pat = getstring(x, _("adds requires a pattern"))
222 return checkstatus(repo, subset, pat, 1)
222 return checkstatus(repo, subset, pat, 1)
223
223
224 def ancestor(repo, subset, x):
224 def ancestor(repo, subset, x):
225 """``ancestor(single, single)``
225 """``ancestor(single, single)``
226 Greatest common ancestor of the two changesets.
226 Greatest common ancestor of the two changesets.
227 """
227 """
228 # i18n: "ancestor" is a keyword
228 # i18n: "ancestor" is a keyword
229 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
229 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
230 r = range(len(repo))
230 r = range(len(repo))
231 a = getset(repo, r, l[0])
231 a = getset(repo, r, l[0])
232 b = getset(repo, r, l[1])
232 b = getset(repo, r, l[1])
233 if len(a) != 1 or len(b) != 1:
233 if len(a) != 1 or len(b) != 1:
234 # i18n: "ancestor" is a keyword
234 # i18n: "ancestor" is a keyword
235 raise error.ParseError(_("ancestor arguments must be single revisions"))
235 raise error.ParseError(_("ancestor arguments must be single revisions"))
236 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
236 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
237
237
238 return [r for r in an if r in subset]
238 return [r for r in an if r in subset]
239
239
240 def _ancestors(repo, subset, x, followfirst=False):
240 def _ancestors(repo, subset, x, followfirst=False):
241 args = getset(repo, range(len(repo)), x)
241 args = getset(repo, range(len(repo)), x)
242 if not args:
242 if not args:
243 return []
243 return []
244 s = set(_revancestors(repo, args, followfirst)) | set(args)
244 s = set(_revancestors(repo, args, followfirst)) | set(args)
245 return [r for r in subset if r in s]
245 return [r for r in subset if r in s]
246
246
247 def ancestors(repo, subset, x):
247 def ancestors(repo, subset, x):
248 """``ancestors(set)``
248 """``ancestors(set)``
249 Changesets that are ancestors of a changeset in set.
249 Changesets that are ancestors of a changeset in set.
250 """
250 """
251 return _ancestors(repo, subset, x)
251 return _ancestors(repo, subset, x)
252
252
253 def _firstancestors(repo, subset, x):
253 def _firstancestors(repo, subset, x):
254 # ``_firstancestors(set)``
254 # ``_firstancestors(set)``
255 # Like ``ancestors(set)`` but follows only the first parents.
255 # Like ``ancestors(set)`` but follows only the first parents.
256 return _ancestors(repo, subset, x, followfirst=True)
256 return _ancestors(repo, subset, x, followfirst=True)
257
257
258 def ancestorspec(repo, subset, x, n):
258 def ancestorspec(repo, subset, x, n):
259 """``set~n``
259 """``set~n``
260 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
260 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
261 """
261 """
262 try:
262 try:
263 n = int(n[1])
263 n = int(n[1])
264 except (TypeError, ValueError):
264 except (TypeError, ValueError):
265 raise error.ParseError(_("~ expects a number"))
265 raise error.ParseError(_("~ expects a number"))
266 ps = set()
266 ps = set()
267 cl = repo.changelog
267 cl = repo.changelog
268 for r in getset(repo, subset, x):
268 for r in getset(repo, subset, x):
269 for i in range(n):
269 for i in range(n):
270 r = cl.parentrevs(r)[0]
270 r = cl.parentrevs(r)[0]
271 ps.add(r)
271 ps.add(r)
272 return [r for r in subset if r in ps]
272 return [r for r in subset if r in ps]
273
273
274 def author(repo, subset, x):
274 def author(repo, subset, x):
275 """``author(string)``
275 """``author(string)``
276 Alias for ``user(string)``.
276 Alias for ``user(string)``.
277 """
277 """
278 # i18n: "author" is a keyword
278 # i18n: "author" is a keyword
279 n = encoding.lower(getstring(x, _("author requires a string")))
279 n = encoding.lower(getstring(x, _("author requires a string")))
280 return [r for r in subset if n in encoding.lower(repo[r].user())]
280 return [r for r in subset if n in encoding.lower(repo[r].user())]
281
281
282 def bisect(repo, subset, x):
282 def bisect(repo, subset, x):
283 """``bisect(string)``
283 """``bisect(string)``
284 Changesets marked in the specified bisect status:
284 Changesets marked in the specified bisect status:
285
285
286 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
286 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
287 - ``goods``, ``bads`` : csets topologicaly good/bad
287 - ``goods``, ``bads`` : csets topologicaly good/bad
288 - ``range`` : csets taking part in the bisection
288 - ``range`` : csets taking part in the bisection
289 - ``pruned`` : csets that are goods, bads or skipped
289 - ``pruned`` : csets that are goods, bads or skipped
290 - ``untested`` : csets whose fate is yet unknown
290 - ``untested`` : csets whose fate is yet unknown
291 - ``ignored`` : csets ignored due to DAG topology
291 - ``ignored`` : csets ignored due to DAG topology
292 - ``current`` : the cset currently being bisected
292 """
293 """
293 status = getstring(x, _("bisect requires a string")).lower()
294 status = getstring(x, _("bisect requires a string")).lower()
294 state = set(hbisect.get(repo, status))
295 state = set(hbisect.get(repo, status))
295 return [r for r in subset if r in state]
296 return [r for r in subset if r in state]
296
297
297 # Backward-compatibility
298 # Backward-compatibility
298 # - no help entry so that we do not advertise it any more
299 # - no help entry so that we do not advertise it any more
299 def bisected(repo, subset, x):
300 def bisected(repo, subset, x):
300 return bisect(repo, subset, x)
301 return bisect(repo, subset, x)
301
302
302 def bookmark(repo, subset, x):
303 def bookmark(repo, subset, x):
303 """``bookmark([name])``
304 """``bookmark([name])``
304 The named bookmark or all bookmarks.
305 The named bookmark or all bookmarks.
305 """
306 """
306 # i18n: "bookmark" is a keyword
307 # i18n: "bookmark" is a keyword
307 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
308 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
308 if args:
309 if args:
309 bm = getstring(args[0],
310 bm = getstring(args[0],
310 # i18n: "bookmark" is a keyword
311 # i18n: "bookmark" is a keyword
311 _('the argument to bookmark must be a string'))
312 _('the argument to bookmark must be a string'))
312 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
313 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
313 if not bmrev:
314 if not bmrev:
314 raise util.Abort(_("bookmark '%s' does not exist") % bm)
315 raise util.Abort(_("bookmark '%s' does not exist") % bm)
315 bmrev = repo[bmrev].rev()
316 bmrev = repo[bmrev].rev()
316 return [r for r in subset if r == bmrev]
317 return [r for r in subset if r == bmrev]
317 bms = set([repo[r].rev()
318 bms = set([repo[r].rev()
318 for r in bookmarksmod.listbookmarks(repo).values()])
319 for r in bookmarksmod.listbookmarks(repo).values()])
319 return [r for r in subset if r in bms]
320 return [r for r in subset if r in bms]
320
321
321 def branch(repo, subset, x):
322 def branch(repo, subset, x):
322 """``branch(string or set)``
323 """``branch(string or set)``
323 All changesets belonging to the given branch or the branches of the given
324 All changesets belonging to the given branch or the branches of the given
324 changesets.
325 changesets.
325 """
326 """
326 try:
327 try:
327 b = getstring(x, '')
328 b = getstring(x, '')
328 if b in repo.branchmap():
329 if b in repo.branchmap():
329 return [r for r in subset if repo[r].branch() == b]
330 return [r for r in subset if repo[r].branch() == b]
330 except error.ParseError:
331 except error.ParseError:
331 # not a string, but another revspec, e.g. tip()
332 # not a string, but another revspec, e.g. tip()
332 pass
333 pass
333
334
334 s = getset(repo, range(len(repo)), x)
335 s = getset(repo, range(len(repo)), x)
335 b = set()
336 b = set()
336 for r in s:
337 for r in s:
337 b.add(repo[r].branch())
338 b.add(repo[r].branch())
338 s = set(s)
339 s = set(s)
339 return [r for r in subset if r in s or repo[r].branch() in b]
340 return [r for r in subset if r in s or repo[r].branch() in b]
340
341
341 def checkstatus(repo, subset, pat, field):
342 def checkstatus(repo, subset, pat, field):
342 m = None
343 m = None
343 s = []
344 s = []
344 hasset = matchmod.patkind(pat) == 'set'
345 hasset = matchmod.patkind(pat) == 'set'
345 fname = None
346 fname = None
346 for r in subset:
347 for r in subset:
347 c = repo[r]
348 c = repo[r]
348 if not m or hasset:
349 if not m or hasset:
349 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
350 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
350 if not m.anypats() and len(m.files()) == 1:
351 if not m.anypats() and len(m.files()) == 1:
351 fname = m.files()[0]
352 fname = m.files()[0]
352 if fname is not None:
353 if fname is not None:
353 if fname not in c.files():
354 if fname not in c.files():
354 continue
355 continue
355 else:
356 else:
356 for f in c.files():
357 for f in c.files():
357 if m(f):
358 if m(f):
358 break
359 break
359 else:
360 else:
360 continue
361 continue
361 files = repo.status(c.p1().node(), c.node())[field]
362 files = repo.status(c.p1().node(), c.node())[field]
362 if fname is not None:
363 if fname is not None:
363 if fname in files:
364 if fname in files:
364 s.append(r)
365 s.append(r)
365 else:
366 else:
366 for f in files:
367 for f in files:
367 if m(f):
368 if m(f):
368 s.append(r)
369 s.append(r)
369 break
370 break
370 return s
371 return s
371
372
372 def _children(repo, narrow, parentset):
373 def _children(repo, narrow, parentset):
373 cs = set()
374 cs = set()
374 pr = repo.changelog.parentrevs
375 pr = repo.changelog.parentrevs
375 for r in narrow:
376 for r in narrow:
376 for p in pr(r):
377 for p in pr(r):
377 if p in parentset:
378 if p in parentset:
378 cs.add(r)
379 cs.add(r)
379 return cs
380 return cs
380
381
381 def children(repo, subset, x):
382 def children(repo, subset, x):
382 """``children(set)``
383 """``children(set)``
383 Child changesets of changesets in set.
384 Child changesets of changesets in set.
384 """
385 """
385 s = set(getset(repo, range(len(repo)), x))
386 s = set(getset(repo, range(len(repo)), x))
386 cs = _children(repo, subset, s)
387 cs = _children(repo, subset, s)
387 return [r for r in subset if r in cs]
388 return [r for r in subset if r in cs]
388
389
389 def closed(repo, subset, x):
390 def closed(repo, subset, x):
390 """``closed()``
391 """``closed()``
391 Changeset is closed.
392 Changeset is closed.
392 """
393 """
393 # i18n: "closed" is a keyword
394 # i18n: "closed" is a keyword
394 getargs(x, 0, 0, _("closed takes no arguments"))
395 getargs(x, 0, 0, _("closed takes no arguments"))
395 return [r for r in subset if repo[r].extra().get('close')]
396 return [r for r in subset if repo[r].extra().get('close')]
396
397
397 def contains(repo, subset, x):
398 def contains(repo, subset, x):
398 """``contains(pattern)``
399 """``contains(pattern)``
399 Revision contains a file matching pattern. See :hg:`help patterns`
400 Revision contains a file matching pattern. See :hg:`help patterns`
400 for information about file patterns.
401 for information about file patterns.
401 """
402 """
402 # i18n: "contains" is a keyword
403 # i18n: "contains" is a keyword
403 pat = getstring(x, _("contains requires a pattern"))
404 pat = getstring(x, _("contains requires a pattern"))
404 m = None
405 m = None
405 s = []
406 s = []
406 if not matchmod.patkind(pat):
407 if not matchmod.patkind(pat):
407 for r in subset:
408 for r in subset:
408 if pat in repo[r]:
409 if pat in repo[r]:
409 s.append(r)
410 s.append(r)
410 else:
411 else:
411 for r in subset:
412 for r in subset:
412 c = repo[r]
413 c = repo[r]
413 if not m or matchmod.patkind(pat) == 'set':
414 if not m or matchmod.patkind(pat) == 'set':
414 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
415 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
415 for f in c.manifest():
416 for f in c.manifest():
416 if m(f):
417 if m(f):
417 s.append(r)
418 s.append(r)
418 break
419 break
419 return s
420 return s
420
421
421 def date(repo, subset, x):
422 def date(repo, subset, x):
422 """``date(interval)``
423 """``date(interval)``
423 Changesets within the interval, see :hg:`help dates`.
424 Changesets within the interval, see :hg:`help dates`.
424 """
425 """
425 # i18n: "date" is a keyword
426 # i18n: "date" is a keyword
426 ds = getstring(x, _("date requires a string"))
427 ds = getstring(x, _("date requires a string"))
427 dm = util.matchdate(ds)
428 dm = util.matchdate(ds)
428 return [r for r in subset if dm(repo[r].date()[0])]
429 return [r for r in subset if dm(repo[r].date()[0])]
429
430
430 def desc(repo, subset, x):
431 def desc(repo, subset, x):
431 """``desc(string)``
432 """``desc(string)``
432 Search commit message for string. The match is case-insensitive.
433 Search commit message for string. The match is case-insensitive.
433 """
434 """
434 # i18n: "desc" is a keyword
435 # i18n: "desc" is a keyword
435 ds = encoding.lower(getstring(x, _("desc requires a string")))
436 ds = encoding.lower(getstring(x, _("desc requires a string")))
436 l = []
437 l = []
437 for r in subset:
438 for r in subset:
438 c = repo[r]
439 c = repo[r]
439 if ds in encoding.lower(c.description()):
440 if ds in encoding.lower(c.description()):
440 l.append(r)
441 l.append(r)
441 return l
442 return l
442
443
443 def _descendants(repo, subset, x, followfirst=False):
444 def _descendants(repo, subset, x, followfirst=False):
444 args = getset(repo, range(len(repo)), x)
445 args = getset(repo, range(len(repo)), x)
445 if not args:
446 if not args:
446 return []
447 return []
447 s = set(_revdescendants(repo, args, followfirst)) | set(args)
448 s = set(_revdescendants(repo, args, followfirst)) | set(args)
448 return [r for r in subset if r in s]
449 return [r for r in subset if r in s]
449
450
450 def descendants(repo, subset, x):
451 def descendants(repo, subset, x):
451 """``descendants(set)``
452 """``descendants(set)``
452 Changesets which are descendants of changesets in set.
453 Changesets which are descendants of changesets in set.
453 """
454 """
454 return _descendants(repo, subset, x)
455 return _descendants(repo, subset, x)
455
456
456 def _firstdescendants(repo, subset, x):
457 def _firstdescendants(repo, subset, x):
457 # ``_firstdescendants(set)``
458 # ``_firstdescendants(set)``
458 # Like ``descendants(set)`` but follows only the first parents.
459 # Like ``descendants(set)`` but follows only the first parents.
459 return _descendants(repo, subset, x, followfirst=True)
460 return _descendants(repo, subset, x, followfirst=True)
460
461
461 def draft(repo, subset, x):
462 def draft(repo, subset, x):
462 """``draft()``
463 """``draft()``
463 Changeset in draft phase."""
464 Changeset in draft phase."""
464 getargs(x, 0, 0, _("draft takes no arguments"))
465 getargs(x, 0, 0, _("draft takes no arguments"))
465 return [r for r in subset if repo._phaserev[r] == phases.draft]
466 return [r for r in subset if repo._phaserev[r] == phases.draft]
466
467
467 def filelog(repo, subset, x):
468 def filelog(repo, subset, x):
468 """``filelog(pattern)``
469 """``filelog(pattern)``
469 Changesets connected to the specified filelog.
470 Changesets connected to the specified filelog.
470 """
471 """
471
472
472 pat = getstring(x, _("filelog requires a pattern"))
473 pat = getstring(x, _("filelog requires a pattern"))
473 m = matchmod.match(repo.root, repo.getcwd(), [pat], default='relpath',
474 m = matchmod.match(repo.root, repo.getcwd(), [pat], default='relpath',
474 ctx=repo[None])
475 ctx=repo[None])
475 s = set()
476 s = set()
476
477
477 if not matchmod.patkind(pat):
478 if not matchmod.patkind(pat):
478 for f in m.files():
479 for f in m.files():
479 fl = repo.file(f)
480 fl = repo.file(f)
480 for fr in fl:
481 for fr in fl:
481 s.add(fl.linkrev(fr))
482 s.add(fl.linkrev(fr))
482 else:
483 else:
483 for f in repo[None]:
484 for f in repo[None]:
484 if m(f):
485 if m(f):
485 fl = repo.file(f)
486 fl = repo.file(f)
486 for fr in fl:
487 for fr in fl:
487 s.add(fl.linkrev(fr))
488 s.add(fl.linkrev(fr))
488
489
489 return [r for r in subset if r in s]
490 return [r for r in subset if r in s]
490
491
491 def first(repo, subset, x):
492 def first(repo, subset, x):
492 """``first(set, [n])``
493 """``first(set, [n])``
493 An alias for limit().
494 An alias for limit().
494 """
495 """
495 return limit(repo, subset, x)
496 return limit(repo, subset, x)
496
497
497 def _follow(repo, subset, x, name, followfirst=False):
498 def _follow(repo, subset, x, name, followfirst=False):
498 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
499 l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
499 c = repo['.']
500 c = repo['.']
500 if l:
501 if l:
501 x = getstring(l[0], _("%s expected a filename") % name)
502 x = getstring(l[0], _("%s expected a filename") % name)
502 if x in c:
503 if x in c:
503 cx = c[x]
504 cx = c[x]
504 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
505 s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
505 # include the revision responsible for the most recent version
506 # include the revision responsible for the most recent version
506 s.add(cx.linkrev())
507 s.add(cx.linkrev())
507 else:
508 else:
508 return []
509 return []
509 else:
510 else:
510 s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
511 s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
511
512
512 return [r for r in subset if r in s]
513 return [r for r in subset if r in s]
513
514
514 def follow(repo, subset, x):
515 def follow(repo, subset, x):
515 """``follow([file])``
516 """``follow([file])``
516 An alias for ``::.`` (ancestors of the working copy's first parent).
517 An alias for ``::.`` (ancestors of the working copy's first parent).
517 If a filename is specified, the history of the given file is followed,
518 If a filename is specified, the history of the given file is followed,
518 including copies.
519 including copies.
519 """
520 """
520 return _follow(repo, subset, x, 'follow')
521 return _follow(repo, subset, x, 'follow')
521
522
522 def _followfirst(repo, subset, x):
523 def _followfirst(repo, subset, x):
523 # ``followfirst([file])``
524 # ``followfirst([file])``
524 # Like ``follow([file])`` but follows only the first parent of
525 # Like ``follow([file])`` but follows only the first parent of
525 # every revision or file revision.
526 # every revision or file revision.
526 return _follow(repo, subset, x, '_followfirst', followfirst=True)
527 return _follow(repo, subset, x, '_followfirst', followfirst=True)
527
528
528 def getall(repo, subset, x):
529 def getall(repo, subset, x):
529 """``all()``
530 """``all()``
530 All changesets, the same as ``0:tip``.
531 All changesets, the same as ``0:tip``.
531 """
532 """
532 # i18n: "all" is a keyword
533 # i18n: "all" is a keyword
533 getargs(x, 0, 0, _("all takes no arguments"))
534 getargs(x, 0, 0, _("all takes no arguments"))
534 return subset
535 return subset
535
536
536 def grep(repo, subset, x):
537 def grep(repo, subset, x):
537 """``grep(regex)``
538 """``grep(regex)``
538 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
539 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
539 to ensure special escape characters are handled correctly. Unlike
540 to ensure special escape characters are handled correctly. Unlike
540 ``keyword(string)``, the match is case-sensitive.
541 ``keyword(string)``, the match is case-sensitive.
541 """
542 """
542 try:
543 try:
543 # i18n: "grep" is a keyword
544 # i18n: "grep" is a keyword
544 gr = re.compile(getstring(x, _("grep requires a string")))
545 gr = re.compile(getstring(x, _("grep requires a string")))
545 except re.error, e:
546 except re.error, e:
546 raise error.ParseError(_('invalid match pattern: %s') % e)
547 raise error.ParseError(_('invalid match pattern: %s') % e)
547 l = []
548 l = []
548 for r in subset:
549 for r in subset:
549 c = repo[r]
550 c = repo[r]
550 for e in c.files() + [c.user(), c.description()]:
551 for e in c.files() + [c.user(), c.description()]:
551 if gr.search(e):
552 if gr.search(e):
552 l.append(r)
553 l.append(r)
553 break
554 break
554 return l
555 return l
555
556
556 def _matchfiles(repo, subset, x):
557 def _matchfiles(repo, subset, x):
557 # _matchfiles takes a revset list of prefixed arguments:
558 # _matchfiles takes a revset list of prefixed arguments:
558 #
559 #
559 # [p:foo, i:bar, x:baz]
560 # [p:foo, i:bar, x:baz]
560 #
561 #
561 # builds a match object from them and filters subset. Allowed
562 # builds a match object from them and filters subset. Allowed
562 # prefixes are 'p:' for regular patterns, 'i:' for include
563 # prefixes are 'p:' for regular patterns, 'i:' for include
563 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
564 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
564 # a revision identifier, or the empty string to reference the
565 # a revision identifier, or the empty string to reference the
565 # working directory, from which the match object is
566 # working directory, from which the match object is
566 # initialized. Use 'd:' to set the default matching mode, default
567 # initialized. Use 'd:' to set the default matching mode, default
567 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
568 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
568
569
569 # i18n: "_matchfiles" is a keyword
570 # i18n: "_matchfiles" is a keyword
570 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
571 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
571 pats, inc, exc = [], [], []
572 pats, inc, exc = [], [], []
572 hasset = False
573 hasset = False
573 rev, default = None, None
574 rev, default = None, None
574 for arg in l:
575 for arg in l:
575 s = getstring(arg, _("_matchfiles requires string arguments"))
576 s = getstring(arg, _("_matchfiles requires string arguments"))
576 prefix, value = s[:2], s[2:]
577 prefix, value = s[:2], s[2:]
577 if prefix == 'p:':
578 if prefix == 'p:':
578 pats.append(value)
579 pats.append(value)
579 elif prefix == 'i:':
580 elif prefix == 'i:':
580 inc.append(value)
581 inc.append(value)
581 elif prefix == 'x:':
582 elif prefix == 'x:':
582 exc.append(value)
583 exc.append(value)
583 elif prefix == 'r:':
584 elif prefix == 'r:':
584 if rev is not None:
585 if rev is not None:
585 raise error.ParseError(_('_matchfiles expected at most one '
586 raise error.ParseError(_('_matchfiles expected at most one '
586 'revision'))
587 'revision'))
587 rev = value
588 rev = value
588 elif prefix == 'd:':
589 elif prefix == 'd:':
589 if default is not None:
590 if default is not None:
590 raise error.ParseError(_('_matchfiles expected at most one '
591 raise error.ParseError(_('_matchfiles expected at most one '
591 'default mode'))
592 'default mode'))
592 default = value
593 default = value
593 else:
594 else:
594 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
595 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
595 if not hasset and matchmod.patkind(value) == 'set':
596 if not hasset and matchmod.patkind(value) == 'set':
596 hasset = True
597 hasset = True
597 if not default:
598 if not default:
598 default = 'glob'
599 default = 'glob'
599 m = None
600 m = None
600 s = []
601 s = []
601 for r in subset:
602 for r in subset:
602 c = repo[r]
603 c = repo[r]
603 if not m or (hasset and rev is None):
604 if not m or (hasset and rev is None):
604 ctx = c
605 ctx = c
605 if rev is not None:
606 if rev is not None:
606 ctx = repo[rev or None]
607 ctx = repo[rev or None]
607 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
608 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
608 exclude=exc, ctx=ctx, default=default)
609 exclude=exc, ctx=ctx, default=default)
609 for f in c.files():
610 for f in c.files():
610 if m(f):
611 if m(f):
611 s.append(r)
612 s.append(r)
612 break
613 break
613 return s
614 return s
614
615
615 def hasfile(repo, subset, x):
616 def hasfile(repo, subset, x):
616 """``file(pattern)``
617 """``file(pattern)``
617 Changesets affecting files matched by pattern.
618 Changesets affecting files matched by pattern.
618 """
619 """
619 # i18n: "file" is a keyword
620 # i18n: "file" is a keyword
620 pat = getstring(x, _("file requires a pattern"))
621 pat = getstring(x, _("file requires a pattern"))
621 return _matchfiles(repo, subset, ('string', 'p:' + pat))
622 return _matchfiles(repo, subset, ('string', 'p:' + pat))
622
623
623 def head(repo, subset, x):
624 def head(repo, subset, x):
624 """``head()``
625 """``head()``
625 Changeset is a named branch head.
626 Changeset is a named branch head.
626 """
627 """
627 # i18n: "head" is a keyword
628 # i18n: "head" is a keyword
628 getargs(x, 0, 0, _("head takes no arguments"))
629 getargs(x, 0, 0, _("head takes no arguments"))
629 hs = set()
630 hs = set()
630 for b, ls in repo.branchmap().iteritems():
631 for b, ls in repo.branchmap().iteritems():
631 hs.update(repo[h].rev() for h in ls)
632 hs.update(repo[h].rev() for h in ls)
632 return [r for r in subset if r in hs]
633 return [r for r in subset if r in hs]
633
634
634 def heads(repo, subset, x):
635 def heads(repo, subset, x):
635 """``heads(set)``
636 """``heads(set)``
636 Members of set with no children in set.
637 Members of set with no children in set.
637 """
638 """
638 s = getset(repo, subset, x)
639 s = getset(repo, subset, x)
639 ps = set(parents(repo, subset, x))
640 ps = set(parents(repo, subset, x))
640 return [r for r in s if r not in ps]
641 return [r for r in s if r not in ps]
641
642
642 def keyword(repo, subset, x):
643 def keyword(repo, subset, x):
643 """``keyword(string)``
644 """``keyword(string)``
644 Search commit message, user name, and names of changed files for
645 Search commit message, user name, and names of changed files for
645 string. The match is case-insensitive.
646 string. The match is case-insensitive.
646 """
647 """
647 # i18n: "keyword" is a keyword
648 # i18n: "keyword" is a keyword
648 kw = encoding.lower(getstring(x, _("keyword requires a string")))
649 kw = encoding.lower(getstring(x, _("keyword requires a string")))
649 l = []
650 l = []
650 for r in subset:
651 for r in subset:
651 c = repo[r]
652 c = repo[r]
652 t = " ".join(c.files() + [c.user(), c.description()])
653 t = " ".join(c.files() + [c.user(), c.description()])
653 if kw in encoding.lower(t):
654 if kw in encoding.lower(t):
654 l.append(r)
655 l.append(r)
655 return l
656 return l
656
657
657 def limit(repo, subset, x):
658 def limit(repo, subset, x):
658 """``limit(set, [n])``
659 """``limit(set, [n])``
659 First n members of set, defaulting to 1.
660 First n members of set, defaulting to 1.
660 """
661 """
661 # i18n: "limit" is a keyword
662 # i18n: "limit" is a keyword
662 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
663 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
663 try:
664 try:
664 lim = 1
665 lim = 1
665 if len(l) == 2:
666 if len(l) == 2:
666 # i18n: "limit" is a keyword
667 # i18n: "limit" is a keyword
667 lim = int(getstring(l[1], _("limit requires a number")))
668 lim = int(getstring(l[1], _("limit requires a number")))
668 except (TypeError, ValueError):
669 except (TypeError, ValueError):
669 # i18n: "limit" is a keyword
670 # i18n: "limit" is a keyword
670 raise error.ParseError(_("limit expects a number"))
671 raise error.ParseError(_("limit expects a number"))
671 ss = set(subset)
672 ss = set(subset)
672 os = getset(repo, range(len(repo)), l[0])[:lim]
673 os = getset(repo, range(len(repo)), l[0])[:lim]
673 return [r for r in os if r in ss]
674 return [r for r in os if r in ss]
674
675
675 def last(repo, subset, x):
676 def last(repo, subset, x):
676 """``last(set, [n])``
677 """``last(set, [n])``
677 Last n members of set, defaulting to 1.
678 Last n members of set, defaulting to 1.
678 """
679 """
679 # i18n: "last" is a keyword
680 # i18n: "last" is a keyword
680 l = getargs(x, 1, 2, _("last requires one or two arguments"))
681 l = getargs(x, 1, 2, _("last requires one or two arguments"))
681 try:
682 try:
682 lim = 1
683 lim = 1
683 if len(l) == 2:
684 if len(l) == 2:
684 # i18n: "last" is a keyword
685 # i18n: "last" is a keyword
685 lim = int(getstring(l[1], _("last requires a number")))
686 lim = int(getstring(l[1], _("last requires a number")))
686 except (TypeError, ValueError):
687 except (TypeError, ValueError):
687 # i18n: "last" is a keyword
688 # i18n: "last" is a keyword
688 raise error.ParseError(_("last expects a number"))
689 raise error.ParseError(_("last expects a number"))
689 ss = set(subset)
690 ss = set(subset)
690 os = getset(repo, range(len(repo)), l[0])[-lim:]
691 os = getset(repo, range(len(repo)), l[0])[-lim:]
691 return [r for r in os if r in ss]
692 return [r for r in os if r in ss]
692
693
693 def maxrev(repo, subset, x):
694 def maxrev(repo, subset, x):
694 """``max(set)``
695 """``max(set)``
695 Changeset with highest revision number in set.
696 Changeset with highest revision number in set.
696 """
697 """
697 os = getset(repo, range(len(repo)), x)
698 os = getset(repo, range(len(repo)), x)
698 if os:
699 if os:
699 m = max(os)
700 m = max(os)
700 if m in subset:
701 if m in subset:
701 return [m]
702 return [m]
702 return []
703 return []
703
704
704 def merge(repo, subset, x):
705 def merge(repo, subset, x):
705 """``merge()``
706 """``merge()``
706 Changeset is a merge changeset.
707 Changeset is a merge changeset.
707 """
708 """
708 # i18n: "merge" is a keyword
709 # i18n: "merge" is a keyword
709 getargs(x, 0, 0, _("merge takes no arguments"))
710 getargs(x, 0, 0, _("merge takes no arguments"))
710 cl = repo.changelog
711 cl = repo.changelog
711 return [r for r in subset if cl.parentrevs(r)[1] != -1]
712 return [r for r in subset if cl.parentrevs(r)[1] != -1]
712
713
713 def minrev(repo, subset, x):
714 def minrev(repo, subset, x):
714 """``min(set)``
715 """``min(set)``
715 Changeset with lowest revision number in set.
716 Changeset with lowest revision number in set.
716 """
717 """
717 os = getset(repo, range(len(repo)), x)
718 os = getset(repo, range(len(repo)), x)
718 if os:
719 if os:
719 m = min(os)
720 m = min(os)
720 if m in subset:
721 if m in subset:
721 return [m]
722 return [m]
722 return []
723 return []
723
724
724 def modifies(repo, subset, x):
725 def modifies(repo, subset, x):
725 """``modifies(pattern)``
726 """``modifies(pattern)``
726 Changesets modifying files matched by pattern.
727 Changesets modifying files matched by pattern.
727 """
728 """
728 # i18n: "modifies" is a keyword
729 # i18n: "modifies" is a keyword
729 pat = getstring(x, _("modifies requires a pattern"))
730 pat = getstring(x, _("modifies requires a pattern"))
730 return checkstatus(repo, subset, pat, 0)
731 return checkstatus(repo, subset, pat, 0)
731
732
732 def node_(repo, subset, x):
733 def node_(repo, subset, x):
733 """``id(string)``
734 """``id(string)``
734 Revision non-ambiguously specified by the given hex string prefix.
735 Revision non-ambiguously specified by the given hex string prefix.
735 """
736 """
736 # i18n: "id" is a keyword
737 # i18n: "id" is a keyword
737 l = getargs(x, 1, 1, _("id requires one argument"))
738 l = getargs(x, 1, 1, _("id requires one argument"))
738 # i18n: "id" is a keyword
739 # i18n: "id" is a keyword
739 n = getstring(l[0], _("id requires a string"))
740 n = getstring(l[0], _("id requires a string"))
740 if len(n) == 40:
741 if len(n) == 40:
741 rn = repo[n].rev()
742 rn = repo[n].rev()
742 else:
743 else:
743 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
744 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
744 return [r for r in subset if r == rn]
745 return [r for r in subset if r == rn]
745
746
746 def outgoing(repo, subset, x):
747 def outgoing(repo, subset, x):
747 """``outgoing([path])``
748 """``outgoing([path])``
748 Changesets not found in the specified destination repository, or the
749 Changesets not found in the specified destination repository, or the
749 default push location.
750 default push location.
750 """
751 """
751 import hg # avoid start-up nasties
752 import hg # avoid start-up nasties
752 # i18n: "outgoing" is a keyword
753 # i18n: "outgoing" is a keyword
753 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
754 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
754 # i18n: "outgoing" is a keyword
755 # i18n: "outgoing" is a keyword
755 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
756 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
756 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
757 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
757 dest, branches = hg.parseurl(dest)
758 dest, branches = hg.parseurl(dest)
758 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
759 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
759 if revs:
760 if revs:
760 revs = [repo.lookup(rev) for rev in revs]
761 revs = [repo.lookup(rev) for rev in revs]
761 other = hg.peer(repo, {}, dest)
762 other = hg.peer(repo, {}, dest)
762 repo.ui.pushbuffer()
763 repo.ui.pushbuffer()
763 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
764 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
764 repo.ui.popbuffer()
765 repo.ui.popbuffer()
765 cl = repo.changelog
766 cl = repo.changelog
766 o = set([cl.rev(r) for r in outgoing.missing])
767 o = set([cl.rev(r) for r in outgoing.missing])
767 return [r for r in subset if r in o]
768 return [r for r in subset if r in o]
768
769
769 def p1(repo, subset, x):
770 def p1(repo, subset, x):
770 """``p1([set])``
771 """``p1([set])``
771 First parent of changesets in set, or the working directory.
772 First parent of changesets in set, or the working directory.
772 """
773 """
773 if x is None:
774 if x is None:
774 p = repo[x].p1().rev()
775 p = repo[x].p1().rev()
775 return [r for r in subset if r == p]
776 return [r for r in subset if r == p]
776
777
777 ps = set()
778 ps = set()
778 cl = repo.changelog
779 cl = repo.changelog
779 for r in getset(repo, range(len(repo)), x):
780 for r in getset(repo, range(len(repo)), x):
780 ps.add(cl.parentrevs(r)[0])
781 ps.add(cl.parentrevs(r)[0])
781 return [r for r in subset if r in ps]
782 return [r for r in subset if r in ps]
782
783
783 def p2(repo, subset, x):
784 def p2(repo, subset, x):
784 """``p2([set])``
785 """``p2([set])``
785 Second parent of changesets in set, or the working directory.
786 Second parent of changesets in set, or the working directory.
786 """
787 """
787 if x is None:
788 if x is None:
788 ps = repo[x].parents()
789 ps = repo[x].parents()
789 try:
790 try:
790 p = ps[1].rev()
791 p = ps[1].rev()
791 return [r for r in subset if r == p]
792 return [r for r in subset if r == p]
792 except IndexError:
793 except IndexError:
793 return []
794 return []
794
795
795 ps = set()
796 ps = set()
796 cl = repo.changelog
797 cl = repo.changelog
797 for r in getset(repo, range(len(repo)), x):
798 for r in getset(repo, range(len(repo)), x):
798 ps.add(cl.parentrevs(r)[1])
799 ps.add(cl.parentrevs(r)[1])
799 return [r for r in subset if r in ps]
800 return [r for r in subset if r in ps]
800
801
801 def parents(repo, subset, x):
802 def parents(repo, subset, x):
802 """``parents([set])``
803 """``parents([set])``
803 The set of all parents for all changesets in set, or the working directory.
804 The set of all parents for all changesets in set, or the working directory.
804 """
805 """
805 if x is None:
806 if x is None:
806 ps = tuple(p.rev() for p in repo[x].parents())
807 ps = tuple(p.rev() for p in repo[x].parents())
807 return [r for r in subset if r in ps]
808 return [r for r in subset if r in ps]
808
809
809 ps = set()
810 ps = set()
810 cl = repo.changelog
811 cl = repo.changelog
811 for r in getset(repo, range(len(repo)), x):
812 for r in getset(repo, range(len(repo)), x):
812 ps.update(cl.parentrevs(r))
813 ps.update(cl.parentrevs(r))
813 return [r for r in subset if r in ps]
814 return [r for r in subset if r in ps]
814
815
815 def parentspec(repo, subset, x, n):
816 def parentspec(repo, subset, x, n):
816 """``set^0``
817 """``set^0``
817 The set.
818 The set.
818 ``set^1`` (or ``set^``), ``set^2``
819 ``set^1`` (or ``set^``), ``set^2``
819 First or second parent, respectively, of all changesets in set.
820 First or second parent, respectively, of all changesets in set.
820 """
821 """
821 try:
822 try:
822 n = int(n[1])
823 n = int(n[1])
823 if n not in (0, 1, 2):
824 if n not in (0, 1, 2):
824 raise ValueError
825 raise ValueError
825 except (TypeError, ValueError):
826 except (TypeError, ValueError):
826 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
827 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
827 ps = set()
828 ps = set()
828 cl = repo.changelog
829 cl = repo.changelog
829 for r in getset(repo, subset, x):
830 for r in getset(repo, subset, x):
830 if n == 0:
831 if n == 0:
831 ps.add(r)
832 ps.add(r)
832 elif n == 1:
833 elif n == 1:
833 ps.add(cl.parentrevs(r)[0])
834 ps.add(cl.parentrevs(r)[0])
834 elif n == 2:
835 elif n == 2:
835 parents = cl.parentrevs(r)
836 parents = cl.parentrevs(r)
836 if len(parents) > 1:
837 if len(parents) > 1:
837 ps.add(parents[1])
838 ps.add(parents[1])
838 return [r for r in subset if r in ps]
839 return [r for r in subset if r in ps]
839
840
840 def present(repo, subset, x):
841 def present(repo, subset, x):
841 """``present(set)``
842 """``present(set)``
842 An empty set, if any revision in set isn't found; otherwise,
843 An empty set, if any revision in set isn't found; otherwise,
843 all revisions in set.
844 all revisions in set.
844 """
845 """
845 try:
846 try:
846 return getset(repo, subset, x)
847 return getset(repo, subset, x)
847 except error.RepoLookupError:
848 except error.RepoLookupError:
848 return []
849 return []
849
850
850 def public(repo, subset, x):
851 def public(repo, subset, x):
851 """``public()``
852 """``public()``
852 Changeset in public phase."""
853 Changeset in public phase."""
853 getargs(x, 0, 0, _("public takes no arguments"))
854 getargs(x, 0, 0, _("public takes no arguments"))
854 return [r for r in subset if repo._phaserev[r] == phases.public]
855 return [r for r in subset if repo._phaserev[r] == phases.public]
855
856
856 def remote(repo, subset, x):
857 def remote(repo, subset, x):
857 """``remote([id [,path]])``
858 """``remote([id [,path]])``
858 Local revision that corresponds to the given identifier in a
859 Local revision that corresponds to the given identifier in a
859 remote repository, if present. Here, the '.' identifier is a
860 remote repository, if present. Here, the '.' identifier is a
860 synonym for the current local branch.
861 synonym for the current local branch.
861 """
862 """
862
863
863 import hg # avoid start-up nasties
864 import hg # avoid start-up nasties
864 # i18n: "remote" is a keyword
865 # i18n: "remote" is a keyword
865 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
866 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
866
867
867 q = '.'
868 q = '.'
868 if len(l) > 0:
869 if len(l) > 0:
869 # i18n: "remote" is a keyword
870 # i18n: "remote" is a keyword
870 q = getstring(l[0], _("remote requires a string id"))
871 q = getstring(l[0], _("remote requires a string id"))
871 if q == '.':
872 if q == '.':
872 q = repo['.'].branch()
873 q = repo['.'].branch()
873
874
874 dest = ''
875 dest = ''
875 if len(l) > 1:
876 if len(l) > 1:
876 # i18n: "remote" is a keyword
877 # i18n: "remote" is a keyword
877 dest = getstring(l[1], _("remote requires a repository path"))
878 dest = getstring(l[1], _("remote requires a repository path"))
878 dest = repo.ui.expandpath(dest or 'default')
879 dest = repo.ui.expandpath(dest or 'default')
879 dest, branches = hg.parseurl(dest)
880 dest, branches = hg.parseurl(dest)
880 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
881 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
881 if revs:
882 if revs:
882 revs = [repo.lookup(rev) for rev in revs]
883 revs = [repo.lookup(rev) for rev in revs]
883 other = hg.peer(repo, {}, dest)
884 other = hg.peer(repo, {}, dest)
884 n = other.lookup(q)
885 n = other.lookup(q)
885 if n in repo:
886 if n in repo:
886 r = repo[n].rev()
887 r = repo[n].rev()
887 if r in subset:
888 if r in subset:
888 return [r]
889 return [r]
889 return []
890 return []
890
891
891 def removes(repo, subset, x):
892 def removes(repo, subset, x):
892 """``removes(pattern)``
893 """``removes(pattern)``
893 Changesets which remove files matching pattern.
894 Changesets which remove files matching pattern.
894 """
895 """
895 # i18n: "removes" is a keyword
896 # i18n: "removes" is a keyword
896 pat = getstring(x, _("removes requires a pattern"))
897 pat = getstring(x, _("removes requires a pattern"))
897 return checkstatus(repo, subset, pat, 2)
898 return checkstatus(repo, subset, pat, 2)
898
899
899 def rev(repo, subset, x):
900 def rev(repo, subset, x):
900 """``rev(number)``
901 """``rev(number)``
901 Revision with the given numeric identifier.
902 Revision with the given numeric identifier.
902 """
903 """
903 # i18n: "rev" is a keyword
904 # i18n: "rev" is a keyword
904 l = getargs(x, 1, 1, _("rev requires one argument"))
905 l = getargs(x, 1, 1, _("rev requires one argument"))
905 try:
906 try:
906 # i18n: "rev" is a keyword
907 # i18n: "rev" is a keyword
907 l = int(getstring(l[0], _("rev requires a number")))
908 l = int(getstring(l[0], _("rev requires a number")))
908 except (TypeError, ValueError):
909 except (TypeError, ValueError):
909 # i18n: "rev" is a keyword
910 # i18n: "rev" is a keyword
910 raise error.ParseError(_("rev expects a number"))
911 raise error.ParseError(_("rev expects a number"))
911 return [r for r in subset if r == l]
912 return [r for r in subset if r == l]
912
913
913 def matching(repo, subset, x):
914 def matching(repo, subset, x):
914 """``matching(revision [, field])``
915 """``matching(revision [, field])``
915 Changesets in which a given set of fields match the set of fields in the
916 Changesets in which a given set of fields match the set of fields in the
916 selected revision or set.
917 selected revision or set.
917
918
918 To match more than one field pass the list of fields to match separated
919 To match more than one field pass the list of fields to match separated
919 by spaces (e.g. ``author description``).
920 by spaces (e.g. ``author description``).
920
921
921 Valid fields are most regular revision fields and some special fields.
922 Valid fields are most regular revision fields and some special fields.
922
923
923 Regular revision fields are ``description``, ``author``, ``branch``,
924 Regular revision fields are ``description``, ``author``, ``branch``,
924 ``date``, ``files``, ``phase``, ``parents``, ``substate`` and ``user``.
925 ``date``, ``files``, ``phase``, ``parents``, ``substate`` and ``user``.
925 Note that ``author`` and ``user`` are synonyms.
926 Note that ``author`` and ``user`` are synonyms.
926
927
927 Special fields are ``summary`` and ``metadata``:
928 Special fields are ``summary`` and ``metadata``:
928 ``summary`` matches the first line of the description.
929 ``summary`` matches the first line of the description.
929 ``metadata`` is equivalent to matching ``description user date``
930 ``metadata`` is equivalent to matching ``description user date``
930 (i.e. it matches the main metadata fields).
931 (i.e. it matches the main metadata fields).
931
932
932 ``metadata`` is the default field which is used when no fields are
933 ``metadata`` is the default field which is used when no fields are
933 specified. You can match more than one field at a time.
934 specified. You can match more than one field at a time.
934 """
935 """
935 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
936 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
936
937
937 revs = getset(repo, xrange(len(repo)), l[0])
938 revs = getset(repo, xrange(len(repo)), l[0])
938
939
939 fieldlist = ['metadata']
940 fieldlist = ['metadata']
940 if len(l) > 1:
941 if len(l) > 1:
941 fieldlist = getstring(l[1],
942 fieldlist = getstring(l[1],
942 _("matching requires a string "
943 _("matching requires a string "
943 "as its second argument")).split()
944 "as its second argument")).split()
944
945
945 # Make sure that there are no repeated fields, and expand the
946 # Make sure that there are no repeated fields, and expand the
946 # 'special' 'metadata' field type
947 # 'special' 'metadata' field type
947 fields = []
948 fields = []
948 for field in fieldlist:
949 for field in fieldlist:
949 if field == 'metadata':
950 if field == 'metadata':
950 fields += ['user', 'description', 'date']
951 fields += ['user', 'description', 'date']
951 else:
952 else:
952 if field == 'author':
953 if field == 'author':
953 field = 'user'
954 field = 'user'
954 fields.append(field)
955 fields.append(field)
955 fields = set(fields)
956 fields = set(fields)
956 if 'summary' in fields and 'description' in fields:
957 if 'summary' in fields and 'description' in fields:
957 # If a revision matches its description it also matches its summary
958 # If a revision matches its description it also matches its summary
958 fields.discard('summary')
959 fields.discard('summary')
959
960
960 # We may want to match more than one field
961 # We may want to match more than one field
961 # Not all fields take the same amount of time to be matched
962 # Not all fields take the same amount of time to be matched
962 # Sort the selected fields in order of increasing matching cost
963 # Sort the selected fields in order of increasing matching cost
963 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
964 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
964 'files', 'description', 'substate']
965 'files', 'description', 'substate']
965 def fieldkeyfunc(f):
966 def fieldkeyfunc(f):
966 try:
967 try:
967 return fieldorder.index(f)
968 return fieldorder.index(f)
968 except ValueError:
969 except ValueError:
969 # assume an unknown field is very costly
970 # assume an unknown field is very costly
970 return len(fieldorder)
971 return len(fieldorder)
971 fields = list(fields)
972 fields = list(fields)
972 fields.sort(key=fieldkeyfunc)
973 fields.sort(key=fieldkeyfunc)
973
974
974 # Each field will be matched with its own "getfield" function
975 # Each field will be matched with its own "getfield" function
975 # which will be added to the getfieldfuncs array of functions
976 # which will be added to the getfieldfuncs array of functions
976 getfieldfuncs = []
977 getfieldfuncs = []
977 _funcs = {
978 _funcs = {
978 'user': lambda r: repo[r].user(),
979 'user': lambda r: repo[r].user(),
979 'branch': lambda r: repo[r].branch(),
980 'branch': lambda r: repo[r].branch(),
980 'date': lambda r: repo[r].date(),
981 'date': lambda r: repo[r].date(),
981 'description': lambda r: repo[r].description(),
982 'description': lambda r: repo[r].description(),
982 'files': lambda r: repo[r].files(),
983 'files': lambda r: repo[r].files(),
983 'parents': lambda r: repo[r].parents(),
984 'parents': lambda r: repo[r].parents(),
984 'phase': lambda r: repo[r].phase(),
985 'phase': lambda r: repo[r].phase(),
985 'substate': lambda r: repo[r].substate,
986 'substate': lambda r: repo[r].substate,
986 'summary': lambda r: repo[r].description().splitlines()[0],
987 'summary': lambda r: repo[r].description().splitlines()[0],
987 }
988 }
988 for info in fields:
989 for info in fields:
989 getfield = _funcs.get(info, None)
990 getfield = _funcs.get(info, None)
990 if getfield is None:
991 if getfield is None:
991 raise error.ParseError(
992 raise error.ParseError(
992 _("unexpected field name passed to matching: %s") % info)
993 _("unexpected field name passed to matching: %s") % info)
993 getfieldfuncs.append(getfield)
994 getfieldfuncs.append(getfield)
994 # convert the getfield array of functions into a "getinfo" function
995 # convert the getfield array of functions into a "getinfo" function
995 # which returns an array of field values (or a single value if there
996 # which returns an array of field values (or a single value if there
996 # is only one field to match)
997 # is only one field to match)
997 getinfo = lambda r: [f(r) for f in getfieldfuncs]
998 getinfo = lambda r: [f(r) for f in getfieldfuncs]
998
999
999 matches = set()
1000 matches = set()
1000 for rev in revs:
1001 for rev in revs:
1001 target = getinfo(rev)
1002 target = getinfo(rev)
1002 for r in subset:
1003 for r in subset:
1003 match = True
1004 match = True
1004 for n, f in enumerate(getfieldfuncs):
1005 for n, f in enumerate(getfieldfuncs):
1005 if target[n] != f(r):
1006 if target[n] != f(r):
1006 match = False
1007 match = False
1007 break
1008 break
1008 if match:
1009 if match:
1009 matches.add(r)
1010 matches.add(r)
1010 return [r for r in subset if r in matches]
1011 return [r for r in subset if r in matches]
1011
1012
1012 def reverse(repo, subset, x):
1013 def reverse(repo, subset, x):
1013 """``reverse(set)``
1014 """``reverse(set)``
1014 Reverse order of set.
1015 Reverse order of set.
1015 """
1016 """
1016 l = getset(repo, subset, x)
1017 l = getset(repo, subset, x)
1017 l.reverse()
1018 l.reverse()
1018 return l
1019 return l
1019
1020
1020 def roots(repo, subset, x):
1021 def roots(repo, subset, x):
1021 """``roots(set)``
1022 """``roots(set)``
1022 Changesets in set with no parent changeset in set.
1023 Changesets in set with no parent changeset in set.
1023 """
1024 """
1024 s = set(getset(repo, xrange(len(repo)), x))
1025 s = set(getset(repo, xrange(len(repo)), x))
1025 subset = [r for r in subset if r in s]
1026 subset = [r for r in subset if r in s]
1026 cs = _children(repo, subset, s)
1027 cs = _children(repo, subset, s)
1027 return [r for r in subset if r not in cs]
1028 return [r for r in subset if r not in cs]
1028
1029
1029 def secret(repo, subset, x):
1030 def secret(repo, subset, x):
1030 """``secret()``
1031 """``secret()``
1031 Changeset in secret phase."""
1032 Changeset in secret phase."""
1032 getargs(x, 0, 0, _("secret takes no arguments"))
1033 getargs(x, 0, 0, _("secret takes no arguments"))
1033 return [r for r in subset if repo._phaserev[r] == phases.secret]
1034 return [r for r in subset if repo._phaserev[r] == phases.secret]
1034
1035
1035 def sort(repo, subset, x):
1036 def sort(repo, subset, x):
1036 """``sort(set[, [-]key...])``
1037 """``sort(set[, [-]key...])``
1037 Sort set by keys. The default sort order is ascending, specify a key
1038 Sort set by keys. The default sort order is ascending, specify a key
1038 as ``-key`` to sort in descending order.
1039 as ``-key`` to sort in descending order.
1039
1040
1040 The keys can be:
1041 The keys can be:
1041
1042
1042 - ``rev`` for the revision number,
1043 - ``rev`` for the revision number,
1043 - ``branch`` for the branch name,
1044 - ``branch`` for the branch name,
1044 - ``desc`` for the commit message (description),
1045 - ``desc`` for the commit message (description),
1045 - ``user`` for user name (``author`` can be used as an alias),
1046 - ``user`` for user name (``author`` can be used as an alias),
1046 - ``date`` for the commit date
1047 - ``date`` for the commit date
1047 """
1048 """
1048 # i18n: "sort" is a keyword
1049 # i18n: "sort" is a keyword
1049 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1050 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
1050 keys = "rev"
1051 keys = "rev"
1051 if len(l) == 2:
1052 if len(l) == 2:
1052 keys = getstring(l[1], _("sort spec must be a string"))
1053 keys = getstring(l[1], _("sort spec must be a string"))
1053
1054
1054 s = l[0]
1055 s = l[0]
1055 keys = keys.split()
1056 keys = keys.split()
1056 l = []
1057 l = []
1057 def invert(s):
1058 def invert(s):
1058 return "".join(chr(255 - ord(c)) for c in s)
1059 return "".join(chr(255 - ord(c)) for c in s)
1059 for r in getset(repo, subset, s):
1060 for r in getset(repo, subset, s):
1060 c = repo[r]
1061 c = repo[r]
1061 e = []
1062 e = []
1062 for k in keys:
1063 for k in keys:
1063 if k == 'rev':
1064 if k == 'rev':
1064 e.append(r)
1065 e.append(r)
1065 elif k == '-rev':
1066 elif k == '-rev':
1066 e.append(-r)
1067 e.append(-r)
1067 elif k == 'branch':
1068 elif k == 'branch':
1068 e.append(c.branch())
1069 e.append(c.branch())
1069 elif k == '-branch':
1070 elif k == '-branch':
1070 e.append(invert(c.branch()))
1071 e.append(invert(c.branch()))
1071 elif k == 'desc':
1072 elif k == 'desc':
1072 e.append(c.description())
1073 e.append(c.description())
1073 elif k == '-desc':
1074 elif k == '-desc':
1074 e.append(invert(c.description()))
1075 e.append(invert(c.description()))
1075 elif k in 'user author':
1076 elif k in 'user author':
1076 e.append(c.user())
1077 e.append(c.user())
1077 elif k in '-user -author':
1078 elif k in '-user -author':
1078 e.append(invert(c.user()))
1079 e.append(invert(c.user()))
1079 elif k == 'date':
1080 elif k == 'date':
1080 e.append(c.date()[0])
1081 e.append(c.date()[0])
1081 elif k == '-date':
1082 elif k == '-date':
1082 e.append(-c.date()[0])
1083 e.append(-c.date()[0])
1083 else:
1084 else:
1084 raise error.ParseError(_("unknown sort key %r") % k)
1085 raise error.ParseError(_("unknown sort key %r") % k)
1085 e.append(r)
1086 e.append(r)
1086 l.append(e)
1087 l.append(e)
1087 l.sort()
1088 l.sort()
1088 return [e[-1] for e in l]
1089 return [e[-1] for e in l]
1089
1090
1090 def tag(repo, subset, x):
1091 def tag(repo, subset, x):
1091 """``tag([name])``
1092 """``tag([name])``
1092 The specified tag by name, or all tagged revisions if no name is given.
1093 The specified tag by name, or all tagged revisions if no name is given.
1093 """
1094 """
1094 # i18n: "tag" is a keyword
1095 # i18n: "tag" is a keyword
1095 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1096 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
1096 cl = repo.changelog
1097 cl = repo.changelog
1097 if args:
1098 if args:
1098 tn = getstring(args[0],
1099 tn = getstring(args[0],
1099 # i18n: "tag" is a keyword
1100 # i18n: "tag" is a keyword
1100 _('the argument to tag must be a string'))
1101 _('the argument to tag must be a string'))
1101 if not repo.tags().get(tn, None):
1102 if not repo.tags().get(tn, None):
1102 raise util.Abort(_("tag '%s' does not exist") % tn)
1103 raise util.Abort(_("tag '%s' does not exist") % tn)
1103 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
1104 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
1104 else:
1105 else:
1105 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1106 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
1106 return [r for r in subset if r in s]
1107 return [r for r in subset if r in s]
1107
1108
1108 def tagged(repo, subset, x):
1109 def tagged(repo, subset, x):
1109 return tag(repo, subset, x)
1110 return tag(repo, subset, x)
1110
1111
1111 def user(repo, subset, x):
1112 def user(repo, subset, x):
1112 """``user(string)``
1113 """``user(string)``
1113 User name contains string. The match is case-insensitive.
1114 User name contains string. The match is case-insensitive.
1114 """
1115 """
1115 return author(repo, subset, x)
1116 return author(repo, subset, x)
1116
1117
1117 # for internal use
1118 # for internal use
1118 def _list(repo, subset, x):
1119 def _list(repo, subset, x):
1119 s = getstring(x, "internal error")
1120 s = getstring(x, "internal error")
1120 if not s:
1121 if not s:
1121 return []
1122 return []
1122 if not isinstance(subset, set):
1123 if not isinstance(subset, set):
1123 subset = set(subset)
1124 subset = set(subset)
1124 ls = [repo[r].rev() for r in s.split('\0')]
1125 ls = [repo[r].rev() for r in s.split('\0')]
1125 return [r for r in ls if r in subset]
1126 return [r for r in ls if r in subset]
1126
1127
1127 symbols = {
1128 symbols = {
1128 "adds": adds,
1129 "adds": adds,
1129 "all": getall,
1130 "all": getall,
1130 "ancestor": ancestor,
1131 "ancestor": ancestor,
1131 "ancestors": ancestors,
1132 "ancestors": ancestors,
1132 "_firstancestors": _firstancestors,
1133 "_firstancestors": _firstancestors,
1133 "author": author,
1134 "author": author,
1134 "bisect": bisect,
1135 "bisect": bisect,
1135 "bisected": bisected,
1136 "bisected": bisected,
1136 "bookmark": bookmark,
1137 "bookmark": bookmark,
1137 "branch": branch,
1138 "branch": branch,
1138 "children": children,
1139 "children": children,
1139 "closed": closed,
1140 "closed": closed,
1140 "contains": contains,
1141 "contains": contains,
1141 "date": date,
1142 "date": date,
1142 "desc": desc,
1143 "desc": desc,
1143 "descendants": descendants,
1144 "descendants": descendants,
1144 "_firstdescendants": _firstdescendants,
1145 "_firstdescendants": _firstdescendants,
1145 "draft": draft,
1146 "draft": draft,
1146 "file": hasfile,
1147 "file": hasfile,
1147 "filelog": filelog,
1148 "filelog": filelog,
1148 "first": first,
1149 "first": first,
1149 "follow": follow,
1150 "follow": follow,
1150 "_followfirst": _followfirst,
1151 "_followfirst": _followfirst,
1151 "grep": grep,
1152 "grep": grep,
1152 "head": head,
1153 "head": head,
1153 "heads": heads,
1154 "heads": heads,
1154 "id": node_,
1155 "id": node_,
1155 "keyword": keyword,
1156 "keyword": keyword,
1156 "last": last,
1157 "last": last,
1157 "limit": limit,
1158 "limit": limit,
1158 "_matchfiles": _matchfiles,
1159 "_matchfiles": _matchfiles,
1159 "max": maxrev,
1160 "max": maxrev,
1160 "merge": merge,
1161 "merge": merge,
1161 "min": minrev,
1162 "min": minrev,
1162 "modifies": modifies,
1163 "modifies": modifies,
1163 "outgoing": outgoing,
1164 "outgoing": outgoing,
1164 "p1": p1,
1165 "p1": p1,
1165 "p2": p2,
1166 "p2": p2,
1166 "parents": parents,
1167 "parents": parents,
1167 "present": present,
1168 "present": present,
1168 "public": public,
1169 "public": public,
1169 "remote": remote,
1170 "remote": remote,
1170 "removes": removes,
1171 "removes": removes,
1171 "rev": rev,
1172 "rev": rev,
1172 "reverse": reverse,
1173 "reverse": reverse,
1173 "roots": roots,
1174 "roots": roots,
1174 "sort": sort,
1175 "sort": sort,
1175 "secret": secret,
1176 "secret": secret,
1176 "matching": matching,
1177 "matching": matching,
1177 "tag": tag,
1178 "tag": tag,
1178 "tagged": tagged,
1179 "tagged": tagged,
1179 "user": user,
1180 "user": user,
1180 "_list": _list,
1181 "_list": _list,
1181 }
1182 }
1182
1183
1183 methods = {
1184 methods = {
1184 "range": rangeset,
1185 "range": rangeset,
1185 "string": stringset,
1186 "string": stringset,
1186 "symbol": symbolset,
1187 "symbol": symbolset,
1187 "and": andset,
1188 "and": andset,
1188 "or": orset,
1189 "or": orset,
1189 "not": notset,
1190 "not": notset,
1190 "list": listset,
1191 "list": listset,
1191 "func": func,
1192 "func": func,
1192 "ancestor": ancestorspec,
1193 "ancestor": ancestorspec,
1193 "parent": parentspec,
1194 "parent": parentspec,
1194 "parentpost": p1,
1195 "parentpost": p1,
1195 }
1196 }
1196
1197
1197 def optimize(x, small):
1198 def optimize(x, small):
1198 if x is None:
1199 if x is None:
1199 return 0, x
1200 return 0, x
1200
1201
1201 smallbonus = 1
1202 smallbonus = 1
1202 if small:
1203 if small:
1203 smallbonus = .5
1204 smallbonus = .5
1204
1205
1205 op = x[0]
1206 op = x[0]
1206 if op == 'minus':
1207 if op == 'minus':
1207 return optimize(('and', x[1], ('not', x[2])), small)
1208 return optimize(('and', x[1], ('not', x[2])), small)
1208 elif op == 'dagrange':
1209 elif op == 'dagrange':
1209 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
1210 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
1210 ('func', ('symbol', 'ancestors'), x[2])), small)
1211 ('func', ('symbol', 'ancestors'), x[2])), small)
1211 elif op == 'dagrangepre':
1212 elif op == 'dagrangepre':
1212 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
1213 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
1213 elif op == 'dagrangepost':
1214 elif op == 'dagrangepost':
1214 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
1215 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
1215 elif op == 'rangepre':
1216 elif op == 'rangepre':
1216 return optimize(('range', ('string', '0'), x[1]), small)
1217 return optimize(('range', ('string', '0'), x[1]), small)
1217 elif op == 'rangepost':
1218 elif op == 'rangepost':
1218 return optimize(('range', x[1], ('string', 'tip')), small)
1219 return optimize(('range', x[1], ('string', 'tip')), small)
1219 elif op == 'negate':
1220 elif op == 'negate':
1220 return optimize(('string',
1221 return optimize(('string',
1221 '-' + getstring(x[1], _("can't negate that"))), small)
1222 '-' + getstring(x[1], _("can't negate that"))), small)
1222 elif op in 'string symbol negate':
1223 elif op in 'string symbol negate':
1223 return smallbonus, x # single revisions are small
1224 return smallbonus, x # single revisions are small
1224 elif op == 'and' or op == 'dagrange':
1225 elif op == 'and' or op == 'dagrange':
1225 wa, ta = optimize(x[1], True)
1226 wa, ta = optimize(x[1], True)
1226 wb, tb = optimize(x[2], True)
1227 wb, tb = optimize(x[2], True)
1227 w = min(wa, wb)
1228 w = min(wa, wb)
1228 if wa > wb:
1229 if wa > wb:
1229 return w, (op, tb, ta)
1230 return w, (op, tb, ta)
1230 return w, (op, ta, tb)
1231 return w, (op, ta, tb)
1231 elif op == 'or':
1232 elif op == 'or':
1232 wa, ta = optimize(x[1], False)
1233 wa, ta = optimize(x[1], False)
1233 wb, tb = optimize(x[2], False)
1234 wb, tb = optimize(x[2], False)
1234 if wb < wa:
1235 if wb < wa:
1235 wb, wa = wa, wb
1236 wb, wa = wa, wb
1236 return max(wa, wb), (op, ta, tb)
1237 return max(wa, wb), (op, ta, tb)
1237 elif op == 'not':
1238 elif op == 'not':
1238 o = optimize(x[1], not small)
1239 o = optimize(x[1], not small)
1239 return o[0], (op, o[1])
1240 return o[0], (op, o[1])
1240 elif op == 'parentpost':
1241 elif op == 'parentpost':
1241 o = optimize(x[1], small)
1242 o = optimize(x[1], small)
1242 return o[0], (op, o[1])
1243 return o[0], (op, o[1])
1243 elif op == 'group':
1244 elif op == 'group':
1244 return optimize(x[1], small)
1245 return optimize(x[1], small)
1245 elif op in 'range list parent ancestorspec':
1246 elif op in 'range list parent ancestorspec':
1246 if op == 'parent':
1247 if op == 'parent':
1247 # x^:y means (x^) : y, not x ^ (:y)
1248 # x^:y means (x^) : y, not x ^ (:y)
1248 post = ('parentpost', x[1])
1249 post = ('parentpost', x[1])
1249 if x[2][0] == 'dagrangepre':
1250 if x[2][0] == 'dagrangepre':
1250 return optimize(('dagrange', post, x[2][1]), small)
1251 return optimize(('dagrange', post, x[2][1]), small)
1251 elif x[2][0] == 'rangepre':
1252 elif x[2][0] == 'rangepre':
1252 return optimize(('range', post, x[2][1]), small)
1253 return optimize(('range', post, x[2][1]), small)
1253
1254
1254 wa, ta = optimize(x[1], small)
1255 wa, ta = optimize(x[1], small)
1255 wb, tb = optimize(x[2], small)
1256 wb, tb = optimize(x[2], small)
1256 return wa + wb, (op, ta, tb)
1257 return wa + wb, (op, ta, tb)
1257 elif op == 'func':
1258 elif op == 'func':
1258 f = getstring(x[1], _("not a symbol"))
1259 f = getstring(x[1], _("not a symbol"))
1259 wa, ta = optimize(x[2], small)
1260 wa, ta = optimize(x[2], small)
1260 if f in ("author branch closed date desc file grep keyword "
1261 if f in ("author branch closed date desc file grep keyword "
1261 "outgoing user"):
1262 "outgoing user"):
1262 w = 10 # slow
1263 w = 10 # slow
1263 elif f in "modifies adds removes":
1264 elif f in "modifies adds removes":
1264 w = 30 # slower
1265 w = 30 # slower
1265 elif f == "contains":
1266 elif f == "contains":
1266 w = 100 # very slow
1267 w = 100 # very slow
1267 elif f == "ancestor":
1268 elif f == "ancestor":
1268 w = 1 * smallbonus
1269 w = 1 * smallbonus
1269 elif f in "reverse limit first":
1270 elif f in "reverse limit first":
1270 w = 0
1271 w = 0
1271 elif f in "sort":
1272 elif f in "sort":
1272 w = 10 # assume most sorts look at changelog
1273 w = 10 # assume most sorts look at changelog
1273 else:
1274 else:
1274 w = 1
1275 w = 1
1275 return w + wa, (op, x[1], ta)
1276 return w + wa, (op, x[1], ta)
1276 return 1, x
1277 return 1, x
1277
1278
1278 class revsetalias(object):
1279 class revsetalias(object):
1279 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1280 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1280 args = None
1281 args = None
1281
1282
1282 def __init__(self, name, value):
1283 def __init__(self, name, value):
1283 '''Aliases like:
1284 '''Aliases like:
1284
1285
1285 h = heads(default)
1286 h = heads(default)
1286 b($1) = ancestors($1) - ancestors(default)
1287 b($1) = ancestors($1) - ancestors(default)
1287 '''
1288 '''
1288 m = self.funcre.search(name)
1289 m = self.funcre.search(name)
1289 if m:
1290 if m:
1290 self.name = m.group(1)
1291 self.name = m.group(1)
1291 self.tree = ('func', ('symbol', m.group(1)))
1292 self.tree = ('func', ('symbol', m.group(1)))
1292 self.args = [x.strip() for x in m.group(2).split(',')]
1293 self.args = [x.strip() for x in m.group(2).split(',')]
1293 for arg in self.args:
1294 for arg in self.args:
1294 value = value.replace(arg, repr(arg))
1295 value = value.replace(arg, repr(arg))
1295 else:
1296 else:
1296 self.name = name
1297 self.name = name
1297 self.tree = ('symbol', name)
1298 self.tree = ('symbol', name)
1298
1299
1299 self.replacement, pos = parse(value)
1300 self.replacement, pos = parse(value)
1300 if pos != len(value):
1301 if pos != len(value):
1301 raise error.ParseError(_('invalid token'), pos)
1302 raise error.ParseError(_('invalid token'), pos)
1302
1303
1303 def _getalias(aliases, tree):
1304 def _getalias(aliases, tree):
1304 """If tree looks like an unexpanded alias, return it. Return None
1305 """If tree looks like an unexpanded alias, return it. Return None
1305 otherwise.
1306 otherwise.
1306 """
1307 """
1307 if isinstance(tree, tuple) and tree:
1308 if isinstance(tree, tuple) and tree:
1308 if tree[0] == 'symbol' and len(tree) == 2:
1309 if tree[0] == 'symbol' and len(tree) == 2:
1309 name = tree[1]
1310 name = tree[1]
1310 alias = aliases.get(name)
1311 alias = aliases.get(name)
1311 if alias and alias.args is None and alias.tree == tree:
1312 if alias and alias.args is None and alias.tree == tree:
1312 return alias
1313 return alias
1313 if tree[0] == 'func' and len(tree) > 1:
1314 if tree[0] == 'func' and len(tree) > 1:
1314 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
1315 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
1315 name = tree[1][1]
1316 name = tree[1][1]
1316 alias = aliases.get(name)
1317 alias = aliases.get(name)
1317 if alias and alias.args is not None and alias.tree == tree[:2]:
1318 if alias and alias.args is not None and alias.tree == tree[:2]:
1318 return alias
1319 return alias
1319 return None
1320 return None
1320
1321
1321 def _expandargs(tree, args):
1322 def _expandargs(tree, args):
1322 """Replace all occurences of ('string', name) with the
1323 """Replace all occurences of ('string', name) with the
1323 substitution value of the same name in args, recursively.
1324 substitution value of the same name in args, recursively.
1324 """
1325 """
1325 if not isinstance(tree, tuple):
1326 if not isinstance(tree, tuple):
1326 return tree
1327 return tree
1327 if len(tree) == 2 and tree[0] == 'string':
1328 if len(tree) == 2 and tree[0] == 'string':
1328 return args.get(tree[1], tree)
1329 return args.get(tree[1], tree)
1329 return tuple(_expandargs(t, args) for t in tree)
1330 return tuple(_expandargs(t, args) for t in tree)
1330
1331
1331 def _expandaliases(aliases, tree, expanding):
1332 def _expandaliases(aliases, tree, expanding):
1332 """Expand aliases in tree, recursively.
1333 """Expand aliases in tree, recursively.
1333
1334
1334 'aliases' is a dictionary mapping user defined aliases to
1335 'aliases' is a dictionary mapping user defined aliases to
1335 revsetalias objects.
1336 revsetalias objects.
1336 """
1337 """
1337 if not isinstance(tree, tuple):
1338 if not isinstance(tree, tuple):
1338 # Do not expand raw strings
1339 # Do not expand raw strings
1339 return tree
1340 return tree
1340 alias = _getalias(aliases, tree)
1341 alias = _getalias(aliases, tree)
1341 if alias is not None:
1342 if alias is not None:
1342 if alias in expanding:
1343 if alias in expanding:
1343 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1344 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1344 'detected') % alias.name)
1345 'detected') % alias.name)
1345 expanding.append(alias)
1346 expanding.append(alias)
1346 result = alias.replacement
1347 result = alias.replacement
1347 if alias.args is not None:
1348 if alias.args is not None:
1348 l = getlist(tree[2])
1349 l = getlist(tree[2])
1349 if len(l) != len(alias.args):
1350 if len(l) != len(alias.args):
1350 raise error.ParseError(
1351 raise error.ParseError(
1351 _('invalid number of arguments: %s') % len(l))
1352 _('invalid number of arguments: %s') % len(l))
1352 result = _expandargs(result, dict(zip(alias.args, l)))
1353 result = _expandargs(result, dict(zip(alias.args, l)))
1353 # Recurse in place, the base expression may have been rewritten
1354 # Recurse in place, the base expression may have been rewritten
1354 result = _expandaliases(aliases, result, expanding)
1355 result = _expandaliases(aliases, result, expanding)
1355 expanding.pop()
1356 expanding.pop()
1356 else:
1357 else:
1357 result = tuple(_expandaliases(aliases, t, expanding)
1358 result = tuple(_expandaliases(aliases, t, expanding)
1358 for t in tree)
1359 for t in tree)
1359 return result
1360 return result
1360
1361
1361 def findaliases(ui, tree):
1362 def findaliases(ui, tree):
1362 aliases = {}
1363 aliases = {}
1363 for k, v in ui.configitems('revsetalias'):
1364 for k, v in ui.configitems('revsetalias'):
1364 alias = revsetalias(k, v)
1365 alias = revsetalias(k, v)
1365 aliases[alias.name] = alias
1366 aliases[alias.name] = alias
1366 return _expandaliases(aliases, tree, [])
1367 return _expandaliases(aliases, tree, [])
1367
1368
1368 parse = parser.parser(tokenize, elements).parse
1369 parse = parser.parser(tokenize, elements).parse
1369
1370
1370 def match(ui, spec):
1371 def match(ui, spec):
1371 if not spec:
1372 if not spec:
1372 raise error.ParseError(_("empty query"))
1373 raise error.ParseError(_("empty query"))
1373 tree, pos = parse(spec)
1374 tree, pos = parse(spec)
1374 if (pos != len(spec)):
1375 if (pos != len(spec)):
1375 raise error.ParseError(_("invalid token"), pos)
1376 raise error.ParseError(_("invalid token"), pos)
1376 if ui:
1377 if ui:
1377 tree = findaliases(ui, tree)
1378 tree = findaliases(ui, tree)
1378 weight, tree = optimize(tree, True)
1379 weight, tree = optimize(tree, True)
1379 def mfunc(repo, subset):
1380 def mfunc(repo, subset):
1380 return getset(repo, subset, tree)
1381 return getset(repo, subset, tree)
1381 return mfunc
1382 return mfunc
1382
1383
1383 def formatspec(expr, *args):
1384 def formatspec(expr, *args):
1384 '''
1385 '''
1385 This is a convenience function for using revsets internally, and
1386 This is a convenience function for using revsets internally, and
1386 escapes arguments appropriately. Aliases are intentionally ignored
1387 escapes arguments appropriately. Aliases are intentionally ignored
1387 so that intended expression behavior isn't accidentally subverted.
1388 so that intended expression behavior isn't accidentally subverted.
1388
1389
1389 Supported arguments:
1390 Supported arguments:
1390
1391
1391 %r = revset expression, parenthesized
1392 %r = revset expression, parenthesized
1392 %d = int(arg), no quoting
1393 %d = int(arg), no quoting
1393 %s = string(arg), escaped and single-quoted
1394 %s = string(arg), escaped and single-quoted
1394 %b = arg.branch(), escaped and single-quoted
1395 %b = arg.branch(), escaped and single-quoted
1395 %n = hex(arg), single-quoted
1396 %n = hex(arg), single-quoted
1396 %% = a literal '%'
1397 %% = a literal '%'
1397
1398
1398 Prefixing the type with 'l' specifies a parenthesized list of that type.
1399 Prefixing the type with 'l' specifies a parenthesized list of that type.
1399
1400
1400 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
1401 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
1401 '(10 or 11):: and ((this()) or (that()))'
1402 '(10 or 11):: and ((this()) or (that()))'
1402 >>> formatspec('%d:: and not %d::', 10, 20)
1403 >>> formatspec('%d:: and not %d::', 10, 20)
1403 '10:: and not 20::'
1404 '10:: and not 20::'
1404 >>> formatspec('%ld or %ld', [], [1])
1405 >>> formatspec('%ld or %ld', [], [1])
1405 "_list('') or 1"
1406 "_list('') or 1"
1406 >>> formatspec('keyword(%s)', 'foo\\xe9')
1407 >>> formatspec('keyword(%s)', 'foo\\xe9')
1407 "keyword('foo\\\\xe9')"
1408 "keyword('foo\\\\xe9')"
1408 >>> b = lambda: 'default'
1409 >>> b = lambda: 'default'
1409 >>> b.branch = b
1410 >>> b.branch = b
1410 >>> formatspec('branch(%b)', b)
1411 >>> formatspec('branch(%b)', b)
1411 "branch('default')"
1412 "branch('default')"
1412 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
1413 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
1413 "root(_list('a\\x00b\\x00c\\x00d'))"
1414 "root(_list('a\\x00b\\x00c\\x00d'))"
1414 '''
1415 '''
1415
1416
1416 def quote(s):
1417 def quote(s):
1417 return repr(str(s))
1418 return repr(str(s))
1418
1419
1419 def argtype(c, arg):
1420 def argtype(c, arg):
1420 if c == 'd':
1421 if c == 'd':
1421 return str(int(arg))
1422 return str(int(arg))
1422 elif c == 's':
1423 elif c == 's':
1423 return quote(arg)
1424 return quote(arg)
1424 elif c == 'r':
1425 elif c == 'r':
1425 parse(arg) # make sure syntax errors are confined
1426 parse(arg) # make sure syntax errors are confined
1426 return '(%s)' % arg
1427 return '(%s)' % arg
1427 elif c == 'n':
1428 elif c == 'n':
1428 return quote(node.hex(arg))
1429 return quote(node.hex(arg))
1429 elif c == 'b':
1430 elif c == 'b':
1430 return quote(arg.branch())
1431 return quote(arg.branch())
1431
1432
1432 def listexp(s, t):
1433 def listexp(s, t):
1433 l = len(s)
1434 l = len(s)
1434 if l == 0:
1435 if l == 0:
1435 return "_list('')"
1436 return "_list('')"
1436 elif l == 1:
1437 elif l == 1:
1437 return argtype(t, s[0])
1438 return argtype(t, s[0])
1438 elif t == 'd':
1439 elif t == 'd':
1439 return "_list('%s')" % "\0".join(str(int(a)) for a in s)
1440 return "_list('%s')" % "\0".join(str(int(a)) for a in s)
1440 elif t == 's':
1441 elif t == 's':
1441 return "_list('%s')" % "\0".join(s)
1442 return "_list('%s')" % "\0".join(s)
1442 elif t == 'n':
1443 elif t == 'n':
1443 return "_list('%s')" % "\0".join(node.hex(a) for a in s)
1444 return "_list('%s')" % "\0".join(node.hex(a) for a in s)
1444 elif t == 'b':
1445 elif t == 'b':
1445 return "_list('%s')" % "\0".join(a.branch() for a in s)
1446 return "_list('%s')" % "\0".join(a.branch() for a in s)
1446
1447
1447 m = l // 2
1448 m = l // 2
1448 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
1449 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
1449
1450
1450 ret = ''
1451 ret = ''
1451 pos = 0
1452 pos = 0
1452 arg = 0
1453 arg = 0
1453 while pos < len(expr):
1454 while pos < len(expr):
1454 c = expr[pos]
1455 c = expr[pos]
1455 if c == '%':
1456 if c == '%':
1456 pos += 1
1457 pos += 1
1457 d = expr[pos]
1458 d = expr[pos]
1458 if d == '%':
1459 if d == '%':
1459 ret += d
1460 ret += d
1460 elif d in 'dsnbr':
1461 elif d in 'dsnbr':
1461 ret += argtype(d, args[arg])
1462 ret += argtype(d, args[arg])
1462 arg += 1
1463 arg += 1
1463 elif d == 'l':
1464 elif d == 'l':
1464 # a list of some type
1465 # a list of some type
1465 pos += 1
1466 pos += 1
1466 d = expr[pos]
1467 d = expr[pos]
1467 ret += listexp(list(args[arg]), d)
1468 ret += listexp(list(args[arg]), d)
1468 arg += 1
1469 arg += 1
1469 else:
1470 else:
1470 raise util.Abort('unexpected revspec format character %s' % d)
1471 raise util.Abort('unexpected revspec format character %s' % d)
1471 else:
1472 else:
1472 ret += c
1473 ret += c
1473 pos += 1
1474 pos += 1
1474
1475
1475 return ret
1476 return ret
1476
1477
1477 def prettyformat(tree):
1478 def prettyformat(tree):
1478 def _prettyformat(tree, level, lines):
1479 def _prettyformat(tree, level, lines):
1479 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
1480 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
1480 lines.append((level, str(tree)))
1481 lines.append((level, str(tree)))
1481 else:
1482 else:
1482 lines.append((level, '(%s' % tree[0]))
1483 lines.append((level, '(%s' % tree[0]))
1483 for s in tree[1:]:
1484 for s in tree[1:]:
1484 _prettyformat(s, level + 1, lines)
1485 _prettyformat(s, level + 1, lines)
1485 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
1486 lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
1486
1487
1487 lines = []
1488 lines = []
1488 _prettyformat(tree, 0, lines)
1489 _prettyformat(tree, 0, lines)
1489 output = '\n'.join((' '*l + s) for l, s in lines)
1490 output = '\n'.join((' '*l + s) for l, s in lines)
1490 return output
1491 return output
1491
1492
1492 # tell hggettext to extract docstrings from these functions:
1493 # tell hggettext to extract docstrings from these functions:
1493 i18nfunctions = symbols.values()
1494 i18nfunctions = symbols.values()
@@ -1,468 +1,475 b''
1 $ "$TESTDIR/hghave" system-sh || exit 80
1 $ "$TESTDIR/hghave" system-sh || exit 80
2
2
3 $ hg init
3 $ hg init
4
4
5
5
6 committing changes
6 committing changes
7
7
8 $ count=0
8 $ count=0
9 $ echo > a
9 $ echo > a
10 $ while test $count -lt 32 ; do
10 $ while test $count -lt 32 ; do
11 > echo 'a' >> a
11 > echo 'a' >> a
12 > test $count -eq 0 && hg add
12 > test $count -eq 0 && hg add
13 > hg ci -m "msg $count" -d "$count 0"
13 > hg ci -m "msg $count" -d "$count 0"
14 > count=`expr $count + 1`
14 > count=`expr $count + 1`
15 > done
15 > done
16 adding a
16 adding a
17
17
18
18
19 $ hg log
19 $ hg log
20 changeset: 31:58c80a7c8a40
20 changeset: 31:58c80a7c8a40
21 tag: tip
21 tag: tip
22 user: test
22 user: test
23 date: Thu Jan 01 00:00:31 1970 +0000
23 date: Thu Jan 01 00:00:31 1970 +0000
24 summary: msg 31
24 summary: msg 31
25
25
26 changeset: 30:ed2d2f24b11c
26 changeset: 30:ed2d2f24b11c
27 user: test
27 user: test
28 date: Thu Jan 01 00:00:30 1970 +0000
28 date: Thu Jan 01 00:00:30 1970 +0000
29 summary: msg 30
29 summary: msg 30
30
30
31 changeset: 29:b5bd63375ab9
31 changeset: 29:b5bd63375ab9
32 user: test
32 user: test
33 date: Thu Jan 01 00:00:29 1970 +0000
33 date: Thu Jan 01 00:00:29 1970 +0000
34 summary: msg 29
34 summary: msg 29
35
35
36 changeset: 28:8e0c2264c8af
36 changeset: 28:8e0c2264c8af
37 user: test
37 user: test
38 date: Thu Jan 01 00:00:28 1970 +0000
38 date: Thu Jan 01 00:00:28 1970 +0000
39 summary: msg 28
39 summary: msg 28
40
40
41 changeset: 27:288867a866e9
41 changeset: 27:288867a866e9
42 user: test
42 user: test
43 date: Thu Jan 01 00:00:27 1970 +0000
43 date: Thu Jan 01 00:00:27 1970 +0000
44 summary: msg 27
44 summary: msg 27
45
45
46 changeset: 26:3efc6fd51aeb
46 changeset: 26:3efc6fd51aeb
47 user: test
47 user: test
48 date: Thu Jan 01 00:00:26 1970 +0000
48 date: Thu Jan 01 00:00:26 1970 +0000
49 summary: msg 26
49 summary: msg 26
50
50
51 changeset: 25:02a84173a97a
51 changeset: 25:02a84173a97a
52 user: test
52 user: test
53 date: Thu Jan 01 00:00:25 1970 +0000
53 date: Thu Jan 01 00:00:25 1970 +0000
54 summary: msg 25
54 summary: msg 25
55
55
56 changeset: 24:10e0acd3809e
56 changeset: 24:10e0acd3809e
57 user: test
57 user: test
58 date: Thu Jan 01 00:00:24 1970 +0000
58 date: Thu Jan 01 00:00:24 1970 +0000
59 summary: msg 24
59 summary: msg 24
60
60
61 changeset: 23:5ec79163bff4
61 changeset: 23:5ec79163bff4
62 user: test
62 user: test
63 date: Thu Jan 01 00:00:23 1970 +0000
63 date: Thu Jan 01 00:00:23 1970 +0000
64 summary: msg 23
64 summary: msg 23
65
65
66 changeset: 22:06c7993750ce
66 changeset: 22:06c7993750ce
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:22 1970 +0000
68 date: Thu Jan 01 00:00:22 1970 +0000
69 summary: msg 22
69 summary: msg 22
70
70
71 changeset: 21:e5db6aa3fe2a
71 changeset: 21:e5db6aa3fe2a
72 user: test
72 user: test
73 date: Thu Jan 01 00:00:21 1970 +0000
73 date: Thu Jan 01 00:00:21 1970 +0000
74 summary: msg 21
74 summary: msg 21
75
75
76 changeset: 20:7128fb4fdbc9
76 changeset: 20:7128fb4fdbc9
77 user: test
77 user: test
78 date: Thu Jan 01 00:00:20 1970 +0000
78 date: Thu Jan 01 00:00:20 1970 +0000
79 summary: msg 20
79 summary: msg 20
80
80
81 changeset: 19:52798545b482
81 changeset: 19:52798545b482
82 user: test
82 user: test
83 date: Thu Jan 01 00:00:19 1970 +0000
83 date: Thu Jan 01 00:00:19 1970 +0000
84 summary: msg 19
84 summary: msg 19
85
85
86 changeset: 18:86977a90077e
86 changeset: 18:86977a90077e
87 user: test
87 user: test
88 date: Thu Jan 01 00:00:18 1970 +0000
88 date: Thu Jan 01 00:00:18 1970 +0000
89 summary: msg 18
89 summary: msg 18
90
90
91 changeset: 17:03515f4a9080
91 changeset: 17:03515f4a9080
92 user: test
92 user: test
93 date: Thu Jan 01 00:00:17 1970 +0000
93 date: Thu Jan 01 00:00:17 1970 +0000
94 summary: msg 17
94 summary: msg 17
95
95
96 changeset: 16:a2e6ea4973e9
96 changeset: 16:a2e6ea4973e9
97 user: test
97 user: test
98 date: Thu Jan 01 00:00:16 1970 +0000
98 date: Thu Jan 01 00:00:16 1970 +0000
99 summary: msg 16
99 summary: msg 16
100
100
101 changeset: 15:e7fa0811edb0
101 changeset: 15:e7fa0811edb0
102 user: test
102 user: test
103 date: Thu Jan 01 00:00:15 1970 +0000
103 date: Thu Jan 01 00:00:15 1970 +0000
104 summary: msg 15
104 summary: msg 15
105
105
106 changeset: 14:ce8f0998e922
106 changeset: 14:ce8f0998e922
107 user: test
107 user: test
108 date: Thu Jan 01 00:00:14 1970 +0000
108 date: Thu Jan 01 00:00:14 1970 +0000
109 summary: msg 14
109 summary: msg 14
110
110
111 changeset: 13:9d7d07bc967c
111 changeset: 13:9d7d07bc967c
112 user: test
112 user: test
113 date: Thu Jan 01 00:00:13 1970 +0000
113 date: Thu Jan 01 00:00:13 1970 +0000
114 summary: msg 13
114 summary: msg 13
115
115
116 changeset: 12:1941b52820a5
116 changeset: 12:1941b52820a5
117 user: test
117 user: test
118 date: Thu Jan 01 00:00:12 1970 +0000
118 date: Thu Jan 01 00:00:12 1970 +0000
119 summary: msg 12
119 summary: msg 12
120
120
121 changeset: 11:7b4cd9578619
121 changeset: 11:7b4cd9578619
122 user: test
122 user: test
123 date: Thu Jan 01 00:00:11 1970 +0000
123 date: Thu Jan 01 00:00:11 1970 +0000
124 summary: msg 11
124 summary: msg 11
125
125
126 changeset: 10:7c5eff49a6b6
126 changeset: 10:7c5eff49a6b6
127 user: test
127 user: test
128 date: Thu Jan 01 00:00:10 1970 +0000
128 date: Thu Jan 01 00:00:10 1970 +0000
129 summary: msg 10
129 summary: msg 10
130
130
131 changeset: 9:eb44510ef29a
131 changeset: 9:eb44510ef29a
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:09 1970 +0000
133 date: Thu Jan 01 00:00:09 1970 +0000
134 summary: msg 9
134 summary: msg 9
135
135
136 changeset: 8:453eb4dba229
136 changeset: 8:453eb4dba229
137 user: test
137 user: test
138 date: Thu Jan 01 00:00:08 1970 +0000
138 date: Thu Jan 01 00:00:08 1970 +0000
139 summary: msg 8
139 summary: msg 8
140
140
141 changeset: 7:03750880c6b5
141 changeset: 7:03750880c6b5
142 user: test
142 user: test
143 date: Thu Jan 01 00:00:07 1970 +0000
143 date: Thu Jan 01 00:00:07 1970 +0000
144 summary: msg 7
144 summary: msg 7
145
145
146 changeset: 6:a3d5c6fdf0d3
146 changeset: 6:a3d5c6fdf0d3
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:06 1970 +0000
148 date: Thu Jan 01 00:00:06 1970 +0000
149 summary: msg 6
149 summary: msg 6
150
150
151 changeset: 5:7874a09ea728
151 changeset: 5:7874a09ea728
152 user: test
152 user: test
153 date: Thu Jan 01 00:00:05 1970 +0000
153 date: Thu Jan 01 00:00:05 1970 +0000
154 summary: msg 5
154 summary: msg 5
155
155
156 changeset: 4:9b2ba8336a65
156 changeset: 4:9b2ba8336a65
157 user: test
157 user: test
158 date: Thu Jan 01 00:00:04 1970 +0000
158 date: Thu Jan 01 00:00:04 1970 +0000
159 summary: msg 4
159 summary: msg 4
160
160
161 changeset: 3:b53bea5e2fcb
161 changeset: 3:b53bea5e2fcb
162 user: test
162 user: test
163 date: Thu Jan 01 00:00:03 1970 +0000
163 date: Thu Jan 01 00:00:03 1970 +0000
164 summary: msg 3
164 summary: msg 3
165
165
166 changeset: 2:db07c04beaca
166 changeset: 2:db07c04beaca
167 user: test
167 user: test
168 date: Thu Jan 01 00:00:02 1970 +0000
168 date: Thu Jan 01 00:00:02 1970 +0000
169 summary: msg 2
169 summary: msg 2
170
170
171 changeset: 1:5cd978ea5149
171 changeset: 1:5cd978ea5149
172 user: test
172 user: test
173 date: Thu Jan 01 00:00:01 1970 +0000
173 date: Thu Jan 01 00:00:01 1970 +0000
174 summary: msg 1
174 summary: msg 1
175
175
176 changeset: 0:b99c7b9c8e11
176 changeset: 0:b99c7b9c8e11
177 user: test
177 user: test
178 date: Thu Jan 01 00:00:00 1970 +0000
178 date: Thu Jan 01 00:00:00 1970 +0000
179 summary: msg 0
179 summary: msg 0
180
180
181
181
182 $ hg up -C
182 $ hg up -C
183 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
184
184
185 bisect test
185 bisect test
186
186
187 $ hg bisect -r
187 $ hg bisect -r
188 $ hg bisect -b
188 $ hg bisect -b
189 $ hg bisect -g 1
189 $ hg bisect -g 1
190 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
190 Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 $ hg bisect -g
192 $ hg bisect -g
193 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
193 Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
194 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
195
195
196 skip
196 skip
197
197
198 $ hg bisect -s
198 $ hg bisect -s
199 Testing changeset 24:10e0acd3809e (15 changesets remaining, ~3 tests)
199 Testing changeset 24:10e0acd3809e (15 changesets remaining, ~3 tests)
200 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 $ hg bisect -g
201 $ hg bisect -g
202 Testing changeset 27:288867a866e9 (7 changesets remaining, ~2 tests)
202 Testing changeset 27:288867a866e9 (7 changesets remaining, ~2 tests)
203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 $ hg bisect -g
204 $ hg bisect -g
205 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
205 Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 $ hg bisect -b
207 $ hg bisect -b
208 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
208 Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 $ hg bisect -g
210 $ hg bisect -g
211 The first bad revision is:
211 The first bad revision is:
212 changeset: 29:b5bd63375ab9
212 changeset: 29:b5bd63375ab9
213 user: test
213 user: test
214 date: Thu Jan 01 00:00:29 1970 +0000
214 date: Thu Jan 01 00:00:29 1970 +0000
215 summary: msg 29
215 summary: msg 29
216
216
217
217
218 mark revsets instead of single revs
218 mark revsets instead of single revs
219
219
220 $ hg bisect -r
220 $ hg bisect -r
221 $ hg bisect -b "0::3"
221 $ hg bisect -b "0::3"
222 $ hg bisect -s "13::16"
222 $ hg bisect -s "13::16"
223 $ hg bisect -g "26::tip"
223 $ hg bisect -g "26::tip"
224 Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
224 Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 $ cat .hg/bisect.state
226 $ cat .hg/bisect.state
227 current 1941b52820a544549596820a8ae006842b0e2c64
227 skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
228 skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
228 skip ce8f0998e922c179e80819d5066fbe46e2998784
229 skip ce8f0998e922c179e80819d5066fbe46e2998784
229 skip e7fa0811edb063f6319531f0d0a865882138e180
230 skip e7fa0811edb063f6319531f0d0a865882138e180
230 skip a2e6ea4973e9196ddd3386493b0c214b41fd97d3
231 skip a2e6ea4973e9196ddd3386493b0c214b41fd97d3
231 bad b99c7b9c8e11558adef3fad9af211c58d46f325b
232 bad b99c7b9c8e11558adef3fad9af211c58d46f325b
232 bad 5cd978ea51499179507ee7b6f340d2dbaa401185
233 bad 5cd978ea51499179507ee7b6f340d2dbaa401185
233 bad db07c04beaca44cf24832541e7f4a2346a95275b
234 bad db07c04beaca44cf24832541e7f4a2346a95275b
234 bad b53bea5e2fcb30d3e00bd3409507a5659ce0fd8b
235 bad b53bea5e2fcb30d3e00bd3409507a5659ce0fd8b
235 good 3efc6fd51aeb8594398044c6c846ca59ae021203
236 good 3efc6fd51aeb8594398044c6c846ca59ae021203
236 good 288867a866e9adb7a29880b66936c874b80f4651
237 good 288867a866e9adb7a29880b66936c874b80f4651
237 good 8e0c2264c8af790daf3585ada0669d93dee09c83
238 good 8e0c2264c8af790daf3585ada0669d93dee09c83
238 good b5bd63375ab9a290419f2024b7f4ee9ea7ce90a8
239 good b5bd63375ab9a290419f2024b7f4ee9ea7ce90a8
239 good ed2d2f24b11c368fa8aa0da9f4e1db580abade59
240 good ed2d2f24b11c368fa8aa0da9f4e1db580abade59
240 good 58c80a7c8a4025a94cedaf7b4a4e3124e8909a96
241 good 58c80a7c8a4025a94cedaf7b4a4e3124e8909a96
241
242
242 bisect reverse test
243 bisect reverse test
243
244
244 $ hg bisect -r
245 $ hg bisect -r
245 $ hg bisect -b null
246 $ hg bisect -b null
246 $ hg bisect -g tip
247 $ hg bisect -g tip
247 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
248 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 $ hg bisect -g
250 $ hg bisect -g
250 Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
251 Testing changeset 7:03750880c6b5 (16 changesets remaining, ~4 tests)
251 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
252
253
253 skip
254 skip
254
255
255 $ hg bisect -s
256 $ hg bisect -s
256 Testing changeset 6:a3d5c6fdf0d3 (16 changesets remaining, ~4 tests)
257 Testing changeset 6:a3d5c6fdf0d3 (16 changesets remaining, ~4 tests)
257 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 $ hg bisect -g
259 $ hg bisect -g
259 Testing changeset 2:db07c04beaca (7 changesets remaining, ~2 tests)
260 Testing changeset 2:db07c04beaca (7 changesets remaining, ~2 tests)
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 $ hg bisect -g
262 $ hg bisect -g
262 Testing changeset 0:b99c7b9c8e11 (3 changesets remaining, ~1 tests)
263 Testing changeset 0:b99c7b9c8e11 (3 changesets remaining, ~1 tests)
263 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 $ hg bisect -b
265 $ hg bisect -b
265 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
266 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 $ hg bisect -g
268 $ hg bisect -g
268 The first good revision is:
269 The first good revision is:
269 changeset: 1:5cd978ea5149
270 changeset: 1:5cd978ea5149
270 user: test
271 user: test
271 date: Thu Jan 01 00:00:01 1970 +0000
272 date: Thu Jan 01 00:00:01 1970 +0000
272 summary: msg 1
273 summary: msg 1
273
274
274
275
275 $ hg bisect -r
276 $ hg bisect -r
276 $ hg bisect -g tip
277 $ hg bisect -g tip
277 $ hg bisect -b tip
278 $ hg bisect -b tip
278 abort: starting revisions are not directly related
279 abort: starting revisions are not directly related
279 [255]
280 [255]
280
281
281 $ hg bisect -r
282 $ hg bisect -r
282 $ hg bisect -g null
283 $ hg bisect -g null
283 $ hg bisect -bU tip
284 $ hg bisect -bU tip
284 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
285 Testing changeset 15:e7fa0811edb0 (32 changesets remaining, ~5 tests)
285 $ hg id
286 $ hg id
286 5cd978ea5149
287 5cd978ea5149
287
288
288
289
289 Issue1228: hg bisect crashes when you skip the last rev in bisection
290 Issue1228: hg bisect crashes when you skip the last rev in bisection
290 Issue1182: hg bisect exception
291 Issue1182: hg bisect exception
291
292
292 $ hg bisect -r
293 $ hg bisect -r
293 $ hg bisect -b 4
294 $ hg bisect -b 4
294 $ hg bisect -g 0
295 $ hg bisect -g 0
295 Testing changeset 2:db07c04beaca (4 changesets remaining, ~2 tests)
296 Testing changeset 2:db07c04beaca (4 changesets remaining, ~2 tests)
296 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 $ hg bisect -s
298 $ hg bisect -s
298 Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
299 Testing changeset 1:5cd978ea5149 (4 changesets remaining, ~2 tests)
299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 $ hg bisect -s
301 $ hg bisect -s
301 Testing changeset 3:b53bea5e2fcb (4 changesets remaining, ~2 tests)
302 Testing changeset 3:b53bea5e2fcb (4 changesets remaining, ~2 tests)
302 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
303 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
303 $ hg bisect -s
304 $ hg bisect -s
304 Due to skipped revisions, the first bad revision could be any of:
305 Due to skipped revisions, the first bad revision could be any of:
305 changeset: 1:5cd978ea5149
306 changeset: 1:5cd978ea5149
306 user: test
307 user: test
307 date: Thu Jan 01 00:00:01 1970 +0000
308 date: Thu Jan 01 00:00:01 1970 +0000
308 summary: msg 1
309 summary: msg 1
309
310
310 changeset: 2:db07c04beaca
311 changeset: 2:db07c04beaca
311 user: test
312 user: test
312 date: Thu Jan 01 00:00:02 1970 +0000
313 date: Thu Jan 01 00:00:02 1970 +0000
313 summary: msg 2
314 summary: msg 2
314
315
315 changeset: 3:b53bea5e2fcb
316 changeset: 3:b53bea5e2fcb
316 user: test
317 user: test
317 date: Thu Jan 01 00:00:03 1970 +0000
318 date: Thu Jan 01 00:00:03 1970 +0000
318 summary: msg 3
319 summary: msg 3
319
320
320 changeset: 4:9b2ba8336a65
321 changeset: 4:9b2ba8336a65
321 user: test
322 user: test
322 date: Thu Jan 01 00:00:04 1970 +0000
323 date: Thu Jan 01 00:00:04 1970 +0000
323 summary: msg 4
324 summary: msg 4
324
325
325
326
326
327
327 reproduce non converging bisect, issue1182
328 reproduce non converging bisect, issue1182
328
329
329 $ hg bisect -r
330 $ hg bisect -r
330 $ hg bisect -g 0
331 $ hg bisect -g 0
331 $ hg bisect -b 2
332 $ hg bisect -b 2
332 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
333 Testing changeset 1:5cd978ea5149 (2 changesets remaining, ~1 tests)
333 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 $ hg bisect -s
335 $ hg bisect -s
335 Due to skipped revisions, the first bad revision could be any of:
336 Due to skipped revisions, the first bad revision could be any of:
336 changeset: 1:5cd978ea5149
337 changeset: 1:5cd978ea5149
337 user: test
338 user: test
338 date: Thu Jan 01 00:00:01 1970 +0000
339 date: Thu Jan 01 00:00:01 1970 +0000
339 summary: msg 1
340 summary: msg 1
340
341
341 changeset: 2:db07c04beaca
342 changeset: 2:db07c04beaca
342 user: test
343 user: test
343 date: Thu Jan 01 00:00:02 1970 +0000
344 date: Thu Jan 01 00:00:02 1970 +0000
344 summary: msg 2
345 summary: msg 2
345
346
346
347
347
348
348 test no action
349 test no action
349
350
350 $ hg bisect -r
351 $ hg bisect -r
351 $ hg bisect
352 $ hg bisect
352 abort: cannot bisect (no known good revisions)
353 abort: cannot bisect (no known good revisions)
353 [255]
354 [255]
354
355
355
356
356 reproduce AssertionError, issue1445
357 reproduce AssertionError, issue1445
357
358
358 $ hg bisect -r
359 $ hg bisect -r
359 $ hg bisect -b 6
360 $ hg bisect -b 6
360 $ hg bisect -g 0
361 $ hg bisect -g 0
361 Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests)
362 Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests)
362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 $ hg bisect -s
364 $ hg bisect -s
364 Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests)
365 Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests)
365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 $ hg bisect -s
367 $ hg bisect -s
367 Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests)
368 Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests)
368 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 $ hg bisect -s
370 $ hg bisect -s
370 Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests)
371 Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests)
371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 $ hg bisect -s
373 $ hg bisect -s
373 Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests)
374 Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests)
374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 $ hg bisect -g
376 $ hg bisect -g
376 The first bad revision is:
377 The first bad revision is:
377 changeset: 6:a3d5c6fdf0d3
378 changeset: 6:a3d5c6fdf0d3
378 user: test
379 user: test
379 date: Thu Jan 01 00:00:06 1970 +0000
380 date: Thu Jan 01 00:00:06 1970 +0000
380 summary: msg 6
381 summary: msg 6
381
382
382 $ hg log -r "bisect(good)"
383 $ hg log -r "bisect(good)"
383 changeset: 0:b99c7b9c8e11
384 changeset: 0:b99c7b9c8e11
384 user: test
385 user: test
385 date: Thu Jan 01 00:00:00 1970 +0000
386 date: Thu Jan 01 00:00:00 1970 +0000
386 summary: msg 0
387 summary: msg 0
387
388
388 changeset: 5:7874a09ea728
389 changeset: 5:7874a09ea728
389 user: test
390 user: test
390 date: Thu Jan 01 00:00:05 1970 +0000
391 date: Thu Jan 01 00:00:05 1970 +0000
391 summary: msg 5
392 summary: msg 5
392
393
393 $ hg log -r "bisect(bad)"
394 $ hg log -r "bisect(bad)"
394 changeset: 6:a3d5c6fdf0d3
395 changeset: 6:a3d5c6fdf0d3
395 user: test
396 user: test
396 date: Thu Jan 01 00:00:06 1970 +0000
397 date: Thu Jan 01 00:00:06 1970 +0000
397 summary: msg 6
398 summary: msg 6
398
399
400 $ hg log -r "bisect(current)"
401 changeset: 5:7874a09ea728
402 user: test
403 date: Thu Jan 01 00:00:05 1970 +0000
404 summary: msg 5
405
399 $ hg log -r "bisect(skip)"
406 $ hg log -r "bisect(skip)"
400 changeset: 1:5cd978ea5149
407 changeset: 1:5cd978ea5149
401 user: test
408 user: test
402 date: Thu Jan 01 00:00:01 1970 +0000
409 date: Thu Jan 01 00:00:01 1970 +0000
403 summary: msg 1
410 summary: msg 1
404
411
405 changeset: 2:db07c04beaca
412 changeset: 2:db07c04beaca
406 user: test
413 user: test
407 date: Thu Jan 01 00:00:02 1970 +0000
414 date: Thu Jan 01 00:00:02 1970 +0000
408 summary: msg 2
415 summary: msg 2
409
416
410 changeset: 3:b53bea5e2fcb
417 changeset: 3:b53bea5e2fcb
411 user: test
418 user: test
412 date: Thu Jan 01 00:00:03 1970 +0000
419 date: Thu Jan 01 00:00:03 1970 +0000
413 summary: msg 3
420 summary: msg 3
414
421
415 changeset: 4:9b2ba8336a65
422 changeset: 4:9b2ba8336a65
416 user: test
423 user: test
417 date: Thu Jan 01 00:00:04 1970 +0000
424 date: Thu Jan 01 00:00:04 1970 +0000
418 summary: msg 4
425 summary: msg 4
419
426
420
427
421 test legacy bisected() keyword
428 test legacy bisected() keyword
422
429
423 $ hg log -r "bisected(bad)"
430 $ hg log -r "bisected(bad)"
424 changeset: 6:a3d5c6fdf0d3
431 changeset: 6:a3d5c6fdf0d3
425 user: test
432 user: test
426 date: Thu Jan 01 00:00:06 1970 +0000
433 date: Thu Jan 01 00:00:06 1970 +0000
427 summary: msg 6
434 summary: msg 6
428
435
429
436
430 $ set +e
437 $ set +e
431
438
432 test invalid command
439 test invalid command
433 assuming that the shell returns 127 if command not found ...
440 assuming that the shell returns 127 if command not found ...
434
441
435 $ hg bisect -r
442 $ hg bisect -r
436 $ hg bisect --command 'exit 127'
443 $ hg bisect --command 'exit 127'
437 abort: failed to execute exit 127
444 abort: failed to execute exit 127
438 [255]
445 [255]
439
446
440
447
441 test bisecting command
448 test bisecting command
442
449
443 $ cat > script.py <<EOF
450 $ cat > script.py <<EOF
444 > #!/usr/bin/env python
451 > #!/usr/bin/env python
445 > import sys
452 > import sys
446 > from mercurial import ui, hg
453 > from mercurial import ui, hg
447 > repo = hg.repository(ui.ui(), '.')
454 > repo = hg.repository(ui.ui(), '.')
448 > if repo['.'].rev() < 6:
455 > if repo['.'].rev() < 6:
449 > sys.exit(1)
456 > sys.exit(1)
450 > EOF
457 > EOF
451 $ chmod +x script.py
458 $ chmod +x script.py
452 $ hg bisect -r
459 $ hg bisect -r
453 $ hg bisect --good tip
460 $ hg bisect --good tip
454 $ hg bisect --bad 0
461 $ hg bisect --bad 0
455 Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
462 Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
456 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 $ hg bisect --command "'`pwd`/script.py' and some parameters"
464 $ hg bisect --command "'`pwd`/script.py' and some parameters"
458 Changeset 15:e7fa0811edb0: good
465 Changeset 15:e7fa0811edb0: good
459 Changeset 7:03750880c6b5: good
466 Changeset 7:03750880c6b5: good
460 Changeset 3:b53bea5e2fcb: bad
467 Changeset 3:b53bea5e2fcb: bad
461 Changeset 5:7874a09ea728: bad
468 Changeset 5:7874a09ea728: bad
462 Changeset 6:a3d5c6fdf0d3: good
469 Changeset 6:a3d5c6fdf0d3: good
463 The first good revision is:
470 The first good revision is:
464 changeset: 6:a3d5c6fdf0d3
471 changeset: 6:a3d5c6fdf0d3
465 user: test
472 user: test
466 date: Thu Jan 01 00:00:06 1970 +0000
473 date: Thu Jan 01 00:00:06 1970 +0000
467 summary: msg 6
474 summary: msg 6
468
475
General Comments 0
You need to be logged in to leave comments. Login now