##// END OF EJS Templates
help: move rst formatting of help documents into help.py...
Augie Fackler -
r31059:2a0c8e36 default
parent child Browse files
Show More
@@ -1,5464 +1,5429 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 )
21 )
22 from . import (
22 from . import (
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 changegroup,
26 changegroup,
27 cmdutil,
27 cmdutil,
28 copies,
28 copies,
29 destutil,
29 destutil,
30 dirstateguard,
30 dirstateguard,
31 discovery,
31 discovery,
32 encoding,
32 encoding,
33 error,
33 error,
34 exchange,
34 exchange,
35 extensions,
35 extensions,
36 graphmod,
36 graphmod,
37 hbisect,
37 hbisect,
38 help,
38 help,
39 hg,
39 hg,
40 lock as lockmod,
40 lock as lockmod,
41 merge as mergemod,
41 merge as mergemod,
42 minirst,
43 obsolete,
42 obsolete,
44 patch,
43 patch,
45 phases,
44 phases,
46 pycompat,
45 pycompat,
47 revsetlang,
46 revsetlang,
48 scmutil,
47 scmutil,
49 server,
48 server,
50 sshserver,
49 sshserver,
51 streamclone,
50 streamclone,
52 templatekw,
51 templatekw,
53 ui as uimod,
52 ui as uimod,
54 util,
53 util,
55 )
54 )
56
55
57 release = lockmod.release
56 release = lockmod.release
58
57
59 table = {}
58 table = {}
60
59
61 command = cmdutil.command(table)
60 command = cmdutil.command(table)
62
61
63 # label constants
62 # label constants
64 # until 3.5, bookmarks.current was the advertised name, not
63 # until 3.5, bookmarks.current was the advertised name, not
65 # bookmarks.active, so we must use both to avoid breaking old
64 # bookmarks.active, so we must use both to avoid breaking old
66 # custom styles
65 # custom styles
67 activebookmarklabel = 'bookmarks.active bookmarks.current'
66 activebookmarklabel = 'bookmarks.active bookmarks.current'
68
67
69 # common command options
68 # common command options
70
69
71 globalopts = [
70 globalopts = [
72 ('R', 'repository', '',
71 ('R', 'repository', '',
73 _('repository root directory or name of overlay bundle file'),
72 _('repository root directory or name of overlay bundle file'),
74 _('REPO')),
73 _('REPO')),
75 ('', 'cwd', '',
74 ('', 'cwd', '',
76 _('change working directory'), _('DIR')),
75 _('change working directory'), _('DIR')),
77 ('y', 'noninteractive', None,
76 ('y', 'noninteractive', None,
78 _('do not prompt, automatically pick the first choice for all prompts')),
77 _('do not prompt, automatically pick the first choice for all prompts')),
79 ('q', 'quiet', None, _('suppress output')),
78 ('q', 'quiet', None, _('suppress output')),
80 ('v', 'verbose', None, _('enable additional output')),
79 ('v', 'verbose', None, _('enable additional output')),
81 ('', 'config', [],
80 ('', 'config', [],
82 _('set/override config option (use \'section.name=value\')'),
81 _('set/override config option (use \'section.name=value\')'),
83 _('CONFIG')),
82 _('CONFIG')),
84 ('', 'debug', None, _('enable debugging output')),
83 ('', 'debug', None, _('enable debugging output')),
85 ('', 'debugger', None, _('start debugger')),
84 ('', 'debugger', None, _('start debugger')),
86 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
85 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
87 _('ENCODE')),
86 _('ENCODE')),
88 ('', 'encodingmode', encoding.encodingmode,
87 ('', 'encodingmode', encoding.encodingmode,
89 _('set the charset encoding mode'), _('MODE')),
88 _('set the charset encoding mode'), _('MODE')),
90 ('', 'traceback', None, _('always print a traceback on exception')),
89 ('', 'traceback', None, _('always print a traceback on exception')),
91 ('', 'time', None, _('time how long the command takes')),
90 ('', 'time', None, _('time how long the command takes')),
92 ('', 'profile', None, _('print command execution profile')),
91 ('', 'profile', None, _('print command execution profile')),
93 ('', 'version', None, _('output version information and exit')),
92 ('', 'version', None, _('output version information and exit')),
94 ('h', 'help', None, _('display help and exit')),
93 ('h', 'help', None, _('display help and exit')),
95 ('', 'hidden', False, _('consider hidden changesets')),
94 ('', 'hidden', False, _('consider hidden changesets')),
96 ('', 'pager', 'auto',
95 ('', 'pager', 'auto',
97 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
96 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
98 ]
97 ]
99
98
100 dryrunopts = [('n', 'dry-run', None,
99 dryrunopts = [('n', 'dry-run', None,
101 _('do not perform actions, just print output'))]
100 _('do not perform actions, just print output'))]
102
101
103 remoteopts = [
102 remoteopts = [
104 ('e', 'ssh', '',
103 ('e', 'ssh', '',
105 _('specify ssh command to use'), _('CMD')),
104 _('specify ssh command to use'), _('CMD')),
106 ('', 'remotecmd', '',
105 ('', 'remotecmd', '',
107 _('specify hg command to run on the remote side'), _('CMD')),
106 _('specify hg command to run on the remote side'), _('CMD')),
108 ('', 'insecure', None,
107 ('', 'insecure', None,
109 _('do not verify server certificate (ignoring web.cacerts config)')),
108 _('do not verify server certificate (ignoring web.cacerts config)')),
110 ]
109 ]
111
110
112 walkopts = [
111 walkopts = [
113 ('I', 'include', [],
112 ('I', 'include', [],
114 _('include names matching the given patterns'), _('PATTERN')),
113 _('include names matching the given patterns'), _('PATTERN')),
115 ('X', 'exclude', [],
114 ('X', 'exclude', [],
116 _('exclude names matching the given patterns'), _('PATTERN')),
115 _('exclude names matching the given patterns'), _('PATTERN')),
117 ]
116 ]
118
117
119 commitopts = [
118 commitopts = [
120 ('m', 'message', '',
119 ('m', 'message', '',
121 _('use text as commit message'), _('TEXT')),
120 _('use text as commit message'), _('TEXT')),
122 ('l', 'logfile', '',
121 ('l', 'logfile', '',
123 _('read commit message from file'), _('FILE')),
122 _('read commit message from file'), _('FILE')),
124 ]
123 ]
125
124
126 commitopts2 = [
125 commitopts2 = [
127 ('d', 'date', '',
126 ('d', 'date', '',
128 _('record the specified date as commit date'), _('DATE')),
127 _('record the specified date as commit date'), _('DATE')),
129 ('u', 'user', '',
128 ('u', 'user', '',
130 _('record the specified user as committer'), _('USER')),
129 _('record the specified user as committer'), _('USER')),
131 ]
130 ]
132
131
133 # hidden for now
132 # hidden for now
134 formatteropts = [
133 formatteropts = [
135 ('T', 'template', '',
134 ('T', 'template', '',
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
135 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
137 ]
136 ]
138
137
139 templateopts = [
138 templateopts = [
140 ('', 'style', '',
139 ('', 'style', '',
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
140 _('display using template map file (DEPRECATED)'), _('STYLE')),
142 ('T', 'template', '',
141 ('T', 'template', '',
143 _('display with template'), _('TEMPLATE')),
142 _('display with template'), _('TEMPLATE')),
144 ]
143 ]
145
144
146 logopts = [
145 logopts = [
147 ('p', 'patch', None, _('show patch')),
146 ('p', 'patch', None, _('show patch')),
148 ('g', 'git', None, _('use git extended diff format')),
147 ('g', 'git', None, _('use git extended diff format')),
149 ('l', 'limit', '',
148 ('l', 'limit', '',
150 _('limit number of changes displayed'), _('NUM')),
149 _('limit number of changes displayed'), _('NUM')),
151 ('M', 'no-merges', None, _('do not show merges')),
150 ('M', 'no-merges', None, _('do not show merges')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ('', 'stat', None, _('output diffstat-style summary of changes')),
153 ('G', 'graph', None, _("show the revision DAG")),
152 ('G', 'graph', None, _("show the revision DAG")),
154 ] + templateopts
153 ] + templateopts
155
154
156 diffopts = [
155 diffopts = [
157 ('a', 'text', None, _('treat all files as text')),
156 ('a', 'text', None, _('treat all files as text')),
158 ('g', 'git', None, _('use git extended diff format')),
157 ('g', 'git', None, _('use git extended diff format')),
159 ('', 'nodates', None, _('omit dates from diff headers'))
158 ('', 'nodates', None, _('omit dates from diff headers'))
160 ]
159 ]
161
160
162 diffwsopts = [
161 diffwsopts = [
163 ('w', 'ignore-all-space', None,
162 ('w', 'ignore-all-space', None,
164 _('ignore white space when comparing lines')),
163 _('ignore white space when comparing lines')),
165 ('b', 'ignore-space-change', None,
164 ('b', 'ignore-space-change', None,
166 _('ignore changes in the amount of white space')),
165 _('ignore changes in the amount of white space')),
167 ('B', 'ignore-blank-lines', None,
166 ('B', 'ignore-blank-lines', None,
168 _('ignore changes whose lines are all blank')),
167 _('ignore changes whose lines are all blank')),
169 ]
168 ]
170
169
171 diffopts2 = [
170 diffopts2 = [
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
171 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
173 ('p', 'show-function', None, _('show which function each change is in')),
172 ('p', 'show-function', None, _('show which function each change is in')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
173 ('', 'reverse', None, _('produce a diff that undoes the changes')),
175 ] + diffwsopts + [
174 ] + diffwsopts + [
176 ('U', 'unified', '',
175 ('U', 'unified', '',
177 _('number of lines of context to show'), _('NUM')),
176 _('number of lines of context to show'), _('NUM')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
177 ('', 'stat', None, _('output diffstat-style summary of changes')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
178 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
180 ]
179 ]
181
180
182 mergetoolopts = [
181 mergetoolopts = [
183 ('t', 'tool', '', _('specify merge tool')),
182 ('t', 'tool', '', _('specify merge tool')),
184 ]
183 ]
185
184
186 similarityopts = [
185 similarityopts = [
187 ('s', 'similarity', '',
186 ('s', 'similarity', '',
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
187 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
189 ]
188 ]
190
189
191 subrepoopts = [
190 subrepoopts = [
192 ('S', 'subrepos', None,
191 ('S', 'subrepos', None,
193 _('recurse into subrepositories'))
192 _('recurse into subrepositories'))
194 ]
193 ]
195
194
196 debugrevlogopts = [
195 debugrevlogopts = [
197 ('c', 'changelog', False, _('open changelog')),
196 ('c', 'changelog', False, _('open changelog')),
198 ('m', 'manifest', False, _('open manifest')),
197 ('m', 'manifest', False, _('open manifest')),
199 ('', 'dir', '', _('open directory manifest')),
198 ('', 'dir', '', _('open directory manifest')),
200 ]
199 ]
201
200
202 # Commands start here, listed alphabetically
201 # Commands start here, listed alphabetically
203
202
204 @command('^add',
203 @command('^add',
205 walkopts + subrepoopts + dryrunopts,
204 walkopts + subrepoopts + dryrunopts,
206 _('[OPTION]... [FILE]...'),
205 _('[OPTION]... [FILE]...'),
207 inferrepo=True)
206 inferrepo=True)
208 def add(ui, repo, *pats, **opts):
207 def add(ui, repo, *pats, **opts):
209 """add the specified files on the next commit
208 """add the specified files on the next commit
210
209
211 Schedule files to be version controlled and added to the
210 Schedule files to be version controlled and added to the
212 repository.
211 repository.
213
212
214 The files will be added to the repository at the next commit. To
213 The files will be added to the repository at the next commit. To
215 undo an add before that, see :hg:`forget`.
214 undo an add before that, see :hg:`forget`.
216
215
217 If no names are given, add all files to the repository (except
216 If no names are given, add all files to the repository (except
218 files matching ``.hgignore``).
217 files matching ``.hgignore``).
219
218
220 .. container:: verbose
219 .. container:: verbose
221
220
222 Examples:
221 Examples:
223
222
224 - New (unknown) files are added
223 - New (unknown) files are added
225 automatically by :hg:`add`::
224 automatically by :hg:`add`::
226
225
227 $ ls
226 $ ls
228 foo.c
227 foo.c
229 $ hg status
228 $ hg status
230 ? foo.c
229 ? foo.c
231 $ hg add
230 $ hg add
232 adding foo.c
231 adding foo.c
233 $ hg status
232 $ hg status
234 A foo.c
233 A foo.c
235
234
236 - Specific files to be added can be specified::
235 - Specific files to be added can be specified::
237
236
238 $ ls
237 $ ls
239 bar.c foo.c
238 bar.c foo.c
240 $ hg status
239 $ hg status
241 ? bar.c
240 ? bar.c
242 ? foo.c
241 ? foo.c
243 $ hg add bar.c
242 $ hg add bar.c
244 $ hg status
243 $ hg status
245 A bar.c
244 A bar.c
246 ? foo.c
245 ? foo.c
247
246
248 Returns 0 if all files are successfully added.
247 Returns 0 if all files are successfully added.
249 """
248 """
250
249
251 m = scmutil.match(repo[None], pats, opts)
250 m = scmutil.match(repo[None], pats, opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
251 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
253 return rejected and 1 or 0
252 return rejected and 1 or 0
254
253
255 @command('addremove',
254 @command('addremove',
256 similarityopts + subrepoopts + walkopts + dryrunopts,
255 similarityopts + subrepoopts + walkopts + dryrunopts,
257 _('[OPTION]... [FILE]...'),
256 _('[OPTION]... [FILE]...'),
258 inferrepo=True)
257 inferrepo=True)
259 def addremove(ui, repo, *pats, **opts):
258 def addremove(ui, repo, *pats, **opts):
260 """add all new files, delete all missing files
259 """add all new files, delete all missing files
261
260
262 Add all new files and remove all missing files from the
261 Add all new files and remove all missing files from the
263 repository.
262 repository.
264
263
265 Unless names are given, new files are ignored if they match any of
264 Unless names are given, new files are ignored if they match any of
266 the patterns in ``.hgignore``. As with add, these changes take
265 the patterns in ``.hgignore``. As with add, these changes take
267 effect at the next commit.
266 effect at the next commit.
268
267
269 Use the -s/--similarity option to detect renamed files. This
268 Use the -s/--similarity option to detect renamed files. This
270 option takes a percentage between 0 (disabled) and 100 (files must
269 option takes a percentage between 0 (disabled) and 100 (files must
271 be identical) as its parameter. With a parameter greater than 0,
270 be identical) as its parameter. With a parameter greater than 0,
272 this compares every removed file with every added file and records
271 this compares every removed file with every added file and records
273 those similar enough as renames. Detecting renamed files this way
272 those similar enough as renames. Detecting renamed files this way
274 can be expensive. After using this option, :hg:`status -C` can be
273 can be expensive. After using this option, :hg:`status -C` can be
275 used to check which files were identified as moved or renamed. If
274 used to check which files were identified as moved or renamed. If
276 not specified, -s/--similarity defaults to 100 and only renames of
275 not specified, -s/--similarity defaults to 100 and only renames of
277 identical files are detected.
276 identical files are detected.
278
277
279 .. container:: verbose
278 .. container:: verbose
280
279
281 Examples:
280 Examples:
282
281
283 - A number of files (bar.c and foo.c) are new,
282 - A number of files (bar.c and foo.c) are new,
284 while foobar.c has been removed (without using :hg:`remove`)
283 while foobar.c has been removed (without using :hg:`remove`)
285 from the repository::
284 from the repository::
286
285
287 $ ls
286 $ ls
288 bar.c foo.c
287 bar.c foo.c
289 $ hg status
288 $ hg status
290 ! foobar.c
289 ! foobar.c
291 ? bar.c
290 ? bar.c
292 ? foo.c
291 ? foo.c
293 $ hg addremove
292 $ hg addremove
294 adding bar.c
293 adding bar.c
295 adding foo.c
294 adding foo.c
296 removing foobar.c
295 removing foobar.c
297 $ hg status
296 $ hg status
298 A bar.c
297 A bar.c
299 A foo.c
298 A foo.c
300 R foobar.c
299 R foobar.c
301
300
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
301 - A file foobar.c was moved to foo.c without using :hg:`rename`.
303 Afterwards, it was edited slightly::
302 Afterwards, it was edited slightly::
304
303
305 $ ls
304 $ ls
306 foo.c
305 foo.c
307 $ hg status
306 $ hg status
308 ! foobar.c
307 ! foobar.c
309 ? foo.c
308 ? foo.c
310 $ hg addremove --similarity 90
309 $ hg addremove --similarity 90
311 removing foobar.c
310 removing foobar.c
312 adding foo.c
311 adding foo.c
313 recording removal of foobar.c as rename to foo.c (94% similar)
312 recording removal of foobar.c as rename to foo.c (94% similar)
314 $ hg status -C
313 $ hg status -C
315 A foo.c
314 A foo.c
316 foobar.c
315 foobar.c
317 R foobar.c
316 R foobar.c
318
317
319 Returns 0 if all files are successfully added.
318 Returns 0 if all files are successfully added.
320 """
319 """
321 try:
320 try:
322 sim = float(opts.get('similarity') or 100)
321 sim = float(opts.get('similarity') or 100)
323 except ValueError:
322 except ValueError:
324 raise error.Abort(_('similarity must be a number'))
323 raise error.Abort(_('similarity must be a number'))
325 if sim < 0 or sim > 100:
324 if sim < 0 or sim > 100:
326 raise error.Abort(_('similarity must be between 0 and 100'))
325 raise error.Abort(_('similarity must be between 0 and 100'))
327 matcher = scmutil.match(repo[None], pats, opts)
326 matcher = scmutil.match(repo[None], pats, opts)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
327 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
329
328
330 @command('^annotate|blame',
329 @command('^annotate|blame',
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
330 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
332 ('', 'follow', None,
331 ('', 'follow', None,
333 _('follow copies/renames and list the filename (DEPRECATED)')),
332 _('follow copies/renames and list the filename (DEPRECATED)')),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
333 ('', 'no-follow', None, _("don't follow copies and renames")),
335 ('a', 'text', None, _('treat all files as text')),
334 ('a', 'text', None, _('treat all files as text')),
336 ('u', 'user', None, _('list the author (long with -v)')),
335 ('u', 'user', None, _('list the author (long with -v)')),
337 ('f', 'file', None, _('list the filename')),
336 ('f', 'file', None, _('list the filename')),
338 ('d', 'date', None, _('list the date (short with -q)')),
337 ('d', 'date', None, _('list the date (short with -q)')),
339 ('n', 'number', None, _('list the revision number (default)')),
338 ('n', 'number', None, _('list the revision number (default)')),
340 ('c', 'changeset', None, _('list the changeset')),
339 ('c', 'changeset', None, _('list the changeset')),
341 ('l', 'line-number', None, _('show line number at the first appearance'))
340 ('l', 'line-number', None, _('show line number at the first appearance'))
342 ] + diffwsopts + walkopts + formatteropts,
341 ] + diffwsopts + walkopts + formatteropts,
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
342 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
344 inferrepo=True)
343 inferrepo=True)
345 def annotate(ui, repo, *pats, **opts):
344 def annotate(ui, repo, *pats, **opts):
346 """show changeset information by line for each file
345 """show changeset information by line for each file
347
346
348 List changes in files, showing the revision id responsible for
347 List changes in files, showing the revision id responsible for
349 each line.
348 each line.
350
349
351 This command is useful for discovering when a change was made and
350 This command is useful for discovering when a change was made and
352 by whom.
351 by whom.
353
352
354 If you include --file, --user, or --date, the revision number is
353 If you include --file, --user, or --date, the revision number is
355 suppressed unless you also include --number.
354 suppressed unless you also include --number.
356
355
357 Without the -a/--text option, annotate will avoid processing files
356 Without the -a/--text option, annotate will avoid processing files
358 it detects as binary. With -a, annotate will annotate the file
357 it detects as binary. With -a, annotate will annotate the file
359 anyway, although the results will probably be neither useful
358 anyway, although the results will probably be neither useful
360 nor desirable.
359 nor desirable.
361
360
362 Returns 0 on success.
361 Returns 0 on success.
363 """
362 """
364 if not pats:
363 if not pats:
365 raise error.Abort(_('at least one filename or pattern is required'))
364 raise error.Abort(_('at least one filename or pattern is required'))
366
365
367 if opts.get('follow'):
366 if opts.get('follow'):
368 # --follow is deprecated and now just an alias for -f/--file
367 # --follow is deprecated and now just an alias for -f/--file
369 # to mimic the behavior of Mercurial before version 1.5
368 # to mimic the behavior of Mercurial before version 1.5
370 opts['file'] = True
369 opts['file'] = True
371
370
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
371 ctx = scmutil.revsingle(repo, opts.get('rev'))
373
372
374 fm = ui.formatter('annotate', opts)
373 fm = ui.formatter('annotate', opts)
375 if ui.quiet:
374 if ui.quiet:
376 datefunc = util.shortdate
375 datefunc = util.shortdate
377 else:
376 else:
378 datefunc = util.datestr
377 datefunc = util.datestr
379 if ctx.rev() is None:
378 if ctx.rev() is None:
380 def hexfn(node):
379 def hexfn(node):
381 if node is None:
380 if node is None:
382 return None
381 return None
383 else:
382 else:
384 return fm.hexfunc(node)
383 return fm.hexfunc(node)
385 if opts.get('changeset'):
384 if opts.get('changeset'):
386 # omit "+" suffix which is appended to node hex
385 # omit "+" suffix which is appended to node hex
387 def formatrev(rev):
386 def formatrev(rev):
388 if rev is None:
387 if rev is None:
389 return '%d' % ctx.p1().rev()
388 return '%d' % ctx.p1().rev()
390 else:
389 else:
391 return '%d' % rev
390 return '%d' % rev
392 else:
391 else:
393 def formatrev(rev):
392 def formatrev(rev):
394 if rev is None:
393 if rev is None:
395 return '%d+' % ctx.p1().rev()
394 return '%d+' % ctx.p1().rev()
396 else:
395 else:
397 return '%d ' % rev
396 return '%d ' % rev
398 def formathex(hex):
397 def formathex(hex):
399 if hex is None:
398 if hex is None:
400 return '%s+' % fm.hexfunc(ctx.p1().node())
399 return '%s+' % fm.hexfunc(ctx.p1().node())
401 else:
400 else:
402 return '%s ' % hex
401 return '%s ' % hex
403 else:
402 else:
404 hexfn = fm.hexfunc
403 hexfn = fm.hexfunc
405 formatrev = formathex = str
404 formatrev = formathex = str
406
405
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
406 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
407 ('number', ' ', lambda x: x[0].rev(), formatrev),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
408 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
409 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
411 ('file', ' ', lambda x: x[0].path(), str),
410 ('file', ' ', lambda x: x[0].path(), str),
412 ('line_number', ':', lambda x: x[1], str),
411 ('line_number', ':', lambda x: x[1], str),
413 ]
412 ]
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
413 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
415
414
416 if (not opts.get('user') and not opts.get('changeset')
415 if (not opts.get('user') and not opts.get('changeset')
417 and not opts.get('date') and not opts.get('file')):
416 and not opts.get('date') and not opts.get('file')):
418 opts['number'] = True
417 opts['number'] = True
419
418
420 linenumber = opts.get('line_number') is not None
419 linenumber = opts.get('line_number') is not None
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
420 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
421 raise error.Abort(_('at least one of -n/-c is required for -l'))
423
422
424 ui.pager('annotate')
423 ui.pager('annotate')
425
424
426 if fm.isplain():
425 if fm.isplain():
427 def makefunc(get, fmt):
426 def makefunc(get, fmt):
428 return lambda x: fmt(get(x))
427 return lambda x: fmt(get(x))
429 else:
428 else:
430 def makefunc(get, fmt):
429 def makefunc(get, fmt):
431 return get
430 return get
432 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
431 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
433 if opts.get(op)]
432 if opts.get(op)]
434 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
433 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
435 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
434 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
436 if opts.get(op))
435 if opts.get(op))
437
436
438 def bad(x, y):
437 def bad(x, y):
439 raise error.Abort("%s: %s" % (x, y))
438 raise error.Abort("%s: %s" % (x, y))
440
439
441 m = scmutil.match(ctx, pats, opts, badfn=bad)
440 m = scmutil.match(ctx, pats, opts, badfn=bad)
442
441
443 follow = not opts.get('no_follow')
442 follow = not opts.get('no_follow')
444 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
443 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
445 whitespace=True)
444 whitespace=True)
446 for abs in ctx.walk(m):
445 for abs in ctx.walk(m):
447 fctx = ctx[abs]
446 fctx = ctx[abs]
448 if not opts.get('text') and util.binary(fctx.data()):
447 if not opts.get('text') and util.binary(fctx.data()):
449 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
448 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
450 continue
449 continue
451
450
452 lines = fctx.annotate(follow=follow, linenumber=linenumber,
451 lines = fctx.annotate(follow=follow, linenumber=linenumber,
453 diffopts=diffopts)
452 diffopts=diffopts)
454 if not lines:
453 if not lines:
455 continue
454 continue
456 formats = []
455 formats = []
457 pieces = []
456 pieces = []
458
457
459 for f, sep in funcmap:
458 for f, sep in funcmap:
460 l = [f(n) for n, dummy in lines]
459 l = [f(n) for n, dummy in lines]
461 if fm.isplain():
460 if fm.isplain():
462 sizes = [encoding.colwidth(x) for x in l]
461 sizes = [encoding.colwidth(x) for x in l]
463 ml = max(sizes)
462 ml = max(sizes)
464 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
463 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
465 else:
464 else:
466 formats.append(['%s' for x in l])
465 formats.append(['%s' for x in l])
467 pieces.append(l)
466 pieces.append(l)
468
467
469 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
468 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
470 fm.startitem()
469 fm.startitem()
471 fm.write(fields, "".join(f), *p)
470 fm.write(fields, "".join(f), *p)
472 fm.write('line', ": %s", l[1])
471 fm.write('line', ": %s", l[1])
473
472
474 if not lines[-1][1].endswith('\n'):
473 if not lines[-1][1].endswith('\n'):
475 fm.plain('\n')
474 fm.plain('\n')
476
475
477 fm.end()
476 fm.end()
478
477
479 @command('archive',
478 @command('archive',
480 [('', 'no-decode', None, _('do not pass files through decoders')),
479 [('', 'no-decode', None, _('do not pass files through decoders')),
481 ('p', 'prefix', '', _('directory prefix for files in archive'),
480 ('p', 'prefix', '', _('directory prefix for files in archive'),
482 _('PREFIX')),
481 _('PREFIX')),
483 ('r', 'rev', '', _('revision to distribute'), _('REV')),
482 ('r', 'rev', '', _('revision to distribute'), _('REV')),
484 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
483 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
485 ] + subrepoopts + walkopts,
484 ] + subrepoopts + walkopts,
486 _('[OPTION]... DEST'))
485 _('[OPTION]... DEST'))
487 def archive(ui, repo, dest, **opts):
486 def archive(ui, repo, dest, **opts):
488 '''create an unversioned archive of a repository revision
487 '''create an unversioned archive of a repository revision
489
488
490 By default, the revision used is the parent of the working
489 By default, the revision used is the parent of the working
491 directory; use -r/--rev to specify a different revision.
490 directory; use -r/--rev to specify a different revision.
492
491
493 The archive type is automatically detected based on file
492 The archive type is automatically detected based on file
494 extension (to override, use -t/--type).
493 extension (to override, use -t/--type).
495
494
496 .. container:: verbose
495 .. container:: verbose
497
496
498 Examples:
497 Examples:
499
498
500 - create a zip file containing the 1.0 release::
499 - create a zip file containing the 1.0 release::
501
500
502 hg archive -r 1.0 project-1.0.zip
501 hg archive -r 1.0 project-1.0.zip
503
502
504 - create a tarball excluding .hg files::
503 - create a tarball excluding .hg files::
505
504
506 hg archive project.tar.gz -X ".hg*"
505 hg archive project.tar.gz -X ".hg*"
507
506
508 Valid types are:
507 Valid types are:
509
508
510 :``files``: a directory full of files (default)
509 :``files``: a directory full of files (default)
511 :``tar``: tar archive, uncompressed
510 :``tar``: tar archive, uncompressed
512 :``tbz2``: tar archive, compressed using bzip2
511 :``tbz2``: tar archive, compressed using bzip2
513 :``tgz``: tar archive, compressed using gzip
512 :``tgz``: tar archive, compressed using gzip
514 :``uzip``: zip archive, uncompressed
513 :``uzip``: zip archive, uncompressed
515 :``zip``: zip archive, compressed using deflate
514 :``zip``: zip archive, compressed using deflate
516
515
517 The exact name of the destination archive or directory is given
516 The exact name of the destination archive or directory is given
518 using a format string; see :hg:`help export` for details.
517 using a format string; see :hg:`help export` for details.
519
518
520 Each member added to an archive file has a directory prefix
519 Each member added to an archive file has a directory prefix
521 prepended. Use -p/--prefix to specify a format string for the
520 prepended. Use -p/--prefix to specify a format string for the
522 prefix. The default is the basename of the archive, with suffixes
521 prefix. The default is the basename of the archive, with suffixes
523 removed.
522 removed.
524
523
525 Returns 0 on success.
524 Returns 0 on success.
526 '''
525 '''
527
526
528 ctx = scmutil.revsingle(repo, opts.get('rev'))
527 ctx = scmutil.revsingle(repo, opts.get('rev'))
529 if not ctx:
528 if not ctx:
530 raise error.Abort(_('no working directory: please specify a revision'))
529 raise error.Abort(_('no working directory: please specify a revision'))
531 node = ctx.node()
530 node = ctx.node()
532 dest = cmdutil.makefilename(repo, dest, node)
531 dest = cmdutil.makefilename(repo, dest, node)
533 if os.path.realpath(dest) == repo.root:
532 if os.path.realpath(dest) == repo.root:
534 raise error.Abort(_('repository root cannot be destination'))
533 raise error.Abort(_('repository root cannot be destination'))
535
534
536 kind = opts.get('type') or archival.guesskind(dest) or 'files'
535 kind = opts.get('type') or archival.guesskind(dest) or 'files'
537 prefix = opts.get('prefix')
536 prefix = opts.get('prefix')
538
537
539 if dest == '-':
538 if dest == '-':
540 if kind == 'files':
539 if kind == 'files':
541 raise error.Abort(_('cannot archive plain files to stdout'))
540 raise error.Abort(_('cannot archive plain files to stdout'))
542 dest = cmdutil.makefileobj(repo, dest)
541 dest = cmdutil.makefileobj(repo, dest)
543 if not prefix:
542 if not prefix:
544 prefix = os.path.basename(repo.root) + '-%h'
543 prefix = os.path.basename(repo.root) + '-%h'
545
544
546 prefix = cmdutil.makefilename(repo, prefix, node)
545 prefix = cmdutil.makefilename(repo, prefix, node)
547 matchfn = scmutil.match(ctx, [], opts)
546 matchfn = scmutil.match(ctx, [], opts)
548 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
547 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
549 matchfn, prefix, subrepos=opts.get('subrepos'))
548 matchfn, prefix, subrepos=opts.get('subrepos'))
550
549
551 @command('backout',
550 @command('backout',
552 [('', 'merge', None, _('merge with old dirstate parent after backout')),
551 [('', 'merge', None, _('merge with old dirstate parent after backout')),
553 ('', 'commit', None,
552 ('', 'commit', None,
554 _('commit if no conflicts were encountered (DEPRECATED)')),
553 _('commit if no conflicts were encountered (DEPRECATED)')),
555 ('', 'no-commit', None, _('do not commit')),
554 ('', 'no-commit', None, _('do not commit')),
556 ('', 'parent', '',
555 ('', 'parent', '',
557 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
556 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
558 ('r', 'rev', '', _('revision to backout'), _('REV')),
557 ('r', 'rev', '', _('revision to backout'), _('REV')),
559 ('e', 'edit', False, _('invoke editor on commit messages')),
558 ('e', 'edit', False, _('invoke editor on commit messages')),
560 ] + mergetoolopts + walkopts + commitopts + commitopts2,
559 ] + mergetoolopts + walkopts + commitopts + commitopts2,
561 _('[OPTION]... [-r] REV'))
560 _('[OPTION]... [-r] REV'))
562 def backout(ui, repo, node=None, rev=None, **opts):
561 def backout(ui, repo, node=None, rev=None, **opts):
563 '''reverse effect of earlier changeset
562 '''reverse effect of earlier changeset
564
563
565 Prepare a new changeset with the effect of REV undone in the
564 Prepare a new changeset with the effect of REV undone in the
566 current working directory. If no conflicts were encountered,
565 current working directory. If no conflicts were encountered,
567 it will be committed immediately.
566 it will be committed immediately.
568
567
569 If REV is the parent of the working directory, then this new changeset
568 If REV is the parent of the working directory, then this new changeset
570 is committed automatically (unless --no-commit is specified).
569 is committed automatically (unless --no-commit is specified).
571
570
572 .. note::
571 .. note::
573
572
574 :hg:`backout` cannot be used to fix either an unwanted or
573 :hg:`backout` cannot be used to fix either an unwanted or
575 incorrect merge.
574 incorrect merge.
576
575
577 .. container:: verbose
576 .. container:: verbose
578
577
579 Examples:
578 Examples:
580
579
581 - Reverse the effect of the parent of the working directory.
580 - Reverse the effect of the parent of the working directory.
582 This backout will be committed immediately::
581 This backout will be committed immediately::
583
582
584 hg backout -r .
583 hg backout -r .
585
584
586 - Reverse the effect of previous bad revision 23::
585 - Reverse the effect of previous bad revision 23::
587
586
588 hg backout -r 23
587 hg backout -r 23
589
588
590 - Reverse the effect of previous bad revision 23 and
589 - Reverse the effect of previous bad revision 23 and
591 leave changes uncommitted::
590 leave changes uncommitted::
592
591
593 hg backout -r 23 --no-commit
592 hg backout -r 23 --no-commit
594 hg commit -m "Backout revision 23"
593 hg commit -m "Backout revision 23"
595
594
596 By default, the pending changeset will have one parent,
595 By default, the pending changeset will have one parent,
597 maintaining a linear history. With --merge, the pending
596 maintaining a linear history. With --merge, the pending
598 changeset will instead have two parents: the old parent of the
597 changeset will instead have two parents: the old parent of the
599 working directory and a new child of REV that simply undoes REV.
598 working directory and a new child of REV that simply undoes REV.
600
599
601 Before version 1.7, the behavior without --merge was equivalent
600 Before version 1.7, the behavior without --merge was equivalent
602 to specifying --merge followed by :hg:`update --clean .` to
601 to specifying --merge followed by :hg:`update --clean .` to
603 cancel the merge and leave the child of REV as a head to be
602 cancel the merge and leave the child of REV as a head to be
604 merged separately.
603 merged separately.
605
604
606 See :hg:`help dates` for a list of formats valid for -d/--date.
605 See :hg:`help dates` for a list of formats valid for -d/--date.
607
606
608 See :hg:`help revert` for a way to restore files to the state
607 See :hg:`help revert` for a way to restore files to the state
609 of another revision.
608 of another revision.
610
609
611 Returns 0 on success, 1 if nothing to backout or there are unresolved
610 Returns 0 on success, 1 if nothing to backout or there are unresolved
612 files.
611 files.
613 '''
612 '''
614 wlock = lock = None
613 wlock = lock = None
615 try:
614 try:
616 wlock = repo.wlock()
615 wlock = repo.wlock()
617 lock = repo.lock()
616 lock = repo.lock()
618 return _dobackout(ui, repo, node, rev, **opts)
617 return _dobackout(ui, repo, node, rev, **opts)
619 finally:
618 finally:
620 release(lock, wlock)
619 release(lock, wlock)
621
620
622 def _dobackout(ui, repo, node=None, rev=None, **opts):
621 def _dobackout(ui, repo, node=None, rev=None, **opts):
623 if opts.get('commit') and opts.get('no_commit'):
622 if opts.get('commit') and opts.get('no_commit'):
624 raise error.Abort(_("cannot use --commit with --no-commit"))
623 raise error.Abort(_("cannot use --commit with --no-commit"))
625 if opts.get('merge') and opts.get('no_commit'):
624 if opts.get('merge') and opts.get('no_commit'):
626 raise error.Abort(_("cannot use --merge with --no-commit"))
625 raise error.Abort(_("cannot use --merge with --no-commit"))
627
626
628 if rev and node:
627 if rev and node:
629 raise error.Abort(_("please specify just one revision"))
628 raise error.Abort(_("please specify just one revision"))
630
629
631 if not rev:
630 if not rev:
632 rev = node
631 rev = node
633
632
634 if not rev:
633 if not rev:
635 raise error.Abort(_("please specify a revision to backout"))
634 raise error.Abort(_("please specify a revision to backout"))
636
635
637 date = opts.get('date')
636 date = opts.get('date')
638 if date:
637 if date:
639 opts['date'] = util.parsedate(date)
638 opts['date'] = util.parsedate(date)
640
639
641 cmdutil.checkunfinished(repo)
640 cmdutil.checkunfinished(repo)
642 cmdutil.bailifchanged(repo)
641 cmdutil.bailifchanged(repo)
643 node = scmutil.revsingle(repo, rev).node()
642 node = scmutil.revsingle(repo, rev).node()
644
643
645 op1, op2 = repo.dirstate.parents()
644 op1, op2 = repo.dirstate.parents()
646 if not repo.changelog.isancestor(node, op1):
645 if not repo.changelog.isancestor(node, op1):
647 raise error.Abort(_('cannot backout change that is not an ancestor'))
646 raise error.Abort(_('cannot backout change that is not an ancestor'))
648
647
649 p1, p2 = repo.changelog.parents(node)
648 p1, p2 = repo.changelog.parents(node)
650 if p1 == nullid:
649 if p1 == nullid:
651 raise error.Abort(_('cannot backout a change with no parents'))
650 raise error.Abort(_('cannot backout a change with no parents'))
652 if p2 != nullid:
651 if p2 != nullid:
653 if not opts.get('parent'):
652 if not opts.get('parent'):
654 raise error.Abort(_('cannot backout a merge changeset'))
653 raise error.Abort(_('cannot backout a merge changeset'))
655 p = repo.lookup(opts['parent'])
654 p = repo.lookup(opts['parent'])
656 if p not in (p1, p2):
655 if p not in (p1, p2):
657 raise error.Abort(_('%s is not a parent of %s') %
656 raise error.Abort(_('%s is not a parent of %s') %
658 (short(p), short(node)))
657 (short(p), short(node)))
659 parent = p
658 parent = p
660 else:
659 else:
661 if opts.get('parent'):
660 if opts.get('parent'):
662 raise error.Abort(_('cannot use --parent on non-merge changeset'))
661 raise error.Abort(_('cannot use --parent on non-merge changeset'))
663 parent = p1
662 parent = p1
664
663
665 # the backout should appear on the same branch
664 # the backout should appear on the same branch
666 branch = repo.dirstate.branch()
665 branch = repo.dirstate.branch()
667 bheads = repo.branchheads(branch)
666 bheads = repo.branchheads(branch)
668 rctx = scmutil.revsingle(repo, hex(parent))
667 rctx = scmutil.revsingle(repo, hex(parent))
669 if not opts.get('merge') and op1 != node:
668 if not opts.get('merge') and op1 != node:
670 dsguard = dirstateguard.dirstateguard(repo, 'backout')
669 dsguard = dirstateguard.dirstateguard(repo, 'backout')
671 try:
670 try:
672 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
673 'backout')
672 'backout')
674 stats = mergemod.update(repo, parent, True, True, node, False)
673 stats = mergemod.update(repo, parent, True, True, node, False)
675 repo.setparents(op1, op2)
674 repo.setparents(op1, op2)
676 dsguard.close()
675 dsguard.close()
677 hg._showstats(repo, stats)
676 hg._showstats(repo, stats)
678 if stats[3]:
677 if stats[3]:
679 repo.ui.status(_("use 'hg resolve' to retry unresolved "
678 repo.ui.status(_("use 'hg resolve' to retry unresolved "
680 "file merges\n"))
679 "file merges\n"))
681 return 1
680 return 1
682 finally:
681 finally:
683 ui.setconfig('ui', 'forcemerge', '', '')
682 ui.setconfig('ui', 'forcemerge', '', '')
684 lockmod.release(dsguard)
683 lockmod.release(dsguard)
685 else:
684 else:
686 hg.clean(repo, node, show_stats=False)
685 hg.clean(repo, node, show_stats=False)
687 repo.dirstate.setbranch(branch)
686 repo.dirstate.setbranch(branch)
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
687 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
689
688
690 if opts.get('no_commit'):
689 if opts.get('no_commit'):
691 msg = _("changeset %s backed out, "
690 msg = _("changeset %s backed out, "
692 "don't forget to commit.\n")
691 "don't forget to commit.\n")
693 ui.status(msg % short(node))
692 ui.status(msg % short(node))
694 return 0
693 return 0
695
694
696 def commitfunc(ui, repo, message, match, opts):
695 def commitfunc(ui, repo, message, match, opts):
697 editform = 'backout'
696 editform = 'backout'
698 e = cmdutil.getcommiteditor(editform=editform, **opts)
697 e = cmdutil.getcommiteditor(editform=editform, **opts)
699 if not message:
698 if not message:
700 # we don't translate commit messages
699 # we don't translate commit messages
701 message = "Backed out changeset %s" % short(node)
700 message = "Backed out changeset %s" % short(node)
702 e = cmdutil.getcommiteditor(edit=True, editform=editform)
701 e = cmdutil.getcommiteditor(edit=True, editform=editform)
703 return repo.commit(message, opts.get('user'), opts.get('date'),
702 return repo.commit(message, opts.get('user'), opts.get('date'),
704 match, editor=e)
703 match, editor=e)
705 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
704 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
706 if not newnode:
705 if not newnode:
707 ui.status(_("nothing changed\n"))
706 ui.status(_("nothing changed\n"))
708 return 1
707 return 1
709 cmdutil.commitstatus(repo, newnode, branch, bheads)
708 cmdutil.commitstatus(repo, newnode, branch, bheads)
710
709
711 def nice(node):
710 def nice(node):
712 return '%d:%s' % (repo.changelog.rev(node), short(node))
711 return '%d:%s' % (repo.changelog.rev(node), short(node))
713 ui.status(_('changeset %s backs out changeset %s\n') %
712 ui.status(_('changeset %s backs out changeset %s\n') %
714 (nice(repo.changelog.tip()), nice(node)))
713 (nice(repo.changelog.tip()), nice(node)))
715 if opts.get('merge') and op1 != node:
714 if opts.get('merge') and op1 != node:
716 hg.clean(repo, op1, show_stats=False)
715 hg.clean(repo, op1, show_stats=False)
717 ui.status(_('merging with changeset %s\n')
716 ui.status(_('merging with changeset %s\n')
718 % nice(repo.changelog.tip()))
717 % nice(repo.changelog.tip()))
719 try:
718 try:
720 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
719 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
721 'backout')
720 'backout')
722 return hg.merge(repo, hex(repo.changelog.tip()))
721 return hg.merge(repo, hex(repo.changelog.tip()))
723 finally:
722 finally:
724 ui.setconfig('ui', 'forcemerge', '', '')
723 ui.setconfig('ui', 'forcemerge', '', '')
725 return 0
724 return 0
726
725
727 @command('bisect',
726 @command('bisect',
728 [('r', 'reset', False, _('reset bisect state')),
727 [('r', 'reset', False, _('reset bisect state')),
729 ('g', 'good', False, _('mark changeset good')),
728 ('g', 'good', False, _('mark changeset good')),
730 ('b', 'bad', False, _('mark changeset bad')),
729 ('b', 'bad', False, _('mark changeset bad')),
731 ('s', 'skip', False, _('skip testing changeset')),
730 ('s', 'skip', False, _('skip testing changeset')),
732 ('e', 'extend', False, _('extend the bisect range')),
731 ('e', 'extend', False, _('extend the bisect range')),
733 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
732 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
734 ('U', 'noupdate', False, _('do not update to target'))],
733 ('U', 'noupdate', False, _('do not update to target'))],
735 _("[-gbsr] [-U] [-c CMD] [REV]"))
734 _("[-gbsr] [-U] [-c CMD] [REV]"))
736 def bisect(ui, repo, rev=None, extra=None, command=None,
735 def bisect(ui, repo, rev=None, extra=None, command=None,
737 reset=None, good=None, bad=None, skip=None, extend=None,
736 reset=None, good=None, bad=None, skip=None, extend=None,
738 noupdate=None):
737 noupdate=None):
739 """subdivision search of changesets
738 """subdivision search of changesets
740
739
741 This command helps to find changesets which introduce problems. To
740 This command helps to find changesets which introduce problems. To
742 use, mark the earliest changeset you know exhibits the problem as
741 use, mark the earliest changeset you know exhibits the problem as
743 bad, then mark the latest changeset which is free from the problem
742 bad, then mark the latest changeset which is free from the problem
744 as good. Bisect will update your working directory to a revision
743 as good. Bisect will update your working directory to a revision
745 for testing (unless the -U/--noupdate option is specified). Once
744 for testing (unless the -U/--noupdate option is specified). Once
746 you have performed tests, mark the working directory as good or
745 you have performed tests, mark the working directory as good or
747 bad, and bisect will either update to another candidate changeset
746 bad, and bisect will either update to another candidate changeset
748 or announce that it has found the bad revision.
747 or announce that it has found the bad revision.
749
748
750 As a shortcut, you can also use the revision argument to mark a
749 As a shortcut, you can also use the revision argument to mark a
751 revision as good or bad without checking it out first.
750 revision as good or bad without checking it out first.
752
751
753 If you supply a command, it will be used for automatic bisection.
752 If you supply a command, it will be used for automatic bisection.
754 The environment variable HG_NODE will contain the ID of the
753 The environment variable HG_NODE will contain the ID of the
755 changeset being tested. The exit status of the command will be
754 changeset being tested. The exit status of the command will be
756 used to mark revisions as good or bad: status 0 means good, 125
755 used to mark revisions as good or bad: status 0 means good, 125
757 means to skip the revision, 127 (command not found) will abort the
756 means to skip the revision, 127 (command not found) will abort the
758 bisection, and any other non-zero exit status means the revision
757 bisection, and any other non-zero exit status means the revision
759 is bad.
758 is bad.
760
759
761 .. container:: verbose
760 .. container:: verbose
762
761
763 Some examples:
762 Some examples:
764
763
765 - start a bisection with known bad revision 34, and good revision 12::
764 - start a bisection with known bad revision 34, and good revision 12::
766
765
767 hg bisect --bad 34
766 hg bisect --bad 34
768 hg bisect --good 12
767 hg bisect --good 12
769
768
770 - advance the current bisection by marking current revision as good or
769 - advance the current bisection by marking current revision as good or
771 bad::
770 bad::
772
771
773 hg bisect --good
772 hg bisect --good
774 hg bisect --bad
773 hg bisect --bad
775
774
776 - mark the current revision, or a known revision, to be skipped (e.g. if
775 - mark the current revision, or a known revision, to be skipped (e.g. if
777 that revision is not usable because of another issue)::
776 that revision is not usable because of another issue)::
778
777
779 hg bisect --skip
778 hg bisect --skip
780 hg bisect --skip 23
779 hg bisect --skip 23
781
780
782 - skip all revisions that do not touch directories ``foo`` or ``bar``::
781 - skip all revisions that do not touch directories ``foo`` or ``bar``::
783
782
784 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
783 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
785
784
786 - forget the current bisection::
785 - forget the current bisection::
787
786
788 hg bisect --reset
787 hg bisect --reset
789
788
790 - use 'make && make tests' to automatically find the first broken
789 - use 'make && make tests' to automatically find the first broken
791 revision::
790 revision::
792
791
793 hg bisect --reset
792 hg bisect --reset
794 hg bisect --bad 34
793 hg bisect --bad 34
795 hg bisect --good 12
794 hg bisect --good 12
796 hg bisect --command "make && make tests"
795 hg bisect --command "make && make tests"
797
796
798 - see all changesets whose states are already known in the current
797 - see all changesets whose states are already known in the current
799 bisection::
798 bisection::
800
799
801 hg log -r "bisect(pruned)"
800 hg log -r "bisect(pruned)"
802
801
803 - see the changeset currently being bisected (especially useful
802 - see the changeset currently being bisected (especially useful
804 if running with -U/--noupdate)::
803 if running with -U/--noupdate)::
805
804
806 hg log -r "bisect(current)"
805 hg log -r "bisect(current)"
807
806
808 - see all changesets that took part in the current bisection::
807 - see all changesets that took part in the current bisection::
809
808
810 hg log -r "bisect(range)"
809 hg log -r "bisect(range)"
811
810
812 - you can even get a nice graph::
811 - you can even get a nice graph::
813
812
814 hg log --graph -r "bisect(range)"
813 hg log --graph -r "bisect(range)"
815
814
816 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
815 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
817
816
818 Returns 0 on success.
817 Returns 0 on success.
819 """
818 """
820 # backward compatibility
819 # backward compatibility
821 if rev in "good bad reset init".split():
820 if rev in "good bad reset init".split():
822 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
821 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
823 cmd, rev, extra = rev, extra, None
822 cmd, rev, extra = rev, extra, None
824 if cmd == "good":
823 if cmd == "good":
825 good = True
824 good = True
826 elif cmd == "bad":
825 elif cmd == "bad":
827 bad = True
826 bad = True
828 else:
827 else:
829 reset = True
828 reset = True
830 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
829 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
831 raise error.Abort(_('incompatible arguments'))
830 raise error.Abort(_('incompatible arguments'))
832
831
833 cmdutil.checkunfinished(repo)
832 cmdutil.checkunfinished(repo)
834
833
835 if reset:
834 if reset:
836 hbisect.resetstate(repo)
835 hbisect.resetstate(repo)
837 return
836 return
838
837
839 state = hbisect.load_state(repo)
838 state = hbisect.load_state(repo)
840
839
841 # update state
840 # update state
842 if good or bad or skip:
841 if good or bad or skip:
843 if rev:
842 if rev:
844 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
843 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
845 else:
844 else:
846 nodes = [repo.lookup('.')]
845 nodes = [repo.lookup('.')]
847 if good:
846 if good:
848 state['good'] += nodes
847 state['good'] += nodes
849 elif bad:
848 elif bad:
850 state['bad'] += nodes
849 state['bad'] += nodes
851 elif skip:
850 elif skip:
852 state['skip'] += nodes
851 state['skip'] += nodes
853 hbisect.save_state(repo, state)
852 hbisect.save_state(repo, state)
854 if not (state['good'] and state['bad']):
853 if not (state['good'] and state['bad']):
855 return
854 return
856
855
857 def mayupdate(repo, node, show_stats=True):
856 def mayupdate(repo, node, show_stats=True):
858 """common used update sequence"""
857 """common used update sequence"""
859 if noupdate:
858 if noupdate:
860 return
859 return
861 cmdutil.bailifchanged(repo)
860 cmdutil.bailifchanged(repo)
862 return hg.clean(repo, node, show_stats=show_stats)
861 return hg.clean(repo, node, show_stats=show_stats)
863
862
864 displayer = cmdutil.show_changeset(ui, repo, {})
863 displayer = cmdutil.show_changeset(ui, repo, {})
865
864
866 if command:
865 if command:
867 changesets = 1
866 changesets = 1
868 if noupdate:
867 if noupdate:
869 try:
868 try:
870 node = state['current'][0]
869 node = state['current'][0]
871 except LookupError:
870 except LookupError:
872 raise error.Abort(_('current bisect revision is unknown - '
871 raise error.Abort(_('current bisect revision is unknown - '
873 'start a new bisect to fix'))
872 'start a new bisect to fix'))
874 else:
873 else:
875 node, p2 = repo.dirstate.parents()
874 node, p2 = repo.dirstate.parents()
876 if p2 != nullid:
875 if p2 != nullid:
877 raise error.Abort(_('current bisect revision is a merge'))
876 raise error.Abort(_('current bisect revision is a merge'))
878 if rev:
877 if rev:
879 node = repo[scmutil.revsingle(repo, rev, node)].node()
878 node = repo[scmutil.revsingle(repo, rev, node)].node()
880 try:
879 try:
881 while changesets:
880 while changesets:
882 # update state
881 # update state
883 state['current'] = [node]
882 state['current'] = [node]
884 hbisect.save_state(repo, state)
883 hbisect.save_state(repo, state)
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
884 status = ui.system(command, environ={'HG_NODE': hex(node)})
886 if status == 125:
885 if status == 125:
887 transition = "skip"
886 transition = "skip"
888 elif status == 0:
887 elif status == 0:
889 transition = "good"
888 transition = "good"
890 # status < 0 means process was killed
889 # status < 0 means process was killed
891 elif status == 127:
890 elif status == 127:
892 raise error.Abort(_("failed to execute %s") % command)
891 raise error.Abort(_("failed to execute %s") % command)
893 elif status < 0:
892 elif status < 0:
894 raise error.Abort(_("%s killed") % command)
893 raise error.Abort(_("%s killed") % command)
895 else:
894 else:
896 transition = "bad"
895 transition = "bad"
897 state[transition].append(node)
896 state[transition].append(node)
898 ctx = repo[node]
897 ctx = repo[node]
899 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
898 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
900 hbisect.checkstate(state)
899 hbisect.checkstate(state)
901 # bisect
900 # bisect
902 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
901 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
903 # update to next check
902 # update to next check
904 node = nodes[0]
903 node = nodes[0]
905 mayupdate(repo, node, show_stats=False)
904 mayupdate(repo, node, show_stats=False)
906 finally:
905 finally:
907 state['current'] = [node]
906 state['current'] = [node]
908 hbisect.save_state(repo, state)
907 hbisect.save_state(repo, state)
909 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
908 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
910 return
909 return
911
910
912 hbisect.checkstate(state)
911 hbisect.checkstate(state)
913
912
914 # actually bisect
913 # actually bisect
915 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
914 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
916 if extend:
915 if extend:
917 if not changesets:
916 if not changesets:
918 extendnode = hbisect.extendrange(repo, state, nodes, good)
917 extendnode = hbisect.extendrange(repo, state, nodes, good)
919 if extendnode is not None:
918 if extendnode is not None:
920 ui.write(_("Extending search to changeset %d:%s\n")
919 ui.write(_("Extending search to changeset %d:%s\n")
921 % (extendnode.rev(), extendnode))
920 % (extendnode.rev(), extendnode))
922 state['current'] = [extendnode.node()]
921 state['current'] = [extendnode.node()]
923 hbisect.save_state(repo, state)
922 hbisect.save_state(repo, state)
924 return mayupdate(repo, extendnode.node())
923 return mayupdate(repo, extendnode.node())
925 raise error.Abort(_("nothing to extend"))
924 raise error.Abort(_("nothing to extend"))
926
925
927 if changesets == 0:
926 if changesets == 0:
928 hbisect.printresult(ui, repo, state, displayer, nodes, good)
927 hbisect.printresult(ui, repo, state, displayer, nodes, good)
929 else:
928 else:
930 assert len(nodes) == 1 # only a single node can be tested next
929 assert len(nodes) == 1 # only a single node can be tested next
931 node = nodes[0]
930 node = nodes[0]
932 # compute the approximate number of remaining tests
931 # compute the approximate number of remaining tests
933 tests, size = 0, 2
932 tests, size = 0, 2
934 while size <= changesets:
933 while size <= changesets:
935 tests, size = tests + 1, size * 2
934 tests, size = tests + 1, size * 2
936 rev = repo.changelog.rev(node)
935 rev = repo.changelog.rev(node)
937 ui.write(_("Testing changeset %d:%s "
936 ui.write(_("Testing changeset %d:%s "
938 "(%d changesets remaining, ~%d tests)\n")
937 "(%d changesets remaining, ~%d tests)\n")
939 % (rev, short(node), changesets, tests))
938 % (rev, short(node), changesets, tests))
940 state['current'] = [node]
939 state['current'] = [node]
941 hbisect.save_state(repo, state)
940 hbisect.save_state(repo, state)
942 return mayupdate(repo, node)
941 return mayupdate(repo, node)
943
942
944 @command('bookmarks|bookmark',
943 @command('bookmarks|bookmark',
945 [('f', 'force', False, _('force')),
944 [('f', 'force', False, _('force')),
946 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
945 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
947 ('d', 'delete', False, _('delete a given bookmark')),
946 ('d', 'delete', False, _('delete a given bookmark')),
948 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
947 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
949 ('i', 'inactive', False, _('mark a bookmark inactive')),
948 ('i', 'inactive', False, _('mark a bookmark inactive')),
950 ] + formatteropts,
949 ] + formatteropts,
951 _('hg bookmarks [OPTIONS]... [NAME]...'))
950 _('hg bookmarks [OPTIONS]... [NAME]...'))
952 def bookmark(ui, repo, *names, **opts):
951 def bookmark(ui, repo, *names, **opts):
953 '''create a new bookmark or list existing bookmarks
952 '''create a new bookmark or list existing bookmarks
954
953
955 Bookmarks are labels on changesets to help track lines of development.
954 Bookmarks are labels on changesets to help track lines of development.
956 Bookmarks are unversioned and can be moved, renamed and deleted.
955 Bookmarks are unversioned and can be moved, renamed and deleted.
957 Deleting or moving a bookmark has no effect on the associated changesets.
956 Deleting or moving a bookmark has no effect on the associated changesets.
958
957
959 Creating or updating to a bookmark causes it to be marked as 'active'.
958 Creating or updating to a bookmark causes it to be marked as 'active'.
960 The active bookmark is indicated with a '*'.
959 The active bookmark is indicated with a '*'.
961 When a commit is made, the active bookmark will advance to the new commit.
960 When a commit is made, the active bookmark will advance to the new commit.
962 A plain :hg:`update` will also advance an active bookmark, if possible.
961 A plain :hg:`update` will also advance an active bookmark, if possible.
963 Updating away from a bookmark will cause it to be deactivated.
962 Updating away from a bookmark will cause it to be deactivated.
964
963
965 Bookmarks can be pushed and pulled between repositories (see
964 Bookmarks can be pushed and pulled between repositories (see
966 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
965 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
967 diverged, a new 'divergent bookmark' of the form 'name@path' will
966 diverged, a new 'divergent bookmark' of the form 'name@path' will
968 be created. Using :hg:`merge` will resolve the divergence.
967 be created. Using :hg:`merge` will resolve the divergence.
969
968
970 A bookmark named '@' has the special property that :hg:`clone` will
969 A bookmark named '@' has the special property that :hg:`clone` will
971 check it out by default if it exists.
970 check it out by default if it exists.
972
971
973 .. container:: verbose
972 .. container:: verbose
974
973
975 Examples:
974 Examples:
976
975
977 - create an active bookmark for a new line of development::
976 - create an active bookmark for a new line of development::
978
977
979 hg book new-feature
978 hg book new-feature
980
979
981 - create an inactive bookmark as a place marker::
980 - create an inactive bookmark as a place marker::
982
981
983 hg book -i reviewed
982 hg book -i reviewed
984
983
985 - create an inactive bookmark on another changeset::
984 - create an inactive bookmark on another changeset::
986
985
987 hg book -r .^ tested
986 hg book -r .^ tested
988
987
989 - rename bookmark turkey to dinner::
988 - rename bookmark turkey to dinner::
990
989
991 hg book -m turkey dinner
990 hg book -m turkey dinner
992
991
993 - move the '@' bookmark from another branch::
992 - move the '@' bookmark from another branch::
994
993
995 hg book -f @
994 hg book -f @
996 '''
995 '''
997 force = opts.get('force')
996 force = opts.get('force')
998 rev = opts.get('rev')
997 rev = opts.get('rev')
999 delete = opts.get('delete')
998 delete = opts.get('delete')
1000 rename = opts.get('rename')
999 rename = opts.get('rename')
1001 inactive = opts.get('inactive')
1000 inactive = opts.get('inactive')
1002
1001
1003 def checkformat(mark):
1002 def checkformat(mark):
1004 mark = mark.strip()
1003 mark = mark.strip()
1005 if not mark:
1004 if not mark:
1006 raise error.Abort(_("bookmark names cannot consist entirely of "
1005 raise error.Abort(_("bookmark names cannot consist entirely of "
1007 "whitespace"))
1006 "whitespace"))
1008 scmutil.checknewlabel(repo, mark, 'bookmark')
1007 scmutil.checknewlabel(repo, mark, 'bookmark')
1009 return mark
1008 return mark
1010
1009
1011 def checkconflict(repo, mark, cur, force=False, target=None):
1010 def checkconflict(repo, mark, cur, force=False, target=None):
1012 if mark in marks and not force:
1011 if mark in marks and not force:
1013 if target:
1012 if target:
1014 if marks[mark] == target and target == cur:
1013 if marks[mark] == target and target == cur:
1015 # re-activating a bookmark
1014 # re-activating a bookmark
1016 return
1015 return
1017 anc = repo.changelog.ancestors([repo[target].rev()])
1016 anc = repo.changelog.ancestors([repo[target].rev()])
1018 bmctx = repo[marks[mark]]
1017 bmctx = repo[marks[mark]]
1019 divs = [repo[b].node() for b in marks
1018 divs = [repo[b].node() for b in marks
1020 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1019 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1021
1020
1022 # allow resolving a single divergent bookmark even if moving
1021 # allow resolving a single divergent bookmark even if moving
1023 # the bookmark across branches when a revision is specified
1022 # the bookmark across branches when a revision is specified
1024 # that contains a divergent bookmark
1023 # that contains a divergent bookmark
1025 if bmctx.rev() not in anc and target in divs:
1024 if bmctx.rev() not in anc and target in divs:
1026 bookmarks.deletedivergent(repo, [target], mark)
1025 bookmarks.deletedivergent(repo, [target], mark)
1027 return
1026 return
1028
1027
1029 deletefrom = [b for b in divs
1028 deletefrom = [b for b in divs
1030 if repo[b].rev() in anc or b == target]
1029 if repo[b].rev() in anc or b == target]
1031 bookmarks.deletedivergent(repo, deletefrom, mark)
1030 bookmarks.deletedivergent(repo, deletefrom, mark)
1032 if bookmarks.validdest(repo, bmctx, repo[target]):
1031 if bookmarks.validdest(repo, bmctx, repo[target]):
1033 ui.status(_("moving bookmark '%s' forward from %s\n") %
1032 ui.status(_("moving bookmark '%s' forward from %s\n") %
1034 (mark, short(bmctx.node())))
1033 (mark, short(bmctx.node())))
1035 return
1034 return
1036 raise error.Abort(_("bookmark '%s' already exists "
1035 raise error.Abort(_("bookmark '%s' already exists "
1037 "(use -f to force)") % mark)
1036 "(use -f to force)") % mark)
1038 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1037 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1039 and not force):
1038 and not force):
1040 raise error.Abort(
1039 raise error.Abort(
1041 _("a bookmark cannot have the name of an existing branch"))
1040 _("a bookmark cannot have the name of an existing branch"))
1042
1041
1043 if delete and rename:
1042 if delete and rename:
1044 raise error.Abort(_("--delete and --rename are incompatible"))
1043 raise error.Abort(_("--delete and --rename are incompatible"))
1045 if delete and rev:
1044 if delete and rev:
1046 raise error.Abort(_("--rev is incompatible with --delete"))
1045 raise error.Abort(_("--rev is incompatible with --delete"))
1047 if rename and rev:
1046 if rename and rev:
1048 raise error.Abort(_("--rev is incompatible with --rename"))
1047 raise error.Abort(_("--rev is incompatible with --rename"))
1049 if not names and (delete or rev):
1048 if not names and (delete or rev):
1050 raise error.Abort(_("bookmark name required"))
1049 raise error.Abort(_("bookmark name required"))
1051
1050
1052 if delete or rename or names or inactive:
1051 if delete or rename or names or inactive:
1053 wlock = lock = tr = None
1052 wlock = lock = tr = None
1054 try:
1053 try:
1055 wlock = repo.wlock()
1054 wlock = repo.wlock()
1056 lock = repo.lock()
1055 lock = repo.lock()
1057 cur = repo.changectx('.').node()
1056 cur = repo.changectx('.').node()
1058 marks = repo._bookmarks
1057 marks = repo._bookmarks
1059 if delete:
1058 if delete:
1060 tr = repo.transaction('bookmark')
1059 tr = repo.transaction('bookmark')
1061 for mark in names:
1060 for mark in names:
1062 if mark not in marks:
1061 if mark not in marks:
1063 raise error.Abort(_("bookmark '%s' does not exist") %
1062 raise error.Abort(_("bookmark '%s' does not exist") %
1064 mark)
1063 mark)
1065 if mark == repo._activebookmark:
1064 if mark == repo._activebookmark:
1066 bookmarks.deactivate(repo)
1065 bookmarks.deactivate(repo)
1067 del marks[mark]
1066 del marks[mark]
1068
1067
1069 elif rename:
1068 elif rename:
1070 tr = repo.transaction('bookmark')
1069 tr = repo.transaction('bookmark')
1071 if not names:
1070 if not names:
1072 raise error.Abort(_("new bookmark name required"))
1071 raise error.Abort(_("new bookmark name required"))
1073 elif len(names) > 1:
1072 elif len(names) > 1:
1074 raise error.Abort(_("only one new bookmark name allowed"))
1073 raise error.Abort(_("only one new bookmark name allowed"))
1075 mark = checkformat(names[0])
1074 mark = checkformat(names[0])
1076 if rename not in marks:
1075 if rename not in marks:
1077 raise error.Abort(_("bookmark '%s' does not exist")
1076 raise error.Abort(_("bookmark '%s' does not exist")
1078 % rename)
1077 % rename)
1079 checkconflict(repo, mark, cur, force)
1078 checkconflict(repo, mark, cur, force)
1080 marks[mark] = marks[rename]
1079 marks[mark] = marks[rename]
1081 if repo._activebookmark == rename and not inactive:
1080 if repo._activebookmark == rename and not inactive:
1082 bookmarks.activate(repo, mark)
1081 bookmarks.activate(repo, mark)
1083 del marks[rename]
1082 del marks[rename]
1084 elif names:
1083 elif names:
1085 tr = repo.transaction('bookmark')
1084 tr = repo.transaction('bookmark')
1086 newact = None
1085 newact = None
1087 for mark in names:
1086 for mark in names:
1088 mark = checkformat(mark)
1087 mark = checkformat(mark)
1089 if newact is None:
1088 if newact is None:
1090 newact = mark
1089 newact = mark
1091 if inactive and mark == repo._activebookmark:
1090 if inactive and mark == repo._activebookmark:
1092 bookmarks.deactivate(repo)
1091 bookmarks.deactivate(repo)
1093 return
1092 return
1094 tgt = cur
1093 tgt = cur
1095 if rev:
1094 if rev:
1096 tgt = scmutil.revsingle(repo, rev).node()
1095 tgt = scmutil.revsingle(repo, rev).node()
1097 checkconflict(repo, mark, cur, force, tgt)
1096 checkconflict(repo, mark, cur, force, tgt)
1098 marks[mark] = tgt
1097 marks[mark] = tgt
1099 if not inactive and cur == marks[newact] and not rev:
1098 if not inactive and cur == marks[newact] and not rev:
1100 bookmarks.activate(repo, newact)
1099 bookmarks.activate(repo, newact)
1101 elif cur != tgt and newact == repo._activebookmark:
1100 elif cur != tgt and newact == repo._activebookmark:
1102 bookmarks.deactivate(repo)
1101 bookmarks.deactivate(repo)
1103 elif inactive:
1102 elif inactive:
1104 if len(marks) == 0:
1103 if len(marks) == 0:
1105 ui.status(_("no bookmarks set\n"))
1104 ui.status(_("no bookmarks set\n"))
1106 elif not repo._activebookmark:
1105 elif not repo._activebookmark:
1107 ui.status(_("no active bookmark\n"))
1106 ui.status(_("no active bookmark\n"))
1108 else:
1107 else:
1109 bookmarks.deactivate(repo)
1108 bookmarks.deactivate(repo)
1110 if tr is not None:
1109 if tr is not None:
1111 marks.recordchange(tr)
1110 marks.recordchange(tr)
1112 tr.close()
1111 tr.close()
1113 finally:
1112 finally:
1114 lockmod.release(tr, lock, wlock)
1113 lockmod.release(tr, lock, wlock)
1115 else: # show bookmarks
1114 else: # show bookmarks
1116 fm = ui.formatter('bookmarks', opts)
1115 fm = ui.formatter('bookmarks', opts)
1117 hexfn = fm.hexfunc
1116 hexfn = fm.hexfunc
1118 marks = repo._bookmarks
1117 marks = repo._bookmarks
1119 if len(marks) == 0 and fm.isplain():
1118 if len(marks) == 0 and fm.isplain():
1120 ui.status(_("no bookmarks set\n"))
1119 ui.status(_("no bookmarks set\n"))
1121 for bmark, n in sorted(marks.iteritems()):
1120 for bmark, n in sorted(marks.iteritems()):
1122 active = repo._activebookmark
1121 active = repo._activebookmark
1123 if bmark == active:
1122 if bmark == active:
1124 prefix, label = '*', activebookmarklabel
1123 prefix, label = '*', activebookmarklabel
1125 else:
1124 else:
1126 prefix, label = ' ', ''
1125 prefix, label = ' ', ''
1127
1126
1128 fm.startitem()
1127 fm.startitem()
1129 if not ui.quiet:
1128 if not ui.quiet:
1130 fm.plain(' %s ' % prefix, label=label)
1129 fm.plain(' %s ' % prefix, label=label)
1131 fm.write('bookmark', '%s', bmark, label=label)
1130 fm.write('bookmark', '%s', bmark, label=label)
1132 pad = " " * (25 - encoding.colwidth(bmark))
1131 pad = " " * (25 - encoding.colwidth(bmark))
1133 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1132 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1134 repo.changelog.rev(n), hexfn(n), label=label)
1133 repo.changelog.rev(n), hexfn(n), label=label)
1135 fm.data(active=(bmark == active))
1134 fm.data(active=(bmark == active))
1136 fm.plain('\n')
1135 fm.plain('\n')
1137 fm.end()
1136 fm.end()
1138
1137
1139 @command('branch',
1138 @command('branch',
1140 [('f', 'force', None,
1139 [('f', 'force', None,
1141 _('set branch name even if it shadows an existing branch')),
1140 _('set branch name even if it shadows an existing branch')),
1142 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1141 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1143 _('[-fC] [NAME]'))
1142 _('[-fC] [NAME]'))
1144 def branch(ui, repo, label=None, **opts):
1143 def branch(ui, repo, label=None, **opts):
1145 """set or show the current branch name
1144 """set or show the current branch name
1146
1145
1147 .. note::
1146 .. note::
1148
1147
1149 Branch names are permanent and global. Use :hg:`bookmark` to create a
1148 Branch names are permanent and global. Use :hg:`bookmark` to create a
1150 light-weight bookmark instead. See :hg:`help glossary` for more
1149 light-weight bookmark instead. See :hg:`help glossary` for more
1151 information about named branches and bookmarks.
1150 information about named branches and bookmarks.
1152
1151
1153 With no argument, show the current branch name. With one argument,
1152 With no argument, show the current branch name. With one argument,
1154 set the working directory branch name (the branch will not exist
1153 set the working directory branch name (the branch will not exist
1155 in the repository until the next commit). Standard practice
1154 in the repository until the next commit). Standard practice
1156 recommends that primary development take place on the 'default'
1155 recommends that primary development take place on the 'default'
1157 branch.
1156 branch.
1158
1157
1159 Unless -f/--force is specified, branch will not let you set a
1158 Unless -f/--force is specified, branch will not let you set a
1160 branch name that already exists.
1159 branch name that already exists.
1161
1160
1162 Use -C/--clean to reset the working directory branch to that of
1161 Use -C/--clean to reset the working directory branch to that of
1163 the parent of the working directory, negating a previous branch
1162 the parent of the working directory, negating a previous branch
1164 change.
1163 change.
1165
1164
1166 Use the command :hg:`update` to switch to an existing branch. Use
1165 Use the command :hg:`update` to switch to an existing branch. Use
1167 :hg:`commit --close-branch` to mark this branch head as closed.
1166 :hg:`commit --close-branch` to mark this branch head as closed.
1168 When all heads of a branch are closed, the branch will be
1167 When all heads of a branch are closed, the branch will be
1169 considered closed.
1168 considered closed.
1170
1169
1171 Returns 0 on success.
1170 Returns 0 on success.
1172 """
1171 """
1173 if label:
1172 if label:
1174 label = label.strip()
1173 label = label.strip()
1175
1174
1176 if not opts.get('clean') and not label:
1175 if not opts.get('clean') and not label:
1177 ui.write("%s\n" % repo.dirstate.branch())
1176 ui.write("%s\n" % repo.dirstate.branch())
1178 return
1177 return
1179
1178
1180 with repo.wlock():
1179 with repo.wlock():
1181 if opts.get('clean'):
1180 if opts.get('clean'):
1182 label = repo[None].p1().branch()
1181 label = repo[None].p1().branch()
1183 repo.dirstate.setbranch(label)
1182 repo.dirstate.setbranch(label)
1184 ui.status(_('reset working directory to branch %s\n') % label)
1183 ui.status(_('reset working directory to branch %s\n') % label)
1185 elif label:
1184 elif label:
1186 if not opts.get('force') and label in repo.branchmap():
1185 if not opts.get('force') and label in repo.branchmap():
1187 if label not in [p.branch() for p in repo[None].parents()]:
1186 if label not in [p.branch() for p in repo[None].parents()]:
1188 raise error.Abort(_('a branch of the same name already'
1187 raise error.Abort(_('a branch of the same name already'
1189 ' exists'),
1188 ' exists'),
1190 # i18n: "it" refers to an existing branch
1189 # i18n: "it" refers to an existing branch
1191 hint=_("use 'hg update' to switch to it"))
1190 hint=_("use 'hg update' to switch to it"))
1192 scmutil.checknewlabel(repo, label, 'branch')
1191 scmutil.checknewlabel(repo, label, 'branch')
1193 repo.dirstate.setbranch(label)
1192 repo.dirstate.setbranch(label)
1194 ui.status(_('marked working directory as branch %s\n') % label)
1193 ui.status(_('marked working directory as branch %s\n') % label)
1195
1194
1196 # find any open named branches aside from default
1195 # find any open named branches aside from default
1197 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1196 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1198 if n != "default" and not c]
1197 if n != "default" and not c]
1199 if not others:
1198 if not others:
1200 ui.status(_('(branches are permanent and global, '
1199 ui.status(_('(branches are permanent and global, '
1201 'did you want a bookmark?)\n'))
1200 'did you want a bookmark?)\n'))
1202
1201
1203 @command('branches',
1202 @command('branches',
1204 [('a', 'active', False,
1203 [('a', 'active', False,
1205 _('show only branches that have unmerged heads (DEPRECATED)')),
1204 _('show only branches that have unmerged heads (DEPRECATED)')),
1206 ('c', 'closed', False, _('show normal and closed branches')),
1205 ('c', 'closed', False, _('show normal and closed branches')),
1207 ] + formatteropts,
1206 ] + formatteropts,
1208 _('[-c]'))
1207 _('[-c]'))
1209 def branches(ui, repo, active=False, closed=False, **opts):
1208 def branches(ui, repo, active=False, closed=False, **opts):
1210 """list repository named branches
1209 """list repository named branches
1211
1210
1212 List the repository's named branches, indicating which ones are
1211 List the repository's named branches, indicating which ones are
1213 inactive. If -c/--closed is specified, also list branches which have
1212 inactive. If -c/--closed is specified, also list branches which have
1214 been marked closed (see :hg:`commit --close-branch`).
1213 been marked closed (see :hg:`commit --close-branch`).
1215
1214
1216 Use the command :hg:`update` to switch to an existing branch.
1215 Use the command :hg:`update` to switch to an existing branch.
1217
1216
1218 Returns 0.
1217 Returns 0.
1219 """
1218 """
1220
1219
1221 fm = ui.formatter('branches', opts)
1220 fm = ui.formatter('branches', opts)
1222 hexfunc = fm.hexfunc
1221 hexfunc = fm.hexfunc
1223
1222
1224 allheads = set(repo.heads())
1223 allheads = set(repo.heads())
1225 branches = []
1224 branches = []
1226 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1225 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1227 isactive = not isclosed and bool(set(heads) & allheads)
1226 isactive = not isclosed and bool(set(heads) & allheads)
1228 branches.append((tag, repo[tip], isactive, not isclosed))
1227 branches.append((tag, repo[tip], isactive, not isclosed))
1229 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1228 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1230 reverse=True)
1229 reverse=True)
1231
1230
1232 for tag, ctx, isactive, isopen in branches:
1231 for tag, ctx, isactive, isopen in branches:
1233 if active and not isactive:
1232 if active and not isactive:
1234 continue
1233 continue
1235 if isactive:
1234 if isactive:
1236 label = 'branches.active'
1235 label = 'branches.active'
1237 notice = ''
1236 notice = ''
1238 elif not isopen:
1237 elif not isopen:
1239 if not closed:
1238 if not closed:
1240 continue
1239 continue
1241 label = 'branches.closed'
1240 label = 'branches.closed'
1242 notice = _(' (closed)')
1241 notice = _(' (closed)')
1243 else:
1242 else:
1244 label = 'branches.inactive'
1243 label = 'branches.inactive'
1245 notice = _(' (inactive)')
1244 notice = _(' (inactive)')
1246 current = (tag == repo.dirstate.branch())
1245 current = (tag == repo.dirstate.branch())
1247 if current:
1246 if current:
1248 label = 'branches.current'
1247 label = 'branches.current'
1249
1248
1250 fm.startitem()
1249 fm.startitem()
1251 fm.write('branch', '%s', tag, label=label)
1250 fm.write('branch', '%s', tag, label=label)
1252 rev = ctx.rev()
1251 rev = ctx.rev()
1253 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1252 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1254 fmt = ' ' * padsize + ' %d:%s'
1253 fmt = ' ' * padsize + ' %d:%s'
1255 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1254 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1256 label='log.changeset changeset.%s' % ctx.phasestr())
1255 label='log.changeset changeset.%s' % ctx.phasestr())
1257 fm.data(active=isactive, closed=not isopen, current=current)
1256 fm.data(active=isactive, closed=not isopen, current=current)
1258 if not ui.quiet:
1257 if not ui.quiet:
1259 fm.plain(notice)
1258 fm.plain(notice)
1260 fm.plain('\n')
1259 fm.plain('\n')
1261 fm.end()
1260 fm.end()
1262
1261
1263 @command('bundle',
1262 @command('bundle',
1264 [('f', 'force', None, _('run even when the destination is unrelated')),
1263 [('f', 'force', None, _('run even when the destination is unrelated')),
1265 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1264 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1266 _('REV')),
1265 _('REV')),
1267 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1266 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1268 _('BRANCH')),
1267 _('BRANCH')),
1269 ('', 'base', [],
1268 ('', 'base', [],
1270 _('a base changeset assumed to be available at the destination'),
1269 _('a base changeset assumed to be available at the destination'),
1271 _('REV')),
1270 _('REV')),
1272 ('a', 'all', None, _('bundle all changesets in the repository')),
1271 ('a', 'all', None, _('bundle all changesets in the repository')),
1273 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1272 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1274 ] + remoteopts,
1273 ] + remoteopts,
1275 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1274 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1276 def bundle(ui, repo, fname, dest=None, **opts):
1275 def bundle(ui, repo, fname, dest=None, **opts):
1277 """create a changegroup file
1276 """create a changegroup file
1278
1277
1279 Generate a changegroup file collecting changesets to be added
1278 Generate a changegroup file collecting changesets to be added
1280 to a repository.
1279 to a repository.
1281
1280
1282 To create a bundle containing all changesets, use -a/--all
1281 To create a bundle containing all changesets, use -a/--all
1283 (or --base null). Otherwise, hg assumes the destination will have
1282 (or --base null). Otherwise, hg assumes the destination will have
1284 all the nodes you specify with --base parameters. Otherwise, hg
1283 all the nodes you specify with --base parameters. Otherwise, hg
1285 will assume the repository has all the nodes in destination, or
1284 will assume the repository has all the nodes in destination, or
1286 default-push/default if no destination is specified.
1285 default-push/default if no destination is specified.
1287
1286
1288 You can change bundle format with the -t/--type option. You can
1287 You can change bundle format with the -t/--type option. You can
1289 specify a compression, a bundle version or both using a dash
1288 specify a compression, a bundle version or both using a dash
1290 (comp-version). The available compression methods are: none, bzip2,
1289 (comp-version). The available compression methods are: none, bzip2,
1291 and gzip (by default, bundles are compressed using bzip2). The
1290 and gzip (by default, bundles are compressed using bzip2). The
1292 available formats are: v1, v2 (default to most suitable).
1291 available formats are: v1, v2 (default to most suitable).
1293
1292
1294 The bundle file can then be transferred using conventional means
1293 The bundle file can then be transferred using conventional means
1295 and applied to another repository with the unbundle or pull
1294 and applied to another repository with the unbundle or pull
1296 command. This is useful when direct push and pull are not
1295 command. This is useful when direct push and pull are not
1297 available or when exporting an entire repository is undesirable.
1296 available or when exporting an entire repository is undesirable.
1298
1297
1299 Applying bundles preserves all changeset contents including
1298 Applying bundles preserves all changeset contents including
1300 permissions, copy/rename information, and revision history.
1299 permissions, copy/rename information, and revision history.
1301
1300
1302 Returns 0 on success, 1 if no changes found.
1301 Returns 0 on success, 1 if no changes found.
1303 """
1302 """
1304 revs = None
1303 revs = None
1305 if 'rev' in opts:
1304 if 'rev' in opts:
1306 revstrings = opts['rev']
1305 revstrings = opts['rev']
1307 revs = scmutil.revrange(repo, revstrings)
1306 revs = scmutil.revrange(repo, revstrings)
1308 if revstrings and not revs:
1307 if revstrings and not revs:
1309 raise error.Abort(_('no commits to bundle'))
1308 raise error.Abort(_('no commits to bundle'))
1310
1309
1311 bundletype = opts.get('type', 'bzip2').lower()
1310 bundletype = opts.get('type', 'bzip2').lower()
1312 try:
1311 try:
1313 bcompression, cgversion, params = exchange.parsebundlespec(
1312 bcompression, cgversion, params = exchange.parsebundlespec(
1314 repo, bundletype, strict=False)
1313 repo, bundletype, strict=False)
1315 except error.UnsupportedBundleSpecification as e:
1314 except error.UnsupportedBundleSpecification as e:
1316 raise error.Abort(str(e),
1315 raise error.Abort(str(e),
1317 hint=_("see 'hg help bundle' for supported "
1316 hint=_("see 'hg help bundle' for supported "
1318 "values for --type"))
1317 "values for --type"))
1319
1318
1320 # Packed bundles are a pseudo bundle format for now.
1319 # Packed bundles are a pseudo bundle format for now.
1321 if cgversion == 's1':
1320 if cgversion == 's1':
1322 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1321 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1323 hint=_("use 'hg debugcreatestreamclonebundle'"))
1322 hint=_("use 'hg debugcreatestreamclonebundle'"))
1324
1323
1325 if opts.get('all'):
1324 if opts.get('all'):
1326 if dest:
1325 if dest:
1327 raise error.Abort(_("--all is incompatible with specifying "
1326 raise error.Abort(_("--all is incompatible with specifying "
1328 "a destination"))
1327 "a destination"))
1329 if opts.get('base'):
1328 if opts.get('base'):
1330 ui.warn(_("ignoring --base because --all was specified\n"))
1329 ui.warn(_("ignoring --base because --all was specified\n"))
1331 base = ['null']
1330 base = ['null']
1332 else:
1331 else:
1333 base = scmutil.revrange(repo, opts.get('base'))
1332 base = scmutil.revrange(repo, opts.get('base'))
1334 # TODO: get desired bundlecaps from command line.
1333 # TODO: get desired bundlecaps from command line.
1335 bundlecaps = None
1334 bundlecaps = None
1336 if cgversion not in changegroup.supportedoutgoingversions(repo):
1335 if cgversion not in changegroup.supportedoutgoingversions(repo):
1337 raise error.Abort(_("repository does not support bundle version %s") %
1336 raise error.Abort(_("repository does not support bundle version %s") %
1338 cgversion)
1337 cgversion)
1339
1338
1340 if base:
1339 if base:
1341 if dest:
1340 if dest:
1342 raise error.Abort(_("--base is incompatible with specifying "
1341 raise error.Abort(_("--base is incompatible with specifying "
1343 "a destination"))
1342 "a destination"))
1344 common = [repo.lookup(rev) for rev in base]
1343 common = [repo.lookup(rev) for rev in base]
1345 heads = revs and map(repo.lookup, revs) or None
1344 heads = revs and map(repo.lookup, revs) or None
1346 outgoing = discovery.outgoing(repo, common, heads)
1345 outgoing = discovery.outgoing(repo, common, heads)
1347 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1346 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1348 bundlecaps=bundlecaps,
1347 bundlecaps=bundlecaps,
1349 version=cgversion)
1348 version=cgversion)
1350 outgoing = None
1349 outgoing = None
1351 else:
1350 else:
1352 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1351 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1353 dest, branches = hg.parseurl(dest, opts.get('branch'))
1352 dest, branches = hg.parseurl(dest, opts.get('branch'))
1354 other = hg.peer(repo, opts, dest)
1353 other = hg.peer(repo, opts, dest)
1355 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1354 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1356 heads = revs and map(repo.lookup, revs) or revs
1355 heads = revs and map(repo.lookup, revs) or revs
1357 outgoing = discovery.findcommonoutgoing(repo, other,
1356 outgoing = discovery.findcommonoutgoing(repo, other,
1358 onlyheads=heads,
1357 onlyheads=heads,
1359 force=opts.get('force'),
1358 force=opts.get('force'),
1360 portable=True)
1359 portable=True)
1361 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1360 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1362 bundlecaps, version=cgversion)
1361 bundlecaps, version=cgversion)
1363 if not cg:
1362 if not cg:
1364 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1363 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1365 return 1
1364 return 1
1366
1365
1367 if cgversion == '01': #bundle1
1366 if cgversion == '01': #bundle1
1368 if bcompression is None:
1367 if bcompression is None:
1369 bcompression = 'UN'
1368 bcompression = 'UN'
1370 bversion = 'HG10' + bcompression
1369 bversion = 'HG10' + bcompression
1371 bcompression = None
1370 bcompression = None
1372 else:
1371 else:
1373 assert cgversion == '02'
1372 assert cgversion == '02'
1374 bversion = 'HG20'
1373 bversion = 'HG20'
1375
1374
1376 # TODO compression options should be derived from bundlespec parsing.
1375 # TODO compression options should be derived from bundlespec parsing.
1377 # This is a temporary hack to allow adjusting bundle compression
1376 # This is a temporary hack to allow adjusting bundle compression
1378 # level without a) formalizing the bundlespec changes to declare it
1377 # level without a) formalizing the bundlespec changes to declare it
1379 # b) introducing a command flag.
1378 # b) introducing a command flag.
1380 compopts = {}
1379 compopts = {}
1381 complevel = ui.configint('experimental', 'bundlecomplevel')
1380 complevel = ui.configint('experimental', 'bundlecomplevel')
1382 if complevel is not None:
1381 if complevel is not None:
1383 compopts['level'] = complevel
1382 compopts['level'] = complevel
1384
1383
1385 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1384 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1386 compopts=compopts)
1385 compopts=compopts)
1387
1386
1388 @command('cat',
1387 @command('cat',
1389 [('o', 'output', '',
1388 [('o', 'output', '',
1390 _('print output to file with formatted name'), _('FORMAT')),
1389 _('print output to file with formatted name'), _('FORMAT')),
1391 ('r', 'rev', '', _('print the given revision'), _('REV')),
1390 ('r', 'rev', '', _('print the given revision'), _('REV')),
1392 ('', 'decode', None, _('apply any matching decode filter')),
1391 ('', 'decode', None, _('apply any matching decode filter')),
1393 ] + walkopts,
1392 ] + walkopts,
1394 _('[OPTION]... FILE...'),
1393 _('[OPTION]... FILE...'),
1395 inferrepo=True)
1394 inferrepo=True)
1396 def cat(ui, repo, file1, *pats, **opts):
1395 def cat(ui, repo, file1, *pats, **opts):
1397 """output the current or given revision of files
1396 """output the current or given revision of files
1398
1397
1399 Print the specified files as they were at the given revision. If
1398 Print the specified files as they were at the given revision. If
1400 no revision is given, the parent of the working directory is used.
1399 no revision is given, the parent of the working directory is used.
1401
1400
1402 Output may be to a file, in which case the name of the file is
1401 Output may be to a file, in which case the name of the file is
1403 given using a format string. The formatting rules as follows:
1402 given using a format string. The formatting rules as follows:
1404
1403
1405 :``%%``: literal "%" character
1404 :``%%``: literal "%" character
1406 :``%s``: basename of file being printed
1405 :``%s``: basename of file being printed
1407 :``%d``: dirname of file being printed, or '.' if in repository root
1406 :``%d``: dirname of file being printed, or '.' if in repository root
1408 :``%p``: root-relative path name of file being printed
1407 :``%p``: root-relative path name of file being printed
1409 :``%H``: changeset hash (40 hexadecimal digits)
1408 :``%H``: changeset hash (40 hexadecimal digits)
1410 :``%R``: changeset revision number
1409 :``%R``: changeset revision number
1411 :``%h``: short-form changeset hash (12 hexadecimal digits)
1410 :``%h``: short-form changeset hash (12 hexadecimal digits)
1412 :``%r``: zero-padded changeset revision number
1411 :``%r``: zero-padded changeset revision number
1413 :``%b``: basename of the exporting repository
1412 :``%b``: basename of the exporting repository
1414
1413
1415 Returns 0 on success.
1414 Returns 0 on success.
1416 """
1415 """
1417 ctx = scmutil.revsingle(repo, opts.get('rev'))
1416 ctx = scmutil.revsingle(repo, opts.get('rev'))
1418 m = scmutil.match(ctx, (file1,) + pats, opts)
1417 m = scmutil.match(ctx, (file1,) + pats, opts)
1419
1418
1420 ui.pager('cat')
1419 ui.pager('cat')
1421 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1420 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1422
1421
1423 @command('^clone',
1422 @command('^clone',
1424 [('U', 'noupdate', None, _('the clone will include an empty working '
1423 [('U', 'noupdate', None, _('the clone will include an empty working '
1425 'directory (only a repository)')),
1424 'directory (only a repository)')),
1426 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1425 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1427 _('REV')),
1426 _('REV')),
1428 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1427 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1429 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1428 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1429 ('', 'pull', None, _('use pull protocol to copy metadata')),
1431 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1430 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1432 ] + remoteopts,
1431 ] + remoteopts,
1433 _('[OPTION]... SOURCE [DEST]'),
1432 _('[OPTION]... SOURCE [DEST]'),
1434 norepo=True)
1433 norepo=True)
1435 def clone(ui, source, dest=None, **opts):
1434 def clone(ui, source, dest=None, **opts):
1436 """make a copy of an existing repository
1435 """make a copy of an existing repository
1437
1436
1438 Create a copy of an existing repository in a new directory.
1437 Create a copy of an existing repository in a new directory.
1439
1438
1440 If no destination directory name is specified, it defaults to the
1439 If no destination directory name is specified, it defaults to the
1441 basename of the source.
1440 basename of the source.
1442
1441
1443 The location of the source is added to the new repository's
1442 The location of the source is added to the new repository's
1444 ``.hg/hgrc`` file, as the default to be used for future pulls.
1443 ``.hg/hgrc`` file, as the default to be used for future pulls.
1445
1444
1446 Only local paths and ``ssh://`` URLs are supported as
1445 Only local paths and ``ssh://`` URLs are supported as
1447 destinations. For ``ssh://`` destinations, no working directory or
1446 destinations. For ``ssh://`` destinations, no working directory or
1448 ``.hg/hgrc`` will be created on the remote side.
1447 ``.hg/hgrc`` will be created on the remote side.
1449
1448
1450 If the source repository has a bookmark called '@' set, that
1449 If the source repository has a bookmark called '@' set, that
1451 revision will be checked out in the new repository by default.
1450 revision will be checked out in the new repository by default.
1452
1451
1453 To check out a particular version, use -u/--update, or
1452 To check out a particular version, use -u/--update, or
1454 -U/--noupdate to create a clone with no working directory.
1453 -U/--noupdate to create a clone with no working directory.
1455
1454
1456 To pull only a subset of changesets, specify one or more revisions
1455 To pull only a subset of changesets, specify one or more revisions
1457 identifiers with -r/--rev or branches with -b/--branch. The
1456 identifiers with -r/--rev or branches with -b/--branch. The
1458 resulting clone will contain only the specified changesets and
1457 resulting clone will contain only the specified changesets and
1459 their ancestors. These options (or 'clone src#rev dest') imply
1458 their ancestors. These options (or 'clone src#rev dest') imply
1460 --pull, even for local source repositories.
1459 --pull, even for local source repositories.
1461
1460
1462 .. note::
1461 .. note::
1463
1462
1464 Specifying a tag will include the tagged changeset but not the
1463 Specifying a tag will include the tagged changeset but not the
1465 changeset containing the tag.
1464 changeset containing the tag.
1466
1465
1467 .. container:: verbose
1466 .. container:: verbose
1468
1467
1469 For efficiency, hardlinks are used for cloning whenever the
1468 For efficiency, hardlinks are used for cloning whenever the
1470 source and destination are on the same filesystem (note this
1469 source and destination are on the same filesystem (note this
1471 applies only to the repository data, not to the working
1470 applies only to the repository data, not to the working
1472 directory). Some filesystems, such as AFS, implement hardlinking
1471 directory). Some filesystems, such as AFS, implement hardlinking
1473 incorrectly, but do not report errors. In these cases, use the
1472 incorrectly, but do not report errors. In these cases, use the
1474 --pull option to avoid hardlinking.
1473 --pull option to avoid hardlinking.
1475
1474
1476 In some cases, you can clone repositories and the working
1475 In some cases, you can clone repositories and the working
1477 directory using full hardlinks with ::
1476 directory using full hardlinks with ::
1478
1477
1479 $ cp -al REPO REPOCLONE
1478 $ cp -al REPO REPOCLONE
1480
1479
1481 This is the fastest way to clone, but it is not always safe. The
1480 This is the fastest way to clone, but it is not always safe. The
1482 operation is not atomic (making sure REPO is not modified during
1481 operation is not atomic (making sure REPO is not modified during
1483 the operation is up to you) and you have to make sure your
1482 the operation is up to you) and you have to make sure your
1484 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1483 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1485 so). Also, this is not compatible with certain extensions that
1484 so). Also, this is not compatible with certain extensions that
1486 place their metadata under the .hg directory, such as mq.
1485 place their metadata under the .hg directory, such as mq.
1487
1486
1488 Mercurial will update the working directory to the first applicable
1487 Mercurial will update the working directory to the first applicable
1489 revision from this list:
1488 revision from this list:
1490
1489
1491 a) null if -U or the source repository has no changesets
1490 a) null if -U or the source repository has no changesets
1492 b) if -u . and the source repository is local, the first parent of
1491 b) if -u . and the source repository is local, the first parent of
1493 the source repository's working directory
1492 the source repository's working directory
1494 c) the changeset specified with -u (if a branch name, this means the
1493 c) the changeset specified with -u (if a branch name, this means the
1495 latest head of that branch)
1494 latest head of that branch)
1496 d) the changeset specified with -r
1495 d) the changeset specified with -r
1497 e) the tipmost head specified with -b
1496 e) the tipmost head specified with -b
1498 f) the tipmost head specified with the url#branch source syntax
1497 f) the tipmost head specified with the url#branch source syntax
1499 g) the revision marked with the '@' bookmark, if present
1498 g) the revision marked with the '@' bookmark, if present
1500 h) the tipmost head of the default branch
1499 h) the tipmost head of the default branch
1501 i) tip
1500 i) tip
1502
1501
1503 When cloning from servers that support it, Mercurial may fetch
1502 When cloning from servers that support it, Mercurial may fetch
1504 pre-generated data from a server-advertised URL. When this is done,
1503 pre-generated data from a server-advertised URL. When this is done,
1505 hooks operating on incoming changesets and changegroups may fire twice,
1504 hooks operating on incoming changesets and changegroups may fire twice,
1506 once for the bundle fetched from the URL and another for any additional
1505 once for the bundle fetched from the URL and another for any additional
1507 data not fetched from this URL. In addition, if an error occurs, the
1506 data not fetched from this URL. In addition, if an error occurs, the
1508 repository may be rolled back to a partial clone. This behavior may
1507 repository may be rolled back to a partial clone. This behavior may
1509 change in future releases. See :hg:`help -e clonebundles` for more.
1508 change in future releases. See :hg:`help -e clonebundles` for more.
1510
1509
1511 Examples:
1510 Examples:
1512
1511
1513 - clone a remote repository to a new directory named hg/::
1512 - clone a remote repository to a new directory named hg/::
1514
1513
1515 hg clone https://www.mercurial-scm.org/repo/hg/
1514 hg clone https://www.mercurial-scm.org/repo/hg/
1516
1515
1517 - create a lightweight local clone::
1516 - create a lightweight local clone::
1518
1517
1519 hg clone project/ project-feature/
1518 hg clone project/ project-feature/
1520
1519
1521 - clone from an absolute path on an ssh server (note double-slash)::
1520 - clone from an absolute path on an ssh server (note double-slash)::
1522
1521
1523 hg clone ssh://user@server//home/projects/alpha/
1522 hg clone ssh://user@server//home/projects/alpha/
1524
1523
1525 - do a high-speed clone over a LAN while checking out a
1524 - do a high-speed clone over a LAN while checking out a
1526 specified version::
1525 specified version::
1527
1526
1528 hg clone --uncompressed http://server/repo -u 1.5
1527 hg clone --uncompressed http://server/repo -u 1.5
1529
1528
1530 - create a repository without changesets after a particular revision::
1529 - create a repository without changesets after a particular revision::
1531
1530
1532 hg clone -r 04e544 experimental/ good/
1531 hg clone -r 04e544 experimental/ good/
1533
1532
1534 - clone (and track) a particular named branch::
1533 - clone (and track) a particular named branch::
1535
1534
1536 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1535 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1537
1536
1538 See :hg:`help urls` for details on specifying URLs.
1537 See :hg:`help urls` for details on specifying URLs.
1539
1538
1540 Returns 0 on success.
1539 Returns 0 on success.
1541 """
1540 """
1542 if opts.get('noupdate') and opts.get('updaterev'):
1541 if opts.get('noupdate') and opts.get('updaterev'):
1543 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1542 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1544
1543
1545 r = hg.clone(ui, opts, source, dest,
1544 r = hg.clone(ui, opts, source, dest,
1546 pull=opts.get('pull'),
1545 pull=opts.get('pull'),
1547 stream=opts.get('uncompressed'),
1546 stream=opts.get('uncompressed'),
1548 rev=opts.get('rev'),
1547 rev=opts.get('rev'),
1549 update=opts.get('updaterev') or not opts.get('noupdate'),
1548 update=opts.get('updaterev') or not opts.get('noupdate'),
1550 branch=opts.get('branch'),
1549 branch=opts.get('branch'),
1551 shareopts=opts.get('shareopts'))
1550 shareopts=opts.get('shareopts'))
1552
1551
1553 return r is None
1552 return r is None
1554
1553
1555 @command('^commit|ci',
1554 @command('^commit|ci',
1556 [('A', 'addremove', None,
1555 [('A', 'addremove', None,
1557 _('mark new/missing files as added/removed before committing')),
1556 _('mark new/missing files as added/removed before committing')),
1558 ('', 'close-branch', None,
1557 ('', 'close-branch', None,
1559 _('mark a branch head as closed')),
1558 _('mark a branch head as closed')),
1560 ('', 'amend', None, _('amend the parent of the working directory')),
1559 ('', 'amend', None, _('amend the parent of the working directory')),
1561 ('s', 'secret', None, _('use the secret phase for committing')),
1560 ('s', 'secret', None, _('use the secret phase for committing')),
1562 ('e', 'edit', None, _('invoke editor on commit messages')),
1561 ('e', 'edit', None, _('invoke editor on commit messages')),
1563 ('i', 'interactive', None, _('use interactive mode')),
1562 ('i', 'interactive', None, _('use interactive mode')),
1564 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1563 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1565 _('[OPTION]... [FILE]...'),
1564 _('[OPTION]... [FILE]...'),
1566 inferrepo=True)
1565 inferrepo=True)
1567 def commit(ui, repo, *pats, **opts):
1566 def commit(ui, repo, *pats, **opts):
1568 """commit the specified files or all outstanding changes
1567 """commit the specified files or all outstanding changes
1569
1568
1570 Commit changes to the given files into the repository. Unlike a
1569 Commit changes to the given files into the repository. Unlike a
1571 centralized SCM, this operation is a local operation. See
1570 centralized SCM, this operation is a local operation. See
1572 :hg:`push` for a way to actively distribute your changes.
1571 :hg:`push` for a way to actively distribute your changes.
1573
1572
1574 If a list of files is omitted, all changes reported by :hg:`status`
1573 If a list of files is omitted, all changes reported by :hg:`status`
1575 will be committed.
1574 will be committed.
1576
1575
1577 If you are committing the result of a merge, do not provide any
1576 If you are committing the result of a merge, do not provide any
1578 filenames or -I/-X filters.
1577 filenames or -I/-X filters.
1579
1578
1580 If no commit message is specified, Mercurial starts your
1579 If no commit message is specified, Mercurial starts your
1581 configured editor where you can enter a message. In case your
1580 configured editor where you can enter a message. In case your
1582 commit fails, you will find a backup of your message in
1581 commit fails, you will find a backup of your message in
1583 ``.hg/last-message.txt``.
1582 ``.hg/last-message.txt``.
1584
1583
1585 The --close-branch flag can be used to mark the current branch
1584 The --close-branch flag can be used to mark the current branch
1586 head closed. When all heads of a branch are closed, the branch
1585 head closed. When all heads of a branch are closed, the branch
1587 will be considered closed and no longer listed.
1586 will be considered closed and no longer listed.
1588
1587
1589 The --amend flag can be used to amend the parent of the
1588 The --amend flag can be used to amend the parent of the
1590 working directory with a new commit that contains the changes
1589 working directory with a new commit that contains the changes
1591 in the parent in addition to those currently reported by :hg:`status`,
1590 in the parent in addition to those currently reported by :hg:`status`,
1592 if there are any. The old commit is stored in a backup bundle in
1591 if there are any. The old commit is stored in a backup bundle in
1593 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1592 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1594 on how to restore it).
1593 on how to restore it).
1595
1594
1596 Message, user and date are taken from the amended commit unless
1595 Message, user and date are taken from the amended commit unless
1597 specified. When a message isn't specified on the command line,
1596 specified. When a message isn't specified on the command line,
1598 the editor will open with the message of the amended commit.
1597 the editor will open with the message of the amended commit.
1599
1598
1600 It is not possible to amend public changesets (see :hg:`help phases`)
1599 It is not possible to amend public changesets (see :hg:`help phases`)
1601 or changesets that have children.
1600 or changesets that have children.
1602
1601
1603 See :hg:`help dates` for a list of formats valid for -d/--date.
1602 See :hg:`help dates` for a list of formats valid for -d/--date.
1604
1603
1605 Returns 0 on success, 1 if nothing changed.
1604 Returns 0 on success, 1 if nothing changed.
1606
1605
1607 .. container:: verbose
1606 .. container:: verbose
1608
1607
1609 Examples:
1608 Examples:
1610
1609
1611 - commit all files ending in .py::
1610 - commit all files ending in .py::
1612
1611
1613 hg commit --include "set:**.py"
1612 hg commit --include "set:**.py"
1614
1613
1615 - commit all non-binary files::
1614 - commit all non-binary files::
1616
1615
1617 hg commit --exclude "set:binary()"
1616 hg commit --exclude "set:binary()"
1618
1617
1619 - amend the current commit and set the date to now::
1618 - amend the current commit and set the date to now::
1620
1619
1621 hg commit --amend --date now
1620 hg commit --amend --date now
1622 """
1621 """
1623 wlock = lock = None
1622 wlock = lock = None
1624 try:
1623 try:
1625 wlock = repo.wlock()
1624 wlock = repo.wlock()
1626 lock = repo.lock()
1625 lock = repo.lock()
1627 return _docommit(ui, repo, *pats, **opts)
1626 return _docommit(ui, repo, *pats, **opts)
1628 finally:
1627 finally:
1629 release(lock, wlock)
1628 release(lock, wlock)
1630
1629
1631 def _docommit(ui, repo, *pats, **opts):
1630 def _docommit(ui, repo, *pats, **opts):
1632 if opts.get('interactive'):
1631 if opts.get('interactive'):
1633 opts.pop('interactive')
1632 opts.pop('interactive')
1634 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1633 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1635 cmdutil.recordfilter, *pats, **opts)
1634 cmdutil.recordfilter, *pats, **opts)
1636 # ret can be 0 (no changes to record) or the value returned by
1635 # ret can be 0 (no changes to record) or the value returned by
1637 # commit(), 1 if nothing changed or None on success.
1636 # commit(), 1 if nothing changed or None on success.
1638 return 1 if ret == 0 else ret
1637 return 1 if ret == 0 else ret
1639
1638
1640 if opts.get('subrepos'):
1639 if opts.get('subrepos'):
1641 if opts.get('amend'):
1640 if opts.get('amend'):
1642 raise error.Abort(_('cannot amend with --subrepos'))
1641 raise error.Abort(_('cannot amend with --subrepos'))
1643 # Let --subrepos on the command line override config setting.
1642 # Let --subrepos on the command line override config setting.
1644 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1643 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1645
1644
1646 cmdutil.checkunfinished(repo, commit=True)
1645 cmdutil.checkunfinished(repo, commit=True)
1647
1646
1648 branch = repo[None].branch()
1647 branch = repo[None].branch()
1649 bheads = repo.branchheads(branch)
1648 bheads = repo.branchheads(branch)
1650
1649
1651 extra = {}
1650 extra = {}
1652 if opts.get('close_branch'):
1651 if opts.get('close_branch'):
1653 extra['close'] = 1
1652 extra['close'] = 1
1654
1653
1655 if not bheads:
1654 if not bheads:
1656 raise error.Abort(_('can only close branch heads'))
1655 raise error.Abort(_('can only close branch heads'))
1657 elif opts.get('amend'):
1656 elif opts.get('amend'):
1658 if repo[None].parents()[0].p1().branch() != branch and \
1657 if repo[None].parents()[0].p1().branch() != branch and \
1659 repo[None].parents()[0].p2().branch() != branch:
1658 repo[None].parents()[0].p2().branch() != branch:
1660 raise error.Abort(_('can only close branch heads'))
1659 raise error.Abort(_('can only close branch heads'))
1661
1660
1662 if opts.get('amend'):
1661 if opts.get('amend'):
1663 if ui.configbool('ui', 'commitsubrepos'):
1662 if ui.configbool('ui', 'commitsubrepos'):
1664 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1663 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1665
1664
1666 old = repo['.']
1665 old = repo['.']
1667 if not old.mutable():
1666 if not old.mutable():
1668 raise error.Abort(_('cannot amend public changesets'))
1667 raise error.Abort(_('cannot amend public changesets'))
1669 if len(repo[None].parents()) > 1:
1668 if len(repo[None].parents()) > 1:
1670 raise error.Abort(_('cannot amend while merging'))
1669 raise error.Abort(_('cannot amend while merging'))
1671 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1670 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1672 if not allowunstable and old.children():
1671 if not allowunstable and old.children():
1673 raise error.Abort(_('cannot amend changeset with children'))
1672 raise error.Abort(_('cannot amend changeset with children'))
1674
1673
1675 # Currently histedit gets confused if an amend happens while histedit
1674 # Currently histedit gets confused if an amend happens while histedit
1676 # is in progress. Since we have a checkunfinished command, we are
1675 # is in progress. Since we have a checkunfinished command, we are
1677 # temporarily honoring it.
1676 # temporarily honoring it.
1678 #
1677 #
1679 # Note: eventually this guard will be removed. Please do not expect
1678 # Note: eventually this guard will be removed. Please do not expect
1680 # this behavior to remain.
1679 # this behavior to remain.
1681 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1680 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1682 cmdutil.checkunfinished(repo)
1681 cmdutil.checkunfinished(repo)
1683
1682
1684 # commitfunc is used only for temporary amend commit by cmdutil.amend
1683 # commitfunc is used only for temporary amend commit by cmdutil.amend
1685 def commitfunc(ui, repo, message, match, opts):
1684 def commitfunc(ui, repo, message, match, opts):
1686 return repo.commit(message,
1685 return repo.commit(message,
1687 opts.get('user') or old.user(),
1686 opts.get('user') or old.user(),
1688 opts.get('date') or old.date(),
1687 opts.get('date') or old.date(),
1689 match,
1688 match,
1690 extra=extra)
1689 extra=extra)
1691
1690
1692 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1691 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1693 if node == old.node():
1692 if node == old.node():
1694 ui.status(_("nothing changed\n"))
1693 ui.status(_("nothing changed\n"))
1695 return 1
1694 return 1
1696 else:
1695 else:
1697 def commitfunc(ui, repo, message, match, opts):
1696 def commitfunc(ui, repo, message, match, opts):
1698 backup = ui.backupconfig('phases', 'new-commit')
1697 backup = ui.backupconfig('phases', 'new-commit')
1699 baseui = repo.baseui
1698 baseui = repo.baseui
1700 basebackup = baseui.backupconfig('phases', 'new-commit')
1699 basebackup = baseui.backupconfig('phases', 'new-commit')
1701 try:
1700 try:
1702 if opts.get('secret'):
1701 if opts.get('secret'):
1703 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1702 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1704 # Propagate to subrepos
1703 # Propagate to subrepos
1705 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1704 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1706
1705
1707 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1706 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1708 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1707 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1709 return repo.commit(message, opts.get('user'), opts.get('date'),
1708 return repo.commit(message, opts.get('user'), opts.get('date'),
1710 match,
1709 match,
1711 editor=editor,
1710 editor=editor,
1712 extra=extra)
1711 extra=extra)
1713 finally:
1712 finally:
1714 ui.restoreconfig(backup)
1713 ui.restoreconfig(backup)
1715 repo.baseui.restoreconfig(basebackup)
1714 repo.baseui.restoreconfig(basebackup)
1716
1715
1717
1716
1718 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1717 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1719
1718
1720 if not node:
1719 if not node:
1721 stat = cmdutil.postcommitstatus(repo, pats, opts)
1720 stat = cmdutil.postcommitstatus(repo, pats, opts)
1722 if stat[3]:
1721 if stat[3]:
1723 ui.status(_("nothing changed (%d missing files, see "
1722 ui.status(_("nothing changed (%d missing files, see "
1724 "'hg status')\n") % len(stat[3]))
1723 "'hg status')\n") % len(stat[3]))
1725 else:
1724 else:
1726 ui.status(_("nothing changed\n"))
1725 ui.status(_("nothing changed\n"))
1727 return 1
1726 return 1
1728
1727
1729 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1728 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1730
1729
1731 @command('config|showconfig|debugconfig',
1730 @command('config|showconfig|debugconfig',
1732 [('u', 'untrusted', None, _('show untrusted configuration options')),
1731 [('u', 'untrusted', None, _('show untrusted configuration options')),
1733 ('e', 'edit', None, _('edit user config')),
1732 ('e', 'edit', None, _('edit user config')),
1734 ('l', 'local', None, _('edit repository config')),
1733 ('l', 'local', None, _('edit repository config')),
1735 ('g', 'global', None, _('edit global config'))] + formatteropts,
1734 ('g', 'global', None, _('edit global config'))] + formatteropts,
1736 _('[-u] [NAME]...'),
1735 _('[-u] [NAME]...'),
1737 optionalrepo=True)
1736 optionalrepo=True)
1738 def config(ui, repo, *values, **opts):
1737 def config(ui, repo, *values, **opts):
1739 """show combined config settings from all hgrc files
1738 """show combined config settings from all hgrc files
1740
1739
1741 With no arguments, print names and values of all config items.
1740 With no arguments, print names and values of all config items.
1742
1741
1743 With one argument of the form section.name, print just the value
1742 With one argument of the form section.name, print just the value
1744 of that config item.
1743 of that config item.
1745
1744
1746 With multiple arguments, print names and values of all config
1745 With multiple arguments, print names and values of all config
1747 items with matching section names.
1746 items with matching section names.
1748
1747
1749 With --edit, start an editor on the user-level config file. With
1748 With --edit, start an editor on the user-level config file. With
1750 --global, edit the system-wide config file. With --local, edit the
1749 --global, edit the system-wide config file. With --local, edit the
1751 repository-level config file.
1750 repository-level config file.
1752
1751
1753 With --debug, the source (filename and line number) is printed
1752 With --debug, the source (filename and line number) is printed
1754 for each config item.
1753 for each config item.
1755
1754
1756 See :hg:`help config` for more information about config files.
1755 See :hg:`help config` for more information about config files.
1757
1756
1758 Returns 0 on success, 1 if NAME does not exist.
1757 Returns 0 on success, 1 if NAME does not exist.
1759
1758
1760 """
1759 """
1761
1760
1762 if opts.get('edit') or opts.get('local') or opts.get('global'):
1761 if opts.get('edit') or opts.get('local') or opts.get('global'):
1763 if opts.get('local') and opts.get('global'):
1762 if opts.get('local') and opts.get('global'):
1764 raise error.Abort(_("can't use --local and --global together"))
1763 raise error.Abort(_("can't use --local and --global together"))
1765
1764
1766 if opts.get('local'):
1765 if opts.get('local'):
1767 if not repo:
1766 if not repo:
1768 raise error.Abort(_("can't use --local outside a repository"))
1767 raise error.Abort(_("can't use --local outside a repository"))
1769 paths = [repo.join('hgrc')]
1768 paths = [repo.join('hgrc')]
1770 elif opts.get('global'):
1769 elif opts.get('global'):
1771 paths = scmutil.systemrcpath()
1770 paths = scmutil.systemrcpath()
1772 else:
1771 else:
1773 paths = scmutil.userrcpath()
1772 paths = scmutil.userrcpath()
1774
1773
1775 for f in paths:
1774 for f in paths:
1776 if os.path.exists(f):
1775 if os.path.exists(f):
1777 break
1776 break
1778 else:
1777 else:
1779 if opts.get('global'):
1778 if opts.get('global'):
1780 samplehgrc = uimod.samplehgrcs['global']
1779 samplehgrc = uimod.samplehgrcs['global']
1781 elif opts.get('local'):
1780 elif opts.get('local'):
1782 samplehgrc = uimod.samplehgrcs['local']
1781 samplehgrc = uimod.samplehgrcs['local']
1783 else:
1782 else:
1784 samplehgrc = uimod.samplehgrcs['user']
1783 samplehgrc = uimod.samplehgrcs['user']
1785
1784
1786 f = paths[0]
1785 f = paths[0]
1787 fp = open(f, "w")
1786 fp = open(f, "w")
1788 fp.write(samplehgrc)
1787 fp.write(samplehgrc)
1789 fp.close()
1788 fp.close()
1790
1789
1791 editor = ui.geteditor()
1790 editor = ui.geteditor()
1792 ui.system("%s \"%s\"" % (editor, f),
1791 ui.system("%s \"%s\"" % (editor, f),
1793 onerr=error.Abort, errprefix=_("edit failed"))
1792 onerr=error.Abort, errprefix=_("edit failed"))
1794 return
1793 return
1795 ui.pager('config')
1794 ui.pager('config')
1796 fm = ui.formatter('config', opts)
1795 fm = ui.formatter('config', opts)
1797 for f in scmutil.rcpath():
1796 for f in scmutil.rcpath():
1798 ui.debug('read config from: %s\n' % f)
1797 ui.debug('read config from: %s\n' % f)
1799 untrusted = bool(opts.get('untrusted'))
1798 untrusted = bool(opts.get('untrusted'))
1800 if values:
1799 if values:
1801 sections = [v for v in values if '.' not in v]
1800 sections = [v for v in values if '.' not in v]
1802 items = [v for v in values if '.' in v]
1801 items = [v for v in values if '.' in v]
1803 if len(items) > 1 or items and sections:
1802 if len(items) > 1 or items and sections:
1804 raise error.Abort(_('only one config item permitted'))
1803 raise error.Abort(_('only one config item permitted'))
1805 matched = False
1804 matched = False
1806 for section, name, value in ui.walkconfig(untrusted=untrusted):
1805 for section, name, value in ui.walkconfig(untrusted=untrusted):
1807 source = ui.configsource(section, name, untrusted)
1806 source = ui.configsource(section, name, untrusted)
1808 value = str(value)
1807 value = str(value)
1809 if fm.isplain():
1808 if fm.isplain():
1810 source = source or 'none'
1809 source = source or 'none'
1811 value = value.replace('\n', '\\n')
1810 value = value.replace('\n', '\\n')
1812 entryname = section + '.' + name
1811 entryname = section + '.' + name
1813 if values:
1812 if values:
1814 for v in values:
1813 for v in values:
1815 if v == section:
1814 if v == section:
1816 fm.startitem()
1815 fm.startitem()
1817 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1816 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1818 fm.write('name value', '%s=%s\n', entryname, value)
1817 fm.write('name value', '%s=%s\n', entryname, value)
1819 matched = True
1818 matched = True
1820 elif v == entryname:
1819 elif v == entryname:
1821 fm.startitem()
1820 fm.startitem()
1822 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1821 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1823 fm.write('value', '%s\n', value)
1822 fm.write('value', '%s\n', value)
1824 fm.data(name=entryname)
1823 fm.data(name=entryname)
1825 matched = True
1824 matched = True
1826 else:
1825 else:
1827 fm.startitem()
1826 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1827 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 fm.write('name value', '%s=%s\n', entryname, value)
1828 fm.write('name value', '%s=%s\n', entryname, value)
1830 matched = True
1829 matched = True
1831 fm.end()
1830 fm.end()
1832 if matched:
1831 if matched:
1833 return 0
1832 return 0
1834 return 1
1833 return 1
1835
1834
1836 @command('copy|cp',
1835 @command('copy|cp',
1837 [('A', 'after', None, _('record a copy that has already occurred')),
1836 [('A', 'after', None, _('record a copy that has already occurred')),
1838 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1837 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1839 ] + walkopts + dryrunopts,
1838 ] + walkopts + dryrunopts,
1840 _('[OPTION]... [SOURCE]... DEST'))
1839 _('[OPTION]... [SOURCE]... DEST'))
1841 def copy(ui, repo, *pats, **opts):
1840 def copy(ui, repo, *pats, **opts):
1842 """mark files as copied for the next commit
1841 """mark files as copied for the next commit
1843
1842
1844 Mark dest as having copies of source files. If dest is a
1843 Mark dest as having copies of source files. If dest is a
1845 directory, copies are put in that directory. If dest is a file,
1844 directory, copies are put in that directory. If dest is a file,
1846 the source must be a single file.
1845 the source must be a single file.
1847
1846
1848 By default, this command copies the contents of files as they
1847 By default, this command copies the contents of files as they
1849 exist in the working directory. If invoked with -A/--after, the
1848 exist in the working directory. If invoked with -A/--after, the
1850 operation is recorded, but no copying is performed.
1849 operation is recorded, but no copying is performed.
1851
1850
1852 This command takes effect with the next commit. To undo a copy
1851 This command takes effect with the next commit. To undo a copy
1853 before that, see :hg:`revert`.
1852 before that, see :hg:`revert`.
1854
1853
1855 Returns 0 on success, 1 if errors are encountered.
1854 Returns 0 on success, 1 if errors are encountered.
1856 """
1855 """
1857 with repo.wlock(False):
1856 with repo.wlock(False):
1858 return cmdutil.copy(ui, repo, pats, opts)
1857 return cmdutil.copy(ui, repo, pats, opts)
1859
1858
1860 @command('^diff',
1859 @command('^diff',
1861 [('r', 'rev', [], _('revision'), _('REV')),
1860 [('r', 'rev', [], _('revision'), _('REV')),
1862 ('c', 'change', '', _('change made by revision'), _('REV'))
1861 ('c', 'change', '', _('change made by revision'), _('REV'))
1863 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1862 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1864 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1863 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1865 inferrepo=True)
1864 inferrepo=True)
1866 def diff(ui, repo, *pats, **opts):
1865 def diff(ui, repo, *pats, **opts):
1867 """diff repository (or selected files)
1866 """diff repository (or selected files)
1868
1867
1869 Show differences between revisions for the specified files.
1868 Show differences between revisions for the specified files.
1870
1869
1871 Differences between files are shown using the unified diff format.
1870 Differences between files are shown using the unified diff format.
1872
1871
1873 .. note::
1872 .. note::
1874
1873
1875 :hg:`diff` may generate unexpected results for merges, as it will
1874 :hg:`diff` may generate unexpected results for merges, as it will
1876 default to comparing against the working directory's first
1875 default to comparing against the working directory's first
1877 parent changeset if no revisions are specified.
1876 parent changeset if no revisions are specified.
1878
1877
1879 When two revision arguments are given, then changes are shown
1878 When two revision arguments are given, then changes are shown
1880 between those revisions. If only one revision is specified then
1879 between those revisions. If only one revision is specified then
1881 that revision is compared to the working directory, and, when no
1880 that revision is compared to the working directory, and, when no
1882 revisions are specified, the working directory files are compared
1881 revisions are specified, the working directory files are compared
1883 to its first parent.
1882 to its first parent.
1884
1883
1885 Alternatively you can specify -c/--change with a revision to see
1884 Alternatively you can specify -c/--change with a revision to see
1886 the changes in that changeset relative to its first parent.
1885 the changes in that changeset relative to its first parent.
1887
1886
1888 Without the -a/--text option, diff will avoid generating diffs of
1887 Without the -a/--text option, diff will avoid generating diffs of
1889 files it detects as binary. With -a, diff will generate a diff
1888 files it detects as binary. With -a, diff will generate a diff
1890 anyway, probably with undesirable results.
1889 anyway, probably with undesirable results.
1891
1890
1892 Use the -g/--git option to generate diffs in the git extended diff
1891 Use the -g/--git option to generate diffs in the git extended diff
1893 format. For more information, read :hg:`help diffs`.
1892 format. For more information, read :hg:`help diffs`.
1894
1893
1895 .. container:: verbose
1894 .. container:: verbose
1896
1895
1897 Examples:
1896 Examples:
1898
1897
1899 - compare a file in the current working directory to its parent::
1898 - compare a file in the current working directory to its parent::
1900
1899
1901 hg diff foo.c
1900 hg diff foo.c
1902
1901
1903 - compare two historical versions of a directory, with rename info::
1902 - compare two historical versions of a directory, with rename info::
1904
1903
1905 hg diff --git -r 1.0:1.2 lib/
1904 hg diff --git -r 1.0:1.2 lib/
1906
1905
1907 - get change stats relative to the last change on some date::
1906 - get change stats relative to the last change on some date::
1908
1907
1909 hg diff --stat -r "date('may 2')"
1908 hg diff --stat -r "date('may 2')"
1910
1909
1911 - diff all newly-added files that contain a keyword::
1910 - diff all newly-added files that contain a keyword::
1912
1911
1913 hg diff "set:added() and grep(GNU)"
1912 hg diff "set:added() and grep(GNU)"
1914
1913
1915 - compare a revision and its parents::
1914 - compare a revision and its parents::
1916
1915
1917 hg diff -c 9353 # compare against first parent
1916 hg diff -c 9353 # compare against first parent
1918 hg diff -r 9353^:9353 # same using revset syntax
1917 hg diff -r 9353^:9353 # same using revset syntax
1919 hg diff -r 9353^2:9353 # compare against the second parent
1918 hg diff -r 9353^2:9353 # compare against the second parent
1920
1919
1921 Returns 0 on success.
1920 Returns 0 on success.
1922 """
1921 """
1923
1922
1924 revs = opts.get('rev')
1923 revs = opts.get('rev')
1925 change = opts.get('change')
1924 change = opts.get('change')
1926 stat = opts.get('stat')
1925 stat = opts.get('stat')
1927 reverse = opts.get('reverse')
1926 reverse = opts.get('reverse')
1928
1927
1929 if revs and change:
1928 if revs and change:
1930 msg = _('cannot specify --rev and --change at the same time')
1929 msg = _('cannot specify --rev and --change at the same time')
1931 raise error.Abort(msg)
1930 raise error.Abort(msg)
1932 elif change:
1931 elif change:
1933 node2 = scmutil.revsingle(repo, change, None).node()
1932 node2 = scmutil.revsingle(repo, change, None).node()
1934 node1 = repo[node2].p1().node()
1933 node1 = repo[node2].p1().node()
1935 else:
1934 else:
1936 node1, node2 = scmutil.revpair(repo, revs)
1935 node1, node2 = scmutil.revpair(repo, revs)
1937
1936
1938 if reverse:
1937 if reverse:
1939 node1, node2 = node2, node1
1938 node1, node2 = node2, node1
1940
1939
1941 diffopts = patch.diffallopts(ui, opts)
1940 diffopts = patch.diffallopts(ui, opts)
1942 m = scmutil.match(repo[node2], pats, opts)
1941 m = scmutil.match(repo[node2], pats, opts)
1943 ui.pager('diff')
1942 ui.pager('diff')
1944 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1943 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1945 listsubrepos=opts.get('subrepos'),
1944 listsubrepos=opts.get('subrepos'),
1946 root=opts.get('root'))
1945 root=opts.get('root'))
1947
1946
1948 @command('^export',
1947 @command('^export',
1949 [('o', 'output', '',
1948 [('o', 'output', '',
1950 _('print output to file with formatted name'), _('FORMAT')),
1949 _('print output to file with formatted name'), _('FORMAT')),
1951 ('', 'switch-parent', None, _('diff against the second parent')),
1950 ('', 'switch-parent', None, _('diff against the second parent')),
1952 ('r', 'rev', [], _('revisions to export'), _('REV')),
1951 ('r', 'rev', [], _('revisions to export'), _('REV')),
1953 ] + diffopts,
1952 ] + diffopts,
1954 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1953 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1955 def export(ui, repo, *changesets, **opts):
1954 def export(ui, repo, *changesets, **opts):
1956 """dump the header and diffs for one or more changesets
1955 """dump the header and diffs for one or more changesets
1957
1956
1958 Print the changeset header and diffs for one or more revisions.
1957 Print the changeset header and diffs for one or more revisions.
1959 If no revision is given, the parent of the working directory is used.
1958 If no revision is given, the parent of the working directory is used.
1960
1959
1961 The information shown in the changeset header is: author, date,
1960 The information shown in the changeset header is: author, date,
1962 branch name (if non-default), changeset hash, parent(s) and commit
1961 branch name (if non-default), changeset hash, parent(s) and commit
1963 comment.
1962 comment.
1964
1963
1965 .. note::
1964 .. note::
1966
1965
1967 :hg:`export` may generate unexpected diff output for merge
1966 :hg:`export` may generate unexpected diff output for merge
1968 changesets, as it will compare the merge changeset against its
1967 changesets, as it will compare the merge changeset against its
1969 first parent only.
1968 first parent only.
1970
1969
1971 Output may be to a file, in which case the name of the file is
1970 Output may be to a file, in which case the name of the file is
1972 given using a format string. The formatting rules are as follows:
1971 given using a format string. The formatting rules are as follows:
1973
1972
1974 :``%%``: literal "%" character
1973 :``%%``: literal "%" character
1975 :``%H``: changeset hash (40 hexadecimal digits)
1974 :``%H``: changeset hash (40 hexadecimal digits)
1976 :``%N``: number of patches being generated
1975 :``%N``: number of patches being generated
1977 :``%R``: changeset revision number
1976 :``%R``: changeset revision number
1978 :``%b``: basename of the exporting repository
1977 :``%b``: basename of the exporting repository
1979 :``%h``: short-form changeset hash (12 hexadecimal digits)
1978 :``%h``: short-form changeset hash (12 hexadecimal digits)
1980 :``%m``: first line of the commit message (only alphanumeric characters)
1979 :``%m``: first line of the commit message (only alphanumeric characters)
1981 :``%n``: zero-padded sequence number, starting at 1
1980 :``%n``: zero-padded sequence number, starting at 1
1982 :``%r``: zero-padded changeset revision number
1981 :``%r``: zero-padded changeset revision number
1983
1982
1984 Without the -a/--text option, export will avoid generating diffs
1983 Without the -a/--text option, export will avoid generating diffs
1985 of files it detects as binary. With -a, export will generate a
1984 of files it detects as binary. With -a, export will generate a
1986 diff anyway, probably with undesirable results.
1985 diff anyway, probably with undesirable results.
1987
1986
1988 Use the -g/--git option to generate diffs in the git extended diff
1987 Use the -g/--git option to generate diffs in the git extended diff
1989 format. See :hg:`help diffs` for more information.
1988 format. See :hg:`help diffs` for more information.
1990
1989
1991 With the --switch-parent option, the diff will be against the
1990 With the --switch-parent option, the diff will be against the
1992 second parent. It can be useful to review a merge.
1991 second parent. It can be useful to review a merge.
1993
1992
1994 .. container:: verbose
1993 .. container:: verbose
1995
1994
1996 Examples:
1995 Examples:
1997
1996
1998 - use export and import to transplant a bugfix to the current
1997 - use export and import to transplant a bugfix to the current
1999 branch::
1998 branch::
2000
1999
2001 hg export -r 9353 | hg import -
2000 hg export -r 9353 | hg import -
2002
2001
2003 - export all the changesets between two revisions to a file with
2002 - export all the changesets between two revisions to a file with
2004 rename information::
2003 rename information::
2005
2004
2006 hg export --git -r 123:150 > changes.txt
2005 hg export --git -r 123:150 > changes.txt
2007
2006
2008 - split outgoing changes into a series of patches with
2007 - split outgoing changes into a series of patches with
2009 descriptive names::
2008 descriptive names::
2010
2009
2011 hg export -r "outgoing()" -o "%n-%m.patch"
2010 hg export -r "outgoing()" -o "%n-%m.patch"
2012
2011
2013 Returns 0 on success.
2012 Returns 0 on success.
2014 """
2013 """
2015 changesets += tuple(opts.get('rev', []))
2014 changesets += tuple(opts.get('rev', []))
2016 if not changesets:
2015 if not changesets:
2017 changesets = ['.']
2016 changesets = ['.']
2018 revs = scmutil.revrange(repo, changesets)
2017 revs = scmutil.revrange(repo, changesets)
2019 if not revs:
2018 if not revs:
2020 raise error.Abort(_("export requires at least one changeset"))
2019 raise error.Abort(_("export requires at least one changeset"))
2021 if len(revs) > 1:
2020 if len(revs) > 1:
2022 ui.note(_('exporting patches:\n'))
2021 ui.note(_('exporting patches:\n'))
2023 else:
2022 else:
2024 ui.note(_('exporting patch:\n'))
2023 ui.note(_('exporting patch:\n'))
2025 ui.pager('export')
2024 ui.pager('export')
2026 cmdutil.export(repo, revs, template=opts.get('output'),
2025 cmdutil.export(repo, revs, template=opts.get('output'),
2027 switch_parent=opts.get('switch_parent'),
2026 switch_parent=opts.get('switch_parent'),
2028 opts=patch.diffallopts(ui, opts))
2027 opts=patch.diffallopts(ui, opts))
2029
2028
2030 @command('files',
2029 @command('files',
2031 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2030 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2032 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2031 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2033 ] + walkopts + formatteropts + subrepoopts,
2032 ] + walkopts + formatteropts + subrepoopts,
2034 _('[OPTION]... [FILE]...'))
2033 _('[OPTION]... [FILE]...'))
2035 def files(ui, repo, *pats, **opts):
2034 def files(ui, repo, *pats, **opts):
2036 """list tracked files
2035 """list tracked files
2037
2036
2038 Print files under Mercurial control in the working directory or
2037 Print files under Mercurial control in the working directory or
2039 specified revision for given files (excluding removed files).
2038 specified revision for given files (excluding removed files).
2040 Files can be specified as filenames or filesets.
2039 Files can be specified as filenames or filesets.
2041
2040
2042 If no files are given to match, this command prints the names
2041 If no files are given to match, this command prints the names
2043 of all files under Mercurial control.
2042 of all files under Mercurial control.
2044
2043
2045 .. container:: verbose
2044 .. container:: verbose
2046
2045
2047 Examples:
2046 Examples:
2048
2047
2049 - list all files under the current directory::
2048 - list all files under the current directory::
2050
2049
2051 hg files .
2050 hg files .
2052
2051
2053 - shows sizes and flags for current revision::
2052 - shows sizes and flags for current revision::
2054
2053
2055 hg files -vr .
2054 hg files -vr .
2056
2055
2057 - list all files named README::
2056 - list all files named README::
2058
2057
2059 hg files -I "**/README"
2058 hg files -I "**/README"
2060
2059
2061 - list all binary files::
2060 - list all binary files::
2062
2061
2063 hg files "set:binary()"
2062 hg files "set:binary()"
2064
2063
2065 - find files containing a regular expression::
2064 - find files containing a regular expression::
2066
2065
2067 hg files "set:grep('bob')"
2066 hg files "set:grep('bob')"
2068
2067
2069 - search tracked file contents with xargs and grep::
2068 - search tracked file contents with xargs and grep::
2070
2069
2071 hg files -0 | xargs -0 grep foo
2070 hg files -0 | xargs -0 grep foo
2072
2071
2073 See :hg:`help patterns` and :hg:`help filesets` for more information
2072 See :hg:`help patterns` and :hg:`help filesets` for more information
2074 on specifying file patterns.
2073 on specifying file patterns.
2075
2074
2076 Returns 0 if a match is found, 1 otherwise.
2075 Returns 0 if a match is found, 1 otherwise.
2077
2076
2078 """
2077 """
2079 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2078 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2080
2079
2081 end = '\n'
2080 end = '\n'
2082 if opts.get('print0'):
2081 if opts.get('print0'):
2083 end = '\0'
2082 end = '\0'
2084 fmt = '%s' + end
2083 fmt = '%s' + end
2085
2084
2086 m = scmutil.match(ctx, pats, opts)
2085 m = scmutil.match(ctx, pats, opts)
2087 ui.pager('files')
2086 ui.pager('files')
2088 with ui.formatter('files', opts) as fm:
2087 with ui.formatter('files', opts) as fm:
2089 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2088 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2090
2089
2091 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2090 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2092 def forget(ui, repo, *pats, **opts):
2091 def forget(ui, repo, *pats, **opts):
2093 """forget the specified files on the next commit
2092 """forget the specified files on the next commit
2094
2093
2095 Mark the specified files so they will no longer be tracked
2094 Mark the specified files so they will no longer be tracked
2096 after the next commit.
2095 after the next commit.
2097
2096
2098 This only removes files from the current branch, not from the
2097 This only removes files from the current branch, not from the
2099 entire project history, and it does not delete them from the
2098 entire project history, and it does not delete them from the
2100 working directory.
2099 working directory.
2101
2100
2102 To delete the file from the working directory, see :hg:`remove`.
2101 To delete the file from the working directory, see :hg:`remove`.
2103
2102
2104 To undo a forget before the next commit, see :hg:`add`.
2103 To undo a forget before the next commit, see :hg:`add`.
2105
2104
2106 .. container:: verbose
2105 .. container:: verbose
2107
2106
2108 Examples:
2107 Examples:
2109
2108
2110 - forget newly-added binary files::
2109 - forget newly-added binary files::
2111
2110
2112 hg forget "set:added() and binary()"
2111 hg forget "set:added() and binary()"
2113
2112
2114 - forget files that would be excluded by .hgignore::
2113 - forget files that would be excluded by .hgignore::
2115
2114
2116 hg forget "set:hgignore()"
2115 hg forget "set:hgignore()"
2117
2116
2118 Returns 0 on success.
2117 Returns 0 on success.
2119 """
2118 """
2120
2119
2121 if not pats:
2120 if not pats:
2122 raise error.Abort(_('no files specified'))
2121 raise error.Abort(_('no files specified'))
2123
2122
2124 m = scmutil.match(repo[None], pats, opts)
2123 m = scmutil.match(repo[None], pats, opts)
2125 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2124 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2126 return rejected and 1 or 0
2125 return rejected and 1 or 0
2127
2126
2128 @command(
2127 @command(
2129 'graft',
2128 'graft',
2130 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2129 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2131 ('c', 'continue', False, _('resume interrupted graft')),
2130 ('c', 'continue', False, _('resume interrupted graft')),
2132 ('e', 'edit', False, _('invoke editor on commit messages')),
2131 ('e', 'edit', False, _('invoke editor on commit messages')),
2133 ('', 'log', None, _('append graft info to log message')),
2132 ('', 'log', None, _('append graft info to log message')),
2134 ('f', 'force', False, _('force graft')),
2133 ('f', 'force', False, _('force graft')),
2135 ('D', 'currentdate', False,
2134 ('D', 'currentdate', False,
2136 _('record the current date as commit date')),
2135 _('record the current date as commit date')),
2137 ('U', 'currentuser', False,
2136 ('U', 'currentuser', False,
2138 _('record the current user as committer'), _('DATE'))]
2137 _('record the current user as committer'), _('DATE'))]
2139 + commitopts2 + mergetoolopts + dryrunopts,
2138 + commitopts2 + mergetoolopts + dryrunopts,
2140 _('[OPTION]... [-r REV]... REV...'))
2139 _('[OPTION]... [-r REV]... REV...'))
2141 def graft(ui, repo, *revs, **opts):
2140 def graft(ui, repo, *revs, **opts):
2142 '''copy changes from other branches onto the current branch
2141 '''copy changes from other branches onto the current branch
2143
2142
2144 This command uses Mercurial's merge logic to copy individual
2143 This command uses Mercurial's merge logic to copy individual
2145 changes from other branches without merging branches in the
2144 changes from other branches without merging branches in the
2146 history graph. This is sometimes known as 'backporting' or
2145 history graph. This is sometimes known as 'backporting' or
2147 'cherry-picking'. By default, graft will copy user, date, and
2146 'cherry-picking'. By default, graft will copy user, date, and
2148 description from the source changesets.
2147 description from the source changesets.
2149
2148
2150 Changesets that are ancestors of the current revision, that have
2149 Changesets that are ancestors of the current revision, that have
2151 already been grafted, or that are merges will be skipped.
2150 already been grafted, or that are merges will be skipped.
2152
2151
2153 If --log is specified, log messages will have a comment appended
2152 If --log is specified, log messages will have a comment appended
2154 of the form::
2153 of the form::
2155
2154
2156 (grafted from CHANGESETHASH)
2155 (grafted from CHANGESETHASH)
2157
2156
2158 If --force is specified, revisions will be grafted even if they
2157 If --force is specified, revisions will be grafted even if they
2159 are already ancestors of or have been grafted to the destination.
2158 are already ancestors of or have been grafted to the destination.
2160 This is useful when the revisions have since been backed out.
2159 This is useful when the revisions have since been backed out.
2161
2160
2162 If a graft merge results in conflicts, the graft process is
2161 If a graft merge results in conflicts, the graft process is
2163 interrupted so that the current merge can be manually resolved.
2162 interrupted so that the current merge can be manually resolved.
2164 Once all conflicts are addressed, the graft process can be
2163 Once all conflicts are addressed, the graft process can be
2165 continued with the -c/--continue option.
2164 continued with the -c/--continue option.
2166
2165
2167 .. note::
2166 .. note::
2168
2167
2169 The -c/--continue option does not reapply earlier options, except
2168 The -c/--continue option does not reapply earlier options, except
2170 for --force.
2169 for --force.
2171
2170
2172 .. container:: verbose
2171 .. container:: verbose
2173
2172
2174 Examples:
2173 Examples:
2175
2174
2176 - copy a single change to the stable branch and edit its description::
2175 - copy a single change to the stable branch and edit its description::
2177
2176
2178 hg update stable
2177 hg update stable
2179 hg graft --edit 9393
2178 hg graft --edit 9393
2180
2179
2181 - graft a range of changesets with one exception, updating dates::
2180 - graft a range of changesets with one exception, updating dates::
2182
2181
2183 hg graft -D "2085::2093 and not 2091"
2182 hg graft -D "2085::2093 and not 2091"
2184
2183
2185 - continue a graft after resolving conflicts::
2184 - continue a graft after resolving conflicts::
2186
2185
2187 hg graft -c
2186 hg graft -c
2188
2187
2189 - show the source of a grafted changeset::
2188 - show the source of a grafted changeset::
2190
2189
2191 hg log --debug -r .
2190 hg log --debug -r .
2192
2191
2193 - show revisions sorted by date::
2192 - show revisions sorted by date::
2194
2193
2195 hg log -r "sort(all(), date)"
2194 hg log -r "sort(all(), date)"
2196
2195
2197 See :hg:`help revisions` for more about specifying revisions.
2196 See :hg:`help revisions` for more about specifying revisions.
2198
2197
2199 Returns 0 on successful completion.
2198 Returns 0 on successful completion.
2200 '''
2199 '''
2201 with repo.wlock():
2200 with repo.wlock():
2202 return _dograft(ui, repo, *revs, **opts)
2201 return _dograft(ui, repo, *revs, **opts)
2203
2202
2204 def _dograft(ui, repo, *revs, **opts):
2203 def _dograft(ui, repo, *revs, **opts):
2205 if revs and opts.get('rev'):
2204 if revs and opts.get('rev'):
2206 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2205 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2207 'revision ordering!\n'))
2206 'revision ordering!\n'))
2208
2207
2209 revs = list(revs)
2208 revs = list(revs)
2210 revs.extend(opts.get('rev'))
2209 revs.extend(opts.get('rev'))
2211
2210
2212 if not opts.get('user') and opts.get('currentuser'):
2211 if not opts.get('user') and opts.get('currentuser'):
2213 opts['user'] = ui.username()
2212 opts['user'] = ui.username()
2214 if not opts.get('date') and opts.get('currentdate'):
2213 if not opts.get('date') and opts.get('currentdate'):
2215 opts['date'] = "%d %d" % util.makedate()
2214 opts['date'] = "%d %d" % util.makedate()
2216
2215
2217 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2216 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2218
2217
2219 cont = False
2218 cont = False
2220 if opts.get('continue'):
2219 if opts.get('continue'):
2221 cont = True
2220 cont = True
2222 if revs:
2221 if revs:
2223 raise error.Abort(_("can't specify --continue and revisions"))
2222 raise error.Abort(_("can't specify --continue and revisions"))
2224 # read in unfinished revisions
2223 # read in unfinished revisions
2225 try:
2224 try:
2226 nodes = repo.vfs.read('graftstate').splitlines()
2225 nodes = repo.vfs.read('graftstate').splitlines()
2227 revs = [repo[node].rev() for node in nodes]
2226 revs = [repo[node].rev() for node in nodes]
2228 except IOError as inst:
2227 except IOError as inst:
2229 if inst.errno != errno.ENOENT:
2228 if inst.errno != errno.ENOENT:
2230 raise
2229 raise
2231 cmdutil.wrongtooltocontinue(repo, _('graft'))
2230 cmdutil.wrongtooltocontinue(repo, _('graft'))
2232 else:
2231 else:
2233 cmdutil.checkunfinished(repo)
2232 cmdutil.checkunfinished(repo)
2234 cmdutil.bailifchanged(repo)
2233 cmdutil.bailifchanged(repo)
2235 if not revs:
2234 if not revs:
2236 raise error.Abort(_('no revisions specified'))
2235 raise error.Abort(_('no revisions specified'))
2237 revs = scmutil.revrange(repo, revs)
2236 revs = scmutil.revrange(repo, revs)
2238
2237
2239 skipped = set()
2238 skipped = set()
2240 # check for merges
2239 # check for merges
2241 for rev in repo.revs('%ld and merge()', revs):
2240 for rev in repo.revs('%ld and merge()', revs):
2242 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2241 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2243 skipped.add(rev)
2242 skipped.add(rev)
2244 revs = [r for r in revs if r not in skipped]
2243 revs = [r for r in revs if r not in skipped]
2245 if not revs:
2244 if not revs:
2246 return -1
2245 return -1
2247
2246
2248 # Don't check in the --continue case, in effect retaining --force across
2247 # Don't check in the --continue case, in effect retaining --force across
2249 # --continues. That's because without --force, any revisions we decided to
2248 # --continues. That's because without --force, any revisions we decided to
2250 # skip would have been filtered out here, so they wouldn't have made their
2249 # skip would have been filtered out here, so they wouldn't have made their
2251 # way to the graftstate. With --force, any revisions we would have otherwise
2250 # way to the graftstate. With --force, any revisions we would have otherwise
2252 # skipped would not have been filtered out, and if they hadn't been applied
2251 # skipped would not have been filtered out, and if they hadn't been applied
2253 # already, they'd have been in the graftstate.
2252 # already, they'd have been in the graftstate.
2254 if not (cont or opts.get('force')):
2253 if not (cont or opts.get('force')):
2255 # check for ancestors of dest branch
2254 # check for ancestors of dest branch
2256 crev = repo['.'].rev()
2255 crev = repo['.'].rev()
2257 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2256 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2258 # XXX make this lazy in the future
2257 # XXX make this lazy in the future
2259 # don't mutate while iterating, create a copy
2258 # don't mutate while iterating, create a copy
2260 for rev in list(revs):
2259 for rev in list(revs):
2261 if rev in ancestors:
2260 if rev in ancestors:
2262 ui.warn(_('skipping ancestor revision %d:%s\n') %
2261 ui.warn(_('skipping ancestor revision %d:%s\n') %
2263 (rev, repo[rev]))
2262 (rev, repo[rev]))
2264 # XXX remove on list is slow
2263 # XXX remove on list is slow
2265 revs.remove(rev)
2264 revs.remove(rev)
2266 if not revs:
2265 if not revs:
2267 return -1
2266 return -1
2268
2267
2269 # analyze revs for earlier grafts
2268 # analyze revs for earlier grafts
2270 ids = {}
2269 ids = {}
2271 for ctx in repo.set("%ld", revs):
2270 for ctx in repo.set("%ld", revs):
2272 ids[ctx.hex()] = ctx.rev()
2271 ids[ctx.hex()] = ctx.rev()
2273 n = ctx.extra().get('source')
2272 n = ctx.extra().get('source')
2274 if n:
2273 if n:
2275 ids[n] = ctx.rev()
2274 ids[n] = ctx.rev()
2276
2275
2277 # check ancestors for earlier grafts
2276 # check ancestors for earlier grafts
2278 ui.debug('scanning for duplicate grafts\n')
2277 ui.debug('scanning for duplicate grafts\n')
2279
2278
2280 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2279 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2281 ctx = repo[rev]
2280 ctx = repo[rev]
2282 n = ctx.extra().get('source')
2281 n = ctx.extra().get('source')
2283 if n in ids:
2282 if n in ids:
2284 try:
2283 try:
2285 r = repo[n].rev()
2284 r = repo[n].rev()
2286 except error.RepoLookupError:
2285 except error.RepoLookupError:
2287 r = None
2286 r = None
2288 if r in revs:
2287 if r in revs:
2289 ui.warn(_('skipping revision %d:%s '
2288 ui.warn(_('skipping revision %d:%s '
2290 '(already grafted to %d:%s)\n')
2289 '(already grafted to %d:%s)\n')
2291 % (r, repo[r], rev, ctx))
2290 % (r, repo[r], rev, ctx))
2292 revs.remove(r)
2291 revs.remove(r)
2293 elif ids[n] in revs:
2292 elif ids[n] in revs:
2294 if r is None:
2293 if r is None:
2295 ui.warn(_('skipping already grafted revision %d:%s '
2294 ui.warn(_('skipping already grafted revision %d:%s '
2296 '(%d:%s also has unknown origin %s)\n')
2295 '(%d:%s also has unknown origin %s)\n')
2297 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2296 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2298 else:
2297 else:
2299 ui.warn(_('skipping already grafted revision %d:%s '
2298 ui.warn(_('skipping already grafted revision %d:%s '
2300 '(%d:%s also has origin %d:%s)\n')
2299 '(%d:%s also has origin %d:%s)\n')
2301 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2300 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2302 revs.remove(ids[n])
2301 revs.remove(ids[n])
2303 elif ctx.hex() in ids:
2302 elif ctx.hex() in ids:
2304 r = ids[ctx.hex()]
2303 r = ids[ctx.hex()]
2305 ui.warn(_('skipping already grafted revision %d:%s '
2304 ui.warn(_('skipping already grafted revision %d:%s '
2306 '(was grafted from %d:%s)\n') %
2305 '(was grafted from %d:%s)\n') %
2307 (r, repo[r], rev, ctx))
2306 (r, repo[r], rev, ctx))
2308 revs.remove(r)
2307 revs.remove(r)
2309 if not revs:
2308 if not revs:
2310 return -1
2309 return -1
2311
2310
2312 for pos, ctx in enumerate(repo.set("%ld", revs)):
2311 for pos, ctx in enumerate(repo.set("%ld", revs)):
2313 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2312 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2314 ctx.description().split('\n', 1)[0])
2313 ctx.description().split('\n', 1)[0])
2315 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2314 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2316 if names:
2315 if names:
2317 desc += ' (%s)' % ' '.join(names)
2316 desc += ' (%s)' % ' '.join(names)
2318 ui.status(_('grafting %s\n') % desc)
2317 ui.status(_('grafting %s\n') % desc)
2319 if opts.get('dry_run'):
2318 if opts.get('dry_run'):
2320 continue
2319 continue
2321
2320
2322 source = ctx.extra().get('source')
2321 source = ctx.extra().get('source')
2323 extra = {}
2322 extra = {}
2324 if source:
2323 if source:
2325 extra['source'] = source
2324 extra['source'] = source
2326 extra['intermediate-source'] = ctx.hex()
2325 extra['intermediate-source'] = ctx.hex()
2327 else:
2326 else:
2328 extra['source'] = ctx.hex()
2327 extra['source'] = ctx.hex()
2329 user = ctx.user()
2328 user = ctx.user()
2330 if opts.get('user'):
2329 if opts.get('user'):
2331 user = opts['user']
2330 user = opts['user']
2332 date = ctx.date()
2331 date = ctx.date()
2333 if opts.get('date'):
2332 if opts.get('date'):
2334 date = opts['date']
2333 date = opts['date']
2335 message = ctx.description()
2334 message = ctx.description()
2336 if opts.get('log'):
2335 if opts.get('log'):
2337 message += '\n(grafted from %s)' % ctx.hex()
2336 message += '\n(grafted from %s)' % ctx.hex()
2338
2337
2339 # we don't merge the first commit when continuing
2338 # we don't merge the first commit when continuing
2340 if not cont:
2339 if not cont:
2341 # perform the graft merge with p1(rev) as 'ancestor'
2340 # perform the graft merge with p1(rev) as 'ancestor'
2342 try:
2341 try:
2343 # ui.forcemerge is an internal variable, do not document
2342 # ui.forcemerge is an internal variable, do not document
2344 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2343 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2345 'graft')
2344 'graft')
2346 stats = mergemod.graft(repo, ctx, ctx.p1(),
2345 stats = mergemod.graft(repo, ctx, ctx.p1(),
2347 ['local', 'graft'])
2346 ['local', 'graft'])
2348 finally:
2347 finally:
2349 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2348 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2350 # report any conflicts
2349 # report any conflicts
2351 if stats and stats[3] > 0:
2350 if stats and stats[3] > 0:
2352 # write out state for --continue
2351 # write out state for --continue
2353 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2352 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2354 repo.vfs.write('graftstate', ''.join(nodelines))
2353 repo.vfs.write('graftstate', ''.join(nodelines))
2355 extra = ''
2354 extra = ''
2356 if opts.get('user'):
2355 if opts.get('user'):
2357 extra += ' --user %s' % util.shellquote(opts['user'])
2356 extra += ' --user %s' % util.shellquote(opts['user'])
2358 if opts.get('date'):
2357 if opts.get('date'):
2359 extra += ' --date %s' % util.shellquote(opts['date'])
2358 extra += ' --date %s' % util.shellquote(opts['date'])
2360 if opts.get('log'):
2359 if opts.get('log'):
2361 extra += ' --log'
2360 extra += ' --log'
2362 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2361 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2363 raise error.Abort(
2362 raise error.Abort(
2364 _("unresolved conflicts, can't continue"),
2363 _("unresolved conflicts, can't continue"),
2365 hint=hint)
2364 hint=hint)
2366 else:
2365 else:
2367 cont = False
2366 cont = False
2368
2367
2369 # commit
2368 # commit
2370 node = repo.commit(text=message, user=user,
2369 node = repo.commit(text=message, user=user,
2371 date=date, extra=extra, editor=editor)
2370 date=date, extra=extra, editor=editor)
2372 if node is None:
2371 if node is None:
2373 ui.warn(
2372 ui.warn(
2374 _('note: graft of %d:%s created no changes to commit\n') %
2373 _('note: graft of %d:%s created no changes to commit\n') %
2375 (ctx.rev(), ctx))
2374 (ctx.rev(), ctx))
2376
2375
2377 # remove state when we complete successfully
2376 # remove state when we complete successfully
2378 if not opts.get('dry_run'):
2377 if not opts.get('dry_run'):
2379 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2378 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2380
2379
2381 return 0
2380 return 0
2382
2381
2383 @command('grep',
2382 @command('grep',
2384 [('0', 'print0', None, _('end fields with NUL')),
2383 [('0', 'print0', None, _('end fields with NUL')),
2385 ('', 'all', None, _('print all revisions that match')),
2384 ('', 'all', None, _('print all revisions that match')),
2386 ('a', 'text', None, _('treat all files as text')),
2385 ('a', 'text', None, _('treat all files as text')),
2387 ('f', 'follow', None,
2386 ('f', 'follow', None,
2388 _('follow changeset history,'
2387 _('follow changeset history,'
2389 ' or file history across copies and renames')),
2388 ' or file history across copies and renames')),
2390 ('i', 'ignore-case', None, _('ignore case when matching')),
2389 ('i', 'ignore-case', None, _('ignore case when matching')),
2391 ('l', 'files-with-matches', None,
2390 ('l', 'files-with-matches', None,
2392 _('print only filenames and revisions that match')),
2391 _('print only filenames and revisions that match')),
2393 ('n', 'line-number', None, _('print matching line numbers')),
2392 ('n', 'line-number', None, _('print matching line numbers')),
2394 ('r', 'rev', [],
2393 ('r', 'rev', [],
2395 _('only search files changed within revision range'), _('REV')),
2394 _('only search files changed within revision range'), _('REV')),
2396 ('u', 'user', None, _('list the author (long with -v)')),
2395 ('u', 'user', None, _('list the author (long with -v)')),
2397 ('d', 'date', None, _('list the date (short with -q)')),
2396 ('d', 'date', None, _('list the date (short with -q)')),
2398 ] + formatteropts + walkopts,
2397 ] + formatteropts + walkopts,
2399 _('[OPTION]... PATTERN [FILE]...'),
2398 _('[OPTION]... PATTERN [FILE]...'),
2400 inferrepo=True)
2399 inferrepo=True)
2401 def grep(ui, repo, pattern, *pats, **opts):
2400 def grep(ui, repo, pattern, *pats, **opts):
2402 """search revision history for a pattern in specified files
2401 """search revision history for a pattern in specified files
2403
2402
2404 Search revision history for a regular expression in the specified
2403 Search revision history for a regular expression in the specified
2405 files or the entire project.
2404 files or the entire project.
2406
2405
2407 By default, grep prints the most recent revision number for each
2406 By default, grep prints the most recent revision number for each
2408 file in which it finds a match. To get it to print every revision
2407 file in which it finds a match. To get it to print every revision
2409 that contains a change in match status ("-" for a match that becomes
2408 that contains a change in match status ("-" for a match that becomes
2410 a non-match, or "+" for a non-match that becomes a match), use the
2409 a non-match, or "+" for a non-match that becomes a match), use the
2411 --all flag.
2410 --all flag.
2412
2411
2413 PATTERN can be any Python (roughly Perl-compatible) regular
2412 PATTERN can be any Python (roughly Perl-compatible) regular
2414 expression.
2413 expression.
2415
2414
2416 If no FILEs are specified (and -f/--follow isn't set), all files in
2415 If no FILEs are specified (and -f/--follow isn't set), all files in
2417 the repository are searched, including those that don't exist in the
2416 the repository are searched, including those that don't exist in the
2418 current branch or have been deleted in a prior changeset.
2417 current branch or have been deleted in a prior changeset.
2419
2418
2420 Returns 0 if a match is found, 1 otherwise.
2419 Returns 0 if a match is found, 1 otherwise.
2421 """
2420 """
2422 reflags = re.M
2421 reflags = re.M
2423 if opts.get('ignore_case'):
2422 if opts.get('ignore_case'):
2424 reflags |= re.I
2423 reflags |= re.I
2425 try:
2424 try:
2426 regexp = util.re.compile(pattern, reflags)
2425 regexp = util.re.compile(pattern, reflags)
2427 except re.error as inst:
2426 except re.error as inst:
2428 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2427 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2429 return 1
2428 return 1
2430 sep, eol = ':', '\n'
2429 sep, eol = ':', '\n'
2431 if opts.get('print0'):
2430 if opts.get('print0'):
2432 sep = eol = '\0'
2431 sep = eol = '\0'
2433
2432
2434 getfile = util.lrucachefunc(repo.file)
2433 getfile = util.lrucachefunc(repo.file)
2435
2434
2436 def matchlines(body):
2435 def matchlines(body):
2437 begin = 0
2436 begin = 0
2438 linenum = 0
2437 linenum = 0
2439 while begin < len(body):
2438 while begin < len(body):
2440 match = regexp.search(body, begin)
2439 match = regexp.search(body, begin)
2441 if not match:
2440 if not match:
2442 break
2441 break
2443 mstart, mend = match.span()
2442 mstart, mend = match.span()
2444 linenum += body.count('\n', begin, mstart) + 1
2443 linenum += body.count('\n', begin, mstart) + 1
2445 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2444 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2446 begin = body.find('\n', mend) + 1 or len(body) + 1
2445 begin = body.find('\n', mend) + 1 or len(body) + 1
2447 lend = begin - 1
2446 lend = begin - 1
2448 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2447 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2449
2448
2450 class linestate(object):
2449 class linestate(object):
2451 def __init__(self, line, linenum, colstart, colend):
2450 def __init__(self, line, linenum, colstart, colend):
2452 self.line = line
2451 self.line = line
2453 self.linenum = linenum
2452 self.linenum = linenum
2454 self.colstart = colstart
2453 self.colstart = colstart
2455 self.colend = colend
2454 self.colend = colend
2456
2455
2457 def __hash__(self):
2456 def __hash__(self):
2458 return hash((self.linenum, self.line))
2457 return hash((self.linenum, self.line))
2459
2458
2460 def __eq__(self, other):
2459 def __eq__(self, other):
2461 return self.line == other.line
2460 return self.line == other.line
2462
2461
2463 def findpos(self):
2462 def findpos(self):
2464 """Iterate all (start, end) indices of matches"""
2463 """Iterate all (start, end) indices of matches"""
2465 yield self.colstart, self.colend
2464 yield self.colstart, self.colend
2466 p = self.colend
2465 p = self.colend
2467 while p < len(self.line):
2466 while p < len(self.line):
2468 m = regexp.search(self.line, p)
2467 m = regexp.search(self.line, p)
2469 if not m:
2468 if not m:
2470 break
2469 break
2471 yield m.span()
2470 yield m.span()
2472 p = m.end()
2471 p = m.end()
2473
2472
2474 matches = {}
2473 matches = {}
2475 copies = {}
2474 copies = {}
2476 def grepbody(fn, rev, body):
2475 def grepbody(fn, rev, body):
2477 matches[rev].setdefault(fn, [])
2476 matches[rev].setdefault(fn, [])
2478 m = matches[rev][fn]
2477 m = matches[rev][fn]
2479 for lnum, cstart, cend, line in matchlines(body):
2478 for lnum, cstart, cend, line in matchlines(body):
2480 s = linestate(line, lnum, cstart, cend)
2479 s = linestate(line, lnum, cstart, cend)
2481 m.append(s)
2480 m.append(s)
2482
2481
2483 def difflinestates(a, b):
2482 def difflinestates(a, b):
2484 sm = difflib.SequenceMatcher(None, a, b)
2483 sm = difflib.SequenceMatcher(None, a, b)
2485 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2484 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2486 if tag == 'insert':
2485 if tag == 'insert':
2487 for i in xrange(blo, bhi):
2486 for i in xrange(blo, bhi):
2488 yield ('+', b[i])
2487 yield ('+', b[i])
2489 elif tag == 'delete':
2488 elif tag == 'delete':
2490 for i in xrange(alo, ahi):
2489 for i in xrange(alo, ahi):
2491 yield ('-', a[i])
2490 yield ('-', a[i])
2492 elif tag == 'replace':
2491 elif tag == 'replace':
2493 for i in xrange(alo, ahi):
2492 for i in xrange(alo, ahi):
2494 yield ('-', a[i])
2493 yield ('-', a[i])
2495 for i in xrange(blo, bhi):
2494 for i in xrange(blo, bhi):
2496 yield ('+', b[i])
2495 yield ('+', b[i])
2497
2496
2498 def display(fm, fn, ctx, pstates, states):
2497 def display(fm, fn, ctx, pstates, states):
2499 rev = ctx.rev()
2498 rev = ctx.rev()
2500 if fm.isplain():
2499 if fm.isplain():
2501 formatuser = ui.shortuser
2500 formatuser = ui.shortuser
2502 else:
2501 else:
2503 formatuser = str
2502 formatuser = str
2504 if ui.quiet:
2503 if ui.quiet:
2505 datefmt = '%Y-%m-%d'
2504 datefmt = '%Y-%m-%d'
2506 else:
2505 else:
2507 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2506 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2508 found = False
2507 found = False
2509 @util.cachefunc
2508 @util.cachefunc
2510 def binary():
2509 def binary():
2511 flog = getfile(fn)
2510 flog = getfile(fn)
2512 return util.binary(flog.read(ctx.filenode(fn)))
2511 return util.binary(flog.read(ctx.filenode(fn)))
2513
2512
2514 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2513 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2515 if opts.get('all'):
2514 if opts.get('all'):
2516 iter = difflinestates(pstates, states)
2515 iter = difflinestates(pstates, states)
2517 else:
2516 else:
2518 iter = [('', l) for l in states]
2517 iter = [('', l) for l in states]
2519 for change, l in iter:
2518 for change, l in iter:
2520 fm.startitem()
2519 fm.startitem()
2521 fm.data(node=fm.hexfunc(ctx.node()))
2520 fm.data(node=fm.hexfunc(ctx.node()))
2522 cols = [
2521 cols = [
2523 ('filename', fn, True),
2522 ('filename', fn, True),
2524 ('rev', rev, True),
2523 ('rev', rev, True),
2525 ('linenumber', l.linenum, opts.get('line_number')),
2524 ('linenumber', l.linenum, opts.get('line_number')),
2526 ]
2525 ]
2527 if opts.get('all'):
2526 if opts.get('all'):
2528 cols.append(('change', change, True))
2527 cols.append(('change', change, True))
2529 cols.extend([
2528 cols.extend([
2530 ('user', formatuser(ctx.user()), opts.get('user')),
2529 ('user', formatuser(ctx.user()), opts.get('user')),
2531 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2530 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2532 ])
2531 ])
2533 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2532 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2534 for name, data, cond in cols:
2533 for name, data, cond in cols:
2535 field = fieldnamemap.get(name, name)
2534 field = fieldnamemap.get(name, name)
2536 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2535 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2537 if cond and name != lastcol:
2536 if cond and name != lastcol:
2538 fm.plain(sep, label='grep.sep')
2537 fm.plain(sep, label='grep.sep')
2539 if not opts.get('files_with_matches'):
2538 if not opts.get('files_with_matches'):
2540 fm.plain(sep, label='grep.sep')
2539 fm.plain(sep, label='grep.sep')
2541 if not opts.get('text') and binary():
2540 if not opts.get('text') and binary():
2542 fm.plain(_(" Binary file matches"))
2541 fm.plain(_(" Binary file matches"))
2543 else:
2542 else:
2544 displaymatches(fm.nested('texts'), l)
2543 displaymatches(fm.nested('texts'), l)
2545 fm.plain(eol)
2544 fm.plain(eol)
2546 found = True
2545 found = True
2547 if opts.get('files_with_matches'):
2546 if opts.get('files_with_matches'):
2548 break
2547 break
2549 return found
2548 return found
2550
2549
2551 def displaymatches(fm, l):
2550 def displaymatches(fm, l):
2552 p = 0
2551 p = 0
2553 for s, e in l.findpos():
2552 for s, e in l.findpos():
2554 if p < s:
2553 if p < s:
2555 fm.startitem()
2554 fm.startitem()
2556 fm.write('text', '%s', l.line[p:s])
2555 fm.write('text', '%s', l.line[p:s])
2557 fm.data(matched=False)
2556 fm.data(matched=False)
2558 fm.startitem()
2557 fm.startitem()
2559 fm.write('text', '%s', l.line[s:e], label='grep.match')
2558 fm.write('text', '%s', l.line[s:e], label='grep.match')
2560 fm.data(matched=True)
2559 fm.data(matched=True)
2561 p = e
2560 p = e
2562 if p < len(l.line):
2561 if p < len(l.line):
2563 fm.startitem()
2562 fm.startitem()
2564 fm.write('text', '%s', l.line[p:])
2563 fm.write('text', '%s', l.line[p:])
2565 fm.data(matched=False)
2564 fm.data(matched=False)
2566 fm.end()
2565 fm.end()
2567
2566
2568 skip = {}
2567 skip = {}
2569 revfiles = {}
2568 revfiles = {}
2570 matchfn = scmutil.match(repo[None], pats, opts)
2569 matchfn = scmutil.match(repo[None], pats, opts)
2571 found = False
2570 found = False
2572 follow = opts.get('follow')
2571 follow = opts.get('follow')
2573
2572
2574 def prep(ctx, fns):
2573 def prep(ctx, fns):
2575 rev = ctx.rev()
2574 rev = ctx.rev()
2576 pctx = ctx.p1()
2575 pctx = ctx.p1()
2577 parent = pctx.rev()
2576 parent = pctx.rev()
2578 matches.setdefault(rev, {})
2577 matches.setdefault(rev, {})
2579 matches.setdefault(parent, {})
2578 matches.setdefault(parent, {})
2580 files = revfiles.setdefault(rev, [])
2579 files = revfiles.setdefault(rev, [])
2581 for fn in fns:
2580 for fn in fns:
2582 flog = getfile(fn)
2581 flog = getfile(fn)
2583 try:
2582 try:
2584 fnode = ctx.filenode(fn)
2583 fnode = ctx.filenode(fn)
2585 except error.LookupError:
2584 except error.LookupError:
2586 continue
2585 continue
2587
2586
2588 copied = flog.renamed(fnode)
2587 copied = flog.renamed(fnode)
2589 copy = follow and copied and copied[0]
2588 copy = follow and copied and copied[0]
2590 if copy:
2589 if copy:
2591 copies.setdefault(rev, {})[fn] = copy
2590 copies.setdefault(rev, {})[fn] = copy
2592 if fn in skip:
2591 if fn in skip:
2593 if copy:
2592 if copy:
2594 skip[copy] = True
2593 skip[copy] = True
2595 continue
2594 continue
2596 files.append(fn)
2595 files.append(fn)
2597
2596
2598 if fn not in matches[rev]:
2597 if fn not in matches[rev]:
2599 grepbody(fn, rev, flog.read(fnode))
2598 grepbody(fn, rev, flog.read(fnode))
2600
2599
2601 pfn = copy or fn
2600 pfn = copy or fn
2602 if pfn not in matches[parent]:
2601 if pfn not in matches[parent]:
2603 try:
2602 try:
2604 fnode = pctx.filenode(pfn)
2603 fnode = pctx.filenode(pfn)
2605 grepbody(pfn, parent, flog.read(fnode))
2604 grepbody(pfn, parent, flog.read(fnode))
2606 except error.LookupError:
2605 except error.LookupError:
2607 pass
2606 pass
2608
2607
2609 ui.pager('grep')
2608 ui.pager('grep')
2610 fm = ui.formatter('grep', opts)
2609 fm = ui.formatter('grep', opts)
2611 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2610 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2612 rev = ctx.rev()
2611 rev = ctx.rev()
2613 parent = ctx.p1().rev()
2612 parent = ctx.p1().rev()
2614 for fn in sorted(revfiles.get(rev, [])):
2613 for fn in sorted(revfiles.get(rev, [])):
2615 states = matches[rev][fn]
2614 states = matches[rev][fn]
2616 copy = copies.get(rev, {}).get(fn)
2615 copy = copies.get(rev, {}).get(fn)
2617 if fn in skip:
2616 if fn in skip:
2618 if copy:
2617 if copy:
2619 skip[copy] = True
2618 skip[copy] = True
2620 continue
2619 continue
2621 pstates = matches.get(parent, {}).get(copy or fn, [])
2620 pstates = matches.get(parent, {}).get(copy or fn, [])
2622 if pstates or states:
2621 if pstates or states:
2623 r = display(fm, fn, ctx, pstates, states)
2622 r = display(fm, fn, ctx, pstates, states)
2624 found = found or r
2623 found = found or r
2625 if r and not opts.get('all'):
2624 if r and not opts.get('all'):
2626 skip[fn] = True
2625 skip[fn] = True
2627 if copy:
2626 if copy:
2628 skip[copy] = True
2627 skip[copy] = True
2629 del matches[rev]
2628 del matches[rev]
2630 del revfiles[rev]
2629 del revfiles[rev]
2631 fm.end()
2630 fm.end()
2632
2631
2633 return not found
2632 return not found
2634
2633
2635 @command('heads',
2634 @command('heads',
2636 [('r', 'rev', '',
2635 [('r', 'rev', '',
2637 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2636 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2638 ('t', 'topo', False, _('show topological heads only')),
2637 ('t', 'topo', False, _('show topological heads only')),
2639 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2638 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2640 ('c', 'closed', False, _('show normal and closed branch heads')),
2639 ('c', 'closed', False, _('show normal and closed branch heads')),
2641 ] + templateopts,
2640 ] + templateopts,
2642 _('[-ct] [-r STARTREV] [REV]...'))
2641 _('[-ct] [-r STARTREV] [REV]...'))
2643 def heads(ui, repo, *branchrevs, **opts):
2642 def heads(ui, repo, *branchrevs, **opts):
2644 """show branch heads
2643 """show branch heads
2645
2644
2646 With no arguments, show all open branch heads in the repository.
2645 With no arguments, show all open branch heads in the repository.
2647 Branch heads are changesets that have no descendants on the
2646 Branch heads are changesets that have no descendants on the
2648 same branch. They are where development generally takes place and
2647 same branch. They are where development generally takes place and
2649 are the usual targets for update and merge operations.
2648 are the usual targets for update and merge operations.
2650
2649
2651 If one or more REVs are given, only open branch heads on the
2650 If one or more REVs are given, only open branch heads on the
2652 branches associated with the specified changesets are shown. This
2651 branches associated with the specified changesets are shown. This
2653 means that you can use :hg:`heads .` to see the heads on the
2652 means that you can use :hg:`heads .` to see the heads on the
2654 currently checked-out branch.
2653 currently checked-out branch.
2655
2654
2656 If -c/--closed is specified, also show branch heads marked closed
2655 If -c/--closed is specified, also show branch heads marked closed
2657 (see :hg:`commit --close-branch`).
2656 (see :hg:`commit --close-branch`).
2658
2657
2659 If STARTREV is specified, only those heads that are descendants of
2658 If STARTREV is specified, only those heads that are descendants of
2660 STARTREV will be displayed.
2659 STARTREV will be displayed.
2661
2660
2662 If -t/--topo is specified, named branch mechanics will be ignored and only
2661 If -t/--topo is specified, named branch mechanics will be ignored and only
2663 topological heads (changesets with no children) will be shown.
2662 topological heads (changesets with no children) will be shown.
2664
2663
2665 Returns 0 if matching heads are found, 1 if not.
2664 Returns 0 if matching heads are found, 1 if not.
2666 """
2665 """
2667
2666
2668 start = None
2667 start = None
2669 if 'rev' in opts:
2668 if 'rev' in opts:
2670 start = scmutil.revsingle(repo, opts['rev'], None).node()
2669 start = scmutil.revsingle(repo, opts['rev'], None).node()
2671
2670
2672 if opts.get('topo'):
2671 if opts.get('topo'):
2673 heads = [repo[h] for h in repo.heads(start)]
2672 heads = [repo[h] for h in repo.heads(start)]
2674 else:
2673 else:
2675 heads = []
2674 heads = []
2676 for branch in repo.branchmap():
2675 for branch in repo.branchmap():
2677 heads += repo.branchheads(branch, start, opts.get('closed'))
2676 heads += repo.branchheads(branch, start, opts.get('closed'))
2678 heads = [repo[h] for h in heads]
2677 heads = [repo[h] for h in heads]
2679
2678
2680 if branchrevs:
2679 if branchrevs:
2681 branches = set(repo[br].branch() for br in branchrevs)
2680 branches = set(repo[br].branch() for br in branchrevs)
2682 heads = [h for h in heads if h.branch() in branches]
2681 heads = [h for h in heads if h.branch() in branches]
2683
2682
2684 if opts.get('active') and branchrevs:
2683 if opts.get('active') and branchrevs:
2685 dagheads = repo.heads(start)
2684 dagheads = repo.heads(start)
2686 heads = [h for h in heads if h.node() in dagheads]
2685 heads = [h for h in heads if h.node() in dagheads]
2687
2686
2688 if branchrevs:
2687 if branchrevs:
2689 haveheads = set(h.branch() for h in heads)
2688 haveheads = set(h.branch() for h in heads)
2690 if branches - haveheads:
2689 if branches - haveheads:
2691 headless = ', '.join(b for b in branches - haveheads)
2690 headless = ', '.join(b for b in branches - haveheads)
2692 msg = _('no open branch heads found on branches %s')
2691 msg = _('no open branch heads found on branches %s')
2693 if opts.get('rev'):
2692 if opts.get('rev'):
2694 msg += _(' (started at %s)') % opts['rev']
2693 msg += _(' (started at %s)') % opts['rev']
2695 ui.warn((msg + '\n') % headless)
2694 ui.warn((msg + '\n') % headless)
2696
2695
2697 if not heads:
2696 if not heads:
2698 return 1
2697 return 1
2699
2698
2700 heads = sorted(heads, key=lambda x: -x.rev())
2699 heads = sorted(heads, key=lambda x: -x.rev())
2701 displayer = cmdutil.show_changeset(ui, repo, opts)
2700 displayer = cmdutil.show_changeset(ui, repo, opts)
2702 for ctx in heads:
2701 for ctx in heads:
2703 displayer.show(ctx)
2702 displayer.show(ctx)
2704 displayer.close()
2703 displayer.close()
2705
2704
2706 @command('help',
2705 @command('help',
2707 [('e', 'extension', None, _('show only help for extensions')),
2706 [('e', 'extension', None, _('show only help for extensions')),
2708 ('c', 'command', None, _('show only help for commands')),
2707 ('c', 'command', None, _('show only help for commands')),
2709 ('k', 'keyword', None, _('show topics matching keyword')),
2708 ('k', 'keyword', None, _('show topics matching keyword')),
2710 ('s', 'system', [], _('show help for specific platform(s)')),
2709 ('s', 'system', [], _('show help for specific platform(s)')),
2711 ],
2710 ],
2712 _('[-ecks] [TOPIC]'),
2711 _('[-ecks] [TOPIC]'),
2713 norepo=True)
2712 norepo=True)
2714 def help_(ui, name=None, **opts):
2713 def help_(ui, name=None, **opts):
2715 """show help for a given topic or a help overview
2714 """show help for a given topic or a help overview
2716
2715
2717 With no arguments, print a list of commands with short help messages.
2716 With no arguments, print a list of commands with short help messages.
2718
2717
2719 Given a topic, extension, or command name, print help for that
2718 Given a topic, extension, or command name, print help for that
2720 topic.
2719 topic.
2721
2720
2722 Returns 0 if successful.
2721 Returns 0 if successful.
2723 """
2722 """
2724 textwidth = ui.configint('ui', 'textwidth', 78)
2725 termwidth = ui.termwidth() - 2
2726 if textwidth <= 0 or termwidth < textwidth:
2727 textwidth = termwidth
2728
2723
2729 keep = opts.get('system') or []
2724 keep = opts.get('system') or []
2730 if len(keep) == 0:
2725 if len(keep) == 0:
2731 if pycompat.sysplatform.startswith('win'):
2726 if pycompat.sysplatform.startswith('win'):
2732 keep.append('windows')
2727 keep.append('windows')
2733 elif pycompat.sysplatform == 'OpenVMS':
2728 elif pycompat.sysplatform == 'OpenVMS':
2734 keep.append('vms')
2729 keep.append('vms')
2735 elif pycompat.sysplatform == 'plan9':
2730 elif pycompat.sysplatform == 'plan9':
2736 keep.append('plan9')
2731 keep.append('plan9')
2737 else:
2732 else:
2738 keep.append('unix')
2733 keep.append('unix')
2739 keep.append(pycompat.sysplatform.lower())
2734 keep.append(pycompat.sysplatform.lower())
2740 if ui.verbose:
2735 if ui.verbose:
2741 keep.append('verbose')
2736 keep.append('verbose')
2742
2737
2743 fullname = name
2738 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2744 section = None
2745 subtopic = None
2746 if name and '.' in name:
2747 name, remaining = name.split('.', 1)
2748 remaining = encoding.lower(remaining)
2749 if '.' in remaining:
2750 subtopic, section = remaining.split('.', 1)
2751 else:
2752 if name in help.subtopics:
2753 subtopic = remaining
2754 else:
2755 section = remaining
2756
2757 text = help.help_(ui, name, subtopic=subtopic, **opts)
2758
2759 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2760 section=section)
2761
2762 # We could have been given a weird ".foo" section without a name
2763 # to look for, or we could have simply failed to found "foo.bar"
2764 # because bar isn't a section of foo
2765 if section and not (formatted and name):
2766 raise error.Abort(_("help section not found: %s") % fullname)
2767
2768 if 'verbose' in pruned:
2769 keep.append('omitted')
2770 else:
2771 keep.append('notomitted')
2772 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2773 section=section)
2774 ui.pager('help')
2739 ui.pager('help')
2775 ui.write(formatted)
2740 ui.write(formatted)
2776
2741
2777
2742
2778 @command('identify|id',
2743 @command('identify|id',
2779 [('r', 'rev', '',
2744 [('r', 'rev', '',
2780 _('identify the specified revision'), _('REV')),
2745 _('identify the specified revision'), _('REV')),
2781 ('n', 'num', None, _('show local revision number')),
2746 ('n', 'num', None, _('show local revision number')),
2782 ('i', 'id', None, _('show global revision id')),
2747 ('i', 'id', None, _('show global revision id')),
2783 ('b', 'branch', None, _('show branch')),
2748 ('b', 'branch', None, _('show branch')),
2784 ('t', 'tags', None, _('show tags')),
2749 ('t', 'tags', None, _('show tags')),
2785 ('B', 'bookmarks', None, _('show bookmarks')),
2750 ('B', 'bookmarks', None, _('show bookmarks')),
2786 ] + remoteopts,
2751 ] + remoteopts,
2787 _('[-nibtB] [-r REV] [SOURCE]'),
2752 _('[-nibtB] [-r REV] [SOURCE]'),
2788 optionalrepo=True)
2753 optionalrepo=True)
2789 def identify(ui, repo, source=None, rev=None,
2754 def identify(ui, repo, source=None, rev=None,
2790 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2755 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2791 """identify the working directory or specified revision
2756 """identify the working directory or specified revision
2792
2757
2793 Print a summary identifying the repository state at REV using one or
2758 Print a summary identifying the repository state at REV using one or
2794 two parent hash identifiers, followed by a "+" if the working
2759 two parent hash identifiers, followed by a "+" if the working
2795 directory has uncommitted changes, the branch name (if not default),
2760 directory has uncommitted changes, the branch name (if not default),
2796 a list of tags, and a list of bookmarks.
2761 a list of tags, and a list of bookmarks.
2797
2762
2798 When REV is not given, print a summary of the current state of the
2763 When REV is not given, print a summary of the current state of the
2799 repository.
2764 repository.
2800
2765
2801 Specifying a path to a repository root or Mercurial bundle will
2766 Specifying a path to a repository root or Mercurial bundle will
2802 cause lookup to operate on that repository/bundle.
2767 cause lookup to operate on that repository/bundle.
2803
2768
2804 .. container:: verbose
2769 .. container:: verbose
2805
2770
2806 Examples:
2771 Examples:
2807
2772
2808 - generate a build identifier for the working directory::
2773 - generate a build identifier for the working directory::
2809
2774
2810 hg id --id > build-id.dat
2775 hg id --id > build-id.dat
2811
2776
2812 - find the revision corresponding to a tag::
2777 - find the revision corresponding to a tag::
2813
2778
2814 hg id -n -r 1.3
2779 hg id -n -r 1.3
2815
2780
2816 - check the most recent revision of a remote repository::
2781 - check the most recent revision of a remote repository::
2817
2782
2818 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2783 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2819
2784
2820 See :hg:`log` for generating more information about specific revisions,
2785 See :hg:`log` for generating more information about specific revisions,
2821 including full hash identifiers.
2786 including full hash identifiers.
2822
2787
2823 Returns 0 if successful.
2788 Returns 0 if successful.
2824 """
2789 """
2825
2790
2826 if not repo and not source:
2791 if not repo and not source:
2827 raise error.Abort(_("there is no Mercurial repository here "
2792 raise error.Abort(_("there is no Mercurial repository here "
2828 "(.hg not found)"))
2793 "(.hg not found)"))
2829
2794
2830 if ui.debugflag:
2795 if ui.debugflag:
2831 hexfunc = hex
2796 hexfunc = hex
2832 else:
2797 else:
2833 hexfunc = short
2798 hexfunc = short
2834 default = not (num or id or branch or tags or bookmarks)
2799 default = not (num or id or branch or tags or bookmarks)
2835 output = []
2800 output = []
2836 revs = []
2801 revs = []
2837
2802
2838 if source:
2803 if source:
2839 source, branches = hg.parseurl(ui.expandpath(source))
2804 source, branches = hg.parseurl(ui.expandpath(source))
2840 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2805 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2841 repo = peer.local()
2806 repo = peer.local()
2842 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2807 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2843
2808
2844 if not repo:
2809 if not repo:
2845 if num or branch or tags:
2810 if num or branch or tags:
2846 raise error.Abort(
2811 raise error.Abort(
2847 _("can't query remote revision number, branch, or tags"))
2812 _("can't query remote revision number, branch, or tags"))
2848 if not rev and revs:
2813 if not rev and revs:
2849 rev = revs[0]
2814 rev = revs[0]
2850 if not rev:
2815 if not rev:
2851 rev = "tip"
2816 rev = "tip"
2852
2817
2853 remoterev = peer.lookup(rev)
2818 remoterev = peer.lookup(rev)
2854 if default or id:
2819 if default or id:
2855 output = [hexfunc(remoterev)]
2820 output = [hexfunc(remoterev)]
2856
2821
2857 def getbms():
2822 def getbms():
2858 bms = []
2823 bms = []
2859
2824
2860 if 'bookmarks' in peer.listkeys('namespaces'):
2825 if 'bookmarks' in peer.listkeys('namespaces'):
2861 hexremoterev = hex(remoterev)
2826 hexremoterev = hex(remoterev)
2862 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2827 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2863 if bmr == hexremoterev]
2828 if bmr == hexremoterev]
2864
2829
2865 return sorted(bms)
2830 return sorted(bms)
2866
2831
2867 if bookmarks:
2832 if bookmarks:
2868 output.extend(getbms())
2833 output.extend(getbms())
2869 elif default and not ui.quiet:
2834 elif default and not ui.quiet:
2870 # multiple bookmarks for a single parent separated by '/'
2835 # multiple bookmarks for a single parent separated by '/'
2871 bm = '/'.join(getbms())
2836 bm = '/'.join(getbms())
2872 if bm:
2837 if bm:
2873 output.append(bm)
2838 output.append(bm)
2874 else:
2839 else:
2875 ctx = scmutil.revsingle(repo, rev, None)
2840 ctx = scmutil.revsingle(repo, rev, None)
2876
2841
2877 if ctx.rev() is None:
2842 if ctx.rev() is None:
2878 ctx = repo[None]
2843 ctx = repo[None]
2879 parents = ctx.parents()
2844 parents = ctx.parents()
2880 taglist = []
2845 taglist = []
2881 for p in parents:
2846 for p in parents:
2882 taglist.extend(p.tags())
2847 taglist.extend(p.tags())
2883
2848
2884 changed = ""
2849 changed = ""
2885 if default or id or num:
2850 if default or id or num:
2886 if (any(repo.status())
2851 if (any(repo.status())
2887 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2852 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2888 changed = '+'
2853 changed = '+'
2889 if default or id:
2854 if default or id:
2890 output = ["%s%s" %
2855 output = ["%s%s" %
2891 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2856 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2892 if num:
2857 if num:
2893 output.append("%s%s" %
2858 output.append("%s%s" %
2894 ('+'.join([str(p.rev()) for p in parents]), changed))
2859 ('+'.join([str(p.rev()) for p in parents]), changed))
2895 else:
2860 else:
2896 if default or id:
2861 if default or id:
2897 output = [hexfunc(ctx.node())]
2862 output = [hexfunc(ctx.node())]
2898 if num:
2863 if num:
2899 output.append(str(ctx.rev()))
2864 output.append(str(ctx.rev()))
2900 taglist = ctx.tags()
2865 taglist = ctx.tags()
2901
2866
2902 if default and not ui.quiet:
2867 if default and not ui.quiet:
2903 b = ctx.branch()
2868 b = ctx.branch()
2904 if b != 'default':
2869 if b != 'default':
2905 output.append("(%s)" % b)
2870 output.append("(%s)" % b)
2906
2871
2907 # multiple tags for a single parent separated by '/'
2872 # multiple tags for a single parent separated by '/'
2908 t = '/'.join(taglist)
2873 t = '/'.join(taglist)
2909 if t:
2874 if t:
2910 output.append(t)
2875 output.append(t)
2911
2876
2912 # multiple bookmarks for a single parent separated by '/'
2877 # multiple bookmarks for a single parent separated by '/'
2913 bm = '/'.join(ctx.bookmarks())
2878 bm = '/'.join(ctx.bookmarks())
2914 if bm:
2879 if bm:
2915 output.append(bm)
2880 output.append(bm)
2916 else:
2881 else:
2917 if branch:
2882 if branch:
2918 output.append(ctx.branch())
2883 output.append(ctx.branch())
2919
2884
2920 if tags:
2885 if tags:
2921 output.extend(taglist)
2886 output.extend(taglist)
2922
2887
2923 if bookmarks:
2888 if bookmarks:
2924 output.extend(ctx.bookmarks())
2889 output.extend(ctx.bookmarks())
2925
2890
2926 ui.write("%s\n" % ' '.join(output))
2891 ui.write("%s\n" % ' '.join(output))
2927
2892
2928 @command('import|patch',
2893 @command('import|patch',
2929 [('p', 'strip', 1,
2894 [('p', 'strip', 1,
2930 _('directory strip option for patch. This has the same '
2895 _('directory strip option for patch. This has the same '
2931 'meaning as the corresponding patch option'), _('NUM')),
2896 'meaning as the corresponding patch option'), _('NUM')),
2932 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2897 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2933 ('e', 'edit', False, _('invoke editor on commit messages')),
2898 ('e', 'edit', False, _('invoke editor on commit messages')),
2934 ('f', 'force', None,
2899 ('f', 'force', None,
2935 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2900 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2936 ('', 'no-commit', None,
2901 ('', 'no-commit', None,
2937 _("don't commit, just update the working directory")),
2902 _("don't commit, just update the working directory")),
2938 ('', 'bypass', None,
2903 ('', 'bypass', None,
2939 _("apply patch without touching the working directory")),
2904 _("apply patch without touching the working directory")),
2940 ('', 'partial', None,
2905 ('', 'partial', None,
2941 _('commit even if some hunks fail')),
2906 _('commit even if some hunks fail')),
2942 ('', 'exact', None,
2907 ('', 'exact', None,
2943 _('abort if patch would apply lossily')),
2908 _('abort if patch would apply lossily')),
2944 ('', 'prefix', '',
2909 ('', 'prefix', '',
2945 _('apply patch to subdirectory'), _('DIR')),
2910 _('apply patch to subdirectory'), _('DIR')),
2946 ('', 'import-branch', None,
2911 ('', 'import-branch', None,
2947 _('use any branch information in patch (implied by --exact)'))] +
2912 _('use any branch information in patch (implied by --exact)'))] +
2948 commitopts + commitopts2 + similarityopts,
2913 commitopts + commitopts2 + similarityopts,
2949 _('[OPTION]... PATCH...'))
2914 _('[OPTION]... PATCH...'))
2950 def import_(ui, repo, patch1=None, *patches, **opts):
2915 def import_(ui, repo, patch1=None, *patches, **opts):
2951 """import an ordered set of patches
2916 """import an ordered set of patches
2952
2917
2953 Import a list of patches and commit them individually (unless
2918 Import a list of patches and commit them individually (unless
2954 --no-commit is specified).
2919 --no-commit is specified).
2955
2920
2956 To read a patch from standard input (stdin), use "-" as the patch
2921 To read a patch from standard input (stdin), use "-" as the patch
2957 name. If a URL is specified, the patch will be downloaded from
2922 name. If a URL is specified, the patch will be downloaded from
2958 there.
2923 there.
2959
2924
2960 Import first applies changes to the working directory (unless
2925 Import first applies changes to the working directory (unless
2961 --bypass is specified), import will abort if there are outstanding
2926 --bypass is specified), import will abort if there are outstanding
2962 changes.
2927 changes.
2963
2928
2964 Use --bypass to apply and commit patches directly to the
2929 Use --bypass to apply and commit patches directly to the
2965 repository, without affecting the working directory. Without
2930 repository, without affecting the working directory. Without
2966 --exact, patches will be applied on top of the working directory
2931 --exact, patches will be applied on top of the working directory
2967 parent revision.
2932 parent revision.
2968
2933
2969 You can import a patch straight from a mail message. Even patches
2934 You can import a patch straight from a mail message. Even patches
2970 as attachments work (to use the body part, it must have type
2935 as attachments work (to use the body part, it must have type
2971 text/plain or text/x-patch). From and Subject headers of email
2936 text/plain or text/x-patch). From and Subject headers of email
2972 message are used as default committer and commit message. All
2937 message are used as default committer and commit message. All
2973 text/plain body parts before first diff are added to the commit
2938 text/plain body parts before first diff are added to the commit
2974 message.
2939 message.
2975
2940
2976 If the imported patch was generated by :hg:`export`, user and
2941 If the imported patch was generated by :hg:`export`, user and
2977 description from patch override values from message headers and
2942 description from patch override values from message headers and
2978 body. Values given on command line with -m/--message and -u/--user
2943 body. Values given on command line with -m/--message and -u/--user
2979 override these.
2944 override these.
2980
2945
2981 If --exact is specified, import will set the working directory to
2946 If --exact is specified, import will set the working directory to
2982 the parent of each patch before applying it, and will abort if the
2947 the parent of each patch before applying it, and will abort if the
2983 resulting changeset has a different ID than the one recorded in
2948 resulting changeset has a different ID than the one recorded in
2984 the patch. This will guard against various ways that portable
2949 the patch. This will guard against various ways that portable
2985 patch formats and mail systems might fail to transfer Mercurial
2950 patch formats and mail systems might fail to transfer Mercurial
2986 data or metadata. See :hg:`bundle` for lossless transmission.
2951 data or metadata. See :hg:`bundle` for lossless transmission.
2987
2952
2988 Use --partial to ensure a changeset will be created from the patch
2953 Use --partial to ensure a changeset will be created from the patch
2989 even if some hunks fail to apply. Hunks that fail to apply will be
2954 even if some hunks fail to apply. Hunks that fail to apply will be
2990 written to a <target-file>.rej file. Conflicts can then be resolved
2955 written to a <target-file>.rej file. Conflicts can then be resolved
2991 by hand before :hg:`commit --amend` is run to update the created
2956 by hand before :hg:`commit --amend` is run to update the created
2992 changeset. This flag exists to let people import patches that
2957 changeset. This flag exists to let people import patches that
2993 partially apply without losing the associated metadata (author,
2958 partially apply without losing the associated metadata (author,
2994 date, description, ...).
2959 date, description, ...).
2995
2960
2996 .. note::
2961 .. note::
2997
2962
2998 When no hunks apply cleanly, :hg:`import --partial` will create
2963 When no hunks apply cleanly, :hg:`import --partial` will create
2999 an empty changeset, importing only the patch metadata.
2964 an empty changeset, importing only the patch metadata.
3000
2965
3001 With -s/--similarity, hg will attempt to discover renames and
2966 With -s/--similarity, hg will attempt to discover renames and
3002 copies in the patch in the same way as :hg:`addremove`.
2967 copies in the patch in the same way as :hg:`addremove`.
3003
2968
3004 It is possible to use external patch programs to perform the patch
2969 It is possible to use external patch programs to perform the patch
3005 by setting the ``ui.patch`` configuration option. For the default
2970 by setting the ``ui.patch`` configuration option. For the default
3006 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2971 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3007 See :hg:`help config` for more information about configuration
2972 See :hg:`help config` for more information about configuration
3008 files and how to use these options.
2973 files and how to use these options.
3009
2974
3010 See :hg:`help dates` for a list of formats valid for -d/--date.
2975 See :hg:`help dates` for a list of formats valid for -d/--date.
3011
2976
3012 .. container:: verbose
2977 .. container:: verbose
3013
2978
3014 Examples:
2979 Examples:
3015
2980
3016 - import a traditional patch from a website and detect renames::
2981 - import a traditional patch from a website and detect renames::
3017
2982
3018 hg import -s 80 http://example.com/bugfix.patch
2983 hg import -s 80 http://example.com/bugfix.patch
3019
2984
3020 - import a changeset from an hgweb server::
2985 - import a changeset from an hgweb server::
3021
2986
3022 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2987 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3023
2988
3024 - import all the patches in an Unix-style mbox::
2989 - import all the patches in an Unix-style mbox::
3025
2990
3026 hg import incoming-patches.mbox
2991 hg import incoming-patches.mbox
3027
2992
3028 - import patches from stdin::
2993 - import patches from stdin::
3029
2994
3030 hg import -
2995 hg import -
3031
2996
3032 - attempt to exactly restore an exported changeset (not always
2997 - attempt to exactly restore an exported changeset (not always
3033 possible)::
2998 possible)::
3034
2999
3035 hg import --exact proposed-fix.patch
3000 hg import --exact proposed-fix.patch
3036
3001
3037 - use an external tool to apply a patch which is too fuzzy for
3002 - use an external tool to apply a patch which is too fuzzy for
3038 the default internal tool.
3003 the default internal tool.
3039
3004
3040 hg import --config ui.patch="patch --merge" fuzzy.patch
3005 hg import --config ui.patch="patch --merge" fuzzy.patch
3041
3006
3042 - change the default fuzzing from 2 to a less strict 7
3007 - change the default fuzzing from 2 to a less strict 7
3043
3008
3044 hg import --config ui.fuzz=7 fuzz.patch
3009 hg import --config ui.fuzz=7 fuzz.patch
3045
3010
3046 Returns 0 on success, 1 on partial success (see --partial).
3011 Returns 0 on success, 1 on partial success (see --partial).
3047 """
3012 """
3048
3013
3049 if not patch1:
3014 if not patch1:
3050 raise error.Abort(_('need at least one patch to import'))
3015 raise error.Abort(_('need at least one patch to import'))
3051
3016
3052 patches = (patch1,) + patches
3017 patches = (patch1,) + patches
3053
3018
3054 date = opts.get('date')
3019 date = opts.get('date')
3055 if date:
3020 if date:
3056 opts['date'] = util.parsedate(date)
3021 opts['date'] = util.parsedate(date)
3057
3022
3058 exact = opts.get('exact')
3023 exact = opts.get('exact')
3059 update = not opts.get('bypass')
3024 update = not opts.get('bypass')
3060 if not update and opts.get('no_commit'):
3025 if not update and opts.get('no_commit'):
3061 raise error.Abort(_('cannot use --no-commit with --bypass'))
3026 raise error.Abort(_('cannot use --no-commit with --bypass'))
3062 try:
3027 try:
3063 sim = float(opts.get('similarity') or 0)
3028 sim = float(opts.get('similarity') or 0)
3064 except ValueError:
3029 except ValueError:
3065 raise error.Abort(_('similarity must be a number'))
3030 raise error.Abort(_('similarity must be a number'))
3066 if sim < 0 or sim > 100:
3031 if sim < 0 or sim > 100:
3067 raise error.Abort(_('similarity must be between 0 and 100'))
3032 raise error.Abort(_('similarity must be between 0 and 100'))
3068 if sim and not update:
3033 if sim and not update:
3069 raise error.Abort(_('cannot use --similarity with --bypass'))
3034 raise error.Abort(_('cannot use --similarity with --bypass'))
3070 if exact:
3035 if exact:
3071 if opts.get('edit'):
3036 if opts.get('edit'):
3072 raise error.Abort(_('cannot use --exact with --edit'))
3037 raise error.Abort(_('cannot use --exact with --edit'))
3073 if opts.get('prefix'):
3038 if opts.get('prefix'):
3074 raise error.Abort(_('cannot use --exact with --prefix'))
3039 raise error.Abort(_('cannot use --exact with --prefix'))
3075
3040
3076 base = opts["base"]
3041 base = opts["base"]
3077 wlock = dsguard = lock = tr = None
3042 wlock = dsguard = lock = tr = None
3078 msgs = []
3043 msgs = []
3079 ret = 0
3044 ret = 0
3080
3045
3081
3046
3082 try:
3047 try:
3083 wlock = repo.wlock()
3048 wlock = repo.wlock()
3084
3049
3085 if update:
3050 if update:
3086 cmdutil.checkunfinished(repo)
3051 cmdutil.checkunfinished(repo)
3087 if (exact or not opts.get('force')):
3052 if (exact or not opts.get('force')):
3088 cmdutil.bailifchanged(repo)
3053 cmdutil.bailifchanged(repo)
3089
3054
3090 if not opts.get('no_commit'):
3055 if not opts.get('no_commit'):
3091 lock = repo.lock()
3056 lock = repo.lock()
3092 tr = repo.transaction('import')
3057 tr = repo.transaction('import')
3093 else:
3058 else:
3094 dsguard = dirstateguard.dirstateguard(repo, 'import')
3059 dsguard = dirstateguard.dirstateguard(repo, 'import')
3095 parents = repo[None].parents()
3060 parents = repo[None].parents()
3096 for patchurl in patches:
3061 for patchurl in patches:
3097 if patchurl == '-':
3062 if patchurl == '-':
3098 ui.status(_('applying patch from stdin\n'))
3063 ui.status(_('applying patch from stdin\n'))
3099 patchfile = ui.fin
3064 patchfile = ui.fin
3100 patchurl = 'stdin' # for error message
3065 patchurl = 'stdin' # for error message
3101 else:
3066 else:
3102 patchurl = os.path.join(base, patchurl)
3067 patchurl = os.path.join(base, patchurl)
3103 ui.status(_('applying %s\n') % patchurl)
3068 ui.status(_('applying %s\n') % patchurl)
3104 patchfile = hg.openpath(ui, patchurl)
3069 patchfile = hg.openpath(ui, patchurl)
3105
3070
3106 haspatch = False
3071 haspatch = False
3107 for hunk in patch.split(patchfile):
3072 for hunk in patch.split(patchfile):
3108 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3073 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3109 parents, opts,
3074 parents, opts,
3110 msgs, hg.clean)
3075 msgs, hg.clean)
3111 if msg:
3076 if msg:
3112 haspatch = True
3077 haspatch = True
3113 ui.note(msg + '\n')
3078 ui.note(msg + '\n')
3114 if update or exact:
3079 if update or exact:
3115 parents = repo[None].parents()
3080 parents = repo[None].parents()
3116 else:
3081 else:
3117 parents = [repo[node]]
3082 parents = [repo[node]]
3118 if rej:
3083 if rej:
3119 ui.write_err(_("patch applied partially\n"))
3084 ui.write_err(_("patch applied partially\n"))
3120 ui.write_err(_("(fix the .rej files and run "
3085 ui.write_err(_("(fix the .rej files and run "
3121 "`hg commit --amend`)\n"))
3086 "`hg commit --amend`)\n"))
3122 ret = 1
3087 ret = 1
3123 break
3088 break
3124
3089
3125 if not haspatch:
3090 if not haspatch:
3126 raise error.Abort(_('%s: no diffs found') % patchurl)
3091 raise error.Abort(_('%s: no diffs found') % patchurl)
3127
3092
3128 if tr:
3093 if tr:
3129 tr.close()
3094 tr.close()
3130 if msgs:
3095 if msgs:
3131 repo.savecommitmessage('\n* * *\n'.join(msgs))
3096 repo.savecommitmessage('\n* * *\n'.join(msgs))
3132 if dsguard:
3097 if dsguard:
3133 dsguard.close()
3098 dsguard.close()
3134 return ret
3099 return ret
3135 finally:
3100 finally:
3136 if tr:
3101 if tr:
3137 tr.release()
3102 tr.release()
3138 release(lock, dsguard, wlock)
3103 release(lock, dsguard, wlock)
3139
3104
3140 @command('incoming|in',
3105 @command('incoming|in',
3141 [('f', 'force', None,
3106 [('f', 'force', None,
3142 _('run even if remote repository is unrelated')),
3107 _('run even if remote repository is unrelated')),
3143 ('n', 'newest-first', None, _('show newest record first')),
3108 ('n', 'newest-first', None, _('show newest record first')),
3144 ('', 'bundle', '',
3109 ('', 'bundle', '',
3145 _('file to store the bundles into'), _('FILE')),
3110 _('file to store the bundles into'), _('FILE')),
3146 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3111 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3147 ('B', 'bookmarks', False, _("compare bookmarks")),
3112 ('B', 'bookmarks', False, _("compare bookmarks")),
3148 ('b', 'branch', [],
3113 ('b', 'branch', [],
3149 _('a specific branch you would like to pull'), _('BRANCH')),
3114 _('a specific branch you would like to pull'), _('BRANCH')),
3150 ] + logopts + remoteopts + subrepoopts,
3115 ] + logopts + remoteopts + subrepoopts,
3151 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3116 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3152 def incoming(ui, repo, source="default", **opts):
3117 def incoming(ui, repo, source="default", **opts):
3153 """show new changesets found in source
3118 """show new changesets found in source
3154
3119
3155 Show new changesets found in the specified path/URL or the default
3120 Show new changesets found in the specified path/URL or the default
3156 pull location. These are the changesets that would have been pulled
3121 pull location. These are the changesets that would have been pulled
3157 if a pull at the time you issued this command.
3122 if a pull at the time you issued this command.
3158
3123
3159 See pull for valid source format details.
3124 See pull for valid source format details.
3160
3125
3161 .. container:: verbose
3126 .. container:: verbose
3162
3127
3163 With -B/--bookmarks, the result of bookmark comparison between
3128 With -B/--bookmarks, the result of bookmark comparison between
3164 local and remote repositories is displayed. With -v/--verbose,
3129 local and remote repositories is displayed. With -v/--verbose,
3165 status is also displayed for each bookmark like below::
3130 status is also displayed for each bookmark like below::
3166
3131
3167 BM1 01234567890a added
3132 BM1 01234567890a added
3168 BM2 1234567890ab advanced
3133 BM2 1234567890ab advanced
3169 BM3 234567890abc diverged
3134 BM3 234567890abc diverged
3170 BM4 34567890abcd changed
3135 BM4 34567890abcd changed
3171
3136
3172 The action taken locally when pulling depends on the
3137 The action taken locally when pulling depends on the
3173 status of each bookmark:
3138 status of each bookmark:
3174
3139
3175 :``added``: pull will create it
3140 :``added``: pull will create it
3176 :``advanced``: pull will update it
3141 :``advanced``: pull will update it
3177 :``diverged``: pull will create a divergent bookmark
3142 :``diverged``: pull will create a divergent bookmark
3178 :``changed``: result depends on remote changesets
3143 :``changed``: result depends on remote changesets
3179
3144
3180 From the point of view of pulling behavior, bookmark
3145 From the point of view of pulling behavior, bookmark
3181 existing only in the remote repository are treated as ``added``,
3146 existing only in the remote repository are treated as ``added``,
3182 even if it is in fact locally deleted.
3147 even if it is in fact locally deleted.
3183
3148
3184 .. container:: verbose
3149 .. container:: verbose
3185
3150
3186 For remote repository, using --bundle avoids downloading the
3151 For remote repository, using --bundle avoids downloading the
3187 changesets twice if the incoming is followed by a pull.
3152 changesets twice if the incoming is followed by a pull.
3188
3153
3189 Examples:
3154 Examples:
3190
3155
3191 - show incoming changes with patches and full description::
3156 - show incoming changes with patches and full description::
3192
3157
3193 hg incoming -vp
3158 hg incoming -vp
3194
3159
3195 - show incoming changes excluding merges, store a bundle::
3160 - show incoming changes excluding merges, store a bundle::
3196
3161
3197 hg in -vpM --bundle incoming.hg
3162 hg in -vpM --bundle incoming.hg
3198 hg pull incoming.hg
3163 hg pull incoming.hg
3199
3164
3200 - briefly list changes inside a bundle::
3165 - briefly list changes inside a bundle::
3201
3166
3202 hg in changes.hg -T "{desc|firstline}\\n"
3167 hg in changes.hg -T "{desc|firstline}\\n"
3203
3168
3204 Returns 0 if there are incoming changes, 1 otherwise.
3169 Returns 0 if there are incoming changes, 1 otherwise.
3205 """
3170 """
3206 if opts.get('graph'):
3171 if opts.get('graph'):
3207 cmdutil.checkunsupportedgraphflags([], opts)
3172 cmdutil.checkunsupportedgraphflags([], opts)
3208 def display(other, chlist, displayer):
3173 def display(other, chlist, displayer):
3209 revdag = cmdutil.graphrevs(other, chlist, opts)
3174 revdag = cmdutil.graphrevs(other, chlist, opts)
3210 cmdutil.displaygraph(ui, repo, revdag, displayer,
3175 cmdutil.displaygraph(ui, repo, revdag, displayer,
3211 graphmod.asciiedges)
3176 graphmod.asciiedges)
3212
3177
3213 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3178 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3214 return 0
3179 return 0
3215
3180
3216 if opts.get('bundle') and opts.get('subrepos'):
3181 if opts.get('bundle') and opts.get('subrepos'):
3217 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3182 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3218
3183
3219 if opts.get('bookmarks'):
3184 if opts.get('bookmarks'):
3220 source, branches = hg.parseurl(ui.expandpath(source),
3185 source, branches = hg.parseurl(ui.expandpath(source),
3221 opts.get('branch'))
3186 opts.get('branch'))
3222 other = hg.peer(repo, opts, source)
3187 other = hg.peer(repo, opts, source)
3223 if 'bookmarks' not in other.listkeys('namespaces'):
3188 if 'bookmarks' not in other.listkeys('namespaces'):
3224 ui.warn(_("remote doesn't support bookmarks\n"))
3189 ui.warn(_("remote doesn't support bookmarks\n"))
3225 return 0
3190 return 0
3226 ui.pager('incoming')
3191 ui.pager('incoming')
3227 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3192 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3228 return bookmarks.incoming(ui, repo, other)
3193 return bookmarks.incoming(ui, repo, other)
3229
3194
3230 repo._subtoppath = ui.expandpath(source)
3195 repo._subtoppath = ui.expandpath(source)
3231 try:
3196 try:
3232 return hg.incoming(ui, repo, source, opts)
3197 return hg.incoming(ui, repo, source, opts)
3233 finally:
3198 finally:
3234 del repo._subtoppath
3199 del repo._subtoppath
3235
3200
3236
3201
3237 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3202 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3238 norepo=True)
3203 norepo=True)
3239 def init(ui, dest=".", **opts):
3204 def init(ui, dest=".", **opts):
3240 """create a new repository in the given directory
3205 """create a new repository in the given directory
3241
3206
3242 Initialize a new repository in the given directory. If the given
3207 Initialize a new repository in the given directory. If the given
3243 directory does not exist, it will be created.
3208 directory does not exist, it will be created.
3244
3209
3245 If no directory is given, the current directory is used.
3210 If no directory is given, the current directory is used.
3246
3211
3247 It is possible to specify an ``ssh://`` URL as the destination.
3212 It is possible to specify an ``ssh://`` URL as the destination.
3248 See :hg:`help urls` for more information.
3213 See :hg:`help urls` for more information.
3249
3214
3250 Returns 0 on success.
3215 Returns 0 on success.
3251 """
3216 """
3252 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3217 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3253
3218
3254 @command('locate',
3219 @command('locate',
3255 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3220 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3221 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3257 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3222 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3258 ] + walkopts,
3223 ] + walkopts,
3259 _('[OPTION]... [PATTERN]...'))
3224 _('[OPTION]... [PATTERN]...'))
3260 def locate(ui, repo, *pats, **opts):
3225 def locate(ui, repo, *pats, **opts):
3261 """locate files matching specific patterns (DEPRECATED)
3226 """locate files matching specific patterns (DEPRECATED)
3262
3227
3263 Print files under Mercurial control in the working directory whose
3228 Print files under Mercurial control in the working directory whose
3264 names match the given patterns.
3229 names match the given patterns.
3265
3230
3266 By default, this command searches all directories in the working
3231 By default, this command searches all directories in the working
3267 directory. To search just the current directory and its
3232 directory. To search just the current directory and its
3268 subdirectories, use "--include .".
3233 subdirectories, use "--include .".
3269
3234
3270 If no patterns are given to match, this command prints the names
3235 If no patterns are given to match, this command prints the names
3271 of all files under Mercurial control in the working directory.
3236 of all files under Mercurial control in the working directory.
3272
3237
3273 If you want to feed the output of this command into the "xargs"
3238 If you want to feed the output of this command into the "xargs"
3274 command, use the -0 option to both this command and "xargs". This
3239 command, use the -0 option to both this command and "xargs". This
3275 will avoid the problem of "xargs" treating single filenames that
3240 will avoid the problem of "xargs" treating single filenames that
3276 contain whitespace as multiple filenames.
3241 contain whitespace as multiple filenames.
3277
3242
3278 See :hg:`help files` for a more versatile command.
3243 See :hg:`help files` for a more versatile command.
3279
3244
3280 Returns 0 if a match is found, 1 otherwise.
3245 Returns 0 if a match is found, 1 otherwise.
3281 """
3246 """
3282 if opts.get('print0'):
3247 if opts.get('print0'):
3283 end = '\0'
3248 end = '\0'
3284 else:
3249 else:
3285 end = '\n'
3250 end = '\n'
3286 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3251 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3287
3252
3288 ret = 1
3253 ret = 1
3289 ctx = repo[rev]
3254 ctx = repo[rev]
3290 m = scmutil.match(ctx, pats, opts, default='relglob',
3255 m = scmutil.match(ctx, pats, opts, default='relglob',
3291 badfn=lambda x, y: False)
3256 badfn=lambda x, y: False)
3292
3257
3293 ui.pager('locate')
3258 ui.pager('locate')
3294 for abs in ctx.matches(m):
3259 for abs in ctx.matches(m):
3295 if opts.get('fullpath'):
3260 if opts.get('fullpath'):
3296 ui.write(repo.wjoin(abs), end)
3261 ui.write(repo.wjoin(abs), end)
3297 else:
3262 else:
3298 ui.write(((pats and m.rel(abs)) or abs), end)
3263 ui.write(((pats and m.rel(abs)) or abs), end)
3299 ret = 0
3264 ret = 0
3300
3265
3301 return ret
3266 return ret
3302
3267
3303 @command('^log|history',
3268 @command('^log|history',
3304 [('f', 'follow', None,
3269 [('f', 'follow', None,
3305 _('follow changeset history, or file history across copies and renames')),
3270 _('follow changeset history, or file history across copies and renames')),
3306 ('', 'follow-first', None,
3271 ('', 'follow-first', None,
3307 _('only follow the first parent of merge changesets (DEPRECATED)')),
3272 _('only follow the first parent of merge changesets (DEPRECATED)')),
3308 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3273 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3309 ('C', 'copies', None, _('show copied files')),
3274 ('C', 'copies', None, _('show copied files')),
3310 ('k', 'keyword', [],
3275 ('k', 'keyword', [],
3311 _('do case-insensitive search for a given text'), _('TEXT')),
3276 _('do case-insensitive search for a given text'), _('TEXT')),
3312 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3277 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3313 ('', 'removed', None, _('include revisions where files were removed')),
3278 ('', 'removed', None, _('include revisions where files were removed')),
3314 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3279 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3315 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3280 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3316 ('', 'only-branch', [],
3281 ('', 'only-branch', [],
3317 _('show only changesets within the given named branch (DEPRECATED)'),
3282 _('show only changesets within the given named branch (DEPRECATED)'),
3318 _('BRANCH')),
3283 _('BRANCH')),
3319 ('b', 'branch', [],
3284 ('b', 'branch', [],
3320 _('show changesets within the given named branch'), _('BRANCH')),
3285 _('show changesets within the given named branch'), _('BRANCH')),
3321 ('P', 'prune', [],
3286 ('P', 'prune', [],
3322 _('do not display revision or any of its ancestors'), _('REV')),
3287 _('do not display revision or any of its ancestors'), _('REV')),
3323 ] + logopts + walkopts,
3288 ] + logopts + walkopts,
3324 _('[OPTION]... [FILE]'),
3289 _('[OPTION]... [FILE]'),
3325 inferrepo=True)
3290 inferrepo=True)
3326 def log(ui, repo, *pats, **opts):
3291 def log(ui, repo, *pats, **opts):
3327 """show revision history of entire repository or files
3292 """show revision history of entire repository or files
3328
3293
3329 Print the revision history of the specified files or the entire
3294 Print the revision history of the specified files or the entire
3330 project.
3295 project.
3331
3296
3332 If no revision range is specified, the default is ``tip:0`` unless
3297 If no revision range is specified, the default is ``tip:0`` unless
3333 --follow is set, in which case the working directory parent is
3298 --follow is set, in which case the working directory parent is
3334 used as the starting revision.
3299 used as the starting revision.
3335
3300
3336 File history is shown without following rename or copy history of
3301 File history is shown without following rename or copy history of
3337 files. Use -f/--follow with a filename to follow history across
3302 files. Use -f/--follow with a filename to follow history across
3338 renames and copies. --follow without a filename will only show
3303 renames and copies. --follow without a filename will only show
3339 ancestors or descendants of the starting revision.
3304 ancestors or descendants of the starting revision.
3340
3305
3341 By default this command prints revision number and changeset id,
3306 By default this command prints revision number and changeset id,
3342 tags, non-trivial parents, user, date and time, and a summary for
3307 tags, non-trivial parents, user, date and time, and a summary for
3343 each commit. When the -v/--verbose switch is used, the list of
3308 each commit. When the -v/--verbose switch is used, the list of
3344 changed files and full commit message are shown.
3309 changed files and full commit message are shown.
3345
3310
3346 With --graph the revisions are shown as an ASCII art DAG with the most
3311 With --graph the revisions are shown as an ASCII art DAG with the most
3347 recent changeset at the top.
3312 recent changeset at the top.
3348 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3313 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3349 and '+' represents a fork where the changeset from the lines below is a
3314 and '+' represents a fork where the changeset from the lines below is a
3350 parent of the 'o' merge on the same line.
3315 parent of the 'o' merge on the same line.
3351
3316
3352 .. note::
3317 .. note::
3353
3318
3354 :hg:`log --patch` may generate unexpected diff output for merge
3319 :hg:`log --patch` may generate unexpected diff output for merge
3355 changesets, as it will only compare the merge changeset against
3320 changesets, as it will only compare the merge changeset against
3356 its first parent. Also, only files different from BOTH parents
3321 its first parent. Also, only files different from BOTH parents
3357 will appear in files:.
3322 will appear in files:.
3358
3323
3359 .. note::
3324 .. note::
3360
3325
3361 For performance reasons, :hg:`log FILE` may omit duplicate changes
3326 For performance reasons, :hg:`log FILE` may omit duplicate changes
3362 made on branches and will not show removals or mode changes. To
3327 made on branches and will not show removals or mode changes. To
3363 see all such changes, use the --removed switch.
3328 see all such changes, use the --removed switch.
3364
3329
3365 .. container:: verbose
3330 .. container:: verbose
3366
3331
3367 Some examples:
3332 Some examples:
3368
3333
3369 - changesets with full descriptions and file lists::
3334 - changesets with full descriptions and file lists::
3370
3335
3371 hg log -v
3336 hg log -v
3372
3337
3373 - changesets ancestral to the working directory::
3338 - changesets ancestral to the working directory::
3374
3339
3375 hg log -f
3340 hg log -f
3376
3341
3377 - last 10 commits on the current branch::
3342 - last 10 commits on the current branch::
3378
3343
3379 hg log -l 10 -b .
3344 hg log -l 10 -b .
3380
3345
3381 - changesets showing all modifications of a file, including removals::
3346 - changesets showing all modifications of a file, including removals::
3382
3347
3383 hg log --removed file.c
3348 hg log --removed file.c
3384
3349
3385 - all changesets that touch a directory, with diffs, excluding merges::
3350 - all changesets that touch a directory, with diffs, excluding merges::
3386
3351
3387 hg log -Mp lib/
3352 hg log -Mp lib/
3388
3353
3389 - all revision numbers that match a keyword::
3354 - all revision numbers that match a keyword::
3390
3355
3391 hg log -k bug --template "{rev}\\n"
3356 hg log -k bug --template "{rev}\\n"
3392
3357
3393 - the full hash identifier of the working directory parent::
3358 - the full hash identifier of the working directory parent::
3394
3359
3395 hg log -r . --template "{node}\\n"
3360 hg log -r . --template "{node}\\n"
3396
3361
3397 - list available log templates::
3362 - list available log templates::
3398
3363
3399 hg log -T list
3364 hg log -T list
3400
3365
3401 - check if a given changeset is included in a tagged release::
3366 - check if a given changeset is included in a tagged release::
3402
3367
3403 hg log -r "a21ccf and ancestor(1.9)"
3368 hg log -r "a21ccf and ancestor(1.9)"
3404
3369
3405 - find all changesets by some user in a date range::
3370 - find all changesets by some user in a date range::
3406
3371
3407 hg log -k alice -d "may 2008 to jul 2008"
3372 hg log -k alice -d "may 2008 to jul 2008"
3408
3373
3409 - summary of all changesets after the last tag::
3374 - summary of all changesets after the last tag::
3410
3375
3411 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3376 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3412
3377
3413 See :hg:`help dates` for a list of formats valid for -d/--date.
3378 See :hg:`help dates` for a list of formats valid for -d/--date.
3414
3379
3415 See :hg:`help revisions` for more about specifying and ordering
3380 See :hg:`help revisions` for more about specifying and ordering
3416 revisions.
3381 revisions.
3417
3382
3418 See :hg:`help templates` for more about pre-packaged styles and
3383 See :hg:`help templates` for more about pre-packaged styles and
3419 specifying custom templates.
3384 specifying custom templates.
3420
3385
3421 Returns 0 on success.
3386 Returns 0 on success.
3422
3387
3423 """
3388 """
3424 if opts.get('follow') and opts.get('rev'):
3389 if opts.get('follow') and opts.get('rev'):
3425 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3390 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3426 del opts['follow']
3391 del opts['follow']
3427
3392
3428 if opts.get('graph'):
3393 if opts.get('graph'):
3429 return cmdutil.graphlog(ui, repo, *pats, **opts)
3394 return cmdutil.graphlog(ui, repo, *pats, **opts)
3430
3395
3431 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3396 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3432 limit = cmdutil.loglimit(opts)
3397 limit = cmdutil.loglimit(opts)
3433 count = 0
3398 count = 0
3434
3399
3435 getrenamed = None
3400 getrenamed = None
3436 if opts.get('copies'):
3401 if opts.get('copies'):
3437 endrev = None
3402 endrev = None
3438 if opts.get('rev'):
3403 if opts.get('rev'):
3439 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3404 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3440 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3405 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3441
3406
3442 ui.pager('log')
3407 ui.pager('log')
3443 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3408 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3444 for rev in revs:
3409 for rev in revs:
3445 if count == limit:
3410 if count == limit:
3446 break
3411 break
3447 ctx = repo[rev]
3412 ctx = repo[rev]
3448 copies = None
3413 copies = None
3449 if getrenamed is not None and rev:
3414 if getrenamed is not None and rev:
3450 copies = []
3415 copies = []
3451 for fn in ctx.files():
3416 for fn in ctx.files():
3452 rename = getrenamed(fn, rev)
3417 rename = getrenamed(fn, rev)
3453 if rename:
3418 if rename:
3454 copies.append((fn, rename[0]))
3419 copies.append((fn, rename[0]))
3455 if filematcher:
3420 if filematcher:
3456 revmatchfn = filematcher(ctx.rev())
3421 revmatchfn = filematcher(ctx.rev())
3457 else:
3422 else:
3458 revmatchfn = None
3423 revmatchfn = None
3459 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3424 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3460 if displayer.flush(ctx):
3425 if displayer.flush(ctx):
3461 count += 1
3426 count += 1
3462
3427
3463 displayer.close()
3428 displayer.close()
3464
3429
3465 @command('manifest',
3430 @command('manifest',
3466 [('r', 'rev', '', _('revision to display'), _('REV')),
3431 [('r', 'rev', '', _('revision to display'), _('REV')),
3467 ('', 'all', False, _("list files from all revisions"))]
3432 ('', 'all', False, _("list files from all revisions"))]
3468 + formatteropts,
3433 + formatteropts,
3469 _('[-r REV]'))
3434 _('[-r REV]'))
3470 def manifest(ui, repo, node=None, rev=None, **opts):
3435 def manifest(ui, repo, node=None, rev=None, **opts):
3471 """output the current or given revision of the project manifest
3436 """output the current or given revision of the project manifest
3472
3437
3473 Print a list of version controlled files for the given revision.
3438 Print a list of version controlled files for the given revision.
3474 If no revision is given, the first parent of the working directory
3439 If no revision is given, the first parent of the working directory
3475 is used, or the null revision if no revision is checked out.
3440 is used, or the null revision if no revision is checked out.
3476
3441
3477 With -v, print file permissions, symlink and executable bits.
3442 With -v, print file permissions, symlink and executable bits.
3478 With --debug, print file revision hashes.
3443 With --debug, print file revision hashes.
3479
3444
3480 If option --all is specified, the list of all files from all revisions
3445 If option --all is specified, the list of all files from all revisions
3481 is printed. This includes deleted and renamed files.
3446 is printed. This includes deleted and renamed files.
3482
3447
3483 Returns 0 on success.
3448 Returns 0 on success.
3484 """
3449 """
3485 fm = ui.formatter('manifest', opts)
3450 fm = ui.formatter('manifest', opts)
3486
3451
3487 if opts.get('all'):
3452 if opts.get('all'):
3488 if rev or node:
3453 if rev or node:
3489 raise error.Abort(_("can't specify a revision with --all"))
3454 raise error.Abort(_("can't specify a revision with --all"))
3490
3455
3491 res = []
3456 res = []
3492 prefix = "data/"
3457 prefix = "data/"
3493 suffix = ".i"
3458 suffix = ".i"
3494 plen = len(prefix)
3459 plen = len(prefix)
3495 slen = len(suffix)
3460 slen = len(suffix)
3496 with repo.lock():
3461 with repo.lock():
3497 for fn, b, size in repo.store.datafiles():
3462 for fn, b, size in repo.store.datafiles():
3498 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3463 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3499 res.append(fn[plen:-slen])
3464 res.append(fn[plen:-slen])
3500 ui.pager('manifest')
3465 ui.pager('manifest')
3501 for f in res:
3466 for f in res:
3502 fm.startitem()
3467 fm.startitem()
3503 fm.write("path", '%s\n', f)
3468 fm.write("path", '%s\n', f)
3504 fm.end()
3469 fm.end()
3505 return
3470 return
3506
3471
3507 if rev and node:
3472 if rev and node:
3508 raise error.Abort(_("please specify just one revision"))
3473 raise error.Abort(_("please specify just one revision"))
3509
3474
3510 if not node:
3475 if not node:
3511 node = rev
3476 node = rev
3512
3477
3513 char = {'l': '@', 'x': '*', '': ''}
3478 char = {'l': '@', 'x': '*', '': ''}
3514 mode = {'l': '644', 'x': '755', '': '644'}
3479 mode = {'l': '644', 'x': '755', '': '644'}
3515 ctx = scmutil.revsingle(repo, node)
3480 ctx = scmutil.revsingle(repo, node)
3516 mf = ctx.manifest()
3481 mf = ctx.manifest()
3517 ui.pager('manifest')
3482 ui.pager('manifest')
3518 for f in ctx:
3483 for f in ctx:
3519 fm.startitem()
3484 fm.startitem()
3520 fl = ctx[f].flags()
3485 fl = ctx[f].flags()
3521 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3486 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3522 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3487 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3523 fm.write('path', '%s\n', f)
3488 fm.write('path', '%s\n', f)
3524 fm.end()
3489 fm.end()
3525
3490
3526 @command('^merge',
3491 @command('^merge',
3527 [('f', 'force', None,
3492 [('f', 'force', None,
3528 _('force a merge including outstanding changes (DEPRECATED)')),
3493 _('force a merge including outstanding changes (DEPRECATED)')),
3529 ('r', 'rev', '', _('revision to merge'), _('REV')),
3494 ('r', 'rev', '', _('revision to merge'), _('REV')),
3530 ('P', 'preview', None,
3495 ('P', 'preview', None,
3531 _('review revisions to merge (no merge is performed)'))
3496 _('review revisions to merge (no merge is performed)'))
3532 ] + mergetoolopts,
3497 ] + mergetoolopts,
3533 _('[-P] [[-r] REV]'))
3498 _('[-P] [[-r] REV]'))
3534 def merge(ui, repo, node=None, **opts):
3499 def merge(ui, repo, node=None, **opts):
3535 """merge another revision into working directory
3500 """merge another revision into working directory
3536
3501
3537 The current working directory is updated with all changes made in
3502 The current working directory is updated with all changes made in
3538 the requested revision since the last common predecessor revision.
3503 the requested revision since the last common predecessor revision.
3539
3504
3540 Files that changed between either parent are marked as changed for
3505 Files that changed between either parent are marked as changed for
3541 the next commit and a commit must be performed before any further
3506 the next commit and a commit must be performed before any further
3542 updates to the repository are allowed. The next commit will have
3507 updates to the repository are allowed. The next commit will have
3543 two parents.
3508 two parents.
3544
3509
3545 ``--tool`` can be used to specify the merge tool used for file
3510 ``--tool`` can be used to specify the merge tool used for file
3546 merges. It overrides the HGMERGE environment variable and your
3511 merges. It overrides the HGMERGE environment variable and your
3547 configuration files. See :hg:`help merge-tools` for options.
3512 configuration files. See :hg:`help merge-tools` for options.
3548
3513
3549 If no revision is specified, the working directory's parent is a
3514 If no revision is specified, the working directory's parent is a
3550 head revision, and the current branch contains exactly one other
3515 head revision, and the current branch contains exactly one other
3551 head, the other head is merged with by default. Otherwise, an
3516 head, the other head is merged with by default. Otherwise, an
3552 explicit revision with which to merge with must be provided.
3517 explicit revision with which to merge with must be provided.
3553
3518
3554 See :hg:`help resolve` for information on handling file conflicts.
3519 See :hg:`help resolve` for information on handling file conflicts.
3555
3520
3556 To undo an uncommitted merge, use :hg:`update --clean .` which
3521 To undo an uncommitted merge, use :hg:`update --clean .` which
3557 will check out a clean copy of the original merge parent, losing
3522 will check out a clean copy of the original merge parent, losing
3558 all changes.
3523 all changes.
3559
3524
3560 Returns 0 on success, 1 if there are unresolved files.
3525 Returns 0 on success, 1 if there are unresolved files.
3561 """
3526 """
3562
3527
3563 if opts.get('rev') and node:
3528 if opts.get('rev') and node:
3564 raise error.Abort(_("please specify just one revision"))
3529 raise error.Abort(_("please specify just one revision"))
3565 if not node:
3530 if not node:
3566 node = opts.get('rev')
3531 node = opts.get('rev')
3567
3532
3568 if node:
3533 if node:
3569 node = scmutil.revsingle(repo, node).node()
3534 node = scmutil.revsingle(repo, node).node()
3570
3535
3571 if not node:
3536 if not node:
3572 node = repo[destutil.destmerge(repo)].node()
3537 node = repo[destutil.destmerge(repo)].node()
3573
3538
3574 if opts.get('preview'):
3539 if opts.get('preview'):
3575 # find nodes that are ancestors of p2 but not of p1
3540 # find nodes that are ancestors of p2 but not of p1
3576 p1 = repo.lookup('.')
3541 p1 = repo.lookup('.')
3577 p2 = repo.lookup(node)
3542 p2 = repo.lookup(node)
3578 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3543 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3579
3544
3580 displayer = cmdutil.show_changeset(ui, repo, opts)
3545 displayer = cmdutil.show_changeset(ui, repo, opts)
3581 for node in nodes:
3546 for node in nodes:
3582 displayer.show(repo[node])
3547 displayer.show(repo[node])
3583 displayer.close()
3548 displayer.close()
3584 return 0
3549 return 0
3585
3550
3586 try:
3551 try:
3587 # ui.forcemerge is an internal variable, do not document
3552 # ui.forcemerge is an internal variable, do not document
3588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3553 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3589 force = opts.get('force')
3554 force = opts.get('force')
3590 labels = ['working copy', 'merge rev']
3555 labels = ['working copy', 'merge rev']
3591 return hg.merge(repo, node, force=force, mergeforce=force,
3556 return hg.merge(repo, node, force=force, mergeforce=force,
3592 labels=labels)
3557 labels=labels)
3593 finally:
3558 finally:
3594 ui.setconfig('ui', 'forcemerge', '', 'merge')
3559 ui.setconfig('ui', 'forcemerge', '', 'merge')
3595
3560
3596 @command('outgoing|out',
3561 @command('outgoing|out',
3597 [('f', 'force', None, _('run even when the destination is unrelated')),
3562 [('f', 'force', None, _('run even when the destination is unrelated')),
3598 ('r', 'rev', [],
3563 ('r', 'rev', [],
3599 _('a changeset intended to be included in the destination'), _('REV')),
3564 _('a changeset intended to be included in the destination'), _('REV')),
3600 ('n', 'newest-first', None, _('show newest record first')),
3565 ('n', 'newest-first', None, _('show newest record first')),
3601 ('B', 'bookmarks', False, _('compare bookmarks')),
3566 ('B', 'bookmarks', False, _('compare bookmarks')),
3602 ('b', 'branch', [], _('a specific branch you would like to push'),
3567 ('b', 'branch', [], _('a specific branch you would like to push'),
3603 _('BRANCH')),
3568 _('BRANCH')),
3604 ] + logopts + remoteopts + subrepoopts,
3569 ] + logopts + remoteopts + subrepoopts,
3605 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3570 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3606 def outgoing(ui, repo, dest=None, **opts):
3571 def outgoing(ui, repo, dest=None, **opts):
3607 """show changesets not found in the destination
3572 """show changesets not found in the destination
3608
3573
3609 Show changesets not found in the specified destination repository
3574 Show changesets not found in the specified destination repository
3610 or the default push location. These are the changesets that would
3575 or the default push location. These are the changesets that would
3611 be pushed if a push was requested.
3576 be pushed if a push was requested.
3612
3577
3613 See pull for details of valid destination formats.
3578 See pull for details of valid destination formats.
3614
3579
3615 .. container:: verbose
3580 .. container:: verbose
3616
3581
3617 With -B/--bookmarks, the result of bookmark comparison between
3582 With -B/--bookmarks, the result of bookmark comparison between
3618 local and remote repositories is displayed. With -v/--verbose,
3583 local and remote repositories is displayed. With -v/--verbose,
3619 status is also displayed for each bookmark like below::
3584 status is also displayed for each bookmark like below::
3620
3585
3621 BM1 01234567890a added
3586 BM1 01234567890a added
3622 BM2 deleted
3587 BM2 deleted
3623 BM3 234567890abc advanced
3588 BM3 234567890abc advanced
3624 BM4 34567890abcd diverged
3589 BM4 34567890abcd diverged
3625 BM5 4567890abcde changed
3590 BM5 4567890abcde changed
3626
3591
3627 The action taken when pushing depends on the
3592 The action taken when pushing depends on the
3628 status of each bookmark:
3593 status of each bookmark:
3629
3594
3630 :``added``: push with ``-B`` will create it
3595 :``added``: push with ``-B`` will create it
3631 :``deleted``: push with ``-B`` will delete it
3596 :``deleted``: push with ``-B`` will delete it
3632 :``advanced``: push will update it
3597 :``advanced``: push will update it
3633 :``diverged``: push with ``-B`` will update it
3598 :``diverged``: push with ``-B`` will update it
3634 :``changed``: push with ``-B`` will update it
3599 :``changed``: push with ``-B`` will update it
3635
3600
3636 From the point of view of pushing behavior, bookmarks
3601 From the point of view of pushing behavior, bookmarks
3637 existing only in the remote repository are treated as
3602 existing only in the remote repository are treated as
3638 ``deleted``, even if it is in fact added remotely.
3603 ``deleted``, even if it is in fact added remotely.
3639
3604
3640 Returns 0 if there are outgoing changes, 1 otherwise.
3605 Returns 0 if there are outgoing changes, 1 otherwise.
3641 """
3606 """
3642 if opts.get('graph'):
3607 if opts.get('graph'):
3643 cmdutil.checkunsupportedgraphflags([], opts)
3608 cmdutil.checkunsupportedgraphflags([], opts)
3644 o, other = hg._outgoing(ui, repo, dest, opts)
3609 o, other = hg._outgoing(ui, repo, dest, opts)
3645 if not o:
3610 if not o:
3646 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3611 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3647 return
3612 return
3648
3613
3649 revdag = cmdutil.graphrevs(repo, o, opts)
3614 revdag = cmdutil.graphrevs(repo, o, opts)
3650 ui.pager('outgoing')
3615 ui.pager('outgoing')
3651 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3616 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3652 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3617 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3653 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3618 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3654 return 0
3619 return 0
3655
3620
3656 if opts.get('bookmarks'):
3621 if opts.get('bookmarks'):
3657 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3622 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3658 dest, branches = hg.parseurl(dest, opts.get('branch'))
3623 dest, branches = hg.parseurl(dest, opts.get('branch'))
3659 other = hg.peer(repo, opts, dest)
3624 other = hg.peer(repo, opts, dest)
3660 if 'bookmarks' not in other.listkeys('namespaces'):
3625 if 'bookmarks' not in other.listkeys('namespaces'):
3661 ui.warn(_("remote doesn't support bookmarks\n"))
3626 ui.warn(_("remote doesn't support bookmarks\n"))
3662 return 0
3627 return 0
3663 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3628 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3664 ui.pager('outgoing')
3629 ui.pager('outgoing')
3665 return bookmarks.outgoing(ui, repo, other)
3630 return bookmarks.outgoing(ui, repo, other)
3666
3631
3667 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3632 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3668 try:
3633 try:
3669 return hg.outgoing(ui, repo, dest, opts)
3634 return hg.outgoing(ui, repo, dest, opts)
3670 finally:
3635 finally:
3671 del repo._subtoppath
3636 del repo._subtoppath
3672
3637
3673 @command('parents',
3638 @command('parents',
3674 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3639 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3675 ] + templateopts,
3640 ] + templateopts,
3676 _('[-r REV] [FILE]'),
3641 _('[-r REV] [FILE]'),
3677 inferrepo=True)
3642 inferrepo=True)
3678 def parents(ui, repo, file_=None, **opts):
3643 def parents(ui, repo, file_=None, **opts):
3679 """show the parents of the working directory or revision (DEPRECATED)
3644 """show the parents of the working directory or revision (DEPRECATED)
3680
3645
3681 Print the working directory's parent revisions. If a revision is
3646 Print the working directory's parent revisions. If a revision is
3682 given via -r/--rev, the parent of that revision will be printed.
3647 given via -r/--rev, the parent of that revision will be printed.
3683 If a file argument is given, the revision in which the file was
3648 If a file argument is given, the revision in which the file was
3684 last changed (before the working directory revision or the
3649 last changed (before the working directory revision or the
3685 argument to --rev if given) is printed.
3650 argument to --rev if given) is printed.
3686
3651
3687 This command is equivalent to::
3652 This command is equivalent to::
3688
3653
3689 hg log -r "p1()+p2()" or
3654 hg log -r "p1()+p2()" or
3690 hg log -r "p1(REV)+p2(REV)" or
3655 hg log -r "p1(REV)+p2(REV)" or
3691 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3656 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3692 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3657 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3693
3658
3694 See :hg:`summary` and :hg:`help revsets` for related information.
3659 See :hg:`summary` and :hg:`help revsets` for related information.
3695
3660
3696 Returns 0 on success.
3661 Returns 0 on success.
3697 """
3662 """
3698
3663
3699 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3664 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3700
3665
3701 if file_:
3666 if file_:
3702 m = scmutil.match(ctx, (file_,), opts)
3667 m = scmutil.match(ctx, (file_,), opts)
3703 if m.anypats() or len(m.files()) != 1:
3668 if m.anypats() or len(m.files()) != 1:
3704 raise error.Abort(_('can only specify an explicit filename'))
3669 raise error.Abort(_('can only specify an explicit filename'))
3705 file_ = m.files()[0]
3670 file_ = m.files()[0]
3706 filenodes = []
3671 filenodes = []
3707 for cp in ctx.parents():
3672 for cp in ctx.parents():
3708 if not cp:
3673 if not cp:
3709 continue
3674 continue
3710 try:
3675 try:
3711 filenodes.append(cp.filenode(file_))
3676 filenodes.append(cp.filenode(file_))
3712 except error.LookupError:
3677 except error.LookupError:
3713 pass
3678 pass
3714 if not filenodes:
3679 if not filenodes:
3715 raise error.Abort(_("'%s' not found in manifest!") % file_)
3680 raise error.Abort(_("'%s' not found in manifest!") % file_)
3716 p = []
3681 p = []
3717 for fn in filenodes:
3682 for fn in filenodes:
3718 fctx = repo.filectx(file_, fileid=fn)
3683 fctx = repo.filectx(file_, fileid=fn)
3719 p.append(fctx.node())
3684 p.append(fctx.node())
3720 else:
3685 else:
3721 p = [cp.node() for cp in ctx.parents()]
3686 p = [cp.node() for cp in ctx.parents()]
3722
3687
3723 displayer = cmdutil.show_changeset(ui, repo, opts)
3688 displayer = cmdutil.show_changeset(ui, repo, opts)
3724 for n in p:
3689 for n in p:
3725 if n != nullid:
3690 if n != nullid:
3726 displayer.show(repo[n])
3691 displayer.show(repo[n])
3727 displayer.close()
3692 displayer.close()
3728
3693
3729 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3694 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3730 def paths(ui, repo, search=None, **opts):
3695 def paths(ui, repo, search=None, **opts):
3731 """show aliases for remote repositories
3696 """show aliases for remote repositories
3732
3697
3733 Show definition of symbolic path name NAME. If no name is given,
3698 Show definition of symbolic path name NAME. If no name is given,
3734 show definition of all available names.
3699 show definition of all available names.
3735
3700
3736 Option -q/--quiet suppresses all output when searching for NAME
3701 Option -q/--quiet suppresses all output when searching for NAME
3737 and shows only the path names when listing all definitions.
3702 and shows only the path names when listing all definitions.
3738
3703
3739 Path names are defined in the [paths] section of your
3704 Path names are defined in the [paths] section of your
3740 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3705 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3741 repository, ``.hg/hgrc`` is used, too.
3706 repository, ``.hg/hgrc`` is used, too.
3742
3707
3743 The path names ``default`` and ``default-push`` have a special
3708 The path names ``default`` and ``default-push`` have a special
3744 meaning. When performing a push or pull operation, they are used
3709 meaning. When performing a push or pull operation, they are used
3745 as fallbacks if no location is specified on the command-line.
3710 as fallbacks if no location is specified on the command-line.
3746 When ``default-push`` is set, it will be used for push and
3711 When ``default-push`` is set, it will be used for push and
3747 ``default`` will be used for pull; otherwise ``default`` is used
3712 ``default`` will be used for pull; otherwise ``default`` is used
3748 as the fallback for both. When cloning a repository, the clone
3713 as the fallback for both. When cloning a repository, the clone
3749 source is written as ``default`` in ``.hg/hgrc``.
3714 source is written as ``default`` in ``.hg/hgrc``.
3750
3715
3751 .. note::
3716 .. note::
3752
3717
3753 ``default`` and ``default-push`` apply to all inbound (e.g.
3718 ``default`` and ``default-push`` apply to all inbound (e.g.
3754 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3719 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3755 and :hg:`bundle`) operations.
3720 and :hg:`bundle`) operations.
3756
3721
3757 See :hg:`help urls` for more information.
3722 See :hg:`help urls` for more information.
3758
3723
3759 Returns 0 on success.
3724 Returns 0 on success.
3760 """
3725 """
3761 ui.pager('paths')
3726 ui.pager('paths')
3762 if search:
3727 if search:
3763 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3728 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3764 if name == search]
3729 if name == search]
3765 else:
3730 else:
3766 pathitems = sorted(ui.paths.iteritems())
3731 pathitems = sorted(ui.paths.iteritems())
3767
3732
3768 fm = ui.formatter('paths', opts)
3733 fm = ui.formatter('paths', opts)
3769 if fm.isplain():
3734 if fm.isplain():
3770 hidepassword = util.hidepassword
3735 hidepassword = util.hidepassword
3771 else:
3736 else:
3772 hidepassword = str
3737 hidepassword = str
3773 if ui.quiet:
3738 if ui.quiet:
3774 namefmt = '%s\n'
3739 namefmt = '%s\n'
3775 else:
3740 else:
3776 namefmt = '%s = '
3741 namefmt = '%s = '
3777 showsubopts = not search and not ui.quiet
3742 showsubopts = not search and not ui.quiet
3778
3743
3779 for name, path in pathitems:
3744 for name, path in pathitems:
3780 fm.startitem()
3745 fm.startitem()
3781 fm.condwrite(not search, 'name', namefmt, name)
3746 fm.condwrite(not search, 'name', namefmt, name)
3782 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3747 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3783 for subopt, value in sorted(path.suboptions.items()):
3748 for subopt, value in sorted(path.suboptions.items()):
3784 assert subopt not in ('name', 'url')
3749 assert subopt not in ('name', 'url')
3785 if showsubopts:
3750 if showsubopts:
3786 fm.plain('%s:%s = ' % (name, subopt))
3751 fm.plain('%s:%s = ' % (name, subopt))
3787 fm.condwrite(showsubopts, subopt, '%s\n', value)
3752 fm.condwrite(showsubopts, subopt, '%s\n', value)
3788
3753
3789 fm.end()
3754 fm.end()
3790
3755
3791 if search and not pathitems:
3756 if search and not pathitems:
3792 if not ui.quiet:
3757 if not ui.quiet:
3793 ui.warn(_("not found!\n"))
3758 ui.warn(_("not found!\n"))
3794 return 1
3759 return 1
3795 else:
3760 else:
3796 return 0
3761 return 0
3797
3762
3798 @command('phase',
3763 @command('phase',
3799 [('p', 'public', False, _('set changeset phase to public')),
3764 [('p', 'public', False, _('set changeset phase to public')),
3800 ('d', 'draft', False, _('set changeset phase to draft')),
3765 ('d', 'draft', False, _('set changeset phase to draft')),
3801 ('s', 'secret', False, _('set changeset phase to secret')),
3766 ('s', 'secret', False, _('set changeset phase to secret')),
3802 ('f', 'force', False, _('allow to move boundary backward')),
3767 ('f', 'force', False, _('allow to move boundary backward')),
3803 ('r', 'rev', [], _('target revision'), _('REV')),
3768 ('r', 'rev', [], _('target revision'), _('REV')),
3804 ],
3769 ],
3805 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3770 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3806 def phase(ui, repo, *revs, **opts):
3771 def phase(ui, repo, *revs, **opts):
3807 """set or show the current phase name
3772 """set or show the current phase name
3808
3773
3809 With no argument, show the phase name of the current revision(s).
3774 With no argument, show the phase name of the current revision(s).
3810
3775
3811 With one of -p/--public, -d/--draft or -s/--secret, change the
3776 With one of -p/--public, -d/--draft or -s/--secret, change the
3812 phase value of the specified revisions.
3777 phase value of the specified revisions.
3813
3778
3814 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3779 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3815 lower phase to an higher phase. Phases are ordered as follows::
3780 lower phase to an higher phase. Phases are ordered as follows::
3816
3781
3817 public < draft < secret
3782 public < draft < secret
3818
3783
3819 Returns 0 on success, 1 if some phases could not be changed.
3784 Returns 0 on success, 1 if some phases could not be changed.
3820
3785
3821 (For more information about the phases concept, see :hg:`help phases`.)
3786 (For more information about the phases concept, see :hg:`help phases`.)
3822 """
3787 """
3823 # search for a unique phase argument
3788 # search for a unique phase argument
3824 targetphase = None
3789 targetphase = None
3825 for idx, name in enumerate(phases.phasenames):
3790 for idx, name in enumerate(phases.phasenames):
3826 if opts[name]:
3791 if opts[name]:
3827 if targetphase is not None:
3792 if targetphase is not None:
3828 raise error.Abort(_('only one phase can be specified'))
3793 raise error.Abort(_('only one phase can be specified'))
3829 targetphase = idx
3794 targetphase = idx
3830
3795
3831 # look for specified revision
3796 # look for specified revision
3832 revs = list(revs)
3797 revs = list(revs)
3833 revs.extend(opts['rev'])
3798 revs.extend(opts['rev'])
3834 if not revs:
3799 if not revs:
3835 # display both parents as the second parent phase can influence
3800 # display both parents as the second parent phase can influence
3836 # the phase of a merge commit
3801 # the phase of a merge commit
3837 revs = [c.rev() for c in repo[None].parents()]
3802 revs = [c.rev() for c in repo[None].parents()]
3838
3803
3839 revs = scmutil.revrange(repo, revs)
3804 revs = scmutil.revrange(repo, revs)
3840
3805
3841 lock = None
3806 lock = None
3842 ret = 0
3807 ret = 0
3843 if targetphase is None:
3808 if targetphase is None:
3844 # display
3809 # display
3845 for r in revs:
3810 for r in revs:
3846 ctx = repo[r]
3811 ctx = repo[r]
3847 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3812 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3848 else:
3813 else:
3849 tr = None
3814 tr = None
3850 lock = repo.lock()
3815 lock = repo.lock()
3851 try:
3816 try:
3852 tr = repo.transaction("phase")
3817 tr = repo.transaction("phase")
3853 # set phase
3818 # set phase
3854 if not revs:
3819 if not revs:
3855 raise error.Abort(_('empty revision set'))
3820 raise error.Abort(_('empty revision set'))
3856 nodes = [repo[r].node() for r in revs]
3821 nodes = [repo[r].node() for r in revs]
3857 # moving revision from public to draft may hide them
3822 # moving revision from public to draft may hide them
3858 # We have to check result on an unfiltered repository
3823 # We have to check result on an unfiltered repository
3859 unfi = repo.unfiltered()
3824 unfi = repo.unfiltered()
3860 getphase = unfi._phasecache.phase
3825 getphase = unfi._phasecache.phase
3861 olddata = [getphase(unfi, r) for r in unfi]
3826 olddata = [getphase(unfi, r) for r in unfi]
3862 phases.advanceboundary(repo, tr, targetphase, nodes)
3827 phases.advanceboundary(repo, tr, targetphase, nodes)
3863 if opts['force']:
3828 if opts['force']:
3864 phases.retractboundary(repo, tr, targetphase, nodes)
3829 phases.retractboundary(repo, tr, targetphase, nodes)
3865 tr.close()
3830 tr.close()
3866 finally:
3831 finally:
3867 if tr is not None:
3832 if tr is not None:
3868 tr.release()
3833 tr.release()
3869 lock.release()
3834 lock.release()
3870 getphase = unfi._phasecache.phase
3835 getphase = unfi._phasecache.phase
3871 newdata = [getphase(unfi, r) for r in unfi]
3836 newdata = [getphase(unfi, r) for r in unfi]
3872 changes = sum(newdata[r] != olddata[r] for r in unfi)
3837 changes = sum(newdata[r] != olddata[r] for r in unfi)
3873 cl = unfi.changelog
3838 cl = unfi.changelog
3874 rejected = [n for n in nodes
3839 rejected = [n for n in nodes
3875 if newdata[cl.rev(n)] < targetphase]
3840 if newdata[cl.rev(n)] < targetphase]
3876 if rejected:
3841 if rejected:
3877 ui.warn(_('cannot move %i changesets to a higher '
3842 ui.warn(_('cannot move %i changesets to a higher '
3878 'phase, use --force\n') % len(rejected))
3843 'phase, use --force\n') % len(rejected))
3879 ret = 1
3844 ret = 1
3880 if changes:
3845 if changes:
3881 msg = _('phase changed for %i changesets\n') % changes
3846 msg = _('phase changed for %i changesets\n') % changes
3882 if ret:
3847 if ret:
3883 ui.status(msg)
3848 ui.status(msg)
3884 else:
3849 else:
3885 ui.note(msg)
3850 ui.note(msg)
3886 else:
3851 else:
3887 ui.warn(_('no phases changed\n'))
3852 ui.warn(_('no phases changed\n'))
3888 return ret
3853 return ret
3889
3854
3890 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3855 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3891 """Run after a changegroup has been added via pull/unbundle
3856 """Run after a changegroup has been added via pull/unbundle
3892
3857
3893 This takes arguments below:
3858 This takes arguments below:
3894
3859
3895 :modheads: change of heads by pull/unbundle
3860 :modheads: change of heads by pull/unbundle
3896 :optupdate: updating working directory is needed or not
3861 :optupdate: updating working directory is needed or not
3897 :checkout: update destination revision (or None to default destination)
3862 :checkout: update destination revision (or None to default destination)
3898 :brev: a name, which might be a bookmark to be activated after updating
3863 :brev: a name, which might be a bookmark to be activated after updating
3899 """
3864 """
3900 if modheads == 0:
3865 if modheads == 0:
3901 return
3866 return
3902 if optupdate:
3867 if optupdate:
3903 try:
3868 try:
3904 return hg.updatetotally(ui, repo, checkout, brev)
3869 return hg.updatetotally(ui, repo, checkout, brev)
3905 except error.UpdateAbort as inst:
3870 except error.UpdateAbort as inst:
3906 msg = _("not updating: %s") % str(inst)
3871 msg = _("not updating: %s") % str(inst)
3907 hint = inst.hint
3872 hint = inst.hint
3908 raise error.UpdateAbort(msg, hint=hint)
3873 raise error.UpdateAbort(msg, hint=hint)
3909 if modheads > 1:
3874 if modheads > 1:
3910 currentbranchheads = len(repo.branchheads())
3875 currentbranchheads = len(repo.branchheads())
3911 if currentbranchheads == modheads:
3876 if currentbranchheads == modheads:
3912 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3877 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3913 elif currentbranchheads > 1:
3878 elif currentbranchheads > 1:
3914 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3879 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3915 "merge)\n"))
3880 "merge)\n"))
3916 else:
3881 else:
3917 ui.status(_("(run 'hg heads' to see heads)\n"))
3882 ui.status(_("(run 'hg heads' to see heads)\n"))
3918 else:
3883 else:
3919 ui.status(_("(run 'hg update' to get a working copy)\n"))
3884 ui.status(_("(run 'hg update' to get a working copy)\n"))
3920
3885
3921 @command('^pull',
3886 @command('^pull',
3922 [('u', 'update', None,
3887 [('u', 'update', None,
3923 _('update to new branch head if changesets were pulled')),
3888 _('update to new branch head if changesets were pulled')),
3924 ('f', 'force', None, _('run even when remote repository is unrelated')),
3889 ('f', 'force', None, _('run even when remote repository is unrelated')),
3925 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3890 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3926 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3891 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3927 ('b', 'branch', [], _('a specific branch you would like to pull'),
3892 ('b', 'branch', [], _('a specific branch you would like to pull'),
3928 _('BRANCH')),
3893 _('BRANCH')),
3929 ] + remoteopts,
3894 ] + remoteopts,
3930 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3895 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3931 def pull(ui, repo, source="default", **opts):
3896 def pull(ui, repo, source="default", **opts):
3932 """pull changes from the specified source
3897 """pull changes from the specified source
3933
3898
3934 Pull changes from a remote repository to a local one.
3899 Pull changes from a remote repository to a local one.
3935
3900
3936 This finds all changes from the repository at the specified path
3901 This finds all changes from the repository at the specified path
3937 or URL and adds them to a local repository (the current one unless
3902 or URL and adds them to a local repository (the current one unless
3938 -R is specified). By default, this does not update the copy of the
3903 -R is specified). By default, this does not update the copy of the
3939 project in the working directory.
3904 project in the working directory.
3940
3905
3941 Use :hg:`incoming` if you want to see what would have been added
3906 Use :hg:`incoming` if you want to see what would have been added
3942 by a pull at the time you issued this command. If you then decide
3907 by a pull at the time you issued this command. If you then decide
3943 to add those changes to the repository, you should use :hg:`pull
3908 to add those changes to the repository, you should use :hg:`pull
3944 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3909 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3945
3910
3946 If SOURCE is omitted, the 'default' path will be used.
3911 If SOURCE is omitted, the 'default' path will be used.
3947 See :hg:`help urls` for more information.
3912 See :hg:`help urls` for more information.
3948
3913
3949 Specifying bookmark as ``.`` is equivalent to specifying the active
3914 Specifying bookmark as ``.`` is equivalent to specifying the active
3950 bookmark's name.
3915 bookmark's name.
3951
3916
3952 Returns 0 on success, 1 if an update had unresolved files.
3917 Returns 0 on success, 1 if an update had unresolved files.
3953 """
3918 """
3954 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3919 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3955 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3920 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3956 other = hg.peer(repo, opts, source)
3921 other = hg.peer(repo, opts, source)
3957 try:
3922 try:
3958 revs, checkout = hg.addbranchrevs(repo, other, branches,
3923 revs, checkout = hg.addbranchrevs(repo, other, branches,
3959 opts.get('rev'))
3924 opts.get('rev'))
3960
3925
3961
3926
3962 pullopargs = {}
3927 pullopargs = {}
3963 if opts.get('bookmark'):
3928 if opts.get('bookmark'):
3964 if not revs:
3929 if not revs:
3965 revs = []
3930 revs = []
3966 # The list of bookmark used here is not the one used to actually
3931 # The list of bookmark used here is not the one used to actually
3967 # update the bookmark name. This can result in the revision pulled
3932 # update the bookmark name. This can result in the revision pulled
3968 # not ending up with the name of the bookmark because of a race
3933 # not ending up with the name of the bookmark because of a race
3969 # condition on the server. (See issue 4689 for details)
3934 # condition on the server. (See issue 4689 for details)
3970 remotebookmarks = other.listkeys('bookmarks')
3935 remotebookmarks = other.listkeys('bookmarks')
3971 pullopargs['remotebookmarks'] = remotebookmarks
3936 pullopargs['remotebookmarks'] = remotebookmarks
3972 for b in opts['bookmark']:
3937 for b in opts['bookmark']:
3973 b = repo._bookmarks.expandname(b)
3938 b = repo._bookmarks.expandname(b)
3974 if b not in remotebookmarks:
3939 if b not in remotebookmarks:
3975 raise error.Abort(_('remote bookmark %s not found!') % b)
3940 raise error.Abort(_('remote bookmark %s not found!') % b)
3976 revs.append(remotebookmarks[b])
3941 revs.append(remotebookmarks[b])
3977
3942
3978 if revs:
3943 if revs:
3979 try:
3944 try:
3980 # When 'rev' is a bookmark name, we cannot guarantee that it
3945 # When 'rev' is a bookmark name, we cannot guarantee that it
3981 # will be updated with that name because of a race condition
3946 # will be updated with that name because of a race condition
3982 # server side. (See issue 4689 for details)
3947 # server side. (See issue 4689 for details)
3983 oldrevs = revs
3948 oldrevs = revs
3984 revs = [] # actually, nodes
3949 revs = [] # actually, nodes
3985 for r in oldrevs:
3950 for r in oldrevs:
3986 node = other.lookup(r)
3951 node = other.lookup(r)
3987 revs.append(node)
3952 revs.append(node)
3988 if r == checkout:
3953 if r == checkout:
3989 checkout = node
3954 checkout = node
3990 except error.CapabilityError:
3955 except error.CapabilityError:
3991 err = _("other repository doesn't support revision lookup, "
3956 err = _("other repository doesn't support revision lookup, "
3992 "so a rev cannot be specified.")
3957 "so a rev cannot be specified.")
3993 raise error.Abort(err)
3958 raise error.Abort(err)
3994
3959
3995 pullopargs.update(opts.get('opargs', {}))
3960 pullopargs.update(opts.get('opargs', {}))
3996 modheads = exchange.pull(repo, other, heads=revs,
3961 modheads = exchange.pull(repo, other, heads=revs,
3997 force=opts.get('force'),
3962 force=opts.get('force'),
3998 bookmarks=opts.get('bookmark', ()),
3963 bookmarks=opts.get('bookmark', ()),
3999 opargs=pullopargs).cgresult
3964 opargs=pullopargs).cgresult
4000
3965
4001 # brev is a name, which might be a bookmark to be activated at
3966 # brev is a name, which might be a bookmark to be activated at
4002 # the end of the update. In other words, it is an explicit
3967 # the end of the update. In other words, it is an explicit
4003 # destination of the update
3968 # destination of the update
4004 brev = None
3969 brev = None
4005
3970
4006 if checkout:
3971 if checkout:
4007 checkout = str(repo.changelog.rev(checkout))
3972 checkout = str(repo.changelog.rev(checkout))
4008
3973
4009 # order below depends on implementation of
3974 # order below depends on implementation of
4010 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3975 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4011 # because 'checkout' is determined without it.
3976 # because 'checkout' is determined without it.
4012 if opts.get('rev'):
3977 if opts.get('rev'):
4013 brev = opts['rev'][0]
3978 brev = opts['rev'][0]
4014 elif opts.get('branch'):
3979 elif opts.get('branch'):
4015 brev = opts['branch'][0]
3980 brev = opts['branch'][0]
4016 else:
3981 else:
4017 brev = branches[0]
3982 brev = branches[0]
4018 repo._subtoppath = source
3983 repo._subtoppath = source
4019 try:
3984 try:
4020 ret = postincoming(ui, repo, modheads, opts.get('update'),
3985 ret = postincoming(ui, repo, modheads, opts.get('update'),
4021 checkout, brev)
3986 checkout, brev)
4022
3987
4023 finally:
3988 finally:
4024 del repo._subtoppath
3989 del repo._subtoppath
4025
3990
4026 finally:
3991 finally:
4027 other.close()
3992 other.close()
4028 return ret
3993 return ret
4029
3994
4030 @command('^push',
3995 @command('^push',
4031 [('f', 'force', None, _('force push')),
3996 [('f', 'force', None, _('force push')),
4032 ('r', 'rev', [],
3997 ('r', 'rev', [],
4033 _('a changeset intended to be included in the destination'),
3998 _('a changeset intended to be included in the destination'),
4034 _('REV')),
3999 _('REV')),
4035 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4000 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4036 ('b', 'branch', [],
4001 ('b', 'branch', [],
4037 _('a specific branch you would like to push'), _('BRANCH')),
4002 _('a specific branch you would like to push'), _('BRANCH')),
4038 ('', 'new-branch', False, _('allow pushing a new branch')),
4003 ('', 'new-branch', False, _('allow pushing a new branch')),
4039 ] + remoteopts,
4004 ] + remoteopts,
4040 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4005 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4041 def push(ui, repo, dest=None, **opts):
4006 def push(ui, repo, dest=None, **opts):
4042 """push changes to the specified destination
4007 """push changes to the specified destination
4043
4008
4044 Push changesets from the local repository to the specified
4009 Push changesets from the local repository to the specified
4045 destination.
4010 destination.
4046
4011
4047 This operation is symmetrical to pull: it is identical to a pull
4012 This operation is symmetrical to pull: it is identical to a pull
4048 in the destination repository from the current one.
4013 in the destination repository from the current one.
4049
4014
4050 By default, push will not allow creation of new heads at the
4015 By default, push will not allow creation of new heads at the
4051 destination, since multiple heads would make it unclear which head
4016 destination, since multiple heads would make it unclear which head
4052 to use. In this situation, it is recommended to pull and merge
4017 to use. In this situation, it is recommended to pull and merge
4053 before pushing.
4018 before pushing.
4054
4019
4055 Use --new-branch if you want to allow push to create a new named
4020 Use --new-branch if you want to allow push to create a new named
4056 branch that is not present at the destination. This allows you to
4021 branch that is not present at the destination. This allows you to
4057 only create a new branch without forcing other changes.
4022 only create a new branch without forcing other changes.
4058
4023
4059 .. note::
4024 .. note::
4060
4025
4061 Extra care should be taken with the -f/--force option,
4026 Extra care should be taken with the -f/--force option,
4062 which will push all new heads on all branches, an action which will
4027 which will push all new heads on all branches, an action which will
4063 almost always cause confusion for collaborators.
4028 almost always cause confusion for collaborators.
4064
4029
4065 If -r/--rev is used, the specified revision and all its ancestors
4030 If -r/--rev is used, the specified revision and all its ancestors
4066 will be pushed to the remote repository.
4031 will be pushed to the remote repository.
4067
4032
4068 If -B/--bookmark is used, the specified bookmarked revision, its
4033 If -B/--bookmark is used, the specified bookmarked revision, its
4069 ancestors, and the bookmark will be pushed to the remote
4034 ancestors, and the bookmark will be pushed to the remote
4070 repository. Specifying ``.`` is equivalent to specifying the active
4035 repository. Specifying ``.`` is equivalent to specifying the active
4071 bookmark's name.
4036 bookmark's name.
4072
4037
4073 Please see :hg:`help urls` for important details about ``ssh://``
4038 Please see :hg:`help urls` for important details about ``ssh://``
4074 URLs. If DESTINATION is omitted, a default path will be used.
4039 URLs. If DESTINATION is omitted, a default path will be used.
4075
4040
4076 Returns 0 if push was successful, 1 if nothing to push.
4041 Returns 0 if push was successful, 1 if nothing to push.
4077 """
4042 """
4078
4043
4079 if opts.get('bookmark'):
4044 if opts.get('bookmark'):
4080 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4045 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4081 for b in opts['bookmark']:
4046 for b in opts['bookmark']:
4082 # translate -B options to -r so changesets get pushed
4047 # translate -B options to -r so changesets get pushed
4083 b = repo._bookmarks.expandname(b)
4048 b = repo._bookmarks.expandname(b)
4084 if b in repo._bookmarks:
4049 if b in repo._bookmarks:
4085 opts.setdefault('rev', []).append(b)
4050 opts.setdefault('rev', []).append(b)
4086 else:
4051 else:
4087 # if we try to push a deleted bookmark, translate it to null
4052 # if we try to push a deleted bookmark, translate it to null
4088 # this lets simultaneous -r, -b options continue working
4053 # this lets simultaneous -r, -b options continue working
4089 opts.setdefault('rev', []).append("null")
4054 opts.setdefault('rev', []).append("null")
4090
4055
4091 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4056 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4092 if not path:
4057 if not path:
4093 raise error.Abort(_('default repository not configured!'),
4058 raise error.Abort(_('default repository not configured!'),
4094 hint=_("see 'hg help config.paths'"))
4059 hint=_("see 'hg help config.paths'"))
4095 dest = path.pushloc or path.loc
4060 dest = path.pushloc or path.loc
4096 branches = (path.branch, opts.get('branch') or [])
4061 branches = (path.branch, opts.get('branch') or [])
4097 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4062 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4098 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4063 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4099 other = hg.peer(repo, opts, dest)
4064 other = hg.peer(repo, opts, dest)
4100
4065
4101 if revs:
4066 if revs:
4102 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4067 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4103 if not revs:
4068 if not revs:
4104 raise error.Abort(_("specified revisions evaluate to an empty set"),
4069 raise error.Abort(_("specified revisions evaluate to an empty set"),
4105 hint=_("use different revision arguments"))
4070 hint=_("use different revision arguments"))
4106 elif path.pushrev:
4071 elif path.pushrev:
4107 # It doesn't make any sense to specify ancestor revisions. So limit
4072 # It doesn't make any sense to specify ancestor revisions. So limit
4108 # to DAG heads to make discovery simpler.
4073 # to DAG heads to make discovery simpler.
4109 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4074 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4110 revs = scmutil.revrange(repo, [expr])
4075 revs = scmutil.revrange(repo, [expr])
4111 revs = [repo[rev].node() for rev in revs]
4076 revs = [repo[rev].node() for rev in revs]
4112 if not revs:
4077 if not revs:
4113 raise error.Abort(_('default push revset for path evaluates to an '
4078 raise error.Abort(_('default push revset for path evaluates to an '
4114 'empty set'))
4079 'empty set'))
4115
4080
4116 repo._subtoppath = dest
4081 repo._subtoppath = dest
4117 try:
4082 try:
4118 # push subrepos depth-first for coherent ordering
4083 # push subrepos depth-first for coherent ordering
4119 c = repo['']
4084 c = repo['']
4120 subs = c.substate # only repos that are committed
4085 subs = c.substate # only repos that are committed
4121 for s in sorted(subs):
4086 for s in sorted(subs):
4122 result = c.sub(s).push(opts)
4087 result = c.sub(s).push(opts)
4123 if result == 0:
4088 if result == 0:
4124 return not result
4089 return not result
4125 finally:
4090 finally:
4126 del repo._subtoppath
4091 del repo._subtoppath
4127 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4092 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4128 newbranch=opts.get('new_branch'),
4093 newbranch=opts.get('new_branch'),
4129 bookmarks=opts.get('bookmark', ()),
4094 bookmarks=opts.get('bookmark', ()),
4130 opargs=opts.get('opargs'))
4095 opargs=opts.get('opargs'))
4131
4096
4132 result = not pushop.cgresult
4097 result = not pushop.cgresult
4133
4098
4134 if pushop.bkresult is not None:
4099 if pushop.bkresult is not None:
4135 if pushop.bkresult == 2:
4100 if pushop.bkresult == 2:
4136 result = 2
4101 result = 2
4137 elif not result and pushop.bkresult:
4102 elif not result and pushop.bkresult:
4138 result = 2
4103 result = 2
4139
4104
4140 return result
4105 return result
4141
4106
4142 @command('recover', [])
4107 @command('recover', [])
4143 def recover(ui, repo):
4108 def recover(ui, repo):
4144 """roll back an interrupted transaction
4109 """roll back an interrupted transaction
4145
4110
4146 Recover from an interrupted commit or pull.
4111 Recover from an interrupted commit or pull.
4147
4112
4148 This command tries to fix the repository status after an
4113 This command tries to fix the repository status after an
4149 interrupted operation. It should only be necessary when Mercurial
4114 interrupted operation. It should only be necessary when Mercurial
4150 suggests it.
4115 suggests it.
4151
4116
4152 Returns 0 if successful, 1 if nothing to recover or verify fails.
4117 Returns 0 if successful, 1 if nothing to recover or verify fails.
4153 """
4118 """
4154 if repo.recover():
4119 if repo.recover():
4155 return hg.verify(repo)
4120 return hg.verify(repo)
4156 return 1
4121 return 1
4157
4122
4158 @command('^remove|rm',
4123 @command('^remove|rm',
4159 [('A', 'after', None, _('record delete for missing files')),
4124 [('A', 'after', None, _('record delete for missing files')),
4160 ('f', 'force', None,
4125 ('f', 'force', None,
4161 _('forget added files, delete modified files')),
4126 _('forget added files, delete modified files')),
4162 ] + subrepoopts + walkopts,
4127 ] + subrepoopts + walkopts,
4163 _('[OPTION]... FILE...'),
4128 _('[OPTION]... FILE...'),
4164 inferrepo=True)
4129 inferrepo=True)
4165 def remove(ui, repo, *pats, **opts):
4130 def remove(ui, repo, *pats, **opts):
4166 """remove the specified files on the next commit
4131 """remove the specified files on the next commit
4167
4132
4168 Schedule the indicated files for removal from the current branch.
4133 Schedule the indicated files for removal from the current branch.
4169
4134
4170 This command schedules the files to be removed at the next commit.
4135 This command schedules the files to be removed at the next commit.
4171 To undo a remove before that, see :hg:`revert`. To undo added
4136 To undo a remove before that, see :hg:`revert`. To undo added
4172 files, see :hg:`forget`.
4137 files, see :hg:`forget`.
4173
4138
4174 .. container:: verbose
4139 .. container:: verbose
4175
4140
4176 -A/--after can be used to remove only files that have already
4141 -A/--after can be used to remove only files that have already
4177 been deleted, -f/--force can be used to force deletion, and -Af
4142 been deleted, -f/--force can be used to force deletion, and -Af
4178 can be used to remove files from the next revision without
4143 can be used to remove files from the next revision without
4179 deleting them from the working directory.
4144 deleting them from the working directory.
4180
4145
4181 The following table details the behavior of remove for different
4146 The following table details the behavior of remove for different
4182 file states (columns) and option combinations (rows). The file
4147 file states (columns) and option combinations (rows). The file
4183 states are Added [A], Clean [C], Modified [M] and Missing [!]
4148 states are Added [A], Clean [C], Modified [M] and Missing [!]
4184 (as reported by :hg:`status`). The actions are Warn, Remove
4149 (as reported by :hg:`status`). The actions are Warn, Remove
4185 (from branch) and Delete (from disk):
4150 (from branch) and Delete (from disk):
4186
4151
4187 ========= == == == ==
4152 ========= == == == ==
4188 opt/state A C M !
4153 opt/state A C M !
4189 ========= == == == ==
4154 ========= == == == ==
4190 none W RD W R
4155 none W RD W R
4191 -f R RD RD R
4156 -f R RD RD R
4192 -A W W W R
4157 -A W W W R
4193 -Af R R R R
4158 -Af R R R R
4194 ========= == == == ==
4159 ========= == == == ==
4195
4160
4196 .. note::
4161 .. note::
4197
4162
4198 :hg:`remove` never deletes files in Added [A] state from the
4163 :hg:`remove` never deletes files in Added [A] state from the
4199 working directory, not even if ``--force`` is specified.
4164 working directory, not even if ``--force`` is specified.
4200
4165
4201 Returns 0 on success, 1 if any warnings encountered.
4166 Returns 0 on success, 1 if any warnings encountered.
4202 """
4167 """
4203
4168
4204 after, force = opts.get('after'), opts.get('force')
4169 after, force = opts.get('after'), opts.get('force')
4205 if not pats and not after:
4170 if not pats and not after:
4206 raise error.Abort(_('no files specified'))
4171 raise error.Abort(_('no files specified'))
4207
4172
4208 m = scmutil.match(repo[None], pats, opts)
4173 m = scmutil.match(repo[None], pats, opts)
4209 subrepos = opts.get('subrepos')
4174 subrepos = opts.get('subrepos')
4210 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4175 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4211
4176
4212 @command('rename|move|mv',
4177 @command('rename|move|mv',
4213 [('A', 'after', None, _('record a rename that has already occurred')),
4178 [('A', 'after', None, _('record a rename that has already occurred')),
4214 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4179 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4215 ] + walkopts + dryrunopts,
4180 ] + walkopts + dryrunopts,
4216 _('[OPTION]... SOURCE... DEST'))
4181 _('[OPTION]... SOURCE... DEST'))
4217 def rename(ui, repo, *pats, **opts):
4182 def rename(ui, repo, *pats, **opts):
4218 """rename files; equivalent of copy + remove
4183 """rename files; equivalent of copy + remove
4219
4184
4220 Mark dest as copies of sources; mark sources for deletion. If dest
4185 Mark dest as copies of sources; mark sources for deletion. If dest
4221 is a directory, copies are put in that directory. If dest is a
4186 is a directory, copies are put in that directory. If dest is a
4222 file, there can only be one source.
4187 file, there can only be one source.
4223
4188
4224 By default, this command copies the contents of files as they
4189 By default, this command copies the contents of files as they
4225 exist in the working directory. If invoked with -A/--after, the
4190 exist in the working directory. If invoked with -A/--after, the
4226 operation is recorded, but no copying is performed.
4191 operation is recorded, but no copying is performed.
4227
4192
4228 This command takes effect at the next commit. To undo a rename
4193 This command takes effect at the next commit. To undo a rename
4229 before that, see :hg:`revert`.
4194 before that, see :hg:`revert`.
4230
4195
4231 Returns 0 on success, 1 if errors are encountered.
4196 Returns 0 on success, 1 if errors are encountered.
4232 """
4197 """
4233 with repo.wlock(False):
4198 with repo.wlock(False):
4234 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4199 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4235
4200
4236 @command('resolve',
4201 @command('resolve',
4237 [('a', 'all', None, _('select all unresolved files')),
4202 [('a', 'all', None, _('select all unresolved files')),
4238 ('l', 'list', None, _('list state of files needing merge')),
4203 ('l', 'list', None, _('list state of files needing merge')),
4239 ('m', 'mark', None, _('mark files as resolved')),
4204 ('m', 'mark', None, _('mark files as resolved')),
4240 ('u', 'unmark', None, _('mark files as unresolved')),
4205 ('u', 'unmark', None, _('mark files as unresolved')),
4241 ('n', 'no-status', None, _('hide status prefix'))]
4206 ('n', 'no-status', None, _('hide status prefix'))]
4242 + mergetoolopts + walkopts + formatteropts,
4207 + mergetoolopts + walkopts + formatteropts,
4243 _('[OPTION]... [FILE]...'),
4208 _('[OPTION]... [FILE]...'),
4244 inferrepo=True)
4209 inferrepo=True)
4245 def resolve(ui, repo, *pats, **opts):
4210 def resolve(ui, repo, *pats, **opts):
4246 """redo merges or set/view the merge status of files
4211 """redo merges or set/view the merge status of files
4247
4212
4248 Merges with unresolved conflicts are often the result of
4213 Merges with unresolved conflicts are often the result of
4249 non-interactive merging using the ``internal:merge`` configuration
4214 non-interactive merging using the ``internal:merge`` configuration
4250 setting, or a command-line merge tool like ``diff3``. The resolve
4215 setting, or a command-line merge tool like ``diff3``. The resolve
4251 command is used to manage the files involved in a merge, after
4216 command is used to manage the files involved in a merge, after
4252 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4217 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4253 working directory must have two parents). See :hg:`help
4218 working directory must have two parents). See :hg:`help
4254 merge-tools` for information on configuring merge tools.
4219 merge-tools` for information on configuring merge tools.
4255
4220
4256 The resolve command can be used in the following ways:
4221 The resolve command can be used in the following ways:
4257
4222
4258 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4223 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4259 files, discarding any previous merge attempts. Re-merging is not
4224 files, discarding any previous merge attempts. Re-merging is not
4260 performed for files already marked as resolved. Use ``--all/-a``
4225 performed for files already marked as resolved. Use ``--all/-a``
4261 to select all unresolved files. ``--tool`` can be used to specify
4226 to select all unresolved files. ``--tool`` can be used to specify
4262 the merge tool used for the given files. It overrides the HGMERGE
4227 the merge tool used for the given files. It overrides the HGMERGE
4263 environment variable and your configuration files. Previous file
4228 environment variable and your configuration files. Previous file
4264 contents are saved with a ``.orig`` suffix.
4229 contents are saved with a ``.orig`` suffix.
4265
4230
4266 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4231 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4267 (e.g. after having manually fixed-up the files). The default is
4232 (e.g. after having manually fixed-up the files). The default is
4268 to mark all unresolved files.
4233 to mark all unresolved files.
4269
4234
4270 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4235 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4271 default is to mark all resolved files.
4236 default is to mark all resolved files.
4272
4237
4273 - :hg:`resolve -l`: list files which had or still have conflicts.
4238 - :hg:`resolve -l`: list files which had or still have conflicts.
4274 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4239 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4275 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4240 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4276 the list. See :hg:`help filesets` for details.
4241 the list. See :hg:`help filesets` for details.
4277
4242
4278 .. note::
4243 .. note::
4279
4244
4280 Mercurial will not let you commit files with unresolved merge
4245 Mercurial will not let you commit files with unresolved merge
4281 conflicts. You must use :hg:`resolve -m ...` before you can
4246 conflicts. You must use :hg:`resolve -m ...` before you can
4282 commit after a conflicting merge.
4247 commit after a conflicting merge.
4283
4248
4284 Returns 0 on success, 1 if any files fail a resolve attempt.
4249 Returns 0 on success, 1 if any files fail a resolve attempt.
4285 """
4250 """
4286
4251
4287 flaglist = 'all mark unmark list no_status'.split()
4252 flaglist = 'all mark unmark list no_status'.split()
4288 all, mark, unmark, show, nostatus = \
4253 all, mark, unmark, show, nostatus = \
4289 [opts.get(o) for o in flaglist]
4254 [opts.get(o) for o in flaglist]
4290
4255
4291 if (show and (mark or unmark)) or (mark and unmark):
4256 if (show and (mark or unmark)) or (mark and unmark):
4292 raise error.Abort(_("too many options specified"))
4257 raise error.Abort(_("too many options specified"))
4293 if pats and all:
4258 if pats and all:
4294 raise error.Abort(_("can't specify --all and patterns"))
4259 raise error.Abort(_("can't specify --all and patterns"))
4295 if not (all or pats or show or mark or unmark):
4260 if not (all or pats or show or mark or unmark):
4296 raise error.Abort(_('no files or directories specified'),
4261 raise error.Abort(_('no files or directories specified'),
4297 hint=('use --all to re-merge all unresolved files'))
4262 hint=('use --all to re-merge all unresolved files'))
4298
4263
4299 if show:
4264 if show:
4300 ui.pager('resolve')
4265 ui.pager('resolve')
4301 fm = ui.formatter('resolve', opts)
4266 fm = ui.formatter('resolve', opts)
4302 ms = mergemod.mergestate.read(repo)
4267 ms = mergemod.mergestate.read(repo)
4303 m = scmutil.match(repo[None], pats, opts)
4268 m = scmutil.match(repo[None], pats, opts)
4304 for f in ms:
4269 for f in ms:
4305 if not m(f):
4270 if not m(f):
4306 continue
4271 continue
4307 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4272 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4308 'd': 'driverresolved'}[ms[f]]
4273 'd': 'driverresolved'}[ms[f]]
4309 fm.startitem()
4274 fm.startitem()
4310 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4275 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4311 fm.write('path', '%s\n', f, label=l)
4276 fm.write('path', '%s\n', f, label=l)
4312 fm.end()
4277 fm.end()
4313 return 0
4278 return 0
4314
4279
4315 with repo.wlock():
4280 with repo.wlock():
4316 ms = mergemod.mergestate.read(repo)
4281 ms = mergemod.mergestate.read(repo)
4317
4282
4318 if not (ms.active() or repo.dirstate.p2() != nullid):
4283 if not (ms.active() or repo.dirstate.p2() != nullid):
4319 raise error.Abort(
4284 raise error.Abort(
4320 _('resolve command not applicable when not merging'))
4285 _('resolve command not applicable when not merging'))
4321
4286
4322 wctx = repo[None]
4287 wctx = repo[None]
4323
4288
4324 if ms.mergedriver and ms.mdstate() == 'u':
4289 if ms.mergedriver and ms.mdstate() == 'u':
4325 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4290 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4326 ms.commit()
4291 ms.commit()
4327 # allow mark and unmark to go through
4292 # allow mark and unmark to go through
4328 if not mark and not unmark and not proceed:
4293 if not mark and not unmark and not proceed:
4329 return 1
4294 return 1
4330
4295
4331 m = scmutil.match(wctx, pats, opts)
4296 m = scmutil.match(wctx, pats, opts)
4332 ret = 0
4297 ret = 0
4333 didwork = False
4298 didwork = False
4334 runconclude = False
4299 runconclude = False
4335
4300
4336 tocomplete = []
4301 tocomplete = []
4337 for f in ms:
4302 for f in ms:
4338 if not m(f):
4303 if not m(f):
4339 continue
4304 continue
4340
4305
4341 didwork = True
4306 didwork = True
4342
4307
4343 # don't let driver-resolved files be marked, and run the conclude
4308 # don't let driver-resolved files be marked, and run the conclude
4344 # step if asked to resolve
4309 # step if asked to resolve
4345 if ms[f] == "d":
4310 if ms[f] == "d":
4346 exact = m.exact(f)
4311 exact = m.exact(f)
4347 if mark:
4312 if mark:
4348 if exact:
4313 if exact:
4349 ui.warn(_('not marking %s as it is driver-resolved\n')
4314 ui.warn(_('not marking %s as it is driver-resolved\n')
4350 % f)
4315 % f)
4351 elif unmark:
4316 elif unmark:
4352 if exact:
4317 if exact:
4353 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4318 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4354 % f)
4319 % f)
4355 else:
4320 else:
4356 runconclude = True
4321 runconclude = True
4357 continue
4322 continue
4358
4323
4359 if mark:
4324 if mark:
4360 ms.mark(f, "r")
4325 ms.mark(f, "r")
4361 elif unmark:
4326 elif unmark:
4362 ms.mark(f, "u")
4327 ms.mark(f, "u")
4363 else:
4328 else:
4364 # backup pre-resolve (merge uses .orig for its own purposes)
4329 # backup pre-resolve (merge uses .orig for its own purposes)
4365 a = repo.wjoin(f)
4330 a = repo.wjoin(f)
4366 try:
4331 try:
4367 util.copyfile(a, a + ".resolve")
4332 util.copyfile(a, a + ".resolve")
4368 except (IOError, OSError) as inst:
4333 except (IOError, OSError) as inst:
4369 if inst.errno != errno.ENOENT:
4334 if inst.errno != errno.ENOENT:
4370 raise
4335 raise
4371
4336
4372 try:
4337 try:
4373 # preresolve file
4338 # preresolve file
4374 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4339 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4375 'resolve')
4340 'resolve')
4376 complete, r = ms.preresolve(f, wctx)
4341 complete, r = ms.preresolve(f, wctx)
4377 if not complete:
4342 if not complete:
4378 tocomplete.append(f)
4343 tocomplete.append(f)
4379 elif r:
4344 elif r:
4380 ret = 1
4345 ret = 1
4381 finally:
4346 finally:
4382 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4347 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4383 ms.commit()
4348 ms.commit()
4384
4349
4385 # replace filemerge's .orig file with our resolve file, but only
4350 # replace filemerge's .orig file with our resolve file, but only
4386 # for merges that are complete
4351 # for merges that are complete
4387 if complete:
4352 if complete:
4388 try:
4353 try:
4389 util.rename(a + ".resolve",
4354 util.rename(a + ".resolve",
4390 scmutil.origpath(ui, repo, a))
4355 scmutil.origpath(ui, repo, a))
4391 except OSError as inst:
4356 except OSError as inst:
4392 if inst.errno != errno.ENOENT:
4357 if inst.errno != errno.ENOENT:
4393 raise
4358 raise
4394
4359
4395 for f in tocomplete:
4360 for f in tocomplete:
4396 try:
4361 try:
4397 # resolve file
4362 # resolve file
4398 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4363 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4399 'resolve')
4364 'resolve')
4400 r = ms.resolve(f, wctx)
4365 r = ms.resolve(f, wctx)
4401 if r:
4366 if r:
4402 ret = 1
4367 ret = 1
4403 finally:
4368 finally:
4404 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4369 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4405 ms.commit()
4370 ms.commit()
4406
4371
4407 # replace filemerge's .orig file with our resolve file
4372 # replace filemerge's .orig file with our resolve file
4408 a = repo.wjoin(f)
4373 a = repo.wjoin(f)
4409 try:
4374 try:
4410 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4375 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4411 except OSError as inst:
4376 except OSError as inst:
4412 if inst.errno != errno.ENOENT:
4377 if inst.errno != errno.ENOENT:
4413 raise
4378 raise
4414
4379
4415 ms.commit()
4380 ms.commit()
4416 ms.recordactions()
4381 ms.recordactions()
4417
4382
4418 if not didwork and pats:
4383 if not didwork and pats:
4419 hint = None
4384 hint = None
4420 if not any([p for p in pats if p.find(':') >= 0]):
4385 if not any([p for p in pats if p.find(':') >= 0]):
4421 pats = ['path:%s' % p for p in pats]
4386 pats = ['path:%s' % p for p in pats]
4422 m = scmutil.match(wctx, pats, opts)
4387 m = scmutil.match(wctx, pats, opts)
4423 for f in ms:
4388 for f in ms:
4424 if not m(f):
4389 if not m(f):
4425 continue
4390 continue
4426 flags = ''.join(['-%s ' % o[0] for o in flaglist
4391 flags = ''.join(['-%s ' % o[0] for o in flaglist
4427 if opts.get(o)])
4392 if opts.get(o)])
4428 hint = _("(try: hg resolve %s%s)\n") % (
4393 hint = _("(try: hg resolve %s%s)\n") % (
4429 flags,
4394 flags,
4430 ' '.join(pats))
4395 ' '.join(pats))
4431 break
4396 break
4432 ui.warn(_("arguments do not match paths that need resolving\n"))
4397 ui.warn(_("arguments do not match paths that need resolving\n"))
4433 if hint:
4398 if hint:
4434 ui.warn(hint)
4399 ui.warn(hint)
4435 elif ms.mergedriver and ms.mdstate() != 's':
4400 elif ms.mergedriver and ms.mdstate() != 's':
4436 # run conclude step when either a driver-resolved file is requested
4401 # run conclude step when either a driver-resolved file is requested
4437 # or there are no driver-resolved files
4402 # or there are no driver-resolved files
4438 # we can't use 'ret' to determine whether any files are unresolved
4403 # we can't use 'ret' to determine whether any files are unresolved
4439 # because we might not have tried to resolve some
4404 # because we might not have tried to resolve some
4440 if ((runconclude or not list(ms.driverresolved()))
4405 if ((runconclude or not list(ms.driverresolved()))
4441 and not list(ms.unresolved())):
4406 and not list(ms.unresolved())):
4442 proceed = mergemod.driverconclude(repo, ms, wctx)
4407 proceed = mergemod.driverconclude(repo, ms, wctx)
4443 ms.commit()
4408 ms.commit()
4444 if not proceed:
4409 if not proceed:
4445 return 1
4410 return 1
4446
4411
4447 # Nudge users into finishing an unfinished operation
4412 # Nudge users into finishing an unfinished operation
4448 unresolvedf = list(ms.unresolved())
4413 unresolvedf = list(ms.unresolved())
4449 driverresolvedf = list(ms.driverresolved())
4414 driverresolvedf = list(ms.driverresolved())
4450 if not unresolvedf and not driverresolvedf:
4415 if not unresolvedf and not driverresolvedf:
4451 ui.status(_('(no more unresolved files)\n'))
4416 ui.status(_('(no more unresolved files)\n'))
4452 cmdutil.checkafterresolved(repo)
4417 cmdutil.checkafterresolved(repo)
4453 elif not unresolvedf:
4418 elif not unresolvedf:
4454 ui.status(_('(no more unresolved files -- '
4419 ui.status(_('(no more unresolved files -- '
4455 'run "hg resolve --all" to conclude)\n'))
4420 'run "hg resolve --all" to conclude)\n'))
4456
4421
4457 return ret
4422 return ret
4458
4423
4459 @command('revert',
4424 @command('revert',
4460 [('a', 'all', None, _('revert all changes when no arguments given')),
4425 [('a', 'all', None, _('revert all changes when no arguments given')),
4461 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4426 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4462 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4427 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4463 ('C', 'no-backup', None, _('do not save backup copies of files')),
4428 ('C', 'no-backup', None, _('do not save backup copies of files')),
4464 ('i', 'interactive', None,
4429 ('i', 'interactive', None,
4465 _('interactively select the changes (EXPERIMENTAL)')),
4430 _('interactively select the changes (EXPERIMENTAL)')),
4466 ] + walkopts + dryrunopts,
4431 ] + walkopts + dryrunopts,
4467 _('[OPTION]... [-r REV] [NAME]...'))
4432 _('[OPTION]... [-r REV] [NAME]...'))
4468 def revert(ui, repo, *pats, **opts):
4433 def revert(ui, repo, *pats, **opts):
4469 """restore files to their checkout state
4434 """restore files to their checkout state
4470
4435
4471 .. note::
4436 .. note::
4472
4437
4473 To check out earlier revisions, you should use :hg:`update REV`.
4438 To check out earlier revisions, you should use :hg:`update REV`.
4474 To cancel an uncommitted merge (and lose your changes),
4439 To cancel an uncommitted merge (and lose your changes),
4475 use :hg:`update --clean .`.
4440 use :hg:`update --clean .`.
4476
4441
4477 With no revision specified, revert the specified files or directories
4442 With no revision specified, revert the specified files or directories
4478 to the contents they had in the parent of the working directory.
4443 to the contents they had in the parent of the working directory.
4479 This restores the contents of files to an unmodified
4444 This restores the contents of files to an unmodified
4480 state and unschedules adds, removes, copies, and renames. If the
4445 state and unschedules adds, removes, copies, and renames. If the
4481 working directory has two parents, you must explicitly specify a
4446 working directory has two parents, you must explicitly specify a
4482 revision.
4447 revision.
4483
4448
4484 Using the -r/--rev or -d/--date options, revert the given files or
4449 Using the -r/--rev or -d/--date options, revert the given files or
4485 directories to their states as of a specific revision. Because
4450 directories to their states as of a specific revision. Because
4486 revert does not change the working directory parents, this will
4451 revert does not change the working directory parents, this will
4487 cause these files to appear modified. This can be helpful to "back
4452 cause these files to appear modified. This can be helpful to "back
4488 out" some or all of an earlier change. See :hg:`backout` for a
4453 out" some or all of an earlier change. See :hg:`backout` for a
4489 related method.
4454 related method.
4490
4455
4491 Modified files are saved with a .orig suffix before reverting.
4456 Modified files are saved with a .orig suffix before reverting.
4492 To disable these backups, use --no-backup. It is possible to store
4457 To disable these backups, use --no-backup. It is possible to store
4493 the backup files in a custom directory relative to the root of the
4458 the backup files in a custom directory relative to the root of the
4494 repository by setting the ``ui.origbackuppath`` configuration
4459 repository by setting the ``ui.origbackuppath`` configuration
4495 option.
4460 option.
4496
4461
4497 See :hg:`help dates` for a list of formats valid for -d/--date.
4462 See :hg:`help dates` for a list of formats valid for -d/--date.
4498
4463
4499 See :hg:`help backout` for a way to reverse the effect of an
4464 See :hg:`help backout` for a way to reverse the effect of an
4500 earlier changeset.
4465 earlier changeset.
4501
4466
4502 Returns 0 on success.
4467 Returns 0 on success.
4503 """
4468 """
4504
4469
4505 if opts.get("date"):
4470 if opts.get("date"):
4506 if opts.get("rev"):
4471 if opts.get("rev"):
4507 raise error.Abort(_("you can't specify a revision and a date"))
4472 raise error.Abort(_("you can't specify a revision and a date"))
4508 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4473 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4509
4474
4510 parent, p2 = repo.dirstate.parents()
4475 parent, p2 = repo.dirstate.parents()
4511 if not opts.get('rev') and p2 != nullid:
4476 if not opts.get('rev') and p2 != nullid:
4512 # revert after merge is a trap for new users (issue2915)
4477 # revert after merge is a trap for new users (issue2915)
4513 raise error.Abort(_('uncommitted merge with no revision specified'),
4478 raise error.Abort(_('uncommitted merge with no revision specified'),
4514 hint=_("use 'hg update' or see 'hg help revert'"))
4479 hint=_("use 'hg update' or see 'hg help revert'"))
4515
4480
4516 ctx = scmutil.revsingle(repo, opts.get('rev'))
4481 ctx = scmutil.revsingle(repo, opts.get('rev'))
4517
4482
4518 if (not (pats or opts.get('include') or opts.get('exclude') or
4483 if (not (pats or opts.get('include') or opts.get('exclude') or
4519 opts.get('all') or opts.get('interactive'))):
4484 opts.get('all') or opts.get('interactive'))):
4520 msg = _("no files or directories specified")
4485 msg = _("no files or directories specified")
4521 if p2 != nullid:
4486 if p2 != nullid:
4522 hint = _("uncommitted merge, use --all to discard all changes,"
4487 hint = _("uncommitted merge, use --all to discard all changes,"
4523 " or 'hg update -C .' to abort the merge")
4488 " or 'hg update -C .' to abort the merge")
4524 raise error.Abort(msg, hint=hint)
4489 raise error.Abort(msg, hint=hint)
4525 dirty = any(repo.status())
4490 dirty = any(repo.status())
4526 node = ctx.node()
4491 node = ctx.node()
4527 if node != parent:
4492 if node != parent:
4528 if dirty:
4493 if dirty:
4529 hint = _("uncommitted changes, use --all to discard all"
4494 hint = _("uncommitted changes, use --all to discard all"
4530 " changes, or 'hg update %s' to update") % ctx.rev()
4495 " changes, or 'hg update %s' to update") % ctx.rev()
4531 else:
4496 else:
4532 hint = _("use --all to revert all files,"
4497 hint = _("use --all to revert all files,"
4533 " or 'hg update %s' to update") % ctx.rev()
4498 " or 'hg update %s' to update") % ctx.rev()
4534 elif dirty:
4499 elif dirty:
4535 hint = _("uncommitted changes, use --all to discard all changes")
4500 hint = _("uncommitted changes, use --all to discard all changes")
4536 else:
4501 else:
4537 hint = _("use --all to revert all files")
4502 hint = _("use --all to revert all files")
4538 raise error.Abort(msg, hint=hint)
4503 raise error.Abort(msg, hint=hint)
4539
4504
4540 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4505 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4541
4506
4542 @command('rollback', dryrunopts +
4507 @command('rollback', dryrunopts +
4543 [('f', 'force', False, _('ignore safety measures'))])
4508 [('f', 'force', False, _('ignore safety measures'))])
4544 def rollback(ui, repo, **opts):
4509 def rollback(ui, repo, **opts):
4545 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4510 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4546
4511
4547 Please use :hg:`commit --amend` instead of rollback to correct
4512 Please use :hg:`commit --amend` instead of rollback to correct
4548 mistakes in the last commit.
4513 mistakes in the last commit.
4549
4514
4550 This command should be used with care. There is only one level of
4515 This command should be used with care. There is only one level of
4551 rollback, and there is no way to undo a rollback. It will also
4516 rollback, and there is no way to undo a rollback. It will also
4552 restore the dirstate at the time of the last transaction, losing
4517 restore the dirstate at the time of the last transaction, losing
4553 any dirstate changes since that time. This command does not alter
4518 any dirstate changes since that time. This command does not alter
4554 the working directory.
4519 the working directory.
4555
4520
4556 Transactions are used to encapsulate the effects of all commands
4521 Transactions are used to encapsulate the effects of all commands
4557 that create new changesets or propagate existing changesets into a
4522 that create new changesets or propagate existing changesets into a
4558 repository.
4523 repository.
4559
4524
4560 .. container:: verbose
4525 .. container:: verbose
4561
4526
4562 For example, the following commands are transactional, and their
4527 For example, the following commands are transactional, and their
4563 effects can be rolled back:
4528 effects can be rolled back:
4564
4529
4565 - commit
4530 - commit
4566 - import
4531 - import
4567 - pull
4532 - pull
4568 - push (with this repository as the destination)
4533 - push (with this repository as the destination)
4569 - unbundle
4534 - unbundle
4570
4535
4571 To avoid permanent data loss, rollback will refuse to rollback a
4536 To avoid permanent data loss, rollback will refuse to rollback a
4572 commit transaction if it isn't checked out. Use --force to
4537 commit transaction if it isn't checked out. Use --force to
4573 override this protection.
4538 override this protection.
4574
4539
4575 The rollback command can be entirely disabled by setting the
4540 The rollback command can be entirely disabled by setting the
4576 ``ui.rollback`` configuration setting to false. If you're here
4541 ``ui.rollback`` configuration setting to false. If you're here
4577 because you want to use rollback and it's disabled, you can
4542 because you want to use rollback and it's disabled, you can
4578 re-enable the command by setting ``ui.rollback`` to true.
4543 re-enable the command by setting ``ui.rollback`` to true.
4579
4544
4580 This command is not intended for use on public repositories. Once
4545 This command is not intended for use on public repositories. Once
4581 changes are visible for pull by other users, rolling a transaction
4546 changes are visible for pull by other users, rolling a transaction
4582 back locally is ineffective (someone else may already have pulled
4547 back locally is ineffective (someone else may already have pulled
4583 the changes). Furthermore, a race is possible with readers of the
4548 the changes). Furthermore, a race is possible with readers of the
4584 repository; for example an in-progress pull from the repository
4549 repository; for example an in-progress pull from the repository
4585 may fail if a rollback is performed.
4550 may fail if a rollback is performed.
4586
4551
4587 Returns 0 on success, 1 if no rollback data is available.
4552 Returns 0 on success, 1 if no rollback data is available.
4588 """
4553 """
4589 if not ui.configbool('ui', 'rollback', True):
4554 if not ui.configbool('ui', 'rollback', True):
4590 raise error.Abort(_('rollback is disabled because it is unsafe'),
4555 raise error.Abort(_('rollback is disabled because it is unsafe'),
4591 hint=('see `hg help -v rollback` for information'))
4556 hint=('see `hg help -v rollback` for information'))
4592 return repo.rollback(dryrun=opts.get('dry_run'),
4557 return repo.rollback(dryrun=opts.get('dry_run'),
4593 force=opts.get('force'))
4558 force=opts.get('force'))
4594
4559
4595 @command('root', [])
4560 @command('root', [])
4596 def root(ui, repo):
4561 def root(ui, repo):
4597 """print the root (top) of the current working directory
4562 """print the root (top) of the current working directory
4598
4563
4599 Print the root directory of the current repository.
4564 Print the root directory of the current repository.
4600
4565
4601 Returns 0 on success.
4566 Returns 0 on success.
4602 """
4567 """
4603 ui.write(repo.root + "\n")
4568 ui.write(repo.root + "\n")
4604
4569
4605 @command('^serve',
4570 @command('^serve',
4606 [('A', 'accesslog', '', _('name of access log file to write to'),
4571 [('A', 'accesslog', '', _('name of access log file to write to'),
4607 _('FILE')),
4572 _('FILE')),
4608 ('d', 'daemon', None, _('run server in background')),
4573 ('d', 'daemon', None, _('run server in background')),
4609 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4574 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4610 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4575 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4611 # use string type, then we can check if something was passed
4576 # use string type, then we can check if something was passed
4612 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4577 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4613 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4578 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4614 _('ADDR')),
4579 _('ADDR')),
4615 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4580 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4616 _('PREFIX')),
4581 _('PREFIX')),
4617 ('n', 'name', '',
4582 ('n', 'name', '',
4618 _('name to show in web pages (default: working directory)'), _('NAME')),
4583 _('name to show in web pages (default: working directory)'), _('NAME')),
4619 ('', 'web-conf', '',
4584 ('', 'web-conf', '',
4620 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4585 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4621 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4586 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4622 _('FILE')),
4587 _('FILE')),
4623 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4588 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4624 ('', 'stdio', None, _('for remote clients')),
4589 ('', 'stdio', None, _('for remote clients')),
4625 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4590 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4626 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4591 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4627 ('', 'style', '', _('template style to use'), _('STYLE')),
4592 ('', 'style', '', _('template style to use'), _('STYLE')),
4628 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4593 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4629 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4594 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4630 _('[OPTION]...'),
4595 _('[OPTION]...'),
4631 optionalrepo=True)
4596 optionalrepo=True)
4632 def serve(ui, repo, **opts):
4597 def serve(ui, repo, **opts):
4633 """start stand-alone webserver
4598 """start stand-alone webserver
4634
4599
4635 Start a local HTTP repository browser and pull server. You can use
4600 Start a local HTTP repository browser and pull server. You can use
4636 this for ad-hoc sharing and browsing of repositories. It is
4601 this for ad-hoc sharing and browsing of repositories. It is
4637 recommended to use a real web server to serve a repository for
4602 recommended to use a real web server to serve a repository for
4638 longer periods of time.
4603 longer periods of time.
4639
4604
4640 Please note that the server does not implement access control.
4605 Please note that the server does not implement access control.
4641 This means that, by default, anybody can read from the server and
4606 This means that, by default, anybody can read from the server and
4642 nobody can write to it by default. Set the ``web.allow_push``
4607 nobody can write to it by default. Set the ``web.allow_push``
4643 option to ``*`` to allow everybody to push to the server. You
4608 option to ``*`` to allow everybody to push to the server. You
4644 should use a real web server if you need to authenticate users.
4609 should use a real web server if you need to authenticate users.
4645
4610
4646 By default, the server logs accesses to stdout and errors to
4611 By default, the server logs accesses to stdout and errors to
4647 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4612 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4648 files.
4613 files.
4649
4614
4650 To have the server choose a free port number to listen on, specify
4615 To have the server choose a free port number to listen on, specify
4651 a port number of 0; in this case, the server will print the port
4616 a port number of 0; in this case, the server will print the port
4652 number it uses.
4617 number it uses.
4653
4618
4654 Returns 0 on success.
4619 Returns 0 on success.
4655 """
4620 """
4656
4621
4657 if opts["stdio"] and opts["cmdserver"]:
4622 if opts["stdio"] and opts["cmdserver"]:
4658 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4623 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4659
4624
4660 if opts["stdio"]:
4625 if opts["stdio"]:
4661 if repo is None:
4626 if repo is None:
4662 raise error.RepoError(_("there is no Mercurial repository here"
4627 raise error.RepoError(_("there is no Mercurial repository here"
4663 " (.hg not found)"))
4628 " (.hg not found)"))
4664 s = sshserver.sshserver(ui, repo)
4629 s = sshserver.sshserver(ui, repo)
4665 s.serve_forever()
4630 s.serve_forever()
4666
4631
4667 service = server.createservice(ui, repo, opts)
4632 service = server.createservice(ui, repo, opts)
4668 return server.runservice(opts, initfn=service.init, runfn=service.run)
4633 return server.runservice(opts, initfn=service.init, runfn=service.run)
4669
4634
4670 @command('^status|st',
4635 @command('^status|st',
4671 [('A', 'all', None, _('show status of all files')),
4636 [('A', 'all', None, _('show status of all files')),
4672 ('m', 'modified', None, _('show only modified files')),
4637 ('m', 'modified', None, _('show only modified files')),
4673 ('a', 'added', None, _('show only added files')),
4638 ('a', 'added', None, _('show only added files')),
4674 ('r', 'removed', None, _('show only removed files')),
4639 ('r', 'removed', None, _('show only removed files')),
4675 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4640 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4676 ('c', 'clean', None, _('show only files without changes')),
4641 ('c', 'clean', None, _('show only files without changes')),
4677 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4642 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4678 ('i', 'ignored', None, _('show only ignored files')),
4643 ('i', 'ignored', None, _('show only ignored files')),
4679 ('n', 'no-status', None, _('hide status prefix')),
4644 ('n', 'no-status', None, _('hide status prefix')),
4680 ('C', 'copies', None, _('show source of copied files')),
4645 ('C', 'copies', None, _('show source of copied files')),
4681 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4646 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4682 ('', 'rev', [], _('show difference from revision'), _('REV')),
4647 ('', 'rev', [], _('show difference from revision'), _('REV')),
4683 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4648 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4684 ] + walkopts + subrepoopts + formatteropts,
4649 ] + walkopts + subrepoopts + formatteropts,
4685 _('[OPTION]... [FILE]...'),
4650 _('[OPTION]... [FILE]...'),
4686 inferrepo=True)
4651 inferrepo=True)
4687 def status(ui, repo, *pats, **opts):
4652 def status(ui, repo, *pats, **opts):
4688 """show changed files in the working directory
4653 """show changed files in the working directory
4689
4654
4690 Show status of files in the repository. If names are given, only
4655 Show status of files in the repository. If names are given, only
4691 files that match are shown. Files that are clean or ignored or
4656 files that match are shown. Files that are clean or ignored or
4692 the source of a copy/move operation, are not listed unless
4657 the source of a copy/move operation, are not listed unless
4693 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4658 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4694 Unless options described with "show only ..." are given, the
4659 Unless options described with "show only ..." are given, the
4695 options -mardu are used.
4660 options -mardu are used.
4696
4661
4697 Option -q/--quiet hides untracked (unknown and ignored) files
4662 Option -q/--quiet hides untracked (unknown and ignored) files
4698 unless explicitly requested with -u/--unknown or -i/--ignored.
4663 unless explicitly requested with -u/--unknown or -i/--ignored.
4699
4664
4700 .. note::
4665 .. note::
4701
4666
4702 :hg:`status` may appear to disagree with diff if permissions have
4667 :hg:`status` may appear to disagree with diff if permissions have
4703 changed or a merge has occurred. The standard diff format does
4668 changed or a merge has occurred. The standard diff format does
4704 not report permission changes and diff only reports changes
4669 not report permission changes and diff only reports changes
4705 relative to one merge parent.
4670 relative to one merge parent.
4706
4671
4707 If one revision is given, it is used as the base revision.
4672 If one revision is given, it is used as the base revision.
4708 If two revisions are given, the differences between them are
4673 If two revisions are given, the differences between them are
4709 shown. The --change option can also be used as a shortcut to list
4674 shown. The --change option can also be used as a shortcut to list
4710 the changed files of a revision from its first parent.
4675 the changed files of a revision from its first parent.
4711
4676
4712 The codes used to show the status of files are::
4677 The codes used to show the status of files are::
4713
4678
4714 M = modified
4679 M = modified
4715 A = added
4680 A = added
4716 R = removed
4681 R = removed
4717 C = clean
4682 C = clean
4718 ! = missing (deleted by non-hg command, but still tracked)
4683 ! = missing (deleted by non-hg command, but still tracked)
4719 ? = not tracked
4684 ? = not tracked
4720 I = ignored
4685 I = ignored
4721 = origin of the previous file (with --copies)
4686 = origin of the previous file (with --copies)
4722
4687
4723 .. container:: verbose
4688 .. container:: verbose
4724
4689
4725 Examples:
4690 Examples:
4726
4691
4727 - show changes in the working directory relative to a
4692 - show changes in the working directory relative to a
4728 changeset::
4693 changeset::
4729
4694
4730 hg status --rev 9353
4695 hg status --rev 9353
4731
4696
4732 - show changes in the working directory relative to the
4697 - show changes in the working directory relative to the
4733 current directory (see :hg:`help patterns` for more information)::
4698 current directory (see :hg:`help patterns` for more information)::
4734
4699
4735 hg status re:
4700 hg status re:
4736
4701
4737 - show all changes including copies in an existing changeset::
4702 - show all changes including copies in an existing changeset::
4738
4703
4739 hg status --copies --change 9353
4704 hg status --copies --change 9353
4740
4705
4741 - get a NUL separated list of added files, suitable for xargs::
4706 - get a NUL separated list of added files, suitable for xargs::
4742
4707
4743 hg status -an0
4708 hg status -an0
4744
4709
4745 Returns 0 on success.
4710 Returns 0 on success.
4746 """
4711 """
4747
4712
4748 revs = opts.get('rev')
4713 revs = opts.get('rev')
4749 change = opts.get('change')
4714 change = opts.get('change')
4750
4715
4751 if revs and change:
4716 if revs and change:
4752 msg = _('cannot specify --rev and --change at the same time')
4717 msg = _('cannot specify --rev and --change at the same time')
4753 raise error.Abort(msg)
4718 raise error.Abort(msg)
4754 elif change:
4719 elif change:
4755 node2 = scmutil.revsingle(repo, change, None).node()
4720 node2 = scmutil.revsingle(repo, change, None).node()
4756 node1 = repo[node2].p1().node()
4721 node1 = repo[node2].p1().node()
4757 else:
4722 else:
4758 node1, node2 = scmutil.revpair(repo, revs)
4723 node1, node2 = scmutil.revpair(repo, revs)
4759
4724
4760 if pats:
4725 if pats:
4761 cwd = repo.getcwd()
4726 cwd = repo.getcwd()
4762 else:
4727 else:
4763 cwd = ''
4728 cwd = ''
4764
4729
4765 if opts.get('print0'):
4730 if opts.get('print0'):
4766 end = '\0'
4731 end = '\0'
4767 else:
4732 else:
4768 end = '\n'
4733 end = '\n'
4769 copy = {}
4734 copy = {}
4770 states = 'modified added removed deleted unknown ignored clean'.split()
4735 states = 'modified added removed deleted unknown ignored clean'.split()
4771 show = [k for k in states if opts.get(k)]
4736 show = [k for k in states if opts.get(k)]
4772 if opts.get('all'):
4737 if opts.get('all'):
4773 show += ui.quiet and (states[:4] + ['clean']) or states
4738 show += ui.quiet and (states[:4] + ['clean']) or states
4774 if not show:
4739 if not show:
4775 if ui.quiet:
4740 if ui.quiet:
4776 show = states[:4]
4741 show = states[:4]
4777 else:
4742 else:
4778 show = states[:5]
4743 show = states[:5]
4779
4744
4780 m = scmutil.match(repo[node2], pats, opts)
4745 m = scmutil.match(repo[node2], pats, opts)
4781 stat = repo.status(node1, node2, m,
4746 stat = repo.status(node1, node2, m,
4782 'ignored' in show, 'clean' in show, 'unknown' in show,
4747 'ignored' in show, 'clean' in show, 'unknown' in show,
4783 opts.get('subrepos'))
4748 opts.get('subrepos'))
4784 changestates = zip(states, 'MAR!?IC', stat)
4749 changestates = zip(states, 'MAR!?IC', stat)
4785
4750
4786 if (opts.get('all') or opts.get('copies')
4751 if (opts.get('all') or opts.get('copies')
4787 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4752 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4788 copy = copies.pathcopies(repo[node1], repo[node2], m)
4753 copy = copies.pathcopies(repo[node1], repo[node2], m)
4789
4754
4790 ui.pager('status')
4755 ui.pager('status')
4791 fm = ui.formatter('status', opts)
4756 fm = ui.formatter('status', opts)
4792 fmt = '%s' + end
4757 fmt = '%s' + end
4793 showchar = not opts.get('no_status')
4758 showchar = not opts.get('no_status')
4794
4759
4795 for state, char, files in changestates:
4760 for state, char, files in changestates:
4796 if state in show:
4761 if state in show:
4797 label = 'status.' + state
4762 label = 'status.' + state
4798 for f in files:
4763 for f in files:
4799 fm.startitem()
4764 fm.startitem()
4800 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4765 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4801 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4766 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4802 if f in copy:
4767 if f in copy:
4803 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4768 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4804 label='status.copied')
4769 label='status.copied')
4805 fm.end()
4770 fm.end()
4806
4771
4807 @command('^summary|sum',
4772 @command('^summary|sum',
4808 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4773 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4809 def summary(ui, repo, **opts):
4774 def summary(ui, repo, **opts):
4810 """summarize working directory state
4775 """summarize working directory state
4811
4776
4812 This generates a brief summary of the working directory state,
4777 This generates a brief summary of the working directory state,
4813 including parents, branch, commit status, phase and available updates.
4778 including parents, branch, commit status, phase and available updates.
4814
4779
4815 With the --remote option, this will check the default paths for
4780 With the --remote option, this will check the default paths for
4816 incoming and outgoing changes. This can be time-consuming.
4781 incoming and outgoing changes. This can be time-consuming.
4817
4782
4818 Returns 0 on success.
4783 Returns 0 on success.
4819 """
4784 """
4820
4785
4821 ui.pager('summary')
4786 ui.pager('summary')
4822 ctx = repo[None]
4787 ctx = repo[None]
4823 parents = ctx.parents()
4788 parents = ctx.parents()
4824 pnode = parents[0].node()
4789 pnode = parents[0].node()
4825 marks = []
4790 marks = []
4826
4791
4827 ms = None
4792 ms = None
4828 try:
4793 try:
4829 ms = mergemod.mergestate.read(repo)
4794 ms = mergemod.mergestate.read(repo)
4830 except error.UnsupportedMergeRecords as e:
4795 except error.UnsupportedMergeRecords as e:
4831 s = ' '.join(e.recordtypes)
4796 s = ' '.join(e.recordtypes)
4832 ui.warn(
4797 ui.warn(
4833 _('warning: merge state has unsupported record types: %s\n') % s)
4798 _('warning: merge state has unsupported record types: %s\n') % s)
4834 unresolved = 0
4799 unresolved = 0
4835 else:
4800 else:
4836 unresolved = [f for f in ms if ms[f] == 'u']
4801 unresolved = [f for f in ms if ms[f] == 'u']
4837
4802
4838 for p in parents:
4803 for p in parents:
4839 # label with log.changeset (instead of log.parent) since this
4804 # label with log.changeset (instead of log.parent) since this
4840 # shows a working directory parent *changeset*:
4805 # shows a working directory parent *changeset*:
4841 # i18n: column positioning for "hg summary"
4806 # i18n: column positioning for "hg summary"
4842 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4807 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4843 label=cmdutil._changesetlabels(p))
4808 label=cmdutil._changesetlabels(p))
4844 ui.write(' '.join(p.tags()), label='log.tag')
4809 ui.write(' '.join(p.tags()), label='log.tag')
4845 if p.bookmarks():
4810 if p.bookmarks():
4846 marks.extend(p.bookmarks())
4811 marks.extend(p.bookmarks())
4847 if p.rev() == -1:
4812 if p.rev() == -1:
4848 if not len(repo):
4813 if not len(repo):
4849 ui.write(_(' (empty repository)'))
4814 ui.write(_(' (empty repository)'))
4850 else:
4815 else:
4851 ui.write(_(' (no revision checked out)'))
4816 ui.write(_(' (no revision checked out)'))
4852 if p.troubled():
4817 if p.troubled():
4853 ui.write(' ('
4818 ui.write(' ('
4854 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4819 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4855 for trouble in p.troubles())
4820 for trouble in p.troubles())
4856 + ')')
4821 + ')')
4857 ui.write('\n')
4822 ui.write('\n')
4858 if p.description():
4823 if p.description():
4859 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4824 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4860 label='log.summary')
4825 label='log.summary')
4861
4826
4862 branch = ctx.branch()
4827 branch = ctx.branch()
4863 bheads = repo.branchheads(branch)
4828 bheads = repo.branchheads(branch)
4864 # i18n: column positioning for "hg summary"
4829 # i18n: column positioning for "hg summary"
4865 m = _('branch: %s\n') % branch
4830 m = _('branch: %s\n') % branch
4866 if branch != 'default':
4831 if branch != 'default':
4867 ui.write(m, label='log.branch')
4832 ui.write(m, label='log.branch')
4868 else:
4833 else:
4869 ui.status(m, label='log.branch')
4834 ui.status(m, label='log.branch')
4870
4835
4871 if marks:
4836 if marks:
4872 active = repo._activebookmark
4837 active = repo._activebookmark
4873 # i18n: column positioning for "hg summary"
4838 # i18n: column positioning for "hg summary"
4874 ui.write(_('bookmarks:'), label='log.bookmark')
4839 ui.write(_('bookmarks:'), label='log.bookmark')
4875 if active is not None:
4840 if active is not None:
4876 if active in marks:
4841 if active in marks:
4877 ui.write(' *' + active, label=activebookmarklabel)
4842 ui.write(' *' + active, label=activebookmarklabel)
4878 marks.remove(active)
4843 marks.remove(active)
4879 else:
4844 else:
4880 ui.write(' [%s]' % active, label=activebookmarklabel)
4845 ui.write(' [%s]' % active, label=activebookmarklabel)
4881 for m in marks:
4846 for m in marks:
4882 ui.write(' ' + m, label='log.bookmark')
4847 ui.write(' ' + m, label='log.bookmark')
4883 ui.write('\n', label='log.bookmark')
4848 ui.write('\n', label='log.bookmark')
4884
4849
4885 status = repo.status(unknown=True)
4850 status = repo.status(unknown=True)
4886
4851
4887 c = repo.dirstate.copies()
4852 c = repo.dirstate.copies()
4888 copied, renamed = [], []
4853 copied, renamed = [], []
4889 for d, s in c.iteritems():
4854 for d, s in c.iteritems():
4890 if s in status.removed:
4855 if s in status.removed:
4891 status.removed.remove(s)
4856 status.removed.remove(s)
4892 renamed.append(d)
4857 renamed.append(d)
4893 else:
4858 else:
4894 copied.append(d)
4859 copied.append(d)
4895 if d in status.added:
4860 if d in status.added:
4896 status.added.remove(d)
4861 status.added.remove(d)
4897
4862
4898 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4863 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4899
4864
4900 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4865 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4901 (ui.label(_('%d added'), 'status.added'), status.added),
4866 (ui.label(_('%d added'), 'status.added'), status.added),
4902 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4867 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4903 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4868 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4904 (ui.label(_('%d copied'), 'status.copied'), copied),
4869 (ui.label(_('%d copied'), 'status.copied'), copied),
4905 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4870 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4906 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4871 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4907 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4872 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4908 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4873 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4909 t = []
4874 t = []
4910 for l, s in labels:
4875 for l, s in labels:
4911 if s:
4876 if s:
4912 t.append(l % len(s))
4877 t.append(l % len(s))
4913
4878
4914 t = ', '.join(t)
4879 t = ', '.join(t)
4915 cleanworkdir = False
4880 cleanworkdir = False
4916
4881
4917 if repo.vfs.exists('graftstate'):
4882 if repo.vfs.exists('graftstate'):
4918 t += _(' (graft in progress)')
4883 t += _(' (graft in progress)')
4919 if repo.vfs.exists('updatestate'):
4884 if repo.vfs.exists('updatestate'):
4920 t += _(' (interrupted update)')
4885 t += _(' (interrupted update)')
4921 elif len(parents) > 1:
4886 elif len(parents) > 1:
4922 t += _(' (merge)')
4887 t += _(' (merge)')
4923 elif branch != parents[0].branch():
4888 elif branch != parents[0].branch():
4924 t += _(' (new branch)')
4889 t += _(' (new branch)')
4925 elif (parents[0].closesbranch() and
4890 elif (parents[0].closesbranch() and
4926 pnode in repo.branchheads(branch, closed=True)):
4891 pnode in repo.branchheads(branch, closed=True)):
4927 t += _(' (head closed)')
4892 t += _(' (head closed)')
4928 elif not (status.modified or status.added or status.removed or renamed or
4893 elif not (status.modified or status.added or status.removed or renamed or
4929 copied or subs):
4894 copied or subs):
4930 t += _(' (clean)')
4895 t += _(' (clean)')
4931 cleanworkdir = True
4896 cleanworkdir = True
4932 elif pnode not in bheads:
4897 elif pnode not in bheads:
4933 t += _(' (new branch head)')
4898 t += _(' (new branch head)')
4934
4899
4935 if parents:
4900 if parents:
4936 pendingphase = max(p.phase() for p in parents)
4901 pendingphase = max(p.phase() for p in parents)
4937 else:
4902 else:
4938 pendingphase = phases.public
4903 pendingphase = phases.public
4939
4904
4940 if pendingphase > phases.newcommitphase(ui):
4905 if pendingphase > phases.newcommitphase(ui):
4941 t += ' (%s)' % phases.phasenames[pendingphase]
4906 t += ' (%s)' % phases.phasenames[pendingphase]
4942
4907
4943 if cleanworkdir:
4908 if cleanworkdir:
4944 # i18n: column positioning for "hg summary"
4909 # i18n: column positioning for "hg summary"
4945 ui.status(_('commit: %s\n') % t.strip())
4910 ui.status(_('commit: %s\n') % t.strip())
4946 else:
4911 else:
4947 # i18n: column positioning for "hg summary"
4912 # i18n: column positioning for "hg summary"
4948 ui.write(_('commit: %s\n') % t.strip())
4913 ui.write(_('commit: %s\n') % t.strip())
4949
4914
4950 # all ancestors of branch heads - all ancestors of parent = new csets
4915 # all ancestors of branch heads - all ancestors of parent = new csets
4951 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4916 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4952 bheads))
4917 bheads))
4953
4918
4954 if new == 0:
4919 if new == 0:
4955 # i18n: column positioning for "hg summary"
4920 # i18n: column positioning for "hg summary"
4956 ui.status(_('update: (current)\n'))
4921 ui.status(_('update: (current)\n'))
4957 elif pnode not in bheads:
4922 elif pnode not in bheads:
4958 # i18n: column positioning for "hg summary"
4923 # i18n: column positioning for "hg summary"
4959 ui.write(_('update: %d new changesets (update)\n') % new)
4924 ui.write(_('update: %d new changesets (update)\n') % new)
4960 else:
4925 else:
4961 # i18n: column positioning for "hg summary"
4926 # i18n: column positioning for "hg summary"
4962 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4927 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4963 (new, len(bheads)))
4928 (new, len(bheads)))
4964
4929
4965 t = []
4930 t = []
4966 draft = len(repo.revs('draft()'))
4931 draft = len(repo.revs('draft()'))
4967 if draft:
4932 if draft:
4968 t.append(_('%d draft') % draft)
4933 t.append(_('%d draft') % draft)
4969 secret = len(repo.revs('secret()'))
4934 secret = len(repo.revs('secret()'))
4970 if secret:
4935 if secret:
4971 t.append(_('%d secret') % secret)
4936 t.append(_('%d secret') % secret)
4972
4937
4973 if draft or secret:
4938 if draft or secret:
4974 ui.status(_('phases: %s\n') % ', '.join(t))
4939 ui.status(_('phases: %s\n') % ', '.join(t))
4975
4940
4976 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4941 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4977 for trouble in ("unstable", "divergent", "bumped"):
4942 for trouble in ("unstable", "divergent", "bumped"):
4978 numtrouble = len(repo.revs(trouble + "()"))
4943 numtrouble = len(repo.revs(trouble + "()"))
4979 # We write all the possibilities to ease translation
4944 # We write all the possibilities to ease translation
4980 troublemsg = {
4945 troublemsg = {
4981 "unstable": _("unstable: %d changesets"),
4946 "unstable": _("unstable: %d changesets"),
4982 "divergent": _("divergent: %d changesets"),
4947 "divergent": _("divergent: %d changesets"),
4983 "bumped": _("bumped: %d changesets"),
4948 "bumped": _("bumped: %d changesets"),
4984 }
4949 }
4985 if numtrouble > 0:
4950 if numtrouble > 0:
4986 ui.status(troublemsg[trouble] % numtrouble + "\n")
4951 ui.status(troublemsg[trouble] % numtrouble + "\n")
4987
4952
4988 cmdutil.summaryhooks(ui, repo)
4953 cmdutil.summaryhooks(ui, repo)
4989
4954
4990 if opts.get('remote'):
4955 if opts.get('remote'):
4991 needsincoming, needsoutgoing = True, True
4956 needsincoming, needsoutgoing = True, True
4992 else:
4957 else:
4993 needsincoming, needsoutgoing = False, False
4958 needsincoming, needsoutgoing = False, False
4994 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4959 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4995 if i:
4960 if i:
4996 needsincoming = True
4961 needsincoming = True
4997 if o:
4962 if o:
4998 needsoutgoing = True
4963 needsoutgoing = True
4999 if not needsincoming and not needsoutgoing:
4964 if not needsincoming and not needsoutgoing:
5000 return
4965 return
5001
4966
5002 def getincoming():
4967 def getincoming():
5003 source, branches = hg.parseurl(ui.expandpath('default'))
4968 source, branches = hg.parseurl(ui.expandpath('default'))
5004 sbranch = branches[0]
4969 sbranch = branches[0]
5005 try:
4970 try:
5006 other = hg.peer(repo, {}, source)
4971 other = hg.peer(repo, {}, source)
5007 except error.RepoError:
4972 except error.RepoError:
5008 if opts.get('remote'):
4973 if opts.get('remote'):
5009 raise
4974 raise
5010 return source, sbranch, None, None, None
4975 return source, sbranch, None, None, None
5011 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4976 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5012 if revs:
4977 if revs:
5013 revs = [other.lookup(rev) for rev in revs]
4978 revs = [other.lookup(rev) for rev in revs]
5014 ui.debug('comparing with %s\n' % util.hidepassword(source))
4979 ui.debug('comparing with %s\n' % util.hidepassword(source))
5015 repo.ui.pushbuffer()
4980 repo.ui.pushbuffer()
5016 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4981 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5017 repo.ui.popbuffer()
4982 repo.ui.popbuffer()
5018 return source, sbranch, other, commoninc, commoninc[1]
4983 return source, sbranch, other, commoninc, commoninc[1]
5019
4984
5020 if needsincoming:
4985 if needsincoming:
5021 source, sbranch, sother, commoninc, incoming = getincoming()
4986 source, sbranch, sother, commoninc, incoming = getincoming()
5022 else:
4987 else:
5023 source = sbranch = sother = commoninc = incoming = None
4988 source = sbranch = sother = commoninc = incoming = None
5024
4989
5025 def getoutgoing():
4990 def getoutgoing():
5026 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4991 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5027 dbranch = branches[0]
4992 dbranch = branches[0]
5028 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4993 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5029 if source != dest:
4994 if source != dest:
5030 try:
4995 try:
5031 dother = hg.peer(repo, {}, dest)
4996 dother = hg.peer(repo, {}, dest)
5032 except error.RepoError:
4997 except error.RepoError:
5033 if opts.get('remote'):
4998 if opts.get('remote'):
5034 raise
4999 raise
5035 return dest, dbranch, None, None
5000 return dest, dbranch, None, None
5036 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5001 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5037 elif sother is None:
5002 elif sother is None:
5038 # there is no explicit destination peer, but source one is invalid
5003 # there is no explicit destination peer, but source one is invalid
5039 return dest, dbranch, None, None
5004 return dest, dbranch, None, None
5040 else:
5005 else:
5041 dother = sother
5006 dother = sother
5042 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5007 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5043 common = None
5008 common = None
5044 else:
5009 else:
5045 common = commoninc
5010 common = commoninc
5046 if revs:
5011 if revs:
5047 revs = [repo.lookup(rev) for rev in revs]
5012 revs = [repo.lookup(rev) for rev in revs]
5048 repo.ui.pushbuffer()
5013 repo.ui.pushbuffer()
5049 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5014 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5050 commoninc=common)
5015 commoninc=common)
5051 repo.ui.popbuffer()
5016 repo.ui.popbuffer()
5052 return dest, dbranch, dother, outgoing
5017 return dest, dbranch, dother, outgoing
5053
5018
5054 if needsoutgoing:
5019 if needsoutgoing:
5055 dest, dbranch, dother, outgoing = getoutgoing()
5020 dest, dbranch, dother, outgoing = getoutgoing()
5056 else:
5021 else:
5057 dest = dbranch = dother = outgoing = None
5022 dest = dbranch = dother = outgoing = None
5058
5023
5059 if opts.get('remote'):
5024 if opts.get('remote'):
5060 t = []
5025 t = []
5061 if incoming:
5026 if incoming:
5062 t.append(_('1 or more incoming'))
5027 t.append(_('1 or more incoming'))
5063 o = outgoing.missing
5028 o = outgoing.missing
5064 if o:
5029 if o:
5065 t.append(_('%d outgoing') % len(o))
5030 t.append(_('%d outgoing') % len(o))
5066 other = dother or sother
5031 other = dother or sother
5067 if 'bookmarks' in other.listkeys('namespaces'):
5032 if 'bookmarks' in other.listkeys('namespaces'):
5068 counts = bookmarks.summary(repo, other)
5033 counts = bookmarks.summary(repo, other)
5069 if counts[0] > 0:
5034 if counts[0] > 0:
5070 t.append(_('%d incoming bookmarks') % counts[0])
5035 t.append(_('%d incoming bookmarks') % counts[0])
5071 if counts[1] > 0:
5036 if counts[1] > 0:
5072 t.append(_('%d outgoing bookmarks') % counts[1])
5037 t.append(_('%d outgoing bookmarks') % counts[1])
5073
5038
5074 if t:
5039 if t:
5075 # i18n: column positioning for "hg summary"
5040 # i18n: column positioning for "hg summary"
5076 ui.write(_('remote: %s\n') % (', '.join(t)))
5041 ui.write(_('remote: %s\n') % (', '.join(t)))
5077 else:
5042 else:
5078 # i18n: column positioning for "hg summary"
5043 # i18n: column positioning for "hg summary"
5079 ui.status(_('remote: (synced)\n'))
5044 ui.status(_('remote: (synced)\n'))
5080
5045
5081 cmdutil.summaryremotehooks(ui, repo, opts,
5046 cmdutil.summaryremotehooks(ui, repo, opts,
5082 ((source, sbranch, sother, commoninc),
5047 ((source, sbranch, sother, commoninc),
5083 (dest, dbranch, dother, outgoing)))
5048 (dest, dbranch, dother, outgoing)))
5084
5049
5085 @command('tag',
5050 @command('tag',
5086 [('f', 'force', None, _('force tag')),
5051 [('f', 'force', None, _('force tag')),
5087 ('l', 'local', None, _('make the tag local')),
5052 ('l', 'local', None, _('make the tag local')),
5088 ('r', 'rev', '', _('revision to tag'), _('REV')),
5053 ('r', 'rev', '', _('revision to tag'), _('REV')),
5089 ('', 'remove', None, _('remove a tag')),
5054 ('', 'remove', None, _('remove a tag')),
5090 # -l/--local is already there, commitopts cannot be used
5055 # -l/--local is already there, commitopts cannot be used
5091 ('e', 'edit', None, _('invoke editor on commit messages')),
5056 ('e', 'edit', None, _('invoke editor on commit messages')),
5092 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5057 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5093 ] + commitopts2,
5058 ] + commitopts2,
5094 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5059 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5095 def tag(ui, repo, name1, *names, **opts):
5060 def tag(ui, repo, name1, *names, **opts):
5096 """add one or more tags for the current or given revision
5061 """add one or more tags for the current or given revision
5097
5062
5098 Name a particular revision using <name>.
5063 Name a particular revision using <name>.
5099
5064
5100 Tags are used to name particular revisions of the repository and are
5065 Tags are used to name particular revisions of the repository and are
5101 very useful to compare different revisions, to go back to significant
5066 very useful to compare different revisions, to go back to significant
5102 earlier versions or to mark branch points as releases, etc. Changing
5067 earlier versions or to mark branch points as releases, etc. Changing
5103 an existing tag is normally disallowed; use -f/--force to override.
5068 an existing tag is normally disallowed; use -f/--force to override.
5104
5069
5105 If no revision is given, the parent of the working directory is
5070 If no revision is given, the parent of the working directory is
5106 used.
5071 used.
5107
5072
5108 To facilitate version control, distribution, and merging of tags,
5073 To facilitate version control, distribution, and merging of tags,
5109 they are stored as a file named ".hgtags" which is managed similarly
5074 they are stored as a file named ".hgtags" which is managed similarly
5110 to other project files and can be hand-edited if necessary. This
5075 to other project files and can be hand-edited if necessary. This
5111 also means that tagging creates a new commit. The file
5076 also means that tagging creates a new commit. The file
5112 ".hg/localtags" is used for local tags (not shared among
5077 ".hg/localtags" is used for local tags (not shared among
5113 repositories).
5078 repositories).
5114
5079
5115 Tag commits are usually made at the head of a branch. If the parent
5080 Tag commits are usually made at the head of a branch. If the parent
5116 of the working directory is not a branch head, :hg:`tag` aborts; use
5081 of the working directory is not a branch head, :hg:`tag` aborts; use
5117 -f/--force to force the tag commit to be based on a non-head
5082 -f/--force to force the tag commit to be based on a non-head
5118 changeset.
5083 changeset.
5119
5084
5120 See :hg:`help dates` for a list of formats valid for -d/--date.
5085 See :hg:`help dates` for a list of formats valid for -d/--date.
5121
5086
5122 Since tag names have priority over branch names during revision
5087 Since tag names have priority over branch names during revision
5123 lookup, using an existing branch name as a tag name is discouraged.
5088 lookup, using an existing branch name as a tag name is discouraged.
5124
5089
5125 Returns 0 on success.
5090 Returns 0 on success.
5126 """
5091 """
5127 wlock = lock = None
5092 wlock = lock = None
5128 try:
5093 try:
5129 wlock = repo.wlock()
5094 wlock = repo.wlock()
5130 lock = repo.lock()
5095 lock = repo.lock()
5131 rev_ = "."
5096 rev_ = "."
5132 names = [t.strip() for t in (name1,) + names]
5097 names = [t.strip() for t in (name1,) + names]
5133 if len(names) != len(set(names)):
5098 if len(names) != len(set(names)):
5134 raise error.Abort(_('tag names must be unique'))
5099 raise error.Abort(_('tag names must be unique'))
5135 for n in names:
5100 for n in names:
5136 scmutil.checknewlabel(repo, n, 'tag')
5101 scmutil.checknewlabel(repo, n, 'tag')
5137 if not n:
5102 if not n:
5138 raise error.Abort(_('tag names cannot consist entirely of '
5103 raise error.Abort(_('tag names cannot consist entirely of '
5139 'whitespace'))
5104 'whitespace'))
5140 if opts.get('rev') and opts.get('remove'):
5105 if opts.get('rev') and opts.get('remove'):
5141 raise error.Abort(_("--rev and --remove are incompatible"))
5106 raise error.Abort(_("--rev and --remove are incompatible"))
5142 if opts.get('rev'):
5107 if opts.get('rev'):
5143 rev_ = opts['rev']
5108 rev_ = opts['rev']
5144 message = opts.get('message')
5109 message = opts.get('message')
5145 if opts.get('remove'):
5110 if opts.get('remove'):
5146 if opts.get('local'):
5111 if opts.get('local'):
5147 expectedtype = 'local'
5112 expectedtype = 'local'
5148 else:
5113 else:
5149 expectedtype = 'global'
5114 expectedtype = 'global'
5150
5115
5151 for n in names:
5116 for n in names:
5152 if not repo.tagtype(n):
5117 if not repo.tagtype(n):
5153 raise error.Abort(_("tag '%s' does not exist") % n)
5118 raise error.Abort(_("tag '%s' does not exist") % n)
5154 if repo.tagtype(n) != expectedtype:
5119 if repo.tagtype(n) != expectedtype:
5155 if expectedtype == 'global':
5120 if expectedtype == 'global':
5156 raise error.Abort(_("tag '%s' is not a global tag") % n)
5121 raise error.Abort(_("tag '%s' is not a global tag") % n)
5157 else:
5122 else:
5158 raise error.Abort(_("tag '%s' is not a local tag") % n)
5123 raise error.Abort(_("tag '%s' is not a local tag") % n)
5159 rev_ = 'null'
5124 rev_ = 'null'
5160 if not message:
5125 if not message:
5161 # we don't translate commit messages
5126 # we don't translate commit messages
5162 message = 'Removed tag %s' % ', '.join(names)
5127 message = 'Removed tag %s' % ', '.join(names)
5163 elif not opts.get('force'):
5128 elif not opts.get('force'):
5164 for n in names:
5129 for n in names:
5165 if n in repo.tags():
5130 if n in repo.tags():
5166 raise error.Abort(_("tag '%s' already exists "
5131 raise error.Abort(_("tag '%s' already exists "
5167 "(use -f to force)") % n)
5132 "(use -f to force)") % n)
5168 if not opts.get('local'):
5133 if not opts.get('local'):
5169 p1, p2 = repo.dirstate.parents()
5134 p1, p2 = repo.dirstate.parents()
5170 if p2 != nullid:
5135 if p2 != nullid:
5171 raise error.Abort(_('uncommitted merge'))
5136 raise error.Abort(_('uncommitted merge'))
5172 bheads = repo.branchheads()
5137 bheads = repo.branchheads()
5173 if not opts.get('force') and bheads and p1 not in bheads:
5138 if not opts.get('force') and bheads and p1 not in bheads:
5174 raise error.Abort(_('working directory is not at a branch head '
5139 raise error.Abort(_('working directory is not at a branch head '
5175 '(use -f to force)'))
5140 '(use -f to force)'))
5176 r = scmutil.revsingle(repo, rev_).node()
5141 r = scmutil.revsingle(repo, rev_).node()
5177
5142
5178 if not message:
5143 if not message:
5179 # we don't translate commit messages
5144 # we don't translate commit messages
5180 message = ('Added tag %s for changeset %s' %
5145 message = ('Added tag %s for changeset %s' %
5181 (', '.join(names), short(r)))
5146 (', '.join(names), short(r)))
5182
5147
5183 date = opts.get('date')
5148 date = opts.get('date')
5184 if date:
5149 if date:
5185 date = util.parsedate(date)
5150 date = util.parsedate(date)
5186
5151
5187 if opts.get('remove'):
5152 if opts.get('remove'):
5188 editform = 'tag.remove'
5153 editform = 'tag.remove'
5189 else:
5154 else:
5190 editform = 'tag.add'
5155 editform = 'tag.add'
5191 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5156 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5192
5157
5193 # don't allow tagging the null rev
5158 # don't allow tagging the null rev
5194 if (not opts.get('remove') and
5159 if (not opts.get('remove') and
5195 scmutil.revsingle(repo, rev_).rev() == nullrev):
5160 scmutil.revsingle(repo, rev_).rev() == nullrev):
5196 raise error.Abort(_("cannot tag null revision"))
5161 raise error.Abort(_("cannot tag null revision"))
5197
5162
5198 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5163 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5199 editor=editor)
5164 editor=editor)
5200 finally:
5165 finally:
5201 release(lock, wlock)
5166 release(lock, wlock)
5202
5167
5203 @command('tags', formatteropts, '')
5168 @command('tags', formatteropts, '')
5204 def tags(ui, repo, **opts):
5169 def tags(ui, repo, **opts):
5205 """list repository tags
5170 """list repository tags
5206
5171
5207 This lists both regular and local tags. When the -v/--verbose
5172 This lists both regular and local tags. When the -v/--verbose
5208 switch is used, a third column "local" is printed for local tags.
5173 switch is used, a third column "local" is printed for local tags.
5209 When the -q/--quiet switch is used, only the tag name is printed.
5174 When the -q/--quiet switch is used, only the tag name is printed.
5210
5175
5211 Returns 0 on success.
5176 Returns 0 on success.
5212 """
5177 """
5213
5178
5214 ui.pager('tags')
5179 ui.pager('tags')
5215 fm = ui.formatter('tags', opts)
5180 fm = ui.formatter('tags', opts)
5216 hexfunc = fm.hexfunc
5181 hexfunc = fm.hexfunc
5217 tagtype = ""
5182 tagtype = ""
5218
5183
5219 for t, n in reversed(repo.tagslist()):
5184 for t, n in reversed(repo.tagslist()):
5220 hn = hexfunc(n)
5185 hn = hexfunc(n)
5221 label = 'tags.normal'
5186 label = 'tags.normal'
5222 tagtype = ''
5187 tagtype = ''
5223 if repo.tagtype(t) == 'local':
5188 if repo.tagtype(t) == 'local':
5224 label = 'tags.local'
5189 label = 'tags.local'
5225 tagtype = 'local'
5190 tagtype = 'local'
5226
5191
5227 fm.startitem()
5192 fm.startitem()
5228 fm.write('tag', '%s', t, label=label)
5193 fm.write('tag', '%s', t, label=label)
5229 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5194 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5230 fm.condwrite(not ui.quiet, 'rev node', fmt,
5195 fm.condwrite(not ui.quiet, 'rev node', fmt,
5231 repo.changelog.rev(n), hn, label=label)
5196 repo.changelog.rev(n), hn, label=label)
5232 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5197 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5233 tagtype, label=label)
5198 tagtype, label=label)
5234 fm.plain('\n')
5199 fm.plain('\n')
5235 fm.end()
5200 fm.end()
5236
5201
5237 @command('tip',
5202 @command('tip',
5238 [('p', 'patch', None, _('show patch')),
5203 [('p', 'patch', None, _('show patch')),
5239 ('g', 'git', None, _('use git extended diff format')),
5204 ('g', 'git', None, _('use git extended diff format')),
5240 ] + templateopts,
5205 ] + templateopts,
5241 _('[-p] [-g]'))
5206 _('[-p] [-g]'))
5242 def tip(ui, repo, **opts):
5207 def tip(ui, repo, **opts):
5243 """show the tip revision (DEPRECATED)
5208 """show the tip revision (DEPRECATED)
5244
5209
5245 The tip revision (usually just called the tip) is the changeset
5210 The tip revision (usually just called the tip) is the changeset
5246 most recently added to the repository (and therefore the most
5211 most recently added to the repository (and therefore the most
5247 recently changed head).
5212 recently changed head).
5248
5213
5249 If you have just made a commit, that commit will be the tip. If
5214 If you have just made a commit, that commit will be the tip. If
5250 you have just pulled changes from another repository, the tip of
5215 you have just pulled changes from another repository, the tip of
5251 that repository becomes the current tip. The "tip" tag is special
5216 that repository becomes the current tip. The "tip" tag is special
5252 and cannot be renamed or assigned to a different changeset.
5217 and cannot be renamed or assigned to a different changeset.
5253
5218
5254 This command is deprecated, please use :hg:`heads` instead.
5219 This command is deprecated, please use :hg:`heads` instead.
5255
5220
5256 Returns 0 on success.
5221 Returns 0 on success.
5257 """
5222 """
5258 displayer = cmdutil.show_changeset(ui, repo, opts)
5223 displayer = cmdutil.show_changeset(ui, repo, opts)
5259 displayer.show(repo['tip'])
5224 displayer.show(repo['tip'])
5260 displayer.close()
5225 displayer.close()
5261
5226
5262 @command('unbundle',
5227 @command('unbundle',
5263 [('u', 'update', None,
5228 [('u', 'update', None,
5264 _('update to new branch head if changesets were unbundled'))],
5229 _('update to new branch head if changesets were unbundled'))],
5265 _('[-u] FILE...'))
5230 _('[-u] FILE...'))
5266 def unbundle(ui, repo, fname1, *fnames, **opts):
5231 def unbundle(ui, repo, fname1, *fnames, **opts):
5267 """apply one or more changegroup files
5232 """apply one or more changegroup files
5268
5233
5269 Apply one or more compressed changegroup files generated by the
5234 Apply one or more compressed changegroup files generated by the
5270 bundle command.
5235 bundle command.
5271
5236
5272 Returns 0 on success, 1 if an update has unresolved files.
5237 Returns 0 on success, 1 if an update has unresolved files.
5273 """
5238 """
5274 fnames = (fname1,) + fnames
5239 fnames = (fname1,) + fnames
5275
5240
5276 with repo.lock():
5241 with repo.lock():
5277 for fname in fnames:
5242 for fname in fnames:
5278 f = hg.openpath(ui, fname)
5243 f = hg.openpath(ui, fname)
5279 gen = exchange.readbundle(ui, f, fname)
5244 gen = exchange.readbundle(ui, f, fname)
5280 if isinstance(gen, bundle2.unbundle20):
5245 if isinstance(gen, bundle2.unbundle20):
5281 tr = repo.transaction('unbundle')
5246 tr = repo.transaction('unbundle')
5282 try:
5247 try:
5283 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5248 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5284 url='bundle:' + fname)
5249 url='bundle:' + fname)
5285 tr.close()
5250 tr.close()
5286 except error.BundleUnknownFeatureError as exc:
5251 except error.BundleUnknownFeatureError as exc:
5287 raise error.Abort(_('%s: unknown bundle feature, %s')
5252 raise error.Abort(_('%s: unknown bundle feature, %s')
5288 % (fname, exc),
5253 % (fname, exc),
5289 hint=_("see https://mercurial-scm.org/"
5254 hint=_("see https://mercurial-scm.org/"
5290 "wiki/BundleFeature for more "
5255 "wiki/BundleFeature for more "
5291 "information"))
5256 "information"))
5292 finally:
5257 finally:
5293 if tr:
5258 if tr:
5294 tr.release()
5259 tr.release()
5295 changes = [r.get('return', 0)
5260 changes = [r.get('return', 0)
5296 for r in op.records['changegroup']]
5261 for r in op.records['changegroup']]
5297 modheads = changegroup.combineresults(changes)
5262 modheads = changegroup.combineresults(changes)
5298 elif isinstance(gen, streamclone.streamcloneapplier):
5263 elif isinstance(gen, streamclone.streamcloneapplier):
5299 raise error.Abort(
5264 raise error.Abort(
5300 _('packed bundles cannot be applied with '
5265 _('packed bundles cannot be applied with '
5301 '"hg unbundle"'),
5266 '"hg unbundle"'),
5302 hint=_('use "hg debugapplystreamclonebundle"'))
5267 hint=_('use "hg debugapplystreamclonebundle"'))
5303 else:
5268 else:
5304 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5269 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5305
5270
5306 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5271 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5307
5272
5308 @command('^update|up|checkout|co',
5273 @command('^update|up|checkout|co',
5309 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5274 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5310 ('c', 'check', None, _('require clean working directory')),
5275 ('c', 'check', None, _('require clean working directory')),
5311 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5276 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5312 ('r', 'rev', '', _('revision'), _('REV'))
5277 ('r', 'rev', '', _('revision'), _('REV'))
5313 ] + mergetoolopts,
5278 ] + mergetoolopts,
5314 _('[-C|-c] [-d DATE] [[-r] REV]'))
5279 _('[-C|-c] [-d DATE] [[-r] REV]'))
5315 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5280 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5316 tool=None):
5281 tool=None):
5317 """update working directory (or switch revisions)
5282 """update working directory (or switch revisions)
5318
5283
5319 Update the repository's working directory to the specified
5284 Update the repository's working directory to the specified
5320 changeset. If no changeset is specified, update to the tip of the
5285 changeset. If no changeset is specified, update to the tip of the
5321 current named branch and move the active bookmark (see :hg:`help
5286 current named branch and move the active bookmark (see :hg:`help
5322 bookmarks`).
5287 bookmarks`).
5323
5288
5324 Update sets the working directory's parent revision to the specified
5289 Update sets the working directory's parent revision to the specified
5325 changeset (see :hg:`help parents`).
5290 changeset (see :hg:`help parents`).
5326
5291
5327 If the changeset is not a descendant or ancestor of the working
5292 If the changeset is not a descendant or ancestor of the working
5328 directory's parent and there are uncommitted changes, the update is
5293 directory's parent and there are uncommitted changes, the update is
5329 aborted. With the -c/--check option, the working directory is checked
5294 aborted. With the -c/--check option, the working directory is checked
5330 for uncommitted changes; if none are found, the working directory is
5295 for uncommitted changes; if none are found, the working directory is
5331 updated to the specified changeset.
5296 updated to the specified changeset.
5332
5297
5333 .. container:: verbose
5298 .. container:: verbose
5334
5299
5335 The -C/--clean and -c/--check options control what happens if the
5300 The -C/--clean and -c/--check options control what happens if the
5336 working directory contains uncommitted changes.
5301 working directory contains uncommitted changes.
5337 At most of one of them can be specified.
5302 At most of one of them can be specified.
5338
5303
5339 1. If no option is specified, and if
5304 1. If no option is specified, and if
5340 the requested changeset is an ancestor or descendant of
5305 the requested changeset is an ancestor or descendant of
5341 the working directory's parent, the uncommitted changes
5306 the working directory's parent, the uncommitted changes
5342 are merged into the requested changeset and the merged
5307 are merged into the requested changeset and the merged
5343 result is left uncommitted. If the requested changeset is
5308 result is left uncommitted. If the requested changeset is
5344 not an ancestor or descendant (that is, it is on another
5309 not an ancestor or descendant (that is, it is on another
5345 branch), the update is aborted and the uncommitted changes
5310 branch), the update is aborted and the uncommitted changes
5346 are preserved.
5311 are preserved.
5347
5312
5348 2. With the -c/--check option, the update is aborted and the
5313 2. With the -c/--check option, the update is aborted and the
5349 uncommitted changes are preserved.
5314 uncommitted changes are preserved.
5350
5315
5351 3. With the -C/--clean option, uncommitted changes are discarded and
5316 3. With the -C/--clean option, uncommitted changes are discarded and
5352 the working directory is updated to the requested changeset.
5317 the working directory is updated to the requested changeset.
5353
5318
5354 To cancel an uncommitted merge (and lose your changes), use
5319 To cancel an uncommitted merge (and lose your changes), use
5355 :hg:`update --clean .`.
5320 :hg:`update --clean .`.
5356
5321
5357 Use null as the changeset to remove the working directory (like
5322 Use null as the changeset to remove the working directory (like
5358 :hg:`clone -U`).
5323 :hg:`clone -U`).
5359
5324
5360 If you want to revert just one file to an older revision, use
5325 If you want to revert just one file to an older revision, use
5361 :hg:`revert [-r REV] NAME`.
5326 :hg:`revert [-r REV] NAME`.
5362
5327
5363 See :hg:`help dates` for a list of formats valid for -d/--date.
5328 See :hg:`help dates` for a list of formats valid for -d/--date.
5364
5329
5365 Returns 0 on success, 1 if there are unresolved files.
5330 Returns 0 on success, 1 if there are unresolved files.
5366 """
5331 """
5367 if rev and node:
5332 if rev and node:
5368 raise error.Abort(_("please specify just one revision"))
5333 raise error.Abort(_("please specify just one revision"))
5369
5334
5370 if rev is None or rev == '':
5335 if rev is None or rev == '':
5371 rev = node
5336 rev = node
5372
5337
5373 if date and rev is not None:
5338 if date and rev is not None:
5374 raise error.Abort(_("you can't specify a revision and a date"))
5339 raise error.Abort(_("you can't specify a revision and a date"))
5375
5340
5376 if check and clean:
5341 if check and clean:
5377 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5342 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5378
5343
5379 with repo.wlock():
5344 with repo.wlock():
5380 cmdutil.clearunfinished(repo)
5345 cmdutil.clearunfinished(repo)
5381
5346
5382 if date:
5347 if date:
5383 rev = cmdutil.finddate(ui, repo, date)
5348 rev = cmdutil.finddate(ui, repo, date)
5384
5349
5385 # if we defined a bookmark, we have to remember the original name
5350 # if we defined a bookmark, we have to remember the original name
5386 brev = rev
5351 brev = rev
5387 rev = scmutil.revsingle(repo, rev, rev).rev()
5352 rev = scmutil.revsingle(repo, rev, rev).rev()
5388
5353
5389 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5354 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5390
5355
5391 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5356 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5392
5357
5393 @command('verify', [])
5358 @command('verify', [])
5394 def verify(ui, repo):
5359 def verify(ui, repo):
5395 """verify the integrity of the repository
5360 """verify the integrity of the repository
5396
5361
5397 Verify the integrity of the current repository.
5362 Verify the integrity of the current repository.
5398
5363
5399 This will perform an extensive check of the repository's
5364 This will perform an extensive check of the repository's
5400 integrity, validating the hashes and checksums of each entry in
5365 integrity, validating the hashes and checksums of each entry in
5401 the changelog, manifest, and tracked files, as well as the
5366 the changelog, manifest, and tracked files, as well as the
5402 integrity of their crosslinks and indices.
5367 integrity of their crosslinks and indices.
5403
5368
5404 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5369 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5405 for more information about recovery from corruption of the
5370 for more information about recovery from corruption of the
5406 repository.
5371 repository.
5407
5372
5408 Returns 0 on success, 1 if errors are encountered.
5373 Returns 0 on success, 1 if errors are encountered.
5409 """
5374 """
5410 return hg.verify(repo)
5375 return hg.verify(repo)
5411
5376
5412 @command('version', [] + formatteropts, norepo=True)
5377 @command('version', [] + formatteropts, norepo=True)
5413 def version_(ui, **opts):
5378 def version_(ui, **opts):
5414 """output version and copyright information"""
5379 """output version and copyright information"""
5415 if ui.verbose:
5380 if ui.verbose:
5416 ui.pager('version')
5381 ui.pager('version')
5417 fm = ui.formatter("version", opts)
5382 fm = ui.formatter("version", opts)
5418 fm.startitem()
5383 fm.startitem()
5419 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5384 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5420 util.version())
5385 util.version())
5421 license = _(
5386 license = _(
5422 "(see https://mercurial-scm.org for more information)\n"
5387 "(see https://mercurial-scm.org for more information)\n"
5423 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5388 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5424 "This is free software; see the source for copying conditions. "
5389 "This is free software; see the source for copying conditions. "
5425 "There is NO\nwarranty; "
5390 "There is NO\nwarranty; "
5426 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5391 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5427 )
5392 )
5428 if not ui.quiet:
5393 if not ui.quiet:
5429 fm.plain(license)
5394 fm.plain(license)
5430
5395
5431 if ui.verbose:
5396 if ui.verbose:
5432 fm.plain(_("\nEnabled extensions:\n\n"))
5397 fm.plain(_("\nEnabled extensions:\n\n"))
5433 # format names and versions into columns
5398 # format names and versions into columns
5434 names = []
5399 names = []
5435 vers = []
5400 vers = []
5436 isinternals = []
5401 isinternals = []
5437 for name, module in extensions.extensions():
5402 for name, module in extensions.extensions():
5438 names.append(name)
5403 names.append(name)
5439 vers.append(extensions.moduleversion(module) or None)
5404 vers.append(extensions.moduleversion(module) or None)
5440 isinternals.append(extensions.ismoduleinternal(module))
5405 isinternals.append(extensions.ismoduleinternal(module))
5441 fn = fm.nested("extensions")
5406 fn = fm.nested("extensions")
5442 if names:
5407 if names:
5443 namefmt = " %%-%ds " % max(len(n) for n in names)
5408 namefmt = " %%-%ds " % max(len(n) for n in names)
5444 places = [_("external"), _("internal")]
5409 places = [_("external"), _("internal")]
5445 for n, v, p in zip(names, vers, isinternals):
5410 for n, v, p in zip(names, vers, isinternals):
5446 fn.startitem()
5411 fn.startitem()
5447 fn.condwrite(ui.verbose, "name", namefmt, n)
5412 fn.condwrite(ui.verbose, "name", namefmt, n)
5448 if ui.verbose:
5413 if ui.verbose:
5449 fn.plain("%s " % places[p])
5414 fn.plain("%s " % places[p])
5450 fn.data(bundled=p)
5415 fn.data(bundled=p)
5451 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5416 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5452 if ui.verbose:
5417 if ui.verbose:
5453 fn.plain("\n")
5418 fn.plain("\n")
5454 fn.end()
5419 fn.end()
5455 fm.end()
5420 fm.end()
5456
5421
5457 def loadcmdtable(ui, name, cmdtable):
5422 def loadcmdtable(ui, name, cmdtable):
5458 """Load command functions from specified cmdtable
5423 """Load command functions from specified cmdtable
5459 """
5424 """
5460 overrides = [cmd for cmd in cmdtable if cmd in table]
5425 overrides = [cmd for cmd in cmdtable if cmd in table]
5461 if overrides:
5426 if overrides:
5462 ui.warn(_("extension '%s' overrides commands: %s\n")
5427 ui.warn(_("extension '%s' overrides commands: %s\n")
5463 % (name, " ".join(overrides)))
5428 % (name, " ".join(overrides)))
5464 table.update(cmdtable)
5429 table.update(cmdtable)
@@ -1,607 +1,651 b''
1 # help.py - help data for mercurial
1 # help.py - help data for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import itertools
10 import itertools
11 import os
11 import os
12 import textwrap
12 import textwrap
13
13
14 from .i18n import (
14 from .i18n import (
15 _,
15 _,
16 gettext,
16 gettext,
17 )
17 )
18 from . import (
18 from . import (
19 cmdutil,
19 cmdutil,
20 encoding,
20 encoding,
21 error,
21 error,
22 extensions,
22 extensions,
23 filemerge,
23 filemerge,
24 fileset,
24 fileset,
25 minirst,
25 minirst,
26 revset,
26 revset,
27 templatefilters,
27 templatefilters,
28 templatekw,
28 templatekw,
29 templater,
29 templater,
30 util,
30 util,
31 )
31 )
32 from .hgweb import (
32 from .hgweb import (
33 webcommands,
33 webcommands,
34 )
34 )
35
35
36 _exclkeywords = [
36 _exclkeywords = [
37 "(DEPRECATED)",
37 "(DEPRECATED)",
38 "(EXPERIMENTAL)",
38 "(EXPERIMENTAL)",
39 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
39 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
40 _("(DEPRECATED)"),
40 _("(DEPRECATED)"),
41 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
41 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
42 _("(EXPERIMENTAL)"),
42 _("(EXPERIMENTAL)"),
43 ]
43 ]
44
44
45 def listexts(header, exts, indent=1, showdeprecated=False):
45 def listexts(header, exts, indent=1, showdeprecated=False):
46 '''return a text listing of the given extensions'''
46 '''return a text listing of the given extensions'''
47 rst = []
47 rst = []
48 if exts:
48 if exts:
49 for name, desc in sorted(exts.iteritems()):
49 for name, desc in sorted(exts.iteritems()):
50 if not showdeprecated and any(w in desc for w in _exclkeywords):
50 if not showdeprecated and any(w in desc for w in _exclkeywords):
51 continue
51 continue
52 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
52 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
53 if rst:
53 if rst:
54 rst.insert(0, '\n%s\n\n' % header)
54 rst.insert(0, '\n%s\n\n' % header)
55 return rst
55 return rst
56
56
57 def extshelp(ui):
57 def extshelp(ui):
58 rst = loaddoc('extensions')(ui).splitlines(True)
58 rst = loaddoc('extensions')(ui).splitlines(True)
59 rst.extend(listexts(
59 rst.extend(listexts(
60 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
60 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
61 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
61 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
62 doc = ''.join(rst)
62 doc = ''.join(rst)
63 return doc
63 return doc
64
64
65 def optrst(header, options, verbose):
65 def optrst(header, options, verbose):
66 data = []
66 data = []
67 multioccur = False
67 multioccur = False
68 for option in options:
68 for option in options:
69 if len(option) == 5:
69 if len(option) == 5:
70 shortopt, longopt, default, desc, optlabel = option
70 shortopt, longopt, default, desc, optlabel = option
71 else:
71 else:
72 shortopt, longopt, default, desc = option
72 shortopt, longopt, default, desc = option
73 optlabel = _("VALUE") # default label
73 optlabel = _("VALUE") # default label
74
74
75 if not verbose and any(w in desc for w in _exclkeywords):
75 if not verbose and any(w in desc for w in _exclkeywords):
76 continue
76 continue
77
77
78 so = ''
78 so = ''
79 if shortopt:
79 if shortopt:
80 so = '-' + shortopt
80 so = '-' + shortopt
81 lo = '--' + longopt
81 lo = '--' + longopt
82 if default:
82 if default:
83 desc += _(" (default: %s)") % default
83 desc += _(" (default: %s)") % default
84
84
85 if isinstance(default, list):
85 if isinstance(default, list):
86 lo += " %s [+]" % optlabel
86 lo += " %s [+]" % optlabel
87 multioccur = True
87 multioccur = True
88 elif (default is not None) and not isinstance(default, bool):
88 elif (default is not None) and not isinstance(default, bool):
89 lo += " %s" % optlabel
89 lo += " %s" % optlabel
90
90
91 data.append((so, lo, desc))
91 data.append((so, lo, desc))
92
92
93 if multioccur:
93 if multioccur:
94 header += (_(" ([+] can be repeated)"))
94 header += (_(" ([+] can be repeated)"))
95
95
96 rst = ['\n%s:\n\n' % header]
96 rst = ['\n%s:\n\n' % header]
97 rst.extend(minirst.maketable(data, 1))
97 rst.extend(minirst.maketable(data, 1))
98
98
99 return ''.join(rst)
99 return ''.join(rst)
100
100
101 def indicateomitted(rst, omitted, notomitted=None):
101 def indicateomitted(rst, omitted, notomitted=None):
102 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
102 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
103 if notomitted:
103 if notomitted:
104 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
104 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
105
105
106 def filtercmd(ui, cmd, kw, doc):
106 def filtercmd(ui, cmd, kw, doc):
107 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
107 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
108 return True
108 return True
109 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
109 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
110 return True
110 return True
111 return False
111 return False
112
112
113 def topicmatch(ui, kw):
113 def topicmatch(ui, kw):
114 """Return help topics matching kw.
114 """Return help topics matching kw.
115
115
116 Returns {'section': [(name, summary), ...], ...} where section is
116 Returns {'section': [(name, summary), ...], ...} where section is
117 one of topics, commands, extensions, or extensioncommands.
117 one of topics, commands, extensions, or extensioncommands.
118 """
118 """
119 kw = encoding.lower(kw)
119 kw = encoding.lower(kw)
120 def lowercontains(container):
120 def lowercontains(container):
121 return kw in encoding.lower(container) # translated in helptable
121 return kw in encoding.lower(container) # translated in helptable
122 results = {'topics': [],
122 results = {'topics': [],
123 'commands': [],
123 'commands': [],
124 'extensions': [],
124 'extensions': [],
125 'extensioncommands': [],
125 'extensioncommands': [],
126 }
126 }
127 for names, header, doc in helptable:
127 for names, header, doc in helptable:
128 # Old extensions may use a str as doc.
128 # Old extensions may use a str as doc.
129 if (sum(map(lowercontains, names))
129 if (sum(map(lowercontains, names))
130 or lowercontains(header)
130 or lowercontains(header)
131 or (callable(doc) and lowercontains(doc(ui)))):
131 or (callable(doc) and lowercontains(doc(ui)))):
132 results['topics'].append((names[0], header))
132 results['topics'].append((names[0], header))
133 from . import commands # avoid cycle
133 from . import commands # avoid cycle
134 for cmd, entry in commands.table.iteritems():
134 for cmd, entry in commands.table.iteritems():
135 if len(entry) == 3:
135 if len(entry) == 3:
136 summary = entry[2]
136 summary = entry[2]
137 else:
137 else:
138 summary = ''
138 summary = ''
139 # translate docs *before* searching there
139 # translate docs *before* searching there
140 docs = _(getattr(entry[0], '__doc__', None)) or ''
140 docs = _(getattr(entry[0], '__doc__', None)) or ''
141 if kw in cmd or lowercontains(summary) or lowercontains(docs):
141 if kw in cmd or lowercontains(summary) or lowercontains(docs):
142 doclines = docs.splitlines()
142 doclines = docs.splitlines()
143 if doclines:
143 if doclines:
144 summary = doclines[0]
144 summary = doclines[0]
145 cmdname = cmd.partition('|')[0].lstrip('^')
145 cmdname = cmd.partition('|')[0].lstrip('^')
146 if filtercmd(ui, cmdname, kw, docs):
146 if filtercmd(ui, cmdname, kw, docs):
147 continue
147 continue
148 results['commands'].append((cmdname, summary))
148 results['commands'].append((cmdname, summary))
149 for name, docs in itertools.chain(
149 for name, docs in itertools.chain(
150 extensions.enabled(False).iteritems(),
150 extensions.enabled(False).iteritems(),
151 extensions.disabled().iteritems()):
151 extensions.disabled().iteritems()):
152 if not docs:
152 if not docs:
153 continue
153 continue
154 mod = extensions.load(ui, name, '')
154 mod = extensions.load(ui, name, '')
155 name = name.rpartition('.')[-1]
155 name = name.rpartition('.')[-1]
156 if lowercontains(name) or lowercontains(docs):
156 if lowercontains(name) or lowercontains(docs):
157 # extension docs are already translated
157 # extension docs are already translated
158 results['extensions'].append((name, docs.splitlines()[0]))
158 results['extensions'].append((name, docs.splitlines()[0]))
159 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
159 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
160 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
160 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
161 cmdname = cmd.partition('|')[0].lstrip('^')
161 cmdname = cmd.partition('|')[0].lstrip('^')
162 if entry[0].__doc__:
162 if entry[0].__doc__:
163 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
163 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
164 else:
164 else:
165 cmddoc = _('(no help text available)')
165 cmddoc = _('(no help text available)')
166 if filtercmd(ui, cmdname, kw, cmddoc):
166 if filtercmd(ui, cmdname, kw, cmddoc):
167 continue
167 continue
168 results['extensioncommands'].append((cmdname, cmddoc))
168 results['extensioncommands'].append((cmdname, cmddoc))
169 return results
169 return results
170
170
171 def loaddoc(topic, subdir=None):
171 def loaddoc(topic, subdir=None):
172 """Return a delayed loader for help/topic.txt."""
172 """Return a delayed loader for help/topic.txt."""
173
173
174 def loader(ui):
174 def loader(ui):
175 docdir = os.path.join(util.datapath, 'help')
175 docdir = os.path.join(util.datapath, 'help')
176 if subdir:
176 if subdir:
177 docdir = os.path.join(docdir, subdir)
177 docdir = os.path.join(docdir, subdir)
178 path = os.path.join(docdir, topic + ".txt")
178 path = os.path.join(docdir, topic + ".txt")
179 doc = gettext(util.readfile(path))
179 doc = gettext(util.readfile(path))
180 for rewriter in helphooks.get(topic, []):
180 for rewriter in helphooks.get(topic, []):
181 doc = rewriter(ui, topic, doc)
181 doc = rewriter(ui, topic, doc)
182 return doc
182 return doc
183
183
184 return loader
184 return loader
185
185
186 internalstable = sorted([
186 internalstable = sorted([
187 (['bundles'], _('Bundles'),
187 (['bundles'], _('Bundles'),
188 loaddoc('bundles', subdir='internals')),
188 loaddoc('bundles', subdir='internals')),
189 (['changegroups'], _('Changegroups'),
189 (['changegroups'], _('Changegroups'),
190 loaddoc('changegroups', subdir='internals')),
190 loaddoc('changegroups', subdir='internals')),
191 (['requirements'], _('Repository Requirements'),
191 (['requirements'], _('Repository Requirements'),
192 loaddoc('requirements', subdir='internals')),
192 loaddoc('requirements', subdir='internals')),
193 (['revlogs'], _('Revision Logs'),
193 (['revlogs'], _('Revision Logs'),
194 loaddoc('revlogs', subdir='internals')),
194 loaddoc('revlogs', subdir='internals')),
195 (['wireprotocol'], _('Wire Protocol'),
195 (['wireprotocol'], _('Wire Protocol'),
196 loaddoc('wireprotocol', subdir='internals')),
196 loaddoc('wireprotocol', subdir='internals')),
197 ])
197 ])
198
198
199 def internalshelp(ui):
199 def internalshelp(ui):
200 """Generate the index for the "internals" topic."""
200 """Generate the index for the "internals" topic."""
201 lines = []
201 lines = []
202 for names, header, doc in internalstable:
202 for names, header, doc in internalstable:
203 lines.append(' :%s: %s\n' % (names[0], header))
203 lines.append(' :%s: %s\n' % (names[0], header))
204
204
205 return ''.join(lines)
205 return ''.join(lines)
206
206
207 helptable = sorted([
207 helptable = sorted([
208 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
208 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
209 (["dates"], _("Date Formats"), loaddoc('dates')),
209 (["dates"], _("Date Formats"), loaddoc('dates')),
210 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
210 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
211 (['environment', 'env'], _('Environment Variables'),
211 (['environment', 'env'], _('Environment Variables'),
212 loaddoc('environment')),
212 loaddoc('environment')),
213 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
213 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
214 _('Specifying Revisions'), loaddoc('revisions')),
214 _('Specifying Revisions'), loaddoc('revisions')),
215 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
215 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
216 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
216 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
217 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
217 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
218 loaddoc('merge-tools')),
218 loaddoc('merge-tools')),
219 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
219 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
220 loaddoc('templates')),
220 loaddoc('templates')),
221 (['urls'], _('URL Paths'), loaddoc('urls')),
221 (['urls'], _('URL Paths'), loaddoc('urls')),
222 (["extensions"], _("Using Additional Features"), extshelp),
222 (["extensions"], _("Using Additional Features"), extshelp),
223 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
223 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
224 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
224 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
225 (["glossary"], _("Glossary"), loaddoc('glossary')),
225 (["glossary"], _("Glossary"), loaddoc('glossary')),
226 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
226 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
227 loaddoc('hgignore')),
227 loaddoc('hgignore')),
228 (["phases"], _("Working with Phases"), loaddoc('phases')),
228 (["phases"], _("Working with Phases"), loaddoc('phases')),
229 (['scripting'], _('Using Mercurial from scripts and automation'),
229 (['scripting'], _('Using Mercurial from scripts and automation'),
230 loaddoc('scripting')),
230 loaddoc('scripting')),
231 (['internals'], _("Technical implementation topics"),
231 (['internals'], _("Technical implementation topics"),
232 internalshelp),
232 internalshelp),
233 ])
233 ])
234
234
235 # Maps topics with sub-topics to a list of their sub-topics.
235 # Maps topics with sub-topics to a list of their sub-topics.
236 subtopics = {
236 subtopics = {
237 'internals': internalstable,
237 'internals': internalstable,
238 }
238 }
239
239
240 # Map topics to lists of callable taking the current topic help and
240 # Map topics to lists of callable taking the current topic help and
241 # returning the updated version
241 # returning the updated version
242 helphooks = {}
242 helphooks = {}
243
243
244 def addtopichook(topic, rewriter):
244 def addtopichook(topic, rewriter):
245 helphooks.setdefault(topic, []).append(rewriter)
245 helphooks.setdefault(topic, []).append(rewriter)
246
246
247 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
247 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
248 """Extract docstring from the items key to function mapping, build a
248 """Extract docstring from the items key to function mapping, build a
249 single documentation block and use it to overwrite the marker in doc.
249 single documentation block and use it to overwrite the marker in doc.
250 """
250 """
251 entries = []
251 entries = []
252 for name in sorted(items):
252 for name in sorted(items):
253 text = (items[name].__doc__ or '').rstrip()
253 text = (items[name].__doc__ or '').rstrip()
254 if (not text
254 if (not text
255 or not ui.verbose and any(w in text for w in _exclkeywords)):
255 or not ui.verbose and any(w in text for w in _exclkeywords)):
256 continue
256 continue
257 text = gettext(text)
257 text = gettext(text)
258 if dedent:
258 if dedent:
259 text = textwrap.dedent(text)
259 text = textwrap.dedent(text)
260 lines = text.splitlines()
260 lines = text.splitlines()
261 doclines = [(lines[0])]
261 doclines = [(lines[0])]
262 for l in lines[1:]:
262 for l in lines[1:]:
263 # Stop once we find some Python doctest
263 # Stop once we find some Python doctest
264 if l.strip().startswith('>>>'):
264 if l.strip().startswith('>>>'):
265 break
265 break
266 if dedent:
266 if dedent:
267 doclines.append(l.rstrip())
267 doclines.append(l.rstrip())
268 else:
268 else:
269 doclines.append(' ' + l.strip())
269 doclines.append(' ' + l.strip())
270 entries.append('\n'.join(doclines))
270 entries.append('\n'.join(doclines))
271 entries = '\n\n'.join(entries)
271 entries = '\n\n'.join(entries)
272 return doc.replace(marker, entries)
272 return doc.replace(marker, entries)
273
273
274 def addtopicsymbols(topic, marker, symbols, dedent=False):
274 def addtopicsymbols(topic, marker, symbols, dedent=False):
275 def add(ui, topic, doc):
275 def add(ui, topic, doc):
276 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
276 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
277 addtopichook(topic, add)
277 addtopichook(topic, add)
278
278
279 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
279 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
280 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
280 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
281 filemerge.internalsdoc)
281 filemerge.internalsdoc)
282 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
282 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
283 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
283 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
284 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
284 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
285 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
285 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
286 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
286 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
287 dedent=True)
287 dedent=True)
288
288
289 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
289 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
290 '''
290 '''
291 Generate the help for 'name' as unformatted restructured text. If
291 Generate the help for 'name' as unformatted restructured text. If
292 'name' is None, describe the commands available.
292 'name' is None, describe the commands available.
293 '''
293 '''
294
294
295 from . import commands # avoid cycle
295 from . import commands # avoid cycle
296
296
297 def helpcmd(name, subtopic=None):
297 def helpcmd(name, subtopic=None):
298 try:
298 try:
299 aliases, entry = cmdutil.findcmd(name, commands.table,
299 aliases, entry = cmdutil.findcmd(name, commands.table,
300 strict=unknowncmd)
300 strict=unknowncmd)
301 except error.AmbiguousCommand as inst:
301 except error.AmbiguousCommand as inst:
302 # py3k fix: except vars can't be used outside the scope of the
302 # py3k fix: except vars can't be used outside the scope of the
303 # except block, nor can be used inside a lambda. python issue4617
303 # except block, nor can be used inside a lambda. python issue4617
304 prefix = inst.args[0]
304 prefix = inst.args[0]
305 select = lambda c: c.lstrip('^').startswith(prefix)
305 select = lambda c: c.lstrip('^').startswith(prefix)
306 rst = helplist(select)
306 rst = helplist(select)
307 return rst
307 return rst
308
308
309 rst = []
309 rst = []
310
310
311 # check if it's an invalid alias and display its error if it is
311 # check if it's an invalid alias and display its error if it is
312 if getattr(entry[0], 'badalias', None):
312 if getattr(entry[0], 'badalias', None):
313 rst.append(entry[0].badalias + '\n')
313 rst.append(entry[0].badalias + '\n')
314 if entry[0].unknowncmd:
314 if entry[0].unknowncmd:
315 try:
315 try:
316 rst.extend(helpextcmd(entry[0].cmdname))
316 rst.extend(helpextcmd(entry[0].cmdname))
317 except error.UnknownCommand:
317 except error.UnknownCommand:
318 pass
318 pass
319 return rst
319 return rst
320
320
321 # synopsis
321 # synopsis
322 if len(entry) > 2:
322 if len(entry) > 2:
323 if entry[2].startswith('hg'):
323 if entry[2].startswith('hg'):
324 rst.append("%s\n" % entry[2])
324 rst.append("%s\n" % entry[2])
325 else:
325 else:
326 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
326 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
327 else:
327 else:
328 rst.append('hg %s\n' % aliases[0])
328 rst.append('hg %s\n' % aliases[0])
329 # aliases
329 # aliases
330 if full and not ui.quiet and len(aliases) > 1:
330 if full and not ui.quiet and len(aliases) > 1:
331 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
331 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
332 rst.append('\n')
332 rst.append('\n')
333
333
334 # description
334 # description
335 doc = gettext(entry[0].__doc__)
335 doc = gettext(entry[0].__doc__)
336 if not doc:
336 if not doc:
337 doc = _("(no help text available)")
337 doc = _("(no help text available)")
338 if util.safehasattr(entry[0], 'definition'): # aliased command
338 if util.safehasattr(entry[0], 'definition'): # aliased command
339 source = entry[0].source
339 source = entry[0].source
340 if entry[0].definition.startswith('!'): # shell alias
340 if entry[0].definition.startswith('!'): # shell alias
341 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
341 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
342 (entry[0].definition[1:], source))
342 (entry[0].definition[1:], source))
343 else:
343 else:
344 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
344 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
345 (entry[0].definition, doc, source))
345 (entry[0].definition, doc, source))
346 doc = doc.splitlines(True)
346 doc = doc.splitlines(True)
347 if ui.quiet or not full:
347 if ui.quiet or not full:
348 rst.append(doc[0])
348 rst.append(doc[0])
349 else:
349 else:
350 rst.extend(doc)
350 rst.extend(doc)
351 rst.append('\n')
351 rst.append('\n')
352
352
353 # check if this command shadows a non-trivial (multi-line)
353 # check if this command shadows a non-trivial (multi-line)
354 # extension help text
354 # extension help text
355 try:
355 try:
356 mod = extensions.find(name)
356 mod = extensions.find(name)
357 doc = gettext(mod.__doc__) or ''
357 doc = gettext(mod.__doc__) or ''
358 if '\n' in doc.strip():
358 if '\n' in doc.strip():
359 msg = _("(use 'hg help -e %s' to show help for "
359 msg = _("(use 'hg help -e %s' to show help for "
360 "the %s extension)") % (name, name)
360 "the %s extension)") % (name, name)
361 rst.append('\n%s\n' % msg)
361 rst.append('\n%s\n' % msg)
362 except KeyError:
362 except KeyError:
363 pass
363 pass
364
364
365 # options
365 # options
366 if not ui.quiet and entry[1]:
366 if not ui.quiet and entry[1]:
367 rst.append(optrst(_("options"), entry[1], ui.verbose))
367 rst.append(optrst(_("options"), entry[1], ui.verbose))
368
368
369 if ui.verbose:
369 if ui.verbose:
370 rst.append(optrst(_("global options"),
370 rst.append(optrst(_("global options"),
371 commands.globalopts, ui.verbose))
371 commands.globalopts, ui.verbose))
372
372
373 if not ui.verbose:
373 if not ui.verbose:
374 if not full:
374 if not full:
375 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
375 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
376 % name)
376 % name)
377 elif not ui.quiet:
377 elif not ui.quiet:
378 rst.append(_('\n(some details hidden, use --verbose '
378 rst.append(_('\n(some details hidden, use --verbose '
379 'to show complete help)'))
379 'to show complete help)'))
380
380
381 return rst
381 return rst
382
382
383
383
384 def helplist(select=None, **opts):
384 def helplist(select=None, **opts):
385 # list of commands
385 # list of commands
386 if name == "shortlist":
386 if name == "shortlist":
387 header = _('basic commands:\n\n')
387 header = _('basic commands:\n\n')
388 elif name == "debug":
388 elif name == "debug":
389 header = _('debug commands (internal and unsupported):\n\n')
389 header = _('debug commands (internal and unsupported):\n\n')
390 else:
390 else:
391 header = _('list of commands:\n\n')
391 header = _('list of commands:\n\n')
392
392
393 h = {}
393 h = {}
394 cmds = {}
394 cmds = {}
395 for c, e in commands.table.iteritems():
395 for c, e in commands.table.iteritems():
396 f = c.partition("|")[0]
396 f = c.partition("|")[0]
397 if select and not select(f):
397 if select and not select(f):
398 continue
398 continue
399 if (not select and name != 'shortlist' and
399 if (not select and name != 'shortlist' and
400 e[0].__module__ != commands.__name__):
400 e[0].__module__ != commands.__name__):
401 continue
401 continue
402 if name == "shortlist" and not f.startswith("^"):
402 if name == "shortlist" and not f.startswith("^"):
403 continue
403 continue
404 f = f.lstrip("^")
404 f = f.lstrip("^")
405 doc = e[0].__doc__
405 doc = e[0].__doc__
406 if filtercmd(ui, f, name, doc):
406 if filtercmd(ui, f, name, doc):
407 continue
407 continue
408 doc = gettext(doc)
408 doc = gettext(doc)
409 if not doc:
409 if not doc:
410 doc = _("(no help text available)")
410 doc = _("(no help text available)")
411 h[f] = doc.splitlines()[0].rstrip()
411 h[f] = doc.splitlines()[0].rstrip()
412 cmds[f] = c.lstrip("^")
412 cmds[f] = c.lstrip("^")
413
413
414 rst = []
414 rst = []
415 if not h:
415 if not h:
416 if not ui.quiet:
416 if not ui.quiet:
417 rst.append(_('no commands defined\n'))
417 rst.append(_('no commands defined\n'))
418 return rst
418 return rst
419
419
420 if not ui.quiet:
420 if not ui.quiet:
421 rst.append(header)
421 rst.append(header)
422 fns = sorted(h)
422 fns = sorted(h)
423 for f in fns:
423 for f in fns:
424 if ui.verbose:
424 if ui.verbose:
425 commacmds = cmds[f].replace("|",", ")
425 commacmds = cmds[f].replace("|",", ")
426 rst.append(" :%s: %s\n" % (commacmds, h[f]))
426 rst.append(" :%s: %s\n" % (commacmds, h[f]))
427 else:
427 else:
428 rst.append(' :%s: %s\n' % (f, h[f]))
428 rst.append(' :%s: %s\n' % (f, h[f]))
429
429
430 ex = opts.get
430 ex = opts.get
431 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
431 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
432 if not name and anyopts:
432 if not name and anyopts:
433 exts = listexts(_('enabled extensions:'), extensions.enabled())
433 exts = listexts(_('enabled extensions:'), extensions.enabled())
434 if exts:
434 if exts:
435 rst.append('\n')
435 rst.append('\n')
436 rst.extend(exts)
436 rst.extend(exts)
437
437
438 rst.append(_("\nadditional help topics:\n\n"))
438 rst.append(_("\nadditional help topics:\n\n"))
439 topics = []
439 topics = []
440 for names, header, doc in helptable:
440 for names, header, doc in helptable:
441 topics.append((names[0], header))
441 topics.append((names[0], header))
442 for t, desc in topics:
442 for t, desc in topics:
443 rst.append(" :%s: %s\n" % (t, desc))
443 rst.append(" :%s: %s\n" % (t, desc))
444
444
445 if ui.quiet:
445 if ui.quiet:
446 pass
446 pass
447 elif ui.verbose:
447 elif ui.verbose:
448 rst.append('\n%s\n' % optrst(_("global options"),
448 rst.append('\n%s\n' % optrst(_("global options"),
449 commands.globalopts, ui.verbose))
449 commands.globalopts, ui.verbose))
450 if name == 'shortlist':
450 if name == 'shortlist':
451 rst.append(_("\n(use 'hg help' for the full list "
451 rst.append(_("\n(use 'hg help' for the full list "
452 "of commands)\n"))
452 "of commands)\n"))
453 else:
453 else:
454 if name == 'shortlist':
454 if name == 'shortlist':
455 rst.append(_("\n(use 'hg help' for the full list of commands "
455 rst.append(_("\n(use 'hg help' for the full list of commands "
456 "or 'hg -v' for details)\n"))
456 "or 'hg -v' for details)\n"))
457 elif name and not full:
457 elif name and not full:
458 rst.append(_("\n(use 'hg help %s' to show the full help "
458 rst.append(_("\n(use 'hg help %s' to show the full help "
459 "text)\n") % name)
459 "text)\n") % name)
460 elif name and cmds and name in cmds.keys():
460 elif name and cmds and name in cmds.keys():
461 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
461 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
462 "aliases and global options)\n") % name)
462 "aliases and global options)\n") % name)
463 else:
463 else:
464 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
464 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
465 "and global options)\n")
465 "and global options)\n")
466 % (name and " " + name or ""))
466 % (name and " " + name or ""))
467 return rst
467 return rst
468
468
469 def helptopic(name, subtopic=None):
469 def helptopic(name, subtopic=None):
470 # Look for sub-topic entry first.
470 # Look for sub-topic entry first.
471 header, doc = None, None
471 header, doc = None, None
472 if subtopic and name in subtopics:
472 if subtopic and name in subtopics:
473 for names, header, doc in subtopics[name]:
473 for names, header, doc in subtopics[name]:
474 if subtopic in names:
474 if subtopic in names:
475 break
475 break
476
476
477 if not header:
477 if not header:
478 for names, header, doc in helptable:
478 for names, header, doc in helptable:
479 if name in names:
479 if name in names:
480 break
480 break
481 else:
481 else:
482 raise error.UnknownCommand(name)
482 raise error.UnknownCommand(name)
483
483
484 rst = [minirst.section(header)]
484 rst = [minirst.section(header)]
485
485
486 # description
486 # description
487 if not doc:
487 if not doc:
488 rst.append(" %s\n" % _("(no help text available)"))
488 rst.append(" %s\n" % _("(no help text available)"))
489 if callable(doc):
489 if callable(doc):
490 rst += [" %s\n" % l for l in doc(ui).splitlines()]
490 rst += [" %s\n" % l for l in doc(ui).splitlines()]
491
491
492 if not ui.verbose:
492 if not ui.verbose:
493 omitted = _('(some details hidden, use --verbose'
493 omitted = _('(some details hidden, use --verbose'
494 ' to show complete help)')
494 ' to show complete help)')
495 indicateomitted(rst, omitted)
495 indicateomitted(rst, omitted)
496
496
497 try:
497 try:
498 cmdutil.findcmd(name, commands.table)
498 cmdutil.findcmd(name, commands.table)
499 rst.append(_("\nuse 'hg help -c %s' to see help for "
499 rst.append(_("\nuse 'hg help -c %s' to see help for "
500 "the %s command\n") % (name, name))
500 "the %s command\n") % (name, name))
501 except error.UnknownCommand:
501 except error.UnknownCommand:
502 pass
502 pass
503 return rst
503 return rst
504
504
505 def helpext(name, subtopic=None):
505 def helpext(name, subtopic=None):
506 try:
506 try:
507 mod = extensions.find(name)
507 mod = extensions.find(name)
508 doc = gettext(mod.__doc__) or _('no help text available')
508 doc = gettext(mod.__doc__) or _('no help text available')
509 except KeyError:
509 except KeyError:
510 mod = None
510 mod = None
511 doc = extensions.disabledext(name)
511 doc = extensions.disabledext(name)
512 if not doc:
512 if not doc:
513 raise error.UnknownCommand(name)
513 raise error.UnknownCommand(name)
514
514
515 if '\n' not in doc:
515 if '\n' not in doc:
516 head, tail = doc, ""
516 head, tail = doc, ""
517 else:
517 else:
518 head, tail = doc.split('\n', 1)
518 head, tail = doc.split('\n', 1)
519 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
519 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
520 if tail:
520 if tail:
521 rst.extend(tail.splitlines(True))
521 rst.extend(tail.splitlines(True))
522 rst.append('\n')
522 rst.append('\n')
523
523
524 if not ui.verbose:
524 if not ui.verbose:
525 omitted = _('(some details hidden, use --verbose'
525 omitted = _('(some details hidden, use --verbose'
526 ' to show complete help)')
526 ' to show complete help)')
527 indicateomitted(rst, omitted)
527 indicateomitted(rst, omitted)
528
528
529 if mod:
529 if mod:
530 try:
530 try:
531 ct = mod.cmdtable
531 ct = mod.cmdtable
532 except AttributeError:
532 except AttributeError:
533 ct = {}
533 ct = {}
534 modcmds = set([c.partition('|')[0] for c in ct])
534 modcmds = set([c.partition('|')[0] for c in ct])
535 rst.extend(helplist(modcmds.__contains__))
535 rst.extend(helplist(modcmds.__contains__))
536 else:
536 else:
537 rst.append(_("(use 'hg help extensions' for information on enabling"
537 rst.append(_("(use 'hg help extensions' for information on enabling"
538 " extensions)\n"))
538 " extensions)\n"))
539 return rst
539 return rst
540
540
541 def helpextcmd(name, subtopic=None):
541 def helpextcmd(name, subtopic=None):
542 cmd, ext, mod = extensions.disabledcmd(ui, name,
542 cmd, ext, mod = extensions.disabledcmd(ui, name,
543 ui.configbool('ui', 'strict'))
543 ui.configbool('ui', 'strict'))
544 doc = gettext(mod.__doc__).splitlines()[0]
544 doc = gettext(mod.__doc__).splitlines()[0]
545
545
546 rst = listexts(_("'%s' is provided by the following "
546 rst = listexts(_("'%s' is provided by the following "
547 "extension:") % cmd, {ext: doc}, indent=4,
547 "extension:") % cmd, {ext: doc}, indent=4,
548 showdeprecated=True)
548 showdeprecated=True)
549 rst.append('\n')
549 rst.append('\n')
550 rst.append(_("(use 'hg help extensions' for information on enabling "
550 rst.append(_("(use 'hg help extensions' for information on enabling "
551 "extensions)\n"))
551 "extensions)\n"))
552 return rst
552 return rst
553
553
554
554
555 rst = []
555 rst = []
556 kw = opts.get('keyword')
556 kw = opts.get('keyword')
557 if kw or name is None and any(opts[o] for o in opts):
557 if kw or name is None and any(opts[o] for o in opts):
558 matches = topicmatch(ui, name or '')
558 matches = topicmatch(ui, name or '')
559 helpareas = []
559 helpareas = []
560 if opts.get('extension'):
560 if opts.get('extension'):
561 helpareas += [('extensions', _('Extensions'))]
561 helpareas += [('extensions', _('Extensions'))]
562 if opts.get('command'):
562 if opts.get('command'):
563 helpareas += [('commands', _('Commands'))]
563 helpareas += [('commands', _('Commands'))]
564 if not helpareas:
564 if not helpareas:
565 helpareas = [('topics', _('Topics')),
565 helpareas = [('topics', _('Topics')),
566 ('commands', _('Commands')),
566 ('commands', _('Commands')),
567 ('extensions', _('Extensions')),
567 ('extensions', _('Extensions')),
568 ('extensioncommands', _('Extension Commands'))]
568 ('extensioncommands', _('Extension Commands'))]
569 for t, title in helpareas:
569 for t, title in helpareas:
570 if matches[t]:
570 if matches[t]:
571 rst.append('%s:\n\n' % title)
571 rst.append('%s:\n\n' % title)
572 rst.extend(minirst.maketable(sorted(matches[t]), 1))
572 rst.extend(minirst.maketable(sorted(matches[t]), 1))
573 rst.append('\n')
573 rst.append('\n')
574 if not rst:
574 if not rst:
575 msg = _('no matches')
575 msg = _('no matches')
576 hint = _("try 'hg help' for a list of topics")
576 hint = _("try 'hg help' for a list of topics")
577 raise error.Abort(msg, hint=hint)
577 raise error.Abort(msg, hint=hint)
578 elif name and name != 'shortlist':
578 elif name and name != 'shortlist':
579 queries = []
579 queries = []
580 if unknowncmd:
580 if unknowncmd:
581 queries += [helpextcmd]
581 queries += [helpextcmd]
582 if opts.get('extension'):
582 if opts.get('extension'):
583 queries += [helpext]
583 queries += [helpext]
584 if opts.get('command'):
584 if opts.get('command'):
585 queries += [helpcmd]
585 queries += [helpcmd]
586 if not queries:
586 if not queries:
587 queries = (helptopic, helpcmd, helpext, helpextcmd)
587 queries = (helptopic, helpcmd, helpext, helpextcmd)
588 for f in queries:
588 for f in queries:
589 try:
589 try:
590 rst = f(name, subtopic)
590 rst = f(name, subtopic)
591 break
591 break
592 except error.UnknownCommand:
592 except error.UnknownCommand:
593 pass
593 pass
594 else:
594 else:
595 if unknowncmd:
595 if unknowncmd:
596 raise error.UnknownCommand(name)
596 raise error.UnknownCommand(name)
597 else:
597 else:
598 msg = _('no such help topic: %s') % name
598 msg = _('no such help topic: %s') % name
599 hint = _("try 'hg help --keyword %s'") % name
599 hint = _("try 'hg help --keyword %s'") % name
600 raise error.Abort(msg, hint=hint)
600 raise error.Abort(msg, hint=hint)
601 else:
601 else:
602 # program name
602 # program name
603 if not ui.quiet:
603 if not ui.quiet:
604 rst = [_("Mercurial Distributed SCM\n"), '\n']
604 rst = [_("Mercurial Distributed SCM\n"), '\n']
605 rst.extend(helplist(None, **opts))
605 rst.extend(helplist(None, **opts))
606
606
607 return ''.join(rst)
607 return ''.join(rst)
608
609 def formattedhelp(ui, name, keep=None, unknowncmd=False, full=True, **opts):
610 """get help for a given topic (as a dotted name) as rendered rst
611
612 Either returns the rendered help text or raises an exception.
613 """
614 if keep is None:
615 keep = []
616 fullname = name
617 section = None
618 subtopic = None
619 if name and '.' in name:
620 name, remaining = name.split('.', 1)
621 remaining = encoding.lower(remaining)
622 if '.' in remaining:
623 subtopic, section = remaining.split('.', 1)
624 else:
625 if name in subtopics:
626 subtopic = remaining
627 else:
628 section = remaining
629 textwidth = ui.configint('ui', 'textwidth', 78)
630 termwidth = ui.termwidth() - 2
631 if textwidth <= 0 or termwidth < textwidth:
632 textwidth = termwidth
633 text = help_(ui, name,
634 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
635
636 formatted, pruned = minirst.format(text, textwidth, keep=keep,
637 section=section)
638
639 # We could have been given a weird ".foo" section without a name
640 # to look for, or we could have simply failed to found "foo.bar"
641 # because bar isn't a section of foo
642 if section and not (formatted and name):
643 raise error.Abort(_("help section not found: %s") % fullname)
644
645 if 'verbose' in pruned:
646 keep.append('omitted')
647 else:
648 keep.append('notomitted')
649 formatted, pruned = minirst.format(text, textwidth, keep=keep,
650 section=section)
651 return formatted
General Comments 0
You need to be logged in to leave comments. Login now