##// END OF EJS Templates
fileset: move validation of incomplete parsing to parse() function...
Yuya Nishihara -
r25252:ac381dd7 default
parent child Browse files
Show More
@@ -1,6484 +1,6484 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 _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
108 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
152 ]
152 ]
153
153
154 mergetoolopts = [
154 mergetoolopts = [
155 ('t', 'tool', '', _('specify merge tool')),
155 ('t', 'tool', '', _('specify merge tool')),
156 ]
156 ]
157
157
158 similarityopts = [
158 similarityopts = [
159 ('s', 'similarity', '',
159 ('s', 'similarity', '',
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
161 ]
161 ]
162
162
163 subrepoopts = [
163 subrepoopts = [
164 ('S', 'subrepos', None,
164 ('S', 'subrepos', None,
165 _('recurse into subrepositories'))
165 _('recurse into subrepositories'))
166 ]
166 ]
167
167
168 # Commands start here, listed alphabetically
168 # Commands start here, listed alphabetically
169
169
170 @command('^add',
170 @command('^add',
171 walkopts + subrepoopts + dryrunopts,
171 walkopts + subrepoopts + dryrunopts,
172 _('[OPTION]... [FILE]...'),
172 _('[OPTION]... [FILE]...'),
173 inferrepo=True)
173 inferrepo=True)
174 def add(ui, repo, *pats, **opts):
174 def add(ui, repo, *pats, **opts):
175 """add the specified files on the next commit
175 """add the specified files on the next commit
176
176
177 Schedule files to be version controlled and added to the
177 Schedule files to be version controlled and added to the
178 repository.
178 repository.
179
179
180 The files will be added to the repository at the next commit. To
180 The files will be added to the repository at the next commit. To
181 undo an add before that, see :hg:`forget`.
181 undo an add before that, see :hg:`forget`.
182
182
183 If no names are given, add all files to the repository.
183 If no names are given, add all files to the repository.
184
184
185 .. container:: verbose
185 .. container:: verbose
186
186
187 An example showing how new (unknown) files are added
187 An example showing how new (unknown) files are added
188 automatically by :hg:`add`::
188 automatically by :hg:`add`::
189
189
190 $ ls
190 $ ls
191 foo.c
191 foo.c
192 $ hg status
192 $ hg status
193 ? foo.c
193 ? foo.c
194 $ hg add
194 $ hg add
195 adding foo.c
195 adding foo.c
196 $ hg status
196 $ hg status
197 A foo.c
197 A foo.c
198
198
199 Returns 0 if all files are successfully added.
199 Returns 0 if all files are successfully added.
200 """
200 """
201
201
202 m = scmutil.match(repo[None], pats, opts)
202 m = scmutil.match(repo[None], pats, opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
204 return rejected and 1 or 0
204 return rejected and 1 or 0
205
205
206 @command('addremove',
206 @command('addremove',
207 similarityopts + subrepoopts + walkopts + dryrunopts,
207 similarityopts + subrepoopts + walkopts + dryrunopts,
208 _('[OPTION]... [FILE]...'),
208 _('[OPTION]... [FILE]...'),
209 inferrepo=True)
209 inferrepo=True)
210 def addremove(ui, repo, *pats, **opts):
210 def addremove(ui, repo, *pats, **opts):
211 """add all new files, delete all missing files
211 """add all new files, delete all missing files
212
212
213 Add all new files and remove all missing files from the
213 Add all new files and remove all missing files from the
214 repository.
214 repository.
215
215
216 New files are ignored if they match any of the patterns in
216 New files are ignored if they match any of the patterns in
217 ``.hgignore``. As with add, these changes take effect at the next
217 ``.hgignore``. As with add, these changes take effect at the next
218 commit.
218 commit.
219
219
220 Use the -s/--similarity option to detect renamed files. This
220 Use the -s/--similarity option to detect renamed files. This
221 option takes a percentage between 0 (disabled) and 100 (files must
221 option takes a percentage between 0 (disabled) and 100 (files must
222 be identical) as its parameter. With a parameter greater than 0,
222 be identical) as its parameter. With a parameter greater than 0,
223 this compares every removed file with every added file and records
223 this compares every removed file with every added file and records
224 those similar enough as renames. Detecting renamed files this way
224 those similar enough as renames. Detecting renamed files this way
225 can be expensive. After using this option, :hg:`status -C` can be
225 can be expensive. After using this option, :hg:`status -C` can be
226 used to check which files were identified as moved or renamed. If
226 used to check which files were identified as moved or renamed. If
227 not specified, -s/--similarity defaults to 100 and only renames of
227 not specified, -s/--similarity defaults to 100 and only renames of
228 identical files are detected.
228 identical files are detected.
229
229
230 Returns 0 if all files are successfully added.
230 Returns 0 if all files are successfully added.
231 """
231 """
232 try:
232 try:
233 sim = float(opts.get('similarity') or 100)
233 sim = float(opts.get('similarity') or 100)
234 except ValueError:
234 except ValueError:
235 raise util.Abort(_('similarity must be a number'))
235 raise util.Abort(_('similarity must be a number'))
236 if sim < 0 or sim > 100:
236 if sim < 0 or sim > 100:
237 raise util.Abort(_('similarity must be between 0 and 100'))
237 raise util.Abort(_('similarity must be between 0 and 100'))
238 matcher = scmutil.match(repo[None], pats, opts)
238 matcher = scmutil.match(repo[None], pats, opts)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
240
240
241 @command('^annotate|blame',
241 @command('^annotate|blame',
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
243 ('', 'follow', None,
243 ('', 'follow', None,
244 _('follow copies/renames and list the filename (DEPRECATED)')),
244 _('follow copies/renames and list the filename (DEPRECATED)')),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
246 ('a', 'text', None, _('treat all files as text')),
246 ('a', 'text', None, _('treat all files as text')),
247 ('u', 'user', None, _('list the author (long with -v)')),
247 ('u', 'user', None, _('list the author (long with -v)')),
248 ('f', 'file', None, _('list the filename')),
248 ('f', 'file', None, _('list the filename')),
249 ('d', 'date', None, _('list the date (short with -q)')),
249 ('d', 'date', None, _('list the date (short with -q)')),
250 ('n', 'number', None, _('list the revision number (default)')),
250 ('n', 'number', None, _('list the revision number (default)')),
251 ('c', 'changeset', None, _('list the changeset')),
251 ('c', 'changeset', None, _('list the changeset')),
252 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ('l', 'line-number', None, _('show line number at the first appearance'))
253 ] + diffwsopts + walkopts + formatteropts,
253 ] + diffwsopts + walkopts + formatteropts,
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
255 inferrepo=True)
255 inferrepo=True)
256 def annotate(ui, repo, *pats, **opts):
256 def annotate(ui, repo, *pats, **opts):
257 """show changeset information by line for each file
257 """show changeset information by line for each file
258
258
259 List changes in files, showing the revision id responsible for
259 List changes in files, showing the revision id responsible for
260 each line
260 each line
261
261
262 This command is useful for discovering when a change was made and
262 This command is useful for discovering when a change was made and
263 by whom.
263 by whom.
264
264
265 Without the -a/--text option, annotate will avoid processing files
265 Without the -a/--text option, annotate will avoid processing files
266 it detects as binary. With -a, annotate will annotate the file
266 it detects as binary. With -a, annotate will annotate the file
267 anyway, although the results will probably be neither useful
267 anyway, although the results will probably be neither useful
268 nor desirable.
268 nor desirable.
269
269
270 Returns 0 on success.
270 Returns 0 on success.
271 """
271 """
272 if not pats:
272 if not pats:
273 raise util.Abort(_('at least one filename or pattern is required'))
273 raise util.Abort(_('at least one filename or pattern is required'))
274
274
275 if opts.get('follow'):
275 if opts.get('follow'):
276 # --follow is deprecated and now just an alias for -f/--file
276 # --follow is deprecated and now just an alias for -f/--file
277 # to mimic the behavior of Mercurial before version 1.5
277 # to mimic the behavior of Mercurial before version 1.5
278 opts['file'] = True
278 opts['file'] = True
279
279
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
281
281
282 fm = ui.formatter('annotate', opts)
282 fm = ui.formatter('annotate', opts)
283 if ui.quiet:
283 if ui.quiet:
284 datefunc = util.shortdate
284 datefunc = util.shortdate
285 else:
285 else:
286 datefunc = util.datestr
286 datefunc = util.datestr
287 if ctx.rev() is None:
287 if ctx.rev() is None:
288 def hexfn(node):
288 def hexfn(node):
289 if node is None:
289 if node is None:
290 return None
290 return None
291 else:
291 else:
292 return fm.hexfunc(node)
292 return fm.hexfunc(node)
293 if opts.get('changeset'):
293 if opts.get('changeset'):
294 # omit "+" suffix which is appended to node hex
294 # omit "+" suffix which is appended to node hex
295 def formatrev(rev):
295 def formatrev(rev):
296 if rev is None:
296 if rev is None:
297 return '%d' % ctx.p1().rev()
297 return '%d' % ctx.p1().rev()
298 else:
298 else:
299 return '%d' % rev
299 return '%d' % rev
300 else:
300 else:
301 def formatrev(rev):
301 def formatrev(rev):
302 if rev is None:
302 if rev is None:
303 return '%d+' % ctx.p1().rev()
303 return '%d+' % ctx.p1().rev()
304 else:
304 else:
305 return '%d ' % rev
305 return '%d ' % rev
306 def formathex(hex):
306 def formathex(hex):
307 if hex is None:
307 if hex is None:
308 return '%s+' % fm.hexfunc(ctx.p1().node())
308 return '%s+' % fm.hexfunc(ctx.p1().node())
309 else:
309 else:
310 return '%s ' % hex
310 return '%s ' % hex
311 else:
311 else:
312 hexfn = fm.hexfunc
312 hexfn = fm.hexfunc
313 formatrev = formathex = str
313 formatrev = formathex = str
314
314
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
319 ('file', ' ', lambda x: x[0].path(), str),
319 ('file', ' ', lambda x: x[0].path(), str),
320 ('line_number', ':', lambda x: x[1], str),
320 ('line_number', ':', lambda x: x[1], str),
321 ]
321 ]
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
323
323
324 if (not opts.get('user') and not opts.get('changeset')
324 if (not opts.get('user') and not opts.get('changeset')
325 and not opts.get('date') and not opts.get('file')):
325 and not opts.get('date') and not opts.get('file')):
326 opts['number'] = True
326 opts['number'] = True
327
327
328 linenumber = opts.get('line_number') is not None
328 linenumber = opts.get('line_number') is not None
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
331
331
332 if fm:
332 if fm:
333 def makefunc(get, fmt):
333 def makefunc(get, fmt):
334 return get
334 return get
335 else:
335 else:
336 def makefunc(get, fmt):
336 def makefunc(get, fmt):
337 return lambda x: fmt(get(x))
337 return lambda x: fmt(get(x))
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
339 if opts.get(op)]
339 if opts.get(op)]
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
342 if opts.get(op))
342 if opts.get(op))
343
343
344 def bad(x, y):
344 def bad(x, y):
345 raise util.Abort("%s: %s" % (x, y))
345 raise util.Abort("%s: %s" % (x, y))
346
346
347 m = scmutil.match(ctx, pats, opts)
347 m = scmutil.match(ctx, pats, opts)
348 m.bad = bad
348 m.bad = bad
349 follow = not opts.get('no_follow')
349 follow = not opts.get('no_follow')
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
351 whitespace=True)
351 whitespace=True)
352 for abs in ctx.walk(m):
352 for abs in ctx.walk(m):
353 fctx = ctx[abs]
353 fctx = ctx[abs]
354 if not opts.get('text') and util.binary(fctx.data()):
354 if not opts.get('text') and util.binary(fctx.data()):
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
356 continue
356 continue
357
357
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
359 diffopts=diffopts)
359 diffopts=diffopts)
360 formats = []
360 formats = []
361 pieces = []
361 pieces = []
362
362
363 for f, sep in funcmap:
363 for f, sep in funcmap:
364 l = [f(n) for n, dummy in lines]
364 l = [f(n) for n, dummy in lines]
365 if l:
365 if l:
366 if fm:
366 if fm:
367 formats.append(['%s' for x in l])
367 formats.append(['%s' for x in l])
368 else:
368 else:
369 sizes = [encoding.colwidth(x) for x in l]
369 sizes = [encoding.colwidth(x) for x in l]
370 ml = max(sizes)
370 ml = max(sizes)
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
372 pieces.append(l)
372 pieces.append(l)
373
373
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
375 fm.startitem()
375 fm.startitem()
376 fm.write(fields, "".join(f), *p)
376 fm.write(fields, "".join(f), *p)
377 fm.write('line', ": %s", l[1])
377 fm.write('line', ": %s", l[1])
378
378
379 if lines and not lines[-1][1].endswith('\n'):
379 if lines and not lines[-1][1].endswith('\n'):
380 fm.plain('\n')
380 fm.plain('\n')
381
381
382 fm.end()
382 fm.end()
383
383
384 @command('archive',
384 @command('archive',
385 [('', 'no-decode', None, _('do not pass files through decoders')),
385 [('', 'no-decode', None, _('do not pass files through decoders')),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
387 _('PREFIX')),
387 _('PREFIX')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
390 ] + subrepoopts + walkopts,
390 ] + subrepoopts + walkopts,
391 _('[OPTION]... DEST'))
391 _('[OPTION]... DEST'))
392 def archive(ui, repo, dest, **opts):
392 def archive(ui, repo, dest, **opts):
393 '''create an unversioned archive of a repository revision
393 '''create an unversioned archive of a repository revision
394
394
395 By default, the revision used is the parent of the working
395 By default, the revision used is the parent of the working
396 directory; use -r/--rev to specify a different revision.
396 directory; use -r/--rev to specify a different revision.
397
397
398 The archive type is automatically detected based on file
398 The archive type is automatically detected based on file
399 extension (or override using -t/--type).
399 extension (or override using -t/--type).
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 Examples:
403 Examples:
404
404
405 - create a zip file containing the 1.0 release::
405 - create a zip file containing the 1.0 release::
406
406
407 hg archive -r 1.0 project-1.0.zip
407 hg archive -r 1.0 project-1.0.zip
408
408
409 - create a tarball excluding .hg files::
409 - create a tarball excluding .hg files::
410
410
411 hg archive project.tar.gz -X ".hg*"
411 hg archive project.tar.gz -X ".hg*"
412
412
413 Valid types are:
413 Valid types are:
414
414
415 :``files``: a directory full of files (default)
415 :``files``: a directory full of files (default)
416 :``tar``: tar archive, uncompressed
416 :``tar``: tar archive, uncompressed
417 :``tbz2``: tar archive, compressed using bzip2
417 :``tbz2``: tar archive, compressed using bzip2
418 :``tgz``: tar archive, compressed using gzip
418 :``tgz``: tar archive, compressed using gzip
419 :``uzip``: zip archive, uncompressed
419 :``uzip``: zip archive, uncompressed
420 :``zip``: zip archive, compressed using deflate
420 :``zip``: zip archive, compressed using deflate
421
421
422 The exact name of the destination archive or directory is given
422 The exact name of the destination archive or directory is given
423 using a format string; see :hg:`help export` for details.
423 using a format string; see :hg:`help export` for details.
424
424
425 Each member added to an archive file has a directory prefix
425 Each member added to an archive file has a directory prefix
426 prepended. Use -p/--prefix to specify a format string for the
426 prepended. Use -p/--prefix to specify a format string for the
427 prefix. The default is the basename of the archive, with suffixes
427 prefix. The default is the basename of the archive, with suffixes
428 removed.
428 removed.
429
429
430 Returns 0 on success.
430 Returns 0 on success.
431 '''
431 '''
432
432
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
434 if not ctx:
434 if not ctx:
435 raise util.Abort(_('no working directory: please specify a revision'))
435 raise util.Abort(_('no working directory: please specify a revision'))
436 node = ctx.node()
436 node = ctx.node()
437 dest = cmdutil.makefilename(repo, dest, node)
437 dest = cmdutil.makefilename(repo, dest, node)
438 if os.path.realpath(dest) == repo.root:
438 if os.path.realpath(dest) == repo.root:
439 raise util.Abort(_('repository root cannot be destination'))
439 raise util.Abort(_('repository root cannot be destination'))
440
440
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
442 prefix = opts.get('prefix')
442 prefix = opts.get('prefix')
443
443
444 if dest == '-':
444 if dest == '-':
445 if kind == 'files':
445 if kind == 'files':
446 raise util.Abort(_('cannot archive plain files to stdout'))
446 raise util.Abort(_('cannot archive plain files to stdout'))
447 dest = cmdutil.makefileobj(repo, dest)
447 dest = cmdutil.makefileobj(repo, dest)
448 if not prefix:
448 if not prefix:
449 prefix = os.path.basename(repo.root) + '-%h'
449 prefix = os.path.basename(repo.root) + '-%h'
450
450
451 prefix = cmdutil.makefilename(repo, prefix, node)
451 prefix = cmdutil.makefilename(repo, prefix, node)
452 matchfn = scmutil.match(ctx, [], opts)
452 matchfn = scmutil.match(ctx, [], opts)
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
454 matchfn, prefix, subrepos=opts.get('subrepos'))
454 matchfn, prefix, subrepos=opts.get('subrepos'))
455
455
456 @command('backout',
456 @command('backout',
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
459 ('', 'parent', '',
459 ('', 'parent', '',
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
464 _('[OPTION]... [-r] REV'))
464 _('[OPTION]... [-r] REV'))
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
466 '''reverse effect of earlier changeset
466 '''reverse effect of earlier changeset
467
467
468 Prepare a new changeset with the effect of REV undone in the
468 Prepare a new changeset with the effect of REV undone in the
469 current working directory.
469 current working directory.
470
470
471 If REV is the parent of the working directory, then this new changeset
471 If REV is the parent of the working directory, then this new changeset
472 is committed automatically. Otherwise, hg needs to merge the
472 is committed automatically. Otherwise, hg needs to merge the
473 changes and the merged result is left uncommitted.
473 changes and the merged result is left uncommitted.
474
474
475 .. note::
475 .. note::
476
476
477 backout cannot be used to fix either an unwanted or
477 backout cannot be used to fix either an unwanted or
478 incorrect merge.
478 incorrect merge.
479
479
480 .. container:: verbose
480 .. container:: verbose
481
481
482 By default, the pending changeset will have one parent,
482 By default, the pending changeset will have one parent,
483 maintaining a linear history. With --merge, the pending
483 maintaining a linear history. With --merge, the pending
484 changeset will instead have two parents: the old parent of the
484 changeset will instead have two parents: the old parent of the
485 working directory and a new child of REV that simply undoes REV.
485 working directory and a new child of REV that simply undoes REV.
486
486
487 Before version 1.7, the behavior without --merge was equivalent
487 Before version 1.7, the behavior without --merge was equivalent
488 to specifying --merge followed by :hg:`update --clean .` to
488 to specifying --merge followed by :hg:`update --clean .` to
489 cancel the merge and leave the child of REV as a head to be
489 cancel the merge and leave the child of REV as a head to be
490 merged separately.
490 merged separately.
491
491
492 See :hg:`help dates` for a list of formats valid for -d/--date.
492 See :hg:`help dates` for a list of formats valid for -d/--date.
493
493
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
495 files.
495 files.
496 '''
496 '''
497 if rev and node:
497 if rev and node:
498 raise util.Abort(_("please specify just one revision"))
498 raise util.Abort(_("please specify just one revision"))
499
499
500 if not rev:
500 if not rev:
501 rev = node
501 rev = node
502
502
503 if not rev:
503 if not rev:
504 raise util.Abort(_("please specify a revision to backout"))
504 raise util.Abort(_("please specify a revision to backout"))
505
505
506 date = opts.get('date')
506 date = opts.get('date')
507 if date:
507 if date:
508 opts['date'] = util.parsedate(date)
508 opts['date'] = util.parsedate(date)
509
509
510 cmdutil.checkunfinished(repo)
510 cmdutil.checkunfinished(repo)
511 cmdutil.bailifchanged(repo)
511 cmdutil.bailifchanged(repo)
512 node = scmutil.revsingle(repo, rev).node()
512 node = scmutil.revsingle(repo, rev).node()
513
513
514 op1, op2 = repo.dirstate.parents()
514 op1, op2 = repo.dirstate.parents()
515 if not repo.changelog.isancestor(node, op1):
515 if not repo.changelog.isancestor(node, op1):
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
517
517
518 p1, p2 = repo.changelog.parents(node)
518 p1, p2 = repo.changelog.parents(node)
519 if p1 == nullid:
519 if p1 == nullid:
520 raise util.Abort(_('cannot backout a change with no parents'))
520 raise util.Abort(_('cannot backout a change with no parents'))
521 if p2 != nullid:
521 if p2 != nullid:
522 if not opts.get('parent'):
522 if not opts.get('parent'):
523 raise util.Abort(_('cannot backout a merge changeset'))
523 raise util.Abort(_('cannot backout a merge changeset'))
524 p = repo.lookup(opts['parent'])
524 p = repo.lookup(opts['parent'])
525 if p not in (p1, p2):
525 if p not in (p1, p2):
526 raise util.Abort(_('%s is not a parent of %s') %
526 raise util.Abort(_('%s is not a parent of %s') %
527 (short(p), short(node)))
527 (short(p), short(node)))
528 parent = p
528 parent = p
529 else:
529 else:
530 if opts.get('parent'):
530 if opts.get('parent'):
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
532 parent = p1
532 parent = p1
533
533
534 # the backout should appear on the same branch
534 # the backout should appear on the same branch
535 wlock = repo.wlock()
535 wlock = repo.wlock()
536 try:
536 try:
537 branch = repo.dirstate.branch()
537 branch = repo.dirstate.branch()
538 bheads = repo.branchheads(branch)
538 bheads = repo.branchheads(branch)
539 rctx = scmutil.revsingle(repo, hex(parent))
539 rctx = scmutil.revsingle(repo, hex(parent))
540 if not opts.get('merge') and op1 != node:
540 if not opts.get('merge') and op1 != node:
541 try:
541 try:
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
543 'backout')
543 'backout')
544 repo.dirstate.beginparentchange()
544 repo.dirstate.beginparentchange()
545 stats = mergemod.update(repo, parent, True, True, False,
545 stats = mergemod.update(repo, parent, True, True, False,
546 node, False)
546 node, False)
547 repo.setparents(op1, op2)
547 repo.setparents(op1, op2)
548 repo.dirstate.endparentchange()
548 repo.dirstate.endparentchange()
549 hg._showstats(repo, stats)
549 hg._showstats(repo, stats)
550 if stats[3]:
550 if stats[3]:
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
552 "file merges\n"))
552 "file merges\n"))
553 return 1
553 return 1
554 elif not commit:
554 elif not commit:
555 msg = _("changeset %s backed out, "
555 msg = _("changeset %s backed out, "
556 "don't forget to commit.\n")
556 "don't forget to commit.\n")
557 ui.status(msg % short(node))
557 ui.status(msg % short(node))
558 return 0
558 return 0
559 finally:
559 finally:
560 ui.setconfig('ui', 'forcemerge', '', '')
560 ui.setconfig('ui', 'forcemerge', '', '')
561 else:
561 else:
562 hg.clean(repo, node, show_stats=False)
562 hg.clean(repo, node, show_stats=False)
563 repo.dirstate.setbranch(branch)
563 repo.dirstate.setbranch(branch)
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
565
565
566
566
567 def commitfunc(ui, repo, message, match, opts):
567 def commitfunc(ui, repo, message, match, opts):
568 editform = 'backout'
568 editform = 'backout'
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
570 if not message:
570 if not message:
571 # we don't translate commit messages
571 # we don't translate commit messages
572 message = "Backed out changeset %s" % short(node)
572 message = "Backed out changeset %s" % short(node)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
574 return repo.commit(message, opts.get('user'), opts.get('date'),
574 return repo.commit(message, opts.get('user'), opts.get('date'),
575 match, editor=e)
575 match, editor=e)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
577 if not newnode:
577 if not newnode:
578 ui.status(_("nothing changed\n"))
578 ui.status(_("nothing changed\n"))
579 return 1
579 return 1
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
581
581
582 def nice(node):
582 def nice(node):
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
584 ui.status(_('changeset %s backs out changeset %s\n') %
584 ui.status(_('changeset %s backs out changeset %s\n') %
585 (nice(repo.changelog.tip()), nice(node)))
585 (nice(repo.changelog.tip()), nice(node)))
586 if opts.get('merge') and op1 != node:
586 if opts.get('merge') and op1 != node:
587 hg.clean(repo, op1, show_stats=False)
587 hg.clean(repo, op1, show_stats=False)
588 ui.status(_('merging with changeset %s\n')
588 ui.status(_('merging with changeset %s\n')
589 % nice(repo.changelog.tip()))
589 % nice(repo.changelog.tip()))
590 try:
590 try:
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
592 'backout')
592 'backout')
593 return hg.merge(repo, hex(repo.changelog.tip()))
593 return hg.merge(repo, hex(repo.changelog.tip()))
594 finally:
594 finally:
595 ui.setconfig('ui', 'forcemerge', '', '')
595 ui.setconfig('ui', 'forcemerge', '', '')
596 finally:
596 finally:
597 wlock.release()
597 wlock.release()
598 return 0
598 return 0
599
599
600 @command('bisect',
600 @command('bisect',
601 [('r', 'reset', False, _('reset bisect state')),
601 [('r', 'reset', False, _('reset bisect state')),
602 ('g', 'good', False, _('mark changeset good')),
602 ('g', 'good', False, _('mark changeset good')),
603 ('b', 'bad', False, _('mark changeset bad')),
603 ('b', 'bad', False, _('mark changeset bad')),
604 ('s', 'skip', False, _('skip testing changeset')),
604 ('s', 'skip', False, _('skip testing changeset')),
605 ('e', 'extend', False, _('extend the bisect range')),
605 ('e', 'extend', False, _('extend the bisect range')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
607 ('U', 'noupdate', False, _('do not update to target'))],
607 ('U', 'noupdate', False, _('do not update to target'))],
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
609 def bisect(ui, repo, rev=None, extra=None, command=None,
609 def bisect(ui, repo, rev=None, extra=None, command=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
611 noupdate=None):
611 noupdate=None):
612 """subdivision search of changesets
612 """subdivision search of changesets
613
613
614 This command helps to find changesets which introduce problems. To
614 This command helps to find changesets which introduce problems. To
615 use, mark the earliest changeset you know exhibits the problem as
615 use, mark the earliest changeset you know exhibits the problem as
616 bad, then mark the latest changeset which is free from the problem
616 bad, then mark the latest changeset which is free from the problem
617 as good. Bisect will update your working directory to a revision
617 as good. Bisect will update your working directory to a revision
618 for testing (unless the -U/--noupdate option is specified). Once
618 for testing (unless the -U/--noupdate option is specified). Once
619 you have performed tests, mark the working directory as good or
619 you have performed tests, mark the working directory as good or
620 bad, and bisect will either update to another candidate changeset
620 bad, and bisect will either update to another candidate changeset
621 or announce that it has found the bad revision.
621 or announce that it has found the bad revision.
622
622
623 As a shortcut, you can also use the revision argument to mark a
623 As a shortcut, you can also use the revision argument to mark a
624 revision as good or bad without checking it out first.
624 revision as good or bad without checking it out first.
625
625
626 If you supply a command, it will be used for automatic bisection.
626 If you supply a command, it will be used for automatic bisection.
627 The environment variable HG_NODE will contain the ID of the
627 The environment variable HG_NODE will contain the ID of the
628 changeset being tested. The exit status of the command will be
628 changeset being tested. The exit status of the command will be
629 used to mark revisions as good or bad: status 0 means good, 125
629 used to mark revisions as good or bad: status 0 means good, 125
630 means to skip the revision, 127 (command not found) will abort the
630 means to skip the revision, 127 (command not found) will abort the
631 bisection, and any other non-zero exit status means the revision
631 bisection, and any other non-zero exit status means the revision
632 is bad.
632 is bad.
633
633
634 .. container:: verbose
634 .. container:: verbose
635
635
636 Some examples:
636 Some examples:
637
637
638 - start a bisection with known bad revision 34, and good revision 12::
638 - start a bisection with known bad revision 34, and good revision 12::
639
639
640 hg bisect --bad 34
640 hg bisect --bad 34
641 hg bisect --good 12
641 hg bisect --good 12
642
642
643 - advance the current bisection by marking current revision as good or
643 - advance the current bisection by marking current revision as good or
644 bad::
644 bad::
645
645
646 hg bisect --good
646 hg bisect --good
647 hg bisect --bad
647 hg bisect --bad
648
648
649 - mark the current revision, or a known revision, to be skipped (e.g. if
649 - mark the current revision, or a known revision, to be skipped (e.g. if
650 that revision is not usable because of another issue)::
650 that revision is not usable because of another issue)::
651
651
652 hg bisect --skip
652 hg bisect --skip
653 hg bisect --skip 23
653 hg bisect --skip 23
654
654
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
656
656
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
658
658
659 - forget the current bisection::
659 - forget the current bisection::
660
660
661 hg bisect --reset
661 hg bisect --reset
662
662
663 - use 'make && make tests' to automatically find the first broken
663 - use 'make && make tests' to automatically find the first broken
664 revision::
664 revision::
665
665
666 hg bisect --reset
666 hg bisect --reset
667 hg bisect --bad 34
667 hg bisect --bad 34
668 hg bisect --good 12
668 hg bisect --good 12
669 hg bisect --command "make && make tests"
669 hg bisect --command "make && make tests"
670
670
671 - see all changesets whose states are already known in the current
671 - see all changesets whose states are already known in the current
672 bisection::
672 bisection::
673
673
674 hg log -r "bisect(pruned)"
674 hg log -r "bisect(pruned)"
675
675
676 - see the changeset currently being bisected (especially useful
676 - see the changeset currently being bisected (especially useful
677 if running with -U/--noupdate)::
677 if running with -U/--noupdate)::
678
678
679 hg log -r "bisect(current)"
679 hg log -r "bisect(current)"
680
680
681 - see all changesets that took part in the current bisection::
681 - see all changesets that took part in the current bisection::
682
682
683 hg log -r "bisect(range)"
683 hg log -r "bisect(range)"
684
684
685 - you can even get a nice graph::
685 - you can even get a nice graph::
686
686
687 hg log --graph -r "bisect(range)"
687 hg log --graph -r "bisect(range)"
688
688
689 See :hg:`help revsets` for more about the `bisect()` keyword.
689 See :hg:`help revsets` for more about the `bisect()` keyword.
690
690
691 Returns 0 on success.
691 Returns 0 on success.
692 """
692 """
693 def extendbisectrange(nodes, good):
693 def extendbisectrange(nodes, good):
694 # bisect is incomplete when it ends on a merge node and
694 # bisect is incomplete when it ends on a merge node and
695 # one of the parent was not checked.
695 # one of the parent was not checked.
696 parents = repo[nodes[0]].parents()
696 parents = repo[nodes[0]].parents()
697 if len(parents) > 1:
697 if len(parents) > 1:
698 if good:
698 if good:
699 side = state['bad']
699 side = state['bad']
700 else:
700 else:
701 side = state['good']
701 side = state['good']
702 num = len(set(i.node() for i in parents) & set(side))
702 num = len(set(i.node() for i in parents) & set(side))
703 if num == 1:
703 if num == 1:
704 return parents[0].ancestor(parents[1])
704 return parents[0].ancestor(parents[1])
705 return None
705 return None
706
706
707 def print_result(nodes, good):
707 def print_result(nodes, good):
708 displayer = cmdutil.show_changeset(ui, repo, {})
708 displayer = cmdutil.show_changeset(ui, repo, {})
709 if len(nodes) == 1:
709 if len(nodes) == 1:
710 # narrowed it down to a single revision
710 # narrowed it down to a single revision
711 if good:
711 if good:
712 ui.write(_("The first good revision is:\n"))
712 ui.write(_("The first good revision is:\n"))
713 else:
713 else:
714 ui.write(_("The first bad revision is:\n"))
714 ui.write(_("The first bad revision is:\n"))
715 displayer.show(repo[nodes[0]])
715 displayer.show(repo[nodes[0]])
716 extendnode = extendbisectrange(nodes, good)
716 extendnode = extendbisectrange(nodes, good)
717 if extendnode is not None:
717 if extendnode is not None:
718 ui.write(_('Not all ancestors of this changeset have been'
718 ui.write(_('Not all ancestors of this changeset have been'
719 ' checked.\nUse bisect --extend to continue the '
719 ' checked.\nUse bisect --extend to continue the '
720 'bisection from\nthe common ancestor, %s.\n')
720 'bisection from\nthe common ancestor, %s.\n')
721 % extendnode)
721 % extendnode)
722 else:
722 else:
723 # multiple possible revisions
723 # multiple possible revisions
724 if good:
724 if good:
725 ui.write(_("Due to skipped revisions, the first "
725 ui.write(_("Due to skipped revisions, the first "
726 "good revision could be any of:\n"))
726 "good revision could be any of:\n"))
727 else:
727 else:
728 ui.write(_("Due to skipped revisions, the first "
728 ui.write(_("Due to skipped revisions, the first "
729 "bad revision could be any of:\n"))
729 "bad revision could be any of:\n"))
730 for n in nodes:
730 for n in nodes:
731 displayer.show(repo[n])
731 displayer.show(repo[n])
732 displayer.close()
732 displayer.close()
733
733
734 def check_state(state, interactive=True):
734 def check_state(state, interactive=True):
735 if not state['good'] or not state['bad']:
735 if not state['good'] or not state['bad']:
736 if (good or bad or skip or reset) and interactive:
736 if (good or bad or skip or reset) and interactive:
737 return
737 return
738 if not state['good']:
738 if not state['good']:
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
740 else:
740 else:
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
742 return True
742 return True
743
743
744 # backward compatibility
744 # backward compatibility
745 if rev in "good bad reset init".split():
745 if rev in "good bad reset init".split():
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
747 cmd, rev, extra = rev, extra, None
747 cmd, rev, extra = rev, extra, None
748 if cmd == "good":
748 if cmd == "good":
749 good = True
749 good = True
750 elif cmd == "bad":
750 elif cmd == "bad":
751 bad = True
751 bad = True
752 else:
752 else:
753 reset = True
753 reset = True
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
755 raise util.Abort(_('incompatible arguments'))
755 raise util.Abort(_('incompatible arguments'))
756
756
757 cmdutil.checkunfinished(repo)
757 cmdutil.checkunfinished(repo)
758
758
759 if reset:
759 if reset:
760 p = repo.join("bisect.state")
760 p = repo.join("bisect.state")
761 if os.path.exists(p):
761 if os.path.exists(p):
762 os.unlink(p)
762 os.unlink(p)
763 return
763 return
764
764
765 state = hbisect.load_state(repo)
765 state = hbisect.load_state(repo)
766
766
767 if command:
767 if command:
768 changesets = 1
768 changesets = 1
769 if noupdate:
769 if noupdate:
770 try:
770 try:
771 node = state['current'][0]
771 node = state['current'][0]
772 except LookupError:
772 except LookupError:
773 raise util.Abort(_('current bisect revision is unknown - '
773 raise util.Abort(_('current bisect revision is unknown - '
774 'start a new bisect to fix'))
774 'start a new bisect to fix'))
775 else:
775 else:
776 node, p2 = repo.dirstate.parents()
776 node, p2 = repo.dirstate.parents()
777 if p2 != nullid:
777 if p2 != nullid:
778 raise util.Abort(_('current bisect revision is a merge'))
778 raise util.Abort(_('current bisect revision is a merge'))
779 try:
779 try:
780 while changesets:
780 while changesets:
781 # update state
781 # update state
782 state['current'] = [node]
782 state['current'] = [node]
783 hbisect.save_state(repo, state)
783 hbisect.save_state(repo, state)
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
785 if status == 125:
785 if status == 125:
786 transition = "skip"
786 transition = "skip"
787 elif status == 0:
787 elif status == 0:
788 transition = "good"
788 transition = "good"
789 # status < 0 means process was killed
789 # status < 0 means process was killed
790 elif status == 127:
790 elif status == 127:
791 raise util.Abort(_("failed to execute %s") % command)
791 raise util.Abort(_("failed to execute %s") % command)
792 elif status < 0:
792 elif status < 0:
793 raise util.Abort(_("%s killed") % command)
793 raise util.Abort(_("%s killed") % command)
794 else:
794 else:
795 transition = "bad"
795 transition = "bad"
796 ctx = scmutil.revsingle(repo, rev, node)
796 ctx = scmutil.revsingle(repo, rev, node)
797 rev = None # clear for future iterations
797 rev = None # clear for future iterations
798 state[transition].append(ctx.node())
798 state[transition].append(ctx.node())
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
800 check_state(state, interactive=False)
800 check_state(state, interactive=False)
801 # bisect
801 # bisect
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
803 # update to next check
803 # update to next check
804 node = nodes[0]
804 node = nodes[0]
805 if not noupdate:
805 if not noupdate:
806 cmdutil.bailifchanged(repo)
806 cmdutil.bailifchanged(repo)
807 hg.clean(repo, node, show_stats=False)
807 hg.clean(repo, node, show_stats=False)
808 finally:
808 finally:
809 state['current'] = [node]
809 state['current'] = [node]
810 hbisect.save_state(repo, state)
810 hbisect.save_state(repo, state)
811 print_result(nodes, bgood)
811 print_result(nodes, bgood)
812 return
812 return
813
813
814 # update state
814 # update state
815
815
816 if rev:
816 if rev:
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
818 else:
818 else:
819 nodes = [repo.lookup('.')]
819 nodes = [repo.lookup('.')]
820
820
821 if good or bad or skip:
821 if good or bad or skip:
822 if good:
822 if good:
823 state['good'] += nodes
823 state['good'] += nodes
824 elif bad:
824 elif bad:
825 state['bad'] += nodes
825 state['bad'] += nodes
826 elif skip:
826 elif skip:
827 state['skip'] += nodes
827 state['skip'] += nodes
828 hbisect.save_state(repo, state)
828 hbisect.save_state(repo, state)
829
829
830 if not check_state(state):
830 if not check_state(state):
831 return
831 return
832
832
833 # actually bisect
833 # actually bisect
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
835 if extend:
835 if extend:
836 if not changesets:
836 if not changesets:
837 extendnode = extendbisectrange(nodes, good)
837 extendnode = extendbisectrange(nodes, good)
838 if extendnode is not None:
838 if extendnode is not None:
839 ui.write(_("Extending search to changeset %d:%s\n")
839 ui.write(_("Extending search to changeset %d:%s\n")
840 % (extendnode.rev(), extendnode))
840 % (extendnode.rev(), extendnode))
841 state['current'] = [extendnode.node()]
841 state['current'] = [extendnode.node()]
842 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
843 if noupdate:
843 if noupdate:
844 return
844 return
845 cmdutil.bailifchanged(repo)
845 cmdutil.bailifchanged(repo)
846 return hg.clean(repo, extendnode.node())
846 return hg.clean(repo, extendnode.node())
847 raise util.Abort(_("nothing to extend"))
847 raise util.Abort(_("nothing to extend"))
848
848
849 if changesets == 0:
849 if changesets == 0:
850 print_result(nodes, good)
850 print_result(nodes, good)
851 else:
851 else:
852 assert len(nodes) == 1 # only a single node can be tested next
852 assert len(nodes) == 1 # only a single node can be tested next
853 node = nodes[0]
853 node = nodes[0]
854 # compute the approximate number of remaining tests
854 # compute the approximate number of remaining tests
855 tests, size = 0, 2
855 tests, size = 0, 2
856 while size <= changesets:
856 while size <= changesets:
857 tests, size = tests + 1, size * 2
857 tests, size = tests + 1, size * 2
858 rev = repo.changelog.rev(node)
858 rev = repo.changelog.rev(node)
859 ui.write(_("Testing changeset %d:%s "
859 ui.write(_("Testing changeset %d:%s "
860 "(%d changesets remaining, ~%d tests)\n")
860 "(%d changesets remaining, ~%d tests)\n")
861 % (rev, short(node), changesets, tests))
861 % (rev, short(node), changesets, tests))
862 state['current'] = [node]
862 state['current'] = [node]
863 hbisect.save_state(repo, state)
863 hbisect.save_state(repo, state)
864 if not noupdate:
864 if not noupdate:
865 cmdutil.bailifchanged(repo)
865 cmdutil.bailifchanged(repo)
866 return hg.clean(repo, node)
866 return hg.clean(repo, node)
867
867
868 @command('bookmarks|bookmark',
868 @command('bookmarks|bookmark',
869 [('f', 'force', False, _('force')),
869 [('f', 'force', False, _('force')),
870 ('r', 'rev', '', _('revision'), _('REV')),
870 ('r', 'rev', '', _('revision'), _('REV')),
871 ('d', 'delete', False, _('delete a given bookmark')),
871 ('d', 'delete', False, _('delete a given bookmark')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
874 ] + formatteropts,
874 ] + formatteropts,
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
876 def bookmark(ui, repo, *names, **opts):
876 def bookmark(ui, repo, *names, **opts):
877 '''create a new bookmark or list existing bookmarks
877 '''create a new bookmark or list existing bookmarks
878
878
879 Bookmarks are labels on changesets to help track lines of development.
879 Bookmarks are labels on changesets to help track lines of development.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
881 Deleting or moving a bookmark has no effect on the associated changesets.
881 Deleting or moving a bookmark has no effect on the associated changesets.
882
882
883 Creating or updating to a bookmark causes it to be marked as 'active'.
883 Creating or updating to a bookmark causes it to be marked as 'active'.
884 The active bookmark is indicated with a '*'.
884 The active bookmark is indicated with a '*'.
885 When a commit is made, the active bookmark will advance to the new commit.
885 When a commit is made, the active bookmark will advance to the new commit.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
887 Updating away from a bookmark will cause it to be deactivated.
887 Updating away from a bookmark will cause it to be deactivated.
888
888
889 Bookmarks can be pushed and pulled between repositories (see
889 Bookmarks can be pushed and pulled between repositories (see
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
892 be created. Using :hg:`merge` will resolve the divergence.
892 be created. Using :hg:`merge` will resolve the divergence.
893
893
894 A bookmark named '@' has the special property that :hg:`clone` will
894 A bookmark named '@' has the special property that :hg:`clone` will
895 check it out by default if it exists.
895 check it out by default if it exists.
896
896
897 .. container:: verbose
897 .. container:: verbose
898
898
899 Examples:
899 Examples:
900
900
901 - create an active bookmark for a new line of development::
901 - create an active bookmark for a new line of development::
902
902
903 hg book new-feature
903 hg book new-feature
904
904
905 - create an inactive bookmark as a place marker::
905 - create an inactive bookmark as a place marker::
906
906
907 hg book -i reviewed
907 hg book -i reviewed
908
908
909 - create an inactive bookmark on another changeset::
909 - create an inactive bookmark on another changeset::
910
910
911 hg book -r .^ tested
911 hg book -r .^ tested
912
912
913 - move the '@' bookmark from another branch::
913 - move the '@' bookmark from another branch::
914
914
915 hg book -f @
915 hg book -f @
916 '''
916 '''
917 force = opts.get('force')
917 force = opts.get('force')
918 rev = opts.get('rev')
918 rev = opts.get('rev')
919 delete = opts.get('delete')
919 delete = opts.get('delete')
920 rename = opts.get('rename')
920 rename = opts.get('rename')
921 inactive = opts.get('inactive')
921 inactive = opts.get('inactive')
922
922
923 def checkformat(mark):
923 def checkformat(mark):
924 mark = mark.strip()
924 mark = mark.strip()
925 if not mark:
925 if not mark:
926 raise util.Abort(_("bookmark names cannot consist entirely of "
926 raise util.Abort(_("bookmark names cannot consist entirely of "
927 "whitespace"))
927 "whitespace"))
928 scmutil.checknewlabel(repo, mark, 'bookmark')
928 scmutil.checknewlabel(repo, mark, 'bookmark')
929 return mark
929 return mark
930
930
931 def checkconflict(repo, mark, cur, force=False, target=None):
931 def checkconflict(repo, mark, cur, force=False, target=None):
932 if mark in marks and not force:
932 if mark in marks and not force:
933 if target:
933 if target:
934 if marks[mark] == target and target == cur:
934 if marks[mark] == target and target == cur:
935 # re-activating a bookmark
935 # re-activating a bookmark
936 return
936 return
937 anc = repo.changelog.ancestors([repo[target].rev()])
937 anc = repo.changelog.ancestors([repo[target].rev()])
938 bmctx = repo[marks[mark]]
938 bmctx = repo[marks[mark]]
939 divs = [repo[b].node() for b in marks
939 divs = [repo[b].node() for b in marks
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
941
941
942 # allow resolving a single divergent bookmark even if moving
942 # allow resolving a single divergent bookmark even if moving
943 # the bookmark across branches when a revision is specified
943 # the bookmark across branches when a revision is specified
944 # that contains a divergent bookmark
944 # that contains a divergent bookmark
945 if bmctx.rev() not in anc and target in divs:
945 if bmctx.rev() not in anc and target in divs:
946 bookmarks.deletedivergent(repo, [target], mark)
946 bookmarks.deletedivergent(repo, [target], mark)
947 return
947 return
948
948
949 deletefrom = [b for b in divs
949 deletefrom = [b for b in divs
950 if repo[b].rev() in anc or b == target]
950 if repo[b].rev() in anc or b == target]
951 bookmarks.deletedivergent(repo, deletefrom, mark)
951 bookmarks.deletedivergent(repo, deletefrom, mark)
952 if bookmarks.validdest(repo, bmctx, repo[target]):
952 if bookmarks.validdest(repo, bmctx, repo[target]):
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
954 (mark, short(bmctx.node())))
954 (mark, short(bmctx.node())))
955 return
955 return
956 raise util.Abort(_("bookmark '%s' already exists "
956 raise util.Abort(_("bookmark '%s' already exists "
957 "(use -f to force)") % mark)
957 "(use -f to force)") % mark)
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
959 and not force):
959 and not force):
960 raise util.Abort(
960 raise util.Abort(
961 _("a bookmark cannot have the name of an existing branch"))
961 _("a bookmark cannot have the name of an existing branch"))
962
962
963 if delete and rename:
963 if delete and rename:
964 raise util.Abort(_("--delete and --rename are incompatible"))
964 raise util.Abort(_("--delete and --rename are incompatible"))
965 if delete and rev:
965 if delete and rev:
966 raise util.Abort(_("--rev is incompatible with --delete"))
966 raise util.Abort(_("--rev is incompatible with --delete"))
967 if rename and rev:
967 if rename and rev:
968 raise util.Abort(_("--rev is incompatible with --rename"))
968 raise util.Abort(_("--rev is incompatible with --rename"))
969 if not names and (delete or rev):
969 if not names and (delete or rev):
970 raise util.Abort(_("bookmark name required"))
970 raise util.Abort(_("bookmark name required"))
971
971
972 if delete or rename or names or inactive:
972 if delete or rename or names or inactive:
973 wlock = repo.wlock()
973 wlock = repo.wlock()
974 try:
974 try:
975 cur = repo.changectx('.').node()
975 cur = repo.changectx('.').node()
976 marks = repo._bookmarks
976 marks = repo._bookmarks
977 if delete:
977 if delete:
978 for mark in names:
978 for mark in names:
979 if mark not in marks:
979 if mark not in marks:
980 raise util.Abort(_("bookmark '%s' does not exist") %
980 raise util.Abort(_("bookmark '%s' does not exist") %
981 mark)
981 mark)
982 if mark == repo._activebookmark:
982 if mark == repo._activebookmark:
983 bookmarks.deactivate(repo)
983 bookmarks.deactivate(repo)
984 del marks[mark]
984 del marks[mark]
985 marks.write()
985 marks.write()
986
986
987 elif rename:
987 elif rename:
988 if not names:
988 if not names:
989 raise util.Abort(_("new bookmark name required"))
989 raise util.Abort(_("new bookmark name required"))
990 elif len(names) > 1:
990 elif len(names) > 1:
991 raise util.Abort(_("only one new bookmark name allowed"))
991 raise util.Abort(_("only one new bookmark name allowed"))
992 mark = checkformat(names[0])
992 mark = checkformat(names[0])
993 if rename not in marks:
993 if rename not in marks:
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
995 checkconflict(repo, mark, cur, force)
995 checkconflict(repo, mark, cur, force)
996 marks[mark] = marks[rename]
996 marks[mark] = marks[rename]
997 if repo._activebookmark == rename and not inactive:
997 if repo._activebookmark == rename and not inactive:
998 bookmarks.activate(repo, mark)
998 bookmarks.activate(repo, mark)
999 del marks[rename]
999 del marks[rename]
1000 marks.write()
1000 marks.write()
1001
1001
1002 elif names:
1002 elif names:
1003 newact = None
1003 newact = None
1004 for mark in names:
1004 for mark in names:
1005 mark = checkformat(mark)
1005 mark = checkformat(mark)
1006 if newact is None:
1006 if newact is None:
1007 newact = mark
1007 newact = mark
1008 if inactive and mark == repo._activebookmark:
1008 if inactive and mark == repo._activebookmark:
1009 bookmarks.deactivate(repo)
1009 bookmarks.deactivate(repo)
1010 return
1010 return
1011 tgt = cur
1011 tgt = cur
1012 if rev:
1012 if rev:
1013 tgt = scmutil.revsingle(repo, rev).node()
1013 tgt = scmutil.revsingle(repo, rev).node()
1014 checkconflict(repo, mark, cur, force, tgt)
1014 checkconflict(repo, mark, cur, force, tgt)
1015 marks[mark] = tgt
1015 marks[mark] = tgt
1016 if not inactive and cur == marks[newact] and not rev:
1016 if not inactive and cur == marks[newact] and not rev:
1017 bookmarks.activate(repo, newact)
1017 bookmarks.activate(repo, newact)
1018 elif cur != tgt and newact == repo._activebookmark:
1018 elif cur != tgt and newact == repo._activebookmark:
1019 bookmarks.deactivate(repo)
1019 bookmarks.deactivate(repo)
1020 marks.write()
1020 marks.write()
1021
1021
1022 elif inactive:
1022 elif inactive:
1023 if len(marks) == 0:
1023 if len(marks) == 0:
1024 ui.status(_("no bookmarks set\n"))
1024 ui.status(_("no bookmarks set\n"))
1025 elif not repo._activebookmark:
1025 elif not repo._activebookmark:
1026 ui.status(_("no active bookmark\n"))
1026 ui.status(_("no active bookmark\n"))
1027 else:
1027 else:
1028 bookmarks.deactivate(repo)
1028 bookmarks.deactivate(repo)
1029 finally:
1029 finally:
1030 wlock.release()
1030 wlock.release()
1031 else: # show bookmarks
1031 else: # show bookmarks
1032 fm = ui.formatter('bookmarks', opts)
1032 fm = ui.formatter('bookmarks', opts)
1033 hexfn = fm.hexfunc
1033 hexfn = fm.hexfunc
1034 marks = repo._bookmarks
1034 marks = repo._bookmarks
1035 if len(marks) == 0 and not fm:
1035 if len(marks) == 0 and not fm:
1036 ui.status(_("no bookmarks set\n"))
1036 ui.status(_("no bookmarks set\n"))
1037 for bmark, n in sorted(marks.iteritems()):
1037 for bmark, n in sorted(marks.iteritems()):
1038 current = repo._activebookmark
1038 current = repo._activebookmark
1039 if bmark == current:
1039 if bmark == current:
1040 prefix, label = '*', 'bookmarks.current'
1040 prefix, label = '*', 'bookmarks.current'
1041 else:
1041 else:
1042 prefix, label = ' ', ''
1042 prefix, label = ' ', ''
1043
1043
1044 fm.startitem()
1044 fm.startitem()
1045 if not ui.quiet:
1045 if not ui.quiet:
1046 fm.plain(' %s ' % prefix, label=label)
1046 fm.plain(' %s ' % prefix, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1048 pad = " " * (25 - encoding.colwidth(bmark))
1048 pad = " " * (25 - encoding.colwidth(bmark))
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1050 repo.changelog.rev(n), hexfn(n), label=label)
1050 repo.changelog.rev(n), hexfn(n), label=label)
1051 fm.data(active=(bmark == current))
1051 fm.data(active=(bmark == current))
1052 fm.plain('\n')
1052 fm.plain('\n')
1053 fm.end()
1053 fm.end()
1054
1054
1055 @command('branch',
1055 @command('branch',
1056 [('f', 'force', None,
1056 [('f', 'force', None,
1057 _('set branch name even if it shadows an existing branch')),
1057 _('set branch name even if it shadows an existing branch')),
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1059 _('[-fC] [NAME]'))
1059 _('[-fC] [NAME]'))
1060 def branch(ui, repo, label=None, **opts):
1060 def branch(ui, repo, label=None, **opts):
1061 """set or show the current branch name
1061 """set or show the current branch name
1062
1062
1063 .. note::
1063 .. note::
1064
1064
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1067 information about named branches and bookmarks.
1067 information about named branches and bookmarks.
1068
1068
1069 With no argument, show the current branch name. With one argument,
1069 With no argument, show the current branch name. With one argument,
1070 set the working directory branch name (the branch will not exist
1070 set the working directory branch name (the branch will not exist
1071 in the repository until the next commit). Standard practice
1071 in the repository until the next commit). Standard practice
1072 recommends that primary development take place on the 'default'
1072 recommends that primary development take place on the 'default'
1073 branch.
1073 branch.
1074
1074
1075 Unless -f/--force is specified, branch will not let you set a
1075 Unless -f/--force is specified, branch will not let you set a
1076 branch name that already exists.
1076 branch name that already exists.
1077
1077
1078 Use -C/--clean to reset the working directory branch to that of
1078 Use -C/--clean to reset the working directory branch to that of
1079 the parent of the working directory, negating a previous branch
1079 the parent of the working directory, negating a previous branch
1080 change.
1080 change.
1081
1081
1082 Use the command :hg:`update` to switch to an existing branch. Use
1082 Use the command :hg:`update` to switch to an existing branch. Use
1083 :hg:`commit --close-branch` to mark this branch as closed.
1083 :hg:`commit --close-branch` to mark this branch as closed.
1084
1084
1085 Returns 0 on success.
1085 Returns 0 on success.
1086 """
1086 """
1087 if label:
1087 if label:
1088 label = label.strip()
1088 label = label.strip()
1089
1089
1090 if not opts.get('clean') and not label:
1090 if not opts.get('clean') and not label:
1091 ui.write("%s\n" % repo.dirstate.branch())
1091 ui.write("%s\n" % repo.dirstate.branch())
1092 return
1092 return
1093
1093
1094 wlock = repo.wlock()
1094 wlock = repo.wlock()
1095 try:
1095 try:
1096 if opts.get('clean'):
1096 if opts.get('clean'):
1097 label = repo[None].p1().branch()
1097 label = repo[None].p1().branch()
1098 repo.dirstate.setbranch(label)
1098 repo.dirstate.setbranch(label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1100 elif label:
1100 elif label:
1101 if not opts.get('force') and label in repo.branchmap():
1101 if not opts.get('force') and label in repo.branchmap():
1102 if label not in [p.branch() for p in repo.parents()]:
1102 if label not in [p.branch() for p in repo.parents()]:
1103 raise util.Abort(_('a branch of the same name already'
1103 raise util.Abort(_('a branch of the same name already'
1104 ' exists'),
1104 ' exists'),
1105 # i18n: "it" refers to an existing branch
1105 # i18n: "it" refers to an existing branch
1106 hint=_("use 'hg update' to switch to it"))
1106 hint=_("use 'hg update' to switch to it"))
1107 scmutil.checknewlabel(repo, label, 'branch')
1107 scmutil.checknewlabel(repo, label, 'branch')
1108 repo.dirstate.setbranch(label)
1108 repo.dirstate.setbranch(label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1110 ui.status(_('(branches are permanent and global, '
1110 ui.status(_('(branches are permanent and global, '
1111 'did you want a bookmark?)\n'))
1111 'did you want a bookmark?)\n'))
1112 finally:
1112 finally:
1113 wlock.release()
1113 wlock.release()
1114
1114
1115 @command('branches',
1115 @command('branches',
1116 [('a', 'active', False,
1116 [('a', 'active', False,
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1119 ] + formatteropts,
1119 ] + formatteropts,
1120 _('[-ac]'))
1120 _('[-ac]'))
1121 def branches(ui, repo, active=False, closed=False, **opts):
1121 def branches(ui, repo, active=False, closed=False, **opts):
1122 """list repository named branches
1122 """list repository named branches
1123
1123
1124 List the repository's named branches, indicating which ones are
1124 List the repository's named branches, indicating which ones are
1125 inactive. If -c/--closed is specified, also list branches which have
1125 inactive. If -c/--closed is specified, also list branches which have
1126 been marked closed (see :hg:`commit --close-branch`).
1126 been marked closed (see :hg:`commit --close-branch`).
1127
1127
1128 Use the command :hg:`update` to switch to an existing branch.
1128 Use the command :hg:`update` to switch to an existing branch.
1129
1129
1130 Returns 0.
1130 Returns 0.
1131 """
1131 """
1132
1132
1133 fm = ui.formatter('branches', opts)
1133 fm = ui.formatter('branches', opts)
1134 hexfunc = fm.hexfunc
1134 hexfunc = fm.hexfunc
1135
1135
1136 allheads = set(repo.heads())
1136 allheads = set(repo.heads())
1137 branches = []
1137 branches = []
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1139 isactive = not isclosed and bool(set(heads) & allheads)
1139 isactive = not isclosed and bool(set(heads) & allheads)
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1142 reverse=True)
1142 reverse=True)
1143
1143
1144 for tag, ctx, isactive, isopen in branches:
1144 for tag, ctx, isactive, isopen in branches:
1145 if active and not isactive:
1145 if active and not isactive:
1146 continue
1146 continue
1147 if isactive:
1147 if isactive:
1148 label = 'branches.active'
1148 label = 'branches.active'
1149 notice = ''
1149 notice = ''
1150 elif not isopen:
1150 elif not isopen:
1151 if not closed:
1151 if not closed:
1152 continue
1152 continue
1153 label = 'branches.closed'
1153 label = 'branches.closed'
1154 notice = _(' (closed)')
1154 notice = _(' (closed)')
1155 else:
1155 else:
1156 label = 'branches.inactive'
1156 label = 'branches.inactive'
1157 notice = _(' (inactive)')
1157 notice = _(' (inactive)')
1158 current = (tag == repo.dirstate.branch())
1158 current = (tag == repo.dirstate.branch())
1159 if current:
1159 if current:
1160 label = 'branches.current'
1160 label = 'branches.current'
1161
1161
1162 fm.startitem()
1162 fm.startitem()
1163 fm.write('branch', '%s', tag, label=label)
1163 fm.write('branch', '%s', tag, label=label)
1164 rev = ctx.rev()
1164 rev = ctx.rev()
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1166 fmt = ' ' * padsize + ' %d:%s'
1166 fmt = ' ' * padsize + ' %d:%s'
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1169 fm.data(active=isactive, closed=not isopen, current=current)
1169 fm.data(active=isactive, closed=not isopen, current=current)
1170 if not ui.quiet:
1170 if not ui.quiet:
1171 fm.plain(notice)
1171 fm.plain(notice)
1172 fm.plain('\n')
1172 fm.plain('\n')
1173 fm.end()
1173 fm.end()
1174
1174
1175 @command('bundle',
1175 @command('bundle',
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1178 _('REV')),
1178 _('REV')),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1180 _('BRANCH')),
1180 _('BRANCH')),
1181 ('', 'base', [],
1181 ('', 'base', [],
1182 _('a base changeset assumed to be available at the destination'),
1182 _('a base changeset assumed to be available at the destination'),
1183 _('REV')),
1183 _('REV')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1186 ] + remoteopts,
1186 ] + remoteopts,
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1188 def bundle(ui, repo, fname, dest=None, **opts):
1188 def bundle(ui, repo, fname, dest=None, **opts):
1189 """create a changegroup file
1189 """create a changegroup file
1190
1190
1191 Generate a compressed changegroup file collecting changesets not
1191 Generate a compressed changegroup file collecting changesets not
1192 known to be in another repository.
1192 known to be in another repository.
1193
1193
1194 If you omit the destination repository, then hg assumes the
1194 If you omit the destination repository, then hg assumes the
1195 destination will have all the nodes you specify with --base
1195 destination will have all the nodes you specify with --base
1196 parameters. To create a bundle containing all changesets, use
1196 parameters. To create a bundle containing all changesets, use
1197 -a/--all (or --base null).
1197 -a/--all (or --base null).
1198
1198
1199 You can change compression method with the -t/--type option.
1199 You can change compression method with the -t/--type option.
1200 The available compression methods are: none, bzip2, and
1200 The available compression methods are: none, bzip2, and
1201 gzip (by default, bundles are compressed using bzip2).
1201 gzip (by default, bundles are compressed using bzip2).
1202
1202
1203 The bundle file can then be transferred using conventional means
1203 The bundle file can then be transferred using conventional means
1204 and applied to another repository with the unbundle or pull
1204 and applied to another repository with the unbundle or pull
1205 command. This is useful when direct push and pull are not
1205 command. This is useful when direct push and pull are not
1206 available or when exporting an entire repository is undesirable.
1206 available or when exporting an entire repository is undesirable.
1207
1207
1208 Applying bundles preserves all changeset contents including
1208 Applying bundles preserves all changeset contents including
1209 permissions, copy/rename information, and revision history.
1209 permissions, copy/rename information, and revision history.
1210
1210
1211 Returns 0 on success, 1 if no changes found.
1211 Returns 0 on success, 1 if no changes found.
1212 """
1212 """
1213 revs = None
1213 revs = None
1214 if 'rev' in opts:
1214 if 'rev' in opts:
1215 revs = scmutil.revrange(repo, opts['rev'])
1215 revs = scmutil.revrange(repo, opts['rev'])
1216
1216
1217 bundletype = opts.get('type', 'bzip2').lower()
1217 bundletype = opts.get('type', 'bzip2').lower()
1218 btypes = {'none': 'HG10UN',
1218 btypes = {'none': 'HG10UN',
1219 'bzip2': 'HG10BZ',
1219 'bzip2': 'HG10BZ',
1220 'gzip': 'HG10GZ',
1220 'gzip': 'HG10GZ',
1221 'bundle2': 'HG20'}
1221 'bundle2': 'HG20'}
1222 bundletype = btypes.get(bundletype)
1222 bundletype = btypes.get(bundletype)
1223 if bundletype not in changegroup.bundletypes:
1223 if bundletype not in changegroup.bundletypes:
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1225
1225
1226 if opts.get('all'):
1226 if opts.get('all'):
1227 base = ['null']
1227 base = ['null']
1228 else:
1228 else:
1229 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1230 # TODO: get desired bundlecaps from command line.
1230 # TODO: get desired bundlecaps from command line.
1231 bundlecaps = None
1231 bundlecaps = None
1232 if base:
1232 if base:
1233 if dest:
1233 if dest:
1234 raise util.Abort(_("--base is incompatible with specifying "
1234 raise util.Abort(_("--base is incompatible with specifying "
1235 "a destination"))
1235 "a destination"))
1236 common = [repo.lookup(rev) for rev in base]
1236 common = [repo.lookup(rev) for rev in base]
1237 heads = revs and map(repo.lookup, revs) or revs
1237 heads = revs and map(repo.lookup, revs) or revs
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1239 common=common, bundlecaps=bundlecaps)
1239 common=common, bundlecaps=bundlecaps)
1240 outgoing = None
1240 outgoing = None
1241 else:
1241 else:
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1244 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 heads = revs and map(repo.lookup, revs) or revs
1246 heads = revs and map(repo.lookup, revs) or revs
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1248 onlyheads=heads,
1248 onlyheads=heads,
1249 force=opts.get('force'),
1249 force=opts.get('force'),
1250 portable=True)
1250 portable=True)
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1252 bundlecaps)
1252 bundlecaps)
1253 if not cg:
1253 if not cg:
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1255 return 1
1255 return 1
1256
1256
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1258
1258
1259 @command('cat',
1259 @command('cat',
1260 [('o', 'output', '',
1260 [('o', 'output', '',
1261 _('print output to file with formatted name'), _('FORMAT')),
1261 _('print output to file with formatted name'), _('FORMAT')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1264 ] + walkopts,
1264 ] + walkopts,
1265 _('[OPTION]... FILE...'),
1265 _('[OPTION]... FILE...'),
1266 inferrepo=True)
1266 inferrepo=True)
1267 def cat(ui, repo, file1, *pats, **opts):
1267 def cat(ui, repo, file1, *pats, **opts):
1268 """output the current or given revision of files
1268 """output the current or given revision of files
1269
1269
1270 Print the specified files as they were at the given revision. If
1270 Print the specified files as they were at the given revision. If
1271 no revision is given, the parent of the working directory is used.
1271 no revision is given, the parent of the working directory is used.
1272
1272
1273 Output may be to a file, in which case the name of the file is
1273 Output may be to a file, in which case the name of the file is
1274 given using a format string. The formatting rules as follows:
1274 given using a format string. The formatting rules as follows:
1275
1275
1276 :``%%``: literal "%" character
1276 :``%%``: literal "%" character
1277 :``%s``: basename of file being printed
1277 :``%s``: basename of file being printed
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1279 :``%p``: root-relative path name of file being printed
1279 :``%p``: root-relative path name of file being printed
1280 :``%H``: changeset hash (40 hexadecimal digits)
1280 :``%H``: changeset hash (40 hexadecimal digits)
1281 :``%R``: changeset revision number
1281 :``%R``: changeset revision number
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1283 :``%r``: zero-padded changeset revision number
1283 :``%r``: zero-padded changeset revision number
1284 :``%b``: basename of the exporting repository
1284 :``%b``: basename of the exporting repository
1285
1285
1286 Returns 0 on success.
1286 Returns 0 on success.
1287 """
1287 """
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1290
1290
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1292
1292
1293 @command('^clone',
1293 @command('^clone',
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1295 'directory (only a repository)')),
1295 'directory (only a repository)')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1301 ] + remoteopts,
1301 ] + remoteopts,
1302 _('[OPTION]... SOURCE [DEST]'),
1302 _('[OPTION]... SOURCE [DEST]'),
1303 norepo=True)
1303 norepo=True)
1304 def clone(ui, source, dest=None, **opts):
1304 def clone(ui, source, dest=None, **opts):
1305 """make a copy of an existing repository
1305 """make a copy of an existing repository
1306
1306
1307 Create a copy of an existing repository in a new directory.
1307 Create a copy of an existing repository in a new directory.
1308
1308
1309 If no destination directory name is specified, it defaults to the
1309 If no destination directory name is specified, it defaults to the
1310 basename of the source.
1310 basename of the source.
1311
1311
1312 The location of the source is added to the new repository's
1312 The location of the source is added to the new repository's
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1314
1314
1315 Only local paths and ``ssh://`` URLs are supported as
1315 Only local paths and ``ssh://`` URLs are supported as
1316 destinations. For ``ssh://`` destinations, no working directory or
1316 destinations. For ``ssh://`` destinations, no working directory or
1317 ``.hg/hgrc`` will be created on the remote side.
1317 ``.hg/hgrc`` will be created on the remote side.
1318
1318
1319 To pull only a subset of changesets, specify one or more revisions
1319 To pull only a subset of changesets, specify one or more revisions
1320 identifiers with -r/--rev or branches with -b/--branch. The
1320 identifiers with -r/--rev or branches with -b/--branch. The
1321 resulting clone will contain only the specified changesets and
1321 resulting clone will contain only the specified changesets and
1322 their ancestors. These options (or 'clone src#rev dest') imply
1322 their ancestors. These options (or 'clone src#rev dest') imply
1323 --pull, even for local source repositories. Note that specifying a
1323 --pull, even for local source repositories. Note that specifying a
1324 tag will include the tagged changeset but not the changeset
1324 tag will include the tagged changeset but not the changeset
1325 containing the tag.
1325 containing the tag.
1326
1326
1327 If the source repository has a bookmark called '@' set, that
1327 If the source repository has a bookmark called '@' set, that
1328 revision will be checked out in the new repository by default.
1328 revision will be checked out in the new repository by default.
1329
1329
1330 To check out a particular version, use -u/--update, or
1330 To check out a particular version, use -u/--update, or
1331 -U/--noupdate to create a clone with no working directory.
1331 -U/--noupdate to create a clone with no working directory.
1332
1332
1333 .. container:: verbose
1333 .. container:: verbose
1334
1334
1335 For efficiency, hardlinks are used for cloning whenever the
1335 For efficiency, hardlinks are used for cloning whenever the
1336 source and destination are on the same filesystem (note this
1336 source and destination are on the same filesystem (note this
1337 applies only to the repository data, not to the working
1337 applies only to the repository data, not to the working
1338 directory). Some filesystems, such as AFS, implement hardlinking
1338 directory). Some filesystems, such as AFS, implement hardlinking
1339 incorrectly, but do not report errors. In these cases, use the
1339 incorrectly, but do not report errors. In these cases, use the
1340 --pull option to avoid hardlinking.
1340 --pull option to avoid hardlinking.
1341
1341
1342 In some cases, you can clone repositories and the working
1342 In some cases, you can clone repositories and the working
1343 directory using full hardlinks with ::
1343 directory using full hardlinks with ::
1344
1344
1345 $ cp -al REPO REPOCLONE
1345 $ cp -al REPO REPOCLONE
1346
1346
1347 This is the fastest way to clone, but it is not always safe. The
1347 This is the fastest way to clone, but it is not always safe. The
1348 operation is not atomic (making sure REPO is not modified during
1348 operation is not atomic (making sure REPO is not modified during
1349 the operation is up to you) and you have to make sure your
1349 the operation is up to you) and you have to make sure your
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1351 so). Also, this is not compatible with certain extensions that
1351 so). Also, this is not compatible with certain extensions that
1352 place their metadata under the .hg directory, such as mq.
1352 place their metadata under the .hg directory, such as mq.
1353
1353
1354 Mercurial will update the working directory to the first applicable
1354 Mercurial will update the working directory to the first applicable
1355 revision from this list:
1355 revision from this list:
1356
1356
1357 a) null if -U or the source repository has no changesets
1357 a) null if -U or the source repository has no changesets
1358 b) if -u . and the source repository is local, the first parent of
1358 b) if -u . and the source repository is local, the first parent of
1359 the source repository's working directory
1359 the source repository's working directory
1360 c) the changeset specified with -u (if a branch name, this means the
1360 c) the changeset specified with -u (if a branch name, this means the
1361 latest head of that branch)
1361 latest head of that branch)
1362 d) the changeset specified with -r
1362 d) the changeset specified with -r
1363 e) the tipmost head specified with -b
1363 e) the tipmost head specified with -b
1364 f) the tipmost head specified with the url#branch source syntax
1364 f) the tipmost head specified with the url#branch source syntax
1365 g) the revision marked with the '@' bookmark, if present
1365 g) the revision marked with the '@' bookmark, if present
1366 h) the tipmost head of the default branch
1366 h) the tipmost head of the default branch
1367 i) tip
1367 i) tip
1368
1368
1369 Examples:
1369 Examples:
1370
1370
1371 - clone a remote repository to a new directory named hg/::
1371 - clone a remote repository to a new directory named hg/::
1372
1372
1373 hg clone http://selenic.com/hg
1373 hg clone http://selenic.com/hg
1374
1374
1375 - create a lightweight local clone::
1375 - create a lightweight local clone::
1376
1376
1377 hg clone project/ project-feature/
1377 hg clone project/ project-feature/
1378
1378
1379 - clone from an absolute path on an ssh server (note double-slash)::
1379 - clone from an absolute path on an ssh server (note double-slash)::
1380
1380
1381 hg clone ssh://user@server//home/projects/alpha/
1381 hg clone ssh://user@server//home/projects/alpha/
1382
1382
1383 - do a high-speed clone over a LAN while checking out a
1383 - do a high-speed clone over a LAN while checking out a
1384 specified version::
1384 specified version::
1385
1385
1386 hg clone --uncompressed http://server/repo -u 1.5
1386 hg clone --uncompressed http://server/repo -u 1.5
1387
1387
1388 - create a repository without changesets after a particular revision::
1388 - create a repository without changesets after a particular revision::
1389
1389
1390 hg clone -r 04e544 experimental/ good/
1390 hg clone -r 04e544 experimental/ good/
1391
1391
1392 - clone (and track) a particular named branch::
1392 - clone (and track) a particular named branch::
1393
1393
1394 hg clone http://selenic.com/hg#stable
1394 hg clone http://selenic.com/hg#stable
1395
1395
1396 See :hg:`help urls` for details on specifying URLs.
1396 See :hg:`help urls` for details on specifying URLs.
1397
1397
1398 Returns 0 on success.
1398 Returns 0 on success.
1399 """
1399 """
1400 if opts.get('noupdate') and opts.get('updaterev'):
1400 if opts.get('noupdate') and opts.get('updaterev'):
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1402
1402
1403 r = hg.clone(ui, opts, source, dest,
1403 r = hg.clone(ui, opts, source, dest,
1404 pull=opts.get('pull'),
1404 pull=opts.get('pull'),
1405 stream=opts.get('uncompressed'),
1405 stream=opts.get('uncompressed'),
1406 rev=opts.get('rev'),
1406 rev=opts.get('rev'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1408 branch=opts.get('branch'))
1408 branch=opts.get('branch'))
1409
1409
1410 return r is None
1410 return r is None
1411
1411
1412 @command('^commit|ci',
1412 @command('^commit|ci',
1413 [('A', 'addremove', None,
1413 [('A', 'addremove', None,
1414 _('mark new/missing files as added/removed before committing')),
1414 _('mark new/missing files as added/removed before committing')),
1415 ('', 'close-branch', None,
1415 ('', 'close-branch', None,
1416 _('mark a branch as closed, hiding it from the branch list')),
1416 _('mark a branch as closed, hiding it from the branch list')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1422 _('[OPTION]... [FILE]...'),
1422 _('[OPTION]... [FILE]...'),
1423 inferrepo=True)
1423 inferrepo=True)
1424 def commit(ui, repo, *pats, **opts):
1424 def commit(ui, repo, *pats, **opts):
1425 """commit the specified files or all outstanding changes
1425 """commit the specified files or all outstanding changes
1426
1426
1427 Commit changes to the given files into the repository. Unlike a
1427 Commit changes to the given files into the repository. Unlike a
1428 centralized SCM, this operation is a local operation. See
1428 centralized SCM, this operation is a local operation. See
1429 :hg:`push` for a way to actively distribute your changes.
1429 :hg:`push` for a way to actively distribute your changes.
1430
1430
1431 If a list of files is omitted, all changes reported by :hg:`status`
1431 If a list of files is omitted, all changes reported by :hg:`status`
1432 will be committed.
1432 will be committed.
1433
1433
1434 If you are committing the result of a merge, do not provide any
1434 If you are committing the result of a merge, do not provide any
1435 filenames or -I/-X filters.
1435 filenames or -I/-X filters.
1436
1436
1437 If no commit message is specified, Mercurial starts your
1437 If no commit message is specified, Mercurial starts your
1438 configured editor where you can enter a message. In case your
1438 configured editor where you can enter a message. In case your
1439 commit fails, you will find a backup of your message in
1439 commit fails, you will find a backup of your message in
1440 ``.hg/last-message.txt``.
1440 ``.hg/last-message.txt``.
1441
1441
1442 The --amend flag can be used to amend the parent of the
1442 The --amend flag can be used to amend the parent of the
1443 working directory with a new commit that contains the changes
1443 working directory with a new commit that contains the changes
1444 in the parent in addition to those currently reported by :hg:`status`,
1444 in the parent in addition to those currently reported by :hg:`status`,
1445 if there are any. The old commit is stored in a backup bundle in
1445 if there are any. The old commit is stored in a backup bundle in
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1447 on how to restore it).
1447 on how to restore it).
1448
1448
1449 Message, user and date are taken from the amended commit unless
1449 Message, user and date are taken from the amended commit unless
1450 specified. When a message isn't specified on the command line,
1450 specified. When a message isn't specified on the command line,
1451 the editor will open with the message of the amended commit.
1451 the editor will open with the message of the amended commit.
1452
1452
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1454 or changesets that have children.
1454 or changesets that have children.
1455
1455
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1457
1457
1458 Returns 0 on success, 1 if nothing changed.
1458 Returns 0 on success, 1 if nothing changed.
1459 """
1459 """
1460 if opts.get('interactive'):
1460 if opts.get('interactive'):
1461 opts.pop('interactive')
1461 opts.pop('interactive')
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1463 cmdutil.recordfilter, *pats, **opts)
1463 cmdutil.recordfilter, *pats, **opts)
1464 return
1464 return
1465
1465
1466 if opts.get('subrepos'):
1466 if opts.get('subrepos'):
1467 if opts.get('amend'):
1467 if opts.get('amend'):
1468 raise util.Abort(_('cannot amend with --subrepos'))
1468 raise util.Abort(_('cannot amend with --subrepos'))
1469 # Let --subrepos on the command line override config setting.
1469 # Let --subrepos on the command line override config setting.
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1471
1471
1472 cmdutil.checkunfinished(repo, commit=True)
1472 cmdutil.checkunfinished(repo, commit=True)
1473
1473
1474 branch = repo[None].branch()
1474 branch = repo[None].branch()
1475 bheads = repo.branchheads(branch)
1475 bheads = repo.branchheads(branch)
1476
1476
1477 extra = {}
1477 extra = {}
1478 if opts.get('close_branch'):
1478 if opts.get('close_branch'):
1479 extra['close'] = 1
1479 extra['close'] = 1
1480
1480
1481 if not bheads:
1481 if not bheads:
1482 raise util.Abort(_('can only close branch heads'))
1482 raise util.Abort(_('can only close branch heads'))
1483 elif opts.get('amend'):
1483 elif opts.get('amend'):
1484 if repo.parents()[0].p1().branch() != branch and \
1484 if repo.parents()[0].p1().branch() != branch and \
1485 repo.parents()[0].p2().branch() != branch:
1485 repo.parents()[0].p2().branch() != branch:
1486 raise util.Abort(_('can only close branch heads'))
1486 raise util.Abort(_('can only close branch heads'))
1487
1487
1488 if opts.get('amend'):
1488 if opts.get('amend'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1491
1491
1492 old = repo['.']
1492 old = repo['.']
1493 if not old.mutable():
1493 if not old.mutable():
1494 raise util.Abort(_('cannot amend public changesets'))
1494 raise util.Abort(_('cannot amend public changesets'))
1495 if len(repo[None].parents()) > 1:
1495 if len(repo[None].parents()) > 1:
1496 raise util.Abort(_('cannot amend while merging'))
1496 raise util.Abort(_('cannot amend while merging'))
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1498 if not allowunstable and old.children():
1498 if not allowunstable and old.children():
1499 raise util.Abort(_('cannot amend changeset with children'))
1499 raise util.Abort(_('cannot amend changeset with children'))
1500
1500
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1502 def commitfunc(ui, repo, message, match, opts):
1502 def commitfunc(ui, repo, message, match, opts):
1503 return repo.commit(message,
1503 return repo.commit(message,
1504 opts.get('user') or old.user(),
1504 opts.get('user') or old.user(),
1505 opts.get('date') or old.date(),
1505 opts.get('date') or old.date(),
1506 match,
1506 match,
1507 extra=extra)
1507 extra=extra)
1508
1508
1509 current = repo._activebookmark
1509 current = repo._activebookmark
1510 marks = old.bookmarks()
1510 marks = old.bookmarks()
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1512 if node == old.node():
1512 if node == old.node():
1513 ui.status(_("nothing changed\n"))
1513 ui.status(_("nothing changed\n"))
1514 return 1
1514 return 1
1515 elif marks:
1515 elif marks:
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1517 (marks, old.hex(), hex(node)))
1517 (marks, old.hex(), hex(node)))
1518 newmarks = repo._bookmarks
1518 newmarks = repo._bookmarks
1519 for bm in marks:
1519 for bm in marks:
1520 newmarks[bm] = node
1520 newmarks[bm] = node
1521 if bm == current:
1521 if bm == current:
1522 bookmarks.activate(repo, bm)
1522 bookmarks.activate(repo, bm)
1523 newmarks.write()
1523 newmarks.write()
1524 else:
1524 else:
1525 def commitfunc(ui, repo, message, match, opts):
1525 def commitfunc(ui, repo, message, match, opts):
1526 backup = ui.backupconfig('phases', 'new-commit')
1526 backup = ui.backupconfig('phases', 'new-commit')
1527 baseui = repo.baseui
1527 baseui = repo.baseui
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1529 try:
1529 try:
1530 if opts.get('secret'):
1530 if opts.get('secret'):
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1532 # Propagate to subrepos
1532 # Propagate to subrepos
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1534
1534
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1538 match,
1538 match,
1539 editor=editor,
1539 editor=editor,
1540 extra=extra)
1540 extra=extra)
1541 finally:
1541 finally:
1542 ui.restoreconfig(backup)
1542 ui.restoreconfig(backup)
1543 repo.baseui.restoreconfig(basebackup)
1543 repo.baseui.restoreconfig(basebackup)
1544
1544
1545
1545
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1547
1547
1548 if not node:
1548 if not node:
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1550 if stat[3]:
1550 if stat[3]:
1551 ui.status(_("nothing changed (%d missing files, see "
1551 ui.status(_("nothing changed (%d missing files, see "
1552 "'hg status')\n") % len(stat[3]))
1552 "'hg status')\n") % len(stat[3]))
1553 else:
1553 else:
1554 ui.status(_("nothing changed\n"))
1554 ui.status(_("nothing changed\n"))
1555 return 1
1555 return 1
1556
1556
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1558
1558
1559 @command('config|showconfig|debugconfig',
1559 @command('config|showconfig|debugconfig',
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1561 ('e', 'edit', None, _('edit user config')),
1561 ('e', 'edit', None, _('edit user config')),
1562 ('l', 'local', None, _('edit repository config')),
1562 ('l', 'local', None, _('edit repository config')),
1563 ('g', 'global', None, _('edit global config'))],
1563 ('g', 'global', None, _('edit global config'))],
1564 _('[-u] [NAME]...'),
1564 _('[-u] [NAME]...'),
1565 optionalrepo=True)
1565 optionalrepo=True)
1566 def config(ui, repo, *values, **opts):
1566 def config(ui, repo, *values, **opts):
1567 """show combined config settings from all hgrc files
1567 """show combined config settings from all hgrc files
1568
1568
1569 With no arguments, print names and values of all config items.
1569 With no arguments, print names and values of all config items.
1570
1570
1571 With one argument of the form section.name, print just the value
1571 With one argument of the form section.name, print just the value
1572 of that config item.
1572 of that config item.
1573
1573
1574 With multiple arguments, print names and values of all config
1574 With multiple arguments, print names and values of all config
1575 items with matching section names.
1575 items with matching section names.
1576
1576
1577 With --edit, start an editor on the user-level config file. With
1577 With --edit, start an editor on the user-level config file. With
1578 --global, edit the system-wide config file. With --local, edit the
1578 --global, edit the system-wide config file. With --local, edit the
1579 repository-level config file.
1579 repository-level config file.
1580
1580
1581 With --debug, the source (filename and line number) is printed
1581 With --debug, the source (filename and line number) is printed
1582 for each config item.
1582 for each config item.
1583
1583
1584 See :hg:`help config` for more information about config files.
1584 See :hg:`help config` for more information about config files.
1585
1585
1586 Returns 0 on success, 1 if NAME does not exist.
1586 Returns 0 on success, 1 if NAME does not exist.
1587
1587
1588 """
1588 """
1589
1589
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1592 raise util.Abort(_("can't use --local and --global together"))
1592 raise util.Abort(_("can't use --local and --global together"))
1593
1593
1594 if opts.get('local'):
1594 if opts.get('local'):
1595 if not repo:
1595 if not repo:
1596 raise util.Abort(_("can't use --local outside a repository"))
1596 raise util.Abort(_("can't use --local outside a repository"))
1597 paths = [repo.join('hgrc')]
1597 paths = [repo.join('hgrc')]
1598 elif opts.get('global'):
1598 elif opts.get('global'):
1599 paths = scmutil.systemrcpath()
1599 paths = scmutil.systemrcpath()
1600 else:
1600 else:
1601 paths = scmutil.userrcpath()
1601 paths = scmutil.userrcpath()
1602
1602
1603 for f in paths:
1603 for f in paths:
1604 if os.path.exists(f):
1604 if os.path.exists(f):
1605 break
1605 break
1606 else:
1606 else:
1607 if opts.get('global'):
1607 if opts.get('global'):
1608 samplehgrc = uimod.samplehgrcs['global']
1608 samplehgrc = uimod.samplehgrcs['global']
1609 elif opts.get('local'):
1609 elif opts.get('local'):
1610 samplehgrc = uimod.samplehgrcs['local']
1610 samplehgrc = uimod.samplehgrcs['local']
1611 else:
1611 else:
1612 samplehgrc = uimod.samplehgrcs['user']
1612 samplehgrc = uimod.samplehgrcs['user']
1613
1613
1614 f = paths[0]
1614 f = paths[0]
1615 fp = open(f, "w")
1615 fp = open(f, "w")
1616 fp.write(samplehgrc)
1616 fp.write(samplehgrc)
1617 fp.close()
1617 fp.close()
1618
1618
1619 editor = ui.geteditor()
1619 editor = ui.geteditor()
1620 ui.system("%s \"%s\"" % (editor, f),
1620 ui.system("%s \"%s\"" % (editor, f),
1621 onerr=util.Abort, errprefix=_("edit failed"))
1621 onerr=util.Abort, errprefix=_("edit failed"))
1622 return
1622 return
1623
1623
1624 for f in scmutil.rcpath():
1624 for f in scmutil.rcpath():
1625 ui.debug('read config from: %s\n' % f)
1625 ui.debug('read config from: %s\n' % f)
1626 untrusted = bool(opts.get('untrusted'))
1626 untrusted = bool(opts.get('untrusted'))
1627 if values:
1627 if values:
1628 sections = [v for v in values if '.' not in v]
1628 sections = [v for v in values if '.' not in v]
1629 items = [v for v in values if '.' in v]
1629 items = [v for v in values if '.' in v]
1630 if len(items) > 1 or items and sections:
1630 if len(items) > 1 or items and sections:
1631 raise util.Abort(_('only one config item permitted'))
1631 raise util.Abort(_('only one config item permitted'))
1632 matched = False
1632 matched = False
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1634 value = str(value).replace('\n', '\\n')
1634 value = str(value).replace('\n', '\\n')
1635 sectname = section + '.' + name
1635 sectname = section + '.' + name
1636 if values:
1636 if values:
1637 for v in values:
1637 for v in values:
1638 if v == section:
1638 if v == section:
1639 ui.debug('%s: ' %
1639 ui.debug('%s: ' %
1640 ui.configsource(section, name, untrusted))
1640 ui.configsource(section, name, untrusted))
1641 ui.write('%s=%s\n' % (sectname, value))
1641 ui.write('%s=%s\n' % (sectname, value))
1642 matched = True
1642 matched = True
1643 elif v == sectname:
1643 elif v == sectname:
1644 ui.debug('%s: ' %
1644 ui.debug('%s: ' %
1645 ui.configsource(section, name, untrusted))
1645 ui.configsource(section, name, untrusted))
1646 ui.write(value, '\n')
1646 ui.write(value, '\n')
1647 matched = True
1647 matched = True
1648 else:
1648 else:
1649 ui.debug('%s: ' %
1649 ui.debug('%s: ' %
1650 ui.configsource(section, name, untrusted))
1650 ui.configsource(section, name, untrusted))
1651 ui.write('%s=%s\n' % (sectname, value))
1651 ui.write('%s=%s\n' % (sectname, value))
1652 matched = True
1652 matched = True
1653 if matched:
1653 if matched:
1654 return 0
1654 return 0
1655 return 1
1655 return 1
1656
1656
1657 @command('copy|cp',
1657 @command('copy|cp',
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1660 ] + walkopts + dryrunopts,
1660 ] + walkopts + dryrunopts,
1661 _('[OPTION]... [SOURCE]... DEST'))
1661 _('[OPTION]... [SOURCE]... DEST'))
1662 def copy(ui, repo, *pats, **opts):
1662 def copy(ui, repo, *pats, **opts):
1663 """mark files as copied for the next commit
1663 """mark files as copied for the next commit
1664
1664
1665 Mark dest as having copies of source files. If dest is a
1665 Mark dest as having copies of source files. If dest is a
1666 directory, copies are put in that directory. If dest is a file,
1666 directory, copies are put in that directory. If dest is a file,
1667 the source must be a single file.
1667 the source must be a single file.
1668
1668
1669 By default, this command copies the contents of files as they
1669 By default, this command copies the contents of files as they
1670 exist in the working directory. If invoked with -A/--after, the
1670 exist in the working directory. If invoked with -A/--after, the
1671 operation is recorded, but no copying is performed.
1671 operation is recorded, but no copying is performed.
1672
1672
1673 This command takes effect with the next commit. To undo a copy
1673 This command takes effect with the next commit. To undo a copy
1674 before that, see :hg:`revert`.
1674 before that, see :hg:`revert`.
1675
1675
1676 Returns 0 on success, 1 if errors are encountered.
1676 Returns 0 on success, 1 if errors are encountered.
1677 """
1677 """
1678 wlock = repo.wlock(False)
1678 wlock = repo.wlock(False)
1679 try:
1679 try:
1680 return cmdutil.copy(ui, repo, pats, opts)
1680 return cmdutil.copy(ui, repo, pats, opts)
1681 finally:
1681 finally:
1682 wlock.release()
1682 wlock.release()
1683
1683
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1685 def debugancestor(ui, repo, *args):
1685 def debugancestor(ui, repo, *args):
1686 """find the ancestor revision of two revisions in a given index"""
1686 """find the ancestor revision of two revisions in a given index"""
1687 if len(args) == 3:
1687 if len(args) == 3:
1688 index, rev1, rev2 = args
1688 index, rev1, rev2 = args
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1690 lookup = r.lookup
1690 lookup = r.lookup
1691 elif len(args) == 2:
1691 elif len(args) == 2:
1692 if not repo:
1692 if not repo:
1693 raise util.Abort(_("there is no Mercurial repository here "
1693 raise util.Abort(_("there is no Mercurial repository here "
1694 "(.hg not found)"))
1694 "(.hg not found)"))
1695 rev1, rev2 = args
1695 rev1, rev2 = args
1696 r = repo.changelog
1696 r = repo.changelog
1697 lookup = repo.lookup
1697 lookup = repo.lookup
1698 else:
1698 else:
1699 raise util.Abort(_('either two or three arguments required'))
1699 raise util.Abort(_('either two or three arguments required'))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1702
1702
1703 @command('debugbuilddag',
1703 @command('debugbuilddag',
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1707 _('[OPTION]... [TEXT]'))
1707 _('[OPTION]... [TEXT]'))
1708 def debugbuilddag(ui, repo, text=None,
1708 def debugbuilddag(ui, repo, text=None,
1709 mergeable_file=False,
1709 mergeable_file=False,
1710 overwritten_file=False,
1710 overwritten_file=False,
1711 new_file=False):
1711 new_file=False):
1712 """builds a repo with a given DAG from scratch in the current empty repo
1712 """builds a repo with a given DAG from scratch in the current empty repo
1713
1713
1714 The description of the DAG is read from stdin if not given on the
1714 The description of the DAG is read from stdin if not given on the
1715 command line.
1715 command line.
1716
1716
1717 Elements:
1717 Elements:
1718
1718
1719 - "+n" is a linear run of n nodes based on the current default parent
1719 - "+n" is a linear run of n nodes based on the current default parent
1720 - "." is a single node based on the current default parent
1720 - "." is a single node based on the current default parent
1721 - "$" resets the default parent to null (implied at the start);
1721 - "$" resets the default parent to null (implied at the start);
1722 otherwise the default parent is always the last node created
1722 otherwise the default parent is always the last node created
1723 - "<p" sets the default parent to the backref p
1723 - "<p" sets the default parent to the backref p
1724 - "*p" is a fork at parent p, which is a backref
1724 - "*p" is a fork at parent p, which is a backref
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1726 - "/p2" is a merge of the preceding node and p2
1726 - "/p2" is a merge of the preceding node and p2
1727 - ":tag" defines a local tag for the preceding node
1727 - ":tag" defines a local tag for the preceding node
1728 - "@branch" sets the named branch for subsequent nodes
1728 - "@branch" sets the named branch for subsequent nodes
1729 - "#...\\n" is a comment up to the end of the line
1729 - "#...\\n" is a comment up to the end of the line
1730
1730
1731 Whitespace between the above elements is ignored.
1731 Whitespace between the above elements is ignored.
1732
1732
1733 A backref is either
1733 A backref is either
1734
1734
1735 - a number n, which references the node curr-n, where curr is the current
1735 - a number n, which references the node curr-n, where curr is the current
1736 node, or
1736 node, or
1737 - the name of a local tag you placed earlier using ":tag", or
1737 - the name of a local tag you placed earlier using ":tag", or
1738 - empty to denote the default parent.
1738 - empty to denote the default parent.
1739
1739
1740 All string valued-elements are either strictly alphanumeric, or must
1740 All string valued-elements are either strictly alphanumeric, or must
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1742 """
1742 """
1743
1743
1744 if text is None:
1744 if text is None:
1745 ui.status(_("reading DAG from stdin\n"))
1745 ui.status(_("reading DAG from stdin\n"))
1746 text = ui.fin.read()
1746 text = ui.fin.read()
1747
1747
1748 cl = repo.changelog
1748 cl = repo.changelog
1749 if len(cl) > 0:
1749 if len(cl) > 0:
1750 raise util.Abort(_('repository is not empty'))
1750 raise util.Abort(_('repository is not empty'))
1751
1751
1752 # determine number of revs in DAG
1752 # determine number of revs in DAG
1753 total = 0
1753 total = 0
1754 for type, data in dagparser.parsedag(text):
1754 for type, data in dagparser.parsedag(text):
1755 if type == 'n':
1755 if type == 'n':
1756 total += 1
1756 total += 1
1757
1757
1758 if mergeable_file:
1758 if mergeable_file:
1759 linesperrev = 2
1759 linesperrev = 2
1760 # make a file with k lines per rev
1760 # make a file with k lines per rev
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1762 initialmergedlines.append("")
1762 initialmergedlines.append("")
1763
1763
1764 tags = []
1764 tags = []
1765
1765
1766 lock = tr = None
1766 lock = tr = None
1767 try:
1767 try:
1768 lock = repo.lock()
1768 lock = repo.lock()
1769 tr = repo.transaction("builddag")
1769 tr = repo.transaction("builddag")
1770
1770
1771 at = -1
1771 at = -1
1772 atbranch = 'default'
1772 atbranch = 'default'
1773 nodeids = []
1773 nodeids = []
1774 id = 0
1774 id = 0
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1776 for type, data in dagparser.parsedag(text):
1776 for type, data in dagparser.parsedag(text):
1777 if type == 'n':
1777 if type == 'n':
1778 ui.note(('node %s\n' % str(data)))
1778 ui.note(('node %s\n' % str(data)))
1779 id, ps = data
1779 id, ps = data
1780
1780
1781 files = []
1781 files = []
1782 fctxs = {}
1782 fctxs = {}
1783
1783
1784 p2 = None
1784 p2 = None
1785 if mergeable_file:
1785 if mergeable_file:
1786 fn = "mf"
1786 fn = "mf"
1787 p1 = repo[ps[0]]
1787 p1 = repo[ps[0]]
1788 if len(ps) > 1:
1788 if len(ps) > 1:
1789 p2 = repo[ps[1]]
1789 p2 = repo[ps[1]]
1790 pa = p1.ancestor(p2)
1790 pa = p1.ancestor(p2)
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1792 p2)]
1792 p2)]
1793 m3 = simplemerge.Merge3Text(base, local, other)
1793 m3 = simplemerge.Merge3Text(base, local, other)
1794 ml = [l.strip() for l in m3.merge_lines()]
1794 ml = [l.strip() for l in m3.merge_lines()]
1795 ml.append("")
1795 ml.append("")
1796 elif at > 0:
1796 elif at > 0:
1797 ml = p1[fn].data().split("\n")
1797 ml = p1[fn].data().split("\n")
1798 else:
1798 else:
1799 ml = initialmergedlines
1799 ml = initialmergedlines
1800 ml[id * linesperrev] += " r%i" % id
1800 ml[id * linesperrev] += " r%i" % id
1801 mergedtext = "\n".join(ml)
1801 mergedtext = "\n".join(ml)
1802 files.append(fn)
1802 files.append(fn)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1804
1804
1805 if overwritten_file:
1805 if overwritten_file:
1806 fn = "of"
1806 fn = "of"
1807 files.append(fn)
1807 files.append(fn)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1809
1809
1810 if new_file:
1810 if new_file:
1811 fn = "nf%i" % id
1811 fn = "nf%i" % id
1812 files.append(fn)
1812 files.append(fn)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1814 if len(ps) > 1:
1814 if len(ps) > 1:
1815 if not p2:
1815 if not p2:
1816 p2 = repo[ps[1]]
1816 p2 = repo[ps[1]]
1817 for fn in p2:
1817 for fn in p2:
1818 if fn.startswith("nf"):
1818 if fn.startswith("nf"):
1819 files.append(fn)
1819 files.append(fn)
1820 fctxs[fn] = p2[fn]
1820 fctxs[fn] = p2[fn]
1821
1821
1822 def fctxfn(repo, cx, path):
1822 def fctxfn(repo, cx, path):
1823 return fctxs.get(path)
1823 return fctxs.get(path)
1824
1824
1825 if len(ps) == 0 or ps[0] < 0:
1825 if len(ps) == 0 or ps[0] < 0:
1826 pars = [None, None]
1826 pars = [None, None]
1827 elif len(ps) == 1:
1827 elif len(ps) == 1:
1828 pars = [nodeids[ps[0]], None]
1828 pars = [nodeids[ps[0]], None]
1829 else:
1829 else:
1830 pars = [nodeids[p] for p in ps]
1830 pars = [nodeids[p] for p in ps]
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1832 date=(id, 0),
1832 date=(id, 0),
1833 user="debugbuilddag",
1833 user="debugbuilddag",
1834 extra={'branch': atbranch})
1834 extra={'branch': atbranch})
1835 nodeid = repo.commitctx(cx)
1835 nodeid = repo.commitctx(cx)
1836 nodeids.append(nodeid)
1836 nodeids.append(nodeid)
1837 at = id
1837 at = id
1838 elif type == 'l':
1838 elif type == 'l':
1839 id, name = data
1839 id, name = data
1840 ui.note(('tag %s\n' % name))
1840 ui.note(('tag %s\n' % name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1842 elif type == 'a':
1842 elif type == 'a':
1843 ui.note(('branch %s\n' % data))
1843 ui.note(('branch %s\n' % data))
1844 atbranch = data
1844 atbranch = data
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1846 tr.close()
1846 tr.close()
1847
1847
1848 if tags:
1848 if tags:
1849 repo.vfs.write("localtags", "".join(tags))
1849 repo.vfs.write("localtags", "".join(tags))
1850 finally:
1850 finally:
1851 ui.progress(_('building'), None)
1851 ui.progress(_('building'), None)
1852 release(tr, lock)
1852 release(tr, lock)
1853
1853
1854 @command('debugbundle',
1854 @command('debugbundle',
1855 [('a', 'all', None, _('show all details'))],
1855 [('a', 'all', None, _('show all details'))],
1856 _('FILE'),
1856 _('FILE'),
1857 norepo=True)
1857 norepo=True)
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1859 """lists the contents of a bundle"""
1859 """lists the contents of a bundle"""
1860 f = hg.openpath(ui, bundlepath)
1860 f = hg.openpath(ui, bundlepath)
1861 try:
1861 try:
1862 gen = exchange.readbundle(ui, f, bundlepath)
1862 gen = exchange.readbundle(ui, f, bundlepath)
1863 if isinstance(gen, bundle2.unbundle20):
1863 if isinstance(gen, bundle2.unbundle20):
1864 return _debugbundle2(ui, gen, all=all, **opts)
1864 return _debugbundle2(ui, gen, all=all, **opts)
1865 if all:
1865 if all:
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1867
1867
1868 def showchunks(named):
1868 def showchunks(named):
1869 ui.write("\n%s\n" % named)
1869 ui.write("\n%s\n" % named)
1870 chain = None
1870 chain = None
1871 while True:
1871 while True:
1872 chunkdata = gen.deltachunk(chain)
1872 chunkdata = gen.deltachunk(chain)
1873 if not chunkdata:
1873 if not chunkdata:
1874 break
1874 break
1875 node = chunkdata['node']
1875 node = chunkdata['node']
1876 p1 = chunkdata['p1']
1876 p1 = chunkdata['p1']
1877 p2 = chunkdata['p2']
1877 p2 = chunkdata['p2']
1878 cs = chunkdata['cs']
1878 cs = chunkdata['cs']
1879 deltabase = chunkdata['deltabase']
1879 deltabase = chunkdata['deltabase']
1880 delta = chunkdata['delta']
1880 delta = chunkdata['delta']
1881 ui.write("%s %s %s %s %s %s\n" %
1881 ui.write("%s %s %s %s %s %s\n" %
1882 (hex(node), hex(p1), hex(p2),
1882 (hex(node), hex(p1), hex(p2),
1883 hex(cs), hex(deltabase), len(delta)))
1883 hex(cs), hex(deltabase), len(delta)))
1884 chain = node
1884 chain = node
1885
1885
1886 chunkdata = gen.changelogheader()
1886 chunkdata = gen.changelogheader()
1887 showchunks("changelog")
1887 showchunks("changelog")
1888 chunkdata = gen.manifestheader()
1888 chunkdata = gen.manifestheader()
1889 showchunks("manifest")
1889 showchunks("manifest")
1890 while True:
1890 while True:
1891 chunkdata = gen.filelogheader()
1891 chunkdata = gen.filelogheader()
1892 if not chunkdata:
1892 if not chunkdata:
1893 break
1893 break
1894 fname = chunkdata['filename']
1894 fname = chunkdata['filename']
1895 showchunks(fname)
1895 showchunks(fname)
1896 else:
1896 else:
1897 if isinstance(gen, bundle2.unbundle20):
1897 if isinstance(gen, bundle2.unbundle20):
1898 raise util.Abort(_('use debugbundle2 for this file'))
1898 raise util.Abort(_('use debugbundle2 for this file'))
1899 chunkdata = gen.changelogheader()
1899 chunkdata = gen.changelogheader()
1900 chain = None
1900 chain = None
1901 while True:
1901 while True:
1902 chunkdata = gen.deltachunk(chain)
1902 chunkdata = gen.deltachunk(chain)
1903 if not chunkdata:
1903 if not chunkdata:
1904 break
1904 break
1905 node = chunkdata['node']
1905 node = chunkdata['node']
1906 ui.write("%s\n" % hex(node))
1906 ui.write("%s\n" % hex(node))
1907 chain = node
1907 chain = node
1908 finally:
1908 finally:
1909 f.close()
1909 f.close()
1910
1910
1911 def _debugbundle2(ui, gen, **opts):
1911 def _debugbundle2(ui, gen, **opts):
1912 """lists the contents of a bundle2"""
1912 """lists the contents of a bundle2"""
1913 if not isinstance(gen, bundle2.unbundle20):
1913 if not isinstance(gen, bundle2.unbundle20):
1914 raise util.Abort(_('not a bundle2 file'))
1914 raise util.Abort(_('not a bundle2 file'))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1916 for part in gen.iterparts():
1916 for part in gen.iterparts():
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1918 if part.type == 'changegroup':
1918 if part.type == 'changegroup':
1919 version = part.params.get('version', '01')
1919 version = part.params.get('version', '01')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1921 chunkdata = cg.changelogheader()
1921 chunkdata = cg.changelogheader()
1922 chain = None
1922 chain = None
1923 while True:
1923 while True:
1924 chunkdata = cg.deltachunk(chain)
1924 chunkdata = cg.deltachunk(chain)
1925 if not chunkdata:
1925 if not chunkdata:
1926 break
1926 break
1927 node = chunkdata['node']
1927 node = chunkdata['node']
1928 ui.write(" %s\n" % hex(node))
1928 ui.write(" %s\n" % hex(node))
1929 chain = node
1929 chain = node
1930
1930
1931 @command('debugcheckstate', [], '')
1931 @command('debugcheckstate', [], '')
1932 def debugcheckstate(ui, repo):
1932 def debugcheckstate(ui, repo):
1933 """validate the correctness of the current dirstate"""
1933 """validate the correctness of the current dirstate"""
1934 parent1, parent2 = repo.dirstate.parents()
1934 parent1, parent2 = repo.dirstate.parents()
1935 m1 = repo[parent1].manifest()
1935 m1 = repo[parent1].manifest()
1936 m2 = repo[parent2].manifest()
1936 m2 = repo[parent2].manifest()
1937 errors = 0
1937 errors = 0
1938 for f in repo.dirstate:
1938 for f in repo.dirstate:
1939 state = repo.dirstate[f]
1939 state = repo.dirstate[f]
1940 if state in "nr" and f not in m1:
1940 if state in "nr" and f not in m1:
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1942 errors += 1
1942 errors += 1
1943 if state in "a" and f in m1:
1943 if state in "a" and f in m1:
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1945 errors += 1
1945 errors += 1
1946 if state in "m" and f not in m1 and f not in m2:
1946 if state in "m" and f not in m1 and f not in m2:
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1948 (f, state))
1948 (f, state))
1949 errors += 1
1949 errors += 1
1950 for f in m1:
1950 for f in m1:
1951 state = repo.dirstate[f]
1951 state = repo.dirstate[f]
1952 if state not in "nrm":
1952 if state not in "nrm":
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1954 errors += 1
1954 errors += 1
1955 if errors:
1955 if errors:
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1957 raise util.Abort(error)
1957 raise util.Abort(error)
1958
1958
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1960 def debugcommands(ui, cmd='', *args):
1960 def debugcommands(ui, cmd='', *args):
1961 """list all available commands and options"""
1961 """list all available commands and options"""
1962 for cmd, vals in sorted(table.iteritems()):
1962 for cmd, vals in sorted(table.iteritems()):
1963 cmd = cmd.split('|')[0].strip('^')
1963 cmd = cmd.split('|')[0].strip('^')
1964 opts = ', '.join([i[1] for i in vals[1]])
1964 opts = ', '.join([i[1] for i in vals[1]])
1965 ui.write('%s: %s\n' % (cmd, opts))
1965 ui.write('%s: %s\n' % (cmd, opts))
1966
1966
1967 @command('debugcomplete',
1967 @command('debugcomplete',
1968 [('o', 'options', None, _('show the command options'))],
1968 [('o', 'options', None, _('show the command options'))],
1969 _('[-o] CMD'),
1969 _('[-o] CMD'),
1970 norepo=True)
1970 norepo=True)
1971 def debugcomplete(ui, cmd='', **opts):
1971 def debugcomplete(ui, cmd='', **opts):
1972 """returns the completion list associated with the given command"""
1972 """returns the completion list associated with the given command"""
1973
1973
1974 if opts.get('options'):
1974 if opts.get('options'):
1975 options = []
1975 options = []
1976 otables = [globalopts]
1976 otables = [globalopts]
1977 if cmd:
1977 if cmd:
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1979 otables.append(entry[1])
1979 otables.append(entry[1])
1980 for t in otables:
1980 for t in otables:
1981 for o in t:
1981 for o in t:
1982 if "(DEPRECATED)" in o[3]:
1982 if "(DEPRECATED)" in o[3]:
1983 continue
1983 continue
1984 if o[0]:
1984 if o[0]:
1985 options.append('-%s' % o[0])
1985 options.append('-%s' % o[0])
1986 options.append('--%s' % o[1])
1986 options.append('--%s' % o[1])
1987 ui.write("%s\n" % "\n".join(options))
1987 ui.write("%s\n" % "\n".join(options))
1988 return
1988 return
1989
1989
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1991 if ui.verbose:
1991 if ui.verbose:
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1994
1994
1995 @command('debugdag',
1995 @command('debugdag',
1996 [('t', 'tags', None, _('use tags as labels')),
1996 [('t', 'tags', None, _('use tags as labels')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1998 ('', 'dots', None, _('use dots for runs')),
1998 ('', 'dots', None, _('use dots for runs')),
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
2000 _('[OPTION]... [FILE [REV]...]'),
2000 _('[OPTION]... [FILE [REV]...]'),
2001 optionalrepo=True)
2001 optionalrepo=True)
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2003 """format the changelog or an index DAG as a concise textual description
2003 """format the changelog or an index DAG as a concise textual description
2004
2004
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2006 revision numbers, they get labeled in the output as rN.
2006 revision numbers, they get labeled in the output as rN.
2007
2007
2008 Otherwise, the changelog DAG of the current repo is emitted.
2008 Otherwise, the changelog DAG of the current repo is emitted.
2009 """
2009 """
2010 spaces = opts.get('spaces')
2010 spaces = opts.get('spaces')
2011 dots = opts.get('dots')
2011 dots = opts.get('dots')
2012 if file_:
2012 if file_:
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2014 revs = set((int(r) for r in revs))
2014 revs = set((int(r) for r in revs))
2015 def events():
2015 def events():
2016 for r in rlog:
2016 for r in rlog:
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2018 if p != -1))
2018 if p != -1))
2019 if r in revs:
2019 if r in revs:
2020 yield 'l', (r, "r%i" % r)
2020 yield 'l', (r, "r%i" % r)
2021 elif repo:
2021 elif repo:
2022 cl = repo.changelog
2022 cl = repo.changelog
2023 tags = opts.get('tags')
2023 tags = opts.get('tags')
2024 branches = opts.get('branches')
2024 branches = opts.get('branches')
2025 if tags:
2025 if tags:
2026 labels = {}
2026 labels = {}
2027 for l, n in repo.tags().items():
2027 for l, n in repo.tags().items():
2028 labels.setdefault(cl.rev(n), []).append(l)
2028 labels.setdefault(cl.rev(n), []).append(l)
2029 def events():
2029 def events():
2030 b = "default"
2030 b = "default"
2031 for r in cl:
2031 for r in cl:
2032 if branches:
2032 if branches:
2033 newb = cl.read(cl.node(r))[5]['branch']
2033 newb = cl.read(cl.node(r))[5]['branch']
2034 if newb != b:
2034 if newb != b:
2035 yield 'a', newb
2035 yield 'a', newb
2036 b = newb
2036 b = newb
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2038 if p != -1))
2038 if p != -1))
2039 if tags:
2039 if tags:
2040 ls = labels.get(r)
2040 ls = labels.get(r)
2041 if ls:
2041 if ls:
2042 for l in ls:
2042 for l in ls:
2043 yield 'l', (r, l)
2043 yield 'l', (r, l)
2044 else:
2044 else:
2045 raise util.Abort(_('need repo for changelog dag'))
2045 raise util.Abort(_('need repo for changelog dag'))
2046
2046
2047 for line in dagparser.dagtextlines(events(),
2047 for line in dagparser.dagtextlines(events(),
2048 addspaces=spaces,
2048 addspaces=spaces,
2049 wraplabels=True,
2049 wraplabels=True,
2050 wrapannotations=True,
2050 wrapannotations=True,
2051 wrapnonlinear=dots,
2051 wrapnonlinear=dots,
2052 usedots=dots,
2052 usedots=dots,
2053 maxlinewidth=70):
2053 maxlinewidth=70):
2054 ui.write(line)
2054 ui.write(line)
2055 ui.write("\n")
2055 ui.write("\n")
2056
2056
2057 @command('debugdata',
2057 @command('debugdata',
2058 [('c', 'changelog', False, _('open changelog')),
2058 [('c', 'changelog', False, _('open changelog')),
2059 ('m', 'manifest', False, _('open manifest')),
2059 ('m', 'manifest', False, _('open manifest')),
2060 ('', 'dir', False, _('open directory manifest'))],
2060 ('', 'dir', False, _('open directory manifest'))],
2061 _('-c|-m|FILE REV'))
2061 _('-c|-m|FILE REV'))
2062 def debugdata(ui, repo, file_, rev=None, **opts):
2062 def debugdata(ui, repo, file_, rev=None, **opts):
2063 """dump the contents of a data file revision"""
2063 """dump the contents of a data file revision"""
2064 if opts.get('changelog') or opts.get('manifest'):
2064 if opts.get('changelog') or opts.get('manifest'):
2065 file_, rev = None, file_
2065 file_, rev = None, file_
2066 elif rev is None:
2066 elif rev is None:
2067 raise error.CommandError('debugdata', _('invalid arguments'))
2067 raise error.CommandError('debugdata', _('invalid arguments'))
2068 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2068 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2069 try:
2069 try:
2070 ui.write(r.revision(r.lookup(rev)))
2070 ui.write(r.revision(r.lookup(rev)))
2071 except KeyError:
2071 except KeyError:
2072 raise util.Abort(_('invalid revision identifier %s') % rev)
2072 raise util.Abort(_('invalid revision identifier %s') % rev)
2073
2073
2074 @command('debugdate',
2074 @command('debugdate',
2075 [('e', 'extended', None, _('try extended date formats'))],
2075 [('e', 'extended', None, _('try extended date formats'))],
2076 _('[-e] DATE [RANGE]'),
2076 _('[-e] DATE [RANGE]'),
2077 norepo=True, optionalrepo=True)
2077 norepo=True, optionalrepo=True)
2078 def debugdate(ui, date, range=None, **opts):
2078 def debugdate(ui, date, range=None, **opts):
2079 """parse and display a date"""
2079 """parse and display a date"""
2080 if opts["extended"]:
2080 if opts["extended"]:
2081 d = util.parsedate(date, util.extendeddateformats)
2081 d = util.parsedate(date, util.extendeddateformats)
2082 else:
2082 else:
2083 d = util.parsedate(date)
2083 d = util.parsedate(date)
2084 ui.write(("internal: %s %s\n") % d)
2084 ui.write(("internal: %s %s\n") % d)
2085 ui.write(("standard: %s\n") % util.datestr(d))
2085 ui.write(("standard: %s\n") % util.datestr(d))
2086 if range:
2086 if range:
2087 m = util.matchdate(range)
2087 m = util.matchdate(range)
2088 ui.write(("match: %s\n") % m(d[0]))
2088 ui.write(("match: %s\n") % m(d[0]))
2089
2089
2090 @command('debugdiscovery',
2090 @command('debugdiscovery',
2091 [('', 'old', None, _('use old-style discovery')),
2091 [('', 'old', None, _('use old-style discovery')),
2092 ('', 'nonheads', None,
2092 ('', 'nonheads', None,
2093 _('use old-style discovery with non-heads included')),
2093 _('use old-style discovery with non-heads included')),
2094 ] + remoteopts,
2094 ] + remoteopts,
2095 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2095 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2096 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2096 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2097 """runs the changeset discovery protocol in isolation"""
2097 """runs the changeset discovery protocol in isolation"""
2098 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2098 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2099 opts.get('branch'))
2099 opts.get('branch'))
2100 remote = hg.peer(repo, opts, remoteurl)
2100 remote = hg.peer(repo, opts, remoteurl)
2101 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2101 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2102
2102
2103 # make sure tests are repeatable
2103 # make sure tests are repeatable
2104 random.seed(12323)
2104 random.seed(12323)
2105
2105
2106 def doit(localheads, remoteheads, remote=remote):
2106 def doit(localheads, remoteheads, remote=remote):
2107 if opts.get('old'):
2107 if opts.get('old'):
2108 if localheads:
2108 if localheads:
2109 raise util.Abort('cannot use localheads with old style '
2109 raise util.Abort('cannot use localheads with old style '
2110 'discovery')
2110 'discovery')
2111 if not util.safehasattr(remote, 'branches'):
2111 if not util.safehasattr(remote, 'branches'):
2112 # enable in-client legacy support
2112 # enable in-client legacy support
2113 remote = localrepo.locallegacypeer(remote.local())
2113 remote = localrepo.locallegacypeer(remote.local())
2114 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2114 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2115 force=True)
2115 force=True)
2116 common = set(common)
2116 common = set(common)
2117 if not opts.get('nonheads'):
2117 if not opts.get('nonheads'):
2118 ui.write(("unpruned common: %s\n") %
2118 ui.write(("unpruned common: %s\n") %
2119 " ".join(sorted(short(n) for n in common)))
2119 " ".join(sorted(short(n) for n in common)))
2120 dag = dagutil.revlogdag(repo.changelog)
2120 dag = dagutil.revlogdag(repo.changelog)
2121 all = dag.ancestorset(dag.internalizeall(common))
2121 all = dag.ancestorset(dag.internalizeall(common))
2122 common = dag.externalizeall(dag.headsetofconnecteds(all))
2122 common = dag.externalizeall(dag.headsetofconnecteds(all))
2123 else:
2123 else:
2124 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2124 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2125 common = set(common)
2125 common = set(common)
2126 rheads = set(hds)
2126 rheads = set(hds)
2127 lheads = set(repo.heads())
2127 lheads = set(repo.heads())
2128 ui.write(("common heads: %s\n") %
2128 ui.write(("common heads: %s\n") %
2129 " ".join(sorted(short(n) for n in common)))
2129 " ".join(sorted(short(n) for n in common)))
2130 if lheads <= common:
2130 if lheads <= common:
2131 ui.write(("local is subset\n"))
2131 ui.write(("local is subset\n"))
2132 elif rheads <= common:
2132 elif rheads <= common:
2133 ui.write(("remote is subset\n"))
2133 ui.write(("remote is subset\n"))
2134
2134
2135 serverlogs = opts.get('serverlog')
2135 serverlogs = opts.get('serverlog')
2136 if serverlogs:
2136 if serverlogs:
2137 for filename in serverlogs:
2137 for filename in serverlogs:
2138 logfile = open(filename, 'r')
2138 logfile = open(filename, 'r')
2139 try:
2139 try:
2140 line = logfile.readline()
2140 line = logfile.readline()
2141 while line:
2141 while line:
2142 parts = line.strip().split(';')
2142 parts = line.strip().split(';')
2143 op = parts[1]
2143 op = parts[1]
2144 if op == 'cg':
2144 if op == 'cg':
2145 pass
2145 pass
2146 elif op == 'cgss':
2146 elif op == 'cgss':
2147 doit(parts[2].split(' '), parts[3].split(' '))
2147 doit(parts[2].split(' '), parts[3].split(' '))
2148 elif op == 'unb':
2148 elif op == 'unb':
2149 doit(parts[3].split(' '), parts[2].split(' '))
2149 doit(parts[3].split(' '), parts[2].split(' '))
2150 line = logfile.readline()
2150 line = logfile.readline()
2151 finally:
2151 finally:
2152 logfile.close()
2152 logfile.close()
2153
2153
2154 else:
2154 else:
2155 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2155 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2156 opts.get('remote_head'))
2156 opts.get('remote_head'))
2157 localrevs = opts.get('local_head')
2157 localrevs = opts.get('local_head')
2158 doit(localrevs, remoterevs)
2158 doit(localrevs, remoterevs)
2159
2159
2160 @command('debugfileset',
2160 @command('debugfileset',
2161 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2161 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2162 _('[-r REV] FILESPEC'))
2162 _('[-r REV] FILESPEC'))
2163 def debugfileset(ui, repo, expr, **opts):
2163 def debugfileset(ui, repo, expr, **opts):
2164 '''parse and apply a fileset specification'''
2164 '''parse and apply a fileset specification'''
2165 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2165 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2166 if ui.verbose:
2166 if ui.verbose:
2167 tree = fileset.parse(expr)[0]
2167 tree = fileset.parse(expr)
2168 ui.note(tree, "\n")
2168 ui.note(tree, "\n")
2169
2169
2170 for f in ctx.getfileset(expr):
2170 for f in ctx.getfileset(expr):
2171 ui.write("%s\n" % f)
2171 ui.write("%s\n" % f)
2172
2172
2173 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2173 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2174 def debugfsinfo(ui, path="."):
2174 def debugfsinfo(ui, path="."):
2175 """show information detected about current filesystem"""
2175 """show information detected about current filesystem"""
2176 util.writefile('.debugfsinfo', '')
2176 util.writefile('.debugfsinfo', '')
2177 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2177 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2178 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2178 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2179 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2179 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2180 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2180 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2181 and 'yes' or 'no'))
2181 and 'yes' or 'no'))
2182 os.unlink('.debugfsinfo')
2182 os.unlink('.debugfsinfo')
2183
2183
2184 @command('debuggetbundle',
2184 @command('debuggetbundle',
2185 [('H', 'head', [], _('id of head node'), _('ID')),
2185 [('H', 'head', [], _('id of head node'), _('ID')),
2186 ('C', 'common', [], _('id of common node'), _('ID')),
2186 ('C', 'common', [], _('id of common node'), _('ID')),
2187 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2187 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2188 _('REPO FILE [-H|-C ID]...'),
2188 _('REPO FILE [-H|-C ID]...'),
2189 norepo=True)
2189 norepo=True)
2190 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2190 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2191 """retrieves a bundle from a repo
2191 """retrieves a bundle from a repo
2192
2192
2193 Every ID must be a full-length hex node id string. Saves the bundle to the
2193 Every ID must be a full-length hex node id string. Saves the bundle to the
2194 given file.
2194 given file.
2195 """
2195 """
2196 repo = hg.peer(ui, opts, repopath)
2196 repo = hg.peer(ui, opts, repopath)
2197 if not repo.capable('getbundle'):
2197 if not repo.capable('getbundle'):
2198 raise util.Abort("getbundle() not supported by target repository")
2198 raise util.Abort("getbundle() not supported by target repository")
2199 args = {}
2199 args = {}
2200 if common:
2200 if common:
2201 args['common'] = [bin(s) for s in common]
2201 args['common'] = [bin(s) for s in common]
2202 if head:
2202 if head:
2203 args['heads'] = [bin(s) for s in head]
2203 args['heads'] = [bin(s) for s in head]
2204 # TODO: get desired bundlecaps from command line.
2204 # TODO: get desired bundlecaps from command line.
2205 args['bundlecaps'] = None
2205 args['bundlecaps'] = None
2206 bundle = repo.getbundle('debug', **args)
2206 bundle = repo.getbundle('debug', **args)
2207
2207
2208 bundletype = opts.get('type', 'bzip2').lower()
2208 bundletype = opts.get('type', 'bzip2').lower()
2209 btypes = {'none': 'HG10UN',
2209 btypes = {'none': 'HG10UN',
2210 'bzip2': 'HG10BZ',
2210 'bzip2': 'HG10BZ',
2211 'gzip': 'HG10GZ',
2211 'gzip': 'HG10GZ',
2212 'bundle2': 'HG20'}
2212 'bundle2': 'HG20'}
2213 bundletype = btypes.get(bundletype)
2213 bundletype = btypes.get(bundletype)
2214 if bundletype not in changegroup.bundletypes:
2214 if bundletype not in changegroup.bundletypes:
2215 raise util.Abort(_('unknown bundle type specified with --type'))
2215 raise util.Abort(_('unknown bundle type specified with --type'))
2216 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2216 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2217
2217
2218 @command('debugignore', [], '')
2218 @command('debugignore', [], '')
2219 def debugignore(ui, repo, *values, **opts):
2219 def debugignore(ui, repo, *values, **opts):
2220 """display the combined ignore pattern"""
2220 """display the combined ignore pattern"""
2221 ignore = repo.dirstate._ignore
2221 ignore = repo.dirstate._ignore
2222 includepat = getattr(ignore, 'includepat', None)
2222 includepat = getattr(ignore, 'includepat', None)
2223 if includepat is not None:
2223 if includepat is not None:
2224 ui.write("%s\n" % includepat)
2224 ui.write("%s\n" % includepat)
2225 else:
2225 else:
2226 raise util.Abort(_("no ignore patterns found"))
2226 raise util.Abort(_("no ignore patterns found"))
2227
2227
2228 @command('debugindex',
2228 @command('debugindex',
2229 [('c', 'changelog', False, _('open changelog')),
2229 [('c', 'changelog', False, _('open changelog')),
2230 ('m', 'manifest', False, _('open manifest')),
2230 ('m', 'manifest', False, _('open manifest')),
2231 ('', 'dir', False, _('open directory manifest')),
2231 ('', 'dir', False, _('open directory manifest')),
2232 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2232 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2233 _('[-f FORMAT] -c|-m|FILE'),
2233 _('[-f FORMAT] -c|-m|FILE'),
2234 optionalrepo=True)
2234 optionalrepo=True)
2235 def debugindex(ui, repo, file_=None, **opts):
2235 def debugindex(ui, repo, file_=None, **opts):
2236 """dump the contents of an index file"""
2236 """dump the contents of an index file"""
2237 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2237 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2238 format = opts.get('format', 0)
2238 format = opts.get('format', 0)
2239 if format not in (0, 1):
2239 if format not in (0, 1):
2240 raise util.Abort(_("unknown format %d") % format)
2240 raise util.Abort(_("unknown format %d") % format)
2241
2241
2242 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2242 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2243 if generaldelta:
2243 if generaldelta:
2244 basehdr = ' delta'
2244 basehdr = ' delta'
2245 else:
2245 else:
2246 basehdr = ' base'
2246 basehdr = ' base'
2247
2247
2248 if ui.debugflag:
2248 if ui.debugflag:
2249 shortfn = hex
2249 shortfn = hex
2250 else:
2250 else:
2251 shortfn = short
2251 shortfn = short
2252
2252
2253 # There might not be anything in r, so have a sane default
2253 # There might not be anything in r, so have a sane default
2254 idlen = 12
2254 idlen = 12
2255 for i in r:
2255 for i in r:
2256 idlen = len(shortfn(r.node(i)))
2256 idlen = len(shortfn(r.node(i)))
2257 break
2257 break
2258
2258
2259 if format == 0:
2259 if format == 0:
2260 ui.write(" rev offset length " + basehdr + " linkrev"
2260 ui.write(" rev offset length " + basehdr + " linkrev"
2261 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2261 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2262 elif format == 1:
2262 elif format == 1:
2263 ui.write(" rev flag offset length"
2263 ui.write(" rev flag offset length"
2264 " size " + basehdr + " link p1 p2"
2264 " size " + basehdr + " link p1 p2"
2265 " %s\n" % "nodeid".rjust(idlen))
2265 " %s\n" % "nodeid".rjust(idlen))
2266
2266
2267 for i in r:
2267 for i in r:
2268 node = r.node(i)
2268 node = r.node(i)
2269 if generaldelta:
2269 if generaldelta:
2270 base = r.deltaparent(i)
2270 base = r.deltaparent(i)
2271 else:
2271 else:
2272 base = r.chainbase(i)
2272 base = r.chainbase(i)
2273 if format == 0:
2273 if format == 0:
2274 try:
2274 try:
2275 pp = r.parents(node)
2275 pp = r.parents(node)
2276 except Exception:
2276 except Exception:
2277 pp = [nullid, nullid]
2277 pp = [nullid, nullid]
2278 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2278 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2279 i, r.start(i), r.length(i), base, r.linkrev(i),
2279 i, r.start(i), r.length(i), base, r.linkrev(i),
2280 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2280 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2281 elif format == 1:
2281 elif format == 1:
2282 pr = r.parentrevs(i)
2282 pr = r.parentrevs(i)
2283 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2283 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2284 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2284 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2285 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2285 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2286
2286
2287 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2287 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2288 def debugindexdot(ui, repo, file_):
2288 def debugindexdot(ui, repo, file_):
2289 """dump an index DAG as a graphviz dot file"""
2289 """dump an index DAG as a graphviz dot file"""
2290 r = None
2290 r = None
2291 if repo:
2291 if repo:
2292 filelog = repo.file(file_)
2292 filelog = repo.file(file_)
2293 if len(filelog):
2293 if len(filelog):
2294 r = filelog
2294 r = filelog
2295 if not r:
2295 if not r:
2296 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2296 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2297 ui.write(("digraph G {\n"))
2297 ui.write(("digraph G {\n"))
2298 for i in r:
2298 for i in r:
2299 node = r.node(i)
2299 node = r.node(i)
2300 pp = r.parents(node)
2300 pp = r.parents(node)
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2302 if pp[1] != nullid:
2302 if pp[1] != nullid:
2303 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2303 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2304 ui.write("}\n")
2304 ui.write("}\n")
2305
2305
2306 @command('debuginstall', [], '', norepo=True)
2306 @command('debuginstall', [], '', norepo=True)
2307 def debuginstall(ui):
2307 def debuginstall(ui):
2308 '''test Mercurial installation
2308 '''test Mercurial installation
2309
2309
2310 Returns 0 on success.
2310 Returns 0 on success.
2311 '''
2311 '''
2312
2312
2313 def writetemp(contents):
2313 def writetemp(contents):
2314 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2314 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2315 f = os.fdopen(fd, "wb")
2315 f = os.fdopen(fd, "wb")
2316 f.write(contents)
2316 f.write(contents)
2317 f.close()
2317 f.close()
2318 return name
2318 return name
2319
2319
2320 problems = 0
2320 problems = 0
2321
2321
2322 # encoding
2322 # encoding
2323 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2323 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2324 try:
2324 try:
2325 encoding.fromlocal("test")
2325 encoding.fromlocal("test")
2326 except util.Abort, inst:
2326 except util.Abort, inst:
2327 ui.write(" %s\n" % inst)
2327 ui.write(" %s\n" % inst)
2328 ui.write(_(" (check that your locale is properly set)\n"))
2328 ui.write(_(" (check that your locale is properly set)\n"))
2329 problems += 1
2329 problems += 1
2330
2330
2331 # Python
2331 # Python
2332 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2332 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2333 ui.status(_("checking Python version (%s)\n")
2333 ui.status(_("checking Python version (%s)\n")
2334 % ("%s.%s.%s" % sys.version_info[:3]))
2334 % ("%s.%s.%s" % sys.version_info[:3]))
2335 ui.status(_("checking Python lib (%s)...\n")
2335 ui.status(_("checking Python lib (%s)...\n")
2336 % os.path.dirname(os.__file__))
2336 % os.path.dirname(os.__file__))
2337
2337
2338 # compiled modules
2338 # compiled modules
2339 ui.status(_("checking installed modules (%s)...\n")
2339 ui.status(_("checking installed modules (%s)...\n")
2340 % os.path.dirname(__file__))
2340 % os.path.dirname(__file__))
2341 try:
2341 try:
2342 import bdiff, mpatch, base85, osutil
2342 import bdiff, mpatch, base85, osutil
2343 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2343 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2344 except Exception, inst:
2344 except Exception, inst:
2345 ui.write(" %s\n" % inst)
2345 ui.write(" %s\n" % inst)
2346 ui.write(_(" One or more extensions could not be found"))
2346 ui.write(_(" One or more extensions could not be found"))
2347 ui.write(_(" (check that you compiled the extensions)\n"))
2347 ui.write(_(" (check that you compiled the extensions)\n"))
2348 problems += 1
2348 problems += 1
2349
2349
2350 # templates
2350 # templates
2351 import templater
2351 import templater
2352 p = templater.templatepaths()
2352 p = templater.templatepaths()
2353 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2353 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2354 if p:
2354 if p:
2355 m = templater.templatepath("map-cmdline.default")
2355 m = templater.templatepath("map-cmdline.default")
2356 if m:
2356 if m:
2357 # template found, check if it is working
2357 # template found, check if it is working
2358 try:
2358 try:
2359 templater.templater(m)
2359 templater.templater(m)
2360 except Exception, inst:
2360 except Exception, inst:
2361 ui.write(" %s\n" % inst)
2361 ui.write(" %s\n" % inst)
2362 p = None
2362 p = None
2363 else:
2363 else:
2364 ui.write(_(" template 'default' not found\n"))
2364 ui.write(_(" template 'default' not found\n"))
2365 p = None
2365 p = None
2366 else:
2366 else:
2367 ui.write(_(" no template directories found\n"))
2367 ui.write(_(" no template directories found\n"))
2368 if not p:
2368 if not p:
2369 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2369 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2370 problems += 1
2370 problems += 1
2371
2371
2372 # editor
2372 # editor
2373 ui.status(_("checking commit editor...\n"))
2373 ui.status(_("checking commit editor...\n"))
2374 editor = ui.geteditor()
2374 editor = ui.geteditor()
2375 editor = util.expandpath(editor)
2375 editor = util.expandpath(editor)
2376 cmdpath = util.findexe(shlex.split(editor)[0])
2376 cmdpath = util.findexe(shlex.split(editor)[0])
2377 if not cmdpath:
2377 if not cmdpath:
2378 if editor == 'vi':
2378 if editor == 'vi':
2379 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2379 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2380 ui.write(_(" (specify a commit editor in your configuration"
2380 ui.write(_(" (specify a commit editor in your configuration"
2381 " file)\n"))
2381 " file)\n"))
2382 else:
2382 else:
2383 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2383 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2384 ui.write(_(" (specify a commit editor in your configuration"
2384 ui.write(_(" (specify a commit editor in your configuration"
2385 " file)\n"))
2385 " file)\n"))
2386 problems += 1
2386 problems += 1
2387
2387
2388 # check username
2388 # check username
2389 ui.status(_("checking username...\n"))
2389 ui.status(_("checking username...\n"))
2390 try:
2390 try:
2391 ui.username()
2391 ui.username()
2392 except util.Abort, e:
2392 except util.Abort, e:
2393 ui.write(" %s\n" % e)
2393 ui.write(" %s\n" % e)
2394 ui.write(_(" (specify a username in your configuration file)\n"))
2394 ui.write(_(" (specify a username in your configuration file)\n"))
2395 problems += 1
2395 problems += 1
2396
2396
2397 if not problems:
2397 if not problems:
2398 ui.status(_("no problems detected\n"))
2398 ui.status(_("no problems detected\n"))
2399 else:
2399 else:
2400 ui.write(_("%s problems detected,"
2400 ui.write(_("%s problems detected,"
2401 " please check your install!\n") % problems)
2401 " please check your install!\n") % problems)
2402
2402
2403 return problems
2403 return problems
2404
2404
2405 @command('debugknown', [], _('REPO ID...'), norepo=True)
2405 @command('debugknown', [], _('REPO ID...'), norepo=True)
2406 def debugknown(ui, repopath, *ids, **opts):
2406 def debugknown(ui, repopath, *ids, **opts):
2407 """test whether node ids are known to a repo
2407 """test whether node ids are known to a repo
2408
2408
2409 Every ID must be a full-length hex node id string. Returns a list of 0s
2409 Every ID must be a full-length hex node id string. Returns a list of 0s
2410 and 1s indicating unknown/known.
2410 and 1s indicating unknown/known.
2411 """
2411 """
2412 repo = hg.peer(ui, opts, repopath)
2412 repo = hg.peer(ui, opts, repopath)
2413 if not repo.capable('known'):
2413 if not repo.capable('known'):
2414 raise util.Abort("known() not supported by target repository")
2414 raise util.Abort("known() not supported by target repository")
2415 flags = repo.known([bin(s) for s in ids])
2415 flags = repo.known([bin(s) for s in ids])
2416 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2416 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2417
2417
2418 @command('debuglabelcomplete', [], _('LABEL...'))
2418 @command('debuglabelcomplete', [], _('LABEL...'))
2419 def debuglabelcomplete(ui, repo, *args):
2419 def debuglabelcomplete(ui, repo, *args):
2420 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2420 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2421 debugnamecomplete(ui, repo, *args)
2421 debugnamecomplete(ui, repo, *args)
2422
2422
2423 @command('debugnamecomplete', [], _('NAME...'))
2423 @command('debugnamecomplete', [], _('NAME...'))
2424 def debugnamecomplete(ui, repo, *args):
2424 def debugnamecomplete(ui, repo, *args):
2425 '''complete "names" - tags, open branch names, bookmark names'''
2425 '''complete "names" - tags, open branch names, bookmark names'''
2426
2426
2427 names = set()
2427 names = set()
2428 # since we previously only listed open branches, we will handle that
2428 # since we previously only listed open branches, we will handle that
2429 # specially (after this for loop)
2429 # specially (after this for loop)
2430 for name, ns in repo.names.iteritems():
2430 for name, ns in repo.names.iteritems():
2431 if name != 'branches':
2431 if name != 'branches':
2432 names.update(ns.listnames(repo))
2432 names.update(ns.listnames(repo))
2433 names.update(tag for (tag, heads, tip, closed)
2433 names.update(tag for (tag, heads, tip, closed)
2434 in repo.branchmap().iterbranches() if not closed)
2434 in repo.branchmap().iterbranches() if not closed)
2435 completions = set()
2435 completions = set()
2436 if not args:
2436 if not args:
2437 args = ['']
2437 args = ['']
2438 for a in args:
2438 for a in args:
2439 completions.update(n for n in names if n.startswith(a))
2439 completions.update(n for n in names if n.startswith(a))
2440 ui.write('\n'.join(sorted(completions)))
2440 ui.write('\n'.join(sorted(completions)))
2441 ui.write('\n')
2441 ui.write('\n')
2442
2442
2443 @command('debuglocks',
2443 @command('debuglocks',
2444 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2444 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2445 ('W', 'force-wlock', None,
2445 ('W', 'force-wlock', None,
2446 _('free the working state lock (DANGEROUS)'))],
2446 _('free the working state lock (DANGEROUS)'))],
2447 _('[OPTION]...'))
2447 _('[OPTION]...'))
2448 def debuglocks(ui, repo, **opts):
2448 def debuglocks(ui, repo, **opts):
2449 """show or modify state of locks
2449 """show or modify state of locks
2450
2450
2451 By default, this command will show which locks are held. This
2451 By default, this command will show which locks are held. This
2452 includes the user and process holding the lock, the amount of time
2452 includes the user and process holding the lock, the amount of time
2453 the lock has been held, and the machine name where the process is
2453 the lock has been held, and the machine name where the process is
2454 running if it's not local.
2454 running if it's not local.
2455
2455
2456 Locks protect the integrity of Mercurial's data, so should be
2456 Locks protect the integrity of Mercurial's data, so should be
2457 treated with care. System crashes or other interruptions may cause
2457 treated with care. System crashes or other interruptions may cause
2458 locks to not be properly released, though Mercurial will usually
2458 locks to not be properly released, though Mercurial will usually
2459 detect and remove such stale locks automatically.
2459 detect and remove such stale locks automatically.
2460
2460
2461 However, detecting stale locks may not always be possible (for
2461 However, detecting stale locks may not always be possible (for
2462 instance, on a shared filesystem). Removing locks may also be
2462 instance, on a shared filesystem). Removing locks may also be
2463 blocked by filesystem permissions.
2463 blocked by filesystem permissions.
2464
2464
2465 Returns 0 if no locks are held.
2465 Returns 0 if no locks are held.
2466
2466
2467 """
2467 """
2468
2468
2469 if opts.get('force_lock'):
2469 if opts.get('force_lock'):
2470 repo.svfs.unlink('lock')
2470 repo.svfs.unlink('lock')
2471 if opts.get('force_wlock'):
2471 if opts.get('force_wlock'):
2472 repo.vfs.unlink('wlock')
2472 repo.vfs.unlink('wlock')
2473 if opts.get('force_lock') or opts.get('force_lock'):
2473 if opts.get('force_lock') or opts.get('force_lock'):
2474 return 0
2474 return 0
2475
2475
2476 now = time.time()
2476 now = time.time()
2477 held = 0
2477 held = 0
2478
2478
2479 def report(vfs, name, method):
2479 def report(vfs, name, method):
2480 # this causes stale locks to get reaped for more accurate reporting
2480 # this causes stale locks to get reaped for more accurate reporting
2481 try:
2481 try:
2482 l = method(False)
2482 l = method(False)
2483 except error.LockHeld:
2483 except error.LockHeld:
2484 l = None
2484 l = None
2485
2485
2486 if l:
2486 if l:
2487 l.release()
2487 l.release()
2488 else:
2488 else:
2489 try:
2489 try:
2490 stat = vfs.lstat(name)
2490 stat = vfs.lstat(name)
2491 age = now - stat.st_mtime
2491 age = now - stat.st_mtime
2492 user = util.username(stat.st_uid)
2492 user = util.username(stat.st_uid)
2493 locker = vfs.readlock(name)
2493 locker = vfs.readlock(name)
2494 if ":" in locker:
2494 if ":" in locker:
2495 host, pid = locker.split(':')
2495 host, pid = locker.split(':')
2496 if host == socket.gethostname():
2496 if host == socket.gethostname():
2497 locker = 'user %s, process %s' % (user, pid)
2497 locker = 'user %s, process %s' % (user, pid)
2498 else:
2498 else:
2499 locker = 'user %s, process %s, host %s' \
2499 locker = 'user %s, process %s, host %s' \
2500 % (user, pid, host)
2500 % (user, pid, host)
2501 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2501 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2502 return 1
2502 return 1
2503 except OSError, e:
2503 except OSError, e:
2504 if e.errno != errno.ENOENT:
2504 if e.errno != errno.ENOENT:
2505 raise
2505 raise
2506
2506
2507 ui.write("%-6s free\n" % (name + ":"))
2507 ui.write("%-6s free\n" % (name + ":"))
2508 return 0
2508 return 0
2509
2509
2510 held += report(repo.svfs, "lock", repo.lock)
2510 held += report(repo.svfs, "lock", repo.lock)
2511 held += report(repo.vfs, "wlock", repo.wlock)
2511 held += report(repo.vfs, "wlock", repo.wlock)
2512
2512
2513 return held
2513 return held
2514
2514
2515 @command('debugobsolete',
2515 @command('debugobsolete',
2516 [('', 'flags', 0, _('markers flag')),
2516 [('', 'flags', 0, _('markers flag')),
2517 ('', 'record-parents', False,
2517 ('', 'record-parents', False,
2518 _('record parent information for the precursor')),
2518 _('record parent information for the precursor')),
2519 ('r', 'rev', [], _('display markers relevant to REV')),
2519 ('r', 'rev', [], _('display markers relevant to REV')),
2520 ] + commitopts2,
2520 ] + commitopts2,
2521 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2521 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2522 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2522 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2523 """create arbitrary obsolete marker
2523 """create arbitrary obsolete marker
2524
2524
2525 With no arguments, displays the list of obsolescence markers."""
2525 With no arguments, displays the list of obsolescence markers."""
2526
2526
2527 def parsenodeid(s):
2527 def parsenodeid(s):
2528 try:
2528 try:
2529 # We do not use revsingle/revrange functions here to accept
2529 # We do not use revsingle/revrange functions here to accept
2530 # arbitrary node identifiers, possibly not present in the
2530 # arbitrary node identifiers, possibly not present in the
2531 # local repository.
2531 # local repository.
2532 n = bin(s)
2532 n = bin(s)
2533 if len(n) != len(nullid):
2533 if len(n) != len(nullid):
2534 raise TypeError()
2534 raise TypeError()
2535 return n
2535 return n
2536 except TypeError:
2536 except TypeError:
2537 raise util.Abort('changeset references must be full hexadecimal '
2537 raise util.Abort('changeset references must be full hexadecimal '
2538 'node identifiers')
2538 'node identifiers')
2539
2539
2540 if precursor is not None:
2540 if precursor is not None:
2541 if opts['rev']:
2541 if opts['rev']:
2542 raise util.Abort('cannot select revision when creating marker')
2542 raise util.Abort('cannot select revision when creating marker')
2543 metadata = {}
2543 metadata = {}
2544 metadata['user'] = opts['user'] or ui.username()
2544 metadata['user'] = opts['user'] or ui.username()
2545 succs = tuple(parsenodeid(succ) for succ in successors)
2545 succs = tuple(parsenodeid(succ) for succ in successors)
2546 l = repo.lock()
2546 l = repo.lock()
2547 try:
2547 try:
2548 tr = repo.transaction('debugobsolete')
2548 tr = repo.transaction('debugobsolete')
2549 try:
2549 try:
2550 date = opts.get('date')
2550 date = opts.get('date')
2551 if date:
2551 if date:
2552 date = util.parsedate(date)
2552 date = util.parsedate(date)
2553 else:
2553 else:
2554 date = None
2554 date = None
2555 prec = parsenodeid(precursor)
2555 prec = parsenodeid(precursor)
2556 parents = None
2556 parents = None
2557 if opts['record_parents']:
2557 if opts['record_parents']:
2558 if prec not in repo.unfiltered():
2558 if prec not in repo.unfiltered():
2559 raise util.Abort('cannot used --record-parents on '
2559 raise util.Abort('cannot used --record-parents on '
2560 'unknown changesets')
2560 'unknown changesets')
2561 parents = repo.unfiltered()[prec].parents()
2561 parents = repo.unfiltered()[prec].parents()
2562 parents = tuple(p.node() for p in parents)
2562 parents = tuple(p.node() for p in parents)
2563 repo.obsstore.create(tr, prec, succs, opts['flags'],
2563 repo.obsstore.create(tr, prec, succs, opts['flags'],
2564 parents=parents, date=date,
2564 parents=parents, date=date,
2565 metadata=metadata)
2565 metadata=metadata)
2566 tr.close()
2566 tr.close()
2567 except ValueError, exc:
2567 except ValueError, exc:
2568 raise util.Abort(_('bad obsmarker input: %s') % exc)
2568 raise util.Abort(_('bad obsmarker input: %s') % exc)
2569 finally:
2569 finally:
2570 tr.release()
2570 tr.release()
2571 finally:
2571 finally:
2572 l.release()
2572 l.release()
2573 else:
2573 else:
2574 if opts['rev']:
2574 if opts['rev']:
2575 revs = scmutil.revrange(repo, opts['rev'])
2575 revs = scmutil.revrange(repo, opts['rev'])
2576 nodes = [repo[r].node() for r in revs]
2576 nodes = [repo[r].node() for r in revs]
2577 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2577 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2578 markers.sort(key=lambda x: x._data)
2578 markers.sort(key=lambda x: x._data)
2579 else:
2579 else:
2580 markers = obsolete.getmarkers(repo)
2580 markers = obsolete.getmarkers(repo)
2581
2581
2582 for m in markers:
2582 for m in markers:
2583 cmdutil.showmarker(ui, m)
2583 cmdutil.showmarker(ui, m)
2584
2584
2585 @command('debugpathcomplete',
2585 @command('debugpathcomplete',
2586 [('f', 'full', None, _('complete an entire path')),
2586 [('f', 'full', None, _('complete an entire path')),
2587 ('n', 'normal', None, _('show only normal files')),
2587 ('n', 'normal', None, _('show only normal files')),
2588 ('a', 'added', None, _('show only added files')),
2588 ('a', 'added', None, _('show only added files')),
2589 ('r', 'removed', None, _('show only removed files'))],
2589 ('r', 'removed', None, _('show only removed files'))],
2590 _('FILESPEC...'))
2590 _('FILESPEC...'))
2591 def debugpathcomplete(ui, repo, *specs, **opts):
2591 def debugpathcomplete(ui, repo, *specs, **opts):
2592 '''complete part or all of a tracked path
2592 '''complete part or all of a tracked path
2593
2593
2594 This command supports shells that offer path name completion. It
2594 This command supports shells that offer path name completion. It
2595 currently completes only files already known to the dirstate.
2595 currently completes only files already known to the dirstate.
2596
2596
2597 Completion extends only to the next path segment unless
2597 Completion extends only to the next path segment unless
2598 --full is specified, in which case entire paths are used.'''
2598 --full is specified, in which case entire paths are used.'''
2599
2599
2600 def complete(path, acceptable):
2600 def complete(path, acceptable):
2601 dirstate = repo.dirstate
2601 dirstate = repo.dirstate
2602 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2602 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2603 rootdir = repo.root + os.sep
2603 rootdir = repo.root + os.sep
2604 if spec != repo.root and not spec.startswith(rootdir):
2604 if spec != repo.root and not spec.startswith(rootdir):
2605 return [], []
2605 return [], []
2606 if os.path.isdir(spec):
2606 if os.path.isdir(spec):
2607 spec += '/'
2607 spec += '/'
2608 spec = spec[len(rootdir):]
2608 spec = spec[len(rootdir):]
2609 fixpaths = os.sep != '/'
2609 fixpaths = os.sep != '/'
2610 if fixpaths:
2610 if fixpaths:
2611 spec = spec.replace(os.sep, '/')
2611 spec = spec.replace(os.sep, '/')
2612 speclen = len(spec)
2612 speclen = len(spec)
2613 fullpaths = opts['full']
2613 fullpaths = opts['full']
2614 files, dirs = set(), set()
2614 files, dirs = set(), set()
2615 adddir, addfile = dirs.add, files.add
2615 adddir, addfile = dirs.add, files.add
2616 for f, st in dirstate.iteritems():
2616 for f, st in dirstate.iteritems():
2617 if f.startswith(spec) and st[0] in acceptable:
2617 if f.startswith(spec) and st[0] in acceptable:
2618 if fixpaths:
2618 if fixpaths:
2619 f = f.replace('/', os.sep)
2619 f = f.replace('/', os.sep)
2620 if fullpaths:
2620 if fullpaths:
2621 addfile(f)
2621 addfile(f)
2622 continue
2622 continue
2623 s = f.find(os.sep, speclen)
2623 s = f.find(os.sep, speclen)
2624 if s >= 0:
2624 if s >= 0:
2625 adddir(f[:s])
2625 adddir(f[:s])
2626 else:
2626 else:
2627 addfile(f)
2627 addfile(f)
2628 return files, dirs
2628 return files, dirs
2629
2629
2630 acceptable = ''
2630 acceptable = ''
2631 if opts['normal']:
2631 if opts['normal']:
2632 acceptable += 'nm'
2632 acceptable += 'nm'
2633 if opts['added']:
2633 if opts['added']:
2634 acceptable += 'a'
2634 acceptable += 'a'
2635 if opts['removed']:
2635 if opts['removed']:
2636 acceptable += 'r'
2636 acceptable += 'r'
2637 cwd = repo.getcwd()
2637 cwd = repo.getcwd()
2638 if not specs:
2638 if not specs:
2639 specs = ['.']
2639 specs = ['.']
2640
2640
2641 files, dirs = set(), set()
2641 files, dirs = set(), set()
2642 for spec in specs:
2642 for spec in specs:
2643 f, d = complete(spec, acceptable or 'nmar')
2643 f, d = complete(spec, acceptable or 'nmar')
2644 files.update(f)
2644 files.update(f)
2645 dirs.update(d)
2645 dirs.update(d)
2646 files.update(dirs)
2646 files.update(dirs)
2647 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2647 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2648 ui.write('\n')
2648 ui.write('\n')
2649
2649
2650 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2650 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2651 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2651 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2652 '''access the pushkey key/value protocol
2652 '''access the pushkey key/value protocol
2653
2653
2654 With two args, list the keys in the given namespace.
2654 With two args, list the keys in the given namespace.
2655
2655
2656 With five args, set a key to new if it currently is set to old.
2656 With five args, set a key to new if it currently is set to old.
2657 Reports success or failure.
2657 Reports success or failure.
2658 '''
2658 '''
2659
2659
2660 target = hg.peer(ui, {}, repopath)
2660 target = hg.peer(ui, {}, repopath)
2661 if keyinfo:
2661 if keyinfo:
2662 key, old, new = keyinfo
2662 key, old, new = keyinfo
2663 r = target.pushkey(namespace, key, old, new)
2663 r = target.pushkey(namespace, key, old, new)
2664 ui.status(str(r) + '\n')
2664 ui.status(str(r) + '\n')
2665 return not r
2665 return not r
2666 else:
2666 else:
2667 for k, v in sorted(target.listkeys(namespace).iteritems()):
2667 for k, v in sorted(target.listkeys(namespace).iteritems()):
2668 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2668 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2669 v.encode('string-escape')))
2669 v.encode('string-escape')))
2670
2670
2671 @command('debugpvec', [], _('A B'))
2671 @command('debugpvec', [], _('A B'))
2672 def debugpvec(ui, repo, a, b=None):
2672 def debugpvec(ui, repo, a, b=None):
2673 ca = scmutil.revsingle(repo, a)
2673 ca = scmutil.revsingle(repo, a)
2674 cb = scmutil.revsingle(repo, b)
2674 cb = scmutil.revsingle(repo, b)
2675 pa = pvec.ctxpvec(ca)
2675 pa = pvec.ctxpvec(ca)
2676 pb = pvec.ctxpvec(cb)
2676 pb = pvec.ctxpvec(cb)
2677 if pa == pb:
2677 if pa == pb:
2678 rel = "="
2678 rel = "="
2679 elif pa > pb:
2679 elif pa > pb:
2680 rel = ">"
2680 rel = ">"
2681 elif pa < pb:
2681 elif pa < pb:
2682 rel = "<"
2682 rel = "<"
2683 elif pa | pb:
2683 elif pa | pb:
2684 rel = "|"
2684 rel = "|"
2685 ui.write(_("a: %s\n") % pa)
2685 ui.write(_("a: %s\n") % pa)
2686 ui.write(_("b: %s\n") % pb)
2686 ui.write(_("b: %s\n") % pb)
2687 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2687 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2688 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2688 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2689 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2689 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2690 pa.distance(pb), rel))
2690 pa.distance(pb), rel))
2691
2691
2692 @command('debugrebuilddirstate|debugrebuildstate',
2692 @command('debugrebuilddirstate|debugrebuildstate',
2693 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2693 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2694 _('[-r REV]'))
2694 _('[-r REV]'))
2695 def debugrebuilddirstate(ui, repo, rev):
2695 def debugrebuilddirstate(ui, repo, rev):
2696 """rebuild the dirstate as it would look like for the given revision
2696 """rebuild the dirstate as it would look like for the given revision
2697
2697
2698 If no revision is specified the first current parent will be used.
2698 If no revision is specified the first current parent will be used.
2699
2699
2700 The dirstate will be set to the files of the given revision.
2700 The dirstate will be set to the files of the given revision.
2701 The actual working directory content or existing dirstate
2701 The actual working directory content or existing dirstate
2702 information such as adds or removes is not considered.
2702 information such as adds or removes is not considered.
2703
2703
2704 One use of this command is to make the next :hg:`status` invocation
2704 One use of this command is to make the next :hg:`status` invocation
2705 check the actual file content.
2705 check the actual file content.
2706 """
2706 """
2707 ctx = scmutil.revsingle(repo, rev)
2707 ctx = scmutil.revsingle(repo, rev)
2708 wlock = repo.wlock()
2708 wlock = repo.wlock()
2709 try:
2709 try:
2710 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2710 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2711 finally:
2711 finally:
2712 wlock.release()
2712 wlock.release()
2713
2713
2714 @command('debugrename',
2714 @command('debugrename',
2715 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2715 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2716 _('[-r REV] FILE'))
2716 _('[-r REV] FILE'))
2717 def debugrename(ui, repo, file1, *pats, **opts):
2717 def debugrename(ui, repo, file1, *pats, **opts):
2718 """dump rename information"""
2718 """dump rename information"""
2719
2719
2720 ctx = scmutil.revsingle(repo, opts.get('rev'))
2720 ctx = scmutil.revsingle(repo, opts.get('rev'))
2721 m = scmutil.match(ctx, (file1,) + pats, opts)
2721 m = scmutil.match(ctx, (file1,) + pats, opts)
2722 for abs in ctx.walk(m):
2722 for abs in ctx.walk(m):
2723 fctx = ctx[abs]
2723 fctx = ctx[abs]
2724 o = fctx.filelog().renamed(fctx.filenode())
2724 o = fctx.filelog().renamed(fctx.filenode())
2725 rel = m.rel(abs)
2725 rel = m.rel(abs)
2726 if o:
2726 if o:
2727 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2727 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2728 else:
2728 else:
2729 ui.write(_("%s not renamed\n") % rel)
2729 ui.write(_("%s not renamed\n") % rel)
2730
2730
2731 @command('debugrevlog',
2731 @command('debugrevlog',
2732 [('c', 'changelog', False, _('open changelog')),
2732 [('c', 'changelog', False, _('open changelog')),
2733 ('m', 'manifest', False, _('open manifest')),
2733 ('m', 'manifest', False, _('open manifest')),
2734 ('', 'dir', False, _('open directory manifest')),
2734 ('', 'dir', False, _('open directory manifest')),
2735 ('d', 'dump', False, _('dump index data'))],
2735 ('d', 'dump', False, _('dump index data'))],
2736 _('-c|-m|FILE'),
2736 _('-c|-m|FILE'),
2737 optionalrepo=True)
2737 optionalrepo=True)
2738 def debugrevlog(ui, repo, file_=None, **opts):
2738 def debugrevlog(ui, repo, file_=None, **opts):
2739 """show data and statistics about a revlog"""
2739 """show data and statistics about a revlog"""
2740 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2740 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2741
2741
2742 if opts.get("dump"):
2742 if opts.get("dump"):
2743 numrevs = len(r)
2743 numrevs = len(r)
2744 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2744 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2745 " rawsize totalsize compression heads chainlen\n")
2745 " rawsize totalsize compression heads chainlen\n")
2746 ts = 0
2746 ts = 0
2747 heads = set()
2747 heads = set()
2748
2748
2749 for rev in xrange(numrevs):
2749 for rev in xrange(numrevs):
2750 dbase = r.deltaparent(rev)
2750 dbase = r.deltaparent(rev)
2751 if dbase == -1:
2751 if dbase == -1:
2752 dbase = rev
2752 dbase = rev
2753 cbase = r.chainbase(rev)
2753 cbase = r.chainbase(rev)
2754 clen = r.chainlen(rev)
2754 clen = r.chainlen(rev)
2755 p1, p2 = r.parentrevs(rev)
2755 p1, p2 = r.parentrevs(rev)
2756 rs = r.rawsize(rev)
2756 rs = r.rawsize(rev)
2757 ts = ts + rs
2757 ts = ts + rs
2758 heads -= set(r.parentrevs(rev))
2758 heads -= set(r.parentrevs(rev))
2759 heads.add(rev)
2759 heads.add(rev)
2760 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2760 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2761 "%11d %5d %8d\n" %
2761 "%11d %5d %8d\n" %
2762 (rev, p1, p2, r.start(rev), r.end(rev),
2762 (rev, p1, p2, r.start(rev), r.end(rev),
2763 r.start(dbase), r.start(cbase),
2763 r.start(dbase), r.start(cbase),
2764 r.start(p1), r.start(p2),
2764 r.start(p1), r.start(p2),
2765 rs, ts, ts / r.end(rev), len(heads), clen))
2765 rs, ts, ts / r.end(rev), len(heads), clen))
2766 return 0
2766 return 0
2767
2767
2768 v = r.version
2768 v = r.version
2769 format = v & 0xFFFF
2769 format = v & 0xFFFF
2770 flags = []
2770 flags = []
2771 gdelta = False
2771 gdelta = False
2772 if v & revlog.REVLOGNGINLINEDATA:
2772 if v & revlog.REVLOGNGINLINEDATA:
2773 flags.append('inline')
2773 flags.append('inline')
2774 if v & revlog.REVLOGGENERALDELTA:
2774 if v & revlog.REVLOGGENERALDELTA:
2775 gdelta = True
2775 gdelta = True
2776 flags.append('generaldelta')
2776 flags.append('generaldelta')
2777 if not flags:
2777 if not flags:
2778 flags = ['(none)']
2778 flags = ['(none)']
2779
2779
2780 nummerges = 0
2780 nummerges = 0
2781 numfull = 0
2781 numfull = 0
2782 numprev = 0
2782 numprev = 0
2783 nump1 = 0
2783 nump1 = 0
2784 nump2 = 0
2784 nump2 = 0
2785 numother = 0
2785 numother = 0
2786 nump1prev = 0
2786 nump1prev = 0
2787 nump2prev = 0
2787 nump2prev = 0
2788 chainlengths = []
2788 chainlengths = []
2789
2789
2790 datasize = [None, 0, 0L]
2790 datasize = [None, 0, 0L]
2791 fullsize = [None, 0, 0L]
2791 fullsize = [None, 0, 0L]
2792 deltasize = [None, 0, 0L]
2792 deltasize = [None, 0, 0L]
2793
2793
2794 def addsize(size, l):
2794 def addsize(size, l):
2795 if l[0] is None or size < l[0]:
2795 if l[0] is None or size < l[0]:
2796 l[0] = size
2796 l[0] = size
2797 if size > l[1]:
2797 if size > l[1]:
2798 l[1] = size
2798 l[1] = size
2799 l[2] += size
2799 l[2] += size
2800
2800
2801 numrevs = len(r)
2801 numrevs = len(r)
2802 for rev in xrange(numrevs):
2802 for rev in xrange(numrevs):
2803 p1, p2 = r.parentrevs(rev)
2803 p1, p2 = r.parentrevs(rev)
2804 delta = r.deltaparent(rev)
2804 delta = r.deltaparent(rev)
2805 if format > 0:
2805 if format > 0:
2806 addsize(r.rawsize(rev), datasize)
2806 addsize(r.rawsize(rev), datasize)
2807 if p2 != nullrev:
2807 if p2 != nullrev:
2808 nummerges += 1
2808 nummerges += 1
2809 size = r.length(rev)
2809 size = r.length(rev)
2810 if delta == nullrev:
2810 if delta == nullrev:
2811 chainlengths.append(0)
2811 chainlengths.append(0)
2812 numfull += 1
2812 numfull += 1
2813 addsize(size, fullsize)
2813 addsize(size, fullsize)
2814 else:
2814 else:
2815 chainlengths.append(chainlengths[delta] + 1)
2815 chainlengths.append(chainlengths[delta] + 1)
2816 addsize(size, deltasize)
2816 addsize(size, deltasize)
2817 if delta == rev - 1:
2817 if delta == rev - 1:
2818 numprev += 1
2818 numprev += 1
2819 if delta == p1:
2819 if delta == p1:
2820 nump1prev += 1
2820 nump1prev += 1
2821 elif delta == p2:
2821 elif delta == p2:
2822 nump2prev += 1
2822 nump2prev += 1
2823 elif delta == p1:
2823 elif delta == p1:
2824 nump1 += 1
2824 nump1 += 1
2825 elif delta == p2:
2825 elif delta == p2:
2826 nump2 += 1
2826 nump2 += 1
2827 elif delta != nullrev:
2827 elif delta != nullrev:
2828 numother += 1
2828 numother += 1
2829
2829
2830 # Adjust size min value for empty cases
2830 # Adjust size min value for empty cases
2831 for size in (datasize, fullsize, deltasize):
2831 for size in (datasize, fullsize, deltasize):
2832 if size[0] is None:
2832 if size[0] is None:
2833 size[0] = 0
2833 size[0] = 0
2834
2834
2835 numdeltas = numrevs - numfull
2835 numdeltas = numrevs - numfull
2836 numoprev = numprev - nump1prev - nump2prev
2836 numoprev = numprev - nump1prev - nump2prev
2837 totalrawsize = datasize[2]
2837 totalrawsize = datasize[2]
2838 datasize[2] /= numrevs
2838 datasize[2] /= numrevs
2839 fulltotal = fullsize[2]
2839 fulltotal = fullsize[2]
2840 fullsize[2] /= numfull
2840 fullsize[2] /= numfull
2841 deltatotal = deltasize[2]
2841 deltatotal = deltasize[2]
2842 if numrevs - numfull > 0:
2842 if numrevs - numfull > 0:
2843 deltasize[2] /= numrevs - numfull
2843 deltasize[2] /= numrevs - numfull
2844 totalsize = fulltotal + deltatotal
2844 totalsize = fulltotal + deltatotal
2845 avgchainlen = sum(chainlengths) / numrevs
2845 avgchainlen = sum(chainlengths) / numrevs
2846 maxchainlen = max(chainlengths)
2846 maxchainlen = max(chainlengths)
2847 compratio = totalrawsize / totalsize
2847 compratio = totalrawsize / totalsize
2848
2848
2849 basedfmtstr = '%%%dd\n'
2849 basedfmtstr = '%%%dd\n'
2850 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2850 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2851
2851
2852 def dfmtstr(max):
2852 def dfmtstr(max):
2853 return basedfmtstr % len(str(max))
2853 return basedfmtstr % len(str(max))
2854 def pcfmtstr(max, padding=0):
2854 def pcfmtstr(max, padding=0):
2855 return basepcfmtstr % (len(str(max)), ' ' * padding)
2855 return basepcfmtstr % (len(str(max)), ' ' * padding)
2856
2856
2857 def pcfmt(value, total):
2857 def pcfmt(value, total):
2858 return (value, 100 * float(value) / total)
2858 return (value, 100 * float(value) / total)
2859
2859
2860 ui.write(('format : %d\n') % format)
2860 ui.write(('format : %d\n') % format)
2861 ui.write(('flags : %s\n') % ', '.join(flags))
2861 ui.write(('flags : %s\n') % ', '.join(flags))
2862
2862
2863 ui.write('\n')
2863 ui.write('\n')
2864 fmt = pcfmtstr(totalsize)
2864 fmt = pcfmtstr(totalsize)
2865 fmt2 = dfmtstr(totalsize)
2865 fmt2 = dfmtstr(totalsize)
2866 ui.write(('revisions : ') + fmt2 % numrevs)
2866 ui.write(('revisions : ') + fmt2 % numrevs)
2867 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2867 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2868 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2868 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2869 ui.write(('revisions : ') + fmt2 % numrevs)
2869 ui.write(('revisions : ') + fmt2 % numrevs)
2870 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2870 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2871 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2871 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2872 ui.write(('revision size : ') + fmt2 % totalsize)
2872 ui.write(('revision size : ') + fmt2 % totalsize)
2873 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2873 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2874 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2874 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2875
2875
2876 ui.write('\n')
2876 ui.write('\n')
2877 fmt = dfmtstr(max(avgchainlen, compratio))
2877 fmt = dfmtstr(max(avgchainlen, compratio))
2878 ui.write(('avg chain length : ') + fmt % avgchainlen)
2878 ui.write(('avg chain length : ') + fmt % avgchainlen)
2879 ui.write(('max chain length : ') + fmt % maxchainlen)
2879 ui.write(('max chain length : ') + fmt % maxchainlen)
2880 ui.write(('compression ratio : ') + fmt % compratio)
2880 ui.write(('compression ratio : ') + fmt % compratio)
2881
2881
2882 if format > 0:
2882 if format > 0:
2883 ui.write('\n')
2883 ui.write('\n')
2884 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2884 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2885 % tuple(datasize))
2885 % tuple(datasize))
2886 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2886 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2887 % tuple(fullsize))
2887 % tuple(fullsize))
2888 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2888 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2889 % tuple(deltasize))
2889 % tuple(deltasize))
2890
2890
2891 if numdeltas > 0:
2891 if numdeltas > 0:
2892 ui.write('\n')
2892 ui.write('\n')
2893 fmt = pcfmtstr(numdeltas)
2893 fmt = pcfmtstr(numdeltas)
2894 fmt2 = pcfmtstr(numdeltas, 4)
2894 fmt2 = pcfmtstr(numdeltas, 4)
2895 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2895 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2896 if numprev > 0:
2896 if numprev > 0:
2897 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2897 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2898 numprev))
2898 numprev))
2899 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2899 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2900 numprev))
2900 numprev))
2901 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2901 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2902 numprev))
2902 numprev))
2903 if gdelta:
2903 if gdelta:
2904 ui.write(('deltas against p1 : ')
2904 ui.write(('deltas against p1 : ')
2905 + fmt % pcfmt(nump1, numdeltas))
2905 + fmt % pcfmt(nump1, numdeltas))
2906 ui.write(('deltas against p2 : ')
2906 ui.write(('deltas against p2 : ')
2907 + fmt % pcfmt(nump2, numdeltas))
2907 + fmt % pcfmt(nump2, numdeltas))
2908 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2908 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2909 numdeltas))
2909 numdeltas))
2910
2910
2911 @command('debugrevspec',
2911 @command('debugrevspec',
2912 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2912 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2913 ('REVSPEC'))
2913 ('REVSPEC'))
2914 def debugrevspec(ui, repo, expr, **opts):
2914 def debugrevspec(ui, repo, expr, **opts):
2915 """parse and apply a revision specification
2915 """parse and apply a revision specification
2916
2916
2917 Use --verbose to print the parsed tree before and after aliases
2917 Use --verbose to print the parsed tree before and after aliases
2918 expansion.
2918 expansion.
2919 """
2919 """
2920 if ui.verbose:
2920 if ui.verbose:
2921 tree = revset.parse(expr)
2921 tree = revset.parse(expr)
2922 ui.note(revset.prettyformat(tree), "\n")
2922 ui.note(revset.prettyformat(tree), "\n")
2923 newtree = revset.findaliases(ui, tree)
2923 newtree = revset.findaliases(ui, tree)
2924 if newtree != tree:
2924 if newtree != tree:
2925 ui.note(revset.prettyformat(newtree), "\n")
2925 ui.note(revset.prettyformat(newtree), "\n")
2926 tree = newtree
2926 tree = newtree
2927 newtree = revset.foldconcat(tree)
2927 newtree = revset.foldconcat(tree)
2928 if newtree != tree:
2928 if newtree != tree:
2929 ui.note(revset.prettyformat(newtree), "\n")
2929 ui.note(revset.prettyformat(newtree), "\n")
2930 if opts["optimize"]:
2930 if opts["optimize"]:
2931 weight, optimizedtree = revset.optimize(newtree, True)
2931 weight, optimizedtree = revset.optimize(newtree, True)
2932 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2932 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2933 func = revset.match(ui, expr)
2933 func = revset.match(ui, expr)
2934 revs = func(repo)
2934 revs = func(repo)
2935 if ui.verbose:
2935 if ui.verbose:
2936 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2936 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2937 for c in revs:
2937 for c in revs:
2938 ui.write("%s\n" % c)
2938 ui.write("%s\n" % c)
2939
2939
2940 @command('debugsetparents', [], _('REV1 [REV2]'))
2940 @command('debugsetparents', [], _('REV1 [REV2]'))
2941 def debugsetparents(ui, repo, rev1, rev2=None):
2941 def debugsetparents(ui, repo, rev1, rev2=None):
2942 """manually set the parents of the current working directory
2942 """manually set the parents of the current working directory
2943
2943
2944 This is useful for writing repository conversion tools, but should
2944 This is useful for writing repository conversion tools, but should
2945 be used with care. For example, neither the working directory nor the
2945 be used with care. For example, neither the working directory nor the
2946 dirstate is updated, so file status may be incorrect after running this
2946 dirstate is updated, so file status may be incorrect after running this
2947 command.
2947 command.
2948
2948
2949 Returns 0 on success.
2949 Returns 0 on success.
2950 """
2950 """
2951
2951
2952 r1 = scmutil.revsingle(repo, rev1).node()
2952 r1 = scmutil.revsingle(repo, rev1).node()
2953 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2953 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2954
2954
2955 wlock = repo.wlock()
2955 wlock = repo.wlock()
2956 try:
2956 try:
2957 repo.dirstate.beginparentchange()
2957 repo.dirstate.beginparentchange()
2958 repo.setparents(r1, r2)
2958 repo.setparents(r1, r2)
2959 repo.dirstate.endparentchange()
2959 repo.dirstate.endparentchange()
2960 finally:
2960 finally:
2961 wlock.release()
2961 wlock.release()
2962
2962
2963 @command('debugdirstate|debugstate',
2963 @command('debugdirstate|debugstate',
2964 [('', 'nodates', None, _('do not display the saved mtime')),
2964 [('', 'nodates', None, _('do not display the saved mtime')),
2965 ('', 'datesort', None, _('sort by saved mtime'))],
2965 ('', 'datesort', None, _('sort by saved mtime'))],
2966 _('[OPTION]...'))
2966 _('[OPTION]...'))
2967 def debugstate(ui, repo, nodates=None, datesort=None):
2967 def debugstate(ui, repo, nodates=None, datesort=None):
2968 """show the contents of the current dirstate"""
2968 """show the contents of the current dirstate"""
2969 timestr = ""
2969 timestr = ""
2970 if datesort:
2970 if datesort:
2971 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2971 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2972 else:
2972 else:
2973 keyfunc = None # sort by filename
2973 keyfunc = None # sort by filename
2974 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2974 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2975 if ent[3] == -1:
2975 if ent[3] == -1:
2976 timestr = 'unset '
2976 timestr = 'unset '
2977 elif nodates:
2977 elif nodates:
2978 timestr = 'set '
2978 timestr = 'set '
2979 else:
2979 else:
2980 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2980 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2981 time.localtime(ent[3]))
2981 time.localtime(ent[3]))
2982 if ent[1] & 020000:
2982 if ent[1] & 020000:
2983 mode = 'lnk'
2983 mode = 'lnk'
2984 else:
2984 else:
2985 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2985 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2986 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2986 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2987 for f in repo.dirstate.copies():
2987 for f in repo.dirstate.copies():
2988 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2988 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2989
2989
2990 @command('debugsub',
2990 @command('debugsub',
2991 [('r', 'rev', '',
2991 [('r', 'rev', '',
2992 _('revision to check'), _('REV'))],
2992 _('revision to check'), _('REV'))],
2993 _('[-r REV] [REV]'))
2993 _('[-r REV] [REV]'))
2994 def debugsub(ui, repo, rev=None):
2994 def debugsub(ui, repo, rev=None):
2995 ctx = scmutil.revsingle(repo, rev, None)
2995 ctx = scmutil.revsingle(repo, rev, None)
2996 for k, v in sorted(ctx.substate.items()):
2996 for k, v in sorted(ctx.substate.items()):
2997 ui.write(('path %s\n') % k)
2997 ui.write(('path %s\n') % k)
2998 ui.write((' source %s\n') % v[0])
2998 ui.write((' source %s\n') % v[0])
2999 ui.write((' revision %s\n') % v[1])
2999 ui.write((' revision %s\n') % v[1])
3000
3000
3001 @command('debugsuccessorssets',
3001 @command('debugsuccessorssets',
3002 [],
3002 [],
3003 _('[REV]'))
3003 _('[REV]'))
3004 def debugsuccessorssets(ui, repo, *revs):
3004 def debugsuccessorssets(ui, repo, *revs):
3005 """show set of successors for revision
3005 """show set of successors for revision
3006
3006
3007 A successors set of changeset A is a consistent group of revisions that
3007 A successors set of changeset A is a consistent group of revisions that
3008 succeed A. It contains non-obsolete changesets only.
3008 succeed A. It contains non-obsolete changesets only.
3009
3009
3010 In most cases a changeset A has a single successors set containing a single
3010 In most cases a changeset A has a single successors set containing a single
3011 successor (changeset A replaced by A').
3011 successor (changeset A replaced by A').
3012
3012
3013 A changeset that is made obsolete with no successors are called "pruned".
3013 A changeset that is made obsolete with no successors are called "pruned".
3014 Such changesets have no successors sets at all.
3014 Such changesets have no successors sets at all.
3015
3015
3016 A changeset that has been "split" will have a successors set containing
3016 A changeset that has been "split" will have a successors set containing
3017 more than one successor.
3017 more than one successor.
3018
3018
3019 A changeset that has been rewritten in multiple different ways is called
3019 A changeset that has been rewritten in multiple different ways is called
3020 "divergent". Such changesets have multiple successor sets (each of which
3020 "divergent". Such changesets have multiple successor sets (each of which
3021 may also be split, i.e. have multiple successors).
3021 may also be split, i.e. have multiple successors).
3022
3022
3023 Results are displayed as follows::
3023 Results are displayed as follows::
3024
3024
3025 <rev1>
3025 <rev1>
3026 <successors-1A>
3026 <successors-1A>
3027 <rev2>
3027 <rev2>
3028 <successors-2A>
3028 <successors-2A>
3029 <successors-2B1> <successors-2B2> <successors-2B3>
3029 <successors-2B1> <successors-2B2> <successors-2B3>
3030
3030
3031 Here rev2 has two possible (i.e. divergent) successors sets. The first
3031 Here rev2 has two possible (i.e. divergent) successors sets. The first
3032 holds one element, whereas the second holds three (i.e. the changeset has
3032 holds one element, whereas the second holds three (i.e. the changeset has
3033 been split).
3033 been split).
3034 """
3034 """
3035 # passed to successorssets caching computation from one call to another
3035 # passed to successorssets caching computation from one call to another
3036 cache = {}
3036 cache = {}
3037 ctx2str = str
3037 ctx2str = str
3038 node2str = short
3038 node2str = short
3039 if ui.debug():
3039 if ui.debug():
3040 def ctx2str(ctx):
3040 def ctx2str(ctx):
3041 return ctx.hex()
3041 return ctx.hex()
3042 node2str = hex
3042 node2str = hex
3043 for rev in scmutil.revrange(repo, revs):
3043 for rev in scmutil.revrange(repo, revs):
3044 ctx = repo[rev]
3044 ctx = repo[rev]
3045 ui.write('%s\n'% ctx2str(ctx))
3045 ui.write('%s\n'% ctx2str(ctx))
3046 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3046 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3047 if succsset:
3047 if succsset:
3048 ui.write(' ')
3048 ui.write(' ')
3049 ui.write(node2str(succsset[0]))
3049 ui.write(node2str(succsset[0]))
3050 for node in succsset[1:]:
3050 for node in succsset[1:]:
3051 ui.write(' ')
3051 ui.write(' ')
3052 ui.write(node2str(node))
3052 ui.write(node2str(node))
3053 ui.write('\n')
3053 ui.write('\n')
3054
3054
3055 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3055 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3056 def debugwalk(ui, repo, *pats, **opts):
3056 def debugwalk(ui, repo, *pats, **opts):
3057 """show how files match on given patterns"""
3057 """show how files match on given patterns"""
3058 m = scmutil.match(repo[None], pats, opts)
3058 m = scmutil.match(repo[None], pats, opts)
3059 items = list(repo.walk(m))
3059 items = list(repo.walk(m))
3060 if not items:
3060 if not items:
3061 return
3061 return
3062 f = lambda fn: fn
3062 f = lambda fn: fn
3063 if ui.configbool('ui', 'slash') and os.sep != '/':
3063 if ui.configbool('ui', 'slash') and os.sep != '/':
3064 f = lambda fn: util.normpath(fn)
3064 f = lambda fn: util.normpath(fn)
3065 fmt = 'f %%-%ds %%-%ds %%s' % (
3065 fmt = 'f %%-%ds %%-%ds %%s' % (
3066 max([len(abs) for abs in items]),
3066 max([len(abs) for abs in items]),
3067 max([len(m.rel(abs)) for abs in items]))
3067 max([len(m.rel(abs)) for abs in items]))
3068 for abs in items:
3068 for abs in items:
3069 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3069 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3070 ui.write("%s\n" % line.rstrip())
3070 ui.write("%s\n" % line.rstrip())
3071
3071
3072 @command('debugwireargs',
3072 @command('debugwireargs',
3073 [('', 'three', '', 'three'),
3073 [('', 'three', '', 'three'),
3074 ('', 'four', '', 'four'),
3074 ('', 'four', '', 'four'),
3075 ('', 'five', '', 'five'),
3075 ('', 'five', '', 'five'),
3076 ] + remoteopts,
3076 ] + remoteopts,
3077 _('REPO [OPTIONS]... [ONE [TWO]]'),
3077 _('REPO [OPTIONS]... [ONE [TWO]]'),
3078 norepo=True)
3078 norepo=True)
3079 def debugwireargs(ui, repopath, *vals, **opts):
3079 def debugwireargs(ui, repopath, *vals, **opts):
3080 repo = hg.peer(ui, opts, repopath)
3080 repo = hg.peer(ui, opts, repopath)
3081 for opt in remoteopts:
3081 for opt in remoteopts:
3082 del opts[opt[1]]
3082 del opts[opt[1]]
3083 args = {}
3083 args = {}
3084 for k, v in opts.iteritems():
3084 for k, v in opts.iteritems():
3085 if v:
3085 if v:
3086 args[k] = v
3086 args[k] = v
3087 # run twice to check that we don't mess up the stream for the next command
3087 # run twice to check that we don't mess up the stream for the next command
3088 res1 = repo.debugwireargs(*vals, **args)
3088 res1 = repo.debugwireargs(*vals, **args)
3089 res2 = repo.debugwireargs(*vals, **args)
3089 res2 = repo.debugwireargs(*vals, **args)
3090 ui.write("%s\n" % res1)
3090 ui.write("%s\n" % res1)
3091 if res1 != res2:
3091 if res1 != res2:
3092 ui.warn("%s\n" % res2)
3092 ui.warn("%s\n" % res2)
3093
3093
3094 @command('^diff',
3094 @command('^diff',
3095 [('r', 'rev', [], _('revision'), _('REV')),
3095 [('r', 'rev', [], _('revision'), _('REV')),
3096 ('c', 'change', '', _('change made by revision'), _('REV'))
3096 ('c', 'change', '', _('change made by revision'), _('REV'))
3097 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3097 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3098 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3098 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3099 inferrepo=True)
3099 inferrepo=True)
3100 def diff(ui, repo, *pats, **opts):
3100 def diff(ui, repo, *pats, **opts):
3101 """diff repository (or selected files)
3101 """diff repository (or selected files)
3102
3102
3103 Show differences between revisions for the specified files.
3103 Show differences between revisions for the specified files.
3104
3104
3105 Differences between files are shown using the unified diff format.
3105 Differences between files are shown using the unified diff format.
3106
3106
3107 .. note::
3107 .. note::
3108
3108
3109 diff may generate unexpected results for merges, as it will
3109 diff may generate unexpected results for merges, as it will
3110 default to comparing against the working directory's first
3110 default to comparing against the working directory's first
3111 parent changeset if no revisions are specified.
3111 parent changeset if no revisions are specified.
3112
3112
3113 When two revision arguments are given, then changes are shown
3113 When two revision arguments are given, then changes are shown
3114 between those revisions. If only one revision is specified then
3114 between those revisions. If only one revision is specified then
3115 that revision is compared to the working directory, and, when no
3115 that revision is compared to the working directory, and, when no
3116 revisions are specified, the working directory files are compared
3116 revisions are specified, the working directory files are compared
3117 to its parent.
3117 to its parent.
3118
3118
3119 Alternatively you can specify -c/--change with a revision to see
3119 Alternatively you can specify -c/--change with a revision to see
3120 the changes in that changeset relative to its first parent.
3120 the changes in that changeset relative to its first parent.
3121
3121
3122 Without the -a/--text option, diff will avoid generating diffs of
3122 Without the -a/--text option, diff will avoid generating diffs of
3123 files it detects as binary. With -a, diff will generate a diff
3123 files it detects as binary. With -a, diff will generate a diff
3124 anyway, probably with undesirable results.
3124 anyway, probably with undesirable results.
3125
3125
3126 Use the -g/--git option to generate diffs in the git extended diff
3126 Use the -g/--git option to generate diffs in the git extended diff
3127 format. For more information, read :hg:`help diffs`.
3127 format. For more information, read :hg:`help diffs`.
3128
3128
3129 .. container:: verbose
3129 .. container:: verbose
3130
3130
3131 Examples:
3131 Examples:
3132
3132
3133 - compare a file in the current working directory to its parent::
3133 - compare a file in the current working directory to its parent::
3134
3134
3135 hg diff foo.c
3135 hg diff foo.c
3136
3136
3137 - compare two historical versions of a directory, with rename info::
3137 - compare two historical versions of a directory, with rename info::
3138
3138
3139 hg diff --git -r 1.0:1.2 lib/
3139 hg diff --git -r 1.0:1.2 lib/
3140
3140
3141 - get change stats relative to the last change on some date::
3141 - get change stats relative to the last change on some date::
3142
3142
3143 hg diff --stat -r "date('may 2')"
3143 hg diff --stat -r "date('may 2')"
3144
3144
3145 - diff all newly-added files that contain a keyword::
3145 - diff all newly-added files that contain a keyword::
3146
3146
3147 hg diff "set:added() and grep(GNU)"
3147 hg diff "set:added() and grep(GNU)"
3148
3148
3149 - compare a revision and its parents::
3149 - compare a revision and its parents::
3150
3150
3151 hg diff -c 9353 # compare against first parent
3151 hg diff -c 9353 # compare against first parent
3152 hg diff -r 9353^:9353 # same using revset syntax
3152 hg diff -r 9353^:9353 # same using revset syntax
3153 hg diff -r 9353^2:9353 # compare against the second parent
3153 hg diff -r 9353^2:9353 # compare against the second parent
3154
3154
3155 Returns 0 on success.
3155 Returns 0 on success.
3156 """
3156 """
3157
3157
3158 revs = opts.get('rev')
3158 revs = opts.get('rev')
3159 change = opts.get('change')
3159 change = opts.get('change')
3160 stat = opts.get('stat')
3160 stat = opts.get('stat')
3161 reverse = opts.get('reverse')
3161 reverse = opts.get('reverse')
3162
3162
3163 if revs and change:
3163 if revs and change:
3164 msg = _('cannot specify --rev and --change at the same time')
3164 msg = _('cannot specify --rev and --change at the same time')
3165 raise util.Abort(msg)
3165 raise util.Abort(msg)
3166 elif change:
3166 elif change:
3167 node2 = scmutil.revsingle(repo, change, None).node()
3167 node2 = scmutil.revsingle(repo, change, None).node()
3168 node1 = repo[node2].p1().node()
3168 node1 = repo[node2].p1().node()
3169 else:
3169 else:
3170 node1, node2 = scmutil.revpair(repo, revs)
3170 node1, node2 = scmutil.revpair(repo, revs)
3171
3171
3172 if reverse:
3172 if reverse:
3173 node1, node2 = node2, node1
3173 node1, node2 = node2, node1
3174
3174
3175 diffopts = patch.diffallopts(ui, opts)
3175 diffopts = patch.diffallopts(ui, opts)
3176 m = scmutil.match(repo[node2], pats, opts)
3176 m = scmutil.match(repo[node2], pats, opts)
3177 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3177 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3178 listsubrepos=opts.get('subrepos'),
3178 listsubrepos=opts.get('subrepos'),
3179 root=opts.get('root'))
3179 root=opts.get('root'))
3180
3180
3181 @command('^export',
3181 @command('^export',
3182 [('o', 'output', '',
3182 [('o', 'output', '',
3183 _('print output to file with formatted name'), _('FORMAT')),
3183 _('print output to file with formatted name'), _('FORMAT')),
3184 ('', 'switch-parent', None, _('diff against the second parent')),
3184 ('', 'switch-parent', None, _('diff against the second parent')),
3185 ('r', 'rev', [], _('revisions to export'), _('REV')),
3185 ('r', 'rev', [], _('revisions to export'), _('REV')),
3186 ] + diffopts,
3186 ] + diffopts,
3187 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3187 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3188 def export(ui, repo, *changesets, **opts):
3188 def export(ui, repo, *changesets, **opts):
3189 """dump the header and diffs for one or more changesets
3189 """dump the header and diffs for one or more changesets
3190
3190
3191 Print the changeset header and diffs for one or more revisions.
3191 Print the changeset header and diffs for one or more revisions.
3192 If no revision is given, the parent of the working directory is used.
3192 If no revision is given, the parent of the working directory is used.
3193
3193
3194 The information shown in the changeset header is: author, date,
3194 The information shown in the changeset header is: author, date,
3195 branch name (if non-default), changeset hash, parent(s) and commit
3195 branch name (if non-default), changeset hash, parent(s) and commit
3196 comment.
3196 comment.
3197
3197
3198 .. note::
3198 .. note::
3199
3199
3200 export may generate unexpected diff output for merge
3200 export may generate unexpected diff output for merge
3201 changesets, as it will compare the merge changeset against its
3201 changesets, as it will compare the merge changeset against its
3202 first parent only.
3202 first parent only.
3203
3203
3204 Output may be to a file, in which case the name of the file is
3204 Output may be to a file, in which case the name of the file is
3205 given using a format string. The formatting rules are as follows:
3205 given using a format string. The formatting rules are as follows:
3206
3206
3207 :``%%``: literal "%" character
3207 :``%%``: literal "%" character
3208 :``%H``: changeset hash (40 hexadecimal digits)
3208 :``%H``: changeset hash (40 hexadecimal digits)
3209 :``%N``: number of patches being generated
3209 :``%N``: number of patches being generated
3210 :``%R``: changeset revision number
3210 :``%R``: changeset revision number
3211 :``%b``: basename of the exporting repository
3211 :``%b``: basename of the exporting repository
3212 :``%h``: short-form changeset hash (12 hexadecimal digits)
3212 :``%h``: short-form changeset hash (12 hexadecimal digits)
3213 :``%m``: first line of the commit message (only alphanumeric characters)
3213 :``%m``: first line of the commit message (only alphanumeric characters)
3214 :``%n``: zero-padded sequence number, starting at 1
3214 :``%n``: zero-padded sequence number, starting at 1
3215 :``%r``: zero-padded changeset revision number
3215 :``%r``: zero-padded changeset revision number
3216
3216
3217 Without the -a/--text option, export will avoid generating diffs
3217 Without the -a/--text option, export will avoid generating diffs
3218 of files it detects as binary. With -a, export will generate a
3218 of files it detects as binary. With -a, export will generate a
3219 diff anyway, probably with undesirable results.
3219 diff anyway, probably with undesirable results.
3220
3220
3221 Use the -g/--git option to generate diffs in the git extended diff
3221 Use the -g/--git option to generate diffs in the git extended diff
3222 format. See :hg:`help diffs` for more information.
3222 format. See :hg:`help diffs` for more information.
3223
3223
3224 With the --switch-parent option, the diff will be against the
3224 With the --switch-parent option, the diff will be against the
3225 second parent. It can be useful to review a merge.
3225 second parent. It can be useful to review a merge.
3226
3226
3227 .. container:: verbose
3227 .. container:: verbose
3228
3228
3229 Examples:
3229 Examples:
3230
3230
3231 - use export and import to transplant a bugfix to the current
3231 - use export and import to transplant a bugfix to the current
3232 branch::
3232 branch::
3233
3233
3234 hg export -r 9353 | hg import -
3234 hg export -r 9353 | hg import -
3235
3235
3236 - export all the changesets between two revisions to a file with
3236 - export all the changesets between two revisions to a file with
3237 rename information::
3237 rename information::
3238
3238
3239 hg export --git -r 123:150 > changes.txt
3239 hg export --git -r 123:150 > changes.txt
3240
3240
3241 - split outgoing changes into a series of patches with
3241 - split outgoing changes into a series of patches with
3242 descriptive names::
3242 descriptive names::
3243
3243
3244 hg export -r "outgoing()" -o "%n-%m.patch"
3244 hg export -r "outgoing()" -o "%n-%m.patch"
3245
3245
3246 Returns 0 on success.
3246 Returns 0 on success.
3247 """
3247 """
3248 changesets += tuple(opts.get('rev', []))
3248 changesets += tuple(opts.get('rev', []))
3249 if not changesets:
3249 if not changesets:
3250 changesets = ['.']
3250 changesets = ['.']
3251 revs = scmutil.revrange(repo, changesets)
3251 revs = scmutil.revrange(repo, changesets)
3252 if not revs:
3252 if not revs:
3253 raise util.Abort(_("export requires at least one changeset"))
3253 raise util.Abort(_("export requires at least one changeset"))
3254 if len(revs) > 1:
3254 if len(revs) > 1:
3255 ui.note(_('exporting patches:\n'))
3255 ui.note(_('exporting patches:\n'))
3256 else:
3256 else:
3257 ui.note(_('exporting patch:\n'))
3257 ui.note(_('exporting patch:\n'))
3258 cmdutil.export(repo, revs, template=opts.get('output'),
3258 cmdutil.export(repo, revs, template=opts.get('output'),
3259 switch_parent=opts.get('switch_parent'),
3259 switch_parent=opts.get('switch_parent'),
3260 opts=patch.diffallopts(ui, opts))
3260 opts=patch.diffallopts(ui, opts))
3261
3261
3262 @command('files',
3262 @command('files',
3263 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3263 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3264 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3265 ] + walkopts + formatteropts + subrepoopts,
3265 ] + walkopts + formatteropts + subrepoopts,
3266 _('[OPTION]... [PATTERN]...'))
3266 _('[OPTION]... [PATTERN]...'))
3267 def files(ui, repo, *pats, **opts):
3267 def files(ui, repo, *pats, **opts):
3268 """list tracked files
3268 """list tracked files
3269
3269
3270 Print files under Mercurial control in the working directory or
3270 Print files under Mercurial control in the working directory or
3271 specified revision whose names match the given patterns (excluding
3271 specified revision whose names match the given patterns (excluding
3272 removed files).
3272 removed files).
3273
3273
3274 If no patterns are given to match, this command prints the names
3274 If no patterns are given to match, this command prints the names
3275 of all files under Mercurial control in the working directory.
3275 of all files under Mercurial control in the working directory.
3276
3276
3277 .. container:: verbose
3277 .. container:: verbose
3278
3278
3279 Examples:
3279 Examples:
3280
3280
3281 - list all files under the current directory::
3281 - list all files under the current directory::
3282
3282
3283 hg files .
3283 hg files .
3284
3284
3285 - shows sizes and flags for current revision::
3285 - shows sizes and flags for current revision::
3286
3286
3287 hg files -vr .
3287 hg files -vr .
3288
3288
3289 - list all files named README::
3289 - list all files named README::
3290
3290
3291 hg files -I "**/README"
3291 hg files -I "**/README"
3292
3292
3293 - list all binary files::
3293 - list all binary files::
3294
3294
3295 hg files "set:binary()"
3295 hg files "set:binary()"
3296
3296
3297 - find files containing a regular expression::
3297 - find files containing a regular expression::
3298
3298
3299 hg files "set:grep('bob')"
3299 hg files "set:grep('bob')"
3300
3300
3301 - search tracked file contents with xargs and grep::
3301 - search tracked file contents with xargs and grep::
3302
3302
3303 hg files -0 | xargs -0 grep foo
3303 hg files -0 | xargs -0 grep foo
3304
3304
3305 See :hg:`help patterns` and :hg:`help filesets` for more information
3305 See :hg:`help patterns` and :hg:`help filesets` for more information
3306 on specifying file patterns.
3306 on specifying file patterns.
3307
3307
3308 Returns 0 if a match is found, 1 otherwise.
3308 Returns 0 if a match is found, 1 otherwise.
3309
3309
3310 """
3310 """
3311 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3311 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3312
3312
3313 end = '\n'
3313 end = '\n'
3314 if opts.get('print0'):
3314 if opts.get('print0'):
3315 end = '\0'
3315 end = '\0'
3316 fm = ui.formatter('files', opts)
3316 fm = ui.formatter('files', opts)
3317 fmt = '%s' + end
3317 fmt = '%s' + end
3318
3318
3319 m = scmutil.match(ctx, pats, opts)
3319 m = scmutil.match(ctx, pats, opts)
3320 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3320 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3321
3321
3322 fm.end()
3322 fm.end()
3323
3323
3324 return ret
3324 return ret
3325
3325
3326 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3326 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3327 def forget(ui, repo, *pats, **opts):
3327 def forget(ui, repo, *pats, **opts):
3328 """forget the specified files on the next commit
3328 """forget the specified files on the next commit
3329
3329
3330 Mark the specified files so they will no longer be tracked
3330 Mark the specified files so they will no longer be tracked
3331 after the next commit.
3331 after the next commit.
3332
3332
3333 This only removes files from the current branch, not from the
3333 This only removes files from the current branch, not from the
3334 entire project history, and it does not delete them from the
3334 entire project history, and it does not delete them from the
3335 working directory.
3335 working directory.
3336
3336
3337 To undo a forget before the next commit, see :hg:`add`.
3337 To undo a forget before the next commit, see :hg:`add`.
3338
3338
3339 .. container:: verbose
3339 .. container:: verbose
3340
3340
3341 Examples:
3341 Examples:
3342
3342
3343 - forget newly-added binary files::
3343 - forget newly-added binary files::
3344
3344
3345 hg forget "set:added() and binary()"
3345 hg forget "set:added() and binary()"
3346
3346
3347 - forget files that would be excluded by .hgignore::
3347 - forget files that would be excluded by .hgignore::
3348
3348
3349 hg forget "set:hgignore()"
3349 hg forget "set:hgignore()"
3350
3350
3351 Returns 0 on success.
3351 Returns 0 on success.
3352 """
3352 """
3353
3353
3354 if not pats:
3354 if not pats:
3355 raise util.Abort(_('no files specified'))
3355 raise util.Abort(_('no files specified'))
3356
3356
3357 m = scmutil.match(repo[None], pats, opts)
3357 m = scmutil.match(repo[None], pats, opts)
3358 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3358 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3359 return rejected and 1 or 0
3359 return rejected and 1 or 0
3360
3360
3361 @command(
3361 @command(
3362 'graft',
3362 'graft',
3363 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3363 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3364 ('c', 'continue', False, _('resume interrupted graft')),
3364 ('c', 'continue', False, _('resume interrupted graft')),
3365 ('e', 'edit', False, _('invoke editor on commit messages')),
3365 ('e', 'edit', False, _('invoke editor on commit messages')),
3366 ('', 'log', None, _('append graft info to log message')),
3366 ('', 'log', None, _('append graft info to log message')),
3367 ('f', 'force', False, _('force graft')),
3367 ('f', 'force', False, _('force graft')),
3368 ('D', 'currentdate', False,
3368 ('D', 'currentdate', False,
3369 _('record the current date as commit date')),
3369 _('record the current date as commit date')),
3370 ('U', 'currentuser', False,
3370 ('U', 'currentuser', False,
3371 _('record the current user as committer'), _('DATE'))]
3371 _('record the current user as committer'), _('DATE'))]
3372 + commitopts2 + mergetoolopts + dryrunopts,
3372 + commitopts2 + mergetoolopts + dryrunopts,
3373 _('[OPTION]... [-r] REV...'))
3373 _('[OPTION]... [-r] REV...'))
3374 def graft(ui, repo, *revs, **opts):
3374 def graft(ui, repo, *revs, **opts):
3375 '''copy changes from other branches onto the current branch
3375 '''copy changes from other branches onto the current branch
3376
3376
3377 This command uses Mercurial's merge logic to copy individual
3377 This command uses Mercurial's merge logic to copy individual
3378 changes from other branches without merging branches in the
3378 changes from other branches without merging branches in the
3379 history graph. This is sometimes known as 'backporting' or
3379 history graph. This is sometimes known as 'backporting' or
3380 'cherry-picking'. By default, graft will copy user, date, and
3380 'cherry-picking'. By default, graft will copy user, date, and
3381 description from the source changesets.
3381 description from the source changesets.
3382
3382
3383 Changesets that are ancestors of the current revision, that have
3383 Changesets that are ancestors of the current revision, that have
3384 already been grafted, or that are merges will be skipped.
3384 already been grafted, or that are merges will be skipped.
3385
3385
3386 If --log is specified, log messages will have a comment appended
3386 If --log is specified, log messages will have a comment appended
3387 of the form::
3387 of the form::
3388
3388
3389 (grafted from CHANGESETHASH)
3389 (grafted from CHANGESETHASH)
3390
3390
3391 If --force is specified, revisions will be grafted even if they
3391 If --force is specified, revisions will be grafted even if they
3392 are already ancestors of or have been grafted to the destination.
3392 are already ancestors of or have been grafted to the destination.
3393 This is useful when the revisions have since been backed out.
3393 This is useful when the revisions have since been backed out.
3394
3394
3395 If a graft merge results in conflicts, the graft process is
3395 If a graft merge results in conflicts, the graft process is
3396 interrupted so that the current merge can be manually resolved.
3396 interrupted so that the current merge can be manually resolved.
3397 Once all conflicts are addressed, the graft process can be
3397 Once all conflicts are addressed, the graft process can be
3398 continued with the -c/--continue option.
3398 continued with the -c/--continue option.
3399
3399
3400 .. note::
3400 .. note::
3401
3401
3402 The -c/--continue option does not reapply earlier options, except
3402 The -c/--continue option does not reapply earlier options, except
3403 for --force.
3403 for --force.
3404
3404
3405 .. container:: verbose
3405 .. container:: verbose
3406
3406
3407 Examples:
3407 Examples:
3408
3408
3409 - copy a single change to the stable branch and edit its description::
3409 - copy a single change to the stable branch and edit its description::
3410
3410
3411 hg update stable
3411 hg update stable
3412 hg graft --edit 9393
3412 hg graft --edit 9393
3413
3413
3414 - graft a range of changesets with one exception, updating dates::
3414 - graft a range of changesets with one exception, updating dates::
3415
3415
3416 hg graft -D "2085::2093 and not 2091"
3416 hg graft -D "2085::2093 and not 2091"
3417
3417
3418 - continue a graft after resolving conflicts::
3418 - continue a graft after resolving conflicts::
3419
3419
3420 hg graft -c
3420 hg graft -c
3421
3421
3422 - show the source of a grafted changeset::
3422 - show the source of a grafted changeset::
3423
3423
3424 hg log --debug -r .
3424 hg log --debug -r .
3425
3425
3426 See :hg:`help revisions` and :hg:`help revsets` for more about
3426 See :hg:`help revisions` and :hg:`help revsets` for more about
3427 specifying revisions.
3427 specifying revisions.
3428
3428
3429 Returns 0 on successful completion.
3429 Returns 0 on successful completion.
3430 '''
3430 '''
3431
3431
3432 revs = list(revs)
3432 revs = list(revs)
3433 revs.extend(opts['rev'])
3433 revs.extend(opts['rev'])
3434
3434
3435 if not opts.get('user') and opts.get('currentuser'):
3435 if not opts.get('user') and opts.get('currentuser'):
3436 opts['user'] = ui.username()
3436 opts['user'] = ui.username()
3437 if not opts.get('date') and opts.get('currentdate'):
3437 if not opts.get('date') and opts.get('currentdate'):
3438 opts['date'] = "%d %d" % util.makedate()
3438 opts['date'] = "%d %d" % util.makedate()
3439
3439
3440 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3440 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3441
3441
3442 cont = False
3442 cont = False
3443 if opts['continue']:
3443 if opts['continue']:
3444 cont = True
3444 cont = True
3445 if revs:
3445 if revs:
3446 raise util.Abort(_("can't specify --continue and revisions"))
3446 raise util.Abort(_("can't specify --continue and revisions"))
3447 # read in unfinished revisions
3447 # read in unfinished revisions
3448 try:
3448 try:
3449 nodes = repo.vfs.read('graftstate').splitlines()
3449 nodes = repo.vfs.read('graftstate').splitlines()
3450 revs = [repo[node].rev() for node in nodes]
3450 revs = [repo[node].rev() for node in nodes]
3451 except IOError, inst:
3451 except IOError, inst:
3452 if inst.errno != errno.ENOENT:
3452 if inst.errno != errno.ENOENT:
3453 raise
3453 raise
3454 raise util.Abort(_("no graft state found, can't continue"))
3454 raise util.Abort(_("no graft state found, can't continue"))
3455 else:
3455 else:
3456 cmdutil.checkunfinished(repo)
3456 cmdutil.checkunfinished(repo)
3457 cmdutil.bailifchanged(repo)
3457 cmdutil.bailifchanged(repo)
3458 if not revs:
3458 if not revs:
3459 raise util.Abort(_('no revisions specified'))
3459 raise util.Abort(_('no revisions specified'))
3460 revs = scmutil.revrange(repo, revs)
3460 revs = scmutil.revrange(repo, revs)
3461
3461
3462 skipped = set()
3462 skipped = set()
3463 # check for merges
3463 # check for merges
3464 for rev in repo.revs('%ld and merge()', revs):
3464 for rev in repo.revs('%ld and merge()', revs):
3465 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3465 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3466 skipped.add(rev)
3466 skipped.add(rev)
3467 revs = [r for r in revs if r not in skipped]
3467 revs = [r for r in revs if r not in skipped]
3468 if not revs:
3468 if not revs:
3469 return -1
3469 return -1
3470
3470
3471 # Don't check in the --continue case, in effect retaining --force across
3471 # Don't check in the --continue case, in effect retaining --force across
3472 # --continues. That's because without --force, any revisions we decided to
3472 # --continues. That's because without --force, any revisions we decided to
3473 # skip would have been filtered out here, so they wouldn't have made their
3473 # skip would have been filtered out here, so they wouldn't have made their
3474 # way to the graftstate. With --force, any revisions we would have otherwise
3474 # way to the graftstate. With --force, any revisions we would have otherwise
3475 # skipped would not have been filtered out, and if they hadn't been applied
3475 # skipped would not have been filtered out, and if they hadn't been applied
3476 # already, they'd have been in the graftstate.
3476 # already, they'd have been in the graftstate.
3477 if not (cont or opts.get('force')):
3477 if not (cont or opts.get('force')):
3478 # check for ancestors of dest branch
3478 # check for ancestors of dest branch
3479 crev = repo['.'].rev()
3479 crev = repo['.'].rev()
3480 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3480 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3481 # Cannot use x.remove(y) on smart set, this has to be a list.
3481 # Cannot use x.remove(y) on smart set, this has to be a list.
3482 # XXX make this lazy in the future
3482 # XXX make this lazy in the future
3483 revs = list(revs)
3483 revs = list(revs)
3484 # don't mutate while iterating, create a copy
3484 # don't mutate while iterating, create a copy
3485 for rev in list(revs):
3485 for rev in list(revs):
3486 if rev in ancestors:
3486 if rev in ancestors:
3487 ui.warn(_('skipping ancestor revision %d:%s\n') %
3487 ui.warn(_('skipping ancestor revision %d:%s\n') %
3488 (rev, repo[rev]))
3488 (rev, repo[rev]))
3489 # XXX remove on list is slow
3489 # XXX remove on list is slow
3490 revs.remove(rev)
3490 revs.remove(rev)
3491 if not revs:
3491 if not revs:
3492 return -1
3492 return -1
3493
3493
3494 # analyze revs for earlier grafts
3494 # analyze revs for earlier grafts
3495 ids = {}
3495 ids = {}
3496 for ctx in repo.set("%ld", revs):
3496 for ctx in repo.set("%ld", revs):
3497 ids[ctx.hex()] = ctx.rev()
3497 ids[ctx.hex()] = ctx.rev()
3498 n = ctx.extra().get('source')
3498 n = ctx.extra().get('source')
3499 if n:
3499 if n:
3500 ids[n] = ctx.rev()
3500 ids[n] = ctx.rev()
3501
3501
3502 # check ancestors for earlier grafts
3502 # check ancestors for earlier grafts
3503 ui.debug('scanning for duplicate grafts\n')
3503 ui.debug('scanning for duplicate grafts\n')
3504
3504
3505 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3505 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3506 ctx = repo[rev]
3506 ctx = repo[rev]
3507 n = ctx.extra().get('source')
3507 n = ctx.extra().get('source')
3508 if n in ids:
3508 if n in ids:
3509 try:
3509 try:
3510 r = repo[n].rev()
3510 r = repo[n].rev()
3511 except error.RepoLookupError:
3511 except error.RepoLookupError:
3512 r = None
3512 r = None
3513 if r in revs:
3513 if r in revs:
3514 ui.warn(_('skipping revision %d:%s '
3514 ui.warn(_('skipping revision %d:%s '
3515 '(already grafted to %d:%s)\n')
3515 '(already grafted to %d:%s)\n')
3516 % (r, repo[r], rev, ctx))
3516 % (r, repo[r], rev, ctx))
3517 revs.remove(r)
3517 revs.remove(r)
3518 elif ids[n] in revs:
3518 elif ids[n] in revs:
3519 if r is None:
3519 if r is None:
3520 ui.warn(_('skipping already grafted revision %d:%s '
3520 ui.warn(_('skipping already grafted revision %d:%s '
3521 '(%d:%s also has unknown origin %s)\n')
3521 '(%d:%s also has unknown origin %s)\n')
3522 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3522 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3523 else:
3523 else:
3524 ui.warn(_('skipping already grafted revision %d:%s '
3524 ui.warn(_('skipping already grafted revision %d:%s '
3525 '(%d:%s also has origin %d:%s)\n')
3525 '(%d:%s also has origin %d:%s)\n')
3526 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3526 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3527 revs.remove(ids[n])
3527 revs.remove(ids[n])
3528 elif ctx.hex() in ids:
3528 elif ctx.hex() in ids:
3529 r = ids[ctx.hex()]
3529 r = ids[ctx.hex()]
3530 ui.warn(_('skipping already grafted revision %d:%s '
3530 ui.warn(_('skipping already grafted revision %d:%s '
3531 '(was grafted from %d:%s)\n') %
3531 '(was grafted from %d:%s)\n') %
3532 (r, repo[r], rev, ctx))
3532 (r, repo[r], rev, ctx))
3533 revs.remove(r)
3533 revs.remove(r)
3534 if not revs:
3534 if not revs:
3535 return -1
3535 return -1
3536
3536
3537 wlock = repo.wlock()
3537 wlock = repo.wlock()
3538 try:
3538 try:
3539 for pos, ctx in enumerate(repo.set("%ld", revs)):
3539 for pos, ctx in enumerate(repo.set("%ld", revs)):
3540 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3540 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3541 ctx.description().split('\n', 1)[0])
3541 ctx.description().split('\n', 1)[0])
3542 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3542 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3543 if names:
3543 if names:
3544 desc += ' (%s)' % ' '.join(names)
3544 desc += ' (%s)' % ' '.join(names)
3545 ui.status(_('grafting %s\n') % desc)
3545 ui.status(_('grafting %s\n') % desc)
3546 if opts.get('dry_run'):
3546 if opts.get('dry_run'):
3547 continue
3547 continue
3548
3548
3549 source = ctx.extra().get('source')
3549 source = ctx.extra().get('source')
3550 extra = {}
3550 extra = {}
3551 if source:
3551 if source:
3552 extra['source'] = source
3552 extra['source'] = source
3553 extra['intermediate-source'] = ctx.hex()
3553 extra['intermediate-source'] = ctx.hex()
3554 else:
3554 else:
3555 extra['source'] = ctx.hex()
3555 extra['source'] = ctx.hex()
3556 user = ctx.user()
3556 user = ctx.user()
3557 if opts.get('user'):
3557 if opts.get('user'):
3558 user = opts['user']
3558 user = opts['user']
3559 date = ctx.date()
3559 date = ctx.date()
3560 if opts.get('date'):
3560 if opts.get('date'):
3561 date = opts['date']
3561 date = opts['date']
3562 message = ctx.description()
3562 message = ctx.description()
3563 if opts.get('log'):
3563 if opts.get('log'):
3564 message += '\n(grafted from %s)' % ctx.hex()
3564 message += '\n(grafted from %s)' % ctx.hex()
3565
3565
3566 # we don't merge the first commit when continuing
3566 # we don't merge the first commit when continuing
3567 if not cont:
3567 if not cont:
3568 # perform the graft merge with p1(rev) as 'ancestor'
3568 # perform the graft merge with p1(rev) as 'ancestor'
3569 try:
3569 try:
3570 # ui.forcemerge is an internal variable, do not document
3570 # ui.forcemerge is an internal variable, do not document
3571 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3571 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3572 'graft')
3572 'graft')
3573 stats = mergemod.graft(repo, ctx, ctx.p1(),
3573 stats = mergemod.graft(repo, ctx, ctx.p1(),
3574 ['local', 'graft'])
3574 ['local', 'graft'])
3575 finally:
3575 finally:
3576 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3576 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3577 # report any conflicts
3577 # report any conflicts
3578 if stats and stats[3] > 0:
3578 if stats and stats[3] > 0:
3579 # write out state for --continue
3579 # write out state for --continue
3580 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3580 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3581 repo.vfs.write('graftstate', ''.join(nodelines))
3581 repo.vfs.write('graftstate', ''.join(nodelines))
3582 raise util.Abort(
3582 raise util.Abort(
3583 _("unresolved conflicts, can't continue"),
3583 _("unresolved conflicts, can't continue"),
3584 hint=_('use hg resolve and hg graft --continue'))
3584 hint=_('use hg resolve and hg graft --continue'))
3585 else:
3585 else:
3586 cont = False
3586 cont = False
3587
3587
3588 # commit
3588 # commit
3589 node = repo.commit(text=message, user=user,
3589 node = repo.commit(text=message, user=user,
3590 date=date, extra=extra, editor=editor)
3590 date=date, extra=extra, editor=editor)
3591 if node is None:
3591 if node is None:
3592 ui.warn(
3592 ui.warn(
3593 _('note: graft of %d:%s created no changes to commit\n') %
3593 _('note: graft of %d:%s created no changes to commit\n') %
3594 (ctx.rev(), ctx))
3594 (ctx.rev(), ctx))
3595 finally:
3595 finally:
3596 wlock.release()
3596 wlock.release()
3597
3597
3598 # remove state when we complete successfully
3598 # remove state when we complete successfully
3599 if not opts.get('dry_run'):
3599 if not opts.get('dry_run'):
3600 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3600 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3601
3601
3602 return 0
3602 return 0
3603
3603
3604 @command('grep',
3604 @command('grep',
3605 [('0', 'print0', None, _('end fields with NUL')),
3605 [('0', 'print0', None, _('end fields with NUL')),
3606 ('', 'all', None, _('print all revisions that match')),
3606 ('', 'all', None, _('print all revisions that match')),
3607 ('a', 'text', None, _('treat all files as text')),
3607 ('a', 'text', None, _('treat all files as text')),
3608 ('f', 'follow', None,
3608 ('f', 'follow', None,
3609 _('follow changeset history,'
3609 _('follow changeset history,'
3610 ' or file history across copies and renames')),
3610 ' or file history across copies and renames')),
3611 ('i', 'ignore-case', None, _('ignore case when matching')),
3611 ('i', 'ignore-case', None, _('ignore case when matching')),
3612 ('l', 'files-with-matches', None,
3612 ('l', 'files-with-matches', None,
3613 _('print only filenames and revisions that match')),
3613 _('print only filenames and revisions that match')),
3614 ('n', 'line-number', None, _('print matching line numbers')),
3614 ('n', 'line-number', None, _('print matching line numbers')),
3615 ('r', 'rev', [],
3615 ('r', 'rev', [],
3616 _('only search files changed within revision range'), _('REV')),
3616 _('only search files changed within revision range'), _('REV')),
3617 ('u', 'user', None, _('list the author (long with -v)')),
3617 ('u', 'user', None, _('list the author (long with -v)')),
3618 ('d', 'date', None, _('list the date (short with -q)')),
3618 ('d', 'date', None, _('list the date (short with -q)')),
3619 ] + walkopts,
3619 ] + walkopts,
3620 _('[OPTION]... PATTERN [FILE]...'),
3620 _('[OPTION]... PATTERN [FILE]...'),
3621 inferrepo=True)
3621 inferrepo=True)
3622 def grep(ui, repo, pattern, *pats, **opts):
3622 def grep(ui, repo, pattern, *pats, **opts):
3623 """search for a pattern in specified files and revisions
3623 """search for a pattern in specified files and revisions
3624
3624
3625 Search revisions of files for a regular expression.
3625 Search revisions of files for a regular expression.
3626
3626
3627 This command behaves differently than Unix grep. It only accepts
3627 This command behaves differently than Unix grep. It only accepts
3628 Python/Perl regexps. It searches repository history, not the
3628 Python/Perl regexps. It searches repository history, not the
3629 working directory. It always prints the revision number in which a
3629 working directory. It always prints the revision number in which a
3630 match appears.
3630 match appears.
3631
3631
3632 By default, grep only prints output for the first revision of a
3632 By default, grep only prints output for the first revision of a
3633 file in which it finds a match. To get it to print every revision
3633 file in which it finds a match. To get it to print every revision
3634 that contains a change in match status ("-" for a match that
3634 that contains a change in match status ("-" for a match that
3635 becomes a non-match, or "+" for a non-match that becomes a match),
3635 becomes a non-match, or "+" for a non-match that becomes a match),
3636 use the --all flag.
3636 use the --all flag.
3637
3637
3638 Returns 0 if a match is found, 1 otherwise.
3638 Returns 0 if a match is found, 1 otherwise.
3639 """
3639 """
3640 reflags = re.M
3640 reflags = re.M
3641 if opts.get('ignore_case'):
3641 if opts.get('ignore_case'):
3642 reflags |= re.I
3642 reflags |= re.I
3643 try:
3643 try:
3644 regexp = util.re.compile(pattern, reflags)
3644 regexp = util.re.compile(pattern, reflags)
3645 except re.error, inst:
3645 except re.error, inst:
3646 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3646 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3647 return 1
3647 return 1
3648 sep, eol = ':', '\n'
3648 sep, eol = ':', '\n'
3649 if opts.get('print0'):
3649 if opts.get('print0'):
3650 sep = eol = '\0'
3650 sep = eol = '\0'
3651
3651
3652 getfile = util.lrucachefunc(repo.file)
3652 getfile = util.lrucachefunc(repo.file)
3653
3653
3654 def matchlines(body):
3654 def matchlines(body):
3655 begin = 0
3655 begin = 0
3656 linenum = 0
3656 linenum = 0
3657 while begin < len(body):
3657 while begin < len(body):
3658 match = regexp.search(body, begin)
3658 match = regexp.search(body, begin)
3659 if not match:
3659 if not match:
3660 break
3660 break
3661 mstart, mend = match.span()
3661 mstart, mend = match.span()
3662 linenum += body.count('\n', begin, mstart) + 1
3662 linenum += body.count('\n', begin, mstart) + 1
3663 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3663 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3664 begin = body.find('\n', mend) + 1 or len(body) + 1
3664 begin = body.find('\n', mend) + 1 or len(body) + 1
3665 lend = begin - 1
3665 lend = begin - 1
3666 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3666 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3667
3667
3668 class linestate(object):
3668 class linestate(object):
3669 def __init__(self, line, linenum, colstart, colend):
3669 def __init__(self, line, linenum, colstart, colend):
3670 self.line = line
3670 self.line = line
3671 self.linenum = linenum
3671 self.linenum = linenum
3672 self.colstart = colstart
3672 self.colstart = colstart
3673 self.colend = colend
3673 self.colend = colend
3674
3674
3675 def __hash__(self):
3675 def __hash__(self):
3676 return hash((self.linenum, self.line))
3676 return hash((self.linenum, self.line))
3677
3677
3678 def __eq__(self, other):
3678 def __eq__(self, other):
3679 return self.line == other.line
3679 return self.line == other.line
3680
3680
3681 def __iter__(self):
3681 def __iter__(self):
3682 yield (self.line[:self.colstart], '')
3682 yield (self.line[:self.colstart], '')
3683 yield (self.line[self.colstart:self.colend], 'grep.match')
3683 yield (self.line[self.colstart:self.colend], 'grep.match')
3684 rest = self.line[self.colend:]
3684 rest = self.line[self.colend:]
3685 while rest != '':
3685 while rest != '':
3686 match = regexp.search(rest)
3686 match = regexp.search(rest)
3687 if not match:
3687 if not match:
3688 yield (rest, '')
3688 yield (rest, '')
3689 break
3689 break
3690 mstart, mend = match.span()
3690 mstart, mend = match.span()
3691 yield (rest[:mstart], '')
3691 yield (rest[:mstart], '')
3692 yield (rest[mstart:mend], 'grep.match')
3692 yield (rest[mstart:mend], 'grep.match')
3693 rest = rest[mend:]
3693 rest = rest[mend:]
3694
3694
3695 matches = {}
3695 matches = {}
3696 copies = {}
3696 copies = {}
3697 def grepbody(fn, rev, body):
3697 def grepbody(fn, rev, body):
3698 matches[rev].setdefault(fn, [])
3698 matches[rev].setdefault(fn, [])
3699 m = matches[rev][fn]
3699 m = matches[rev][fn]
3700 for lnum, cstart, cend, line in matchlines(body):
3700 for lnum, cstart, cend, line in matchlines(body):
3701 s = linestate(line, lnum, cstart, cend)
3701 s = linestate(line, lnum, cstart, cend)
3702 m.append(s)
3702 m.append(s)
3703
3703
3704 def difflinestates(a, b):
3704 def difflinestates(a, b):
3705 sm = difflib.SequenceMatcher(None, a, b)
3705 sm = difflib.SequenceMatcher(None, a, b)
3706 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3706 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3707 if tag == 'insert':
3707 if tag == 'insert':
3708 for i in xrange(blo, bhi):
3708 for i in xrange(blo, bhi):
3709 yield ('+', b[i])
3709 yield ('+', b[i])
3710 elif tag == 'delete':
3710 elif tag == 'delete':
3711 for i in xrange(alo, ahi):
3711 for i in xrange(alo, ahi):
3712 yield ('-', a[i])
3712 yield ('-', a[i])
3713 elif tag == 'replace':
3713 elif tag == 'replace':
3714 for i in xrange(alo, ahi):
3714 for i in xrange(alo, ahi):
3715 yield ('-', a[i])
3715 yield ('-', a[i])
3716 for i in xrange(blo, bhi):
3716 for i in xrange(blo, bhi):
3717 yield ('+', b[i])
3717 yield ('+', b[i])
3718
3718
3719 def display(fn, ctx, pstates, states):
3719 def display(fn, ctx, pstates, states):
3720 rev = ctx.rev()
3720 rev = ctx.rev()
3721 if ui.quiet:
3721 if ui.quiet:
3722 datefunc = util.shortdate
3722 datefunc = util.shortdate
3723 else:
3723 else:
3724 datefunc = util.datestr
3724 datefunc = util.datestr
3725 found = False
3725 found = False
3726 @util.cachefunc
3726 @util.cachefunc
3727 def binary():
3727 def binary():
3728 flog = getfile(fn)
3728 flog = getfile(fn)
3729 return util.binary(flog.read(ctx.filenode(fn)))
3729 return util.binary(flog.read(ctx.filenode(fn)))
3730
3730
3731 if opts.get('all'):
3731 if opts.get('all'):
3732 iter = difflinestates(pstates, states)
3732 iter = difflinestates(pstates, states)
3733 else:
3733 else:
3734 iter = [('', l) for l in states]
3734 iter = [('', l) for l in states]
3735 for change, l in iter:
3735 for change, l in iter:
3736 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3736 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3737
3737
3738 if opts.get('line_number'):
3738 if opts.get('line_number'):
3739 cols.append((str(l.linenum), 'grep.linenumber'))
3739 cols.append((str(l.linenum), 'grep.linenumber'))
3740 if opts.get('all'):
3740 if opts.get('all'):
3741 cols.append((change, 'grep.change'))
3741 cols.append((change, 'grep.change'))
3742 if opts.get('user'):
3742 if opts.get('user'):
3743 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3743 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3744 if opts.get('date'):
3744 if opts.get('date'):
3745 cols.append((datefunc(ctx.date()), 'grep.date'))
3745 cols.append((datefunc(ctx.date()), 'grep.date'))
3746 for col, label in cols[:-1]:
3746 for col, label in cols[:-1]:
3747 ui.write(col, label=label)
3747 ui.write(col, label=label)
3748 ui.write(sep, label='grep.sep')
3748 ui.write(sep, label='grep.sep')
3749 ui.write(cols[-1][0], label=cols[-1][1])
3749 ui.write(cols[-1][0], label=cols[-1][1])
3750 if not opts.get('files_with_matches'):
3750 if not opts.get('files_with_matches'):
3751 ui.write(sep, label='grep.sep')
3751 ui.write(sep, label='grep.sep')
3752 if not opts.get('text') and binary():
3752 if not opts.get('text') and binary():
3753 ui.write(" Binary file matches")
3753 ui.write(" Binary file matches")
3754 else:
3754 else:
3755 for s, label in l:
3755 for s, label in l:
3756 ui.write(s, label=label)
3756 ui.write(s, label=label)
3757 ui.write(eol)
3757 ui.write(eol)
3758 found = True
3758 found = True
3759 if opts.get('files_with_matches'):
3759 if opts.get('files_with_matches'):
3760 break
3760 break
3761 return found
3761 return found
3762
3762
3763 skip = {}
3763 skip = {}
3764 revfiles = {}
3764 revfiles = {}
3765 matchfn = scmutil.match(repo[None], pats, opts)
3765 matchfn = scmutil.match(repo[None], pats, opts)
3766 found = False
3766 found = False
3767 follow = opts.get('follow')
3767 follow = opts.get('follow')
3768
3768
3769 def prep(ctx, fns):
3769 def prep(ctx, fns):
3770 rev = ctx.rev()
3770 rev = ctx.rev()
3771 pctx = ctx.p1()
3771 pctx = ctx.p1()
3772 parent = pctx.rev()
3772 parent = pctx.rev()
3773 matches.setdefault(rev, {})
3773 matches.setdefault(rev, {})
3774 matches.setdefault(parent, {})
3774 matches.setdefault(parent, {})
3775 files = revfiles.setdefault(rev, [])
3775 files = revfiles.setdefault(rev, [])
3776 for fn in fns:
3776 for fn in fns:
3777 flog = getfile(fn)
3777 flog = getfile(fn)
3778 try:
3778 try:
3779 fnode = ctx.filenode(fn)
3779 fnode = ctx.filenode(fn)
3780 except error.LookupError:
3780 except error.LookupError:
3781 continue
3781 continue
3782
3782
3783 copied = flog.renamed(fnode)
3783 copied = flog.renamed(fnode)
3784 copy = follow and copied and copied[0]
3784 copy = follow and copied and copied[0]
3785 if copy:
3785 if copy:
3786 copies.setdefault(rev, {})[fn] = copy
3786 copies.setdefault(rev, {})[fn] = copy
3787 if fn in skip:
3787 if fn in skip:
3788 if copy:
3788 if copy:
3789 skip[copy] = True
3789 skip[copy] = True
3790 continue
3790 continue
3791 files.append(fn)
3791 files.append(fn)
3792
3792
3793 if fn not in matches[rev]:
3793 if fn not in matches[rev]:
3794 grepbody(fn, rev, flog.read(fnode))
3794 grepbody(fn, rev, flog.read(fnode))
3795
3795
3796 pfn = copy or fn
3796 pfn = copy or fn
3797 if pfn not in matches[parent]:
3797 if pfn not in matches[parent]:
3798 try:
3798 try:
3799 fnode = pctx.filenode(pfn)
3799 fnode = pctx.filenode(pfn)
3800 grepbody(pfn, parent, flog.read(fnode))
3800 grepbody(pfn, parent, flog.read(fnode))
3801 except error.LookupError:
3801 except error.LookupError:
3802 pass
3802 pass
3803
3803
3804 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3804 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3805 rev = ctx.rev()
3805 rev = ctx.rev()
3806 parent = ctx.p1().rev()
3806 parent = ctx.p1().rev()
3807 for fn in sorted(revfiles.get(rev, [])):
3807 for fn in sorted(revfiles.get(rev, [])):
3808 states = matches[rev][fn]
3808 states = matches[rev][fn]
3809 copy = copies.get(rev, {}).get(fn)
3809 copy = copies.get(rev, {}).get(fn)
3810 if fn in skip:
3810 if fn in skip:
3811 if copy:
3811 if copy:
3812 skip[copy] = True
3812 skip[copy] = True
3813 continue
3813 continue
3814 pstates = matches.get(parent, {}).get(copy or fn, [])
3814 pstates = matches.get(parent, {}).get(copy or fn, [])
3815 if pstates or states:
3815 if pstates or states:
3816 r = display(fn, ctx, pstates, states)
3816 r = display(fn, ctx, pstates, states)
3817 found = found or r
3817 found = found or r
3818 if r and not opts.get('all'):
3818 if r and not opts.get('all'):
3819 skip[fn] = True
3819 skip[fn] = True
3820 if copy:
3820 if copy:
3821 skip[copy] = True
3821 skip[copy] = True
3822 del matches[rev]
3822 del matches[rev]
3823 del revfiles[rev]
3823 del revfiles[rev]
3824
3824
3825 return not found
3825 return not found
3826
3826
3827 @command('heads',
3827 @command('heads',
3828 [('r', 'rev', '',
3828 [('r', 'rev', '',
3829 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3829 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3830 ('t', 'topo', False, _('show topological heads only')),
3830 ('t', 'topo', False, _('show topological heads only')),
3831 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3831 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3832 ('c', 'closed', False, _('show normal and closed branch heads')),
3832 ('c', 'closed', False, _('show normal and closed branch heads')),
3833 ] + templateopts,
3833 ] + templateopts,
3834 _('[-ct] [-r STARTREV] [REV]...'))
3834 _('[-ct] [-r STARTREV] [REV]...'))
3835 def heads(ui, repo, *branchrevs, **opts):
3835 def heads(ui, repo, *branchrevs, **opts):
3836 """show branch heads
3836 """show branch heads
3837
3837
3838 With no arguments, show all open branch heads in the repository.
3838 With no arguments, show all open branch heads in the repository.
3839 Branch heads are changesets that have no descendants on the
3839 Branch heads are changesets that have no descendants on the
3840 same branch. They are where development generally takes place and
3840 same branch. They are where development generally takes place and
3841 are the usual targets for update and merge operations.
3841 are the usual targets for update and merge operations.
3842
3842
3843 If one or more REVs are given, only open branch heads on the
3843 If one or more REVs are given, only open branch heads on the
3844 branches associated with the specified changesets are shown. This
3844 branches associated with the specified changesets are shown. This
3845 means that you can use :hg:`heads .` to see the heads on the
3845 means that you can use :hg:`heads .` to see the heads on the
3846 currently checked-out branch.
3846 currently checked-out branch.
3847
3847
3848 If -c/--closed is specified, also show branch heads marked closed
3848 If -c/--closed is specified, also show branch heads marked closed
3849 (see :hg:`commit --close-branch`).
3849 (see :hg:`commit --close-branch`).
3850
3850
3851 If STARTREV is specified, only those heads that are descendants of
3851 If STARTREV is specified, only those heads that are descendants of
3852 STARTREV will be displayed.
3852 STARTREV will be displayed.
3853
3853
3854 If -t/--topo is specified, named branch mechanics will be ignored and only
3854 If -t/--topo is specified, named branch mechanics will be ignored and only
3855 topological heads (changesets with no children) will be shown.
3855 topological heads (changesets with no children) will be shown.
3856
3856
3857 Returns 0 if matching heads are found, 1 if not.
3857 Returns 0 if matching heads are found, 1 if not.
3858 """
3858 """
3859
3859
3860 start = None
3860 start = None
3861 if 'rev' in opts:
3861 if 'rev' in opts:
3862 start = scmutil.revsingle(repo, opts['rev'], None).node()
3862 start = scmutil.revsingle(repo, opts['rev'], None).node()
3863
3863
3864 if opts.get('topo'):
3864 if opts.get('topo'):
3865 heads = [repo[h] for h in repo.heads(start)]
3865 heads = [repo[h] for h in repo.heads(start)]
3866 else:
3866 else:
3867 heads = []
3867 heads = []
3868 for branch in repo.branchmap():
3868 for branch in repo.branchmap():
3869 heads += repo.branchheads(branch, start, opts.get('closed'))
3869 heads += repo.branchheads(branch, start, opts.get('closed'))
3870 heads = [repo[h] for h in heads]
3870 heads = [repo[h] for h in heads]
3871
3871
3872 if branchrevs:
3872 if branchrevs:
3873 branches = set(repo[br].branch() for br in branchrevs)
3873 branches = set(repo[br].branch() for br in branchrevs)
3874 heads = [h for h in heads if h.branch() in branches]
3874 heads = [h for h in heads if h.branch() in branches]
3875
3875
3876 if opts.get('active') and branchrevs:
3876 if opts.get('active') and branchrevs:
3877 dagheads = repo.heads(start)
3877 dagheads = repo.heads(start)
3878 heads = [h for h in heads if h.node() in dagheads]
3878 heads = [h for h in heads if h.node() in dagheads]
3879
3879
3880 if branchrevs:
3880 if branchrevs:
3881 haveheads = set(h.branch() for h in heads)
3881 haveheads = set(h.branch() for h in heads)
3882 if branches - haveheads:
3882 if branches - haveheads:
3883 headless = ', '.join(b for b in branches - haveheads)
3883 headless = ', '.join(b for b in branches - haveheads)
3884 msg = _('no open branch heads found on branches %s')
3884 msg = _('no open branch heads found on branches %s')
3885 if opts.get('rev'):
3885 if opts.get('rev'):
3886 msg += _(' (started at %s)') % opts['rev']
3886 msg += _(' (started at %s)') % opts['rev']
3887 ui.warn((msg + '\n') % headless)
3887 ui.warn((msg + '\n') % headless)
3888
3888
3889 if not heads:
3889 if not heads:
3890 return 1
3890 return 1
3891
3891
3892 heads = sorted(heads, key=lambda x: -x.rev())
3892 heads = sorted(heads, key=lambda x: -x.rev())
3893 displayer = cmdutil.show_changeset(ui, repo, opts)
3893 displayer = cmdutil.show_changeset(ui, repo, opts)
3894 for ctx in heads:
3894 for ctx in heads:
3895 displayer.show(ctx)
3895 displayer.show(ctx)
3896 displayer.close()
3896 displayer.close()
3897
3897
3898 @command('help',
3898 @command('help',
3899 [('e', 'extension', None, _('show only help for extensions')),
3899 [('e', 'extension', None, _('show only help for extensions')),
3900 ('c', 'command', None, _('show only help for commands')),
3900 ('c', 'command', None, _('show only help for commands')),
3901 ('k', 'keyword', '', _('show topics matching keyword')),
3901 ('k', 'keyword', '', _('show topics matching keyword')),
3902 ],
3902 ],
3903 _('[-ec] [TOPIC]'),
3903 _('[-ec] [TOPIC]'),
3904 norepo=True)
3904 norepo=True)
3905 def help_(ui, name=None, **opts):
3905 def help_(ui, name=None, **opts):
3906 """show help for a given topic or a help overview
3906 """show help for a given topic or a help overview
3907
3907
3908 With no arguments, print a list of commands with short help messages.
3908 With no arguments, print a list of commands with short help messages.
3909
3909
3910 Given a topic, extension, or command name, print help for that
3910 Given a topic, extension, or command name, print help for that
3911 topic.
3911 topic.
3912
3912
3913 Returns 0 if successful.
3913 Returns 0 if successful.
3914 """
3914 """
3915
3915
3916 textwidth = min(ui.termwidth(), 80) - 2
3916 textwidth = min(ui.termwidth(), 80) - 2
3917
3917
3918 keep = []
3918 keep = []
3919 if ui.verbose:
3919 if ui.verbose:
3920 keep.append('verbose')
3920 keep.append('verbose')
3921 if sys.platform.startswith('win'):
3921 if sys.platform.startswith('win'):
3922 keep.append('windows')
3922 keep.append('windows')
3923 elif sys.platform == 'OpenVMS':
3923 elif sys.platform == 'OpenVMS':
3924 keep.append('vms')
3924 keep.append('vms')
3925 elif sys.platform == 'plan9':
3925 elif sys.platform == 'plan9':
3926 keep.append('plan9')
3926 keep.append('plan9')
3927 else:
3927 else:
3928 keep.append('unix')
3928 keep.append('unix')
3929 keep.append(sys.platform.lower())
3929 keep.append(sys.platform.lower())
3930
3930
3931 section = None
3931 section = None
3932 if name and '.' in name:
3932 if name and '.' in name:
3933 name, section = name.split('.', 1)
3933 name, section = name.split('.', 1)
3934
3934
3935 text = help.help_(ui, name, **opts)
3935 text = help.help_(ui, name, **opts)
3936
3936
3937 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3937 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3938 section=section)
3938 section=section)
3939 if section and not formatted:
3939 if section and not formatted:
3940 raise util.Abort(_("help section not found"))
3940 raise util.Abort(_("help section not found"))
3941
3941
3942 if 'verbose' in pruned:
3942 if 'verbose' in pruned:
3943 keep.append('omitted')
3943 keep.append('omitted')
3944 else:
3944 else:
3945 keep.append('notomitted')
3945 keep.append('notomitted')
3946 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3946 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3947 section=section)
3947 section=section)
3948 ui.write(formatted)
3948 ui.write(formatted)
3949
3949
3950
3950
3951 @command('identify|id',
3951 @command('identify|id',
3952 [('r', 'rev', '',
3952 [('r', 'rev', '',
3953 _('identify the specified revision'), _('REV')),
3953 _('identify the specified revision'), _('REV')),
3954 ('n', 'num', None, _('show local revision number')),
3954 ('n', 'num', None, _('show local revision number')),
3955 ('i', 'id', None, _('show global revision id')),
3955 ('i', 'id', None, _('show global revision id')),
3956 ('b', 'branch', None, _('show branch')),
3956 ('b', 'branch', None, _('show branch')),
3957 ('t', 'tags', None, _('show tags')),
3957 ('t', 'tags', None, _('show tags')),
3958 ('B', 'bookmarks', None, _('show bookmarks')),
3958 ('B', 'bookmarks', None, _('show bookmarks')),
3959 ] + remoteopts,
3959 ] + remoteopts,
3960 _('[-nibtB] [-r REV] [SOURCE]'),
3960 _('[-nibtB] [-r REV] [SOURCE]'),
3961 optionalrepo=True)
3961 optionalrepo=True)
3962 def identify(ui, repo, source=None, rev=None,
3962 def identify(ui, repo, source=None, rev=None,
3963 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3963 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3964 """identify the working directory or specified revision
3964 """identify the working directory or specified revision
3965
3965
3966 Print a summary identifying the repository state at REV using one or
3966 Print a summary identifying the repository state at REV using one or
3967 two parent hash identifiers, followed by a "+" if the working
3967 two parent hash identifiers, followed by a "+" if the working
3968 directory has uncommitted changes, the branch name (if not default),
3968 directory has uncommitted changes, the branch name (if not default),
3969 a list of tags, and a list of bookmarks.
3969 a list of tags, and a list of bookmarks.
3970
3970
3971 When REV is not given, print a summary of the current state of the
3971 When REV is not given, print a summary of the current state of the
3972 repository.
3972 repository.
3973
3973
3974 Specifying a path to a repository root or Mercurial bundle will
3974 Specifying a path to a repository root or Mercurial bundle will
3975 cause lookup to operate on that repository/bundle.
3975 cause lookup to operate on that repository/bundle.
3976
3976
3977 .. container:: verbose
3977 .. container:: verbose
3978
3978
3979 Examples:
3979 Examples:
3980
3980
3981 - generate a build identifier for the working directory::
3981 - generate a build identifier for the working directory::
3982
3982
3983 hg id --id > build-id.dat
3983 hg id --id > build-id.dat
3984
3984
3985 - find the revision corresponding to a tag::
3985 - find the revision corresponding to a tag::
3986
3986
3987 hg id -n -r 1.3
3987 hg id -n -r 1.3
3988
3988
3989 - check the most recent revision of a remote repository::
3989 - check the most recent revision of a remote repository::
3990
3990
3991 hg id -r tip http://selenic.com/hg/
3991 hg id -r tip http://selenic.com/hg/
3992
3992
3993 Returns 0 if successful.
3993 Returns 0 if successful.
3994 """
3994 """
3995
3995
3996 if not repo and not source:
3996 if not repo and not source:
3997 raise util.Abort(_("there is no Mercurial repository here "
3997 raise util.Abort(_("there is no Mercurial repository here "
3998 "(.hg not found)"))
3998 "(.hg not found)"))
3999
3999
4000 if ui.debugflag:
4000 if ui.debugflag:
4001 hexfunc = hex
4001 hexfunc = hex
4002 else:
4002 else:
4003 hexfunc = short
4003 hexfunc = short
4004 default = not (num or id or branch or tags or bookmarks)
4004 default = not (num or id or branch or tags or bookmarks)
4005 output = []
4005 output = []
4006 revs = []
4006 revs = []
4007
4007
4008 if source:
4008 if source:
4009 source, branches = hg.parseurl(ui.expandpath(source))
4009 source, branches = hg.parseurl(ui.expandpath(source))
4010 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4010 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4011 repo = peer.local()
4011 repo = peer.local()
4012 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4012 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4013
4013
4014 if not repo:
4014 if not repo:
4015 if num or branch or tags:
4015 if num or branch or tags:
4016 raise util.Abort(
4016 raise util.Abort(
4017 _("can't query remote revision number, branch, or tags"))
4017 _("can't query remote revision number, branch, or tags"))
4018 if not rev and revs:
4018 if not rev and revs:
4019 rev = revs[0]
4019 rev = revs[0]
4020 if not rev:
4020 if not rev:
4021 rev = "tip"
4021 rev = "tip"
4022
4022
4023 remoterev = peer.lookup(rev)
4023 remoterev = peer.lookup(rev)
4024 if default or id:
4024 if default or id:
4025 output = [hexfunc(remoterev)]
4025 output = [hexfunc(remoterev)]
4026
4026
4027 def getbms():
4027 def getbms():
4028 bms = []
4028 bms = []
4029
4029
4030 if 'bookmarks' in peer.listkeys('namespaces'):
4030 if 'bookmarks' in peer.listkeys('namespaces'):
4031 hexremoterev = hex(remoterev)
4031 hexremoterev = hex(remoterev)
4032 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4032 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4033 if bmr == hexremoterev]
4033 if bmr == hexremoterev]
4034
4034
4035 return sorted(bms)
4035 return sorted(bms)
4036
4036
4037 if bookmarks:
4037 if bookmarks:
4038 output.extend(getbms())
4038 output.extend(getbms())
4039 elif default and not ui.quiet:
4039 elif default and not ui.quiet:
4040 # multiple bookmarks for a single parent separated by '/'
4040 # multiple bookmarks for a single parent separated by '/'
4041 bm = '/'.join(getbms())
4041 bm = '/'.join(getbms())
4042 if bm:
4042 if bm:
4043 output.append(bm)
4043 output.append(bm)
4044 else:
4044 else:
4045 if not rev:
4045 if not rev:
4046 ctx = repo[None]
4046 ctx = repo[None]
4047 parents = ctx.parents()
4047 parents = ctx.parents()
4048 changed = ""
4048 changed = ""
4049 if default or id or num:
4049 if default or id or num:
4050 if (any(repo.status())
4050 if (any(repo.status())
4051 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4051 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4052 changed = '+'
4052 changed = '+'
4053 if default or id:
4053 if default or id:
4054 output = ["%s%s" %
4054 output = ["%s%s" %
4055 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4055 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4056 if num:
4056 if num:
4057 output.append("%s%s" %
4057 output.append("%s%s" %
4058 ('+'.join([str(p.rev()) for p in parents]), changed))
4058 ('+'.join([str(p.rev()) for p in parents]), changed))
4059 else:
4059 else:
4060 ctx = scmutil.revsingle(repo, rev)
4060 ctx = scmutil.revsingle(repo, rev)
4061 if default or id:
4061 if default or id:
4062 output = [hexfunc(ctx.node())]
4062 output = [hexfunc(ctx.node())]
4063 if num:
4063 if num:
4064 output.append(str(ctx.rev()))
4064 output.append(str(ctx.rev()))
4065
4065
4066 if default and not ui.quiet:
4066 if default and not ui.quiet:
4067 b = ctx.branch()
4067 b = ctx.branch()
4068 if b != 'default':
4068 if b != 'default':
4069 output.append("(%s)" % b)
4069 output.append("(%s)" % b)
4070
4070
4071 # multiple tags for a single parent separated by '/'
4071 # multiple tags for a single parent separated by '/'
4072 t = '/'.join(ctx.tags())
4072 t = '/'.join(ctx.tags())
4073 if t:
4073 if t:
4074 output.append(t)
4074 output.append(t)
4075
4075
4076 # multiple bookmarks for a single parent separated by '/'
4076 # multiple bookmarks for a single parent separated by '/'
4077 bm = '/'.join(ctx.bookmarks())
4077 bm = '/'.join(ctx.bookmarks())
4078 if bm:
4078 if bm:
4079 output.append(bm)
4079 output.append(bm)
4080 else:
4080 else:
4081 if branch:
4081 if branch:
4082 output.append(ctx.branch())
4082 output.append(ctx.branch())
4083
4083
4084 if tags:
4084 if tags:
4085 output.extend(ctx.tags())
4085 output.extend(ctx.tags())
4086
4086
4087 if bookmarks:
4087 if bookmarks:
4088 output.extend(ctx.bookmarks())
4088 output.extend(ctx.bookmarks())
4089
4089
4090 ui.write("%s\n" % ' '.join(output))
4090 ui.write("%s\n" % ' '.join(output))
4091
4091
4092 @command('import|patch',
4092 @command('import|patch',
4093 [('p', 'strip', 1,
4093 [('p', 'strip', 1,
4094 _('directory strip option for patch. This has the same '
4094 _('directory strip option for patch. This has the same '
4095 'meaning as the corresponding patch option'), _('NUM')),
4095 'meaning as the corresponding patch option'), _('NUM')),
4096 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4096 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4097 ('e', 'edit', False, _('invoke editor on commit messages')),
4097 ('e', 'edit', False, _('invoke editor on commit messages')),
4098 ('f', 'force', None,
4098 ('f', 'force', None,
4099 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4099 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4100 ('', 'no-commit', None,
4100 ('', 'no-commit', None,
4101 _("don't commit, just update the working directory")),
4101 _("don't commit, just update the working directory")),
4102 ('', 'bypass', None,
4102 ('', 'bypass', None,
4103 _("apply patch without touching the working directory")),
4103 _("apply patch without touching the working directory")),
4104 ('', 'partial', None,
4104 ('', 'partial', None,
4105 _('commit even if some hunks fail')),
4105 _('commit even if some hunks fail')),
4106 ('', 'exact', None,
4106 ('', 'exact', None,
4107 _('apply patch to the nodes from which it was generated')),
4107 _('apply patch to the nodes from which it was generated')),
4108 ('', 'prefix', '',
4108 ('', 'prefix', '',
4109 _('apply patch to subdirectory'), _('DIR')),
4109 _('apply patch to subdirectory'), _('DIR')),
4110 ('', 'import-branch', None,
4110 ('', 'import-branch', None,
4111 _('use any branch information in patch (implied by --exact)'))] +
4111 _('use any branch information in patch (implied by --exact)'))] +
4112 commitopts + commitopts2 + similarityopts,
4112 commitopts + commitopts2 + similarityopts,
4113 _('[OPTION]... PATCH...'))
4113 _('[OPTION]... PATCH...'))
4114 def import_(ui, repo, patch1=None, *patches, **opts):
4114 def import_(ui, repo, patch1=None, *patches, **opts):
4115 """import an ordered set of patches
4115 """import an ordered set of patches
4116
4116
4117 Import a list of patches and commit them individually (unless
4117 Import a list of patches and commit them individually (unless
4118 --no-commit is specified).
4118 --no-commit is specified).
4119
4119
4120 Because import first applies changes to the working directory,
4120 Because import first applies changes to the working directory,
4121 import will abort if there are outstanding changes.
4121 import will abort if there are outstanding changes.
4122
4122
4123 You can import a patch straight from a mail message. Even patches
4123 You can import a patch straight from a mail message. Even patches
4124 as attachments work (to use the body part, it must have type
4124 as attachments work (to use the body part, it must have type
4125 text/plain or text/x-patch). From and Subject headers of email
4125 text/plain or text/x-patch). From and Subject headers of email
4126 message are used as default committer and commit message. All
4126 message are used as default committer and commit message. All
4127 text/plain body parts before first diff are added to commit
4127 text/plain body parts before first diff are added to commit
4128 message.
4128 message.
4129
4129
4130 If the imported patch was generated by :hg:`export`, user and
4130 If the imported patch was generated by :hg:`export`, user and
4131 description from patch override values from message headers and
4131 description from patch override values from message headers and
4132 body. Values given on command line with -m/--message and -u/--user
4132 body. Values given on command line with -m/--message and -u/--user
4133 override these.
4133 override these.
4134
4134
4135 If --exact is specified, import will set the working directory to
4135 If --exact is specified, import will set the working directory to
4136 the parent of each patch before applying it, and will abort if the
4136 the parent of each patch before applying it, and will abort if the
4137 resulting changeset has a different ID than the one recorded in
4137 resulting changeset has a different ID than the one recorded in
4138 the patch. This may happen due to character set problems or other
4138 the patch. This may happen due to character set problems or other
4139 deficiencies in the text patch format.
4139 deficiencies in the text patch format.
4140
4140
4141 Use --bypass to apply and commit patches directly to the
4141 Use --bypass to apply and commit patches directly to the
4142 repository, not touching the working directory. Without --exact,
4142 repository, not touching the working directory. Without --exact,
4143 patches will be applied on top of the working directory parent
4143 patches will be applied on top of the working directory parent
4144 revision.
4144 revision.
4145
4145
4146 With -s/--similarity, hg will attempt to discover renames and
4146 With -s/--similarity, hg will attempt to discover renames and
4147 copies in the patch in the same way as :hg:`addremove`.
4147 copies in the patch in the same way as :hg:`addremove`.
4148
4148
4149 Use --partial to ensure a changeset will be created from the patch
4149 Use --partial to ensure a changeset will be created from the patch
4150 even if some hunks fail to apply. Hunks that fail to apply will be
4150 even if some hunks fail to apply. Hunks that fail to apply will be
4151 written to a <target-file>.rej file. Conflicts can then be resolved
4151 written to a <target-file>.rej file. Conflicts can then be resolved
4152 by hand before :hg:`commit --amend` is run to update the created
4152 by hand before :hg:`commit --amend` is run to update the created
4153 changeset. This flag exists to let people import patches that
4153 changeset. This flag exists to let people import patches that
4154 partially apply without losing the associated metadata (author,
4154 partially apply without losing the associated metadata (author,
4155 date, description, ...). Note that when none of the hunk applies
4155 date, description, ...). Note that when none of the hunk applies
4156 cleanly, :hg:`import --partial` will create an empty changeset,
4156 cleanly, :hg:`import --partial` will create an empty changeset,
4157 importing only the patch metadata.
4157 importing only the patch metadata.
4158
4158
4159 To read a patch from standard input, use "-" as the patch name. If
4159 To read a patch from standard input, use "-" as the patch name. If
4160 a URL is specified, the patch will be downloaded from it.
4160 a URL is specified, the patch will be downloaded from it.
4161 See :hg:`help dates` for a list of formats valid for -d/--date.
4161 See :hg:`help dates` for a list of formats valid for -d/--date.
4162
4162
4163 .. container:: verbose
4163 .. container:: verbose
4164
4164
4165 Examples:
4165 Examples:
4166
4166
4167 - import a traditional patch from a website and detect renames::
4167 - import a traditional patch from a website and detect renames::
4168
4168
4169 hg import -s 80 http://example.com/bugfix.patch
4169 hg import -s 80 http://example.com/bugfix.patch
4170
4170
4171 - import a changeset from an hgweb server::
4171 - import a changeset from an hgweb server::
4172
4172
4173 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4173 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4174
4174
4175 - import all the patches in an Unix-style mbox::
4175 - import all the patches in an Unix-style mbox::
4176
4176
4177 hg import incoming-patches.mbox
4177 hg import incoming-patches.mbox
4178
4178
4179 - attempt to exactly restore an exported changeset (not always
4179 - attempt to exactly restore an exported changeset (not always
4180 possible)::
4180 possible)::
4181
4181
4182 hg import --exact proposed-fix.patch
4182 hg import --exact proposed-fix.patch
4183
4183
4184 Returns 0 on success, 1 on partial success (see --partial).
4184 Returns 0 on success, 1 on partial success (see --partial).
4185 """
4185 """
4186
4186
4187 if not patch1:
4187 if not patch1:
4188 raise util.Abort(_('need at least one patch to import'))
4188 raise util.Abort(_('need at least one patch to import'))
4189
4189
4190 patches = (patch1,) + patches
4190 patches = (patch1,) + patches
4191
4191
4192 date = opts.get('date')
4192 date = opts.get('date')
4193 if date:
4193 if date:
4194 opts['date'] = util.parsedate(date)
4194 opts['date'] = util.parsedate(date)
4195
4195
4196 update = not opts.get('bypass')
4196 update = not opts.get('bypass')
4197 if not update and opts.get('no_commit'):
4197 if not update and opts.get('no_commit'):
4198 raise util.Abort(_('cannot use --no-commit with --bypass'))
4198 raise util.Abort(_('cannot use --no-commit with --bypass'))
4199 try:
4199 try:
4200 sim = float(opts.get('similarity') or 0)
4200 sim = float(opts.get('similarity') or 0)
4201 except ValueError:
4201 except ValueError:
4202 raise util.Abort(_('similarity must be a number'))
4202 raise util.Abort(_('similarity must be a number'))
4203 if sim < 0 or sim > 100:
4203 if sim < 0 or sim > 100:
4204 raise util.Abort(_('similarity must be between 0 and 100'))
4204 raise util.Abort(_('similarity must be between 0 and 100'))
4205 if sim and not update:
4205 if sim and not update:
4206 raise util.Abort(_('cannot use --similarity with --bypass'))
4206 raise util.Abort(_('cannot use --similarity with --bypass'))
4207 if opts.get('exact') and opts.get('edit'):
4207 if opts.get('exact') and opts.get('edit'):
4208 raise util.Abort(_('cannot use --exact with --edit'))
4208 raise util.Abort(_('cannot use --exact with --edit'))
4209 if opts.get('exact') and opts.get('prefix'):
4209 if opts.get('exact') and opts.get('prefix'):
4210 raise util.Abort(_('cannot use --exact with --prefix'))
4210 raise util.Abort(_('cannot use --exact with --prefix'))
4211
4211
4212 if update:
4212 if update:
4213 cmdutil.checkunfinished(repo)
4213 cmdutil.checkunfinished(repo)
4214 if (opts.get('exact') or not opts.get('force')) and update:
4214 if (opts.get('exact') or not opts.get('force')) and update:
4215 cmdutil.bailifchanged(repo)
4215 cmdutil.bailifchanged(repo)
4216
4216
4217 base = opts["base"]
4217 base = opts["base"]
4218 wlock = dsguard = lock = tr = None
4218 wlock = dsguard = lock = tr = None
4219 msgs = []
4219 msgs = []
4220 ret = 0
4220 ret = 0
4221
4221
4222
4222
4223 try:
4223 try:
4224 try:
4224 try:
4225 wlock = repo.wlock()
4225 wlock = repo.wlock()
4226 dsguard = cmdutil.dirstateguard(repo, 'import')
4226 dsguard = cmdutil.dirstateguard(repo, 'import')
4227 if not opts.get('no_commit'):
4227 if not opts.get('no_commit'):
4228 lock = repo.lock()
4228 lock = repo.lock()
4229 tr = repo.transaction('import')
4229 tr = repo.transaction('import')
4230 parents = repo.parents()
4230 parents = repo.parents()
4231 for patchurl in patches:
4231 for patchurl in patches:
4232 if patchurl == '-':
4232 if patchurl == '-':
4233 ui.status(_('applying patch from stdin\n'))
4233 ui.status(_('applying patch from stdin\n'))
4234 patchfile = ui.fin
4234 patchfile = ui.fin
4235 patchurl = 'stdin' # for error message
4235 patchurl = 'stdin' # for error message
4236 else:
4236 else:
4237 patchurl = os.path.join(base, patchurl)
4237 patchurl = os.path.join(base, patchurl)
4238 ui.status(_('applying %s\n') % patchurl)
4238 ui.status(_('applying %s\n') % patchurl)
4239 patchfile = hg.openpath(ui, patchurl)
4239 patchfile = hg.openpath(ui, patchurl)
4240
4240
4241 haspatch = False
4241 haspatch = False
4242 for hunk in patch.split(patchfile):
4242 for hunk in patch.split(patchfile):
4243 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4243 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4244 parents, opts,
4244 parents, opts,
4245 msgs, hg.clean)
4245 msgs, hg.clean)
4246 if msg:
4246 if msg:
4247 haspatch = True
4247 haspatch = True
4248 ui.note(msg + '\n')
4248 ui.note(msg + '\n')
4249 if update or opts.get('exact'):
4249 if update or opts.get('exact'):
4250 parents = repo.parents()
4250 parents = repo.parents()
4251 else:
4251 else:
4252 parents = [repo[node]]
4252 parents = [repo[node]]
4253 if rej:
4253 if rej:
4254 ui.write_err(_("patch applied partially\n"))
4254 ui.write_err(_("patch applied partially\n"))
4255 ui.write_err(_("(fix the .rej files and run "
4255 ui.write_err(_("(fix the .rej files and run "
4256 "`hg commit --amend`)\n"))
4256 "`hg commit --amend`)\n"))
4257 ret = 1
4257 ret = 1
4258 break
4258 break
4259
4259
4260 if not haspatch:
4260 if not haspatch:
4261 raise util.Abort(_('%s: no diffs found') % patchurl)
4261 raise util.Abort(_('%s: no diffs found') % patchurl)
4262
4262
4263 if tr:
4263 if tr:
4264 tr.close()
4264 tr.close()
4265 if msgs:
4265 if msgs:
4266 repo.savecommitmessage('\n* * *\n'.join(msgs))
4266 repo.savecommitmessage('\n* * *\n'.join(msgs))
4267 dsguard.close()
4267 dsguard.close()
4268 return ret
4268 return ret
4269 finally:
4269 finally:
4270 # TODO: get rid of this meaningless try/finally enclosing.
4270 # TODO: get rid of this meaningless try/finally enclosing.
4271 # this is kept only to reduce changes in a patch.
4271 # this is kept only to reduce changes in a patch.
4272 pass
4272 pass
4273 finally:
4273 finally:
4274 if tr:
4274 if tr:
4275 tr.release()
4275 tr.release()
4276 release(lock, dsguard, wlock)
4276 release(lock, dsguard, wlock)
4277
4277
4278 @command('incoming|in',
4278 @command('incoming|in',
4279 [('f', 'force', None,
4279 [('f', 'force', None,
4280 _('run even if remote repository is unrelated')),
4280 _('run even if remote repository is unrelated')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4282 ('', 'bundle', '',
4282 ('', 'bundle', '',
4283 _('file to store the bundles into'), _('FILE')),
4283 _('file to store the bundles into'), _('FILE')),
4284 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4284 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4285 ('B', 'bookmarks', False, _("compare bookmarks")),
4285 ('B', 'bookmarks', False, _("compare bookmarks")),
4286 ('b', 'branch', [],
4286 ('b', 'branch', [],
4287 _('a specific branch you would like to pull'), _('BRANCH')),
4287 _('a specific branch you would like to pull'), _('BRANCH')),
4288 ] + logopts + remoteopts + subrepoopts,
4288 ] + logopts + remoteopts + subrepoopts,
4289 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4289 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4290 def incoming(ui, repo, source="default", **opts):
4290 def incoming(ui, repo, source="default", **opts):
4291 """show new changesets found in source
4291 """show new changesets found in source
4292
4292
4293 Show new changesets found in the specified path/URL or the default
4293 Show new changesets found in the specified path/URL or the default
4294 pull location. These are the changesets that would have been pulled
4294 pull location. These are the changesets that would have been pulled
4295 if a pull at the time you issued this command.
4295 if a pull at the time you issued this command.
4296
4296
4297 See pull for valid source format details.
4297 See pull for valid source format details.
4298
4298
4299 .. container:: verbose
4299 .. container:: verbose
4300
4300
4301 With -B/--bookmarks, the result of bookmark comparison between
4301 With -B/--bookmarks, the result of bookmark comparison between
4302 local and remote repositories is displayed. With -v/--verbose,
4302 local and remote repositories is displayed. With -v/--verbose,
4303 status is also displayed for each bookmark like below::
4303 status is also displayed for each bookmark like below::
4304
4304
4305 BM1 01234567890a added
4305 BM1 01234567890a added
4306 BM2 1234567890ab advanced
4306 BM2 1234567890ab advanced
4307 BM3 234567890abc diverged
4307 BM3 234567890abc diverged
4308 BM4 34567890abcd changed
4308 BM4 34567890abcd changed
4309
4309
4310 The action taken locally when pulling depends on the
4310 The action taken locally when pulling depends on the
4311 status of each bookmark:
4311 status of each bookmark:
4312
4312
4313 :``added``: pull will create it
4313 :``added``: pull will create it
4314 :``advanced``: pull will update it
4314 :``advanced``: pull will update it
4315 :``diverged``: pull will create a divergent bookmark
4315 :``diverged``: pull will create a divergent bookmark
4316 :``changed``: result depends on remote changesets
4316 :``changed``: result depends on remote changesets
4317
4317
4318 From the point of view of pulling behavior, bookmark
4318 From the point of view of pulling behavior, bookmark
4319 existing only in the remote repository are treated as ``added``,
4319 existing only in the remote repository are treated as ``added``,
4320 even if it is in fact locally deleted.
4320 even if it is in fact locally deleted.
4321
4321
4322 .. container:: verbose
4322 .. container:: verbose
4323
4323
4324 For remote repository, using --bundle avoids downloading the
4324 For remote repository, using --bundle avoids downloading the
4325 changesets twice if the incoming is followed by a pull.
4325 changesets twice if the incoming is followed by a pull.
4326
4326
4327 Examples:
4327 Examples:
4328
4328
4329 - show incoming changes with patches and full description::
4329 - show incoming changes with patches and full description::
4330
4330
4331 hg incoming -vp
4331 hg incoming -vp
4332
4332
4333 - show incoming changes excluding merges, store a bundle::
4333 - show incoming changes excluding merges, store a bundle::
4334
4334
4335 hg in -vpM --bundle incoming.hg
4335 hg in -vpM --bundle incoming.hg
4336 hg pull incoming.hg
4336 hg pull incoming.hg
4337
4337
4338 - briefly list changes inside a bundle::
4338 - briefly list changes inside a bundle::
4339
4339
4340 hg in changes.hg -T "{desc|firstline}\\n"
4340 hg in changes.hg -T "{desc|firstline}\\n"
4341
4341
4342 Returns 0 if there are incoming changes, 1 otherwise.
4342 Returns 0 if there are incoming changes, 1 otherwise.
4343 """
4343 """
4344 if opts.get('graph'):
4344 if opts.get('graph'):
4345 cmdutil.checkunsupportedgraphflags([], opts)
4345 cmdutil.checkunsupportedgraphflags([], opts)
4346 def display(other, chlist, displayer):
4346 def display(other, chlist, displayer):
4347 revdag = cmdutil.graphrevs(other, chlist, opts)
4347 revdag = cmdutil.graphrevs(other, chlist, opts)
4348 showparents = [ctx.node() for ctx in repo[None].parents()]
4348 showparents = [ctx.node() for ctx in repo[None].parents()]
4349 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4349 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4350 graphmod.asciiedges)
4350 graphmod.asciiedges)
4351
4351
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4353 return 0
4353 return 0
4354
4354
4355 if opts.get('bundle') and opts.get('subrepos'):
4355 if opts.get('bundle') and opts.get('subrepos'):
4356 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4356 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4357
4357
4358 if opts.get('bookmarks'):
4358 if opts.get('bookmarks'):
4359 source, branches = hg.parseurl(ui.expandpath(source),
4359 source, branches = hg.parseurl(ui.expandpath(source),
4360 opts.get('branch'))
4360 opts.get('branch'))
4361 other = hg.peer(repo, opts, source)
4361 other = hg.peer(repo, opts, source)
4362 if 'bookmarks' not in other.listkeys('namespaces'):
4362 if 'bookmarks' not in other.listkeys('namespaces'):
4363 ui.warn(_("remote doesn't support bookmarks\n"))
4363 ui.warn(_("remote doesn't support bookmarks\n"))
4364 return 0
4364 return 0
4365 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4365 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4366 return bookmarks.incoming(ui, repo, other)
4366 return bookmarks.incoming(ui, repo, other)
4367
4367
4368 repo._subtoppath = ui.expandpath(source)
4368 repo._subtoppath = ui.expandpath(source)
4369 try:
4369 try:
4370 return hg.incoming(ui, repo, source, opts)
4370 return hg.incoming(ui, repo, source, opts)
4371 finally:
4371 finally:
4372 del repo._subtoppath
4372 del repo._subtoppath
4373
4373
4374
4374
4375 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4375 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4376 norepo=True)
4376 norepo=True)
4377 def init(ui, dest=".", **opts):
4377 def init(ui, dest=".", **opts):
4378 """create a new repository in the given directory
4378 """create a new repository in the given directory
4379
4379
4380 Initialize a new repository in the given directory. If the given
4380 Initialize a new repository in the given directory. If the given
4381 directory does not exist, it will be created.
4381 directory does not exist, it will be created.
4382
4382
4383 If no directory is given, the current directory is used.
4383 If no directory is given, the current directory is used.
4384
4384
4385 It is possible to specify an ``ssh://`` URL as the destination.
4385 It is possible to specify an ``ssh://`` URL as the destination.
4386 See :hg:`help urls` for more information.
4386 See :hg:`help urls` for more information.
4387
4387
4388 Returns 0 on success.
4388 Returns 0 on success.
4389 """
4389 """
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4391
4391
4392 @command('locate',
4392 @command('locate',
4393 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4393 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4394 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4394 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4395 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4395 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4396 ] + walkopts,
4396 ] + walkopts,
4397 _('[OPTION]... [PATTERN]...'))
4397 _('[OPTION]... [PATTERN]...'))
4398 def locate(ui, repo, *pats, **opts):
4398 def locate(ui, repo, *pats, **opts):
4399 """locate files matching specific patterns (DEPRECATED)
4399 """locate files matching specific patterns (DEPRECATED)
4400
4400
4401 Print files under Mercurial control in the working directory whose
4401 Print files under Mercurial control in the working directory whose
4402 names match the given patterns.
4402 names match the given patterns.
4403
4403
4404 By default, this command searches all directories in the working
4404 By default, this command searches all directories in the working
4405 directory. To search just the current directory and its
4405 directory. To search just the current directory and its
4406 subdirectories, use "--include .".
4406 subdirectories, use "--include .".
4407
4407
4408 If no patterns are given to match, this command prints the names
4408 If no patterns are given to match, this command prints the names
4409 of all files under Mercurial control in the working directory.
4409 of all files under Mercurial control in the working directory.
4410
4410
4411 If you want to feed the output of this command into the "xargs"
4411 If you want to feed the output of this command into the "xargs"
4412 command, use the -0 option to both this command and "xargs". This
4412 command, use the -0 option to both this command and "xargs". This
4413 will avoid the problem of "xargs" treating single filenames that
4413 will avoid the problem of "xargs" treating single filenames that
4414 contain whitespace as multiple filenames.
4414 contain whitespace as multiple filenames.
4415
4415
4416 See :hg:`help files` for a more versatile command.
4416 See :hg:`help files` for a more versatile command.
4417
4417
4418 Returns 0 if a match is found, 1 otherwise.
4418 Returns 0 if a match is found, 1 otherwise.
4419 """
4419 """
4420 if opts.get('print0'):
4420 if opts.get('print0'):
4421 end = '\0'
4421 end = '\0'
4422 else:
4422 else:
4423 end = '\n'
4423 end = '\n'
4424 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4424 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4425
4425
4426 ret = 1
4426 ret = 1
4427 ctx = repo[rev]
4427 ctx = repo[rev]
4428 m = scmutil.match(ctx, pats, opts, default='relglob')
4428 m = scmutil.match(ctx, pats, opts, default='relglob')
4429 m.bad = lambda x, y: False
4429 m.bad = lambda x, y: False
4430
4430
4431 for abs in ctx.matches(m):
4431 for abs in ctx.matches(m):
4432 if opts.get('fullpath'):
4432 if opts.get('fullpath'):
4433 ui.write(repo.wjoin(abs), end)
4433 ui.write(repo.wjoin(abs), end)
4434 else:
4434 else:
4435 ui.write(((pats and m.rel(abs)) or abs), end)
4435 ui.write(((pats and m.rel(abs)) or abs), end)
4436 ret = 0
4436 ret = 0
4437
4437
4438 return ret
4438 return ret
4439
4439
4440 @command('^log|history',
4440 @command('^log|history',
4441 [('f', 'follow', None,
4441 [('f', 'follow', None,
4442 _('follow changeset history, or file history across copies and renames')),
4442 _('follow changeset history, or file history across copies and renames')),
4443 ('', 'follow-first', None,
4443 ('', 'follow-first', None,
4444 _('only follow the first parent of merge changesets (DEPRECATED)')),
4444 _('only follow the first parent of merge changesets (DEPRECATED)')),
4445 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4445 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4446 ('C', 'copies', None, _('show copied files')),
4446 ('C', 'copies', None, _('show copied files')),
4447 ('k', 'keyword', [],
4447 ('k', 'keyword', [],
4448 _('do case-insensitive search for a given text'), _('TEXT')),
4448 _('do case-insensitive search for a given text'), _('TEXT')),
4449 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4449 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4450 ('', 'removed', None, _('include revisions where files were removed')),
4450 ('', 'removed', None, _('include revisions where files were removed')),
4451 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4451 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4452 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4452 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4453 ('', 'only-branch', [],
4453 ('', 'only-branch', [],
4454 _('show only changesets within the given named branch (DEPRECATED)'),
4454 _('show only changesets within the given named branch (DEPRECATED)'),
4455 _('BRANCH')),
4455 _('BRANCH')),
4456 ('b', 'branch', [],
4456 ('b', 'branch', [],
4457 _('show changesets within the given named branch'), _('BRANCH')),
4457 _('show changesets within the given named branch'), _('BRANCH')),
4458 ('P', 'prune', [],
4458 ('P', 'prune', [],
4459 _('do not display revision or any of its ancestors'), _('REV')),
4459 _('do not display revision or any of its ancestors'), _('REV')),
4460 ] + logopts + walkopts,
4460 ] + logopts + walkopts,
4461 _('[OPTION]... [FILE]'),
4461 _('[OPTION]... [FILE]'),
4462 inferrepo=True)
4462 inferrepo=True)
4463 def log(ui, repo, *pats, **opts):
4463 def log(ui, repo, *pats, **opts):
4464 """show revision history of entire repository or files
4464 """show revision history of entire repository or files
4465
4465
4466 Print the revision history of the specified files or the entire
4466 Print the revision history of the specified files or the entire
4467 project.
4467 project.
4468
4468
4469 If no revision range is specified, the default is ``tip:0`` unless
4469 If no revision range is specified, the default is ``tip:0`` unless
4470 --follow is set, in which case the working directory parent is
4470 --follow is set, in which case the working directory parent is
4471 used as the starting revision.
4471 used as the starting revision.
4472
4472
4473 File history is shown without following rename or copy history of
4473 File history is shown without following rename or copy history of
4474 files. Use -f/--follow with a filename to follow history across
4474 files. Use -f/--follow with a filename to follow history across
4475 renames and copies. --follow without a filename will only show
4475 renames and copies. --follow without a filename will only show
4476 ancestors or descendants of the starting revision.
4476 ancestors or descendants of the starting revision.
4477
4477
4478 By default this command prints revision number and changeset id,
4478 By default this command prints revision number and changeset id,
4479 tags, non-trivial parents, user, date and time, and a summary for
4479 tags, non-trivial parents, user, date and time, and a summary for
4480 each commit. When the -v/--verbose switch is used, the list of
4480 each commit. When the -v/--verbose switch is used, the list of
4481 changed files and full commit message are shown.
4481 changed files and full commit message are shown.
4482
4482
4483 With --graph the revisions are shown as an ASCII art DAG with the most
4483 With --graph the revisions are shown as an ASCII art DAG with the most
4484 recent changeset at the top.
4484 recent changeset at the top.
4485 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4485 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4486 and '+' represents a fork where the changeset from the lines below is a
4486 and '+' represents a fork where the changeset from the lines below is a
4487 parent of the 'o' merge on the same line.
4487 parent of the 'o' merge on the same line.
4488
4488
4489 .. note::
4489 .. note::
4490
4490
4491 log -p/--patch may generate unexpected diff output for merge
4491 log -p/--patch may generate unexpected diff output for merge
4492 changesets, as it will only compare the merge changeset against
4492 changesets, as it will only compare the merge changeset against
4493 its first parent. Also, only files different from BOTH parents
4493 its first parent. Also, only files different from BOTH parents
4494 will appear in files:.
4494 will appear in files:.
4495
4495
4496 .. note::
4496 .. note::
4497
4497
4498 for performance reasons, log FILE may omit duplicate changes
4498 for performance reasons, log FILE may omit duplicate changes
4499 made on branches and will not show removals or mode changes. To
4499 made on branches and will not show removals or mode changes. To
4500 see all such changes, use the --removed switch.
4500 see all such changes, use the --removed switch.
4501
4501
4502 .. container:: verbose
4502 .. container:: verbose
4503
4503
4504 Some examples:
4504 Some examples:
4505
4505
4506 - changesets with full descriptions and file lists::
4506 - changesets with full descriptions and file lists::
4507
4507
4508 hg log -v
4508 hg log -v
4509
4509
4510 - changesets ancestral to the working directory::
4510 - changesets ancestral to the working directory::
4511
4511
4512 hg log -f
4512 hg log -f
4513
4513
4514 - last 10 commits on the current branch::
4514 - last 10 commits on the current branch::
4515
4515
4516 hg log -l 10 -b .
4516 hg log -l 10 -b .
4517
4517
4518 - changesets showing all modifications of a file, including removals::
4518 - changesets showing all modifications of a file, including removals::
4519
4519
4520 hg log --removed file.c
4520 hg log --removed file.c
4521
4521
4522 - all changesets that touch a directory, with diffs, excluding merges::
4522 - all changesets that touch a directory, with diffs, excluding merges::
4523
4523
4524 hg log -Mp lib/
4524 hg log -Mp lib/
4525
4525
4526 - all revision numbers that match a keyword::
4526 - all revision numbers that match a keyword::
4527
4527
4528 hg log -k bug --template "{rev}\\n"
4528 hg log -k bug --template "{rev}\\n"
4529
4529
4530 - list available log templates::
4530 - list available log templates::
4531
4531
4532 hg log -T list
4532 hg log -T list
4533
4533
4534 - check if a given changeset is included in a tagged release::
4534 - check if a given changeset is included in a tagged release::
4535
4535
4536 hg log -r "a21ccf and ancestor(1.9)"
4536 hg log -r "a21ccf and ancestor(1.9)"
4537
4537
4538 - find all changesets by some user in a date range::
4538 - find all changesets by some user in a date range::
4539
4539
4540 hg log -k alice -d "may 2008 to jul 2008"
4540 hg log -k alice -d "may 2008 to jul 2008"
4541
4541
4542 - summary of all changesets after the last tag::
4542 - summary of all changesets after the last tag::
4543
4543
4544 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4544 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4545
4545
4546 See :hg:`help dates` for a list of formats valid for -d/--date.
4546 See :hg:`help dates` for a list of formats valid for -d/--date.
4547
4547
4548 See :hg:`help revisions` and :hg:`help revsets` for more about
4548 See :hg:`help revisions` and :hg:`help revsets` for more about
4549 specifying revisions.
4549 specifying revisions.
4550
4550
4551 See :hg:`help templates` for more about pre-packaged styles and
4551 See :hg:`help templates` for more about pre-packaged styles and
4552 specifying custom templates.
4552 specifying custom templates.
4553
4553
4554 Returns 0 on success.
4554 Returns 0 on success.
4555
4555
4556 """
4556 """
4557 if opts.get('follow') and opts.get('rev'):
4557 if opts.get('follow') and opts.get('rev'):
4558 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4558 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4559 del opts['follow']
4559 del opts['follow']
4560
4560
4561 if opts.get('graph'):
4561 if opts.get('graph'):
4562 return cmdutil.graphlog(ui, repo, *pats, **opts)
4562 return cmdutil.graphlog(ui, repo, *pats, **opts)
4563
4563
4564 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4564 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4565 limit = cmdutil.loglimit(opts)
4565 limit = cmdutil.loglimit(opts)
4566 count = 0
4566 count = 0
4567
4567
4568 getrenamed = None
4568 getrenamed = None
4569 if opts.get('copies'):
4569 if opts.get('copies'):
4570 endrev = None
4570 endrev = None
4571 if opts.get('rev'):
4571 if opts.get('rev'):
4572 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4572 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4573 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4573 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4574
4574
4575 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4575 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4576 for rev in revs:
4576 for rev in revs:
4577 if count == limit:
4577 if count == limit:
4578 break
4578 break
4579 ctx = repo[rev]
4579 ctx = repo[rev]
4580 copies = None
4580 copies = None
4581 if getrenamed is not None and rev:
4581 if getrenamed is not None and rev:
4582 copies = []
4582 copies = []
4583 for fn in ctx.files():
4583 for fn in ctx.files():
4584 rename = getrenamed(fn, rev)
4584 rename = getrenamed(fn, rev)
4585 if rename:
4585 if rename:
4586 copies.append((fn, rename[0]))
4586 copies.append((fn, rename[0]))
4587 if filematcher:
4587 if filematcher:
4588 revmatchfn = filematcher(ctx.rev())
4588 revmatchfn = filematcher(ctx.rev())
4589 else:
4589 else:
4590 revmatchfn = None
4590 revmatchfn = None
4591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4592 if displayer.flush(rev):
4592 if displayer.flush(rev):
4593 count += 1
4593 count += 1
4594
4594
4595 displayer.close()
4595 displayer.close()
4596
4596
4597 @command('manifest',
4597 @command('manifest',
4598 [('r', 'rev', '', _('revision to display'), _('REV')),
4598 [('r', 'rev', '', _('revision to display'), _('REV')),
4599 ('', 'all', False, _("list files from all revisions"))]
4599 ('', 'all', False, _("list files from all revisions"))]
4600 + formatteropts,
4600 + formatteropts,
4601 _('[-r REV]'))
4601 _('[-r REV]'))
4602 def manifest(ui, repo, node=None, rev=None, **opts):
4602 def manifest(ui, repo, node=None, rev=None, **opts):
4603 """output the current or given revision of the project manifest
4603 """output the current or given revision of the project manifest
4604
4604
4605 Print a list of version controlled files for the given revision.
4605 Print a list of version controlled files for the given revision.
4606 If no revision is given, the first parent of the working directory
4606 If no revision is given, the first parent of the working directory
4607 is used, or the null revision if no revision is checked out.
4607 is used, or the null revision if no revision is checked out.
4608
4608
4609 With -v, print file permissions, symlink and executable bits.
4609 With -v, print file permissions, symlink and executable bits.
4610 With --debug, print file revision hashes.
4610 With --debug, print file revision hashes.
4611
4611
4612 If option --all is specified, the list of all files from all revisions
4612 If option --all is specified, the list of all files from all revisions
4613 is printed. This includes deleted and renamed files.
4613 is printed. This includes deleted and renamed files.
4614
4614
4615 Returns 0 on success.
4615 Returns 0 on success.
4616 """
4616 """
4617
4617
4618 fm = ui.formatter('manifest', opts)
4618 fm = ui.formatter('manifest', opts)
4619
4619
4620 if opts.get('all'):
4620 if opts.get('all'):
4621 if rev or node:
4621 if rev or node:
4622 raise util.Abort(_("can't specify a revision with --all"))
4622 raise util.Abort(_("can't specify a revision with --all"))
4623
4623
4624 res = []
4624 res = []
4625 prefix = "data/"
4625 prefix = "data/"
4626 suffix = ".i"
4626 suffix = ".i"
4627 plen = len(prefix)
4627 plen = len(prefix)
4628 slen = len(suffix)
4628 slen = len(suffix)
4629 lock = repo.lock()
4629 lock = repo.lock()
4630 try:
4630 try:
4631 for fn, b, size in repo.store.datafiles():
4631 for fn, b, size in repo.store.datafiles():
4632 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4632 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4633 res.append(fn[plen:-slen])
4633 res.append(fn[plen:-slen])
4634 finally:
4634 finally:
4635 lock.release()
4635 lock.release()
4636 for f in res:
4636 for f in res:
4637 fm.startitem()
4637 fm.startitem()
4638 fm.write("path", '%s\n', f)
4638 fm.write("path", '%s\n', f)
4639 fm.end()
4639 fm.end()
4640 return
4640 return
4641
4641
4642 if rev and node:
4642 if rev and node:
4643 raise util.Abort(_("please specify just one revision"))
4643 raise util.Abort(_("please specify just one revision"))
4644
4644
4645 if not node:
4645 if not node:
4646 node = rev
4646 node = rev
4647
4647
4648 char = {'l': '@', 'x': '*', '': ''}
4648 char = {'l': '@', 'x': '*', '': ''}
4649 mode = {'l': '644', 'x': '755', '': '644'}
4649 mode = {'l': '644', 'x': '755', '': '644'}
4650 ctx = scmutil.revsingle(repo, node)
4650 ctx = scmutil.revsingle(repo, node)
4651 mf = ctx.manifest()
4651 mf = ctx.manifest()
4652 for f in ctx:
4652 for f in ctx:
4653 fm.startitem()
4653 fm.startitem()
4654 fl = ctx[f].flags()
4654 fl = ctx[f].flags()
4655 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4655 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4656 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4656 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4657 fm.write('path', '%s\n', f)
4657 fm.write('path', '%s\n', f)
4658 fm.end()
4658 fm.end()
4659
4659
4660 @command('^merge',
4660 @command('^merge',
4661 [('f', 'force', None,
4661 [('f', 'force', None,
4662 _('force a merge including outstanding changes (DEPRECATED)')),
4662 _('force a merge including outstanding changes (DEPRECATED)')),
4663 ('r', 'rev', '', _('revision to merge'), _('REV')),
4663 ('r', 'rev', '', _('revision to merge'), _('REV')),
4664 ('P', 'preview', None,
4664 ('P', 'preview', None,
4665 _('review revisions to merge (no merge is performed)'))
4665 _('review revisions to merge (no merge is performed)'))
4666 ] + mergetoolopts,
4666 ] + mergetoolopts,
4667 _('[-P] [-f] [[-r] REV]'))
4667 _('[-P] [-f] [[-r] REV]'))
4668 def merge(ui, repo, node=None, **opts):
4668 def merge(ui, repo, node=None, **opts):
4669 """merge another revision into working directory
4669 """merge another revision into working directory
4670
4670
4671 The current working directory is updated with all changes made in
4671 The current working directory is updated with all changes made in
4672 the requested revision since the last common predecessor revision.
4672 the requested revision since the last common predecessor revision.
4673
4673
4674 Files that changed between either parent are marked as changed for
4674 Files that changed between either parent are marked as changed for
4675 the next commit and a commit must be performed before any further
4675 the next commit and a commit must be performed before any further
4676 updates to the repository are allowed. The next commit will have
4676 updates to the repository are allowed. The next commit will have
4677 two parents.
4677 two parents.
4678
4678
4679 ``--tool`` can be used to specify the merge tool used for file
4679 ``--tool`` can be used to specify the merge tool used for file
4680 merges. It overrides the HGMERGE environment variable and your
4680 merges. It overrides the HGMERGE environment variable and your
4681 configuration files. See :hg:`help merge-tools` for options.
4681 configuration files. See :hg:`help merge-tools` for options.
4682
4682
4683 If no revision is specified, the working directory's parent is a
4683 If no revision is specified, the working directory's parent is a
4684 head revision, and the current branch contains exactly one other
4684 head revision, and the current branch contains exactly one other
4685 head, the other head is merged with by default. Otherwise, an
4685 head, the other head is merged with by default. Otherwise, an
4686 explicit revision with which to merge with must be provided.
4686 explicit revision with which to merge with must be provided.
4687
4687
4688 :hg:`resolve` must be used to resolve unresolved files.
4688 :hg:`resolve` must be used to resolve unresolved files.
4689
4689
4690 To undo an uncommitted merge, use :hg:`update --clean .` which
4690 To undo an uncommitted merge, use :hg:`update --clean .` which
4691 will check out a clean copy of the original merge parent, losing
4691 will check out a clean copy of the original merge parent, losing
4692 all changes.
4692 all changes.
4693
4693
4694 Returns 0 on success, 1 if there are unresolved files.
4694 Returns 0 on success, 1 if there are unresolved files.
4695 """
4695 """
4696
4696
4697 if opts.get('rev') and node:
4697 if opts.get('rev') and node:
4698 raise util.Abort(_("please specify just one revision"))
4698 raise util.Abort(_("please specify just one revision"))
4699 if not node:
4699 if not node:
4700 node = opts.get('rev')
4700 node = opts.get('rev')
4701
4701
4702 if node:
4702 if node:
4703 node = scmutil.revsingle(repo, node).node()
4703 node = scmutil.revsingle(repo, node).node()
4704
4704
4705 if not node and repo._activebookmark:
4705 if not node and repo._activebookmark:
4706 bmheads = repo.bookmarkheads(repo._activebookmark)
4706 bmheads = repo.bookmarkheads(repo._activebookmark)
4707 curhead = repo[repo._activebookmark].node()
4707 curhead = repo[repo._activebookmark].node()
4708 if len(bmheads) == 2:
4708 if len(bmheads) == 2:
4709 if curhead == bmheads[0]:
4709 if curhead == bmheads[0]:
4710 node = bmheads[1]
4710 node = bmheads[1]
4711 else:
4711 else:
4712 node = bmheads[0]
4712 node = bmheads[0]
4713 elif len(bmheads) > 2:
4713 elif len(bmheads) > 2:
4714 raise util.Abort(_("multiple matching bookmarks to merge - "
4714 raise util.Abort(_("multiple matching bookmarks to merge - "
4715 "please merge with an explicit rev or bookmark"),
4715 "please merge with an explicit rev or bookmark"),
4716 hint=_("run 'hg heads' to see all heads"))
4716 hint=_("run 'hg heads' to see all heads"))
4717 elif len(bmheads) <= 1:
4717 elif len(bmheads) <= 1:
4718 raise util.Abort(_("no matching bookmark to merge - "
4718 raise util.Abort(_("no matching bookmark to merge - "
4719 "please merge with an explicit rev or bookmark"),
4719 "please merge with an explicit rev or bookmark"),
4720 hint=_("run 'hg heads' to see all heads"))
4720 hint=_("run 'hg heads' to see all heads"))
4721
4721
4722 if not node and not repo._activebookmark:
4722 if not node and not repo._activebookmark:
4723 branch = repo[None].branch()
4723 branch = repo[None].branch()
4724 bheads = repo.branchheads(branch)
4724 bheads = repo.branchheads(branch)
4725 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4725 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4726
4726
4727 if len(nbhs) > 2:
4727 if len(nbhs) > 2:
4728 raise util.Abort(_("branch '%s' has %d heads - "
4728 raise util.Abort(_("branch '%s' has %d heads - "
4729 "please merge with an explicit rev")
4729 "please merge with an explicit rev")
4730 % (branch, len(bheads)),
4730 % (branch, len(bheads)),
4731 hint=_("run 'hg heads .' to see heads"))
4731 hint=_("run 'hg heads .' to see heads"))
4732
4732
4733 parent = repo.dirstate.p1()
4733 parent = repo.dirstate.p1()
4734 if len(nbhs) <= 1:
4734 if len(nbhs) <= 1:
4735 if len(bheads) > 1:
4735 if len(bheads) > 1:
4736 raise util.Abort(_("heads are bookmarked - "
4736 raise util.Abort(_("heads are bookmarked - "
4737 "please merge with an explicit rev"),
4737 "please merge with an explicit rev"),
4738 hint=_("run 'hg heads' to see all heads"))
4738 hint=_("run 'hg heads' to see all heads"))
4739 if len(repo.heads()) > 1:
4739 if len(repo.heads()) > 1:
4740 raise util.Abort(_("branch '%s' has one head - "
4740 raise util.Abort(_("branch '%s' has one head - "
4741 "please merge with an explicit rev")
4741 "please merge with an explicit rev")
4742 % branch,
4742 % branch,
4743 hint=_("run 'hg heads' to see all heads"))
4743 hint=_("run 'hg heads' to see all heads"))
4744 msg, hint = _('nothing to merge'), None
4744 msg, hint = _('nothing to merge'), None
4745 if parent != repo.lookup(branch):
4745 if parent != repo.lookup(branch):
4746 hint = _("use 'hg update' instead")
4746 hint = _("use 'hg update' instead")
4747 raise util.Abort(msg, hint=hint)
4747 raise util.Abort(msg, hint=hint)
4748
4748
4749 if parent not in bheads:
4749 if parent not in bheads:
4750 raise util.Abort(_('working directory not at a head revision'),
4750 raise util.Abort(_('working directory not at a head revision'),
4751 hint=_("use 'hg update' or merge with an "
4751 hint=_("use 'hg update' or merge with an "
4752 "explicit revision"))
4752 "explicit revision"))
4753 if parent == nbhs[0]:
4753 if parent == nbhs[0]:
4754 node = nbhs[-1]
4754 node = nbhs[-1]
4755 else:
4755 else:
4756 node = nbhs[0]
4756 node = nbhs[0]
4757
4757
4758 if opts.get('preview'):
4758 if opts.get('preview'):
4759 # find nodes that are ancestors of p2 but not of p1
4759 # find nodes that are ancestors of p2 but not of p1
4760 p1 = repo.lookup('.')
4760 p1 = repo.lookup('.')
4761 p2 = repo.lookup(node)
4761 p2 = repo.lookup(node)
4762 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4762 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4763
4763
4764 displayer = cmdutil.show_changeset(ui, repo, opts)
4764 displayer = cmdutil.show_changeset(ui, repo, opts)
4765 for node in nodes:
4765 for node in nodes:
4766 displayer.show(repo[node])
4766 displayer.show(repo[node])
4767 displayer.close()
4767 displayer.close()
4768 return 0
4768 return 0
4769
4769
4770 try:
4770 try:
4771 # ui.forcemerge is an internal variable, do not document
4771 # ui.forcemerge is an internal variable, do not document
4772 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4772 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4773 return hg.merge(repo, node, force=opts.get('force'))
4773 return hg.merge(repo, node, force=opts.get('force'))
4774 finally:
4774 finally:
4775 ui.setconfig('ui', 'forcemerge', '', 'merge')
4775 ui.setconfig('ui', 'forcemerge', '', 'merge')
4776
4776
4777 @command('outgoing|out',
4777 @command('outgoing|out',
4778 [('f', 'force', None, _('run even when the destination is unrelated')),
4778 [('f', 'force', None, _('run even when the destination is unrelated')),
4779 ('r', 'rev', [],
4779 ('r', 'rev', [],
4780 _('a changeset intended to be included in the destination'), _('REV')),
4780 _('a changeset intended to be included in the destination'), _('REV')),
4781 ('n', 'newest-first', None, _('show newest record first')),
4781 ('n', 'newest-first', None, _('show newest record first')),
4782 ('B', 'bookmarks', False, _('compare bookmarks')),
4782 ('B', 'bookmarks', False, _('compare bookmarks')),
4783 ('b', 'branch', [], _('a specific branch you would like to push'),
4783 ('b', 'branch', [], _('a specific branch you would like to push'),
4784 _('BRANCH')),
4784 _('BRANCH')),
4785 ] + logopts + remoteopts + subrepoopts,
4785 ] + logopts + remoteopts + subrepoopts,
4786 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4786 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4787 def outgoing(ui, repo, dest=None, **opts):
4787 def outgoing(ui, repo, dest=None, **opts):
4788 """show changesets not found in the destination
4788 """show changesets not found in the destination
4789
4789
4790 Show changesets not found in the specified destination repository
4790 Show changesets not found in the specified destination repository
4791 or the default push location. These are the changesets that would
4791 or the default push location. These are the changesets that would
4792 be pushed if a push was requested.
4792 be pushed if a push was requested.
4793
4793
4794 See pull for details of valid destination formats.
4794 See pull for details of valid destination formats.
4795
4795
4796 .. container:: verbose
4796 .. container:: verbose
4797
4797
4798 With -B/--bookmarks, the result of bookmark comparison between
4798 With -B/--bookmarks, the result of bookmark comparison between
4799 local and remote repositories is displayed. With -v/--verbose,
4799 local and remote repositories is displayed. With -v/--verbose,
4800 status is also displayed for each bookmark like below::
4800 status is also displayed for each bookmark like below::
4801
4801
4802 BM1 01234567890a added
4802 BM1 01234567890a added
4803 BM2 deleted
4803 BM2 deleted
4804 BM3 234567890abc advanced
4804 BM3 234567890abc advanced
4805 BM4 34567890abcd diverged
4805 BM4 34567890abcd diverged
4806 BM5 4567890abcde changed
4806 BM5 4567890abcde changed
4807
4807
4808 The action taken when pushing depends on the
4808 The action taken when pushing depends on the
4809 status of each bookmark:
4809 status of each bookmark:
4810
4810
4811 :``added``: push with ``-B`` will create it
4811 :``added``: push with ``-B`` will create it
4812 :``deleted``: push with ``-B`` will delete it
4812 :``deleted``: push with ``-B`` will delete it
4813 :``advanced``: push will update it
4813 :``advanced``: push will update it
4814 :``diverged``: push with ``-B`` will update it
4814 :``diverged``: push with ``-B`` will update it
4815 :``changed``: push with ``-B`` will update it
4815 :``changed``: push with ``-B`` will update it
4816
4816
4817 From the point of view of pushing behavior, bookmarks
4817 From the point of view of pushing behavior, bookmarks
4818 existing only in the remote repository are treated as
4818 existing only in the remote repository are treated as
4819 ``deleted``, even if it is in fact added remotely.
4819 ``deleted``, even if it is in fact added remotely.
4820
4820
4821 Returns 0 if there are outgoing changes, 1 otherwise.
4821 Returns 0 if there are outgoing changes, 1 otherwise.
4822 """
4822 """
4823 if opts.get('graph'):
4823 if opts.get('graph'):
4824 cmdutil.checkunsupportedgraphflags([], opts)
4824 cmdutil.checkunsupportedgraphflags([], opts)
4825 o, other = hg._outgoing(ui, repo, dest, opts)
4825 o, other = hg._outgoing(ui, repo, dest, opts)
4826 if not o:
4826 if not o:
4827 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4827 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4828 return
4828 return
4829
4829
4830 revdag = cmdutil.graphrevs(repo, o, opts)
4830 revdag = cmdutil.graphrevs(repo, o, opts)
4831 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4831 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4832 showparents = [ctx.node() for ctx in repo[None].parents()]
4832 showparents = [ctx.node() for ctx in repo[None].parents()]
4833 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4833 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4834 graphmod.asciiedges)
4834 graphmod.asciiedges)
4835 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4835 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4836 return 0
4836 return 0
4837
4837
4838 if opts.get('bookmarks'):
4838 if opts.get('bookmarks'):
4839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4840 dest, branches = hg.parseurl(dest, opts.get('branch'))
4840 dest, branches = hg.parseurl(dest, opts.get('branch'))
4841 other = hg.peer(repo, opts, dest)
4841 other = hg.peer(repo, opts, dest)
4842 if 'bookmarks' not in other.listkeys('namespaces'):
4842 if 'bookmarks' not in other.listkeys('namespaces'):
4843 ui.warn(_("remote doesn't support bookmarks\n"))
4843 ui.warn(_("remote doesn't support bookmarks\n"))
4844 return 0
4844 return 0
4845 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4845 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4846 return bookmarks.outgoing(ui, repo, other)
4846 return bookmarks.outgoing(ui, repo, other)
4847
4847
4848 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4848 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4849 try:
4849 try:
4850 return hg.outgoing(ui, repo, dest, opts)
4850 return hg.outgoing(ui, repo, dest, opts)
4851 finally:
4851 finally:
4852 del repo._subtoppath
4852 del repo._subtoppath
4853
4853
4854 @command('parents',
4854 @command('parents',
4855 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4855 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4856 ] + templateopts,
4856 ] + templateopts,
4857 _('[-r REV] [FILE]'),
4857 _('[-r REV] [FILE]'),
4858 inferrepo=True)
4858 inferrepo=True)
4859 def parents(ui, repo, file_=None, **opts):
4859 def parents(ui, repo, file_=None, **opts):
4860 """show the parents of the working directory or revision (DEPRECATED)
4860 """show the parents of the working directory or revision (DEPRECATED)
4861
4861
4862 Print the working directory's parent revisions. If a revision is
4862 Print the working directory's parent revisions. If a revision is
4863 given via -r/--rev, the parent of that revision will be printed.
4863 given via -r/--rev, the parent of that revision will be printed.
4864 If a file argument is given, the revision in which the file was
4864 If a file argument is given, the revision in which the file was
4865 last changed (before the working directory revision or the
4865 last changed (before the working directory revision or the
4866 argument to --rev if given) is printed.
4866 argument to --rev if given) is printed.
4867
4867
4868 See :hg:`summary` and :hg:`help revsets` for related information.
4868 See :hg:`summary` and :hg:`help revsets` for related information.
4869
4869
4870 Returns 0 on success.
4870 Returns 0 on success.
4871 """
4871 """
4872
4872
4873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4874
4874
4875 if file_:
4875 if file_:
4876 m = scmutil.match(ctx, (file_,), opts)
4876 m = scmutil.match(ctx, (file_,), opts)
4877 if m.anypats() or len(m.files()) != 1:
4877 if m.anypats() or len(m.files()) != 1:
4878 raise util.Abort(_('can only specify an explicit filename'))
4878 raise util.Abort(_('can only specify an explicit filename'))
4879 file_ = m.files()[0]
4879 file_ = m.files()[0]
4880 filenodes = []
4880 filenodes = []
4881 for cp in ctx.parents():
4881 for cp in ctx.parents():
4882 if not cp:
4882 if not cp:
4883 continue
4883 continue
4884 try:
4884 try:
4885 filenodes.append(cp.filenode(file_))
4885 filenodes.append(cp.filenode(file_))
4886 except error.LookupError:
4886 except error.LookupError:
4887 pass
4887 pass
4888 if not filenodes:
4888 if not filenodes:
4889 raise util.Abort(_("'%s' not found in manifest!") % file_)
4889 raise util.Abort(_("'%s' not found in manifest!") % file_)
4890 p = []
4890 p = []
4891 for fn in filenodes:
4891 for fn in filenodes:
4892 fctx = repo.filectx(file_, fileid=fn)
4892 fctx = repo.filectx(file_, fileid=fn)
4893 p.append(fctx.node())
4893 p.append(fctx.node())
4894 else:
4894 else:
4895 p = [cp.node() for cp in ctx.parents()]
4895 p = [cp.node() for cp in ctx.parents()]
4896
4896
4897 displayer = cmdutil.show_changeset(ui, repo, opts)
4897 displayer = cmdutil.show_changeset(ui, repo, opts)
4898 for n in p:
4898 for n in p:
4899 if n != nullid:
4899 if n != nullid:
4900 displayer.show(repo[n])
4900 displayer.show(repo[n])
4901 displayer.close()
4901 displayer.close()
4902
4902
4903 @command('paths', [], _('[NAME]'), optionalrepo=True)
4903 @command('paths', [], _('[NAME]'), optionalrepo=True)
4904 def paths(ui, repo, search=None):
4904 def paths(ui, repo, search=None):
4905 """show aliases for remote repositories
4905 """show aliases for remote repositories
4906
4906
4907 Show definition of symbolic path name NAME. If no name is given,
4907 Show definition of symbolic path name NAME. If no name is given,
4908 show definition of all available names.
4908 show definition of all available names.
4909
4909
4910 Option -q/--quiet suppresses all output when searching for NAME
4910 Option -q/--quiet suppresses all output when searching for NAME
4911 and shows only the path names when listing all definitions.
4911 and shows only the path names when listing all definitions.
4912
4912
4913 Path names are defined in the [paths] section of your
4913 Path names are defined in the [paths] section of your
4914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4915 repository, ``.hg/hgrc`` is used, too.
4915 repository, ``.hg/hgrc`` is used, too.
4916
4916
4917 The path names ``default`` and ``default-push`` have a special
4917 The path names ``default`` and ``default-push`` have a special
4918 meaning. When performing a push or pull operation, they are used
4918 meaning. When performing a push or pull operation, they are used
4919 as fallbacks if no location is specified on the command-line.
4919 as fallbacks if no location is specified on the command-line.
4920 When ``default-push`` is set, it will be used for push and
4920 When ``default-push`` is set, it will be used for push and
4921 ``default`` will be used for pull; otherwise ``default`` is used
4921 ``default`` will be used for pull; otherwise ``default`` is used
4922 as the fallback for both. When cloning a repository, the clone
4922 as the fallback for both. When cloning a repository, the clone
4923 source is written as ``default`` in ``.hg/hgrc``. Note that
4923 source is written as ``default`` in ``.hg/hgrc``. Note that
4924 ``default`` and ``default-push`` apply to all inbound (e.g.
4924 ``default`` and ``default-push`` apply to all inbound (e.g.
4925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4926 :hg:`bundle`) operations.
4926 :hg:`bundle`) operations.
4927
4927
4928 See :hg:`help urls` for more information.
4928 See :hg:`help urls` for more information.
4929
4929
4930 Returns 0 on success.
4930 Returns 0 on success.
4931 """
4931 """
4932 if search:
4932 if search:
4933 for name, path in sorted(ui.paths.iteritems()):
4933 for name, path in sorted(ui.paths.iteritems()):
4934 if name == search:
4934 if name == search:
4935 ui.status("%s\n" % util.hidepassword(path.loc))
4935 ui.status("%s\n" % util.hidepassword(path.loc))
4936 return
4936 return
4937 if not ui.quiet:
4937 if not ui.quiet:
4938 ui.warn(_("not found!\n"))
4938 ui.warn(_("not found!\n"))
4939 return 1
4939 return 1
4940 else:
4940 else:
4941 for name, path in sorted(ui.paths.iteritems()):
4941 for name, path in sorted(ui.paths.iteritems()):
4942 if ui.quiet:
4942 if ui.quiet:
4943 ui.write("%s\n" % name)
4943 ui.write("%s\n" % name)
4944 else:
4944 else:
4945 ui.write("%s = %s\n" % (name,
4945 ui.write("%s = %s\n" % (name,
4946 util.hidepassword(path.loc)))
4946 util.hidepassword(path.loc)))
4947
4947
4948 @command('phase',
4948 @command('phase',
4949 [('p', 'public', False, _('set changeset phase to public')),
4949 [('p', 'public', False, _('set changeset phase to public')),
4950 ('d', 'draft', False, _('set changeset phase to draft')),
4950 ('d', 'draft', False, _('set changeset phase to draft')),
4951 ('s', 'secret', False, _('set changeset phase to secret')),
4951 ('s', 'secret', False, _('set changeset phase to secret')),
4952 ('f', 'force', False, _('allow to move boundary backward')),
4952 ('f', 'force', False, _('allow to move boundary backward')),
4953 ('r', 'rev', [], _('target revision'), _('REV')),
4953 ('r', 'rev', [], _('target revision'), _('REV')),
4954 ],
4954 ],
4955 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4955 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4956 def phase(ui, repo, *revs, **opts):
4956 def phase(ui, repo, *revs, **opts):
4957 """set or show the current phase name
4957 """set or show the current phase name
4958
4958
4959 With no argument, show the phase name of the current revision(s).
4959 With no argument, show the phase name of the current revision(s).
4960
4960
4961 With one of -p/--public, -d/--draft or -s/--secret, change the
4961 With one of -p/--public, -d/--draft or -s/--secret, change the
4962 phase value of the specified revisions.
4962 phase value of the specified revisions.
4963
4963
4964 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4964 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4965 lower phase to an higher phase. Phases are ordered as follows::
4965 lower phase to an higher phase. Phases are ordered as follows::
4966
4966
4967 public < draft < secret
4967 public < draft < secret
4968
4968
4969 Returns 0 on success, 1 if no phases were changed or some could not
4969 Returns 0 on success, 1 if no phases were changed or some could not
4970 be changed.
4970 be changed.
4971 """
4971 """
4972 # search for a unique phase argument
4972 # search for a unique phase argument
4973 targetphase = None
4973 targetphase = None
4974 for idx, name in enumerate(phases.phasenames):
4974 for idx, name in enumerate(phases.phasenames):
4975 if opts[name]:
4975 if opts[name]:
4976 if targetphase is not None:
4976 if targetphase is not None:
4977 raise util.Abort(_('only one phase can be specified'))
4977 raise util.Abort(_('only one phase can be specified'))
4978 targetphase = idx
4978 targetphase = idx
4979
4979
4980 # look for specified revision
4980 # look for specified revision
4981 revs = list(revs)
4981 revs = list(revs)
4982 revs.extend(opts['rev'])
4982 revs.extend(opts['rev'])
4983 if not revs:
4983 if not revs:
4984 # display both parents as the second parent phase can influence
4984 # display both parents as the second parent phase can influence
4985 # the phase of a merge commit
4985 # the phase of a merge commit
4986 revs = [c.rev() for c in repo[None].parents()]
4986 revs = [c.rev() for c in repo[None].parents()]
4987
4987
4988 revs = scmutil.revrange(repo, revs)
4988 revs = scmutil.revrange(repo, revs)
4989
4989
4990 lock = None
4990 lock = None
4991 ret = 0
4991 ret = 0
4992 if targetphase is None:
4992 if targetphase is None:
4993 # display
4993 # display
4994 for r in revs:
4994 for r in revs:
4995 ctx = repo[r]
4995 ctx = repo[r]
4996 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4996 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4997 else:
4997 else:
4998 tr = None
4998 tr = None
4999 lock = repo.lock()
4999 lock = repo.lock()
5000 try:
5000 try:
5001 tr = repo.transaction("phase")
5001 tr = repo.transaction("phase")
5002 # set phase
5002 # set phase
5003 if not revs:
5003 if not revs:
5004 raise util.Abort(_('empty revision set'))
5004 raise util.Abort(_('empty revision set'))
5005 nodes = [repo[r].node() for r in revs]
5005 nodes = [repo[r].node() for r in revs]
5006 # moving revision from public to draft may hide them
5006 # moving revision from public to draft may hide them
5007 # We have to check result on an unfiltered repository
5007 # We have to check result on an unfiltered repository
5008 unfi = repo.unfiltered()
5008 unfi = repo.unfiltered()
5009 getphase = unfi._phasecache.phase
5009 getphase = unfi._phasecache.phase
5010 olddata = [getphase(unfi, r) for r in unfi]
5010 olddata = [getphase(unfi, r) for r in unfi]
5011 phases.advanceboundary(repo, tr, targetphase, nodes)
5011 phases.advanceboundary(repo, tr, targetphase, nodes)
5012 if opts['force']:
5012 if opts['force']:
5013 phases.retractboundary(repo, tr, targetphase, nodes)
5013 phases.retractboundary(repo, tr, targetphase, nodes)
5014 tr.close()
5014 tr.close()
5015 finally:
5015 finally:
5016 if tr is not None:
5016 if tr is not None:
5017 tr.release()
5017 tr.release()
5018 lock.release()
5018 lock.release()
5019 getphase = unfi._phasecache.phase
5019 getphase = unfi._phasecache.phase
5020 newdata = [getphase(unfi, r) for r in unfi]
5020 newdata = [getphase(unfi, r) for r in unfi]
5021 changes = sum(newdata[r] != olddata[r] for r in unfi)
5021 changes = sum(newdata[r] != olddata[r] for r in unfi)
5022 cl = unfi.changelog
5022 cl = unfi.changelog
5023 rejected = [n for n in nodes
5023 rejected = [n for n in nodes
5024 if newdata[cl.rev(n)] < targetphase]
5024 if newdata[cl.rev(n)] < targetphase]
5025 if rejected:
5025 if rejected:
5026 ui.warn(_('cannot move %i changesets to a higher '
5026 ui.warn(_('cannot move %i changesets to a higher '
5027 'phase, use --force\n') % len(rejected))
5027 'phase, use --force\n') % len(rejected))
5028 ret = 1
5028 ret = 1
5029 if changes:
5029 if changes:
5030 msg = _('phase changed for %i changesets\n') % changes
5030 msg = _('phase changed for %i changesets\n') % changes
5031 if ret:
5031 if ret:
5032 ui.status(msg)
5032 ui.status(msg)
5033 else:
5033 else:
5034 ui.note(msg)
5034 ui.note(msg)
5035 else:
5035 else:
5036 ui.warn(_('no phases changed\n'))
5036 ui.warn(_('no phases changed\n'))
5037 ret = 1
5037 ret = 1
5038 return ret
5038 return ret
5039
5039
5040 def postincoming(ui, repo, modheads, optupdate, checkout):
5040 def postincoming(ui, repo, modheads, optupdate, checkout):
5041 if modheads == 0:
5041 if modheads == 0:
5042 return
5042 return
5043 if optupdate:
5043 if optupdate:
5044 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5044 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5045 try:
5045 try:
5046 ret = hg.update(repo, checkout)
5046 ret = hg.update(repo, checkout)
5047 except util.Abort, inst:
5047 except util.Abort, inst:
5048 ui.warn(_("not updating: %s\n") % str(inst))
5048 ui.warn(_("not updating: %s\n") % str(inst))
5049 if inst.hint:
5049 if inst.hint:
5050 ui.warn(_("(%s)\n") % inst.hint)
5050 ui.warn(_("(%s)\n") % inst.hint)
5051 return 0
5051 return 0
5052 if not ret and not checkout:
5052 if not ret and not checkout:
5053 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5053 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5054 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5054 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5055 return ret
5055 return ret
5056 if modheads > 1:
5056 if modheads > 1:
5057 currentbranchheads = len(repo.branchheads())
5057 currentbranchheads = len(repo.branchheads())
5058 if currentbranchheads == modheads:
5058 if currentbranchheads == modheads:
5059 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5059 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5060 elif currentbranchheads > 1:
5060 elif currentbranchheads > 1:
5061 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5061 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5062 "merge)\n"))
5062 "merge)\n"))
5063 else:
5063 else:
5064 ui.status(_("(run 'hg heads' to see heads)\n"))
5064 ui.status(_("(run 'hg heads' to see heads)\n"))
5065 else:
5065 else:
5066 ui.status(_("(run 'hg update' to get a working copy)\n"))
5066 ui.status(_("(run 'hg update' to get a working copy)\n"))
5067
5067
5068 @command('^pull',
5068 @command('^pull',
5069 [('u', 'update', None,
5069 [('u', 'update', None,
5070 _('update to new branch head if changesets were pulled')),
5070 _('update to new branch head if changesets were pulled')),
5071 ('f', 'force', None, _('run even when remote repository is unrelated')),
5071 ('f', 'force', None, _('run even when remote repository is unrelated')),
5072 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5072 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5073 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5073 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5074 ('b', 'branch', [], _('a specific branch you would like to pull'),
5074 ('b', 'branch', [], _('a specific branch you would like to pull'),
5075 _('BRANCH')),
5075 _('BRANCH')),
5076 ] + remoteopts,
5076 ] + remoteopts,
5077 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5077 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5078 def pull(ui, repo, source="default", **opts):
5078 def pull(ui, repo, source="default", **opts):
5079 """pull changes from the specified source
5079 """pull changes from the specified source
5080
5080
5081 Pull changes from a remote repository to a local one.
5081 Pull changes from a remote repository to a local one.
5082
5082
5083 This finds all changes from the repository at the specified path
5083 This finds all changes from the repository at the specified path
5084 or URL and adds them to a local repository (the current one unless
5084 or URL and adds them to a local repository (the current one unless
5085 -R is specified). By default, this does not update the copy of the
5085 -R is specified). By default, this does not update the copy of the
5086 project in the working directory.
5086 project in the working directory.
5087
5087
5088 Use :hg:`incoming` if you want to see what would have been added
5088 Use :hg:`incoming` if you want to see what would have been added
5089 by a pull at the time you issued this command. If you then decide
5089 by a pull at the time you issued this command. If you then decide
5090 to add those changes to the repository, you should use :hg:`pull
5090 to add those changes to the repository, you should use :hg:`pull
5091 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5091 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5092
5092
5093 If SOURCE is omitted, the 'default' path will be used.
5093 If SOURCE is omitted, the 'default' path will be used.
5094 See :hg:`help urls` for more information.
5094 See :hg:`help urls` for more information.
5095
5095
5096 Returns 0 on success, 1 if an update had unresolved files.
5096 Returns 0 on success, 1 if an update had unresolved files.
5097 """
5097 """
5098 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5098 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5099 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5099 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5100 other = hg.peer(repo, opts, source)
5100 other = hg.peer(repo, opts, source)
5101 try:
5101 try:
5102 revs, checkout = hg.addbranchrevs(repo, other, branches,
5102 revs, checkout = hg.addbranchrevs(repo, other, branches,
5103 opts.get('rev'))
5103 opts.get('rev'))
5104
5104
5105 remotebookmarks = other.listkeys('bookmarks')
5105 remotebookmarks = other.listkeys('bookmarks')
5106
5106
5107 if opts.get('bookmark'):
5107 if opts.get('bookmark'):
5108 if not revs:
5108 if not revs:
5109 revs = []
5109 revs = []
5110 for b in opts['bookmark']:
5110 for b in opts['bookmark']:
5111 if b not in remotebookmarks:
5111 if b not in remotebookmarks:
5112 raise util.Abort(_('remote bookmark %s not found!') % b)
5112 raise util.Abort(_('remote bookmark %s not found!') % b)
5113 revs.append(remotebookmarks[b])
5113 revs.append(remotebookmarks[b])
5114
5114
5115 if revs:
5115 if revs:
5116 try:
5116 try:
5117 revs = [other.lookup(rev) for rev in revs]
5117 revs = [other.lookup(rev) for rev in revs]
5118 except error.CapabilityError:
5118 except error.CapabilityError:
5119 err = _("other repository doesn't support revision lookup, "
5119 err = _("other repository doesn't support revision lookup, "
5120 "so a rev cannot be specified.")
5120 "so a rev cannot be specified.")
5121 raise util.Abort(err)
5121 raise util.Abort(err)
5122
5122
5123 modheads = exchange.pull(repo, other, heads=revs,
5123 modheads = exchange.pull(repo, other, heads=revs,
5124 force=opts.get('force'),
5124 force=opts.get('force'),
5125 bookmarks=opts.get('bookmark', ())).cgresult
5125 bookmarks=opts.get('bookmark', ())).cgresult
5126 if checkout:
5126 if checkout:
5127 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5127 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5128 repo._subtoppath = source
5128 repo._subtoppath = source
5129 try:
5129 try:
5130 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5130 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5131
5131
5132 finally:
5132 finally:
5133 del repo._subtoppath
5133 del repo._subtoppath
5134
5134
5135 finally:
5135 finally:
5136 other.close()
5136 other.close()
5137 return ret
5137 return ret
5138
5138
5139 @command('^push',
5139 @command('^push',
5140 [('f', 'force', None, _('force push')),
5140 [('f', 'force', None, _('force push')),
5141 ('r', 'rev', [],
5141 ('r', 'rev', [],
5142 _('a changeset intended to be included in the destination'),
5142 _('a changeset intended to be included in the destination'),
5143 _('REV')),
5143 _('REV')),
5144 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5144 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5145 ('b', 'branch', [],
5145 ('b', 'branch', [],
5146 _('a specific branch you would like to push'), _('BRANCH')),
5146 _('a specific branch you would like to push'), _('BRANCH')),
5147 ('', 'new-branch', False, _('allow pushing a new branch')),
5147 ('', 'new-branch', False, _('allow pushing a new branch')),
5148 ] + remoteopts,
5148 ] + remoteopts,
5149 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5149 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5150 def push(ui, repo, dest=None, **opts):
5150 def push(ui, repo, dest=None, **opts):
5151 """push changes to the specified destination
5151 """push changes to the specified destination
5152
5152
5153 Push changesets from the local repository to the specified
5153 Push changesets from the local repository to the specified
5154 destination.
5154 destination.
5155
5155
5156 This operation is symmetrical to pull: it is identical to a pull
5156 This operation is symmetrical to pull: it is identical to a pull
5157 in the destination repository from the current one.
5157 in the destination repository from the current one.
5158
5158
5159 By default, push will not allow creation of new heads at the
5159 By default, push will not allow creation of new heads at the
5160 destination, since multiple heads would make it unclear which head
5160 destination, since multiple heads would make it unclear which head
5161 to use. In this situation, it is recommended to pull and merge
5161 to use. In this situation, it is recommended to pull and merge
5162 before pushing.
5162 before pushing.
5163
5163
5164 Use --new-branch if you want to allow push to create a new named
5164 Use --new-branch if you want to allow push to create a new named
5165 branch that is not present at the destination. This allows you to
5165 branch that is not present at the destination. This allows you to
5166 only create a new branch without forcing other changes.
5166 only create a new branch without forcing other changes.
5167
5167
5168 .. note::
5168 .. note::
5169
5169
5170 Extra care should be taken with the -f/--force option,
5170 Extra care should be taken with the -f/--force option,
5171 which will push all new heads on all branches, an action which will
5171 which will push all new heads on all branches, an action which will
5172 almost always cause confusion for collaborators.
5172 almost always cause confusion for collaborators.
5173
5173
5174 If -r/--rev is used, the specified revision and all its ancestors
5174 If -r/--rev is used, the specified revision and all its ancestors
5175 will be pushed to the remote repository.
5175 will be pushed to the remote repository.
5176
5176
5177 If -B/--bookmark is used, the specified bookmarked revision, its
5177 If -B/--bookmark is used, the specified bookmarked revision, its
5178 ancestors, and the bookmark will be pushed to the remote
5178 ancestors, and the bookmark will be pushed to the remote
5179 repository.
5179 repository.
5180
5180
5181 Please see :hg:`help urls` for important details about ``ssh://``
5181 Please see :hg:`help urls` for important details about ``ssh://``
5182 URLs. If DESTINATION is omitted, a default path will be used.
5182 URLs. If DESTINATION is omitted, a default path will be used.
5183
5183
5184 Returns 0 if push was successful, 1 if nothing to push.
5184 Returns 0 if push was successful, 1 if nothing to push.
5185 """
5185 """
5186
5186
5187 if opts.get('bookmark'):
5187 if opts.get('bookmark'):
5188 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5188 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5189 for b in opts['bookmark']:
5189 for b in opts['bookmark']:
5190 # translate -B options to -r so changesets get pushed
5190 # translate -B options to -r so changesets get pushed
5191 if b in repo._bookmarks:
5191 if b in repo._bookmarks:
5192 opts.setdefault('rev', []).append(b)
5192 opts.setdefault('rev', []).append(b)
5193 else:
5193 else:
5194 # if we try to push a deleted bookmark, translate it to null
5194 # if we try to push a deleted bookmark, translate it to null
5195 # this lets simultaneous -r, -b options continue working
5195 # this lets simultaneous -r, -b options continue working
5196 opts.setdefault('rev', []).append("null")
5196 opts.setdefault('rev', []).append("null")
5197
5197
5198 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5198 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5199 dest, branches = hg.parseurl(dest, opts.get('branch'))
5199 dest, branches = hg.parseurl(dest, opts.get('branch'))
5200 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5200 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5201 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5201 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5202 try:
5202 try:
5203 other = hg.peer(repo, opts, dest)
5203 other = hg.peer(repo, opts, dest)
5204 except error.RepoError:
5204 except error.RepoError:
5205 if dest == "default-push":
5205 if dest == "default-push":
5206 raise util.Abort(_("default repository not configured!"),
5206 raise util.Abort(_("default repository not configured!"),
5207 hint=_('see the "path" section in "hg help config"'))
5207 hint=_('see the "path" section in "hg help config"'))
5208 else:
5208 else:
5209 raise
5209 raise
5210
5210
5211 if revs:
5211 if revs:
5212 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5212 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5213 if not revs:
5213 if not revs:
5214 raise util.Abort(_("specified revisions evaluate to an empty set"),
5214 raise util.Abort(_("specified revisions evaluate to an empty set"),
5215 hint=_("use different revision arguments"))
5215 hint=_("use different revision arguments"))
5216
5216
5217 repo._subtoppath = dest
5217 repo._subtoppath = dest
5218 try:
5218 try:
5219 # push subrepos depth-first for coherent ordering
5219 # push subrepos depth-first for coherent ordering
5220 c = repo['']
5220 c = repo['']
5221 subs = c.substate # only repos that are committed
5221 subs = c.substate # only repos that are committed
5222 for s in sorted(subs):
5222 for s in sorted(subs):
5223 result = c.sub(s).push(opts)
5223 result = c.sub(s).push(opts)
5224 if result == 0:
5224 if result == 0:
5225 return not result
5225 return not result
5226 finally:
5226 finally:
5227 del repo._subtoppath
5227 del repo._subtoppath
5228 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5228 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5229 newbranch=opts.get('new_branch'),
5229 newbranch=opts.get('new_branch'),
5230 bookmarks=opts.get('bookmark', ()))
5230 bookmarks=opts.get('bookmark', ()))
5231
5231
5232 result = not pushop.cgresult
5232 result = not pushop.cgresult
5233
5233
5234 if pushop.bkresult is not None:
5234 if pushop.bkresult is not None:
5235 if pushop.bkresult == 2:
5235 if pushop.bkresult == 2:
5236 result = 2
5236 result = 2
5237 elif not result and pushop.bkresult:
5237 elif not result and pushop.bkresult:
5238 result = 2
5238 result = 2
5239
5239
5240 return result
5240 return result
5241
5241
5242 @command('recover', [])
5242 @command('recover', [])
5243 def recover(ui, repo):
5243 def recover(ui, repo):
5244 """roll back an interrupted transaction
5244 """roll back an interrupted transaction
5245
5245
5246 Recover from an interrupted commit or pull.
5246 Recover from an interrupted commit or pull.
5247
5247
5248 This command tries to fix the repository status after an
5248 This command tries to fix the repository status after an
5249 interrupted operation. It should only be necessary when Mercurial
5249 interrupted operation. It should only be necessary when Mercurial
5250 suggests it.
5250 suggests it.
5251
5251
5252 Returns 0 if successful, 1 if nothing to recover or verify fails.
5252 Returns 0 if successful, 1 if nothing to recover or verify fails.
5253 """
5253 """
5254 if repo.recover():
5254 if repo.recover():
5255 return hg.verify(repo)
5255 return hg.verify(repo)
5256 return 1
5256 return 1
5257
5257
5258 @command('^remove|rm',
5258 @command('^remove|rm',
5259 [('A', 'after', None, _('record delete for missing files')),
5259 [('A', 'after', None, _('record delete for missing files')),
5260 ('f', 'force', None,
5260 ('f', 'force', None,
5261 _('remove (and delete) file even if added or modified')),
5261 _('remove (and delete) file even if added or modified')),
5262 ] + subrepoopts + walkopts,
5262 ] + subrepoopts + walkopts,
5263 _('[OPTION]... FILE...'),
5263 _('[OPTION]... FILE...'),
5264 inferrepo=True)
5264 inferrepo=True)
5265 def remove(ui, repo, *pats, **opts):
5265 def remove(ui, repo, *pats, **opts):
5266 """remove the specified files on the next commit
5266 """remove the specified files on the next commit
5267
5267
5268 Schedule the indicated files for removal from the current branch.
5268 Schedule the indicated files for removal from the current branch.
5269
5269
5270 This command schedules the files to be removed at the next commit.
5270 This command schedules the files to be removed at the next commit.
5271 To undo a remove before that, see :hg:`revert`. To undo added
5271 To undo a remove before that, see :hg:`revert`. To undo added
5272 files, see :hg:`forget`.
5272 files, see :hg:`forget`.
5273
5273
5274 .. container:: verbose
5274 .. container:: verbose
5275
5275
5276 -A/--after can be used to remove only files that have already
5276 -A/--after can be used to remove only files that have already
5277 been deleted, -f/--force can be used to force deletion, and -Af
5277 been deleted, -f/--force can be used to force deletion, and -Af
5278 can be used to remove files from the next revision without
5278 can be used to remove files from the next revision without
5279 deleting them from the working directory.
5279 deleting them from the working directory.
5280
5280
5281 The following table details the behavior of remove for different
5281 The following table details the behavior of remove for different
5282 file states (columns) and option combinations (rows). The file
5282 file states (columns) and option combinations (rows). The file
5283 states are Added [A], Clean [C], Modified [M] and Missing [!]
5283 states are Added [A], Clean [C], Modified [M] and Missing [!]
5284 (as reported by :hg:`status`). The actions are Warn, Remove
5284 (as reported by :hg:`status`). The actions are Warn, Remove
5285 (from branch) and Delete (from disk):
5285 (from branch) and Delete (from disk):
5286
5286
5287 ========= == == == ==
5287 ========= == == == ==
5288 opt/state A C M !
5288 opt/state A C M !
5289 ========= == == == ==
5289 ========= == == == ==
5290 none W RD W R
5290 none W RD W R
5291 -f R RD RD R
5291 -f R RD RD R
5292 -A W W W R
5292 -A W W W R
5293 -Af R R R R
5293 -Af R R R R
5294 ========= == == == ==
5294 ========= == == == ==
5295
5295
5296 Note that remove never deletes files in Added [A] state from the
5296 Note that remove never deletes files in Added [A] state from the
5297 working directory, not even if option --force is specified.
5297 working directory, not even if option --force is specified.
5298
5298
5299 Returns 0 on success, 1 if any warnings encountered.
5299 Returns 0 on success, 1 if any warnings encountered.
5300 """
5300 """
5301
5301
5302 after, force = opts.get('after'), opts.get('force')
5302 after, force = opts.get('after'), opts.get('force')
5303 if not pats and not after:
5303 if not pats and not after:
5304 raise util.Abort(_('no files specified'))
5304 raise util.Abort(_('no files specified'))
5305
5305
5306 m = scmutil.match(repo[None], pats, opts)
5306 m = scmutil.match(repo[None], pats, opts)
5307 subrepos = opts.get('subrepos')
5307 subrepos = opts.get('subrepos')
5308 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5308 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5309
5309
5310 @command('rename|move|mv',
5310 @command('rename|move|mv',
5311 [('A', 'after', None, _('record a rename that has already occurred')),
5311 [('A', 'after', None, _('record a rename that has already occurred')),
5312 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5312 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5313 ] + walkopts + dryrunopts,
5313 ] + walkopts + dryrunopts,
5314 _('[OPTION]... SOURCE... DEST'))
5314 _('[OPTION]... SOURCE... DEST'))
5315 def rename(ui, repo, *pats, **opts):
5315 def rename(ui, repo, *pats, **opts):
5316 """rename files; equivalent of copy + remove
5316 """rename files; equivalent of copy + remove
5317
5317
5318 Mark dest as copies of sources; mark sources for deletion. If dest
5318 Mark dest as copies of sources; mark sources for deletion. If dest
5319 is a directory, copies are put in that directory. If dest is a
5319 is a directory, copies are put in that directory. If dest is a
5320 file, there can only be one source.
5320 file, there can only be one source.
5321
5321
5322 By default, this command copies the contents of files as they
5322 By default, this command copies the contents of files as they
5323 exist in the working directory. If invoked with -A/--after, the
5323 exist in the working directory. If invoked with -A/--after, the
5324 operation is recorded, but no copying is performed.
5324 operation is recorded, but no copying is performed.
5325
5325
5326 This command takes effect at the next commit. To undo a rename
5326 This command takes effect at the next commit. To undo a rename
5327 before that, see :hg:`revert`.
5327 before that, see :hg:`revert`.
5328
5328
5329 Returns 0 on success, 1 if errors are encountered.
5329 Returns 0 on success, 1 if errors are encountered.
5330 """
5330 """
5331 wlock = repo.wlock(False)
5331 wlock = repo.wlock(False)
5332 try:
5332 try:
5333 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5333 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5334 finally:
5334 finally:
5335 wlock.release()
5335 wlock.release()
5336
5336
5337 @command('resolve',
5337 @command('resolve',
5338 [('a', 'all', None, _('select all unresolved files')),
5338 [('a', 'all', None, _('select all unresolved files')),
5339 ('l', 'list', None, _('list state of files needing merge')),
5339 ('l', 'list', None, _('list state of files needing merge')),
5340 ('m', 'mark', None, _('mark files as resolved')),
5340 ('m', 'mark', None, _('mark files as resolved')),
5341 ('u', 'unmark', None, _('mark files as unresolved')),
5341 ('u', 'unmark', None, _('mark files as unresolved')),
5342 ('n', 'no-status', None, _('hide status prefix'))]
5342 ('n', 'no-status', None, _('hide status prefix'))]
5343 + mergetoolopts + walkopts + formatteropts,
5343 + mergetoolopts + walkopts + formatteropts,
5344 _('[OPTION]... [FILE]...'),
5344 _('[OPTION]... [FILE]...'),
5345 inferrepo=True)
5345 inferrepo=True)
5346 def resolve(ui, repo, *pats, **opts):
5346 def resolve(ui, repo, *pats, **opts):
5347 """redo merges or set/view the merge status of files
5347 """redo merges or set/view the merge status of files
5348
5348
5349 Merges with unresolved conflicts are often the result of
5349 Merges with unresolved conflicts are often the result of
5350 non-interactive merging using the ``internal:merge`` configuration
5350 non-interactive merging using the ``internal:merge`` configuration
5351 setting, or a command-line merge tool like ``diff3``. The resolve
5351 setting, or a command-line merge tool like ``diff3``. The resolve
5352 command is used to manage the files involved in a merge, after
5352 command is used to manage the files involved in a merge, after
5353 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5353 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5354 working directory must have two parents). See :hg:`help
5354 working directory must have two parents). See :hg:`help
5355 merge-tools` for information on configuring merge tools.
5355 merge-tools` for information on configuring merge tools.
5356
5356
5357 The resolve command can be used in the following ways:
5357 The resolve command can be used in the following ways:
5358
5358
5359 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5359 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5360 files, discarding any previous merge attempts. Re-merging is not
5360 files, discarding any previous merge attempts. Re-merging is not
5361 performed for files already marked as resolved. Use ``--all/-a``
5361 performed for files already marked as resolved. Use ``--all/-a``
5362 to select all unresolved files. ``--tool`` can be used to specify
5362 to select all unresolved files. ``--tool`` can be used to specify
5363 the merge tool used for the given files. It overrides the HGMERGE
5363 the merge tool used for the given files. It overrides the HGMERGE
5364 environment variable and your configuration files. Previous file
5364 environment variable and your configuration files. Previous file
5365 contents are saved with a ``.orig`` suffix.
5365 contents are saved with a ``.orig`` suffix.
5366
5366
5367 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5367 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5368 (e.g. after having manually fixed-up the files). The default is
5368 (e.g. after having manually fixed-up the files). The default is
5369 to mark all unresolved files.
5369 to mark all unresolved files.
5370
5370
5371 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5371 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5372 default is to mark all resolved files.
5372 default is to mark all resolved files.
5373
5373
5374 - :hg:`resolve -l`: list files which had or still have conflicts.
5374 - :hg:`resolve -l`: list files which had or still have conflicts.
5375 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5375 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5376
5376
5377 Note that Mercurial will not let you commit files with unresolved
5377 Note that Mercurial will not let you commit files with unresolved
5378 merge conflicts. You must use :hg:`resolve -m ...` before you can
5378 merge conflicts. You must use :hg:`resolve -m ...` before you can
5379 commit after a conflicting merge.
5379 commit after a conflicting merge.
5380
5380
5381 Returns 0 on success, 1 if any files fail a resolve attempt.
5381 Returns 0 on success, 1 if any files fail a resolve attempt.
5382 """
5382 """
5383
5383
5384 all, mark, unmark, show, nostatus = \
5384 all, mark, unmark, show, nostatus = \
5385 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5385 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5386
5386
5387 if (show and (mark or unmark)) or (mark and unmark):
5387 if (show and (mark or unmark)) or (mark and unmark):
5388 raise util.Abort(_("too many options specified"))
5388 raise util.Abort(_("too many options specified"))
5389 if pats and all:
5389 if pats and all:
5390 raise util.Abort(_("can't specify --all and patterns"))
5390 raise util.Abort(_("can't specify --all and patterns"))
5391 if not (all or pats or show or mark or unmark):
5391 if not (all or pats or show or mark or unmark):
5392 raise util.Abort(_('no files or directories specified'),
5392 raise util.Abort(_('no files or directories specified'),
5393 hint=('use --all to remerge all files'))
5393 hint=('use --all to remerge all files'))
5394
5394
5395 if show:
5395 if show:
5396 fm = ui.formatter('resolve', opts)
5396 fm = ui.formatter('resolve', opts)
5397 ms = mergemod.mergestate(repo)
5397 ms = mergemod.mergestate(repo)
5398 m = scmutil.match(repo[None], pats, opts)
5398 m = scmutil.match(repo[None], pats, opts)
5399 for f in ms:
5399 for f in ms:
5400 if not m(f):
5400 if not m(f):
5401 continue
5401 continue
5402 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5402 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5403 fm.startitem()
5403 fm.startitem()
5404 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5404 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5405 fm.write('path', '%s\n', f, label=l)
5405 fm.write('path', '%s\n', f, label=l)
5406 fm.end()
5406 fm.end()
5407 return 0
5407 return 0
5408
5408
5409 wlock = repo.wlock()
5409 wlock = repo.wlock()
5410 try:
5410 try:
5411 ms = mergemod.mergestate(repo)
5411 ms = mergemod.mergestate(repo)
5412
5412
5413 if not (ms.active() or repo.dirstate.p2() != nullid):
5413 if not (ms.active() or repo.dirstate.p2() != nullid):
5414 raise util.Abort(
5414 raise util.Abort(
5415 _('resolve command not applicable when not merging'))
5415 _('resolve command not applicable when not merging'))
5416
5416
5417 m = scmutil.match(repo[None], pats, opts)
5417 m = scmutil.match(repo[None], pats, opts)
5418 ret = 0
5418 ret = 0
5419 didwork = False
5419 didwork = False
5420
5420
5421 for f in ms:
5421 for f in ms:
5422 if not m(f):
5422 if not m(f):
5423 continue
5423 continue
5424
5424
5425 didwork = True
5425 didwork = True
5426
5426
5427 if mark:
5427 if mark:
5428 ms.mark(f, "r")
5428 ms.mark(f, "r")
5429 elif unmark:
5429 elif unmark:
5430 ms.mark(f, "u")
5430 ms.mark(f, "u")
5431 else:
5431 else:
5432 wctx = repo[None]
5432 wctx = repo[None]
5433
5433
5434 # backup pre-resolve (merge uses .orig for its own purposes)
5434 # backup pre-resolve (merge uses .orig for its own purposes)
5435 a = repo.wjoin(f)
5435 a = repo.wjoin(f)
5436 util.copyfile(a, a + ".resolve")
5436 util.copyfile(a, a + ".resolve")
5437
5437
5438 try:
5438 try:
5439 # resolve file
5439 # resolve file
5440 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5440 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5441 'resolve')
5441 'resolve')
5442 if ms.resolve(f, wctx):
5442 if ms.resolve(f, wctx):
5443 ret = 1
5443 ret = 1
5444 finally:
5444 finally:
5445 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5445 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5446 ms.commit()
5446 ms.commit()
5447
5447
5448 # replace filemerge's .orig file with our resolve file
5448 # replace filemerge's .orig file with our resolve file
5449 util.rename(a + ".resolve", a + ".orig")
5449 util.rename(a + ".resolve", a + ".orig")
5450
5450
5451 ms.commit()
5451 ms.commit()
5452
5452
5453 if not didwork and pats:
5453 if not didwork and pats:
5454 ui.warn(_("arguments do not match paths that need resolving\n"))
5454 ui.warn(_("arguments do not match paths that need resolving\n"))
5455
5455
5456 finally:
5456 finally:
5457 wlock.release()
5457 wlock.release()
5458
5458
5459 # Nudge users into finishing an unfinished operation
5459 # Nudge users into finishing an unfinished operation
5460 if not list(ms.unresolved()):
5460 if not list(ms.unresolved()):
5461 ui.status(_('(no more unresolved files)\n'))
5461 ui.status(_('(no more unresolved files)\n'))
5462
5462
5463 return ret
5463 return ret
5464
5464
5465 @command('revert',
5465 @command('revert',
5466 [('a', 'all', None, _('revert all changes when no arguments given')),
5466 [('a', 'all', None, _('revert all changes when no arguments given')),
5467 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5467 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5468 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5468 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5469 ('C', 'no-backup', None, _('do not save backup copies of files')),
5469 ('C', 'no-backup', None, _('do not save backup copies of files')),
5470 ('i', 'interactive', None,
5470 ('i', 'interactive', None,
5471 _('interactively select the changes (EXPERIMENTAL)')),
5471 _('interactively select the changes (EXPERIMENTAL)')),
5472 ] + walkopts + dryrunopts,
5472 ] + walkopts + dryrunopts,
5473 _('[OPTION]... [-r REV] [NAME]...'))
5473 _('[OPTION]... [-r REV] [NAME]...'))
5474 def revert(ui, repo, *pats, **opts):
5474 def revert(ui, repo, *pats, **opts):
5475 """restore files to their checkout state
5475 """restore files to their checkout state
5476
5476
5477 .. note::
5477 .. note::
5478
5478
5479 To check out earlier revisions, you should use :hg:`update REV`.
5479 To check out earlier revisions, you should use :hg:`update REV`.
5480 To cancel an uncommitted merge (and lose your changes),
5480 To cancel an uncommitted merge (and lose your changes),
5481 use :hg:`update --clean .`.
5481 use :hg:`update --clean .`.
5482
5482
5483 With no revision specified, revert the specified files or directories
5483 With no revision specified, revert the specified files or directories
5484 to the contents they had in the parent of the working directory.
5484 to the contents they had in the parent of the working directory.
5485 This restores the contents of files to an unmodified
5485 This restores the contents of files to an unmodified
5486 state and unschedules adds, removes, copies, and renames. If the
5486 state and unschedules adds, removes, copies, and renames. If the
5487 working directory has two parents, you must explicitly specify a
5487 working directory has two parents, you must explicitly specify a
5488 revision.
5488 revision.
5489
5489
5490 Using the -r/--rev or -d/--date options, revert the given files or
5490 Using the -r/--rev or -d/--date options, revert the given files or
5491 directories to their states as of a specific revision. Because
5491 directories to their states as of a specific revision. Because
5492 revert does not change the working directory parents, this will
5492 revert does not change the working directory parents, this will
5493 cause these files to appear modified. This can be helpful to "back
5493 cause these files to appear modified. This can be helpful to "back
5494 out" some or all of an earlier change. See :hg:`backout` for a
5494 out" some or all of an earlier change. See :hg:`backout` for a
5495 related method.
5495 related method.
5496
5496
5497 Modified files are saved with a .orig suffix before reverting.
5497 Modified files are saved with a .orig suffix before reverting.
5498 To disable these backups, use --no-backup.
5498 To disable these backups, use --no-backup.
5499
5499
5500 See :hg:`help dates` for a list of formats valid for -d/--date.
5500 See :hg:`help dates` for a list of formats valid for -d/--date.
5501
5501
5502 Returns 0 on success.
5502 Returns 0 on success.
5503 """
5503 """
5504
5504
5505 if opts.get("date"):
5505 if opts.get("date"):
5506 if opts.get("rev"):
5506 if opts.get("rev"):
5507 raise util.Abort(_("you can't specify a revision and a date"))
5507 raise util.Abort(_("you can't specify a revision and a date"))
5508 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5508 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5509
5509
5510 parent, p2 = repo.dirstate.parents()
5510 parent, p2 = repo.dirstate.parents()
5511 if not opts.get('rev') and p2 != nullid:
5511 if not opts.get('rev') and p2 != nullid:
5512 # revert after merge is a trap for new users (issue2915)
5512 # revert after merge is a trap for new users (issue2915)
5513 raise util.Abort(_('uncommitted merge with no revision specified'),
5513 raise util.Abort(_('uncommitted merge with no revision specified'),
5514 hint=_('use "hg update" or see "hg help revert"'))
5514 hint=_('use "hg update" or see "hg help revert"'))
5515
5515
5516 ctx = scmutil.revsingle(repo, opts.get('rev'))
5516 ctx = scmutil.revsingle(repo, opts.get('rev'))
5517
5517
5518 if (not (pats or opts.get('include') or opts.get('exclude') or
5518 if (not (pats or opts.get('include') or opts.get('exclude') or
5519 opts.get('all') or opts.get('interactive'))):
5519 opts.get('all') or opts.get('interactive'))):
5520 msg = _("no files or directories specified")
5520 msg = _("no files or directories specified")
5521 if p2 != nullid:
5521 if p2 != nullid:
5522 hint = _("uncommitted merge, use --all to discard all changes,"
5522 hint = _("uncommitted merge, use --all to discard all changes,"
5523 " or 'hg update -C .' to abort the merge")
5523 " or 'hg update -C .' to abort the merge")
5524 raise util.Abort(msg, hint=hint)
5524 raise util.Abort(msg, hint=hint)
5525 dirty = any(repo.status())
5525 dirty = any(repo.status())
5526 node = ctx.node()
5526 node = ctx.node()
5527 if node != parent:
5527 if node != parent:
5528 if dirty:
5528 if dirty:
5529 hint = _("uncommitted changes, use --all to discard all"
5529 hint = _("uncommitted changes, use --all to discard all"
5530 " changes, or 'hg update %s' to update") % ctx.rev()
5530 " changes, or 'hg update %s' to update") % ctx.rev()
5531 else:
5531 else:
5532 hint = _("use --all to revert all files,"
5532 hint = _("use --all to revert all files,"
5533 " or 'hg update %s' to update") % ctx.rev()
5533 " or 'hg update %s' to update") % ctx.rev()
5534 elif dirty:
5534 elif dirty:
5535 hint = _("uncommitted changes, use --all to discard all changes")
5535 hint = _("uncommitted changes, use --all to discard all changes")
5536 else:
5536 else:
5537 hint = _("use --all to revert all files")
5537 hint = _("use --all to revert all files")
5538 raise util.Abort(msg, hint=hint)
5538 raise util.Abort(msg, hint=hint)
5539
5539
5540 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5540 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5541
5541
5542 @command('rollback', dryrunopts +
5542 @command('rollback', dryrunopts +
5543 [('f', 'force', False, _('ignore safety measures'))])
5543 [('f', 'force', False, _('ignore safety measures'))])
5544 def rollback(ui, repo, **opts):
5544 def rollback(ui, repo, **opts):
5545 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5545 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5546
5546
5547 Please use :hg:`commit --amend` instead of rollback to correct
5547 Please use :hg:`commit --amend` instead of rollback to correct
5548 mistakes in the last commit.
5548 mistakes in the last commit.
5549
5549
5550 This command should be used with care. There is only one level of
5550 This command should be used with care. There is only one level of
5551 rollback, and there is no way to undo a rollback. It will also
5551 rollback, and there is no way to undo a rollback. It will also
5552 restore the dirstate at the time of the last transaction, losing
5552 restore the dirstate at the time of the last transaction, losing
5553 any dirstate changes since that time. This command does not alter
5553 any dirstate changes since that time. This command does not alter
5554 the working directory.
5554 the working directory.
5555
5555
5556 Transactions are used to encapsulate the effects of all commands
5556 Transactions are used to encapsulate the effects of all commands
5557 that create new changesets or propagate existing changesets into a
5557 that create new changesets or propagate existing changesets into a
5558 repository.
5558 repository.
5559
5559
5560 .. container:: verbose
5560 .. container:: verbose
5561
5561
5562 For example, the following commands are transactional, and their
5562 For example, the following commands are transactional, and their
5563 effects can be rolled back:
5563 effects can be rolled back:
5564
5564
5565 - commit
5565 - commit
5566 - import
5566 - import
5567 - pull
5567 - pull
5568 - push (with this repository as the destination)
5568 - push (with this repository as the destination)
5569 - unbundle
5569 - unbundle
5570
5570
5571 To avoid permanent data loss, rollback will refuse to rollback a
5571 To avoid permanent data loss, rollback will refuse to rollback a
5572 commit transaction if it isn't checked out. Use --force to
5572 commit transaction if it isn't checked out. Use --force to
5573 override this protection.
5573 override this protection.
5574
5574
5575 This command is not intended for use on public repositories. Once
5575 This command is not intended for use on public repositories. Once
5576 changes are visible for pull by other users, rolling a transaction
5576 changes are visible for pull by other users, rolling a transaction
5577 back locally is ineffective (someone else may already have pulled
5577 back locally is ineffective (someone else may already have pulled
5578 the changes). Furthermore, a race is possible with readers of the
5578 the changes). Furthermore, a race is possible with readers of the
5579 repository; for example an in-progress pull from the repository
5579 repository; for example an in-progress pull from the repository
5580 may fail if a rollback is performed.
5580 may fail if a rollback is performed.
5581
5581
5582 Returns 0 on success, 1 if no rollback data is available.
5582 Returns 0 on success, 1 if no rollback data is available.
5583 """
5583 """
5584 return repo.rollback(dryrun=opts.get('dry_run'),
5584 return repo.rollback(dryrun=opts.get('dry_run'),
5585 force=opts.get('force'))
5585 force=opts.get('force'))
5586
5586
5587 @command('root', [])
5587 @command('root', [])
5588 def root(ui, repo):
5588 def root(ui, repo):
5589 """print the root (top) of the current working directory
5589 """print the root (top) of the current working directory
5590
5590
5591 Print the root directory of the current repository.
5591 Print the root directory of the current repository.
5592
5592
5593 Returns 0 on success.
5593 Returns 0 on success.
5594 """
5594 """
5595 ui.write(repo.root + "\n")
5595 ui.write(repo.root + "\n")
5596
5596
5597 @command('^serve',
5597 @command('^serve',
5598 [('A', 'accesslog', '', _('name of access log file to write to'),
5598 [('A', 'accesslog', '', _('name of access log file to write to'),
5599 _('FILE')),
5599 _('FILE')),
5600 ('d', 'daemon', None, _('run server in background')),
5600 ('d', 'daemon', None, _('run server in background')),
5601 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5601 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5602 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5602 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5603 # use string type, then we can check if something was passed
5603 # use string type, then we can check if something was passed
5604 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5604 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5605 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5605 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5606 _('ADDR')),
5606 _('ADDR')),
5607 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5607 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5608 _('PREFIX')),
5608 _('PREFIX')),
5609 ('n', 'name', '',
5609 ('n', 'name', '',
5610 _('name to show in web pages (default: working directory)'), _('NAME')),
5610 _('name to show in web pages (default: working directory)'), _('NAME')),
5611 ('', 'web-conf', '',
5611 ('', 'web-conf', '',
5612 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5612 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5613 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5613 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5614 _('FILE')),
5614 _('FILE')),
5615 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5615 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5616 ('', 'stdio', None, _('for remote clients')),
5616 ('', 'stdio', None, _('for remote clients')),
5617 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5617 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5618 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5618 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5619 ('', 'style', '', _('template style to use'), _('STYLE')),
5619 ('', 'style', '', _('template style to use'), _('STYLE')),
5620 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5620 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5621 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5621 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5622 _('[OPTION]...'),
5622 _('[OPTION]...'),
5623 optionalrepo=True)
5623 optionalrepo=True)
5624 def serve(ui, repo, **opts):
5624 def serve(ui, repo, **opts):
5625 """start stand-alone webserver
5625 """start stand-alone webserver
5626
5626
5627 Start a local HTTP repository browser and pull server. You can use
5627 Start a local HTTP repository browser and pull server. You can use
5628 this for ad-hoc sharing and browsing of repositories. It is
5628 this for ad-hoc sharing and browsing of repositories. It is
5629 recommended to use a real web server to serve a repository for
5629 recommended to use a real web server to serve a repository for
5630 longer periods of time.
5630 longer periods of time.
5631
5631
5632 Please note that the server does not implement access control.
5632 Please note that the server does not implement access control.
5633 This means that, by default, anybody can read from the server and
5633 This means that, by default, anybody can read from the server and
5634 nobody can write to it by default. Set the ``web.allow_push``
5634 nobody can write to it by default. Set the ``web.allow_push``
5635 option to ``*`` to allow everybody to push to the server. You
5635 option to ``*`` to allow everybody to push to the server. You
5636 should use a real web server if you need to authenticate users.
5636 should use a real web server if you need to authenticate users.
5637
5637
5638 By default, the server logs accesses to stdout and errors to
5638 By default, the server logs accesses to stdout and errors to
5639 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5639 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5640 files.
5640 files.
5641
5641
5642 To have the server choose a free port number to listen on, specify
5642 To have the server choose a free port number to listen on, specify
5643 a port number of 0; in this case, the server will print the port
5643 a port number of 0; in this case, the server will print the port
5644 number it uses.
5644 number it uses.
5645
5645
5646 Returns 0 on success.
5646 Returns 0 on success.
5647 """
5647 """
5648
5648
5649 if opts["stdio"] and opts["cmdserver"]:
5649 if opts["stdio"] and opts["cmdserver"]:
5650 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5650 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5651
5651
5652 if opts["stdio"]:
5652 if opts["stdio"]:
5653 if repo is None:
5653 if repo is None:
5654 raise error.RepoError(_("there is no Mercurial repository here"
5654 raise error.RepoError(_("there is no Mercurial repository here"
5655 " (.hg not found)"))
5655 " (.hg not found)"))
5656 s = sshserver.sshserver(ui, repo)
5656 s = sshserver.sshserver(ui, repo)
5657 s.serve_forever()
5657 s.serve_forever()
5658
5658
5659 if opts["cmdserver"]:
5659 if opts["cmdserver"]:
5660 service = commandserver.createservice(ui, repo, opts)
5660 service = commandserver.createservice(ui, repo, opts)
5661 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5661 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5662
5662
5663 # this way we can check if something was given in the command-line
5663 # this way we can check if something was given in the command-line
5664 if opts.get('port'):
5664 if opts.get('port'):
5665 opts['port'] = util.getport(opts.get('port'))
5665 opts['port'] = util.getport(opts.get('port'))
5666
5666
5667 if repo:
5667 if repo:
5668 baseui = repo.baseui
5668 baseui = repo.baseui
5669 else:
5669 else:
5670 baseui = ui
5670 baseui = ui
5671 optlist = ("name templates style address port prefix ipv6"
5671 optlist = ("name templates style address port prefix ipv6"
5672 " accesslog errorlog certificate encoding")
5672 " accesslog errorlog certificate encoding")
5673 for o in optlist.split():
5673 for o in optlist.split():
5674 val = opts.get(o, '')
5674 val = opts.get(o, '')
5675 if val in (None, ''): # should check against default options instead
5675 if val in (None, ''): # should check against default options instead
5676 continue
5676 continue
5677 baseui.setconfig("web", o, val, 'serve')
5677 baseui.setconfig("web", o, val, 'serve')
5678 if repo and repo.ui != baseui:
5678 if repo and repo.ui != baseui:
5679 repo.ui.setconfig("web", o, val, 'serve')
5679 repo.ui.setconfig("web", o, val, 'serve')
5680
5680
5681 o = opts.get('web_conf') or opts.get('webdir_conf')
5681 o = opts.get('web_conf') or opts.get('webdir_conf')
5682 if not o:
5682 if not o:
5683 if not repo:
5683 if not repo:
5684 raise error.RepoError(_("there is no Mercurial repository"
5684 raise error.RepoError(_("there is no Mercurial repository"
5685 " here (.hg not found)"))
5685 " here (.hg not found)"))
5686 o = repo
5686 o = repo
5687
5687
5688 app = hgweb.hgweb(o, baseui=baseui)
5688 app = hgweb.hgweb(o, baseui=baseui)
5689 service = httpservice(ui, app, opts)
5689 service = httpservice(ui, app, opts)
5690 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5690 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5691
5691
5692 class httpservice(object):
5692 class httpservice(object):
5693 def __init__(self, ui, app, opts):
5693 def __init__(self, ui, app, opts):
5694 self.ui = ui
5694 self.ui = ui
5695 self.app = app
5695 self.app = app
5696 self.opts = opts
5696 self.opts = opts
5697
5697
5698 def init(self):
5698 def init(self):
5699 util.setsignalhandler()
5699 util.setsignalhandler()
5700 self.httpd = hgweb_server.create_server(self.ui, self.app)
5700 self.httpd = hgweb_server.create_server(self.ui, self.app)
5701
5701
5702 if self.opts['port'] and not self.ui.verbose:
5702 if self.opts['port'] and not self.ui.verbose:
5703 return
5703 return
5704
5704
5705 if self.httpd.prefix:
5705 if self.httpd.prefix:
5706 prefix = self.httpd.prefix.strip('/') + '/'
5706 prefix = self.httpd.prefix.strip('/') + '/'
5707 else:
5707 else:
5708 prefix = ''
5708 prefix = ''
5709
5709
5710 port = ':%d' % self.httpd.port
5710 port = ':%d' % self.httpd.port
5711 if port == ':80':
5711 if port == ':80':
5712 port = ''
5712 port = ''
5713
5713
5714 bindaddr = self.httpd.addr
5714 bindaddr = self.httpd.addr
5715 if bindaddr == '0.0.0.0':
5715 if bindaddr == '0.0.0.0':
5716 bindaddr = '*'
5716 bindaddr = '*'
5717 elif ':' in bindaddr: # IPv6
5717 elif ':' in bindaddr: # IPv6
5718 bindaddr = '[%s]' % bindaddr
5718 bindaddr = '[%s]' % bindaddr
5719
5719
5720 fqaddr = self.httpd.fqaddr
5720 fqaddr = self.httpd.fqaddr
5721 if ':' in fqaddr:
5721 if ':' in fqaddr:
5722 fqaddr = '[%s]' % fqaddr
5722 fqaddr = '[%s]' % fqaddr
5723 if self.opts['port']:
5723 if self.opts['port']:
5724 write = self.ui.status
5724 write = self.ui.status
5725 else:
5725 else:
5726 write = self.ui.write
5726 write = self.ui.write
5727 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5727 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5728 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5728 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5729 self.ui.flush() # avoid buffering of status message
5729 self.ui.flush() # avoid buffering of status message
5730
5730
5731 def run(self):
5731 def run(self):
5732 self.httpd.serve_forever()
5732 self.httpd.serve_forever()
5733
5733
5734
5734
5735 @command('^status|st',
5735 @command('^status|st',
5736 [('A', 'all', None, _('show status of all files')),
5736 [('A', 'all', None, _('show status of all files')),
5737 ('m', 'modified', None, _('show only modified files')),
5737 ('m', 'modified', None, _('show only modified files')),
5738 ('a', 'added', None, _('show only added files')),
5738 ('a', 'added', None, _('show only added files')),
5739 ('r', 'removed', None, _('show only removed files')),
5739 ('r', 'removed', None, _('show only removed files')),
5740 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5740 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5741 ('c', 'clean', None, _('show only files without changes')),
5741 ('c', 'clean', None, _('show only files without changes')),
5742 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5742 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5743 ('i', 'ignored', None, _('show only ignored files')),
5743 ('i', 'ignored', None, _('show only ignored files')),
5744 ('n', 'no-status', None, _('hide status prefix')),
5744 ('n', 'no-status', None, _('hide status prefix')),
5745 ('C', 'copies', None, _('show source of copied files')),
5745 ('C', 'copies', None, _('show source of copied files')),
5746 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5746 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5747 ('', 'rev', [], _('show difference from revision'), _('REV')),
5747 ('', 'rev', [], _('show difference from revision'), _('REV')),
5748 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5748 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5749 ] + walkopts + subrepoopts + formatteropts,
5749 ] + walkopts + subrepoopts + formatteropts,
5750 _('[OPTION]... [FILE]...'),
5750 _('[OPTION]... [FILE]...'),
5751 inferrepo=True)
5751 inferrepo=True)
5752 def status(ui, repo, *pats, **opts):
5752 def status(ui, repo, *pats, **opts):
5753 """show changed files in the working directory
5753 """show changed files in the working directory
5754
5754
5755 Show status of files in the repository. If names are given, only
5755 Show status of files in the repository. If names are given, only
5756 files that match are shown. Files that are clean or ignored or
5756 files that match are shown. Files that are clean or ignored or
5757 the source of a copy/move operation, are not listed unless
5757 the source of a copy/move operation, are not listed unless
5758 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5758 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5759 Unless options described with "show only ..." are given, the
5759 Unless options described with "show only ..." are given, the
5760 options -mardu are used.
5760 options -mardu are used.
5761
5761
5762 Option -q/--quiet hides untracked (unknown and ignored) files
5762 Option -q/--quiet hides untracked (unknown and ignored) files
5763 unless explicitly requested with -u/--unknown or -i/--ignored.
5763 unless explicitly requested with -u/--unknown or -i/--ignored.
5764
5764
5765 .. note::
5765 .. note::
5766
5766
5767 status may appear to disagree with diff if permissions have
5767 status may appear to disagree with diff if permissions have
5768 changed or a merge has occurred. The standard diff format does
5768 changed or a merge has occurred. The standard diff format does
5769 not report permission changes and diff only reports changes
5769 not report permission changes and diff only reports changes
5770 relative to one merge parent.
5770 relative to one merge parent.
5771
5771
5772 If one revision is given, it is used as the base revision.
5772 If one revision is given, it is used as the base revision.
5773 If two revisions are given, the differences between them are
5773 If two revisions are given, the differences between them are
5774 shown. The --change option can also be used as a shortcut to list
5774 shown. The --change option can also be used as a shortcut to list
5775 the changed files of a revision from its first parent.
5775 the changed files of a revision from its first parent.
5776
5776
5777 The codes used to show the status of files are::
5777 The codes used to show the status of files are::
5778
5778
5779 M = modified
5779 M = modified
5780 A = added
5780 A = added
5781 R = removed
5781 R = removed
5782 C = clean
5782 C = clean
5783 ! = missing (deleted by non-hg command, but still tracked)
5783 ! = missing (deleted by non-hg command, but still tracked)
5784 ? = not tracked
5784 ? = not tracked
5785 I = ignored
5785 I = ignored
5786 = origin of the previous file (with --copies)
5786 = origin of the previous file (with --copies)
5787
5787
5788 .. container:: verbose
5788 .. container:: verbose
5789
5789
5790 Examples:
5790 Examples:
5791
5791
5792 - show changes in the working directory relative to a
5792 - show changes in the working directory relative to a
5793 changeset::
5793 changeset::
5794
5794
5795 hg status --rev 9353
5795 hg status --rev 9353
5796
5796
5797 - show changes in the working directory relative to the
5797 - show changes in the working directory relative to the
5798 current directory (see :hg:`help patterns` for more information)::
5798 current directory (see :hg:`help patterns` for more information)::
5799
5799
5800 hg status re:
5800 hg status re:
5801
5801
5802 - show all changes including copies in an existing changeset::
5802 - show all changes including copies in an existing changeset::
5803
5803
5804 hg status --copies --change 9353
5804 hg status --copies --change 9353
5805
5805
5806 - get a NUL separated list of added files, suitable for xargs::
5806 - get a NUL separated list of added files, suitable for xargs::
5807
5807
5808 hg status -an0
5808 hg status -an0
5809
5809
5810 Returns 0 on success.
5810 Returns 0 on success.
5811 """
5811 """
5812
5812
5813 revs = opts.get('rev')
5813 revs = opts.get('rev')
5814 change = opts.get('change')
5814 change = opts.get('change')
5815
5815
5816 if revs and change:
5816 if revs and change:
5817 msg = _('cannot specify --rev and --change at the same time')
5817 msg = _('cannot specify --rev and --change at the same time')
5818 raise util.Abort(msg)
5818 raise util.Abort(msg)
5819 elif change:
5819 elif change:
5820 node2 = scmutil.revsingle(repo, change, None).node()
5820 node2 = scmutil.revsingle(repo, change, None).node()
5821 node1 = repo[node2].p1().node()
5821 node1 = repo[node2].p1().node()
5822 else:
5822 else:
5823 node1, node2 = scmutil.revpair(repo, revs)
5823 node1, node2 = scmutil.revpair(repo, revs)
5824
5824
5825 if pats:
5825 if pats:
5826 cwd = repo.getcwd()
5826 cwd = repo.getcwd()
5827 else:
5827 else:
5828 cwd = ''
5828 cwd = ''
5829
5829
5830 if opts.get('print0'):
5830 if opts.get('print0'):
5831 end = '\0'
5831 end = '\0'
5832 else:
5832 else:
5833 end = '\n'
5833 end = '\n'
5834 copy = {}
5834 copy = {}
5835 states = 'modified added removed deleted unknown ignored clean'.split()
5835 states = 'modified added removed deleted unknown ignored clean'.split()
5836 show = [k for k in states if opts.get(k)]
5836 show = [k for k in states if opts.get(k)]
5837 if opts.get('all'):
5837 if opts.get('all'):
5838 show += ui.quiet and (states[:4] + ['clean']) or states
5838 show += ui.quiet and (states[:4] + ['clean']) or states
5839 if not show:
5839 if not show:
5840 if ui.quiet:
5840 if ui.quiet:
5841 show = states[:4]
5841 show = states[:4]
5842 else:
5842 else:
5843 show = states[:5]
5843 show = states[:5]
5844
5844
5845 m = scmutil.match(repo[node2], pats, opts)
5845 m = scmutil.match(repo[node2], pats, opts)
5846 stat = repo.status(node1, node2, m,
5846 stat = repo.status(node1, node2, m,
5847 'ignored' in show, 'clean' in show, 'unknown' in show,
5847 'ignored' in show, 'clean' in show, 'unknown' in show,
5848 opts.get('subrepos'))
5848 opts.get('subrepos'))
5849 changestates = zip(states, 'MAR!?IC', stat)
5849 changestates = zip(states, 'MAR!?IC', stat)
5850
5850
5851 if (opts.get('all') or opts.get('copies')
5851 if (opts.get('all') or opts.get('copies')
5852 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5852 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5853 copy = copies.pathcopies(repo[node1], repo[node2], m)
5853 copy = copies.pathcopies(repo[node1], repo[node2], m)
5854
5854
5855 fm = ui.formatter('status', opts)
5855 fm = ui.formatter('status', opts)
5856 fmt = '%s' + end
5856 fmt = '%s' + end
5857 showchar = not opts.get('no_status')
5857 showchar = not opts.get('no_status')
5858
5858
5859 for state, char, files in changestates:
5859 for state, char, files in changestates:
5860 if state in show:
5860 if state in show:
5861 label = 'status.' + state
5861 label = 'status.' + state
5862 for f in files:
5862 for f in files:
5863 fm.startitem()
5863 fm.startitem()
5864 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5864 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5865 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5865 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5866 if f in copy:
5866 if f in copy:
5867 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5867 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5868 label='status.copied')
5868 label='status.copied')
5869 fm.end()
5869 fm.end()
5870
5870
5871 @command('^summary|sum',
5871 @command('^summary|sum',
5872 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5872 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5873 def summary(ui, repo, **opts):
5873 def summary(ui, repo, **opts):
5874 """summarize working directory state
5874 """summarize working directory state
5875
5875
5876 This generates a brief summary of the working directory state,
5876 This generates a brief summary of the working directory state,
5877 including parents, branch, commit status, phase and available updates.
5877 including parents, branch, commit status, phase and available updates.
5878
5878
5879 With the --remote option, this will check the default paths for
5879 With the --remote option, this will check the default paths for
5880 incoming and outgoing changes. This can be time-consuming.
5880 incoming and outgoing changes. This can be time-consuming.
5881
5881
5882 Returns 0 on success.
5882 Returns 0 on success.
5883 """
5883 """
5884
5884
5885 ctx = repo[None]
5885 ctx = repo[None]
5886 parents = ctx.parents()
5886 parents = ctx.parents()
5887 pnode = parents[0].node()
5887 pnode = parents[0].node()
5888 marks = []
5888 marks = []
5889
5889
5890 for p in parents:
5890 for p in parents:
5891 # label with log.changeset (instead of log.parent) since this
5891 # label with log.changeset (instead of log.parent) since this
5892 # shows a working directory parent *changeset*:
5892 # shows a working directory parent *changeset*:
5893 # i18n: column positioning for "hg summary"
5893 # i18n: column positioning for "hg summary"
5894 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5894 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5895 label='log.changeset changeset.%s' % p.phasestr())
5895 label='log.changeset changeset.%s' % p.phasestr())
5896 ui.write(' '.join(p.tags()), label='log.tag')
5896 ui.write(' '.join(p.tags()), label='log.tag')
5897 if p.bookmarks():
5897 if p.bookmarks():
5898 marks.extend(p.bookmarks())
5898 marks.extend(p.bookmarks())
5899 if p.rev() == -1:
5899 if p.rev() == -1:
5900 if not len(repo):
5900 if not len(repo):
5901 ui.write(_(' (empty repository)'))
5901 ui.write(_(' (empty repository)'))
5902 else:
5902 else:
5903 ui.write(_(' (no revision checked out)'))
5903 ui.write(_(' (no revision checked out)'))
5904 ui.write('\n')
5904 ui.write('\n')
5905 if p.description():
5905 if p.description():
5906 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5906 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5907 label='log.summary')
5907 label='log.summary')
5908
5908
5909 branch = ctx.branch()
5909 branch = ctx.branch()
5910 bheads = repo.branchheads(branch)
5910 bheads = repo.branchheads(branch)
5911 # i18n: column positioning for "hg summary"
5911 # i18n: column positioning for "hg summary"
5912 m = _('branch: %s\n') % branch
5912 m = _('branch: %s\n') % branch
5913 if branch != 'default':
5913 if branch != 'default':
5914 ui.write(m, label='log.branch')
5914 ui.write(m, label='log.branch')
5915 else:
5915 else:
5916 ui.status(m, label='log.branch')
5916 ui.status(m, label='log.branch')
5917
5917
5918 if marks:
5918 if marks:
5919 current = repo._activebookmark
5919 current = repo._activebookmark
5920 # i18n: column positioning for "hg summary"
5920 # i18n: column positioning for "hg summary"
5921 ui.write(_('bookmarks:'), label='log.bookmark')
5921 ui.write(_('bookmarks:'), label='log.bookmark')
5922 if current is not None:
5922 if current is not None:
5923 if current in marks:
5923 if current in marks:
5924 ui.write(' *' + current, label='bookmarks.current')
5924 ui.write(' *' + current, label='bookmarks.current')
5925 marks.remove(current)
5925 marks.remove(current)
5926 else:
5926 else:
5927 ui.write(' [%s]' % current, label='bookmarks.current')
5927 ui.write(' [%s]' % current, label='bookmarks.current')
5928 for m in marks:
5928 for m in marks:
5929 ui.write(' ' + m, label='log.bookmark')
5929 ui.write(' ' + m, label='log.bookmark')
5930 ui.write('\n', label='log.bookmark')
5930 ui.write('\n', label='log.bookmark')
5931
5931
5932 status = repo.status(unknown=True)
5932 status = repo.status(unknown=True)
5933
5933
5934 c = repo.dirstate.copies()
5934 c = repo.dirstate.copies()
5935 copied, renamed = [], []
5935 copied, renamed = [], []
5936 for d, s in c.iteritems():
5936 for d, s in c.iteritems():
5937 if s in status.removed:
5937 if s in status.removed:
5938 status.removed.remove(s)
5938 status.removed.remove(s)
5939 renamed.append(d)
5939 renamed.append(d)
5940 else:
5940 else:
5941 copied.append(d)
5941 copied.append(d)
5942 if d in status.added:
5942 if d in status.added:
5943 status.added.remove(d)
5943 status.added.remove(d)
5944
5944
5945 ms = mergemod.mergestate(repo)
5945 ms = mergemod.mergestate(repo)
5946 unresolved = [f for f in ms if ms[f] == 'u']
5946 unresolved = [f for f in ms if ms[f] == 'u']
5947
5947
5948 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5948 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5949
5949
5950 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5950 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5951 (ui.label(_('%d added'), 'status.added'), status.added),
5951 (ui.label(_('%d added'), 'status.added'), status.added),
5952 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5952 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5953 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5953 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5954 (ui.label(_('%d copied'), 'status.copied'), copied),
5954 (ui.label(_('%d copied'), 'status.copied'), copied),
5955 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5955 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5956 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5956 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5957 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5957 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5958 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5958 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5959 t = []
5959 t = []
5960 for l, s in labels:
5960 for l, s in labels:
5961 if s:
5961 if s:
5962 t.append(l % len(s))
5962 t.append(l % len(s))
5963
5963
5964 t = ', '.join(t)
5964 t = ', '.join(t)
5965 cleanworkdir = False
5965 cleanworkdir = False
5966
5966
5967 if repo.vfs.exists('updatestate'):
5967 if repo.vfs.exists('updatestate'):
5968 t += _(' (interrupted update)')
5968 t += _(' (interrupted update)')
5969 elif len(parents) > 1:
5969 elif len(parents) > 1:
5970 t += _(' (merge)')
5970 t += _(' (merge)')
5971 elif branch != parents[0].branch():
5971 elif branch != parents[0].branch():
5972 t += _(' (new branch)')
5972 t += _(' (new branch)')
5973 elif (parents[0].closesbranch() and
5973 elif (parents[0].closesbranch() and
5974 pnode in repo.branchheads(branch, closed=True)):
5974 pnode in repo.branchheads(branch, closed=True)):
5975 t += _(' (head closed)')
5975 t += _(' (head closed)')
5976 elif not (status.modified or status.added or status.removed or renamed or
5976 elif not (status.modified or status.added or status.removed or renamed or
5977 copied or subs):
5977 copied or subs):
5978 t += _(' (clean)')
5978 t += _(' (clean)')
5979 cleanworkdir = True
5979 cleanworkdir = True
5980 elif pnode not in bheads:
5980 elif pnode not in bheads:
5981 t += _(' (new branch head)')
5981 t += _(' (new branch head)')
5982
5982
5983 if cleanworkdir:
5983 if cleanworkdir:
5984 # i18n: column positioning for "hg summary"
5984 # i18n: column positioning for "hg summary"
5985 ui.status(_('commit: %s\n') % t.strip())
5985 ui.status(_('commit: %s\n') % t.strip())
5986 else:
5986 else:
5987 # i18n: column positioning for "hg summary"
5987 # i18n: column positioning for "hg summary"
5988 ui.write(_('commit: %s\n') % t.strip())
5988 ui.write(_('commit: %s\n') % t.strip())
5989
5989
5990 # all ancestors of branch heads - all ancestors of parent = new csets
5990 # all ancestors of branch heads - all ancestors of parent = new csets
5991 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5991 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5992 bheads))
5992 bheads))
5993
5993
5994 if new == 0:
5994 if new == 0:
5995 # i18n: column positioning for "hg summary"
5995 # i18n: column positioning for "hg summary"
5996 ui.status(_('update: (current)\n'))
5996 ui.status(_('update: (current)\n'))
5997 elif pnode not in bheads:
5997 elif pnode not in bheads:
5998 # i18n: column positioning for "hg summary"
5998 # i18n: column positioning for "hg summary"
5999 ui.write(_('update: %d new changesets (update)\n') % new)
5999 ui.write(_('update: %d new changesets (update)\n') % new)
6000 else:
6000 else:
6001 # i18n: column positioning for "hg summary"
6001 # i18n: column positioning for "hg summary"
6002 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6002 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6003 (new, len(bheads)))
6003 (new, len(bheads)))
6004
6004
6005 t = []
6005 t = []
6006 draft = len(repo.revs('draft()'))
6006 draft = len(repo.revs('draft()'))
6007 if draft:
6007 if draft:
6008 t.append(_('%d draft') % draft)
6008 t.append(_('%d draft') % draft)
6009 secret = len(repo.revs('secret()'))
6009 secret = len(repo.revs('secret()'))
6010 if secret:
6010 if secret:
6011 t.append(_('%d secret') % secret)
6011 t.append(_('%d secret') % secret)
6012
6012
6013 if parents:
6013 if parents:
6014 parentphase = max(p.phase() for p in parents)
6014 parentphase = max(p.phase() for p in parents)
6015 else:
6015 else:
6016 parentphase = phases.public
6016 parentphase = phases.public
6017
6017
6018 if draft or secret:
6018 if draft or secret:
6019 ui.status(_('phases: %s (%s)\n') % (', '.join(t),
6019 ui.status(_('phases: %s (%s)\n') % (', '.join(t),
6020 phases.phasenames[parentphase]))
6020 phases.phasenames[parentphase]))
6021 else:
6021 else:
6022 ui.note(_('phases: (%s)\n') % phases.phasenames[parentphase])
6022 ui.note(_('phases: (%s)\n') % phases.phasenames[parentphase])
6023
6023
6024 cmdutil.summaryhooks(ui, repo)
6024 cmdutil.summaryhooks(ui, repo)
6025
6025
6026 if opts.get('remote'):
6026 if opts.get('remote'):
6027 needsincoming, needsoutgoing = True, True
6027 needsincoming, needsoutgoing = True, True
6028 else:
6028 else:
6029 needsincoming, needsoutgoing = False, False
6029 needsincoming, needsoutgoing = False, False
6030 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6030 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6031 if i:
6031 if i:
6032 needsincoming = True
6032 needsincoming = True
6033 if o:
6033 if o:
6034 needsoutgoing = True
6034 needsoutgoing = True
6035 if not needsincoming and not needsoutgoing:
6035 if not needsincoming and not needsoutgoing:
6036 return
6036 return
6037
6037
6038 def getincoming():
6038 def getincoming():
6039 source, branches = hg.parseurl(ui.expandpath('default'))
6039 source, branches = hg.parseurl(ui.expandpath('default'))
6040 sbranch = branches[0]
6040 sbranch = branches[0]
6041 try:
6041 try:
6042 other = hg.peer(repo, {}, source)
6042 other = hg.peer(repo, {}, source)
6043 except error.RepoError:
6043 except error.RepoError:
6044 if opts.get('remote'):
6044 if opts.get('remote'):
6045 raise
6045 raise
6046 return source, sbranch, None, None, None
6046 return source, sbranch, None, None, None
6047 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6047 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6048 if revs:
6048 if revs:
6049 revs = [other.lookup(rev) for rev in revs]
6049 revs = [other.lookup(rev) for rev in revs]
6050 ui.debug('comparing with %s\n' % util.hidepassword(source))
6050 ui.debug('comparing with %s\n' % util.hidepassword(source))
6051 repo.ui.pushbuffer()
6051 repo.ui.pushbuffer()
6052 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6052 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6053 repo.ui.popbuffer()
6053 repo.ui.popbuffer()
6054 return source, sbranch, other, commoninc, commoninc[1]
6054 return source, sbranch, other, commoninc, commoninc[1]
6055
6055
6056 if needsincoming:
6056 if needsincoming:
6057 source, sbranch, sother, commoninc, incoming = getincoming()
6057 source, sbranch, sother, commoninc, incoming = getincoming()
6058 else:
6058 else:
6059 source = sbranch = sother = commoninc = incoming = None
6059 source = sbranch = sother = commoninc = incoming = None
6060
6060
6061 def getoutgoing():
6061 def getoutgoing():
6062 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6062 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6063 dbranch = branches[0]
6063 dbranch = branches[0]
6064 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6064 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6065 if source != dest:
6065 if source != dest:
6066 try:
6066 try:
6067 dother = hg.peer(repo, {}, dest)
6067 dother = hg.peer(repo, {}, dest)
6068 except error.RepoError:
6068 except error.RepoError:
6069 if opts.get('remote'):
6069 if opts.get('remote'):
6070 raise
6070 raise
6071 return dest, dbranch, None, None
6071 return dest, dbranch, None, None
6072 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6072 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6073 elif sother is None:
6073 elif sother is None:
6074 # there is no explicit destination peer, but source one is invalid
6074 # there is no explicit destination peer, but source one is invalid
6075 return dest, dbranch, None, None
6075 return dest, dbranch, None, None
6076 else:
6076 else:
6077 dother = sother
6077 dother = sother
6078 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6078 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6079 common = None
6079 common = None
6080 else:
6080 else:
6081 common = commoninc
6081 common = commoninc
6082 if revs:
6082 if revs:
6083 revs = [repo.lookup(rev) for rev in revs]
6083 revs = [repo.lookup(rev) for rev in revs]
6084 repo.ui.pushbuffer()
6084 repo.ui.pushbuffer()
6085 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6085 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6086 commoninc=common)
6086 commoninc=common)
6087 repo.ui.popbuffer()
6087 repo.ui.popbuffer()
6088 return dest, dbranch, dother, outgoing
6088 return dest, dbranch, dother, outgoing
6089
6089
6090 if needsoutgoing:
6090 if needsoutgoing:
6091 dest, dbranch, dother, outgoing = getoutgoing()
6091 dest, dbranch, dother, outgoing = getoutgoing()
6092 else:
6092 else:
6093 dest = dbranch = dother = outgoing = None
6093 dest = dbranch = dother = outgoing = None
6094
6094
6095 if opts.get('remote'):
6095 if opts.get('remote'):
6096 t = []
6096 t = []
6097 if incoming:
6097 if incoming:
6098 t.append(_('1 or more incoming'))
6098 t.append(_('1 or more incoming'))
6099 o = outgoing.missing
6099 o = outgoing.missing
6100 if o:
6100 if o:
6101 t.append(_('%d outgoing') % len(o))
6101 t.append(_('%d outgoing') % len(o))
6102 other = dother or sother
6102 other = dother or sother
6103 if 'bookmarks' in other.listkeys('namespaces'):
6103 if 'bookmarks' in other.listkeys('namespaces'):
6104 counts = bookmarks.summary(repo, other)
6104 counts = bookmarks.summary(repo, other)
6105 if counts[0] > 0:
6105 if counts[0] > 0:
6106 t.append(_('%d incoming bookmarks') % counts[0])
6106 t.append(_('%d incoming bookmarks') % counts[0])
6107 if counts[1] > 0:
6107 if counts[1] > 0:
6108 t.append(_('%d outgoing bookmarks') % counts[1])
6108 t.append(_('%d outgoing bookmarks') % counts[1])
6109
6109
6110 if t:
6110 if t:
6111 # i18n: column positioning for "hg summary"
6111 # i18n: column positioning for "hg summary"
6112 ui.write(_('remote: %s\n') % (', '.join(t)))
6112 ui.write(_('remote: %s\n') % (', '.join(t)))
6113 else:
6113 else:
6114 # i18n: column positioning for "hg summary"
6114 # i18n: column positioning for "hg summary"
6115 ui.status(_('remote: (synced)\n'))
6115 ui.status(_('remote: (synced)\n'))
6116
6116
6117 cmdutil.summaryremotehooks(ui, repo, opts,
6117 cmdutil.summaryremotehooks(ui, repo, opts,
6118 ((source, sbranch, sother, commoninc),
6118 ((source, sbranch, sother, commoninc),
6119 (dest, dbranch, dother, outgoing)))
6119 (dest, dbranch, dother, outgoing)))
6120
6120
6121 @command('tag',
6121 @command('tag',
6122 [('f', 'force', None, _('force tag')),
6122 [('f', 'force', None, _('force tag')),
6123 ('l', 'local', None, _('make the tag local')),
6123 ('l', 'local', None, _('make the tag local')),
6124 ('r', 'rev', '', _('revision to tag'), _('REV')),
6124 ('r', 'rev', '', _('revision to tag'), _('REV')),
6125 ('', 'remove', None, _('remove a tag')),
6125 ('', 'remove', None, _('remove a tag')),
6126 # -l/--local is already there, commitopts cannot be used
6126 # -l/--local is already there, commitopts cannot be used
6127 ('e', 'edit', None, _('invoke editor on commit messages')),
6127 ('e', 'edit', None, _('invoke editor on commit messages')),
6128 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6128 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6129 ] + commitopts2,
6129 ] + commitopts2,
6130 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6130 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6131 def tag(ui, repo, name1, *names, **opts):
6131 def tag(ui, repo, name1, *names, **opts):
6132 """add one or more tags for the current or given revision
6132 """add one or more tags for the current or given revision
6133
6133
6134 Name a particular revision using <name>.
6134 Name a particular revision using <name>.
6135
6135
6136 Tags are used to name particular revisions of the repository and are
6136 Tags are used to name particular revisions of the repository and are
6137 very useful to compare different revisions, to go back to significant
6137 very useful to compare different revisions, to go back to significant
6138 earlier versions or to mark branch points as releases, etc. Changing
6138 earlier versions or to mark branch points as releases, etc. Changing
6139 an existing tag is normally disallowed; use -f/--force to override.
6139 an existing tag is normally disallowed; use -f/--force to override.
6140
6140
6141 If no revision is given, the parent of the working directory is
6141 If no revision is given, the parent of the working directory is
6142 used.
6142 used.
6143
6143
6144 To facilitate version control, distribution, and merging of tags,
6144 To facilitate version control, distribution, and merging of tags,
6145 they are stored as a file named ".hgtags" which is managed similarly
6145 they are stored as a file named ".hgtags" which is managed similarly
6146 to other project files and can be hand-edited if necessary. This
6146 to other project files and can be hand-edited if necessary. This
6147 also means that tagging creates a new commit. The file
6147 also means that tagging creates a new commit. The file
6148 ".hg/localtags" is used for local tags (not shared among
6148 ".hg/localtags" is used for local tags (not shared among
6149 repositories).
6149 repositories).
6150
6150
6151 Tag commits are usually made at the head of a branch. If the parent
6151 Tag commits are usually made at the head of a branch. If the parent
6152 of the working directory is not a branch head, :hg:`tag` aborts; use
6152 of the working directory is not a branch head, :hg:`tag` aborts; use
6153 -f/--force to force the tag commit to be based on a non-head
6153 -f/--force to force the tag commit to be based on a non-head
6154 changeset.
6154 changeset.
6155
6155
6156 See :hg:`help dates` for a list of formats valid for -d/--date.
6156 See :hg:`help dates` for a list of formats valid for -d/--date.
6157
6157
6158 Since tag names have priority over branch names during revision
6158 Since tag names have priority over branch names during revision
6159 lookup, using an existing branch name as a tag name is discouraged.
6159 lookup, using an existing branch name as a tag name is discouraged.
6160
6160
6161 Returns 0 on success.
6161 Returns 0 on success.
6162 """
6162 """
6163 wlock = lock = None
6163 wlock = lock = None
6164 try:
6164 try:
6165 wlock = repo.wlock()
6165 wlock = repo.wlock()
6166 lock = repo.lock()
6166 lock = repo.lock()
6167 rev_ = "."
6167 rev_ = "."
6168 names = [t.strip() for t in (name1,) + names]
6168 names = [t.strip() for t in (name1,) + names]
6169 if len(names) != len(set(names)):
6169 if len(names) != len(set(names)):
6170 raise util.Abort(_('tag names must be unique'))
6170 raise util.Abort(_('tag names must be unique'))
6171 for n in names:
6171 for n in names:
6172 scmutil.checknewlabel(repo, n, 'tag')
6172 scmutil.checknewlabel(repo, n, 'tag')
6173 if not n:
6173 if not n:
6174 raise util.Abort(_('tag names cannot consist entirely of '
6174 raise util.Abort(_('tag names cannot consist entirely of '
6175 'whitespace'))
6175 'whitespace'))
6176 if opts.get('rev') and opts.get('remove'):
6176 if opts.get('rev') and opts.get('remove'):
6177 raise util.Abort(_("--rev and --remove are incompatible"))
6177 raise util.Abort(_("--rev and --remove are incompatible"))
6178 if opts.get('rev'):
6178 if opts.get('rev'):
6179 rev_ = opts['rev']
6179 rev_ = opts['rev']
6180 message = opts.get('message')
6180 message = opts.get('message')
6181 if opts.get('remove'):
6181 if opts.get('remove'):
6182 if opts.get('local'):
6182 if opts.get('local'):
6183 expectedtype = 'local'
6183 expectedtype = 'local'
6184 else:
6184 else:
6185 expectedtype = 'global'
6185 expectedtype = 'global'
6186
6186
6187 for n in names:
6187 for n in names:
6188 if not repo.tagtype(n):
6188 if not repo.tagtype(n):
6189 raise util.Abort(_("tag '%s' does not exist") % n)
6189 raise util.Abort(_("tag '%s' does not exist") % n)
6190 if repo.tagtype(n) != expectedtype:
6190 if repo.tagtype(n) != expectedtype:
6191 if expectedtype == 'global':
6191 if expectedtype == 'global':
6192 raise util.Abort(_("tag '%s' is not a global tag") % n)
6192 raise util.Abort(_("tag '%s' is not a global tag") % n)
6193 else:
6193 else:
6194 raise util.Abort(_("tag '%s' is not a local tag") % n)
6194 raise util.Abort(_("tag '%s' is not a local tag") % n)
6195 rev_ = nullid
6195 rev_ = nullid
6196 if not message:
6196 if not message:
6197 # we don't translate commit messages
6197 # we don't translate commit messages
6198 message = 'Removed tag %s' % ', '.join(names)
6198 message = 'Removed tag %s' % ', '.join(names)
6199 elif not opts.get('force'):
6199 elif not opts.get('force'):
6200 for n in names:
6200 for n in names:
6201 if n in repo.tags():
6201 if n in repo.tags():
6202 raise util.Abort(_("tag '%s' already exists "
6202 raise util.Abort(_("tag '%s' already exists "
6203 "(use -f to force)") % n)
6203 "(use -f to force)") % n)
6204 if not opts.get('local'):
6204 if not opts.get('local'):
6205 p1, p2 = repo.dirstate.parents()
6205 p1, p2 = repo.dirstate.parents()
6206 if p2 != nullid:
6206 if p2 != nullid:
6207 raise util.Abort(_('uncommitted merge'))
6207 raise util.Abort(_('uncommitted merge'))
6208 bheads = repo.branchheads()
6208 bheads = repo.branchheads()
6209 if not opts.get('force') and bheads and p1 not in bheads:
6209 if not opts.get('force') and bheads and p1 not in bheads:
6210 raise util.Abort(_('not at a branch head (use -f to force)'))
6210 raise util.Abort(_('not at a branch head (use -f to force)'))
6211 r = scmutil.revsingle(repo, rev_).node()
6211 r = scmutil.revsingle(repo, rev_).node()
6212
6212
6213 if not message:
6213 if not message:
6214 # we don't translate commit messages
6214 # we don't translate commit messages
6215 message = ('Added tag %s for changeset %s' %
6215 message = ('Added tag %s for changeset %s' %
6216 (', '.join(names), short(r)))
6216 (', '.join(names), short(r)))
6217
6217
6218 date = opts.get('date')
6218 date = opts.get('date')
6219 if date:
6219 if date:
6220 date = util.parsedate(date)
6220 date = util.parsedate(date)
6221
6221
6222 if opts.get('remove'):
6222 if opts.get('remove'):
6223 editform = 'tag.remove'
6223 editform = 'tag.remove'
6224 else:
6224 else:
6225 editform = 'tag.add'
6225 editform = 'tag.add'
6226 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6226 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6227
6227
6228 # don't allow tagging the null rev
6228 # don't allow tagging the null rev
6229 if (not opts.get('remove') and
6229 if (not opts.get('remove') and
6230 scmutil.revsingle(repo, rev_).rev() == nullrev):
6230 scmutil.revsingle(repo, rev_).rev() == nullrev):
6231 raise util.Abort(_("cannot tag null revision"))
6231 raise util.Abort(_("cannot tag null revision"))
6232
6232
6233 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6233 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6234 editor=editor)
6234 editor=editor)
6235 finally:
6235 finally:
6236 release(lock, wlock)
6236 release(lock, wlock)
6237
6237
6238 @command('tags', formatteropts, '')
6238 @command('tags', formatteropts, '')
6239 def tags(ui, repo, **opts):
6239 def tags(ui, repo, **opts):
6240 """list repository tags
6240 """list repository tags
6241
6241
6242 This lists both regular and local tags. When the -v/--verbose
6242 This lists both regular and local tags. When the -v/--verbose
6243 switch is used, a third column "local" is printed for local tags.
6243 switch is used, a third column "local" is printed for local tags.
6244
6244
6245 Returns 0 on success.
6245 Returns 0 on success.
6246 """
6246 """
6247
6247
6248 fm = ui.formatter('tags', opts)
6248 fm = ui.formatter('tags', opts)
6249 hexfunc = fm.hexfunc
6249 hexfunc = fm.hexfunc
6250 tagtype = ""
6250 tagtype = ""
6251
6251
6252 for t, n in reversed(repo.tagslist()):
6252 for t, n in reversed(repo.tagslist()):
6253 hn = hexfunc(n)
6253 hn = hexfunc(n)
6254 label = 'tags.normal'
6254 label = 'tags.normal'
6255 tagtype = ''
6255 tagtype = ''
6256 if repo.tagtype(t) == 'local':
6256 if repo.tagtype(t) == 'local':
6257 label = 'tags.local'
6257 label = 'tags.local'
6258 tagtype = 'local'
6258 tagtype = 'local'
6259
6259
6260 fm.startitem()
6260 fm.startitem()
6261 fm.write('tag', '%s', t, label=label)
6261 fm.write('tag', '%s', t, label=label)
6262 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6262 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6263 fm.condwrite(not ui.quiet, 'rev node', fmt,
6263 fm.condwrite(not ui.quiet, 'rev node', fmt,
6264 repo.changelog.rev(n), hn, label=label)
6264 repo.changelog.rev(n), hn, label=label)
6265 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6265 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6266 tagtype, label=label)
6266 tagtype, label=label)
6267 fm.plain('\n')
6267 fm.plain('\n')
6268 fm.end()
6268 fm.end()
6269
6269
6270 @command('tip',
6270 @command('tip',
6271 [('p', 'patch', None, _('show patch')),
6271 [('p', 'patch', None, _('show patch')),
6272 ('g', 'git', None, _('use git extended diff format')),
6272 ('g', 'git', None, _('use git extended diff format')),
6273 ] + templateopts,
6273 ] + templateopts,
6274 _('[-p] [-g]'))
6274 _('[-p] [-g]'))
6275 def tip(ui, repo, **opts):
6275 def tip(ui, repo, **opts):
6276 """show the tip revision (DEPRECATED)
6276 """show the tip revision (DEPRECATED)
6277
6277
6278 The tip revision (usually just called the tip) is the changeset
6278 The tip revision (usually just called the tip) is the changeset
6279 most recently added to the repository (and therefore the most
6279 most recently added to the repository (and therefore the most
6280 recently changed head).
6280 recently changed head).
6281
6281
6282 If you have just made a commit, that commit will be the tip. If
6282 If you have just made a commit, that commit will be the tip. If
6283 you have just pulled changes from another repository, the tip of
6283 you have just pulled changes from another repository, the tip of
6284 that repository becomes the current tip. The "tip" tag is special
6284 that repository becomes the current tip. The "tip" tag is special
6285 and cannot be renamed or assigned to a different changeset.
6285 and cannot be renamed or assigned to a different changeset.
6286
6286
6287 This command is deprecated, please use :hg:`heads` instead.
6287 This command is deprecated, please use :hg:`heads` instead.
6288
6288
6289 Returns 0 on success.
6289 Returns 0 on success.
6290 """
6290 """
6291 displayer = cmdutil.show_changeset(ui, repo, opts)
6291 displayer = cmdutil.show_changeset(ui, repo, opts)
6292 displayer.show(repo['tip'])
6292 displayer.show(repo['tip'])
6293 displayer.close()
6293 displayer.close()
6294
6294
6295 @command('unbundle',
6295 @command('unbundle',
6296 [('u', 'update', None,
6296 [('u', 'update', None,
6297 _('update to new branch head if changesets were unbundled'))],
6297 _('update to new branch head if changesets were unbundled'))],
6298 _('[-u] FILE...'))
6298 _('[-u] FILE...'))
6299 def unbundle(ui, repo, fname1, *fnames, **opts):
6299 def unbundle(ui, repo, fname1, *fnames, **opts):
6300 """apply one or more changegroup files
6300 """apply one or more changegroup files
6301
6301
6302 Apply one or more compressed changegroup files generated by the
6302 Apply one or more compressed changegroup files generated by the
6303 bundle command.
6303 bundle command.
6304
6304
6305 Returns 0 on success, 1 if an update has unresolved files.
6305 Returns 0 on success, 1 if an update has unresolved files.
6306 """
6306 """
6307 fnames = (fname1,) + fnames
6307 fnames = (fname1,) + fnames
6308
6308
6309 lock = repo.lock()
6309 lock = repo.lock()
6310 try:
6310 try:
6311 for fname in fnames:
6311 for fname in fnames:
6312 f = hg.openpath(ui, fname)
6312 f = hg.openpath(ui, fname)
6313 gen = exchange.readbundle(ui, f, fname)
6313 gen = exchange.readbundle(ui, f, fname)
6314 if isinstance(gen, bundle2.unbundle20):
6314 if isinstance(gen, bundle2.unbundle20):
6315 tr = repo.transaction('unbundle')
6315 tr = repo.transaction('unbundle')
6316 try:
6316 try:
6317 op = bundle2.processbundle(repo, gen, lambda: tr)
6317 op = bundle2.processbundle(repo, gen, lambda: tr)
6318 tr.close()
6318 tr.close()
6319 finally:
6319 finally:
6320 if tr:
6320 if tr:
6321 tr.release()
6321 tr.release()
6322 changes = [r.get('result', 0)
6322 changes = [r.get('result', 0)
6323 for r in op.records['changegroup']]
6323 for r in op.records['changegroup']]
6324 modheads = changegroup.combineresults(changes)
6324 modheads = changegroup.combineresults(changes)
6325 else:
6325 else:
6326 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6326 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6327 'bundle:' + fname)
6327 'bundle:' + fname)
6328 finally:
6328 finally:
6329 lock.release()
6329 lock.release()
6330
6330
6331 return postincoming(ui, repo, modheads, opts.get('update'), None)
6331 return postincoming(ui, repo, modheads, opts.get('update'), None)
6332
6332
6333 @command('^update|up|checkout|co',
6333 @command('^update|up|checkout|co',
6334 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6334 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6335 ('c', 'check', None,
6335 ('c', 'check', None,
6336 _('update across branches if no uncommitted changes')),
6336 _('update across branches if no uncommitted changes')),
6337 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6337 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6338 ('r', 'rev', '', _('revision'), _('REV'))
6338 ('r', 'rev', '', _('revision'), _('REV'))
6339 ] + mergetoolopts,
6339 ] + mergetoolopts,
6340 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6340 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6341 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6341 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6342 tool=None):
6342 tool=None):
6343 """update working directory (or switch revisions)
6343 """update working directory (or switch revisions)
6344
6344
6345 Update the repository's working directory to the specified
6345 Update the repository's working directory to the specified
6346 changeset. If no changeset is specified, update to the tip of the
6346 changeset. If no changeset is specified, update to the tip of the
6347 current named branch and move the current bookmark (see :hg:`help
6347 current named branch and move the current bookmark (see :hg:`help
6348 bookmarks`).
6348 bookmarks`).
6349
6349
6350 Update sets the working directory's parent revision to the specified
6350 Update sets the working directory's parent revision to the specified
6351 changeset (see :hg:`help parents`).
6351 changeset (see :hg:`help parents`).
6352
6352
6353 If the changeset is not a descendant or ancestor of the working
6353 If the changeset is not a descendant or ancestor of the working
6354 directory's parent, the update is aborted. With the -c/--check
6354 directory's parent, the update is aborted. With the -c/--check
6355 option, the working directory is checked for uncommitted changes; if
6355 option, the working directory is checked for uncommitted changes; if
6356 none are found, the working directory is updated to the specified
6356 none are found, the working directory is updated to the specified
6357 changeset.
6357 changeset.
6358
6358
6359 .. container:: verbose
6359 .. container:: verbose
6360
6360
6361 The following rules apply when the working directory contains
6361 The following rules apply when the working directory contains
6362 uncommitted changes:
6362 uncommitted changes:
6363
6363
6364 1. If neither -c/--check nor -C/--clean is specified, and if
6364 1. If neither -c/--check nor -C/--clean is specified, and if
6365 the requested changeset is an ancestor or descendant of
6365 the requested changeset is an ancestor or descendant of
6366 the working directory's parent, the uncommitted changes
6366 the working directory's parent, the uncommitted changes
6367 are merged into the requested changeset and the merged
6367 are merged into the requested changeset and the merged
6368 result is left uncommitted. If the requested changeset is
6368 result is left uncommitted. If the requested changeset is
6369 not an ancestor or descendant (that is, it is on another
6369 not an ancestor or descendant (that is, it is on another
6370 branch), the update is aborted and the uncommitted changes
6370 branch), the update is aborted and the uncommitted changes
6371 are preserved.
6371 are preserved.
6372
6372
6373 2. With the -c/--check option, the update is aborted and the
6373 2. With the -c/--check option, the update is aborted and the
6374 uncommitted changes are preserved.
6374 uncommitted changes are preserved.
6375
6375
6376 3. With the -C/--clean option, uncommitted changes are discarded and
6376 3. With the -C/--clean option, uncommitted changes are discarded and
6377 the working directory is updated to the requested changeset.
6377 the working directory is updated to the requested changeset.
6378
6378
6379 To cancel an uncommitted merge (and lose your changes), use
6379 To cancel an uncommitted merge (and lose your changes), use
6380 :hg:`update --clean .`.
6380 :hg:`update --clean .`.
6381
6381
6382 Use null as the changeset to remove the working directory (like
6382 Use null as the changeset to remove the working directory (like
6383 :hg:`clone -U`).
6383 :hg:`clone -U`).
6384
6384
6385 If you want to revert just one file to an older revision, use
6385 If you want to revert just one file to an older revision, use
6386 :hg:`revert [-r REV] NAME`.
6386 :hg:`revert [-r REV] NAME`.
6387
6387
6388 See :hg:`help dates` for a list of formats valid for -d/--date.
6388 See :hg:`help dates` for a list of formats valid for -d/--date.
6389
6389
6390 Returns 0 on success, 1 if there are unresolved files.
6390 Returns 0 on success, 1 if there are unresolved files.
6391 """
6391 """
6392 if rev and node:
6392 if rev and node:
6393 raise util.Abort(_("please specify just one revision"))
6393 raise util.Abort(_("please specify just one revision"))
6394
6394
6395 if rev is None or rev == '':
6395 if rev is None or rev == '':
6396 rev = node
6396 rev = node
6397
6397
6398 cmdutil.clearunfinished(repo)
6398 cmdutil.clearunfinished(repo)
6399
6399
6400 # with no argument, we also move the current bookmark, if any
6400 # with no argument, we also move the current bookmark, if any
6401 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6401 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6402
6402
6403 # if we defined a bookmark, we have to remember the original bookmark name
6403 # if we defined a bookmark, we have to remember the original bookmark name
6404 brev = rev
6404 brev = rev
6405 rev = scmutil.revsingle(repo, rev, rev).rev()
6405 rev = scmutil.revsingle(repo, rev, rev).rev()
6406
6406
6407 if check and clean:
6407 if check and clean:
6408 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6408 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6409
6409
6410 if date:
6410 if date:
6411 if rev is not None:
6411 if rev is not None:
6412 raise util.Abort(_("you can't specify a revision and a date"))
6412 raise util.Abort(_("you can't specify a revision and a date"))
6413 rev = cmdutil.finddate(ui, repo, date)
6413 rev = cmdutil.finddate(ui, repo, date)
6414
6414
6415 if check:
6415 if check:
6416 cmdutil.bailifchanged(repo, merge=False)
6416 cmdutil.bailifchanged(repo, merge=False)
6417 if rev is None:
6417 if rev is None:
6418 rev = repo[repo[None].branch()].rev()
6418 rev = repo[repo[None].branch()].rev()
6419
6419
6420 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6420 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6421
6421
6422 if clean:
6422 if clean:
6423 ret = hg.clean(repo, rev)
6423 ret = hg.clean(repo, rev)
6424 else:
6424 else:
6425 ret = hg.update(repo, rev)
6425 ret = hg.update(repo, rev)
6426
6426
6427 if not ret and movemarkfrom:
6427 if not ret and movemarkfrom:
6428 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6428 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6429 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6429 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6430 elif brev in repo._bookmarks:
6430 elif brev in repo._bookmarks:
6431 bookmarks.activate(repo, brev)
6431 bookmarks.activate(repo, brev)
6432 ui.status(_("(activating bookmark %s)\n") % brev)
6432 ui.status(_("(activating bookmark %s)\n") % brev)
6433 elif brev:
6433 elif brev:
6434 if repo._activebookmark:
6434 if repo._activebookmark:
6435 ui.status(_("(leaving bookmark %s)\n") %
6435 ui.status(_("(leaving bookmark %s)\n") %
6436 repo._activebookmark)
6436 repo._activebookmark)
6437 bookmarks.deactivate(repo)
6437 bookmarks.deactivate(repo)
6438
6438
6439 return ret
6439 return ret
6440
6440
6441 @command('verify', [])
6441 @command('verify', [])
6442 def verify(ui, repo):
6442 def verify(ui, repo):
6443 """verify the integrity of the repository
6443 """verify the integrity of the repository
6444
6444
6445 Verify the integrity of the current repository.
6445 Verify the integrity of the current repository.
6446
6446
6447 This will perform an extensive check of the repository's
6447 This will perform an extensive check of the repository's
6448 integrity, validating the hashes and checksums of each entry in
6448 integrity, validating the hashes and checksums of each entry in
6449 the changelog, manifest, and tracked files, as well as the
6449 the changelog, manifest, and tracked files, as well as the
6450 integrity of their crosslinks and indices.
6450 integrity of their crosslinks and indices.
6451
6451
6452 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6452 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6453 for more information about recovery from corruption of the
6453 for more information about recovery from corruption of the
6454 repository.
6454 repository.
6455
6455
6456 Returns 0 on success, 1 if errors are encountered.
6456 Returns 0 on success, 1 if errors are encountered.
6457 """
6457 """
6458 return hg.verify(repo)
6458 return hg.verify(repo)
6459
6459
6460 @command('version', [], norepo=True)
6460 @command('version', [], norepo=True)
6461 def version_(ui):
6461 def version_(ui):
6462 """output version and copyright information"""
6462 """output version and copyright information"""
6463 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6463 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6464 % util.version())
6464 % util.version())
6465 ui.status(_(
6465 ui.status(_(
6466 "(see http://mercurial.selenic.com for more information)\n"
6466 "(see http://mercurial.selenic.com for more information)\n"
6467 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6467 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6468 "This is free software; see the source for copying conditions. "
6468 "This is free software; see the source for copying conditions. "
6469 "There is NO\nwarranty; "
6469 "There is NO\nwarranty; "
6470 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6470 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6471 ))
6471 ))
6472
6472
6473 ui.note(_("\nEnabled extensions:\n\n"))
6473 ui.note(_("\nEnabled extensions:\n\n"))
6474 if ui.verbose:
6474 if ui.verbose:
6475 # format names and versions into columns
6475 # format names and versions into columns
6476 names = []
6476 names = []
6477 vers = []
6477 vers = []
6478 for name, module in extensions.extensions():
6478 for name, module in extensions.extensions():
6479 names.append(name)
6479 names.append(name)
6480 vers.append(extensions.moduleversion(module))
6480 vers.append(extensions.moduleversion(module))
6481 if names:
6481 if names:
6482 maxnamelen = max(len(n) for n in names)
6482 maxnamelen = max(len(n) for n in names)
6483 for i, name in enumerate(names):
6483 for i, name in enumerate(names):
6484 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6484 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,520 +1,521 b''
1 # fileset.py - file set queries for mercurial
1 # fileset.py - file 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, error, util, merge
9 import parser, error, util, merge
10 from i18n import _
10 from i18n import _
11
11
12 elements = {
12 elements = {
13 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
13 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
14 "-": (5, ("negate", 19), ("minus", 5)),
14 "-": (5, ("negate", 19), ("minus", 5)),
15 "not": (10, ("not", 10)),
15 "not": (10, ("not", 10)),
16 "!": (10, ("not", 10)),
16 "!": (10, ("not", 10)),
17 "and": (5, None, ("and", 5)),
17 "and": (5, None, ("and", 5)),
18 "&": (5, None, ("and", 5)),
18 "&": (5, None, ("and", 5)),
19 "or": (4, None, ("or", 4)),
19 "or": (4, None, ("or", 4)),
20 "|": (4, None, ("or", 4)),
20 "|": (4, None, ("or", 4)),
21 "+": (4, None, ("or", 4)),
21 "+": (4, None, ("or", 4)),
22 ",": (2, None, ("list", 2)),
22 ",": (2, None, ("list", 2)),
23 ")": (0, None, None),
23 ")": (0, None, None),
24 "symbol": (0, ("symbol",), None),
24 "symbol": (0, ("symbol",), None),
25 "string": (0, ("string",), None),
25 "string": (0, ("string",), None),
26 "end": (0, None, None),
26 "end": (0, None, None),
27 }
27 }
28
28
29 keywords = set(['and', 'or', 'not'])
29 keywords = set(['and', 'or', 'not'])
30
30
31 globchars = ".*{}[]?/\\_"
31 globchars = ".*{}[]?/\\_"
32
32
33 def tokenize(program):
33 def tokenize(program):
34 pos, l = 0, len(program)
34 pos, l = 0, len(program)
35 while pos < l:
35 while pos < l:
36 c = program[pos]
36 c = program[pos]
37 if c.isspace(): # skip inter-token whitespace
37 if c.isspace(): # skip inter-token whitespace
38 pass
38 pass
39 elif c in "(),-|&+!": # handle simple operators
39 elif c in "(),-|&+!": # handle simple operators
40 yield (c, None, pos)
40 yield (c, None, pos)
41 elif (c in '"\'' or c == 'r' and
41 elif (c in '"\'' or c == 'r' and
42 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
42 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
43 if c == 'r':
43 if c == 'r':
44 pos += 1
44 pos += 1
45 c = program[pos]
45 c = program[pos]
46 decode = lambda x: x
46 decode = lambda x: x
47 else:
47 else:
48 decode = lambda x: x.decode('string-escape')
48 decode = lambda x: x.decode('string-escape')
49 pos += 1
49 pos += 1
50 s = pos
50 s = pos
51 while pos < l: # find closing quote
51 while pos < l: # find closing quote
52 d = program[pos]
52 d = program[pos]
53 if d == '\\': # skip over escaped characters
53 if d == '\\': # skip over escaped characters
54 pos += 2
54 pos += 2
55 continue
55 continue
56 if d == c:
56 if d == c:
57 yield ('string', decode(program[s:pos]), s)
57 yield ('string', decode(program[s:pos]), s)
58 break
58 break
59 pos += 1
59 pos += 1
60 else:
60 else:
61 raise error.ParseError(_("unterminated string"), s)
61 raise error.ParseError(_("unterminated string"), s)
62 elif c.isalnum() or c in globchars or ord(c) > 127:
62 elif c.isalnum() or c in globchars or ord(c) > 127:
63 # gather up a symbol/keyword
63 # gather up a symbol/keyword
64 s = pos
64 s = pos
65 pos += 1
65 pos += 1
66 while pos < l: # find end of symbol
66 while pos < l: # find end of symbol
67 d = program[pos]
67 d = program[pos]
68 if not (d.isalnum() or d in globchars or ord(d) > 127):
68 if not (d.isalnum() or d in globchars or ord(d) > 127):
69 break
69 break
70 pos += 1
70 pos += 1
71 sym = program[s:pos]
71 sym = program[s:pos]
72 if sym in keywords: # operator keywords
72 if sym in keywords: # operator keywords
73 yield (sym, None, s)
73 yield (sym, None, s)
74 else:
74 else:
75 yield ('symbol', sym, s)
75 yield ('symbol', sym, s)
76 pos -= 1
76 pos -= 1
77 else:
77 else:
78 raise error.ParseError(_("syntax error"), pos)
78 raise error.ParseError(_("syntax error"), pos)
79 pos += 1
79 pos += 1
80 yield ('end', None, pos)
80 yield ('end', None, pos)
81
81
82 def parse(expr):
82 def parse(expr):
83 p = parser.parser(tokenize, elements)
83 p = parser.parser(tokenize, elements)
84 return p.parse(expr)
84 tree, pos = p.parse(expr)
85 if pos != len(expr):
86 raise error.ParseError(_("invalid token"), pos)
87 return tree
85
88
86 def getstring(x, err):
89 def getstring(x, err):
87 if x and (x[0] == 'string' or x[0] == 'symbol'):
90 if x and (x[0] == 'string' or x[0] == 'symbol'):
88 return x[1]
91 return x[1]
89 raise error.ParseError(err)
92 raise error.ParseError(err)
90
93
91 def getset(mctx, x):
94 def getset(mctx, x):
92 if not x:
95 if not x:
93 raise error.ParseError(_("missing argument"))
96 raise error.ParseError(_("missing argument"))
94 return methods[x[0]](mctx, *x[1:])
97 return methods[x[0]](mctx, *x[1:])
95
98
96 def stringset(mctx, x):
99 def stringset(mctx, x):
97 m = mctx.matcher([x])
100 m = mctx.matcher([x])
98 return [f for f in mctx.subset if m(f)]
101 return [f for f in mctx.subset if m(f)]
99
102
100 def andset(mctx, x, y):
103 def andset(mctx, x, y):
101 return getset(mctx.narrow(getset(mctx, x)), y)
104 return getset(mctx.narrow(getset(mctx, x)), y)
102
105
103 def orset(mctx, x, y):
106 def orset(mctx, x, y):
104 # needs optimizing
107 # needs optimizing
105 xl = getset(mctx, x)
108 xl = getset(mctx, x)
106 yl = getset(mctx, y)
109 yl = getset(mctx, y)
107 return xl + [f for f in yl if f not in xl]
110 return xl + [f for f in yl if f not in xl]
108
111
109 def notset(mctx, x):
112 def notset(mctx, x):
110 s = set(getset(mctx, x))
113 s = set(getset(mctx, x))
111 return [r for r in mctx.subset if r not in s]
114 return [r for r in mctx.subset if r not in s]
112
115
113 def minusset(mctx, x, y):
116 def minusset(mctx, x, y):
114 xl = getset(mctx, x)
117 xl = getset(mctx, x)
115 yl = set(getset(mctx, y))
118 yl = set(getset(mctx, y))
116 return [f for f in xl if f not in yl]
119 return [f for f in xl if f not in yl]
117
120
118 def listset(mctx, a, b):
121 def listset(mctx, a, b):
119 raise error.ParseError(_("can't use a list in this context"))
122 raise error.ParseError(_("can't use a list in this context"))
120
123
121 def modified(mctx, x):
124 def modified(mctx, x):
122 """``modified()``
125 """``modified()``
123 File that is modified according to status.
126 File that is modified according to status.
124 """
127 """
125 # i18n: "modified" is a keyword
128 # i18n: "modified" is a keyword
126 getargs(x, 0, 0, _("modified takes no arguments"))
129 getargs(x, 0, 0, _("modified takes no arguments"))
127 s = mctx.status().modified
130 s = mctx.status().modified
128 return [f for f in mctx.subset if f in s]
131 return [f for f in mctx.subset if f in s]
129
132
130 def added(mctx, x):
133 def added(mctx, x):
131 """``added()``
134 """``added()``
132 File that is added according to status.
135 File that is added according to status.
133 """
136 """
134 # i18n: "added" is a keyword
137 # i18n: "added" is a keyword
135 getargs(x, 0, 0, _("added takes no arguments"))
138 getargs(x, 0, 0, _("added takes no arguments"))
136 s = mctx.status().added
139 s = mctx.status().added
137 return [f for f in mctx.subset if f in s]
140 return [f for f in mctx.subset if f in s]
138
141
139 def removed(mctx, x):
142 def removed(mctx, x):
140 """``removed()``
143 """``removed()``
141 File that is removed according to status.
144 File that is removed according to status.
142 """
145 """
143 # i18n: "removed" is a keyword
146 # i18n: "removed" is a keyword
144 getargs(x, 0, 0, _("removed takes no arguments"))
147 getargs(x, 0, 0, _("removed takes no arguments"))
145 s = mctx.status().removed
148 s = mctx.status().removed
146 return [f for f in mctx.subset if f in s]
149 return [f for f in mctx.subset if f in s]
147
150
148 def deleted(mctx, x):
151 def deleted(mctx, x):
149 """``deleted()``
152 """``deleted()``
150 File that is deleted according to status.
153 File that is deleted according to status.
151 """
154 """
152 # i18n: "deleted" is a keyword
155 # i18n: "deleted" is a keyword
153 getargs(x, 0, 0, _("deleted takes no arguments"))
156 getargs(x, 0, 0, _("deleted takes no arguments"))
154 s = mctx.status().deleted
157 s = mctx.status().deleted
155 return [f for f in mctx.subset if f in s]
158 return [f for f in mctx.subset if f in s]
156
159
157 def unknown(mctx, x):
160 def unknown(mctx, x):
158 """``unknown()``
161 """``unknown()``
159 File that is unknown according to status. These files will only be
162 File that is unknown according to status. These files will only be
160 considered if this predicate is used.
163 considered if this predicate is used.
161 """
164 """
162 # i18n: "unknown" is a keyword
165 # i18n: "unknown" is a keyword
163 getargs(x, 0, 0, _("unknown takes no arguments"))
166 getargs(x, 0, 0, _("unknown takes no arguments"))
164 s = mctx.status().unknown
167 s = mctx.status().unknown
165 return [f for f in mctx.subset if f in s]
168 return [f for f in mctx.subset if f in s]
166
169
167 def ignored(mctx, x):
170 def ignored(mctx, x):
168 """``ignored()``
171 """``ignored()``
169 File that is ignored according to status. These files will only be
172 File that is ignored according to status. These files will only be
170 considered if this predicate is used.
173 considered if this predicate is used.
171 """
174 """
172 # i18n: "ignored" is a keyword
175 # i18n: "ignored" is a keyword
173 getargs(x, 0, 0, _("ignored takes no arguments"))
176 getargs(x, 0, 0, _("ignored takes no arguments"))
174 s = mctx.status().ignored
177 s = mctx.status().ignored
175 return [f for f in mctx.subset if f in s]
178 return [f for f in mctx.subset if f in s]
176
179
177 def clean(mctx, x):
180 def clean(mctx, x):
178 """``clean()``
181 """``clean()``
179 File that is clean according to status.
182 File that is clean according to status.
180 """
183 """
181 # i18n: "clean" is a keyword
184 # i18n: "clean" is a keyword
182 getargs(x, 0, 0, _("clean takes no arguments"))
185 getargs(x, 0, 0, _("clean takes no arguments"))
183 s = mctx.status().clean
186 s = mctx.status().clean
184 return [f for f in mctx.subset if f in s]
187 return [f for f in mctx.subset if f in s]
185
188
186 def func(mctx, a, b):
189 def func(mctx, a, b):
187 if a[0] == 'symbol' and a[1] in symbols:
190 if a[0] == 'symbol' and a[1] in symbols:
188 return symbols[a[1]](mctx, b)
191 return symbols[a[1]](mctx, b)
189 raise error.UnknownIdentifier(a[1], symbols.keys())
192 raise error.UnknownIdentifier(a[1], symbols.keys())
190
193
191 def getlist(x):
194 def getlist(x):
192 if not x:
195 if not x:
193 return []
196 return []
194 if x[0] == 'list':
197 if x[0] == 'list':
195 return getlist(x[1]) + [x[2]]
198 return getlist(x[1]) + [x[2]]
196 return [x]
199 return [x]
197
200
198 def getargs(x, min, max, err):
201 def getargs(x, min, max, err):
199 l = getlist(x)
202 l = getlist(x)
200 if len(l) < min or len(l) > max:
203 if len(l) < min or len(l) > max:
201 raise error.ParseError(err)
204 raise error.ParseError(err)
202 return l
205 return l
203
206
204 def binary(mctx, x):
207 def binary(mctx, x):
205 """``binary()``
208 """``binary()``
206 File that appears to be binary (contains NUL bytes).
209 File that appears to be binary (contains NUL bytes).
207 """
210 """
208 # i18n: "binary" is a keyword
211 # i18n: "binary" is a keyword
209 getargs(x, 0, 0, _("binary takes no arguments"))
212 getargs(x, 0, 0, _("binary takes no arguments"))
210 return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
213 return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
211
214
212 def exec_(mctx, x):
215 def exec_(mctx, x):
213 """``exec()``
216 """``exec()``
214 File that is marked as executable.
217 File that is marked as executable.
215 """
218 """
216 # i18n: "exec" is a keyword
219 # i18n: "exec" is a keyword
217 getargs(x, 0, 0, _("exec takes no arguments"))
220 getargs(x, 0, 0, _("exec takes no arguments"))
218 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
221 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
219
222
220 def symlink(mctx, x):
223 def symlink(mctx, x):
221 """``symlink()``
224 """``symlink()``
222 File that is marked as a symlink.
225 File that is marked as a symlink.
223 """
226 """
224 # i18n: "symlink" is a keyword
227 # i18n: "symlink" is a keyword
225 getargs(x, 0, 0, _("symlink takes no arguments"))
228 getargs(x, 0, 0, _("symlink takes no arguments"))
226 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
229 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
227
230
228 def resolved(mctx, x):
231 def resolved(mctx, x):
229 """``resolved()``
232 """``resolved()``
230 File that is marked resolved according to the resolve state.
233 File that is marked resolved according to the resolve state.
231 """
234 """
232 # i18n: "resolved" is a keyword
235 # i18n: "resolved" is a keyword
233 getargs(x, 0, 0, _("resolved takes no arguments"))
236 getargs(x, 0, 0, _("resolved takes no arguments"))
234 if mctx.ctx.rev() is not None:
237 if mctx.ctx.rev() is not None:
235 return []
238 return []
236 ms = merge.mergestate(mctx.ctx.repo())
239 ms = merge.mergestate(mctx.ctx.repo())
237 return [f for f in mctx.subset if f in ms and ms[f] == 'r']
240 return [f for f in mctx.subset if f in ms and ms[f] == 'r']
238
241
239 def unresolved(mctx, x):
242 def unresolved(mctx, x):
240 """``unresolved()``
243 """``unresolved()``
241 File that is marked unresolved according to the resolve state.
244 File that is marked unresolved according to the resolve state.
242 """
245 """
243 # i18n: "unresolved" is a keyword
246 # i18n: "unresolved" is a keyword
244 getargs(x, 0, 0, _("unresolved takes no arguments"))
247 getargs(x, 0, 0, _("unresolved takes no arguments"))
245 if mctx.ctx.rev() is not None:
248 if mctx.ctx.rev() is not None:
246 return []
249 return []
247 ms = merge.mergestate(mctx.ctx.repo())
250 ms = merge.mergestate(mctx.ctx.repo())
248 return [f for f in mctx.subset if f in ms and ms[f] == 'u']
251 return [f for f in mctx.subset if f in ms and ms[f] == 'u']
249
252
250 def hgignore(mctx, x):
253 def hgignore(mctx, x):
251 """``hgignore()``
254 """``hgignore()``
252 File that matches the active .hgignore pattern.
255 File that matches the active .hgignore pattern.
253 """
256 """
254 # i18n: "hgignore" is a keyword
257 # i18n: "hgignore" is a keyword
255 getargs(x, 0, 0, _("hgignore takes no arguments"))
258 getargs(x, 0, 0, _("hgignore takes no arguments"))
256 ignore = mctx.ctx.repo().dirstate._ignore
259 ignore = mctx.ctx.repo().dirstate._ignore
257 return [f for f in mctx.subset if ignore(f)]
260 return [f for f in mctx.subset if ignore(f)]
258
261
259 def portable(mctx, x):
262 def portable(mctx, x):
260 """``portable()``
263 """``portable()``
261 File that has a portable name. (This doesn't include filenames with case
264 File that has a portable name. (This doesn't include filenames with case
262 collisions.)
265 collisions.)
263 """
266 """
264 # i18n: "portable" is a keyword
267 # i18n: "portable" is a keyword
265 getargs(x, 0, 0, _("portable takes no arguments"))
268 getargs(x, 0, 0, _("portable takes no arguments"))
266 checkwinfilename = util.checkwinfilename
269 checkwinfilename = util.checkwinfilename
267 return [f for f in mctx.subset if checkwinfilename(f) is None]
270 return [f for f in mctx.subset if checkwinfilename(f) is None]
268
271
269 def grep(mctx, x):
272 def grep(mctx, x):
270 """``grep(regex)``
273 """``grep(regex)``
271 File contains the given regular expression.
274 File contains the given regular expression.
272 """
275 """
273 try:
276 try:
274 # i18n: "grep" is a keyword
277 # i18n: "grep" is a keyword
275 r = re.compile(getstring(x, _("grep requires a pattern")))
278 r = re.compile(getstring(x, _("grep requires a pattern")))
276 except re.error, e:
279 except re.error, e:
277 raise error.ParseError(_('invalid match pattern: %s') % e)
280 raise error.ParseError(_('invalid match pattern: %s') % e)
278 return [f for f in mctx.existing() if r.search(mctx.ctx[f].data())]
281 return [f for f in mctx.existing() if r.search(mctx.ctx[f].data())]
279
282
280 def _sizetomax(s):
283 def _sizetomax(s):
281 try:
284 try:
282 s = s.strip()
285 s = s.strip()
283 for k, v in util._sizeunits:
286 for k, v in util._sizeunits:
284 if s.endswith(k):
287 if s.endswith(k):
285 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
288 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
286 n = s[:-len(k)]
289 n = s[:-len(k)]
287 inc = 1.0
290 inc = 1.0
288 if "." in n:
291 if "." in n:
289 inc /= 10 ** len(n.split(".")[1])
292 inc /= 10 ** len(n.split(".")[1])
290 return int((float(n) + inc) * v) - 1
293 return int((float(n) + inc) * v) - 1
291 # no extension, this is a precise value
294 # no extension, this is a precise value
292 return int(s)
295 return int(s)
293 except ValueError:
296 except ValueError:
294 raise error.ParseError(_("couldn't parse size: %s") % s)
297 raise error.ParseError(_("couldn't parse size: %s") % s)
295
298
296 def size(mctx, x):
299 def size(mctx, x):
297 """``size(expression)``
300 """``size(expression)``
298 File size matches the given expression. Examples:
301 File size matches the given expression. Examples:
299
302
300 - 1k (files from 1024 to 2047 bytes)
303 - 1k (files from 1024 to 2047 bytes)
301 - < 20k (files less than 20480 bytes)
304 - < 20k (files less than 20480 bytes)
302 - >= .5MB (files at least 524288 bytes)
305 - >= .5MB (files at least 524288 bytes)
303 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
306 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
304 """
307 """
305
308
306 # i18n: "size" is a keyword
309 # i18n: "size" is a keyword
307 expr = getstring(x, _("size requires an expression")).strip()
310 expr = getstring(x, _("size requires an expression")).strip()
308 if '-' in expr: # do we have a range?
311 if '-' in expr: # do we have a range?
309 a, b = expr.split('-', 1)
312 a, b = expr.split('-', 1)
310 a = util.sizetoint(a)
313 a = util.sizetoint(a)
311 b = util.sizetoint(b)
314 b = util.sizetoint(b)
312 m = lambda x: x >= a and x <= b
315 m = lambda x: x >= a and x <= b
313 elif expr.startswith("<="):
316 elif expr.startswith("<="):
314 a = util.sizetoint(expr[2:])
317 a = util.sizetoint(expr[2:])
315 m = lambda x: x <= a
318 m = lambda x: x <= a
316 elif expr.startswith("<"):
319 elif expr.startswith("<"):
317 a = util.sizetoint(expr[1:])
320 a = util.sizetoint(expr[1:])
318 m = lambda x: x < a
321 m = lambda x: x < a
319 elif expr.startswith(">="):
322 elif expr.startswith(">="):
320 a = util.sizetoint(expr[2:])
323 a = util.sizetoint(expr[2:])
321 m = lambda x: x >= a
324 m = lambda x: x >= a
322 elif expr.startswith(">"):
325 elif expr.startswith(">"):
323 a = util.sizetoint(expr[1:])
326 a = util.sizetoint(expr[1:])
324 m = lambda x: x > a
327 m = lambda x: x > a
325 elif expr[0].isdigit or expr[0] == '.':
328 elif expr[0].isdigit or expr[0] == '.':
326 a = util.sizetoint(expr)
329 a = util.sizetoint(expr)
327 b = _sizetomax(expr)
330 b = _sizetomax(expr)
328 m = lambda x: x >= a and x <= b
331 m = lambda x: x >= a and x <= b
329 else:
332 else:
330 raise error.ParseError(_("couldn't parse size: %s") % expr)
333 raise error.ParseError(_("couldn't parse size: %s") % expr)
331
334
332 return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
335 return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
333
336
334 def encoding(mctx, x):
337 def encoding(mctx, x):
335 """``encoding(name)``
338 """``encoding(name)``
336 File can be successfully decoded with the given character
339 File can be successfully decoded with the given character
337 encoding. May not be useful for encodings other than ASCII and
340 encoding. May not be useful for encodings other than ASCII and
338 UTF-8.
341 UTF-8.
339 """
342 """
340
343
341 # i18n: "encoding" is a keyword
344 # i18n: "encoding" is a keyword
342 enc = getstring(x, _("encoding requires an encoding name"))
345 enc = getstring(x, _("encoding requires an encoding name"))
343
346
344 s = []
347 s = []
345 for f in mctx.existing():
348 for f in mctx.existing():
346 d = mctx.ctx[f].data()
349 d = mctx.ctx[f].data()
347 try:
350 try:
348 d.decode(enc)
351 d.decode(enc)
349 except LookupError:
352 except LookupError:
350 raise util.Abort(_("unknown encoding '%s'") % enc)
353 raise util.Abort(_("unknown encoding '%s'") % enc)
351 except UnicodeDecodeError:
354 except UnicodeDecodeError:
352 continue
355 continue
353 s.append(f)
356 s.append(f)
354
357
355 return s
358 return s
356
359
357 def eol(mctx, x):
360 def eol(mctx, x):
358 """``eol(style)``
361 """``eol(style)``
359 File contains newlines of the given style (dos, unix, mac). Binary
362 File contains newlines of the given style (dos, unix, mac). Binary
360 files are excluded, files with mixed line endings match multiple
363 files are excluded, files with mixed line endings match multiple
361 styles.
364 styles.
362 """
365 """
363
366
364 # i18n: "encoding" is a keyword
367 # i18n: "encoding" is a keyword
365 enc = getstring(x, _("encoding requires an encoding name"))
368 enc = getstring(x, _("encoding requires an encoding name"))
366
369
367 s = []
370 s = []
368 for f in mctx.existing():
371 for f in mctx.existing():
369 d = mctx.ctx[f].data()
372 d = mctx.ctx[f].data()
370 if util.binary(d):
373 if util.binary(d):
371 continue
374 continue
372 if (enc == 'dos' or enc == 'win') and '\r\n' in d:
375 if (enc == 'dos' or enc == 'win') and '\r\n' in d:
373 s.append(f)
376 s.append(f)
374 elif enc == 'unix' and re.search('(?<!\r)\n', d):
377 elif enc == 'unix' and re.search('(?<!\r)\n', d):
375 s.append(f)
378 s.append(f)
376 elif enc == 'mac' and re.search('\r(?!\n)', d):
379 elif enc == 'mac' and re.search('\r(?!\n)', d):
377 s.append(f)
380 s.append(f)
378 return s
381 return s
379
382
380 def copied(mctx, x):
383 def copied(mctx, x):
381 """``copied()``
384 """``copied()``
382 File that is recorded as being copied.
385 File that is recorded as being copied.
383 """
386 """
384 # i18n: "copied" is a keyword
387 # i18n: "copied" is a keyword
385 getargs(x, 0, 0, _("copied takes no arguments"))
388 getargs(x, 0, 0, _("copied takes no arguments"))
386 s = []
389 s = []
387 for f in mctx.subset:
390 for f in mctx.subset:
388 p = mctx.ctx[f].parents()
391 p = mctx.ctx[f].parents()
389 if p and p[0].path() != f:
392 if p and p[0].path() != f:
390 s.append(f)
393 s.append(f)
391 return s
394 return s
392
395
393 def subrepo(mctx, x):
396 def subrepo(mctx, x):
394 """``subrepo([pattern])``
397 """``subrepo([pattern])``
395 Subrepositories whose paths match the given pattern.
398 Subrepositories whose paths match the given pattern.
396 """
399 """
397 # i18n: "subrepo" is a keyword
400 # i18n: "subrepo" is a keyword
398 getargs(x, 0, 1, _("subrepo takes at most one argument"))
401 getargs(x, 0, 1, _("subrepo takes at most one argument"))
399 ctx = mctx.ctx
402 ctx = mctx.ctx
400 sstate = sorted(ctx.substate)
403 sstate = sorted(ctx.substate)
401 if x:
404 if x:
402 # i18n: "subrepo" is a keyword
405 # i18n: "subrepo" is a keyword
403 pat = getstring(x, _("subrepo requires a pattern or no arguments"))
406 pat = getstring(x, _("subrepo requires a pattern or no arguments"))
404
407
405 import match as matchmod # avoid circular import issues
408 import match as matchmod # avoid circular import issues
406 fast = not matchmod.patkind(pat)
409 fast = not matchmod.patkind(pat)
407 if fast:
410 if fast:
408 def m(s):
411 def m(s):
409 return (s == pat)
412 return (s == pat)
410 else:
413 else:
411 m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
414 m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
412 return [sub for sub in sstate if m(sub)]
415 return [sub for sub in sstate if m(sub)]
413 else:
416 else:
414 return [sub for sub in sstate]
417 return [sub for sub in sstate]
415
418
416 symbols = {
419 symbols = {
417 'added': added,
420 'added': added,
418 'binary': binary,
421 'binary': binary,
419 'clean': clean,
422 'clean': clean,
420 'copied': copied,
423 'copied': copied,
421 'deleted': deleted,
424 'deleted': deleted,
422 'encoding': encoding,
425 'encoding': encoding,
423 'eol': eol,
426 'eol': eol,
424 'exec': exec_,
427 'exec': exec_,
425 'grep': grep,
428 'grep': grep,
426 'ignored': ignored,
429 'ignored': ignored,
427 'hgignore': hgignore,
430 'hgignore': hgignore,
428 'modified': modified,
431 'modified': modified,
429 'portable': portable,
432 'portable': portable,
430 'removed': removed,
433 'removed': removed,
431 'resolved': resolved,
434 'resolved': resolved,
432 'size': size,
435 'size': size,
433 'symlink': symlink,
436 'symlink': symlink,
434 'unknown': unknown,
437 'unknown': unknown,
435 'unresolved': unresolved,
438 'unresolved': unresolved,
436 'subrepo': subrepo,
439 'subrepo': subrepo,
437 }
440 }
438
441
439 methods = {
442 methods = {
440 'string': stringset,
443 'string': stringset,
441 'symbol': stringset,
444 'symbol': stringset,
442 'and': andset,
445 'and': andset,
443 'or': orset,
446 'or': orset,
444 'minus': minusset,
447 'minus': minusset,
445 'list': listset,
448 'list': listset,
446 'group': getset,
449 'group': getset,
447 'not': notset,
450 'not': notset,
448 'func': func,
451 'func': func,
449 }
452 }
450
453
451 class matchctx(object):
454 class matchctx(object):
452 def __init__(self, ctx, subset=None, status=None):
455 def __init__(self, ctx, subset=None, status=None):
453 self.ctx = ctx
456 self.ctx = ctx
454 self.subset = subset
457 self.subset = subset
455 self._status = status
458 self._status = status
456 def status(self):
459 def status(self):
457 return self._status
460 return self._status
458 def matcher(self, patterns):
461 def matcher(self, patterns):
459 return self.ctx.match(patterns)
462 return self.ctx.match(patterns)
460 def filter(self, files):
463 def filter(self, files):
461 return [f for f in files if f in self.subset]
464 return [f for f in files if f in self.subset]
462 def existing(self):
465 def existing(self):
463 if self._status is not None:
466 if self._status is not None:
464 removed = set(self._status[3])
467 removed = set(self._status[3])
465 unknown = set(self._status[4] + self._status[5])
468 unknown = set(self._status[4] + self._status[5])
466 else:
469 else:
467 removed = set()
470 removed = set()
468 unknown = set()
471 unknown = set()
469 return (f for f in self.subset
472 return (f for f in self.subset
470 if (f in self.ctx and f not in removed) or f in unknown)
473 if (f in self.ctx and f not in removed) or f in unknown)
471 def narrow(self, files):
474 def narrow(self, files):
472 return matchctx(self.ctx, self.filter(files), self._status)
475 return matchctx(self.ctx, self.filter(files), self._status)
473
476
474 def _intree(funcs, tree):
477 def _intree(funcs, tree):
475 if isinstance(tree, tuple):
478 if isinstance(tree, tuple):
476 if tree[0] == 'func' and tree[1][0] == 'symbol':
479 if tree[0] == 'func' and tree[1][0] == 'symbol':
477 if tree[1][1] in funcs:
480 if tree[1][1] in funcs:
478 return True
481 return True
479 for s in tree[1:]:
482 for s in tree[1:]:
480 if _intree(funcs, s):
483 if _intree(funcs, s):
481 return True
484 return True
482 return False
485 return False
483
486
484 # filesets using matchctx.existing()
487 # filesets using matchctx.existing()
485 _existingcallers = [
488 _existingcallers = [
486 'binary',
489 'binary',
487 'exec',
490 'exec',
488 'grep',
491 'grep',
489 'size',
492 'size',
490 'symlink',
493 'symlink',
491 ]
494 ]
492
495
493 def getfileset(ctx, expr):
496 def getfileset(ctx, expr):
494 tree, pos = parse(expr)
497 tree = parse(expr)
495 if (pos != len(expr)):
496 raise error.ParseError(_("invalid token"), pos)
497
498
498 # do we need status info?
499 # do we need status info?
499 if (_intree(['modified', 'added', 'removed', 'deleted',
500 if (_intree(['modified', 'added', 'removed', 'deleted',
500 'unknown', 'ignored', 'clean'], tree) or
501 'unknown', 'ignored', 'clean'], tree) or
501 # Using matchctx.existing() on a workingctx requires us to check
502 # Using matchctx.existing() on a workingctx requires us to check
502 # for deleted files.
503 # for deleted files.
503 (ctx.rev() is None and _intree(_existingcallers, tree))):
504 (ctx.rev() is None and _intree(_existingcallers, tree))):
504 unknown = _intree(['unknown'], tree)
505 unknown = _intree(['unknown'], tree)
505 ignored = _intree(['ignored'], tree)
506 ignored = _intree(['ignored'], tree)
506
507
507 r = ctx.repo()
508 r = ctx.repo()
508 status = r.status(ctx.p1(), ctx,
509 status = r.status(ctx.p1(), ctx,
509 unknown=unknown, ignored=ignored, clean=True)
510 unknown=unknown, ignored=ignored, clean=True)
510 subset = []
511 subset = []
511 for c in status:
512 for c in status:
512 subset.extend(c)
513 subset.extend(c)
513 else:
514 else:
514 status = None
515 status = None
515 subset = list(ctx.walk(ctx.match([])))
516 subset = list(ctx.walk(ctx.match([])))
516
517
517 return getset(matchctx(ctx, subset, status), tree)
518 return getset(matchctx(ctx, subset, status), tree)
518
519
519 # tell hggettext to extract docstrings from these functions:
520 # tell hggettext to extract docstrings from these functions:
520 i18nfunctions = symbols.values()
521 i18nfunctions = symbols.values()
General Comments 0
You need to be logged in to leave comments. Login now