##// END OF EJS Templates
rcutil: let rccomponents return different types of configs (API)...
Jun Wu -
r31683:00e569a2 default
parent child Browse files
Show More
@@ -1,5461 +1,5464
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 obsolete,
42 obsolete,
43 patch,
43 patch,
44 phases,
44 phases,
45 pycompat,
45 pycompat,
46 rcutil,
46 rcutil,
47 revsetlang,
47 revsetlang,
48 scmutil,
48 scmutil,
49 server,
49 server,
50 sshserver,
50 sshserver,
51 streamclone,
51 streamclone,
52 tags as tagsmod,
52 tags as tagsmod,
53 templatekw,
53 templatekw,
54 ui as uimod,
54 ui as uimod,
55 util,
55 util,
56 )
56 )
57
57
58 release = lockmod.release
58 release = lockmod.release
59
59
60 table = {}
60 table = {}
61
61
62 command = cmdutil.command(table)
62 command = cmdutil.command(table)
63
63
64 # label constants
64 # label constants
65 # until 3.5, bookmarks.current was the advertised name, not
65 # until 3.5, bookmarks.current was the advertised name, not
66 # bookmarks.active, so we must use both to avoid breaking old
66 # bookmarks.active, so we must use both to avoid breaking old
67 # custom styles
67 # custom styles
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
69
69
70 # common command options
70 # common command options
71
71
72 globalopts = [
72 globalopts = [
73 ('R', 'repository', '',
73 ('R', 'repository', '',
74 _('repository root directory or name of overlay bundle file'),
74 _('repository root directory or name of overlay bundle file'),
75 _('REPO')),
75 _('REPO')),
76 ('', 'cwd', '',
76 ('', 'cwd', '',
77 _('change working directory'), _('DIR')),
77 _('change working directory'), _('DIR')),
78 ('y', 'noninteractive', None,
78 ('y', 'noninteractive', None,
79 _('do not prompt, automatically pick the first choice for all prompts')),
79 _('do not prompt, automatically pick the first choice for all prompts')),
80 ('q', 'quiet', None, _('suppress output')),
80 ('q', 'quiet', None, _('suppress output')),
81 ('v', 'verbose', None, _('enable additional output')),
81 ('v', 'verbose', None, _('enable additional output')),
82 ('', 'color', '',
82 ('', 'color', '',
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # and should not be translated
84 # and should not be translated
85 _("when to colorize (boolean, always, auto, never, or debug)"),
85 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _('TYPE')),
86 _('TYPE')),
87 ('', 'config', [],
87 ('', 'config', [],
88 _('set/override config option (use \'section.name=value\')'),
88 _('set/override config option (use \'section.name=value\')'),
89 _('CONFIG')),
89 _('CONFIG')),
90 ('', 'debug', None, _('enable debugging output')),
90 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debugger', None, _('start debugger')),
91 ('', 'debugger', None, _('start debugger')),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 _('ENCODE')),
93 _('ENCODE')),
94 ('', 'encodingmode', encoding.encodingmode,
94 ('', 'encodingmode', encoding.encodingmode,
95 _('set the charset encoding mode'), _('MODE')),
95 _('set the charset encoding mode'), _('MODE')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'time', None, _('time how long the command takes')),
97 ('', 'time', None, _('time how long the command takes')),
98 ('', 'profile', None, _('print command execution profile')),
98 ('', 'profile', None, _('print command execution profile')),
99 ('', 'version', None, _('output version information and exit')),
99 ('', 'version', None, _('output version information and exit')),
100 ('h', 'help', None, _('display help and exit')),
100 ('h', 'help', None, _('display help and exit')),
101 ('', 'hidden', False, _('consider hidden changesets')),
101 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'pager', 'auto',
102 ('', 'pager', 'auto',
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 ]
104 ]
105
105
106 dryrunopts = [('n', 'dry-run', None,
106 dryrunopts = [('n', 'dry-run', None,
107 _('do not perform actions, just print output'))]
107 _('do not perform actions, just print output'))]
108
108
109 remoteopts = [
109 remoteopts = [
110 ('e', 'ssh', '',
110 ('e', 'ssh', '',
111 _('specify ssh command to use'), _('CMD')),
111 _('specify ssh command to use'), _('CMD')),
112 ('', 'remotecmd', '',
112 ('', 'remotecmd', '',
113 _('specify hg command to run on the remote side'), _('CMD')),
113 _('specify hg command to run on the remote side'), _('CMD')),
114 ('', 'insecure', None,
114 ('', 'insecure', None,
115 _('do not verify server certificate (ignoring web.cacerts config)')),
115 _('do not verify server certificate (ignoring web.cacerts config)')),
116 ]
116 ]
117
117
118 walkopts = [
118 walkopts = [
119 ('I', 'include', [],
119 ('I', 'include', [],
120 _('include names matching the given patterns'), _('PATTERN')),
120 _('include names matching the given patterns'), _('PATTERN')),
121 ('X', 'exclude', [],
121 ('X', 'exclude', [],
122 _('exclude names matching the given patterns'), _('PATTERN')),
122 _('exclude names matching the given patterns'), _('PATTERN')),
123 ]
123 ]
124
124
125 commitopts = [
125 commitopts = [
126 ('m', 'message', '',
126 ('m', 'message', '',
127 _('use text as commit message'), _('TEXT')),
127 _('use text as commit message'), _('TEXT')),
128 ('l', 'logfile', '',
128 ('l', 'logfile', '',
129 _('read commit message from file'), _('FILE')),
129 _('read commit message from file'), _('FILE')),
130 ]
130 ]
131
131
132 commitopts2 = [
132 commitopts2 = [
133 ('d', 'date', '',
133 ('d', 'date', '',
134 _('record the specified date as commit date'), _('DATE')),
134 _('record the specified date as commit date'), _('DATE')),
135 ('u', 'user', '',
135 ('u', 'user', '',
136 _('record the specified user as committer'), _('USER')),
136 _('record the specified user as committer'), _('USER')),
137 ]
137 ]
138
138
139 # hidden for now
139 # hidden for now
140 formatteropts = [
140 formatteropts = [
141 ('T', 'template', '',
141 ('T', 'template', '',
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
143 ]
143 ]
144
144
145 templateopts = [
145 templateopts = [
146 ('', 'style', '',
146 ('', 'style', '',
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
148 ('T', 'template', '',
148 ('T', 'template', '',
149 _('display with template'), _('TEMPLATE')),
149 _('display with template'), _('TEMPLATE')),
150 ]
150 ]
151
151
152 logopts = [
152 logopts = [
153 ('p', 'patch', None, _('show patch')),
153 ('p', 'patch', None, _('show patch')),
154 ('g', 'git', None, _('use git extended diff format')),
154 ('g', 'git', None, _('use git extended diff format')),
155 ('l', 'limit', '',
155 ('l', 'limit', '',
156 _('limit number of changes displayed'), _('NUM')),
156 _('limit number of changes displayed'), _('NUM')),
157 ('M', 'no-merges', None, _('do not show merges')),
157 ('M', 'no-merges', None, _('do not show merges')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
159 ('G', 'graph', None, _("show the revision DAG")),
159 ('G', 'graph', None, _("show the revision DAG")),
160 ] + templateopts
160 ] + templateopts
161
161
162 diffopts = [
162 diffopts = [
163 ('a', 'text', None, _('treat all files as text')),
163 ('a', 'text', None, _('treat all files as text')),
164 ('g', 'git', None, _('use git extended diff format')),
164 ('g', 'git', None, _('use git extended diff format')),
165 ('', 'nodates', None, _('omit dates from diff headers'))
165 ('', 'nodates', None, _('omit dates from diff headers'))
166 ]
166 ]
167
167
168 diffwsopts = [
168 diffwsopts = [
169 ('w', 'ignore-all-space', None,
169 ('w', 'ignore-all-space', None,
170 _('ignore white space when comparing lines')),
170 _('ignore white space when comparing lines')),
171 ('b', 'ignore-space-change', None,
171 ('b', 'ignore-space-change', None,
172 _('ignore changes in the amount of white space')),
172 _('ignore changes in the amount of white space')),
173 ('B', 'ignore-blank-lines', None,
173 ('B', 'ignore-blank-lines', None,
174 _('ignore changes whose lines are all blank')),
174 _('ignore changes whose lines are all blank')),
175 ]
175 ]
176
176
177 diffopts2 = [
177 diffopts2 = [
178 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
178 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
179 ('p', 'show-function', None, _('show which function each change is in')),
179 ('p', 'show-function', None, _('show which function each change is in')),
180 ('', 'reverse', None, _('produce a diff that undoes the changes')),
180 ('', 'reverse', None, _('produce a diff that undoes the changes')),
181 ] + diffwsopts + [
181 ] + diffwsopts + [
182 ('U', 'unified', '',
182 ('U', 'unified', '',
183 _('number of lines of context to show'), _('NUM')),
183 _('number of lines of context to show'), _('NUM')),
184 ('', 'stat', None, _('output diffstat-style summary of changes')),
184 ('', 'stat', None, _('output diffstat-style summary of changes')),
185 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
185 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
186 ]
186 ]
187
187
188 mergetoolopts = [
188 mergetoolopts = [
189 ('t', 'tool', '', _('specify merge tool')),
189 ('t', 'tool', '', _('specify merge tool')),
190 ]
190 ]
191
191
192 similarityopts = [
192 similarityopts = [
193 ('s', 'similarity', '',
193 ('s', 'similarity', '',
194 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
194 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
195 ]
195 ]
196
196
197 subrepoopts = [
197 subrepoopts = [
198 ('S', 'subrepos', None,
198 ('S', 'subrepos', None,
199 _('recurse into subrepositories'))
199 _('recurse into subrepositories'))
200 ]
200 ]
201
201
202 debugrevlogopts = [
202 debugrevlogopts = [
203 ('c', 'changelog', False, _('open changelog')),
203 ('c', 'changelog', False, _('open changelog')),
204 ('m', 'manifest', False, _('open manifest')),
204 ('m', 'manifest', False, _('open manifest')),
205 ('', 'dir', '', _('open directory manifest')),
205 ('', 'dir', '', _('open directory manifest')),
206 ]
206 ]
207
207
208 # Commands start here, listed alphabetically
208 # Commands start here, listed alphabetically
209
209
210 @command('^add',
210 @command('^add',
211 walkopts + subrepoopts + dryrunopts,
211 walkopts + subrepoopts + dryrunopts,
212 _('[OPTION]... [FILE]...'),
212 _('[OPTION]... [FILE]...'),
213 inferrepo=True)
213 inferrepo=True)
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 m = scmutil.match(repo[None], pats, opts)
257 m = scmutil.match(repo[None], pats, opts)
258 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
258 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
259 return rejected and 1 or 0
259 return rejected and 1 or 0
260
260
261 @command('addremove',
261 @command('addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _('[OPTION]... [FILE]...'),
263 _('[OPTION]... [FILE]...'),
264 inferrepo=True)
264 inferrepo=True)
265 def addremove(ui, repo, *pats, **opts):
265 def addremove(ui, repo, *pats, **opts):
266 """add all new files, delete all missing files
266 """add all new files, delete all missing files
267
267
268 Add all new files and remove all missing files from the
268 Add all new files and remove all missing files from the
269 repository.
269 repository.
270
270
271 Unless names are given, new files are ignored if they match any of
271 Unless names are given, new files are ignored if they match any of
272 the patterns in ``.hgignore``. As with add, these changes take
272 the patterns in ``.hgignore``. As with add, these changes take
273 effect at the next commit.
273 effect at the next commit.
274
274
275 Use the -s/--similarity option to detect renamed files. This
275 Use the -s/--similarity option to detect renamed files. This
276 option takes a percentage between 0 (disabled) and 100 (files must
276 option takes a percentage between 0 (disabled) and 100 (files must
277 be identical) as its parameter. With a parameter greater than 0,
277 be identical) as its parameter. With a parameter greater than 0,
278 this compares every removed file with every added file and records
278 this compares every removed file with every added file and records
279 those similar enough as renames. Detecting renamed files this way
279 those similar enough as renames. Detecting renamed files this way
280 can be expensive. After using this option, :hg:`status -C` can be
280 can be expensive. After using this option, :hg:`status -C` can be
281 used to check which files were identified as moved or renamed. If
281 used to check which files were identified as moved or renamed. If
282 not specified, -s/--similarity defaults to 100 and only renames of
282 not specified, -s/--similarity defaults to 100 and only renames of
283 identical files are detected.
283 identical files are detected.
284
284
285 .. container:: verbose
285 .. container:: verbose
286
286
287 Examples:
287 Examples:
288
288
289 - A number of files (bar.c and foo.c) are new,
289 - A number of files (bar.c and foo.c) are new,
290 while foobar.c has been removed (without using :hg:`remove`)
290 while foobar.c has been removed (without using :hg:`remove`)
291 from the repository::
291 from the repository::
292
292
293 $ ls
293 $ ls
294 bar.c foo.c
294 bar.c foo.c
295 $ hg status
295 $ hg status
296 ! foobar.c
296 ! foobar.c
297 ? bar.c
297 ? bar.c
298 ? foo.c
298 ? foo.c
299 $ hg addremove
299 $ hg addremove
300 adding bar.c
300 adding bar.c
301 adding foo.c
301 adding foo.c
302 removing foobar.c
302 removing foobar.c
303 $ hg status
303 $ hg status
304 A bar.c
304 A bar.c
305 A foo.c
305 A foo.c
306 R foobar.c
306 R foobar.c
307
307
308 - A file foobar.c was moved to foo.c without using :hg:`rename`.
308 - A file foobar.c was moved to foo.c without using :hg:`rename`.
309 Afterwards, it was edited slightly::
309 Afterwards, it was edited slightly::
310
310
311 $ ls
311 $ ls
312 foo.c
312 foo.c
313 $ hg status
313 $ hg status
314 ! foobar.c
314 ! foobar.c
315 ? foo.c
315 ? foo.c
316 $ hg addremove --similarity 90
316 $ hg addremove --similarity 90
317 removing foobar.c
317 removing foobar.c
318 adding foo.c
318 adding foo.c
319 recording removal of foobar.c as rename to foo.c (94% similar)
319 recording removal of foobar.c as rename to foo.c (94% similar)
320 $ hg status -C
320 $ hg status -C
321 A foo.c
321 A foo.c
322 foobar.c
322 foobar.c
323 R foobar.c
323 R foobar.c
324
324
325 Returns 0 if all files are successfully added.
325 Returns 0 if all files are successfully added.
326 """
326 """
327 try:
327 try:
328 sim = float(opts.get('similarity') or 100)
328 sim = float(opts.get('similarity') or 100)
329 except ValueError:
329 except ValueError:
330 raise error.Abort(_('similarity must be a number'))
330 raise error.Abort(_('similarity must be a number'))
331 if sim < 0 or sim > 100:
331 if sim < 0 or sim > 100:
332 raise error.Abort(_('similarity must be between 0 and 100'))
332 raise error.Abort(_('similarity must be between 0 and 100'))
333 matcher = scmutil.match(repo[None], pats, opts)
333 matcher = scmutil.match(repo[None], pats, opts)
334 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
334 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
335
335
336 @command('^annotate|blame',
336 @command('^annotate|blame',
337 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
337 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
338 ('', 'follow', None,
338 ('', 'follow', None,
339 _('follow copies/renames and list the filename (DEPRECATED)')),
339 _('follow copies/renames and list the filename (DEPRECATED)')),
340 ('', 'no-follow', None, _("don't follow copies and renames")),
340 ('', 'no-follow', None, _("don't follow copies and renames")),
341 ('a', 'text', None, _('treat all files as text')),
341 ('a', 'text', None, _('treat all files as text')),
342 ('u', 'user', None, _('list the author (long with -v)')),
342 ('u', 'user', None, _('list the author (long with -v)')),
343 ('f', 'file', None, _('list the filename')),
343 ('f', 'file', None, _('list the filename')),
344 ('d', 'date', None, _('list the date (short with -q)')),
344 ('d', 'date', None, _('list the date (short with -q)')),
345 ('n', 'number', None, _('list the revision number (default)')),
345 ('n', 'number', None, _('list the revision number (default)')),
346 ('c', 'changeset', None, _('list the changeset')),
346 ('c', 'changeset', None, _('list the changeset')),
347 ('l', 'line-number', None, _('show line number at the first appearance'))
347 ('l', 'line-number', None, _('show line number at the first appearance'))
348 ] + diffwsopts + walkopts + formatteropts,
348 ] + diffwsopts + walkopts + formatteropts,
349 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
349 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
350 inferrepo=True)
350 inferrepo=True)
351 def annotate(ui, repo, *pats, **opts):
351 def annotate(ui, repo, *pats, **opts):
352 """show changeset information by line for each file
352 """show changeset information by line for each file
353
353
354 List changes in files, showing the revision id responsible for
354 List changes in files, showing the revision id responsible for
355 each line.
355 each line.
356
356
357 This command is useful for discovering when a change was made and
357 This command is useful for discovering when a change was made and
358 by whom.
358 by whom.
359
359
360 If you include --file, --user, or --date, the revision number is
360 If you include --file, --user, or --date, the revision number is
361 suppressed unless you also include --number.
361 suppressed unless you also include --number.
362
362
363 Without the -a/--text option, annotate will avoid processing files
363 Without the -a/--text option, annotate will avoid processing files
364 it detects as binary. With -a, annotate will annotate the file
364 it detects as binary. With -a, annotate will annotate the file
365 anyway, although the results will probably be neither useful
365 anyway, although the results will probably be neither useful
366 nor desirable.
366 nor desirable.
367
367
368 Returns 0 on success.
368 Returns 0 on success.
369 """
369 """
370 if not pats:
370 if not pats:
371 raise error.Abort(_('at least one filename or pattern is required'))
371 raise error.Abort(_('at least one filename or pattern is required'))
372
372
373 if opts.get('follow'):
373 if opts.get('follow'):
374 # --follow is deprecated and now just an alias for -f/--file
374 # --follow is deprecated and now just an alias for -f/--file
375 # to mimic the behavior of Mercurial before version 1.5
375 # to mimic the behavior of Mercurial before version 1.5
376 opts['file'] = True
376 opts['file'] = True
377
377
378 ctx = scmutil.revsingle(repo, opts.get('rev'))
378 ctx = scmutil.revsingle(repo, opts.get('rev'))
379
379
380 fm = ui.formatter('annotate', opts)
380 fm = ui.formatter('annotate', opts)
381 if ui.quiet:
381 if ui.quiet:
382 datefunc = util.shortdate
382 datefunc = util.shortdate
383 else:
383 else:
384 datefunc = util.datestr
384 datefunc = util.datestr
385 if ctx.rev() is None:
385 if ctx.rev() is None:
386 def hexfn(node):
386 def hexfn(node):
387 if node is None:
387 if node is None:
388 return None
388 return None
389 else:
389 else:
390 return fm.hexfunc(node)
390 return fm.hexfunc(node)
391 if opts.get('changeset'):
391 if opts.get('changeset'):
392 # omit "+" suffix which is appended to node hex
392 # omit "+" suffix which is appended to node hex
393 def formatrev(rev):
393 def formatrev(rev):
394 if rev is None:
394 if rev is None:
395 return '%d' % ctx.p1().rev()
395 return '%d' % ctx.p1().rev()
396 else:
396 else:
397 return '%d' % rev
397 return '%d' % rev
398 else:
398 else:
399 def formatrev(rev):
399 def formatrev(rev):
400 if rev is None:
400 if rev is None:
401 return '%d+' % ctx.p1().rev()
401 return '%d+' % ctx.p1().rev()
402 else:
402 else:
403 return '%d ' % rev
403 return '%d ' % rev
404 def formathex(hex):
404 def formathex(hex):
405 if hex is None:
405 if hex is None:
406 return '%s+' % fm.hexfunc(ctx.p1().node())
406 return '%s+' % fm.hexfunc(ctx.p1().node())
407 else:
407 else:
408 return '%s ' % hex
408 return '%s ' % hex
409 else:
409 else:
410 hexfn = fm.hexfunc
410 hexfn = fm.hexfunc
411 formatrev = formathex = str
411 formatrev = formathex = str
412
412
413 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
413 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
414 ('number', ' ', lambda x: x[0].rev(), formatrev),
414 ('number', ' ', lambda x: x[0].rev(), formatrev),
415 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
415 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
416 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
416 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
417 ('file', ' ', lambda x: x[0].path(), str),
417 ('file', ' ', lambda x: x[0].path(), str),
418 ('line_number', ':', lambda x: x[1], str),
418 ('line_number', ':', lambda x: x[1], str),
419 ]
419 ]
420 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
420 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
421
421
422 if (not opts.get('user') and not opts.get('changeset')
422 if (not opts.get('user') and not opts.get('changeset')
423 and not opts.get('date') and not opts.get('file')):
423 and not opts.get('date') and not opts.get('file')):
424 opts['number'] = True
424 opts['number'] = True
425
425
426 linenumber = opts.get('line_number') is not None
426 linenumber = opts.get('line_number') is not None
427 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
427 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
428 raise error.Abort(_('at least one of -n/-c is required for -l'))
428 raise error.Abort(_('at least one of -n/-c is required for -l'))
429
429
430 ui.pager('annotate')
430 ui.pager('annotate')
431
431
432 if fm.isplain():
432 if fm.isplain():
433 def makefunc(get, fmt):
433 def makefunc(get, fmt):
434 return lambda x: fmt(get(x))
434 return lambda x: fmt(get(x))
435 else:
435 else:
436 def makefunc(get, fmt):
436 def makefunc(get, fmt):
437 return get
437 return get
438 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
438 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
439 if opts.get(op)]
439 if opts.get(op)]
440 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
440 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
441 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
441 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
442 if opts.get(op))
442 if opts.get(op))
443
443
444 def bad(x, y):
444 def bad(x, y):
445 raise error.Abort("%s: %s" % (x, y))
445 raise error.Abort("%s: %s" % (x, y))
446
446
447 m = scmutil.match(ctx, pats, opts, badfn=bad)
447 m = scmutil.match(ctx, pats, opts, badfn=bad)
448
448
449 follow = not opts.get('no_follow')
449 follow = not opts.get('no_follow')
450 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
450 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
451 whitespace=True)
451 whitespace=True)
452 for abs in ctx.walk(m):
452 for abs in ctx.walk(m):
453 fctx = ctx[abs]
453 fctx = ctx[abs]
454 if not opts.get('text') and util.binary(fctx.data()):
454 if not opts.get('text') and util.binary(fctx.data()):
455 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
455 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
456 continue
456 continue
457
457
458 lines = fctx.annotate(follow=follow, linenumber=linenumber,
458 lines = fctx.annotate(follow=follow, linenumber=linenumber,
459 diffopts=diffopts)
459 diffopts=diffopts)
460 if not lines:
460 if not lines:
461 continue
461 continue
462 formats = []
462 formats = []
463 pieces = []
463 pieces = []
464
464
465 for f, sep in funcmap:
465 for f, sep in funcmap:
466 l = [f(n) for n, dummy in lines]
466 l = [f(n) for n, dummy in lines]
467 if fm.isplain():
467 if fm.isplain():
468 sizes = [encoding.colwidth(x) for x in l]
468 sizes = [encoding.colwidth(x) for x in l]
469 ml = max(sizes)
469 ml = max(sizes)
470 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
470 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
471 else:
471 else:
472 formats.append(['%s' for x in l])
472 formats.append(['%s' for x in l])
473 pieces.append(l)
473 pieces.append(l)
474
474
475 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
475 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
476 fm.startitem()
476 fm.startitem()
477 fm.write(fields, "".join(f), *p)
477 fm.write(fields, "".join(f), *p)
478 fm.write('line', ": %s", l[1])
478 fm.write('line', ": %s", l[1])
479
479
480 if not lines[-1][1].endswith('\n'):
480 if not lines[-1][1].endswith('\n'):
481 fm.plain('\n')
481 fm.plain('\n')
482
482
483 fm.end()
483 fm.end()
484
484
485 @command('archive',
485 @command('archive',
486 [('', 'no-decode', None, _('do not pass files through decoders')),
486 [('', 'no-decode', None, _('do not pass files through decoders')),
487 ('p', 'prefix', '', _('directory prefix for files in archive'),
487 ('p', 'prefix', '', _('directory prefix for files in archive'),
488 _('PREFIX')),
488 _('PREFIX')),
489 ('r', 'rev', '', _('revision to distribute'), _('REV')),
489 ('r', 'rev', '', _('revision to distribute'), _('REV')),
490 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
490 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
491 ] + subrepoopts + walkopts,
491 ] + subrepoopts + walkopts,
492 _('[OPTION]... DEST'))
492 _('[OPTION]... DEST'))
493 def archive(ui, repo, dest, **opts):
493 def archive(ui, repo, dest, **opts):
494 '''create an unversioned archive of a repository revision
494 '''create an unversioned archive of a repository revision
495
495
496 By default, the revision used is the parent of the working
496 By default, the revision used is the parent of the working
497 directory; use -r/--rev to specify a different revision.
497 directory; use -r/--rev to specify a different revision.
498
498
499 The archive type is automatically detected based on file
499 The archive type is automatically detected based on file
500 extension (to override, use -t/--type).
500 extension (to override, use -t/--type).
501
501
502 .. container:: verbose
502 .. container:: verbose
503
503
504 Examples:
504 Examples:
505
505
506 - create a zip file containing the 1.0 release::
506 - create a zip file containing the 1.0 release::
507
507
508 hg archive -r 1.0 project-1.0.zip
508 hg archive -r 1.0 project-1.0.zip
509
509
510 - create a tarball excluding .hg files::
510 - create a tarball excluding .hg files::
511
511
512 hg archive project.tar.gz -X ".hg*"
512 hg archive project.tar.gz -X ".hg*"
513
513
514 Valid types are:
514 Valid types are:
515
515
516 :``files``: a directory full of files (default)
516 :``files``: a directory full of files (default)
517 :``tar``: tar archive, uncompressed
517 :``tar``: tar archive, uncompressed
518 :``tbz2``: tar archive, compressed using bzip2
518 :``tbz2``: tar archive, compressed using bzip2
519 :``tgz``: tar archive, compressed using gzip
519 :``tgz``: tar archive, compressed using gzip
520 :``uzip``: zip archive, uncompressed
520 :``uzip``: zip archive, uncompressed
521 :``zip``: zip archive, compressed using deflate
521 :``zip``: zip archive, compressed using deflate
522
522
523 The exact name of the destination archive or directory is given
523 The exact name of the destination archive or directory is given
524 using a format string; see :hg:`help export` for details.
524 using a format string; see :hg:`help export` for details.
525
525
526 Each member added to an archive file has a directory prefix
526 Each member added to an archive file has a directory prefix
527 prepended. Use -p/--prefix to specify a format string for the
527 prepended. Use -p/--prefix to specify a format string for the
528 prefix. The default is the basename of the archive, with suffixes
528 prefix. The default is the basename of the archive, with suffixes
529 removed.
529 removed.
530
530
531 Returns 0 on success.
531 Returns 0 on success.
532 '''
532 '''
533
533
534 ctx = scmutil.revsingle(repo, opts.get('rev'))
534 ctx = scmutil.revsingle(repo, opts.get('rev'))
535 if not ctx:
535 if not ctx:
536 raise error.Abort(_('no working directory: please specify a revision'))
536 raise error.Abort(_('no working directory: please specify a revision'))
537 node = ctx.node()
537 node = ctx.node()
538 dest = cmdutil.makefilename(repo, dest, node)
538 dest = cmdutil.makefilename(repo, dest, node)
539 if os.path.realpath(dest) == repo.root:
539 if os.path.realpath(dest) == repo.root:
540 raise error.Abort(_('repository root cannot be destination'))
540 raise error.Abort(_('repository root cannot be destination'))
541
541
542 kind = opts.get('type') or archival.guesskind(dest) or 'files'
542 kind = opts.get('type') or archival.guesskind(dest) or 'files'
543 prefix = opts.get('prefix')
543 prefix = opts.get('prefix')
544
544
545 if dest == '-':
545 if dest == '-':
546 if kind == 'files':
546 if kind == 'files':
547 raise error.Abort(_('cannot archive plain files to stdout'))
547 raise error.Abort(_('cannot archive plain files to stdout'))
548 dest = cmdutil.makefileobj(repo, dest)
548 dest = cmdutil.makefileobj(repo, dest)
549 if not prefix:
549 if not prefix:
550 prefix = os.path.basename(repo.root) + '-%h'
550 prefix = os.path.basename(repo.root) + '-%h'
551
551
552 prefix = cmdutil.makefilename(repo, prefix, node)
552 prefix = cmdutil.makefilename(repo, prefix, node)
553 matchfn = scmutil.match(ctx, [], opts)
553 matchfn = scmutil.match(ctx, [], opts)
554 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
554 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
555 matchfn, prefix, subrepos=opts.get('subrepos'))
555 matchfn, prefix, subrepos=opts.get('subrepos'))
556
556
557 @command('backout',
557 @command('backout',
558 [('', 'merge', None, _('merge with old dirstate parent after backout')),
558 [('', 'merge', None, _('merge with old dirstate parent after backout')),
559 ('', 'commit', None,
559 ('', 'commit', None,
560 _('commit if no conflicts were encountered (DEPRECATED)')),
560 _('commit if no conflicts were encountered (DEPRECATED)')),
561 ('', 'no-commit', None, _('do not commit')),
561 ('', 'no-commit', None, _('do not commit')),
562 ('', 'parent', '',
562 ('', 'parent', '',
563 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
563 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
564 ('r', 'rev', '', _('revision to backout'), _('REV')),
564 ('r', 'rev', '', _('revision to backout'), _('REV')),
565 ('e', 'edit', False, _('invoke editor on commit messages')),
565 ('e', 'edit', False, _('invoke editor on commit messages')),
566 ] + mergetoolopts + walkopts + commitopts + commitopts2,
566 ] + mergetoolopts + walkopts + commitopts + commitopts2,
567 _('[OPTION]... [-r] REV'))
567 _('[OPTION]... [-r] REV'))
568 def backout(ui, repo, node=None, rev=None, **opts):
568 def backout(ui, repo, node=None, rev=None, **opts):
569 '''reverse effect of earlier changeset
569 '''reverse effect of earlier changeset
570
570
571 Prepare a new changeset with the effect of REV undone in the
571 Prepare a new changeset with the effect of REV undone in the
572 current working directory. If no conflicts were encountered,
572 current working directory. If no conflicts were encountered,
573 it will be committed immediately.
573 it will be committed immediately.
574
574
575 If REV is the parent of the working directory, then this new changeset
575 If REV is the parent of the working directory, then this new changeset
576 is committed automatically (unless --no-commit is specified).
576 is committed automatically (unless --no-commit is specified).
577
577
578 .. note::
578 .. note::
579
579
580 :hg:`backout` cannot be used to fix either an unwanted or
580 :hg:`backout` cannot be used to fix either an unwanted or
581 incorrect merge.
581 incorrect merge.
582
582
583 .. container:: verbose
583 .. container:: verbose
584
584
585 Examples:
585 Examples:
586
586
587 - Reverse the effect of the parent of the working directory.
587 - Reverse the effect of the parent of the working directory.
588 This backout will be committed immediately::
588 This backout will be committed immediately::
589
589
590 hg backout -r .
590 hg backout -r .
591
591
592 - Reverse the effect of previous bad revision 23::
592 - Reverse the effect of previous bad revision 23::
593
593
594 hg backout -r 23
594 hg backout -r 23
595
595
596 - Reverse the effect of previous bad revision 23 and
596 - Reverse the effect of previous bad revision 23 and
597 leave changes uncommitted::
597 leave changes uncommitted::
598
598
599 hg backout -r 23 --no-commit
599 hg backout -r 23 --no-commit
600 hg commit -m "Backout revision 23"
600 hg commit -m "Backout revision 23"
601
601
602 By default, the pending changeset will have one parent,
602 By default, the pending changeset will have one parent,
603 maintaining a linear history. With --merge, the pending
603 maintaining a linear history. With --merge, the pending
604 changeset will instead have two parents: the old parent of the
604 changeset will instead have two parents: the old parent of the
605 working directory and a new child of REV that simply undoes REV.
605 working directory and a new child of REV that simply undoes REV.
606
606
607 Before version 1.7, the behavior without --merge was equivalent
607 Before version 1.7, the behavior without --merge was equivalent
608 to specifying --merge followed by :hg:`update --clean .` to
608 to specifying --merge followed by :hg:`update --clean .` to
609 cancel the merge and leave the child of REV as a head to be
609 cancel the merge and leave the child of REV as a head to be
610 merged separately.
610 merged separately.
611
611
612 See :hg:`help dates` for a list of formats valid for -d/--date.
612 See :hg:`help dates` for a list of formats valid for -d/--date.
613
613
614 See :hg:`help revert` for a way to restore files to the state
614 See :hg:`help revert` for a way to restore files to the state
615 of another revision.
615 of another revision.
616
616
617 Returns 0 on success, 1 if nothing to backout or there are unresolved
617 Returns 0 on success, 1 if nothing to backout or there are unresolved
618 files.
618 files.
619 '''
619 '''
620 wlock = lock = None
620 wlock = lock = None
621 try:
621 try:
622 wlock = repo.wlock()
622 wlock = repo.wlock()
623 lock = repo.lock()
623 lock = repo.lock()
624 return _dobackout(ui, repo, node, rev, **opts)
624 return _dobackout(ui, repo, node, rev, **opts)
625 finally:
625 finally:
626 release(lock, wlock)
626 release(lock, wlock)
627
627
628 def _dobackout(ui, repo, node=None, rev=None, **opts):
628 def _dobackout(ui, repo, node=None, rev=None, **opts):
629 if opts.get('commit') and opts.get('no_commit'):
629 if opts.get('commit') and opts.get('no_commit'):
630 raise error.Abort(_("cannot use --commit with --no-commit"))
630 raise error.Abort(_("cannot use --commit with --no-commit"))
631 if opts.get('merge') and opts.get('no_commit'):
631 if opts.get('merge') and opts.get('no_commit'):
632 raise error.Abort(_("cannot use --merge with --no-commit"))
632 raise error.Abort(_("cannot use --merge with --no-commit"))
633
633
634 if rev and node:
634 if rev and node:
635 raise error.Abort(_("please specify just one revision"))
635 raise error.Abort(_("please specify just one revision"))
636
636
637 if not rev:
637 if not rev:
638 rev = node
638 rev = node
639
639
640 if not rev:
640 if not rev:
641 raise error.Abort(_("please specify a revision to backout"))
641 raise error.Abort(_("please specify a revision to backout"))
642
642
643 date = opts.get('date')
643 date = opts.get('date')
644 if date:
644 if date:
645 opts['date'] = util.parsedate(date)
645 opts['date'] = util.parsedate(date)
646
646
647 cmdutil.checkunfinished(repo)
647 cmdutil.checkunfinished(repo)
648 cmdutil.bailifchanged(repo)
648 cmdutil.bailifchanged(repo)
649 node = scmutil.revsingle(repo, rev).node()
649 node = scmutil.revsingle(repo, rev).node()
650
650
651 op1, op2 = repo.dirstate.parents()
651 op1, op2 = repo.dirstate.parents()
652 if not repo.changelog.isancestor(node, op1):
652 if not repo.changelog.isancestor(node, op1):
653 raise error.Abort(_('cannot backout change that is not an ancestor'))
653 raise error.Abort(_('cannot backout change that is not an ancestor'))
654
654
655 p1, p2 = repo.changelog.parents(node)
655 p1, p2 = repo.changelog.parents(node)
656 if p1 == nullid:
656 if p1 == nullid:
657 raise error.Abort(_('cannot backout a change with no parents'))
657 raise error.Abort(_('cannot backout a change with no parents'))
658 if p2 != nullid:
658 if p2 != nullid:
659 if not opts.get('parent'):
659 if not opts.get('parent'):
660 raise error.Abort(_('cannot backout a merge changeset'))
660 raise error.Abort(_('cannot backout a merge changeset'))
661 p = repo.lookup(opts['parent'])
661 p = repo.lookup(opts['parent'])
662 if p not in (p1, p2):
662 if p not in (p1, p2):
663 raise error.Abort(_('%s is not a parent of %s') %
663 raise error.Abort(_('%s is not a parent of %s') %
664 (short(p), short(node)))
664 (short(p), short(node)))
665 parent = p
665 parent = p
666 else:
666 else:
667 if opts.get('parent'):
667 if opts.get('parent'):
668 raise error.Abort(_('cannot use --parent on non-merge changeset'))
668 raise error.Abort(_('cannot use --parent on non-merge changeset'))
669 parent = p1
669 parent = p1
670
670
671 # the backout should appear on the same branch
671 # the backout should appear on the same branch
672 branch = repo.dirstate.branch()
672 branch = repo.dirstate.branch()
673 bheads = repo.branchheads(branch)
673 bheads = repo.branchheads(branch)
674 rctx = scmutil.revsingle(repo, hex(parent))
674 rctx = scmutil.revsingle(repo, hex(parent))
675 if not opts.get('merge') and op1 != node:
675 if not opts.get('merge') and op1 != node:
676 dsguard = dirstateguard.dirstateguard(repo, 'backout')
676 dsguard = dirstateguard.dirstateguard(repo, 'backout')
677 try:
677 try:
678 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
678 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
679 'backout')
679 'backout')
680 stats = mergemod.update(repo, parent, True, True, node, False)
680 stats = mergemod.update(repo, parent, True, True, node, False)
681 repo.setparents(op1, op2)
681 repo.setparents(op1, op2)
682 dsguard.close()
682 dsguard.close()
683 hg._showstats(repo, stats)
683 hg._showstats(repo, stats)
684 if stats[3]:
684 if stats[3]:
685 repo.ui.status(_("use 'hg resolve' to retry unresolved "
685 repo.ui.status(_("use 'hg resolve' to retry unresolved "
686 "file merges\n"))
686 "file merges\n"))
687 return 1
687 return 1
688 finally:
688 finally:
689 ui.setconfig('ui', 'forcemerge', '', '')
689 ui.setconfig('ui', 'forcemerge', '', '')
690 lockmod.release(dsguard)
690 lockmod.release(dsguard)
691 else:
691 else:
692 hg.clean(repo, node, show_stats=False)
692 hg.clean(repo, node, show_stats=False)
693 repo.dirstate.setbranch(branch)
693 repo.dirstate.setbranch(branch)
694 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
694 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
695
695
696 if opts.get('no_commit'):
696 if opts.get('no_commit'):
697 msg = _("changeset %s backed out, "
697 msg = _("changeset %s backed out, "
698 "don't forget to commit.\n")
698 "don't forget to commit.\n")
699 ui.status(msg % short(node))
699 ui.status(msg % short(node))
700 return 0
700 return 0
701
701
702 def commitfunc(ui, repo, message, match, opts):
702 def commitfunc(ui, repo, message, match, opts):
703 editform = 'backout'
703 editform = 'backout'
704 e = cmdutil.getcommiteditor(editform=editform, **opts)
704 e = cmdutil.getcommiteditor(editform=editform, **opts)
705 if not message:
705 if not message:
706 # we don't translate commit messages
706 # we don't translate commit messages
707 message = "Backed out changeset %s" % short(node)
707 message = "Backed out changeset %s" % short(node)
708 e = cmdutil.getcommiteditor(edit=True, editform=editform)
708 e = cmdutil.getcommiteditor(edit=True, editform=editform)
709 return repo.commit(message, opts.get('user'), opts.get('date'),
709 return repo.commit(message, opts.get('user'), opts.get('date'),
710 match, editor=e)
710 match, editor=e)
711 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
711 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
712 if not newnode:
712 if not newnode:
713 ui.status(_("nothing changed\n"))
713 ui.status(_("nothing changed\n"))
714 return 1
714 return 1
715 cmdutil.commitstatus(repo, newnode, branch, bheads)
715 cmdutil.commitstatus(repo, newnode, branch, bheads)
716
716
717 def nice(node):
717 def nice(node):
718 return '%d:%s' % (repo.changelog.rev(node), short(node))
718 return '%d:%s' % (repo.changelog.rev(node), short(node))
719 ui.status(_('changeset %s backs out changeset %s\n') %
719 ui.status(_('changeset %s backs out changeset %s\n') %
720 (nice(repo.changelog.tip()), nice(node)))
720 (nice(repo.changelog.tip()), nice(node)))
721 if opts.get('merge') and op1 != node:
721 if opts.get('merge') and op1 != node:
722 hg.clean(repo, op1, show_stats=False)
722 hg.clean(repo, op1, show_stats=False)
723 ui.status(_('merging with changeset %s\n')
723 ui.status(_('merging with changeset %s\n')
724 % nice(repo.changelog.tip()))
724 % nice(repo.changelog.tip()))
725 try:
725 try:
726 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
726 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
727 'backout')
727 'backout')
728 return hg.merge(repo, hex(repo.changelog.tip()))
728 return hg.merge(repo, hex(repo.changelog.tip()))
729 finally:
729 finally:
730 ui.setconfig('ui', 'forcemerge', '', '')
730 ui.setconfig('ui', 'forcemerge', '', '')
731 return 0
731 return 0
732
732
733 @command('bisect',
733 @command('bisect',
734 [('r', 'reset', False, _('reset bisect state')),
734 [('r', 'reset', False, _('reset bisect state')),
735 ('g', 'good', False, _('mark changeset good')),
735 ('g', 'good', False, _('mark changeset good')),
736 ('b', 'bad', False, _('mark changeset bad')),
736 ('b', 'bad', False, _('mark changeset bad')),
737 ('s', 'skip', False, _('skip testing changeset')),
737 ('s', 'skip', False, _('skip testing changeset')),
738 ('e', 'extend', False, _('extend the bisect range')),
738 ('e', 'extend', False, _('extend the bisect range')),
739 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
739 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
740 ('U', 'noupdate', False, _('do not update to target'))],
740 ('U', 'noupdate', False, _('do not update to target'))],
741 _("[-gbsr] [-U] [-c CMD] [REV]"))
741 _("[-gbsr] [-U] [-c CMD] [REV]"))
742 def bisect(ui, repo, rev=None, extra=None, command=None,
742 def bisect(ui, repo, rev=None, extra=None, command=None,
743 reset=None, good=None, bad=None, skip=None, extend=None,
743 reset=None, good=None, bad=None, skip=None, extend=None,
744 noupdate=None):
744 noupdate=None):
745 """subdivision search of changesets
745 """subdivision search of changesets
746
746
747 This command helps to find changesets which introduce problems. To
747 This command helps to find changesets which introduce problems. To
748 use, mark the earliest changeset you know exhibits the problem as
748 use, mark the earliest changeset you know exhibits the problem as
749 bad, then mark the latest changeset which is free from the problem
749 bad, then mark the latest changeset which is free from the problem
750 as good. Bisect will update your working directory to a revision
750 as good. Bisect will update your working directory to a revision
751 for testing (unless the -U/--noupdate option is specified). Once
751 for testing (unless the -U/--noupdate option is specified). Once
752 you have performed tests, mark the working directory as good or
752 you have performed tests, mark the working directory as good or
753 bad, and bisect will either update to another candidate changeset
753 bad, and bisect will either update to another candidate changeset
754 or announce that it has found the bad revision.
754 or announce that it has found the bad revision.
755
755
756 As a shortcut, you can also use the revision argument to mark a
756 As a shortcut, you can also use the revision argument to mark a
757 revision as good or bad without checking it out first.
757 revision as good or bad without checking it out first.
758
758
759 If you supply a command, it will be used for automatic bisection.
759 If you supply a command, it will be used for automatic bisection.
760 The environment variable HG_NODE will contain the ID of the
760 The environment variable HG_NODE will contain the ID of the
761 changeset being tested. The exit status of the command will be
761 changeset being tested. The exit status of the command will be
762 used to mark revisions as good or bad: status 0 means good, 125
762 used to mark revisions as good or bad: status 0 means good, 125
763 means to skip the revision, 127 (command not found) will abort the
763 means to skip the revision, 127 (command not found) will abort the
764 bisection, and any other non-zero exit status means the revision
764 bisection, and any other non-zero exit status means the revision
765 is bad.
765 is bad.
766
766
767 .. container:: verbose
767 .. container:: verbose
768
768
769 Some examples:
769 Some examples:
770
770
771 - start a bisection with known bad revision 34, and good revision 12::
771 - start a bisection with known bad revision 34, and good revision 12::
772
772
773 hg bisect --bad 34
773 hg bisect --bad 34
774 hg bisect --good 12
774 hg bisect --good 12
775
775
776 - advance the current bisection by marking current revision as good or
776 - advance the current bisection by marking current revision as good or
777 bad::
777 bad::
778
778
779 hg bisect --good
779 hg bisect --good
780 hg bisect --bad
780 hg bisect --bad
781
781
782 - mark the current revision, or a known revision, to be skipped (e.g. if
782 - mark the current revision, or a known revision, to be skipped (e.g. if
783 that revision is not usable because of another issue)::
783 that revision is not usable because of another issue)::
784
784
785 hg bisect --skip
785 hg bisect --skip
786 hg bisect --skip 23
786 hg bisect --skip 23
787
787
788 - skip all revisions that do not touch directories ``foo`` or ``bar``::
788 - skip all revisions that do not touch directories ``foo`` or ``bar``::
789
789
790 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
790 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
791
791
792 - forget the current bisection::
792 - forget the current bisection::
793
793
794 hg bisect --reset
794 hg bisect --reset
795
795
796 - use 'make && make tests' to automatically find the first broken
796 - use 'make && make tests' to automatically find the first broken
797 revision::
797 revision::
798
798
799 hg bisect --reset
799 hg bisect --reset
800 hg bisect --bad 34
800 hg bisect --bad 34
801 hg bisect --good 12
801 hg bisect --good 12
802 hg bisect --command "make && make tests"
802 hg bisect --command "make && make tests"
803
803
804 - see all changesets whose states are already known in the current
804 - see all changesets whose states are already known in the current
805 bisection::
805 bisection::
806
806
807 hg log -r "bisect(pruned)"
807 hg log -r "bisect(pruned)"
808
808
809 - see the changeset currently being bisected (especially useful
809 - see the changeset currently being bisected (especially useful
810 if running with -U/--noupdate)::
810 if running with -U/--noupdate)::
811
811
812 hg log -r "bisect(current)"
812 hg log -r "bisect(current)"
813
813
814 - see all changesets that took part in the current bisection::
814 - see all changesets that took part in the current bisection::
815
815
816 hg log -r "bisect(range)"
816 hg log -r "bisect(range)"
817
817
818 - you can even get a nice graph::
818 - you can even get a nice graph::
819
819
820 hg log --graph -r "bisect(range)"
820 hg log --graph -r "bisect(range)"
821
821
822 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
822 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
823
823
824 Returns 0 on success.
824 Returns 0 on success.
825 """
825 """
826 # backward compatibility
826 # backward compatibility
827 if rev in "good bad reset init".split():
827 if rev in "good bad reset init".split():
828 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
828 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
829 cmd, rev, extra = rev, extra, None
829 cmd, rev, extra = rev, extra, None
830 if cmd == "good":
830 if cmd == "good":
831 good = True
831 good = True
832 elif cmd == "bad":
832 elif cmd == "bad":
833 bad = True
833 bad = True
834 else:
834 else:
835 reset = True
835 reset = True
836 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
836 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
837 raise error.Abort(_('incompatible arguments'))
837 raise error.Abort(_('incompatible arguments'))
838
838
839 cmdutil.checkunfinished(repo)
839 cmdutil.checkunfinished(repo)
840
840
841 if reset:
841 if reset:
842 hbisect.resetstate(repo)
842 hbisect.resetstate(repo)
843 return
843 return
844
844
845 state = hbisect.load_state(repo)
845 state = hbisect.load_state(repo)
846
846
847 # update state
847 # update state
848 if good or bad or skip:
848 if good or bad or skip:
849 if rev:
849 if rev:
850 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
850 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
851 else:
851 else:
852 nodes = [repo.lookup('.')]
852 nodes = [repo.lookup('.')]
853 if good:
853 if good:
854 state['good'] += nodes
854 state['good'] += nodes
855 elif bad:
855 elif bad:
856 state['bad'] += nodes
856 state['bad'] += nodes
857 elif skip:
857 elif skip:
858 state['skip'] += nodes
858 state['skip'] += nodes
859 hbisect.save_state(repo, state)
859 hbisect.save_state(repo, state)
860 if not (state['good'] and state['bad']):
860 if not (state['good'] and state['bad']):
861 return
861 return
862
862
863 def mayupdate(repo, node, show_stats=True):
863 def mayupdate(repo, node, show_stats=True):
864 """common used update sequence"""
864 """common used update sequence"""
865 if noupdate:
865 if noupdate:
866 return
866 return
867 cmdutil.bailifchanged(repo)
867 cmdutil.bailifchanged(repo)
868 return hg.clean(repo, node, show_stats=show_stats)
868 return hg.clean(repo, node, show_stats=show_stats)
869
869
870 displayer = cmdutil.show_changeset(ui, repo, {})
870 displayer = cmdutil.show_changeset(ui, repo, {})
871
871
872 if command:
872 if command:
873 changesets = 1
873 changesets = 1
874 if noupdate:
874 if noupdate:
875 try:
875 try:
876 node = state['current'][0]
876 node = state['current'][0]
877 except LookupError:
877 except LookupError:
878 raise error.Abort(_('current bisect revision is unknown - '
878 raise error.Abort(_('current bisect revision is unknown - '
879 'start a new bisect to fix'))
879 'start a new bisect to fix'))
880 else:
880 else:
881 node, p2 = repo.dirstate.parents()
881 node, p2 = repo.dirstate.parents()
882 if p2 != nullid:
882 if p2 != nullid:
883 raise error.Abort(_('current bisect revision is a merge'))
883 raise error.Abort(_('current bisect revision is a merge'))
884 if rev:
884 if rev:
885 node = repo[scmutil.revsingle(repo, rev, node)].node()
885 node = repo[scmutil.revsingle(repo, rev, node)].node()
886 try:
886 try:
887 while changesets:
887 while changesets:
888 # update state
888 # update state
889 state['current'] = [node]
889 state['current'] = [node]
890 hbisect.save_state(repo, state)
890 hbisect.save_state(repo, state)
891 status = ui.system(command, environ={'HG_NODE': hex(node)},
891 status = ui.system(command, environ={'HG_NODE': hex(node)},
892 blockedtag='bisect_check')
892 blockedtag='bisect_check')
893 if status == 125:
893 if status == 125:
894 transition = "skip"
894 transition = "skip"
895 elif status == 0:
895 elif status == 0:
896 transition = "good"
896 transition = "good"
897 # status < 0 means process was killed
897 # status < 0 means process was killed
898 elif status == 127:
898 elif status == 127:
899 raise error.Abort(_("failed to execute %s") % command)
899 raise error.Abort(_("failed to execute %s") % command)
900 elif status < 0:
900 elif status < 0:
901 raise error.Abort(_("%s killed") % command)
901 raise error.Abort(_("%s killed") % command)
902 else:
902 else:
903 transition = "bad"
903 transition = "bad"
904 state[transition].append(node)
904 state[transition].append(node)
905 ctx = repo[node]
905 ctx = repo[node]
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
907 hbisect.checkstate(state)
907 hbisect.checkstate(state)
908 # bisect
908 # bisect
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
910 # update to next check
910 # update to next check
911 node = nodes[0]
911 node = nodes[0]
912 mayupdate(repo, node, show_stats=False)
912 mayupdate(repo, node, show_stats=False)
913 finally:
913 finally:
914 state['current'] = [node]
914 state['current'] = [node]
915 hbisect.save_state(repo, state)
915 hbisect.save_state(repo, state)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
917 return
917 return
918
918
919 hbisect.checkstate(state)
919 hbisect.checkstate(state)
920
920
921 # actually bisect
921 # actually bisect
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
923 if extend:
923 if extend:
924 if not changesets:
924 if not changesets:
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
926 if extendnode is not None:
926 if extendnode is not None:
927 ui.write(_("Extending search to changeset %d:%s\n")
927 ui.write(_("Extending search to changeset %d:%s\n")
928 % (extendnode.rev(), extendnode))
928 % (extendnode.rev(), extendnode))
929 state['current'] = [extendnode.node()]
929 state['current'] = [extendnode.node()]
930 hbisect.save_state(repo, state)
930 hbisect.save_state(repo, state)
931 return mayupdate(repo, extendnode.node())
931 return mayupdate(repo, extendnode.node())
932 raise error.Abort(_("nothing to extend"))
932 raise error.Abort(_("nothing to extend"))
933
933
934 if changesets == 0:
934 if changesets == 0:
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
936 else:
936 else:
937 assert len(nodes) == 1 # only a single node can be tested next
937 assert len(nodes) == 1 # only a single node can be tested next
938 node = nodes[0]
938 node = nodes[0]
939 # compute the approximate number of remaining tests
939 # compute the approximate number of remaining tests
940 tests, size = 0, 2
940 tests, size = 0, 2
941 while size <= changesets:
941 while size <= changesets:
942 tests, size = tests + 1, size * 2
942 tests, size = tests + 1, size * 2
943 rev = repo.changelog.rev(node)
943 rev = repo.changelog.rev(node)
944 ui.write(_("Testing changeset %d:%s "
944 ui.write(_("Testing changeset %d:%s "
945 "(%d changesets remaining, ~%d tests)\n")
945 "(%d changesets remaining, ~%d tests)\n")
946 % (rev, short(node), changesets, tests))
946 % (rev, short(node), changesets, tests))
947 state['current'] = [node]
947 state['current'] = [node]
948 hbisect.save_state(repo, state)
948 hbisect.save_state(repo, state)
949 return mayupdate(repo, node)
949 return mayupdate(repo, node)
950
950
951 @command('bookmarks|bookmark',
951 @command('bookmarks|bookmark',
952 [('f', 'force', False, _('force')),
952 [('f', 'force', False, _('force')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
954 ('d', 'delete', False, _('delete a given bookmark')),
954 ('d', 'delete', False, _('delete a given bookmark')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
957 ] + formatteropts,
957 ] + formatteropts,
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
959 def bookmark(ui, repo, *names, **opts):
959 def bookmark(ui, repo, *names, **opts):
960 '''create a new bookmark or list existing bookmarks
960 '''create a new bookmark or list existing bookmarks
961
961
962 Bookmarks are labels on changesets to help track lines of development.
962 Bookmarks are labels on changesets to help track lines of development.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
964 Deleting or moving a bookmark has no effect on the associated changesets.
964 Deleting or moving a bookmark has no effect on the associated changesets.
965
965
966 Creating or updating to a bookmark causes it to be marked as 'active'.
966 Creating or updating to a bookmark causes it to be marked as 'active'.
967 The active bookmark is indicated with a '*'.
967 The active bookmark is indicated with a '*'.
968 When a commit is made, the active bookmark will advance to the new commit.
968 When a commit is made, the active bookmark will advance to the new commit.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
970 Updating away from a bookmark will cause it to be deactivated.
970 Updating away from a bookmark will cause it to be deactivated.
971
971
972 Bookmarks can be pushed and pulled between repositories (see
972 Bookmarks can be pushed and pulled between repositories (see
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
975 be created. Using :hg:`merge` will resolve the divergence.
975 be created. Using :hg:`merge` will resolve the divergence.
976
976
977 A bookmark named '@' has the special property that :hg:`clone` will
977 A bookmark named '@' has the special property that :hg:`clone` will
978 check it out by default if it exists.
978 check it out by default if it exists.
979
979
980 .. container:: verbose
980 .. container:: verbose
981
981
982 Examples:
982 Examples:
983
983
984 - create an active bookmark for a new line of development::
984 - create an active bookmark for a new line of development::
985
985
986 hg book new-feature
986 hg book new-feature
987
987
988 - create an inactive bookmark as a place marker::
988 - create an inactive bookmark as a place marker::
989
989
990 hg book -i reviewed
990 hg book -i reviewed
991
991
992 - create an inactive bookmark on another changeset::
992 - create an inactive bookmark on another changeset::
993
993
994 hg book -r .^ tested
994 hg book -r .^ tested
995
995
996 - rename bookmark turkey to dinner::
996 - rename bookmark turkey to dinner::
997
997
998 hg book -m turkey dinner
998 hg book -m turkey dinner
999
999
1000 - move the '@' bookmark from another branch::
1000 - move the '@' bookmark from another branch::
1001
1001
1002 hg book -f @
1002 hg book -f @
1003 '''
1003 '''
1004 force = opts.get('force')
1004 force = opts.get('force')
1005 rev = opts.get('rev')
1005 rev = opts.get('rev')
1006 delete = opts.get('delete')
1006 delete = opts.get('delete')
1007 rename = opts.get('rename')
1007 rename = opts.get('rename')
1008 inactive = opts.get('inactive')
1008 inactive = opts.get('inactive')
1009
1009
1010 def checkformat(mark):
1010 def checkformat(mark):
1011 mark = mark.strip()
1011 mark = mark.strip()
1012 if not mark:
1012 if not mark:
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1014 "whitespace"))
1014 "whitespace"))
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1016 return mark
1016 return mark
1017
1017
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1019 if mark in marks and not force:
1019 if mark in marks and not force:
1020 if target:
1020 if target:
1021 if marks[mark] == target and target == cur:
1021 if marks[mark] == target and target == cur:
1022 # re-activating a bookmark
1022 # re-activating a bookmark
1023 return
1023 return
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1025 bmctx = repo[marks[mark]]
1025 bmctx = repo[marks[mark]]
1026 divs = [repo[b].node() for b in marks
1026 divs = [repo[b].node() for b in marks
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1028
1028
1029 # allow resolving a single divergent bookmark even if moving
1029 # allow resolving a single divergent bookmark even if moving
1030 # the bookmark across branches when a revision is specified
1030 # the bookmark across branches when a revision is specified
1031 # that contains a divergent bookmark
1031 # that contains a divergent bookmark
1032 if bmctx.rev() not in anc and target in divs:
1032 if bmctx.rev() not in anc and target in divs:
1033 bookmarks.deletedivergent(repo, [target], mark)
1033 bookmarks.deletedivergent(repo, [target], mark)
1034 return
1034 return
1035
1035
1036 deletefrom = [b for b in divs
1036 deletefrom = [b for b in divs
1037 if repo[b].rev() in anc or b == target]
1037 if repo[b].rev() in anc or b == target]
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1041 (mark, short(bmctx.node())))
1041 (mark, short(bmctx.node())))
1042 return
1042 return
1043 raise error.Abort(_("bookmark '%s' already exists "
1043 raise error.Abort(_("bookmark '%s' already exists "
1044 "(use -f to force)") % mark)
1044 "(use -f to force)") % mark)
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1046 and not force):
1046 and not force):
1047 raise error.Abort(
1047 raise error.Abort(
1048 _("a bookmark cannot have the name of an existing branch"))
1048 _("a bookmark cannot have the name of an existing branch"))
1049
1049
1050 if delete and rename:
1050 if delete and rename:
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1052 if delete and rev:
1052 if delete and rev:
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1054 if rename and rev:
1054 if rename and rev:
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1056 if not names and (delete or rev):
1056 if not names and (delete or rev):
1057 raise error.Abort(_("bookmark name required"))
1057 raise error.Abort(_("bookmark name required"))
1058
1058
1059 if delete or rename or names or inactive:
1059 if delete or rename or names or inactive:
1060 wlock = lock = tr = None
1060 wlock = lock = tr = None
1061 try:
1061 try:
1062 wlock = repo.wlock()
1062 wlock = repo.wlock()
1063 lock = repo.lock()
1063 lock = repo.lock()
1064 cur = repo.changectx('.').node()
1064 cur = repo.changectx('.').node()
1065 marks = repo._bookmarks
1065 marks = repo._bookmarks
1066 if delete:
1066 if delete:
1067 tr = repo.transaction('bookmark')
1067 tr = repo.transaction('bookmark')
1068 for mark in names:
1068 for mark in names:
1069 if mark not in marks:
1069 if mark not in marks:
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1071 mark)
1071 mark)
1072 if mark == repo._activebookmark:
1072 if mark == repo._activebookmark:
1073 bookmarks.deactivate(repo)
1073 bookmarks.deactivate(repo)
1074 del marks[mark]
1074 del marks[mark]
1075
1075
1076 elif rename:
1076 elif rename:
1077 tr = repo.transaction('bookmark')
1077 tr = repo.transaction('bookmark')
1078 if not names:
1078 if not names:
1079 raise error.Abort(_("new bookmark name required"))
1079 raise error.Abort(_("new bookmark name required"))
1080 elif len(names) > 1:
1080 elif len(names) > 1:
1081 raise error.Abort(_("only one new bookmark name allowed"))
1081 raise error.Abort(_("only one new bookmark name allowed"))
1082 mark = checkformat(names[0])
1082 mark = checkformat(names[0])
1083 if rename not in marks:
1083 if rename not in marks:
1084 raise error.Abort(_("bookmark '%s' does not exist")
1084 raise error.Abort(_("bookmark '%s' does not exist")
1085 % rename)
1085 % rename)
1086 checkconflict(repo, mark, cur, force)
1086 checkconflict(repo, mark, cur, force)
1087 marks[mark] = marks[rename]
1087 marks[mark] = marks[rename]
1088 if repo._activebookmark == rename and not inactive:
1088 if repo._activebookmark == rename and not inactive:
1089 bookmarks.activate(repo, mark)
1089 bookmarks.activate(repo, mark)
1090 del marks[rename]
1090 del marks[rename]
1091 elif names:
1091 elif names:
1092 tr = repo.transaction('bookmark')
1092 tr = repo.transaction('bookmark')
1093 newact = None
1093 newact = None
1094 for mark in names:
1094 for mark in names:
1095 mark = checkformat(mark)
1095 mark = checkformat(mark)
1096 if newact is None:
1096 if newact is None:
1097 newact = mark
1097 newact = mark
1098 if inactive and mark == repo._activebookmark:
1098 if inactive and mark == repo._activebookmark:
1099 bookmarks.deactivate(repo)
1099 bookmarks.deactivate(repo)
1100 return
1100 return
1101 tgt = cur
1101 tgt = cur
1102 if rev:
1102 if rev:
1103 tgt = scmutil.revsingle(repo, rev).node()
1103 tgt = scmutil.revsingle(repo, rev).node()
1104 checkconflict(repo, mark, cur, force, tgt)
1104 checkconflict(repo, mark, cur, force, tgt)
1105 marks[mark] = tgt
1105 marks[mark] = tgt
1106 if not inactive and cur == marks[newact] and not rev:
1106 if not inactive and cur == marks[newact] and not rev:
1107 bookmarks.activate(repo, newact)
1107 bookmarks.activate(repo, newact)
1108 elif cur != tgt and newact == repo._activebookmark:
1108 elif cur != tgt and newact == repo._activebookmark:
1109 bookmarks.deactivate(repo)
1109 bookmarks.deactivate(repo)
1110 elif inactive:
1110 elif inactive:
1111 if len(marks) == 0:
1111 if len(marks) == 0:
1112 ui.status(_("no bookmarks set\n"))
1112 ui.status(_("no bookmarks set\n"))
1113 elif not repo._activebookmark:
1113 elif not repo._activebookmark:
1114 ui.status(_("no active bookmark\n"))
1114 ui.status(_("no active bookmark\n"))
1115 else:
1115 else:
1116 bookmarks.deactivate(repo)
1116 bookmarks.deactivate(repo)
1117 if tr is not None:
1117 if tr is not None:
1118 marks.recordchange(tr)
1118 marks.recordchange(tr)
1119 tr.close()
1119 tr.close()
1120 finally:
1120 finally:
1121 lockmod.release(tr, lock, wlock)
1121 lockmod.release(tr, lock, wlock)
1122 else: # show bookmarks
1122 else: # show bookmarks
1123 fm = ui.formatter('bookmarks', opts)
1123 fm = ui.formatter('bookmarks', opts)
1124 hexfn = fm.hexfunc
1124 hexfn = fm.hexfunc
1125 marks = repo._bookmarks
1125 marks = repo._bookmarks
1126 if len(marks) == 0 and fm.isplain():
1126 if len(marks) == 0 and fm.isplain():
1127 ui.status(_("no bookmarks set\n"))
1127 ui.status(_("no bookmarks set\n"))
1128 for bmark, n in sorted(marks.iteritems()):
1128 for bmark, n in sorted(marks.iteritems()):
1129 active = repo._activebookmark
1129 active = repo._activebookmark
1130 if bmark == active:
1130 if bmark == active:
1131 prefix, label = '*', activebookmarklabel
1131 prefix, label = '*', activebookmarklabel
1132 else:
1132 else:
1133 prefix, label = ' ', ''
1133 prefix, label = ' ', ''
1134
1134
1135 fm.startitem()
1135 fm.startitem()
1136 if not ui.quiet:
1136 if not ui.quiet:
1137 fm.plain(' %s ' % prefix, label=label)
1137 fm.plain(' %s ' % prefix, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1139 pad = " " * (25 - encoding.colwidth(bmark))
1139 pad = " " * (25 - encoding.colwidth(bmark))
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1141 repo.changelog.rev(n), hexfn(n), label=label)
1141 repo.changelog.rev(n), hexfn(n), label=label)
1142 fm.data(active=(bmark == active))
1142 fm.data(active=(bmark == active))
1143 fm.plain('\n')
1143 fm.plain('\n')
1144 fm.end()
1144 fm.end()
1145
1145
1146 @command('branch',
1146 @command('branch',
1147 [('f', 'force', None,
1147 [('f', 'force', None,
1148 _('set branch name even if it shadows an existing branch')),
1148 _('set branch name even if it shadows an existing branch')),
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1150 _('[-fC] [NAME]'))
1150 _('[-fC] [NAME]'))
1151 def branch(ui, repo, label=None, **opts):
1151 def branch(ui, repo, label=None, **opts):
1152 """set or show the current branch name
1152 """set or show the current branch name
1153
1153
1154 .. note::
1154 .. note::
1155
1155
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1158 information about named branches and bookmarks.
1158 information about named branches and bookmarks.
1159
1159
1160 With no argument, show the current branch name. With one argument,
1160 With no argument, show the current branch name. With one argument,
1161 set the working directory branch name (the branch will not exist
1161 set the working directory branch name (the branch will not exist
1162 in the repository until the next commit). Standard practice
1162 in the repository until the next commit). Standard practice
1163 recommends that primary development take place on the 'default'
1163 recommends that primary development take place on the 'default'
1164 branch.
1164 branch.
1165
1165
1166 Unless -f/--force is specified, branch will not let you set a
1166 Unless -f/--force is specified, branch will not let you set a
1167 branch name that already exists.
1167 branch name that already exists.
1168
1168
1169 Use -C/--clean to reset the working directory branch to that of
1169 Use -C/--clean to reset the working directory branch to that of
1170 the parent of the working directory, negating a previous branch
1170 the parent of the working directory, negating a previous branch
1171 change.
1171 change.
1172
1172
1173 Use the command :hg:`update` to switch to an existing branch. Use
1173 Use the command :hg:`update` to switch to an existing branch. Use
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1175 When all heads of a branch are closed, the branch will be
1175 When all heads of a branch are closed, the branch will be
1176 considered closed.
1176 considered closed.
1177
1177
1178 Returns 0 on success.
1178 Returns 0 on success.
1179 """
1179 """
1180 if label:
1180 if label:
1181 label = label.strip()
1181 label = label.strip()
1182
1182
1183 if not opts.get('clean') and not label:
1183 if not opts.get('clean') and not label:
1184 ui.write("%s\n" % repo.dirstate.branch())
1184 ui.write("%s\n" % repo.dirstate.branch())
1185 return
1185 return
1186
1186
1187 with repo.wlock():
1187 with repo.wlock():
1188 if opts.get('clean'):
1188 if opts.get('clean'):
1189 label = repo[None].p1().branch()
1189 label = repo[None].p1().branch()
1190 repo.dirstate.setbranch(label)
1190 repo.dirstate.setbranch(label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1192 elif label:
1192 elif label:
1193 if not opts.get('force') and label in repo.branchmap():
1193 if not opts.get('force') and label in repo.branchmap():
1194 if label not in [p.branch() for p in repo[None].parents()]:
1194 if label not in [p.branch() for p in repo[None].parents()]:
1195 raise error.Abort(_('a branch of the same name already'
1195 raise error.Abort(_('a branch of the same name already'
1196 ' exists'),
1196 ' exists'),
1197 # i18n: "it" refers to an existing branch
1197 # i18n: "it" refers to an existing branch
1198 hint=_("use 'hg update' to switch to it"))
1198 hint=_("use 'hg update' to switch to it"))
1199 scmutil.checknewlabel(repo, label, 'branch')
1199 scmutil.checknewlabel(repo, label, 'branch')
1200 repo.dirstate.setbranch(label)
1200 repo.dirstate.setbranch(label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1202
1202
1203 # find any open named branches aside from default
1203 # find any open named branches aside from default
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1205 if n != "default" and not c]
1205 if n != "default" and not c]
1206 if not others:
1206 if not others:
1207 ui.status(_('(branches are permanent and global, '
1207 ui.status(_('(branches are permanent and global, '
1208 'did you want a bookmark?)\n'))
1208 'did you want a bookmark?)\n'))
1209
1209
1210 @command('branches',
1210 @command('branches',
1211 [('a', 'active', False,
1211 [('a', 'active', False,
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1214 ] + formatteropts,
1214 ] + formatteropts,
1215 _('[-c]'))
1215 _('[-c]'))
1216 def branches(ui, repo, active=False, closed=False, **opts):
1216 def branches(ui, repo, active=False, closed=False, **opts):
1217 """list repository named branches
1217 """list repository named branches
1218
1218
1219 List the repository's named branches, indicating which ones are
1219 List the repository's named branches, indicating which ones are
1220 inactive. If -c/--closed is specified, also list branches which have
1220 inactive. If -c/--closed is specified, also list branches which have
1221 been marked closed (see :hg:`commit --close-branch`).
1221 been marked closed (see :hg:`commit --close-branch`).
1222
1222
1223 Use the command :hg:`update` to switch to an existing branch.
1223 Use the command :hg:`update` to switch to an existing branch.
1224
1224
1225 Returns 0.
1225 Returns 0.
1226 """
1226 """
1227
1227
1228 ui.pager('branches')
1228 ui.pager('branches')
1229 fm = ui.formatter('branches', opts)
1229 fm = ui.formatter('branches', opts)
1230 hexfunc = fm.hexfunc
1230 hexfunc = fm.hexfunc
1231
1231
1232 allheads = set(repo.heads())
1232 allheads = set(repo.heads())
1233 branches = []
1233 branches = []
1234 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1234 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1235 isactive = not isclosed and bool(set(heads) & allheads)
1235 isactive = not isclosed and bool(set(heads) & allheads)
1236 branches.append((tag, repo[tip], isactive, not isclosed))
1236 branches.append((tag, repo[tip], isactive, not isclosed))
1237 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1237 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1238 reverse=True)
1238 reverse=True)
1239
1239
1240 for tag, ctx, isactive, isopen in branches:
1240 for tag, ctx, isactive, isopen in branches:
1241 if active and not isactive:
1241 if active and not isactive:
1242 continue
1242 continue
1243 if isactive:
1243 if isactive:
1244 label = 'branches.active'
1244 label = 'branches.active'
1245 notice = ''
1245 notice = ''
1246 elif not isopen:
1246 elif not isopen:
1247 if not closed:
1247 if not closed:
1248 continue
1248 continue
1249 label = 'branches.closed'
1249 label = 'branches.closed'
1250 notice = _(' (closed)')
1250 notice = _(' (closed)')
1251 else:
1251 else:
1252 label = 'branches.inactive'
1252 label = 'branches.inactive'
1253 notice = _(' (inactive)')
1253 notice = _(' (inactive)')
1254 current = (tag == repo.dirstate.branch())
1254 current = (tag == repo.dirstate.branch())
1255 if current:
1255 if current:
1256 label = 'branches.current'
1256 label = 'branches.current'
1257
1257
1258 fm.startitem()
1258 fm.startitem()
1259 fm.write('branch', '%s', tag, label=label)
1259 fm.write('branch', '%s', tag, label=label)
1260 rev = ctx.rev()
1260 rev = ctx.rev()
1261 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1261 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1262 fmt = ' ' * padsize + ' %d:%s'
1262 fmt = ' ' * padsize + ' %d:%s'
1263 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1263 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1264 label='log.changeset changeset.%s' % ctx.phasestr())
1264 label='log.changeset changeset.%s' % ctx.phasestr())
1265 fm.context(ctx=ctx)
1265 fm.context(ctx=ctx)
1266 fm.data(active=isactive, closed=not isopen, current=current)
1266 fm.data(active=isactive, closed=not isopen, current=current)
1267 if not ui.quiet:
1267 if not ui.quiet:
1268 fm.plain(notice)
1268 fm.plain(notice)
1269 fm.plain('\n')
1269 fm.plain('\n')
1270 fm.end()
1270 fm.end()
1271
1271
1272 @command('bundle',
1272 @command('bundle',
1273 [('f', 'force', None, _('run even when the destination is unrelated')),
1273 [('f', 'force', None, _('run even when the destination is unrelated')),
1274 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1274 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1275 _('REV')),
1275 _('REV')),
1276 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1276 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1277 _('BRANCH')),
1277 _('BRANCH')),
1278 ('', 'base', [],
1278 ('', 'base', [],
1279 _('a base changeset assumed to be available at the destination'),
1279 _('a base changeset assumed to be available at the destination'),
1280 _('REV')),
1280 _('REV')),
1281 ('a', 'all', None, _('bundle all changesets in the repository')),
1281 ('a', 'all', None, _('bundle all changesets in the repository')),
1282 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1282 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1283 ] + remoteopts,
1283 ] + remoteopts,
1284 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1284 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1285 def bundle(ui, repo, fname, dest=None, **opts):
1285 def bundle(ui, repo, fname, dest=None, **opts):
1286 """create a changegroup file
1286 """create a changegroup file
1287
1287
1288 Generate a changegroup file collecting changesets to be added
1288 Generate a changegroup file collecting changesets to be added
1289 to a repository.
1289 to a repository.
1290
1290
1291 To create a bundle containing all changesets, use -a/--all
1291 To create a bundle containing all changesets, use -a/--all
1292 (or --base null). Otherwise, hg assumes the destination will have
1292 (or --base null). Otherwise, hg assumes the destination will have
1293 all the nodes you specify with --base parameters. Otherwise, hg
1293 all the nodes you specify with --base parameters. Otherwise, hg
1294 will assume the repository has all the nodes in destination, or
1294 will assume the repository has all the nodes in destination, or
1295 default-push/default if no destination is specified.
1295 default-push/default if no destination is specified.
1296
1296
1297 You can change bundle format with the -t/--type option. You can
1297 You can change bundle format with the -t/--type option. You can
1298 specify a compression, a bundle version or both using a dash
1298 specify a compression, a bundle version or both using a dash
1299 (comp-version). The available compression methods are: none, bzip2,
1299 (comp-version). The available compression methods are: none, bzip2,
1300 and gzip (by default, bundles are compressed using bzip2). The
1300 and gzip (by default, bundles are compressed using bzip2). The
1301 available formats are: v1, v2 (default to most suitable).
1301 available formats are: v1, v2 (default to most suitable).
1302
1302
1303 The bundle file can then be transferred using conventional means
1303 The bundle file can then be transferred using conventional means
1304 and applied to another repository with the unbundle or pull
1304 and applied to another repository with the unbundle or pull
1305 command. This is useful when direct push and pull are not
1305 command. This is useful when direct push and pull are not
1306 available or when exporting an entire repository is undesirable.
1306 available or when exporting an entire repository is undesirable.
1307
1307
1308 Applying bundles preserves all changeset contents including
1308 Applying bundles preserves all changeset contents including
1309 permissions, copy/rename information, and revision history.
1309 permissions, copy/rename information, and revision history.
1310
1310
1311 Returns 0 on success, 1 if no changes found.
1311 Returns 0 on success, 1 if no changes found.
1312 """
1312 """
1313 revs = None
1313 revs = None
1314 if 'rev' in opts:
1314 if 'rev' in opts:
1315 revstrings = opts['rev']
1315 revstrings = opts['rev']
1316 revs = scmutil.revrange(repo, revstrings)
1316 revs = scmutil.revrange(repo, revstrings)
1317 if revstrings and not revs:
1317 if revstrings and not revs:
1318 raise error.Abort(_('no commits to bundle'))
1318 raise error.Abort(_('no commits to bundle'))
1319
1319
1320 bundletype = opts.get('type', 'bzip2').lower()
1320 bundletype = opts.get('type', 'bzip2').lower()
1321 try:
1321 try:
1322 bcompression, cgversion, params = exchange.parsebundlespec(
1322 bcompression, cgversion, params = exchange.parsebundlespec(
1323 repo, bundletype, strict=False)
1323 repo, bundletype, strict=False)
1324 except error.UnsupportedBundleSpecification as e:
1324 except error.UnsupportedBundleSpecification as e:
1325 raise error.Abort(str(e),
1325 raise error.Abort(str(e),
1326 hint=_("see 'hg help bundle' for supported "
1326 hint=_("see 'hg help bundle' for supported "
1327 "values for --type"))
1327 "values for --type"))
1328
1328
1329 # Packed bundles are a pseudo bundle format for now.
1329 # Packed bundles are a pseudo bundle format for now.
1330 if cgversion == 's1':
1330 if cgversion == 's1':
1331 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1331 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1332 hint=_("use 'hg debugcreatestreamclonebundle'"))
1332 hint=_("use 'hg debugcreatestreamclonebundle'"))
1333
1333
1334 if opts.get('all'):
1334 if opts.get('all'):
1335 if dest:
1335 if dest:
1336 raise error.Abort(_("--all is incompatible with specifying "
1336 raise error.Abort(_("--all is incompatible with specifying "
1337 "a destination"))
1337 "a destination"))
1338 if opts.get('base'):
1338 if opts.get('base'):
1339 ui.warn(_("ignoring --base because --all was specified\n"))
1339 ui.warn(_("ignoring --base because --all was specified\n"))
1340 base = ['null']
1340 base = ['null']
1341 else:
1341 else:
1342 base = scmutil.revrange(repo, opts.get('base'))
1342 base = scmutil.revrange(repo, opts.get('base'))
1343 # TODO: get desired bundlecaps from command line.
1343 # TODO: get desired bundlecaps from command line.
1344 bundlecaps = None
1344 bundlecaps = None
1345 if cgversion not in changegroup.supportedoutgoingversions(repo):
1345 if cgversion not in changegroup.supportedoutgoingversions(repo):
1346 raise error.Abort(_("repository does not support bundle version %s") %
1346 raise error.Abort(_("repository does not support bundle version %s") %
1347 cgversion)
1347 cgversion)
1348
1348
1349 if base:
1349 if base:
1350 if dest:
1350 if dest:
1351 raise error.Abort(_("--base is incompatible with specifying "
1351 raise error.Abort(_("--base is incompatible with specifying "
1352 "a destination"))
1352 "a destination"))
1353 common = [repo.lookup(rev) for rev in base]
1353 common = [repo.lookup(rev) for rev in base]
1354 heads = revs and map(repo.lookup, revs) or None
1354 heads = revs and map(repo.lookup, revs) or None
1355 outgoing = discovery.outgoing(repo, common, heads)
1355 outgoing = discovery.outgoing(repo, common, heads)
1356 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1356 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1357 bundlecaps=bundlecaps,
1357 bundlecaps=bundlecaps,
1358 version=cgversion)
1358 version=cgversion)
1359 outgoing = None
1359 outgoing = None
1360 else:
1360 else:
1361 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1361 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1362 dest, branches = hg.parseurl(dest, opts.get('branch'))
1362 dest, branches = hg.parseurl(dest, opts.get('branch'))
1363 other = hg.peer(repo, opts, dest)
1363 other = hg.peer(repo, opts, dest)
1364 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1364 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1365 heads = revs and map(repo.lookup, revs) or revs
1365 heads = revs and map(repo.lookup, revs) or revs
1366 outgoing = discovery.findcommonoutgoing(repo, other,
1366 outgoing = discovery.findcommonoutgoing(repo, other,
1367 onlyheads=heads,
1367 onlyheads=heads,
1368 force=opts.get('force'),
1368 force=opts.get('force'),
1369 portable=True)
1369 portable=True)
1370 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1370 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1371 bundlecaps, version=cgversion)
1371 bundlecaps, version=cgversion)
1372 if not cg:
1372 if not cg:
1373 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1373 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1374 return 1
1374 return 1
1375
1375
1376 if cgversion == '01': #bundle1
1376 if cgversion == '01': #bundle1
1377 if bcompression is None:
1377 if bcompression is None:
1378 bcompression = 'UN'
1378 bcompression = 'UN'
1379 bversion = 'HG10' + bcompression
1379 bversion = 'HG10' + bcompression
1380 bcompression = None
1380 bcompression = None
1381 else:
1381 else:
1382 assert cgversion == '02'
1382 assert cgversion == '02'
1383 bversion = 'HG20'
1383 bversion = 'HG20'
1384
1384
1385 # TODO compression options should be derived from bundlespec parsing.
1385 # TODO compression options should be derived from bundlespec parsing.
1386 # This is a temporary hack to allow adjusting bundle compression
1386 # This is a temporary hack to allow adjusting bundle compression
1387 # level without a) formalizing the bundlespec changes to declare it
1387 # level without a) formalizing the bundlespec changes to declare it
1388 # b) introducing a command flag.
1388 # b) introducing a command flag.
1389 compopts = {}
1389 compopts = {}
1390 complevel = ui.configint('experimental', 'bundlecomplevel')
1390 complevel = ui.configint('experimental', 'bundlecomplevel')
1391 if complevel is not None:
1391 if complevel is not None:
1392 compopts['level'] = complevel
1392 compopts['level'] = complevel
1393
1393
1394 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1394 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1395 compopts=compopts)
1395 compopts=compopts)
1396
1396
1397 @command('cat',
1397 @command('cat',
1398 [('o', 'output', '',
1398 [('o', 'output', '',
1399 _('print output to file with formatted name'), _('FORMAT')),
1399 _('print output to file with formatted name'), _('FORMAT')),
1400 ('r', 'rev', '', _('print the given revision'), _('REV')),
1400 ('r', 'rev', '', _('print the given revision'), _('REV')),
1401 ('', 'decode', None, _('apply any matching decode filter')),
1401 ('', 'decode', None, _('apply any matching decode filter')),
1402 ] + walkopts,
1402 ] + walkopts,
1403 _('[OPTION]... FILE...'),
1403 _('[OPTION]... FILE...'),
1404 inferrepo=True)
1404 inferrepo=True)
1405 def cat(ui, repo, file1, *pats, **opts):
1405 def cat(ui, repo, file1, *pats, **opts):
1406 """output the current or given revision of files
1406 """output the current or given revision of files
1407
1407
1408 Print the specified files as they were at the given revision. If
1408 Print the specified files as they were at the given revision. If
1409 no revision is given, the parent of the working directory is used.
1409 no revision is given, the parent of the working directory is used.
1410
1410
1411 Output may be to a file, in which case the name of the file is
1411 Output may be to a file, in which case the name of the file is
1412 given using a format string. The formatting rules as follows:
1412 given using a format string. The formatting rules as follows:
1413
1413
1414 :``%%``: literal "%" character
1414 :``%%``: literal "%" character
1415 :``%s``: basename of file being printed
1415 :``%s``: basename of file being printed
1416 :``%d``: dirname of file being printed, or '.' if in repository root
1416 :``%d``: dirname of file being printed, or '.' if in repository root
1417 :``%p``: root-relative path name of file being printed
1417 :``%p``: root-relative path name of file being printed
1418 :``%H``: changeset hash (40 hexadecimal digits)
1418 :``%H``: changeset hash (40 hexadecimal digits)
1419 :``%R``: changeset revision number
1419 :``%R``: changeset revision number
1420 :``%h``: short-form changeset hash (12 hexadecimal digits)
1420 :``%h``: short-form changeset hash (12 hexadecimal digits)
1421 :``%r``: zero-padded changeset revision number
1421 :``%r``: zero-padded changeset revision number
1422 :``%b``: basename of the exporting repository
1422 :``%b``: basename of the exporting repository
1423
1423
1424 Returns 0 on success.
1424 Returns 0 on success.
1425 """
1425 """
1426 ctx = scmutil.revsingle(repo, opts.get('rev'))
1426 ctx = scmutil.revsingle(repo, opts.get('rev'))
1427 m = scmutil.match(ctx, (file1,) + pats, opts)
1427 m = scmutil.match(ctx, (file1,) + pats, opts)
1428
1428
1429 ui.pager('cat')
1429 ui.pager('cat')
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431
1431
1432 @command('^clone',
1432 @command('^clone',
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 'directory (only a repository)')),
1434 'directory (only a repository)')),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 _('REV')),
1436 _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ] + remoteopts,
1441 ] + remoteopts,
1442 _('[OPTION]... SOURCE [DEST]'),
1442 _('[OPTION]... SOURCE [DEST]'),
1443 norepo=True)
1443 norepo=True)
1444 def clone(ui, source, dest=None, **opts):
1444 def clone(ui, source, dest=None, **opts):
1445 """make a copy of an existing repository
1445 """make a copy of an existing repository
1446
1446
1447 Create a copy of an existing repository in a new directory.
1447 Create a copy of an existing repository in a new directory.
1448
1448
1449 If no destination directory name is specified, it defaults to the
1449 If no destination directory name is specified, it defaults to the
1450 basename of the source.
1450 basename of the source.
1451
1451
1452 The location of the source is added to the new repository's
1452 The location of the source is added to the new repository's
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1454
1454
1455 Only local paths and ``ssh://`` URLs are supported as
1455 Only local paths and ``ssh://`` URLs are supported as
1456 destinations. For ``ssh://`` destinations, no working directory or
1456 destinations. For ``ssh://`` destinations, no working directory or
1457 ``.hg/hgrc`` will be created on the remote side.
1457 ``.hg/hgrc`` will be created on the remote side.
1458
1458
1459 If the source repository has a bookmark called '@' set, that
1459 If the source repository has a bookmark called '@' set, that
1460 revision will be checked out in the new repository by default.
1460 revision will be checked out in the new repository by default.
1461
1461
1462 To check out a particular version, use -u/--update, or
1462 To check out a particular version, use -u/--update, or
1463 -U/--noupdate to create a clone with no working directory.
1463 -U/--noupdate to create a clone with no working directory.
1464
1464
1465 To pull only a subset of changesets, specify one or more revisions
1465 To pull only a subset of changesets, specify one or more revisions
1466 identifiers with -r/--rev or branches with -b/--branch. The
1466 identifiers with -r/--rev or branches with -b/--branch. The
1467 resulting clone will contain only the specified changesets and
1467 resulting clone will contain only the specified changesets and
1468 their ancestors. These options (or 'clone src#rev dest') imply
1468 their ancestors. These options (or 'clone src#rev dest') imply
1469 --pull, even for local source repositories.
1469 --pull, even for local source repositories.
1470
1470
1471 .. note::
1471 .. note::
1472
1472
1473 Specifying a tag will include the tagged changeset but not the
1473 Specifying a tag will include the tagged changeset but not the
1474 changeset containing the tag.
1474 changeset containing the tag.
1475
1475
1476 .. container:: verbose
1476 .. container:: verbose
1477
1477
1478 For efficiency, hardlinks are used for cloning whenever the
1478 For efficiency, hardlinks are used for cloning whenever the
1479 source and destination are on the same filesystem (note this
1479 source and destination are on the same filesystem (note this
1480 applies only to the repository data, not to the working
1480 applies only to the repository data, not to the working
1481 directory). Some filesystems, such as AFS, implement hardlinking
1481 directory). Some filesystems, such as AFS, implement hardlinking
1482 incorrectly, but do not report errors. In these cases, use the
1482 incorrectly, but do not report errors. In these cases, use the
1483 --pull option to avoid hardlinking.
1483 --pull option to avoid hardlinking.
1484
1484
1485 In some cases, you can clone repositories and the working
1485 In some cases, you can clone repositories and the working
1486 directory using full hardlinks with ::
1486 directory using full hardlinks with ::
1487
1487
1488 $ cp -al REPO REPOCLONE
1488 $ cp -al REPO REPOCLONE
1489
1489
1490 This is the fastest way to clone, but it is not always safe. The
1490 This is the fastest way to clone, but it is not always safe. The
1491 operation is not atomic (making sure REPO is not modified during
1491 operation is not atomic (making sure REPO is not modified during
1492 the operation is up to you) and you have to make sure your
1492 the operation is up to you) and you have to make sure your
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 so). Also, this is not compatible with certain extensions that
1494 so). Also, this is not compatible with certain extensions that
1495 place their metadata under the .hg directory, such as mq.
1495 place their metadata under the .hg directory, such as mq.
1496
1496
1497 Mercurial will update the working directory to the first applicable
1497 Mercurial will update the working directory to the first applicable
1498 revision from this list:
1498 revision from this list:
1499
1499
1500 a) null if -U or the source repository has no changesets
1500 a) null if -U or the source repository has no changesets
1501 b) if -u . and the source repository is local, the first parent of
1501 b) if -u . and the source repository is local, the first parent of
1502 the source repository's working directory
1502 the source repository's working directory
1503 c) the changeset specified with -u (if a branch name, this means the
1503 c) the changeset specified with -u (if a branch name, this means the
1504 latest head of that branch)
1504 latest head of that branch)
1505 d) the changeset specified with -r
1505 d) the changeset specified with -r
1506 e) the tipmost head specified with -b
1506 e) the tipmost head specified with -b
1507 f) the tipmost head specified with the url#branch source syntax
1507 f) the tipmost head specified with the url#branch source syntax
1508 g) the revision marked with the '@' bookmark, if present
1508 g) the revision marked with the '@' bookmark, if present
1509 h) the tipmost head of the default branch
1509 h) the tipmost head of the default branch
1510 i) tip
1510 i) tip
1511
1511
1512 When cloning from servers that support it, Mercurial may fetch
1512 When cloning from servers that support it, Mercurial may fetch
1513 pre-generated data from a server-advertised URL. When this is done,
1513 pre-generated data from a server-advertised URL. When this is done,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1515 once for the bundle fetched from the URL and another for any additional
1515 once for the bundle fetched from the URL and another for any additional
1516 data not fetched from this URL. In addition, if an error occurs, the
1516 data not fetched from this URL. In addition, if an error occurs, the
1517 repository may be rolled back to a partial clone. This behavior may
1517 repository may be rolled back to a partial clone. This behavior may
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1519
1519
1520 Examples:
1520 Examples:
1521
1521
1522 - clone a remote repository to a new directory named hg/::
1522 - clone a remote repository to a new directory named hg/::
1523
1523
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1525
1525
1526 - create a lightweight local clone::
1526 - create a lightweight local clone::
1527
1527
1528 hg clone project/ project-feature/
1528 hg clone project/ project-feature/
1529
1529
1530 - clone from an absolute path on an ssh server (note double-slash)::
1530 - clone from an absolute path on an ssh server (note double-slash)::
1531
1531
1532 hg clone ssh://user@server//home/projects/alpha/
1532 hg clone ssh://user@server//home/projects/alpha/
1533
1533
1534 - do a high-speed clone over a LAN while checking out a
1534 - do a high-speed clone over a LAN while checking out a
1535 specified version::
1535 specified version::
1536
1536
1537 hg clone --uncompressed http://server/repo -u 1.5
1537 hg clone --uncompressed http://server/repo -u 1.5
1538
1538
1539 - create a repository without changesets after a particular revision::
1539 - create a repository without changesets after a particular revision::
1540
1540
1541 hg clone -r 04e544 experimental/ good/
1541 hg clone -r 04e544 experimental/ good/
1542
1542
1543 - clone (and track) a particular named branch::
1543 - clone (and track) a particular named branch::
1544
1544
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1546
1546
1547 See :hg:`help urls` for details on specifying URLs.
1547 See :hg:`help urls` for details on specifying URLs.
1548
1548
1549 Returns 0 on success.
1549 Returns 0 on success.
1550 """
1550 """
1551 if opts.get('noupdate') and opts.get('updaterev'):
1551 if opts.get('noupdate') and opts.get('updaterev'):
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1553
1553
1554 r = hg.clone(ui, opts, source, dest,
1554 r = hg.clone(ui, opts, source, dest,
1555 pull=opts.get('pull'),
1555 pull=opts.get('pull'),
1556 stream=opts.get('uncompressed'),
1556 stream=opts.get('uncompressed'),
1557 rev=opts.get('rev'),
1557 rev=opts.get('rev'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1559 branch=opts.get('branch'),
1559 branch=opts.get('branch'),
1560 shareopts=opts.get('shareopts'))
1560 shareopts=opts.get('shareopts'))
1561
1561
1562 return r is None
1562 return r is None
1563
1563
1564 @command('^commit|ci',
1564 @command('^commit|ci',
1565 [('A', 'addremove', None,
1565 [('A', 'addremove', None,
1566 _('mark new/missing files as added/removed before committing')),
1566 _('mark new/missing files as added/removed before committing')),
1567 ('', 'close-branch', None,
1567 ('', 'close-branch', None,
1568 _('mark a branch head as closed')),
1568 _('mark a branch head as closed')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1574 _('[OPTION]... [FILE]...'),
1574 _('[OPTION]... [FILE]...'),
1575 inferrepo=True)
1575 inferrepo=True)
1576 def commit(ui, repo, *pats, **opts):
1576 def commit(ui, repo, *pats, **opts):
1577 """commit the specified files or all outstanding changes
1577 """commit the specified files or all outstanding changes
1578
1578
1579 Commit changes to the given files into the repository. Unlike a
1579 Commit changes to the given files into the repository. Unlike a
1580 centralized SCM, this operation is a local operation. See
1580 centralized SCM, this operation is a local operation. See
1581 :hg:`push` for a way to actively distribute your changes.
1581 :hg:`push` for a way to actively distribute your changes.
1582
1582
1583 If a list of files is omitted, all changes reported by :hg:`status`
1583 If a list of files is omitted, all changes reported by :hg:`status`
1584 will be committed.
1584 will be committed.
1585
1585
1586 If you are committing the result of a merge, do not provide any
1586 If you are committing the result of a merge, do not provide any
1587 filenames or -I/-X filters.
1587 filenames or -I/-X filters.
1588
1588
1589 If no commit message is specified, Mercurial starts your
1589 If no commit message is specified, Mercurial starts your
1590 configured editor where you can enter a message. In case your
1590 configured editor where you can enter a message. In case your
1591 commit fails, you will find a backup of your message in
1591 commit fails, you will find a backup of your message in
1592 ``.hg/last-message.txt``.
1592 ``.hg/last-message.txt``.
1593
1593
1594 The --close-branch flag can be used to mark the current branch
1594 The --close-branch flag can be used to mark the current branch
1595 head closed. When all heads of a branch are closed, the branch
1595 head closed. When all heads of a branch are closed, the branch
1596 will be considered closed and no longer listed.
1596 will be considered closed and no longer listed.
1597
1597
1598 The --amend flag can be used to amend the parent of the
1598 The --amend flag can be used to amend the parent of the
1599 working directory with a new commit that contains the changes
1599 working directory with a new commit that contains the changes
1600 in the parent in addition to those currently reported by :hg:`status`,
1600 in the parent in addition to those currently reported by :hg:`status`,
1601 if there are any. The old commit is stored in a backup bundle in
1601 if there are any. The old commit is stored in a backup bundle in
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 on how to restore it).
1603 on how to restore it).
1604
1604
1605 Message, user and date are taken from the amended commit unless
1605 Message, user and date are taken from the amended commit unless
1606 specified. When a message isn't specified on the command line,
1606 specified. When a message isn't specified on the command line,
1607 the editor will open with the message of the amended commit.
1607 the editor will open with the message of the amended commit.
1608
1608
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1610 or changesets that have children.
1610 or changesets that have children.
1611
1611
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1613
1613
1614 Returns 0 on success, 1 if nothing changed.
1614 Returns 0 on success, 1 if nothing changed.
1615
1615
1616 .. container:: verbose
1616 .. container:: verbose
1617
1617
1618 Examples:
1618 Examples:
1619
1619
1620 - commit all files ending in .py::
1620 - commit all files ending in .py::
1621
1621
1622 hg commit --include "set:**.py"
1622 hg commit --include "set:**.py"
1623
1623
1624 - commit all non-binary files::
1624 - commit all non-binary files::
1625
1625
1626 hg commit --exclude "set:binary()"
1626 hg commit --exclude "set:binary()"
1627
1627
1628 - amend the current commit and set the date to now::
1628 - amend the current commit and set the date to now::
1629
1629
1630 hg commit --amend --date now
1630 hg commit --amend --date now
1631 """
1631 """
1632 wlock = lock = None
1632 wlock = lock = None
1633 try:
1633 try:
1634 wlock = repo.wlock()
1634 wlock = repo.wlock()
1635 lock = repo.lock()
1635 lock = repo.lock()
1636 return _docommit(ui, repo, *pats, **opts)
1636 return _docommit(ui, repo, *pats, **opts)
1637 finally:
1637 finally:
1638 release(lock, wlock)
1638 release(lock, wlock)
1639
1639
1640 def _docommit(ui, repo, *pats, **opts):
1640 def _docommit(ui, repo, *pats, **opts):
1641 opts = pycompat.byteskwargs(opts)
1641 opts = pycompat.byteskwargs(opts)
1642 if opts.get('interactive'):
1642 if opts.get('interactive'):
1643 opts.pop('interactive')
1643 opts.pop('interactive')
1644 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1644 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1645 cmdutil.recordfilter, *pats,
1645 cmdutil.recordfilter, *pats,
1646 **pycompat.strkwargs(opts))
1646 **pycompat.strkwargs(opts))
1647 # ret can be 0 (no changes to record) or the value returned by
1647 # ret can be 0 (no changes to record) or the value returned by
1648 # commit(), 1 if nothing changed or None on success.
1648 # commit(), 1 if nothing changed or None on success.
1649 return 1 if ret == 0 else ret
1649 return 1 if ret == 0 else ret
1650
1650
1651 if opts.get('subrepos'):
1651 if opts.get('subrepos'):
1652 if opts.get('amend'):
1652 if opts.get('amend'):
1653 raise error.Abort(_('cannot amend with --subrepos'))
1653 raise error.Abort(_('cannot amend with --subrepos'))
1654 # Let --subrepos on the command line override config setting.
1654 # Let --subrepos on the command line override config setting.
1655 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1655 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1656
1656
1657 cmdutil.checkunfinished(repo, commit=True)
1657 cmdutil.checkunfinished(repo, commit=True)
1658
1658
1659 branch = repo[None].branch()
1659 branch = repo[None].branch()
1660 bheads = repo.branchheads(branch)
1660 bheads = repo.branchheads(branch)
1661
1661
1662 extra = {}
1662 extra = {}
1663 if opts.get('close_branch'):
1663 if opts.get('close_branch'):
1664 extra['close'] = 1
1664 extra['close'] = 1
1665
1665
1666 if not bheads:
1666 if not bheads:
1667 raise error.Abort(_('can only close branch heads'))
1667 raise error.Abort(_('can only close branch heads'))
1668 elif opts.get('amend'):
1668 elif opts.get('amend'):
1669 if repo[None].parents()[0].p1().branch() != branch and \
1669 if repo[None].parents()[0].p1().branch() != branch and \
1670 repo[None].parents()[0].p2().branch() != branch:
1670 repo[None].parents()[0].p2().branch() != branch:
1671 raise error.Abort(_('can only close branch heads'))
1671 raise error.Abort(_('can only close branch heads'))
1672
1672
1673 if opts.get('amend'):
1673 if opts.get('amend'):
1674 if ui.configbool('ui', 'commitsubrepos'):
1674 if ui.configbool('ui', 'commitsubrepos'):
1675 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1675 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1676
1676
1677 old = repo['.']
1677 old = repo['.']
1678 if not old.mutable():
1678 if not old.mutable():
1679 raise error.Abort(_('cannot amend public changesets'))
1679 raise error.Abort(_('cannot amend public changesets'))
1680 if len(repo[None].parents()) > 1:
1680 if len(repo[None].parents()) > 1:
1681 raise error.Abort(_('cannot amend while merging'))
1681 raise error.Abort(_('cannot amend while merging'))
1682 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1682 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1683 if not allowunstable and old.children():
1683 if not allowunstable and old.children():
1684 raise error.Abort(_('cannot amend changeset with children'))
1684 raise error.Abort(_('cannot amend changeset with children'))
1685
1685
1686 # Currently histedit gets confused if an amend happens while histedit
1686 # Currently histedit gets confused if an amend happens while histedit
1687 # is in progress. Since we have a checkunfinished command, we are
1687 # is in progress. Since we have a checkunfinished command, we are
1688 # temporarily honoring it.
1688 # temporarily honoring it.
1689 #
1689 #
1690 # Note: eventually this guard will be removed. Please do not expect
1690 # Note: eventually this guard will be removed. Please do not expect
1691 # this behavior to remain.
1691 # this behavior to remain.
1692 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1692 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1693 cmdutil.checkunfinished(repo)
1693 cmdutil.checkunfinished(repo)
1694
1694
1695 # commitfunc is used only for temporary amend commit by cmdutil.amend
1695 # commitfunc is used only for temporary amend commit by cmdutil.amend
1696 def commitfunc(ui, repo, message, match, opts):
1696 def commitfunc(ui, repo, message, match, opts):
1697 return repo.commit(message,
1697 return repo.commit(message,
1698 opts.get('user') or old.user(),
1698 opts.get('user') or old.user(),
1699 opts.get('date') or old.date(),
1699 opts.get('date') or old.date(),
1700 match,
1700 match,
1701 extra=extra)
1701 extra=extra)
1702
1702
1703 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1703 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1704 if node == old.node():
1704 if node == old.node():
1705 ui.status(_("nothing changed\n"))
1705 ui.status(_("nothing changed\n"))
1706 return 1
1706 return 1
1707 else:
1707 else:
1708 def commitfunc(ui, repo, message, match, opts):
1708 def commitfunc(ui, repo, message, match, opts):
1709 overrides = {}
1709 overrides = {}
1710 if opts.get('secret'):
1710 if opts.get('secret'):
1711 overrides[('phases', 'new-commit')] = 'secret'
1711 overrides[('phases', 'new-commit')] = 'secret'
1712
1712
1713 baseui = repo.baseui
1713 baseui = repo.baseui
1714 with baseui.configoverride(overrides, 'commit'):
1714 with baseui.configoverride(overrides, 'commit'):
1715 with ui.configoverride(overrides, 'commit'):
1715 with ui.configoverride(overrides, 'commit'):
1716 editform = cmdutil.mergeeditform(repo[None],
1716 editform = cmdutil.mergeeditform(repo[None],
1717 'commit.normal')
1717 'commit.normal')
1718 editor = cmdutil.getcommiteditor(
1718 editor = cmdutil.getcommiteditor(
1719 editform=editform, **pycompat.strkwargs(opts))
1719 editform=editform, **pycompat.strkwargs(opts))
1720 return repo.commit(message,
1720 return repo.commit(message,
1721 opts.get('user'),
1721 opts.get('user'),
1722 opts.get('date'),
1722 opts.get('date'),
1723 match,
1723 match,
1724 editor=editor,
1724 editor=editor,
1725 extra=extra)
1725 extra=extra)
1726
1726
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1728
1728
1729 if not node:
1729 if not node:
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1731 if stat[3]:
1731 if stat[3]:
1732 ui.status(_("nothing changed (%d missing files, see "
1732 ui.status(_("nothing changed (%d missing files, see "
1733 "'hg status')\n") % len(stat[3]))
1733 "'hg status')\n") % len(stat[3]))
1734 else:
1734 else:
1735 ui.status(_("nothing changed\n"))
1735 ui.status(_("nothing changed\n"))
1736 return 1
1736 return 1
1737
1737
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1739
1739
1740 @command('config|showconfig|debugconfig',
1740 @command('config|showconfig|debugconfig',
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1742 ('e', 'edit', None, _('edit user config')),
1742 ('e', 'edit', None, _('edit user config')),
1743 ('l', 'local', None, _('edit repository config')),
1743 ('l', 'local', None, _('edit repository config')),
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1745 _('[-u] [NAME]...'),
1745 _('[-u] [NAME]...'),
1746 optionalrepo=True)
1746 optionalrepo=True)
1747 def config(ui, repo, *values, **opts):
1747 def config(ui, repo, *values, **opts):
1748 """show combined config settings from all hgrc files
1748 """show combined config settings from all hgrc files
1749
1749
1750 With no arguments, print names and values of all config items.
1750 With no arguments, print names and values of all config items.
1751
1751
1752 With one argument of the form section.name, print just the value
1752 With one argument of the form section.name, print just the value
1753 of that config item.
1753 of that config item.
1754
1754
1755 With multiple arguments, print names and values of all config
1755 With multiple arguments, print names and values of all config
1756 items with matching section names.
1756 items with matching section names.
1757
1757
1758 With --edit, start an editor on the user-level config file. With
1758 With --edit, start an editor on the user-level config file. With
1759 --global, edit the system-wide config file. With --local, edit the
1759 --global, edit the system-wide config file. With --local, edit the
1760 repository-level config file.
1760 repository-level config file.
1761
1761
1762 With --debug, the source (filename and line number) is printed
1762 With --debug, the source (filename and line number) is printed
1763 for each config item.
1763 for each config item.
1764
1764
1765 See :hg:`help config` for more information about config files.
1765 See :hg:`help config` for more information about config files.
1766
1766
1767 Returns 0 on success, 1 if NAME does not exist.
1767 Returns 0 on success, 1 if NAME does not exist.
1768
1768
1769 """
1769 """
1770
1770
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1773 raise error.Abort(_("can't use --local and --global together"))
1773 raise error.Abort(_("can't use --local and --global together"))
1774
1774
1775 if opts.get('local'):
1775 if opts.get('local'):
1776 if not repo:
1776 if not repo:
1777 raise error.Abort(_("can't use --local outside a repository"))
1777 raise error.Abort(_("can't use --local outside a repository"))
1778 paths = [repo.vfs.join('hgrc')]
1778 paths = [repo.vfs.join('hgrc')]
1779 elif opts.get('global'):
1779 elif opts.get('global'):
1780 paths = rcutil.systemrcpath()
1780 paths = rcutil.systemrcpath()
1781 else:
1781 else:
1782 paths = rcutil.userrcpath()
1782 paths = rcutil.userrcpath()
1783
1783
1784 for f in paths:
1784 for f in paths:
1785 if os.path.exists(f):
1785 if os.path.exists(f):
1786 break
1786 break
1787 else:
1787 else:
1788 if opts.get('global'):
1788 if opts.get('global'):
1789 samplehgrc = uimod.samplehgrcs['global']
1789 samplehgrc = uimod.samplehgrcs['global']
1790 elif opts.get('local'):
1790 elif opts.get('local'):
1791 samplehgrc = uimod.samplehgrcs['local']
1791 samplehgrc = uimod.samplehgrcs['local']
1792 else:
1792 else:
1793 samplehgrc = uimod.samplehgrcs['user']
1793 samplehgrc = uimod.samplehgrcs['user']
1794
1794
1795 f = paths[0]
1795 f = paths[0]
1796 fp = open(f, "w")
1796 fp = open(f, "w")
1797 fp.write(samplehgrc)
1797 fp.write(samplehgrc)
1798 fp.close()
1798 fp.close()
1799
1799
1800 editor = ui.geteditor()
1800 editor = ui.geteditor()
1801 ui.system("%s \"%s\"" % (editor, f),
1801 ui.system("%s \"%s\"" % (editor, f),
1802 onerr=error.Abort, errprefix=_("edit failed"),
1802 onerr=error.Abort, errprefix=_("edit failed"),
1803 blockedtag='config_edit')
1803 blockedtag='config_edit')
1804 return
1804 return
1805 ui.pager('config')
1805 ui.pager('config')
1806 fm = ui.formatter('config', opts)
1806 fm = ui.formatter('config', opts)
1807 for f in rcutil.rccomponents():
1807 for t, f in rcutil.rccomponents():
1808 if t == 'path':
1808 ui.debug('read config from: %s\n' % f)
1809 ui.debug('read config from: %s\n' % f)
1810 else:
1811 raise error.ProgrammingError('unknown rctype: %s' % t)
1809 untrusted = bool(opts.get('untrusted'))
1812 untrusted = bool(opts.get('untrusted'))
1810 if values:
1813 if values:
1811 sections = [v for v in values if '.' not in v]
1814 sections = [v for v in values if '.' not in v]
1812 items = [v for v in values if '.' in v]
1815 items = [v for v in values if '.' in v]
1813 if len(items) > 1 or items and sections:
1816 if len(items) > 1 or items and sections:
1814 raise error.Abort(_('only one config item permitted'))
1817 raise error.Abort(_('only one config item permitted'))
1815 matched = False
1818 matched = False
1816 for section, name, value in ui.walkconfig(untrusted=untrusted):
1819 for section, name, value in ui.walkconfig(untrusted=untrusted):
1817 source = ui.configsource(section, name, untrusted)
1820 source = ui.configsource(section, name, untrusted)
1818 value = pycompat.bytestr(value)
1821 value = pycompat.bytestr(value)
1819 if fm.isplain():
1822 if fm.isplain():
1820 source = source or 'none'
1823 source = source or 'none'
1821 value = value.replace('\n', '\\n')
1824 value = value.replace('\n', '\\n')
1822 entryname = section + '.' + name
1825 entryname = section + '.' + name
1823 if values:
1826 if values:
1824 for v in values:
1827 for v in values:
1825 if v == section:
1828 if v == section:
1826 fm.startitem()
1829 fm.startitem()
1827 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1830 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.write('name value', '%s=%s\n', entryname, value)
1831 fm.write('name value', '%s=%s\n', entryname, value)
1829 matched = True
1832 matched = True
1830 elif v == entryname:
1833 elif v == entryname:
1831 fm.startitem()
1834 fm.startitem()
1832 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1835 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1833 fm.write('value', '%s\n', value)
1836 fm.write('value', '%s\n', value)
1834 fm.data(name=entryname)
1837 fm.data(name=entryname)
1835 matched = True
1838 matched = True
1836 else:
1839 else:
1837 fm.startitem()
1840 fm.startitem()
1838 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1841 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1839 fm.write('name value', '%s=%s\n', entryname, value)
1842 fm.write('name value', '%s=%s\n', entryname, value)
1840 matched = True
1843 matched = True
1841 fm.end()
1844 fm.end()
1842 if matched:
1845 if matched:
1843 return 0
1846 return 0
1844 return 1
1847 return 1
1845
1848
1846 @command('copy|cp',
1849 @command('copy|cp',
1847 [('A', 'after', None, _('record a copy that has already occurred')),
1850 [('A', 'after', None, _('record a copy that has already occurred')),
1848 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1851 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1849 ] + walkopts + dryrunopts,
1852 ] + walkopts + dryrunopts,
1850 _('[OPTION]... [SOURCE]... DEST'))
1853 _('[OPTION]... [SOURCE]... DEST'))
1851 def copy(ui, repo, *pats, **opts):
1854 def copy(ui, repo, *pats, **opts):
1852 """mark files as copied for the next commit
1855 """mark files as copied for the next commit
1853
1856
1854 Mark dest as having copies of source files. If dest is a
1857 Mark dest as having copies of source files. If dest is a
1855 directory, copies are put in that directory. If dest is a file,
1858 directory, copies are put in that directory. If dest is a file,
1856 the source must be a single file.
1859 the source must be a single file.
1857
1860
1858 By default, this command copies the contents of files as they
1861 By default, this command copies the contents of files as they
1859 exist in the working directory. If invoked with -A/--after, the
1862 exist in the working directory. If invoked with -A/--after, the
1860 operation is recorded, but no copying is performed.
1863 operation is recorded, but no copying is performed.
1861
1864
1862 This command takes effect with the next commit. To undo a copy
1865 This command takes effect with the next commit. To undo a copy
1863 before that, see :hg:`revert`.
1866 before that, see :hg:`revert`.
1864
1867
1865 Returns 0 on success, 1 if errors are encountered.
1868 Returns 0 on success, 1 if errors are encountered.
1866 """
1869 """
1867 with repo.wlock(False):
1870 with repo.wlock(False):
1868 return cmdutil.copy(ui, repo, pats, opts)
1871 return cmdutil.copy(ui, repo, pats, opts)
1869
1872
1870 @command('^diff',
1873 @command('^diff',
1871 [('r', 'rev', [], _('revision'), _('REV')),
1874 [('r', 'rev', [], _('revision'), _('REV')),
1872 ('c', 'change', '', _('change made by revision'), _('REV'))
1875 ('c', 'change', '', _('change made by revision'), _('REV'))
1873 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1876 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1874 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1877 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1875 inferrepo=True)
1878 inferrepo=True)
1876 def diff(ui, repo, *pats, **opts):
1879 def diff(ui, repo, *pats, **opts):
1877 """diff repository (or selected files)
1880 """diff repository (or selected files)
1878
1881
1879 Show differences between revisions for the specified files.
1882 Show differences between revisions for the specified files.
1880
1883
1881 Differences between files are shown using the unified diff format.
1884 Differences between files are shown using the unified diff format.
1882
1885
1883 .. note::
1886 .. note::
1884
1887
1885 :hg:`diff` may generate unexpected results for merges, as it will
1888 :hg:`diff` may generate unexpected results for merges, as it will
1886 default to comparing against the working directory's first
1889 default to comparing against the working directory's first
1887 parent changeset if no revisions are specified.
1890 parent changeset if no revisions are specified.
1888
1891
1889 When two revision arguments are given, then changes are shown
1892 When two revision arguments are given, then changes are shown
1890 between those revisions. If only one revision is specified then
1893 between those revisions. If only one revision is specified then
1891 that revision is compared to the working directory, and, when no
1894 that revision is compared to the working directory, and, when no
1892 revisions are specified, the working directory files are compared
1895 revisions are specified, the working directory files are compared
1893 to its first parent.
1896 to its first parent.
1894
1897
1895 Alternatively you can specify -c/--change with a revision to see
1898 Alternatively you can specify -c/--change with a revision to see
1896 the changes in that changeset relative to its first parent.
1899 the changes in that changeset relative to its first parent.
1897
1900
1898 Without the -a/--text option, diff will avoid generating diffs of
1901 Without the -a/--text option, diff will avoid generating diffs of
1899 files it detects as binary. With -a, diff will generate a diff
1902 files it detects as binary. With -a, diff will generate a diff
1900 anyway, probably with undesirable results.
1903 anyway, probably with undesirable results.
1901
1904
1902 Use the -g/--git option to generate diffs in the git extended diff
1905 Use the -g/--git option to generate diffs in the git extended diff
1903 format. For more information, read :hg:`help diffs`.
1906 format. For more information, read :hg:`help diffs`.
1904
1907
1905 .. container:: verbose
1908 .. container:: verbose
1906
1909
1907 Examples:
1910 Examples:
1908
1911
1909 - compare a file in the current working directory to its parent::
1912 - compare a file in the current working directory to its parent::
1910
1913
1911 hg diff foo.c
1914 hg diff foo.c
1912
1915
1913 - compare two historical versions of a directory, with rename info::
1916 - compare two historical versions of a directory, with rename info::
1914
1917
1915 hg diff --git -r 1.0:1.2 lib/
1918 hg diff --git -r 1.0:1.2 lib/
1916
1919
1917 - get change stats relative to the last change on some date::
1920 - get change stats relative to the last change on some date::
1918
1921
1919 hg diff --stat -r "date('may 2')"
1922 hg diff --stat -r "date('may 2')"
1920
1923
1921 - diff all newly-added files that contain a keyword::
1924 - diff all newly-added files that contain a keyword::
1922
1925
1923 hg diff "set:added() and grep(GNU)"
1926 hg diff "set:added() and grep(GNU)"
1924
1927
1925 - compare a revision and its parents::
1928 - compare a revision and its parents::
1926
1929
1927 hg diff -c 9353 # compare against first parent
1930 hg diff -c 9353 # compare against first parent
1928 hg diff -r 9353^:9353 # same using revset syntax
1931 hg diff -r 9353^:9353 # same using revset syntax
1929 hg diff -r 9353^2:9353 # compare against the second parent
1932 hg diff -r 9353^2:9353 # compare against the second parent
1930
1933
1931 Returns 0 on success.
1934 Returns 0 on success.
1932 """
1935 """
1933
1936
1934 revs = opts.get('rev')
1937 revs = opts.get('rev')
1935 change = opts.get('change')
1938 change = opts.get('change')
1936 stat = opts.get('stat')
1939 stat = opts.get('stat')
1937 reverse = opts.get('reverse')
1940 reverse = opts.get('reverse')
1938
1941
1939 if revs and change:
1942 if revs and change:
1940 msg = _('cannot specify --rev and --change at the same time')
1943 msg = _('cannot specify --rev and --change at the same time')
1941 raise error.Abort(msg)
1944 raise error.Abort(msg)
1942 elif change:
1945 elif change:
1943 node2 = scmutil.revsingle(repo, change, None).node()
1946 node2 = scmutil.revsingle(repo, change, None).node()
1944 node1 = repo[node2].p1().node()
1947 node1 = repo[node2].p1().node()
1945 else:
1948 else:
1946 node1, node2 = scmutil.revpair(repo, revs)
1949 node1, node2 = scmutil.revpair(repo, revs)
1947
1950
1948 if reverse:
1951 if reverse:
1949 node1, node2 = node2, node1
1952 node1, node2 = node2, node1
1950
1953
1951 diffopts = patch.diffallopts(ui, opts)
1954 diffopts = patch.diffallopts(ui, opts)
1952 m = scmutil.match(repo[node2], pats, opts)
1955 m = scmutil.match(repo[node2], pats, opts)
1953 ui.pager('diff')
1956 ui.pager('diff')
1954 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1957 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1955 listsubrepos=opts.get('subrepos'),
1958 listsubrepos=opts.get('subrepos'),
1956 root=opts.get('root'))
1959 root=opts.get('root'))
1957
1960
1958 @command('^export',
1961 @command('^export',
1959 [('o', 'output', '',
1962 [('o', 'output', '',
1960 _('print output to file with formatted name'), _('FORMAT')),
1963 _('print output to file with formatted name'), _('FORMAT')),
1961 ('', 'switch-parent', None, _('diff against the second parent')),
1964 ('', 'switch-parent', None, _('diff against the second parent')),
1962 ('r', 'rev', [], _('revisions to export'), _('REV')),
1965 ('r', 'rev', [], _('revisions to export'), _('REV')),
1963 ] + diffopts,
1966 ] + diffopts,
1964 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1967 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1965 def export(ui, repo, *changesets, **opts):
1968 def export(ui, repo, *changesets, **opts):
1966 """dump the header and diffs for one or more changesets
1969 """dump the header and diffs for one or more changesets
1967
1970
1968 Print the changeset header and diffs for one or more revisions.
1971 Print the changeset header and diffs for one or more revisions.
1969 If no revision is given, the parent of the working directory is used.
1972 If no revision is given, the parent of the working directory is used.
1970
1973
1971 The information shown in the changeset header is: author, date,
1974 The information shown in the changeset header is: author, date,
1972 branch name (if non-default), changeset hash, parent(s) and commit
1975 branch name (if non-default), changeset hash, parent(s) and commit
1973 comment.
1976 comment.
1974
1977
1975 .. note::
1978 .. note::
1976
1979
1977 :hg:`export` may generate unexpected diff output for merge
1980 :hg:`export` may generate unexpected diff output for merge
1978 changesets, as it will compare the merge changeset against its
1981 changesets, as it will compare the merge changeset against its
1979 first parent only.
1982 first parent only.
1980
1983
1981 Output may be to a file, in which case the name of the file is
1984 Output may be to a file, in which case the name of the file is
1982 given using a format string. The formatting rules are as follows:
1985 given using a format string. The formatting rules are as follows:
1983
1986
1984 :``%%``: literal "%" character
1987 :``%%``: literal "%" character
1985 :``%H``: changeset hash (40 hexadecimal digits)
1988 :``%H``: changeset hash (40 hexadecimal digits)
1986 :``%N``: number of patches being generated
1989 :``%N``: number of patches being generated
1987 :``%R``: changeset revision number
1990 :``%R``: changeset revision number
1988 :``%b``: basename of the exporting repository
1991 :``%b``: basename of the exporting repository
1989 :``%h``: short-form changeset hash (12 hexadecimal digits)
1992 :``%h``: short-form changeset hash (12 hexadecimal digits)
1990 :``%m``: first line of the commit message (only alphanumeric characters)
1993 :``%m``: first line of the commit message (only alphanumeric characters)
1991 :``%n``: zero-padded sequence number, starting at 1
1994 :``%n``: zero-padded sequence number, starting at 1
1992 :``%r``: zero-padded changeset revision number
1995 :``%r``: zero-padded changeset revision number
1993
1996
1994 Without the -a/--text option, export will avoid generating diffs
1997 Without the -a/--text option, export will avoid generating diffs
1995 of files it detects as binary. With -a, export will generate a
1998 of files it detects as binary. With -a, export will generate a
1996 diff anyway, probably with undesirable results.
1999 diff anyway, probably with undesirable results.
1997
2000
1998 Use the -g/--git option to generate diffs in the git extended diff
2001 Use the -g/--git option to generate diffs in the git extended diff
1999 format. See :hg:`help diffs` for more information.
2002 format. See :hg:`help diffs` for more information.
2000
2003
2001 With the --switch-parent option, the diff will be against the
2004 With the --switch-parent option, the diff will be against the
2002 second parent. It can be useful to review a merge.
2005 second parent. It can be useful to review a merge.
2003
2006
2004 .. container:: verbose
2007 .. container:: verbose
2005
2008
2006 Examples:
2009 Examples:
2007
2010
2008 - use export and import to transplant a bugfix to the current
2011 - use export and import to transplant a bugfix to the current
2009 branch::
2012 branch::
2010
2013
2011 hg export -r 9353 | hg import -
2014 hg export -r 9353 | hg import -
2012
2015
2013 - export all the changesets between two revisions to a file with
2016 - export all the changesets between two revisions to a file with
2014 rename information::
2017 rename information::
2015
2018
2016 hg export --git -r 123:150 > changes.txt
2019 hg export --git -r 123:150 > changes.txt
2017
2020
2018 - split outgoing changes into a series of patches with
2021 - split outgoing changes into a series of patches with
2019 descriptive names::
2022 descriptive names::
2020
2023
2021 hg export -r "outgoing()" -o "%n-%m.patch"
2024 hg export -r "outgoing()" -o "%n-%m.patch"
2022
2025
2023 Returns 0 on success.
2026 Returns 0 on success.
2024 """
2027 """
2025 changesets += tuple(opts.get('rev', []))
2028 changesets += tuple(opts.get('rev', []))
2026 if not changesets:
2029 if not changesets:
2027 changesets = ['.']
2030 changesets = ['.']
2028 revs = scmutil.revrange(repo, changesets)
2031 revs = scmutil.revrange(repo, changesets)
2029 if not revs:
2032 if not revs:
2030 raise error.Abort(_("export requires at least one changeset"))
2033 raise error.Abort(_("export requires at least one changeset"))
2031 if len(revs) > 1:
2034 if len(revs) > 1:
2032 ui.note(_('exporting patches:\n'))
2035 ui.note(_('exporting patches:\n'))
2033 else:
2036 else:
2034 ui.note(_('exporting patch:\n'))
2037 ui.note(_('exporting patch:\n'))
2035 ui.pager('export')
2038 ui.pager('export')
2036 cmdutil.export(repo, revs, template=opts.get('output'),
2039 cmdutil.export(repo, revs, template=opts.get('output'),
2037 switch_parent=opts.get('switch_parent'),
2040 switch_parent=opts.get('switch_parent'),
2038 opts=patch.diffallopts(ui, opts))
2041 opts=patch.diffallopts(ui, opts))
2039
2042
2040 @command('files',
2043 @command('files',
2041 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2044 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2042 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2045 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2043 ] + walkopts + formatteropts + subrepoopts,
2046 ] + walkopts + formatteropts + subrepoopts,
2044 _('[OPTION]... [FILE]...'))
2047 _('[OPTION]... [FILE]...'))
2045 def files(ui, repo, *pats, **opts):
2048 def files(ui, repo, *pats, **opts):
2046 """list tracked files
2049 """list tracked files
2047
2050
2048 Print files under Mercurial control in the working directory or
2051 Print files under Mercurial control in the working directory or
2049 specified revision for given files (excluding removed files).
2052 specified revision for given files (excluding removed files).
2050 Files can be specified as filenames or filesets.
2053 Files can be specified as filenames or filesets.
2051
2054
2052 If no files are given to match, this command prints the names
2055 If no files are given to match, this command prints the names
2053 of all files under Mercurial control.
2056 of all files under Mercurial control.
2054
2057
2055 .. container:: verbose
2058 .. container:: verbose
2056
2059
2057 Examples:
2060 Examples:
2058
2061
2059 - list all files under the current directory::
2062 - list all files under the current directory::
2060
2063
2061 hg files .
2064 hg files .
2062
2065
2063 - shows sizes and flags for current revision::
2066 - shows sizes and flags for current revision::
2064
2067
2065 hg files -vr .
2068 hg files -vr .
2066
2069
2067 - list all files named README::
2070 - list all files named README::
2068
2071
2069 hg files -I "**/README"
2072 hg files -I "**/README"
2070
2073
2071 - list all binary files::
2074 - list all binary files::
2072
2075
2073 hg files "set:binary()"
2076 hg files "set:binary()"
2074
2077
2075 - find files containing a regular expression::
2078 - find files containing a regular expression::
2076
2079
2077 hg files "set:grep('bob')"
2080 hg files "set:grep('bob')"
2078
2081
2079 - search tracked file contents with xargs and grep::
2082 - search tracked file contents with xargs and grep::
2080
2083
2081 hg files -0 | xargs -0 grep foo
2084 hg files -0 | xargs -0 grep foo
2082
2085
2083 See :hg:`help patterns` and :hg:`help filesets` for more information
2086 See :hg:`help patterns` and :hg:`help filesets` for more information
2084 on specifying file patterns.
2087 on specifying file patterns.
2085
2088
2086 Returns 0 if a match is found, 1 otherwise.
2089 Returns 0 if a match is found, 1 otherwise.
2087
2090
2088 """
2091 """
2089 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
2092 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
2090
2093
2091 end = '\n'
2094 end = '\n'
2092 if opts.get('print0'):
2095 if opts.get('print0'):
2093 end = '\0'
2096 end = '\0'
2094 fmt = '%s' + end
2097 fmt = '%s' + end
2095
2098
2096 m = scmutil.match(ctx, pats, opts)
2099 m = scmutil.match(ctx, pats, opts)
2097 ui.pager('files')
2100 ui.pager('files')
2098 with ui.formatter('files', opts) as fm:
2101 with ui.formatter('files', opts) as fm:
2099 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2102 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2100
2103
2101 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2104 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2102 def forget(ui, repo, *pats, **opts):
2105 def forget(ui, repo, *pats, **opts):
2103 """forget the specified files on the next commit
2106 """forget the specified files on the next commit
2104
2107
2105 Mark the specified files so they will no longer be tracked
2108 Mark the specified files so they will no longer be tracked
2106 after the next commit.
2109 after the next commit.
2107
2110
2108 This only removes files from the current branch, not from the
2111 This only removes files from the current branch, not from the
2109 entire project history, and it does not delete them from the
2112 entire project history, and it does not delete them from the
2110 working directory.
2113 working directory.
2111
2114
2112 To delete the file from the working directory, see :hg:`remove`.
2115 To delete the file from the working directory, see :hg:`remove`.
2113
2116
2114 To undo a forget before the next commit, see :hg:`add`.
2117 To undo a forget before the next commit, see :hg:`add`.
2115
2118
2116 .. container:: verbose
2119 .. container:: verbose
2117
2120
2118 Examples:
2121 Examples:
2119
2122
2120 - forget newly-added binary files::
2123 - forget newly-added binary files::
2121
2124
2122 hg forget "set:added() and binary()"
2125 hg forget "set:added() and binary()"
2123
2126
2124 - forget files that would be excluded by .hgignore::
2127 - forget files that would be excluded by .hgignore::
2125
2128
2126 hg forget "set:hgignore()"
2129 hg forget "set:hgignore()"
2127
2130
2128 Returns 0 on success.
2131 Returns 0 on success.
2129 """
2132 """
2130
2133
2131 if not pats:
2134 if not pats:
2132 raise error.Abort(_('no files specified'))
2135 raise error.Abort(_('no files specified'))
2133
2136
2134 m = scmutil.match(repo[None], pats, opts)
2137 m = scmutil.match(repo[None], pats, opts)
2135 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2138 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2136 return rejected and 1 or 0
2139 return rejected and 1 or 0
2137
2140
2138 @command(
2141 @command(
2139 'graft',
2142 'graft',
2140 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2143 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2141 ('c', 'continue', False, _('resume interrupted graft')),
2144 ('c', 'continue', False, _('resume interrupted graft')),
2142 ('e', 'edit', False, _('invoke editor on commit messages')),
2145 ('e', 'edit', False, _('invoke editor on commit messages')),
2143 ('', 'log', None, _('append graft info to log message')),
2146 ('', 'log', None, _('append graft info to log message')),
2144 ('f', 'force', False, _('force graft')),
2147 ('f', 'force', False, _('force graft')),
2145 ('D', 'currentdate', False,
2148 ('D', 'currentdate', False,
2146 _('record the current date as commit date')),
2149 _('record the current date as commit date')),
2147 ('U', 'currentuser', False,
2150 ('U', 'currentuser', False,
2148 _('record the current user as committer'), _('DATE'))]
2151 _('record the current user as committer'), _('DATE'))]
2149 + commitopts2 + mergetoolopts + dryrunopts,
2152 + commitopts2 + mergetoolopts + dryrunopts,
2150 _('[OPTION]... [-r REV]... REV...'))
2153 _('[OPTION]... [-r REV]... REV...'))
2151 def graft(ui, repo, *revs, **opts):
2154 def graft(ui, repo, *revs, **opts):
2152 '''copy changes from other branches onto the current branch
2155 '''copy changes from other branches onto the current branch
2153
2156
2154 This command uses Mercurial's merge logic to copy individual
2157 This command uses Mercurial's merge logic to copy individual
2155 changes from other branches without merging branches in the
2158 changes from other branches without merging branches in the
2156 history graph. This is sometimes known as 'backporting' or
2159 history graph. This is sometimes known as 'backporting' or
2157 'cherry-picking'. By default, graft will copy user, date, and
2160 'cherry-picking'. By default, graft will copy user, date, and
2158 description from the source changesets.
2161 description from the source changesets.
2159
2162
2160 Changesets that are ancestors of the current revision, that have
2163 Changesets that are ancestors of the current revision, that have
2161 already been grafted, or that are merges will be skipped.
2164 already been grafted, or that are merges will be skipped.
2162
2165
2163 If --log is specified, log messages will have a comment appended
2166 If --log is specified, log messages will have a comment appended
2164 of the form::
2167 of the form::
2165
2168
2166 (grafted from CHANGESETHASH)
2169 (grafted from CHANGESETHASH)
2167
2170
2168 If --force is specified, revisions will be grafted even if they
2171 If --force is specified, revisions will be grafted even if they
2169 are already ancestors of or have been grafted to the destination.
2172 are already ancestors of or have been grafted to the destination.
2170 This is useful when the revisions have since been backed out.
2173 This is useful when the revisions have since been backed out.
2171
2174
2172 If a graft merge results in conflicts, the graft process is
2175 If a graft merge results in conflicts, the graft process is
2173 interrupted so that the current merge can be manually resolved.
2176 interrupted so that the current merge can be manually resolved.
2174 Once all conflicts are addressed, the graft process can be
2177 Once all conflicts are addressed, the graft process can be
2175 continued with the -c/--continue option.
2178 continued with the -c/--continue option.
2176
2179
2177 .. note::
2180 .. note::
2178
2181
2179 The -c/--continue option does not reapply earlier options, except
2182 The -c/--continue option does not reapply earlier options, except
2180 for --force.
2183 for --force.
2181
2184
2182 .. container:: verbose
2185 .. container:: verbose
2183
2186
2184 Examples:
2187 Examples:
2185
2188
2186 - copy a single change to the stable branch and edit its description::
2189 - copy a single change to the stable branch and edit its description::
2187
2190
2188 hg update stable
2191 hg update stable
2189 hg graft --edit 9393
2192 hg graft --edit 9393
2190
2193
2191 - graft a range of changesets with one exception, updating dates::
2194 - graft a range of changesets with one exception, updating dates::
2192
2195
2193 hg graft -D "2085::2093 and not 2091"
2196 hg graft -D "2085::2093 and not 2091"
2194
2197
2195 - continue a graft after resolving conflicts::
2198 - continue a graft after resolving conflicts::
2196
2199
2197 hg graft -c
2200 hg graft -c
2198
2201
2199 - show the source of a grafted changeset::
2202 - show the source of a grafted changeset::
2200
2203
2201 hg log --debug -r .
2204 hg log --debug -r .
2202
2205
2203 - show revisions sorted by date::
2206 - show revisions sorted by date::
2204
2207
2205 hg log -r "sort(all(), date)"
2208 hg log -r "sort(all(), date)"
2206
2209
2207 See :hg:`help revisions` for more about specifying revisions.
2210 See :hg:`help revisions` for more about specifying revisions.
2208
2211
2209 Returns 0 on successful completion.
2212 Returns 0 on successful completion.
2210 '''
2213 '''
2211 with repo.wlock():
2214 with repo.wlock():
2212 return _dograft(ui, repo, *revs, **opts)
2215 return _dograft(ui, repo, *revs, **opts)
2213
2216
2214 def _dograft(ui, repo, *revs, **opts):
2217 def _dograft(ui, repo, *revs, **opts):
2215 if revs and opts.get('rev'):
2218 if revs and opts.get('rev'):
2216 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2219 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2217 'revision ordering!\n'))
2220 'revision ordering!\n'))
2218
2221
2219 revs = list(revs)
2222 revs = list(revs)
2220 revs.extend(opts.get('rev'))
2223 revs.extend(opts.get('rev'))
2221
2224
2222 if not opts.get('user') and opts.get('currentuser'):
2225 if not opts.get('user') and opts.get('currentuser'):
2223 opts['user'] = ui.username()
2226 opts['user'] = ui.username()
2224 if not opts.get('date') and opts.get('currentdate'):
2227 if not opts.get('date') and opts.get('currentdate'):
2225 opts['date'] = "%d %d" % util.makedate()
2228 opts['date'] = "%d %d" % util.makedate()
2226
2229
2227 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2230 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2228
2231
2229 cont = False
2232 cont = False
2230 if opts.get('continue'):
2233 if opts.get('continue'):
2231 cont = True
2234 cont = True
2232 if revs:
2235 if revs:
2233 raise error.Abort(_("can't specify --continue and revisions"))
2236 raise error.Abort(_("can't specify --continue and revisions"))
2234 # read in unfinished revisions
2237 # read in unfinished revisions
2235 try:
2238 try:
2236 nodes = repo.vfs.read('graftstate').splitlines()
2239 nodes = repo.vfs.read('graftstate').splitlines()
2237 revs = [repo[node].rev() for node in nodes]
2240 revs = [repo[node].rev() for node in nodes]
2238 except IOError as inst:
2241 except IOError as inst:
2239 if inst.errno != errno.ENOENT:
2242 if inst.errno != errno.ENOENT:
2240 raise
2243 raise
2241 cmdutil.wrongtooltocontinue(repo, _('graft'))
2244 cmdutil.wrongtooltocontinue(repo, _('graft'))
2242 else:
2245 else:
2243 cmdutil.checkunfinished(repo)
2246 cmdutil.checkunfinished(repo)
2244 cmdutil.bailifchanged(repo)
2247 cmdutil.bailifchanged(repo)
2245 if not revs:
2248 if not revs:
2246 raise error.Abort(_('no revisions specified'))
2249 raise error.Abort(_('no revisions specified'))
2247 revs = scmutil.revrange(repo, revs)
2250 revs = scmutil.revrange(repo, revs)
2248
2251
2249 skipped = set()
2252 skipped = set()
2250 # check for merges
2253 # check for merges
2251 for rev in repo.revs('%ld and merge()', revs):
2254 for rev in repo.revs('%ld and merge()', revs):
2252 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2255 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2253 skipped.add(rev)
2256 skipped.add(rev)
2254 revs = [r for r in revs if r not in skipped]
2257 revs = [r for r in revs if r not in skipped]
2255 if not revs:
2258 if not revs:
2256 return -1
2259 return -1
2257
2260
2258 # Don't check in the --continue case, in effect retaining --force across
2261 # Don't check in the --continue case, in effect retaining --force across
2259 # --continues. That's because without --force, any revisions we decided to
2262 # --continues. That's because without --force, any revisions we decided to
2260 # skip would have been filtered out here, so they wouldn't have made their
2263 # skip would have been filtered out here, so they wouldn't have made their
2261 # way to the graftstate. With --force, any revisions we would have otherwise
2264 # way to the graftstate. With --force, any revisions we would have otherwise
2262 # skipped would not have been filtered out, and if they hadn't been applied
2265 # skipped would not have been filtered out, and if they hadn't been applied
2263 # already, they'd have been in the graftstate.
2266 # already, they'd have been in the graftstate.
2264 if not (cont or opts.get('force')):
2267 if not (cont or opts.get('force')):
2265 # check for ancestors of dest branch
2268 # check for ancestors of dest branch
2266 crev = repo['.'].rev()
2269 crev = repo['.'].rev()
2267 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2270 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2268 # XXX make this lazy in the future
2271 # XXX make this lazy in the future
2269 # don't mutate while iterating, create a copy
2272 # don't mutate while iterating, create a copy
2270 for rev in list(revs):
2273 for rev in list(revs):
2271 if rev in ancestors:
2274 if rev in ancestors:
2272 ui.warn(_('skipping ancestor revision %d:%s\n') %
2275 ui.warn(_('skipping ancestor revision %d:%s\n') %
2273 (rev, repo[rev]))
2276 (rev, repo[rev]))
2274 # XXX remove on list is slow
2277 # XXX remove on list is slow
2275 revs.remove(rev)
2278 revs.remove(rev)
2276 if not revs:
2279 if not revs:
2277 return -1
2280 return -1
2278
2281
2279 # analyze revs for earlier grafts
2282 # analyze revs for earlier grafts
2280 ids = {}
2283 ids = {}
2281 for ctx in repo.set("%ld", revs):
2284 for ctx in repo.set("%ld", revs):
2282 ids[ctx.hex()] = ctx.rev()
2285 ids[ctx.hex()] = ctx.rev()
2283 n = ctx.extra().get('source')
2286 n = ctx.extra().get('source')
2284 if n:
2287 if n:
2285 ids[n] = ctx.rev()
2288 ids[n] = ctx.rev()
2286
2289
2287 # check ancestors for earlier grafts
2290 # check ancestors for earlier grafts
2288 ui.debug('scanning for duplicate grafts\n')
2291 ui.debug('scanning for duplicate grafts\n')
2289
2292
2290 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2293 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2291 ctx = repo[rev]
2294 ctx = repo[rev]
2292 n = ctx.extra().get('source')
2295 n = ctx.extra().get('source')
2293 if n in ids:
2296 if n in ids:
2294 try:
2297 try:
2295 r = repo[n].rev()
2298 r = repo[n].rev()
2296 except error.RepoLookupError:
2299 except error.RepoLookupError:
2297 r = None
2300 r = None
2298 if r in revs:
2301 if r in revs:
2299 ui.warn(_('skipping revision %d:%s '
2302 ui.warn(_('skipping revision %d:%s '
2300 '(already grafted to %d:%s)\n')
2303 '(already grafted to %d:%s)\n')
2301 % (r, repo[r], rev, ctx))
2304 % (r, repo[r], rev, ctx))
2302 revs.remove(r)
2305 revs.remove(r)
2303 elif ids[n] in revs:
2306 elif ids[n] in revs:
2304 if r is None:
2307 if r is None:
2305 ui.warn(_('skipping already grafted revision %d:%s '
2308 ui.warn(_('skipping already grafted revision %d:%s '
2306 '(%d:%s also has unknown origin %s)\n')
2309 '(%d:%s also has unknown origin %s)\n')
2307 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2310 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2308 else:
2311 else:
2309 ui.warn(_('skipping already grafted revision %d:%s '
2312 ui.warn(_('skipping already grafted revision %d:%s '
2310 '(%d:%s also has origin %d:%s)\n')
2313 '(%d:%s also has origin %d:%s)\n')
2311 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2314 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2312 revs.remove(ids[n])
2315 revs.remove(ids[n])
2313 elif ctx.hex() in ids:
2316 elif ctx.hex() in ids:
2314 r = ids[ctx.hex()]
2317 r = ids[ctx.hex()]
2315 ui.warn(_('skipping already grafted revision %d:%s '
2318 ui.warn(_('skipping already grafted revision %d:%s '
2316 '(was grafted from %d:%s)\n') %
2319 '(was grafted from %d:%s)\n') %
2317 (r, repo[r], rev, ctx))
2320 (r, repo[r], rev, ctx))
2318 revs.remove(r)
2321 revs.remove(r)
2319 if not revs:
2322 if not revs:
2320 return -1
2323 return -1
2321
2324
2322 for pos, ctx in enumerate(repo.set("%ld", revs)):
2325 for pos, ctx in enumerate(repo.set("%ld", revs)):
2323 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2326 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2324 ctx.description().split('\n', 1)[0])
2327 ctx.description().split('\n', 1)[0])
2325 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2328 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2326 if names:
2329 if names:
2327 desc += ' (%s)' % ' '.join(names)
2330 desc += ' (%s)' % ' '.join(names)
2328 ui.status(_('grafting %s\n') % desc)
2331 ui.status(_('grafting %s\n') % desc)
2329 if opts.get('dry_run'):
2332 if opts.get('dry_run'):
2330 continue
2333 continue
2331
2334
2332 source = ctx.extra().get('source')
2335 source = ctx.extra().get('source')
2333 extra = {}
2336 extra = {}
2334 if source:
2337 if source:
2335 extra['source'] = source
2338 extra['source'] = source
2336 extra['intermediate-source'] = ctx.hex()
2339 extra['intermediate-source'] = ctx.hex()
2337 else:
2340 else:
2338 extra['source'] = ctx.hex()
2341 extra['source'] = ctx.hex()
2339 user = ctx.user()
2342 user = ctx.user()
2340 if opts.get('user'):
2343 if opts.get('user'):
2341 user = opts['user']
2344 user = opts['user']
2342 date = ctx.date()
2345 date = ctx.date()
2343 if opts.get('date'):
2346 if opts.get('date'):
2344 date = opts['date']
2347 date = opts['date']
2345 message = ctx.description()
2348 message = ctx.description()
2346 if opts.get('log'):
2349 if opts.get('log'):
2347 message += '\n(grafted from %s)' % ctx.hex()
2350 message += '\n(grafted from %s)' % ctx.hex()
2348
2351
2349 # we don't merge the first commit when continuing
2352 # we don't merge the first commit when continuing
2350 if not cont:
2353 if not cont:
2351 # perform the graft merge with p1(rev) as 'ancestor'
2354 # perform the graft merge with p1(rev) as 'ancestor'
2352 try:
2355 try:
2353 # ui.forcemerge is an internal variable, do not document
2356 # ui.forcemerge is an internal variable, do not document
2354 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2357 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2355 'graft')
2358 'graft')
2356 stats = mergemod.graft(repo, ctx, ctx.p1(),
2359 stats = mergemod.graft(repo, ctx, ctx.p1(),
2357 ['local', 'graft'])
2360 ['local', 'graft'])
2358 finally:
2361 finally:
2359 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2362 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2360 # report any conflicts
2363 # report any conflicts
2361 if stats and stats[3] > 0:
2364 if stats and stats[3] > 0:
2362 # write out state for --continue
2365 # write out state for --continue
2363 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2366 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2364 repo.vfs.write('graftstate', ''.join(nodelines))
2367 repo.vfs.write('graftstate', ''.join(nodelines))
2365 extra = ''
2368 extra = ''
2366 if opts.get('user'):
2369 if opts.get('user'):
2367 extra += ' --user %s' % util.shellquote(opts['user'])
2370 extra += ' --user %s' % util.shellquote(opts['user'])
2368 if opts.get('date'):
2371 if opts.get('date'):
2369 extra += ' --date %s' % util.shellquote(opts['date'])
2372 extra += ' --date %s' % util.shellquote(opts['date'])
2370 if opts.get('log'):
2373 if opts.get('log'):
2371 extra += ' --log'
2374 extra += ' --log'
2372 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2375 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2373 raise error.Abort(
2376 raise error.Abort(
2374 _("unresolved conflicts, can't continue"),
2377 _("unresolved conflicts, can't continue"),
2375 hint=hint)
2378 hint=hint)
2376 else:
2379 else:
2377 cont = False
2380 cont = False
2378
2381
2379 # commit
2382 # commit
2380 node = repo.commit(text=message, user=user,
2383 node = repo.commit(text=message, user=user,
2381 date=date, extra=extra, editor=editor)
2384 date=date, extra=extra, editor=editor)
2382 if node is None:
2385 if node is None:
2383 ui.warn(
2386 ui.warn(
2384 _('note: graft of %d:%s created no changes to commit\n') %
2387 _('note: graft of %d:%s created no changes to commit\n') %
2385 (ctx.rev(), ctx))
2388 (ctx.rev(), ctx))
2386
2389
2387 # remove state when we complete successfully
2390 # remove state when we complete successfully
2388 if not opts.get('dry_run'):
2391 if not opts.get('dry_run'):
2389 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2392 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2390
2393
2391 return 0
2394 return 0
2392
2395
2393 @command('grep',
2396 @command('grep',
2394 [('0', 'print0', None, _('end fields with NUL')),
2397 [('0', 'print0', None, _('end fields with NUL')),
2395 ('', 'all', None, _('print all revisions that match')),
2398 ('', 'all', None, _('print all revisions that match')),
2396 ('a', 'text', None, _('treat all files as text')),
2399 ('a', 'text', None, _('treat all files as text')),
2397 ('f', 'follow', None,
2400 ('f', 'follow', None,
2398 _('follow changeset history,'
2401 _('follow changeset history,'
2399 ' or file history across copies and renames')),
2402 ' or file history across copies and renames')),
2400 ('i', 'ignore-case', None, _('ignore case when matching')),
2403 ('i', 'ignore-case', None, _('ignore case when matching')),
2401 ('l', 'files-with-matches', None,
2404 ('l', 'files-with-matches', None,
2402 _('print only filenames and revisions that match')),
2405 _('print only filenames and revisions that match')),
2403 ('n', 'line-number', None, _('print matching line numbers')),
2406 ('n', 'line-number', None, _('print matching line numbers')),
2404 ('r', 'rev', [],
2407 ('r', 'rev', [],
2405 _('only search files changed within revision range'), _('REV')),
2408 _('only search files changed within revision range'), _('REV')),
2406 ('u', 'user', None, _('list the author (long with -v)')),
2409 ('u', 'user', None, _('list the author (long with -v)')),
2407 ('d', 'date', None, _('list the date (short with -q)')),
2410 ('d', 'date', None, _('list the date (short with -q)')),
2408 ] + formatteropts + walkopts,
2411 ] + formatteropts + walkopts,
2409 _('[OPTION]... PATTERN [FILE]...'),
2412 _('[OPTION]... PATTERN [FILE]...'),
2410 inferrepo=True)
2413 inferrepo=True)
2411 def grep(ui, repo, pattern, *pats, **opts):
2414 def grep(ui, repo, pattern, *pats, **opts):
2412 """search revision history for a pattern in specified files
2415 """search revision history for a pattern in specified files
2413
2416
2414 Search revision history for a regular expression in the specified
2417 Search revision history for a regular expression in the specified
2415 files or the entire project.
2418 files or the entire project.
2416
2419
2417 By default, grep prints the most recent revision number for each
2420 By default, grep prints the most recent revision number for each
2418 file in which it finds a match. To get it to print every revision
2421 file in which it finds a match. To get it to print every revision
2419 that contains a change in match status ("-" for a match that becomes
2422 that contains a change in match status ("-" for a match that becomes
2420 a non-match, or "+" for a non-match that becomes a match), use the
2423 a non-match, or "+" for a non-match that becomes a match), use the
2421 --all flag.
2424 --all flag.
2422
2425
2423 PATTERN can be any Python (roughly Perl-compatible) regular
2426 PATTERN can be any Python (roughly Perl-compatible) regular
2424 expression.
2427 expression.
2425
2428
2426 If no FILEs are specified (and -f/--follow isn't set), all files in
2429 If no FILEs are specified (and -f/--follow isn't set), all files in
2427 the repository are searched, including those that don't exist in the
2430 the repository are searched, including those that don't exist in the
2428 current branch or have been deleted in a prior changeset.
2431 current branch or have been deleted in a prior changeset.
2429
2432
2430 Returns 0 if a match is found, 1 otherwise.
2433 Returns 0 if a match is found, 1 otherwise.
2431 """
2434 """
2432 reflags = re.M
2435 reflags = re.M
2433 if opts.get('ignore_case'):
2436 if opts.get('ignore_case'):
2434 reflags |= re.I
2437 reflags |= re.I
2435 try:
2438 try:
2436 regexp = util.re.compile(pattern, reflags)
2439 regexp = util.re.compile(pattern, reflags)
2437 except re.error as inst:
2440 except re.error as inst:
2438 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2441 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2439 return 1
2442 return 1
2440 sep, eol = ':', '\n'
2443 sep, eol = ':', '\n'
2441 if opts.get('print0'):
2444 if opts.get('print0'):
2442 sep = eol = '\0'
2445 sep = eol = '\0'
2443
2446
2444 getfile = util.lrucachefunc(repo.file)
2447 getfile = util.lrucachefunc(repo.file)
2445
2448
2446 def matchlines(body):
2449 def matchlines(body):
2447 begin = 0
2450 begin = 0
2448 linenum = 0
2451 linenum = 0
2449 while begin < len(body):
2452 while begin < len(body):
2450 match = regexp.search(body, begin)
2453 match = regexp.search(body, begin)
2451 if not match:
2454 if not match:
2452 break
2455 break
2453 mstart, mend = match.span()
2456 mstart, mend = match.span()
2454 linenum += body.count('\n', begin, mstart) + 1
2457 linenum += body.count('\n', begin, mstart) + 1
2455 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2458 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2456 begin = body.find('\n', mend) + 1 or len(body) + 1
2459 begin = body.find('\n', mend) + 1 or len(body) + 1
2457 lend = begin - 1
2460 lend = begin - 1
2458 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2461 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2459
2462
2460 class linestate(object):
2463 class linestate(object):
2461 def __init__(self, line, linenum, colstart, colend):
2464 def __init__(self, line, linenum, colstart, colend):
2462 self.line = line
2465 self.line = line
2463 self.linenum = linenum
2466 self.linenum = linenum
2464 self.colstart = colstart
2467 self.colstart = colstart
2465 self.colend = colend
2468 self.colend = colend
2466
2469
2467 def __hash__(self):
2470 def __hash__(self):
2468 return hash((self.linenum, self.line))
2471 return hash((self.linenum, self.line))
2469
2472
2470 def __eq__(self, other):
2473 def __eq__(self, other):
2471 return self.line == other.line
2474 return self.line == other.line
2472
2475
2473 def findpos(self):
2476 def findpos(self):
2474 """Iterate all (start, end) indices of matches"""
2477 """Iterate all (start, end) indices of matches"""
2475 yield self.colstart, self.colend
2478 yield self.colstart, self.colend
2476 p = self.colend
2479 p = self.colend
2477 while p < len(self.line):
2480 while p < len(self.line):
2478 m = regexp.search(self.line, p)
2481 m = regexp.search(self.line, p)
2479 if not m:
2482 if not m:
2480 break
2483 break
2481 yield m.span()
2484 yield m.span()
2482 p = m.end()
2485 p = m.end()
2483
2486
2484 matches = {}
2487 matches = {}
2485 copies = {}
2488 copies = {}
2486 def grepbody(fn, rev, body):
2489 def grepbody(fn, rev, body):
2487 matches[rev].setdefault(fn, [])
2490 matches[rev].setdefault(fn, [])
2488 m = matches[rev][fn]
2491 m = matches[rev][fn]
2489 for lnum, cstart, cend, line in matchlines(body):
2492 for lnum, cstart, cend, line in matchlines(body):
2490 s = linestate(line, lnum, cstart, cend)
2493 s = linestate(line, lnum, cstart, cend)
2491 m.append(s)
2494 m.append(s)
2492
2495
2493 def difflinestates(a, b):
2496 def difflinestates(a, b):
2494 sm = difflib.SequenceMatcher(None, a, b)
2497 sm = difflib.SequenceMatcher(None, a, b)
2495 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2498 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2496 if tag == 'insert':
2499 if tag == 'insert':
2497 for i in xrange(blo, bhi):
2500 for i in xrange(blo, bhi):
2498 yield ('+', b[i])
2501 yield ('+', b[i])
2499 elif tag == 'delete':
2502 elif tag == 'delete':
2500 for i in xrange(alo, ahi):
2503 for i in xrange(alo, ahi):
2501 yield ('-', a[i])
2504 yield ('-', a[i])
2502 elif tag == 'replace':
2505 elif tag == 'replace':
2503 for i in xrange(alo, ahi):
2506 for i in xrange(alo, ahi):
2504 yield ('-', a[i])
2507 yield ('-', a[i])
2505 for i in xrange(blo, bhi):
2508 for i in xrange(blo, bhi):
2506 yield ('+', b[i])
2509 yield ('+', b[i])
2507
2510
2508 def display(fm, fn, ctx, pstates, states):
2511 def display(fm, fn, ctx, pstates, states):
2509 rev = ctx.rev()
2512 rev = ctx.rev()
2510 if fm.isplain():
2513 if fm.isplain():
2511 formatuser = ui.shortuser
2514 formatuser = ui.shortuser
2512 else:
2515 else:
2513 formatuser = str
2516 formatuser = str
2514 if ui.quiet:
2517 if ui.quiet:
2515 datefmt = '%Y-%m-%d'
2518 datefmt = '%Y-%m-%d'
2516 else:
2519 else:
2517 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2520 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2518 found = False
2521 found = False
2519 @util.cachefunc
2522 @util.cachefunc
2520 def binary():
2523 def binary():
2521 flog = getfile(fn)
2524 flog = getfile(fn)
2522 return util.binary(flog.read(ctx.filenode(fn)))
2525 return util.binary(flog.read(ctx.filenode(fn)))
2523
2526
2524 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2527 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2525 if opts.get('all'):
2528 if opts.get('all'):
2526 iter = difflinestates(pstates, states)
2529 iter = difflinestates(pstates, states)
2527 else:
2530 else:
2528 iter = [('', l) for l in states]
2531 iter = [('', l) for l in states]
2529 for change, l in iter:
2532 for change, l in iter:
2530 fm.startitem()
2533 fm.startitem()
2531 fm.data(node=fm.hexfunc(ctx.node()))
2534 fm.data(node=fm.hexfunc(ctx.node()))
2532 cols = [
2535 cols = [
2533 ('filename', fn, True),
2536 ('filename', fn, True),
2534 ('rev', rev, True),
2537 ('rev', rev, True),
2535 ('linenumber', l.linenum, opts.get('line_number')),
2538 ('linenumber', l.linenum, opts.get('line_number')),
2536 ]
2539 ]
2537 if opts.get('all'):
2540 if opts.get('all'):
2538 cols.append(('change', change, True))
2541 cols.append(('change', change, True))
2539 cols.extend([
2542 cols.extend([
2540 ('user', formatuser(ctx.user()), opts.get('user')),
2543 ('user', formatuser(ctx.user()), opts.get('user')),
2541 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2544 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2542 ])
2545 ])
2543 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2546 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2544 for name, data, cond in cols:
2547 for name, data, cond in cols:
2545 field = fieldnamemap.get(name, name)
2548 field = fieldnamemap.get(name, name)
2546 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2549 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2547 if cond and name != lastcol:
2550 if cond and name != lastcol:
2548 fm.plain(sep, label='grep.sep')
2551 fm.plain(sep, label='grep.sep')
2549 if not opts.get('files_with_matches'):
2552 if not opts.get('files_with_matches'):
2550 fm.plain(sep, label='grep.sep')
2553 fm.plain(sep, label='grep.sep')
2551 if not opts.get('text') and binary():
2554 if not opts.get('text') and binary():
2552 fm.plain(_(" Binary file matches"))
2555 fm.plain(_(" Binary file matches"))
2553 else:
2556 else:
2554 displaymatches(fm.nested('texts'), l)
2557 displaymatches(fm.nested('texts'), l)
2555 fm.plain(eol)
2558 fm.plain(eol)
2556 found = True
2559 found = True
2557 if opts.get('files_with_matches'):
2560 if opts.get('files_with_matches'):
2558 break
2561 break
2559 return found
2562 return found
2560
2563
2561 def displaymatches(fm, l):
2564 def displaymatches(fm, l):
2562 p = 0
2565 p = 0
2563 for s, e in l.findpos():
2566 for s, e in l.findpos():
2564 if p < s:
2567 if p < s:
2565 fm.startitem()
2568 fm.startitem()
2566 fm.write('text', '%s', l.line[p:s])
2569 fm.write('text', '%s', l.line[p:s])
2567 fm.data(matched=False)
2570 fm.data(matched=False)
2568 fm.startitem()
2571 fm.startitem()
2569 fm.write('text', '%s', l.line[s:e], label='grep.match')
2572 fm.write('text', '%s', l.line[s:e], label='grep.match')
2570 fm.data(matched=True)
2573 fm.data(matched=True)
2571 p = e
2574 p = e
2572 if p < len(l.line):
2575 if p < len(l.line):
2573 fm.startitem()
2576 fm.startitem()
2574 fm.write('text', '%s', l.line[p:])
2577 fm.write('text', '%s', l.line[p:])
2575 fm.data(matched=False)
2578 fm.data(matched=False)
2576 fm.end()
2579 fm.end()
2577
2580
2578 skip = {}
2581 skip = {}
2579 revfiles = {}
2582 revfiles = {}
2580 matchfn = scmutil.match(repo[None], pats, opts)
2583 matchfn = scmutil.match(repo[None], pats, opts)
2581 found = False
2584 found = False
2582 follow = opts.get('follow')
2585 follow = opts.get('follow')
2583
2586
2584 def prep(ctx, fns):
2587 def prep(ctx, fns):
2585 rev = ctx.rev()
2588 rev = ctx.rev()
2586 pctx = ctx.p1()
2589 pctx = ctx.p1()
2587 parent = pctx.rev()
2590 parent = pctx.rev()
2588 matches.setdefault(rev, {})
2591 matches.setdefault(rev, {})
2589 matches.setdefault(parent, {})
2592 matches.setdefault(parent, {})
2590 files = revfiles.setdefault(rev, [])
2593 files = revfiles.setdefault(rev, [])
2591 for fn in fns:
2594 for fn in fns:
2592 flog = getfile(fn)
2595 flog = getfile(fn)
2593 try:
2596 try:
2594 fnode = ctx.filenode(fn)
2597 fnode = ctx.filenode(fn)
2595 except error.LookupError:
2598 except error.LookupError:
2596 continue
2599 continue
2597
2600
2598 copied = flog.renamed(fnode)
2601 copied = flog.renamed(fnode)
2599 copy = follow and copied and copied[0]
2602 copy = follow and copied and copied[0]
2600 if copy:
2603 if copy:
2601 copies.setdefault(rev, {})[fn] = copy
2604 copies.setdefault(rev, {})[fn] = copy
2602 if fn in skip:
2605 if fn in skip:
2603 if copy:
2606 if copy:
2604 skip[copy] = True
2607 skip[copy] = True
2605 continue
2608 continue
2606 files.append(fn)
2609 files.append(fn)
2607
2610
2608 if fn not in matches[rev]:
2611 if fn not in matches[rev]:
2609 grepbody(fn, rev, flog.read(fnode))
2612 grepbody(fn, rev, flog.read(fnode))
2610
2613
2611 pfn = copy or fn
2614 pfn = copy or fn
2612 if pfn not in matches[parent]:
2615 if pfn not in matches[parent]:
2613 try:
2616 try:
2614 fnode = pctx.filenode(pfn)
2617 fnode = pctx.filenode(pfn)
2615 grepbody(pfn, parent, flog.read(fnode))
2618 grepbody(pfn, parent, flog.read(fnode))
2616 except error.LookupError:
2619 except error.LookupError:
2617 pass
2620 pass
2618
2621
2619 ui.pager('grep')
2622 ui.pager('grep')
2620 fm = ui.formatter('grep', opts)
2623 fm = ui.formatter('grep', opts)
2621 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2624 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2622 rev = ctx.rev()
2625 rev = ctx.rev()
2623 parent = ctx.p1().rev()
2626 parent = ctx.p1().rev()
2624 for fn in sorted(revfiles.get(rev, [])):
2627 for fn in sorted(revfiles.get(rev, [])):
2625 states = matches[rev][fn]
2628 states = matches[rev][fn]
2626 copy = copies.get(rev, {}).get(fn)
2629 copy = copies.get(rev, {}).get(fn)
2627 if fn in skip:
2630 if fn in skip:
2628 if copy:
2631 if copy:
2629 skip[copy] = True
2632 skip[copy] = True
2630 continue
2633 continue
2631 pstates = matches.get(parent, {}).get(copy or fn, [])
2634 pstates = matches.get(parent, {}).get(copy or fn, [])
2632 if pstates or states:
2635 if pstates or states:
2633 r = display(fm, fn, ctx, pstates, states)
2636 r = display(fm, fn, ctx, pstates, states)
2634 found = found or r
2637 found = found or r
2635 if r and not opts.get('all'):
2638 if r and not opts.get('all'):
2636 skip[fn] = True
2639 skip[fn] = True
2637 if copy:
2640 if copy:
2638 skip[copy] = True
2641 skip[copy] = True
2639 del matches[rev]
2642 del matches[rev]
2640 del revfiles[rev]
2643 del revfiles[rev]
2641 fm.end()
2644 fm.end()
2642
2645
2643 return not found
2646 return not found
2644
2647
2645 @command('heads',
2648 @command('heads',
2646 [('r', 'rev', '',
2649 [('r', 'rev', '',
2647 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2650 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2648 ('t', 'topo', False, _('show topological heads only')),
2651 ('t', 'topo', False, _('show topological heads only')),
2649 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2652 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2650 ('c', 'closed', False, _('show normal and closed branch heads')),
2653 ('c', 'closed', False, _('show normal and closed branch heads')),
2651 ] + templateopts,
2654 ] + templateopts,
2652 _('[-ct] [-r STARTREV] [REV]...'))
2655 _('[-ct] [-r STARTREV] [REV]...'))
2653 def heads(ui, repo, *branchrevs, **opts):
2656 def heads(ui, repo, *branchrevs, **opts):
2654 """show branch heads
2657 """show branch heads
2655
2658
2656 With no arguments, show all open branch heads in the repository.
2659 With no arguments, show all open branch heads in the repository.
2657 Branch heads are changesets that have no descendants on the
2660 Branch heads are changesets that have no descendants on the
2658 same branch. They are where development generally takes place and
2661 same branch. They are where development generally takes place and
2659 are the usual targets for update and merge operations.
2662 are the usual targets for update and merge operations.
2660
2663
2661 If one or more REVs are given, only open branch heads on the
2664 If one or more REVs are given, only open branch heads on the
2662 branches associated with the specified changesets are shown. This
2665 branches associated with the specified changesets are shown. This
2663 means that you can use :hg:`heads .` to see the heads on the
2666 means that you can use :hg:`heads .` to see the heads on the
2664 currently checked-out branch.
2667 currently checked-out branch.
2665
2668
2666 If -c/--closed is specified, also show branch heads marked closed
2669 If -c/--closed is specified, also show branch heads marked closed
2667 (see :hg:`commit --close-branch`).
2670 (see :hg:`commit --close-branch`).
2668
2671
2669 If STARTREV is specified, only those heads that are descendants of
2672 If STARTREV is specified, only those heads that are descendants of
2670 STARTREV will be displayed.
2673 STARTREV will be displayed.
2671
2674
2672 If -t/--topo is specified, named branch mechanics will be ignored and only
2675 If -t/--topo is specified, named branch mechanics will be ignored and only
2673 topological heads (changesets with no children) will be shown.
2676 topological heads (changesets with no children) will be shown.
2674
2677
2675 Returns 0 if matching heads are found, 1 if not.
2678 Returns 0 if matching heads are found, 1 if not.
2676 """
2679 """
2677
2680
2678 start = None
2681 start = None
2679 if 'rev' in opts:
2682 if 'rev' in opts:
2680 start = scmutil.revsingle(repo, opts['rev'], None).node()
2683 start = scmutil.revsingle(repo, opts['rev'], None).node()
2681
2684
2682 if opts.get('topo'):
2685 if opts.get('topo'):
2683 heads = [repo[h] for h in repo.heads(start)]
2686 heads = [repo[h] for h in repo.heads(start)]
2684 else:
2687 else:
2685 heads = []
2688 heads = []
2686 for branch in repo.branchmap():
2689 for branch in repo.branchmap():
2687 heads += repo.branchheads(branch, start, opts.get('closed'))
2690 heads += repo.branchheads(branch, start, opts.get('closed'))
2688 heads = [repo[h] for h in heads]
2691 heads = [repo[h] for h in heads]
2689
2692
2690 if branchrevs:
2693 if branchrevs:
2691 branches = set(repo[br].branch() for br in branchrevs)
2694 branches = set(repo[br].branch() for br in branchrevs)
2692 heads = [h for h in heads if h.branch() in branches]
2695 heads = [h for h in heads if h.branch() in branches]
2693
2696
2694 if opts.get('active') and branchrevs:
2697 if opts.get('active') and branchrevs:
2695 dagheads = repo.heads(start)
2698 dagheads = repo.heads(start)
2696 heads = [h for h in heads if h.node() in dagheads]
2699 heads = [h for h in heads if h.node() in dagheads]
2697
2700
2698 if branchrevs:
2701 if branchrevs:
2699 haveheads = set(h.branch() for h in heads)
2702 haveheads = set(h.branch() for h in heads)
2700 if branches - haveheads:
2703 if branches - haveheads:
2701 headless = ', '.join(b for b in branches - haveheads)
2704 headless = ', '.join(b for b in branches - haveheads)
2702 msg = _('no open branch heads found on branches %s')
2705 msg = _('no open branch heads found on branches %s')
2703 if opts.get('rev'):
2706 if opts.get('rev'):
2704 msg += _(' (started at %s)') % opts['rev']
2707 msg += _(' (started at %s)') % opts['rev']
2705 ui.warn((msg + '\n') % headless)
2708 ui.warn((msg + '\n') % headless)
2706
2709
2707 if not heads:
2710 if not heads:
2708 return 1
2711 return 1
2709
2712
2710 ui.pager('heads')
2713 ui.pager('heads')
2711 heads = sorted(heads, key=lambda x: -x.rev())
2714 heads = sorted(heads, key=lambda x: -x.rev())
2712 displayer = cmdutil.show_changeset(ui, repo, opts)
2715 displayer = cmdutil.show_changeset(ui, repo, opts)
2713 for ctx in heads:
2716 for ctx in heads:
2714 displayer.show(ctx)
2717 displayer.show(ctx)
2715 displayer.close()
2718 displayer.close()
2716
2719
2717 @command('help',
2720 @command('help',
2718 [('e', 'extension', None, _('show only help for extensions')),
2721 [('e', 'extension', None, _('show only help for extensions')),
2719 ('c', 'command', None, _('show only help for commands')),
2722 ('c', 'command', None, _('show only help for commands')),
2720 ('k', 'keyword', None, _('show topics matching keyword')),
2723 ('k', 'keyword', None, _('show topics matching keyword')),
2721 ('s', 'system', [], _('show help for specific platform(s)')),
2724 ('s', 'system', [], _('show help for specific platform(s)')),
2722 ],
2725 ],
2723 _('[-ecks] [TOPIC]'),
2726 _('[-ecks] [TOPIC]'),
2724 norepo=True)
2727 norepo=True)
2725 def help_(ui, name=None, **opts):
2728 def help_(ui, name=None, **opts):
2726 """show help for a given topic or a help overview
2729 """show help for a given topic or a help overview
2727
2730
2728 With no arguments, print a list of commands with short help messages.
2731 With no arguments, print a list of commands with short help messages.
2729
2732
2730 Given a topic, extension, or command name, print help for that
2733 Given a topic, extension, or command name, print help for that
2731 topic.
2734 topic.
2732
2735
2733 Returns 0 if successful.
2736 Returns 0 if successful.
2734 """
2737 """
2735
2738
2736 keep = opts.get('system') or []
2739 keep = opts.get('system') or []
2737 if len(keep) == 0:
2740 if len(keep) == 0:
2738 if pycompat.sysplatform.startswith('win'):
2741 if pycompat.sysplatform.startswith('win'):
2739 keep.append('windows')
2742 keep.append('windows')
2740 elif pycompat.sysplatform == 'OpenVMS':
2743 elif pycompat.sysplatform == 'OpenVMS':
2741 keep.append('vms')
2744 keep.append('vms')
2742 elif pycompat.sysplatform == 'plan9':
2745 elif pycompat.sysplatform == 'plan9':
2743 keep.append('plan9')
2746 keep.append('plan9')
2744 else:
2747 else:
2745 keep.append('unix')
2748 keep.append('unix')
2746 keep.append(pycompat.sysplatform.lower())
2749 keep.append(pycompat.sysplatform.lower())
2747 if ui.verbose:
2750 if ui.verbose:
2748 keep.append('verbose')
2751 keep.append('verbose')
2749
2752
2750 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2753 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2751 ui.pager('help')
2754 ui.pager('help')
2752 ui.write(formatted)
2755 ui.write(formatted)
2753
2756
2754
2757
2755 @command('identify|id',
2758 @command('identify|id',
2756 [('r', 'rev', '',
2759 [('r', 'rev', '',
2757 _('identify the specified revision'), _('REV')),
2760 _('identify the specified revision'), _('REV')),
2758 ('n', 'num', None, _('show local revision number')),
2761 ('n', 'num', None, _('show local revision number')),
2759 ('i', 'id', None, _('show global revision id')),
2762 ('i', 'id', None, _('show global revision id')),
2760 ('b', 'branch', None, _('show branch')),
2763 ('b', 'branch', None, _('show branch')),
2761 ('t', 'tags', None, _('show tags')),
2764 ('t', 'tags', None, _('show tags')),
2762 ('B', 'bookmarks', None, _('show bookmarks')),
2765 ('B', 'bookmarks', None, _('show bookmarks')),
2763 ] + remoteopts,
2766 ] + remoteopts,
2764 _('[-nibtB] [-r REV] [SOURCE]'),
2767 _('[-nibtB] [-r REV] [SOURCE]'),
2765 optionalrepo=True)
2768 optionalrepo=True)
2766 def identify(ui, repo, source=None, rev=None,
2769 def identify(ui, repo, source=None, rev=None,
2767 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2770 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2768 """identify the working directory or specified revision
2771 """identify the working directory or specified revision
2769
2772
2770 Print a summary identifying the repository state at REV using one or
2773 Print a summary identifying the repository state at REV using one or
2771 two parent hash identifiers, followed by a "+" if the working
2774 two parent hash identifiers, followed by a "+" if the working
2772 directory has uncommitted changes, the branch name (if not default),
2775 directory has uncommitted changes, the branch name (if not default),
2773 a list of tags, and a list of bookmarks.
2776 a list of tags, and a list of bookmarks.
2774
2777
2775 When REV is not given, print a summary of the current state of the
2778 When REV is not given, print a summary of the current state of the
2776 repository.
2779 repository.
2777
2780
2778 Specifying a path to a repository root or Mercurial bundle will
2781 Specifying a path to a repository root or Mercurial bundle will
2779 cause lookup to operate on that repository/bundle.
2782 cause lookup to operate on that repository/bundle.
2780
2783
2781 .. container:: verbose
2784 .. container:: verbose
2782
2785
2783 Examples:
2786 Examples:
2784
2787
2785 - generate a build identifier for the working directory::
2788 - generate a build identifier for the working directory::
2786
2789
2787 hg id --id > build-id.dat
2790 hg id --id > build-id.dat
2788
2791
2789 - find the revision corresponding to a tag::
2792 - find the revision corresponding to a tag::
2790
2793
2791 hg id -n -r 1.3
2794 hg id -n -r 1.3
2792
2795
2793 - check the most recent revision of a remote repository::
2796 - check the most recent revision of a remote repository::
2794
2797
2795 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2798 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2796
2799
2797 See :hg:`log` for generating more information about specific revisions,
2800 See :hg:`log` for generating more information about specific revisions,
2798 including full hash identifiers.
2801 including full hash identifiers.
2799
2802
2800 Returns 0 if successful.
2803 Returns 0 if successful.
2801 """
2804 """
2802
2805
2803 if not repo and not source:
2806 if not repo and not source:
2804 raise error.Abort(_("there is no Mercurial repository here "
2807 raise error.Abort(_("there is no Mercurial repository here "
2805 "(.hg not found)"))
2808 "(.hg not found)"))
2806
2809
2807 if ui.debugflag:
2810 if ui.debugflag:
2808 hexfunc = hex
2811 hexfunc = hex
2809 else:
2812 else:
2810 hexfunc = short
2813 hexfunc = short
2811 default = not (num or id or branch or tags or bookmarks)
2814 default = not (num or id or branch or tags or bookmarks)
2812 output = []
2815 output = []
2813 revs = []
2816 revs = []
2814
2817
2815 if source:
2818 if source:
2816 source, branches = hg.parseurl(ui.expandpath(source))
2819 source, branches = hg.parseurl(ui.expandpath(source))
2817 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2820 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2818 repo = peer.local()
2821 repo = peer.local()
2819 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2822 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2820
2823
2821 if not repo:
2824 if not repo:
2822 if num or branch or tags:
2825 if num or branch or tags:
2823 raise error.Abort(
2826 raise error.Abort(
2824 _("can't query remote revision number, branch, or tags"))
2827 _("can't query remote revision number, branch, or tags"))
2825 if not rev and revs:
2828 if not rev and revs:
2826 rev = revs[0]
2829 rev = revs[0]
2827 if not rev:
2830 if not rev:
2828 rev = "tip"
2831 rev = "tip"
2829
2832
2830 remoterev = peer.lookup(rev)
2833 remoterev = peer.lookup(rev)
2831 if default or id:
2834 if default or id:
2832 output = [hexfunc(remoterev)]
2835 output = [hexfunc(remoterev)]
2833
2836
2834 def getbms():
2837 def getbms():
2835 bms = []
2838 bms = []
2836
2839
2837 if 'bookmarks' in peer.listkeys('namespaces'):
2840 if 'bookmarks' in peer.listkeys('namespaces'):
2838 hexremoterev = hex(remoterev)
2841 hexremoterev = hex(remoterev)
2839 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2842 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2840 if bmr == hexremoterev]
2843 if bmr == hexremoterev]
2841
2844
2842 return sorted(bms)
2845 return sorted(bms)
2843
2846
2844 if bookmarks:
2847 if bookmarks:
2845 output.extend(getbms())
2848 output.extend(getbms())
2846 elif default and not ui.quiet:
2849 elif default and not ui.quiet:
2847 # multiple bookmarks for a single parent separated by '/'
2850 # multiple bookmarks for a single parent separated by '/'
2848 bm = '/'.join(getbms())
2851 bm = '/'.join(getbms())
2849 if bm:
2852 if bm:
2850 output.append(bm)
2853 output.append(bm)
2851 else:
2854 else:
2852 ctx = scmutil.revsingle(repo, rev, None)
2855 ctx = scmutil.revsingle(repo, rev, None)
2853
2856
2854 if ctx.rev() is None:
2857 if ctx.rev() is None:
2855 ctx = repo[None]
2858 ctx = repo[None]
2856 parents = ctx.parents()
2859 parents = ctx.parents()
2857 taglist = []
2860 taglist = []
2858 for p in parents:
2861 for p in parents:
2859 taglist.extend(p.tags())
2862 taglist.extend(p.tags())
2860
2863
2861 changed = ""
2864 changed = ""
2862 if default or id or num:
2865 if default or id or num:
2863 if (any(repo.status())
2866 if (any(repo.status())
2864 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2867 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2865 changed = '+'
2868 changed = '+'
2866 if default or id:
2869 if default or id:
2867 output = ["%s%s" %
2870 output = ["%s%s" %
2868 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2871 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2869 if num:
2872 if num:
2870 output.append("%s%s" %
2873 output.append("%s%s" %
2871 ('+'.join([str(p.rev()) for p in parents]), changed))
2874 ('+'.join([str(p.rev()) for p in parents]), changed))
2872 else:
2875 else:
2873 if default or id:
2876 if default or id:
2874 output = [hexfunc(ctx.node())]
2877 output = [hexfunc(ctx.node())]
2875 if num:
2878 if num:
2876 output.append(str(ctx.rev()))
2879 output.append(str(ctx.rev()))
2877 taglist = ctx.tags()
2880 taglist = ctx.tags()
2878
2881
2879 if default and not ui.quiet:
2882 if default and not ui.quiet:
2880 b = ctx.branch()
2883 b = ctx.branch()
2881 if b != 'default':
2884 if b != 'default':
2882 output.append("(%s)" % b)
2885 output.append("(%s)" % b)
2883
2886
2884 # multiple tags for a single parent separated by '/'
2887 # multiple tags for a single parent separated by '/'
2885 t = '/'.join(taglist)
2888 t = '/'.join(taglist)
2886 if t:
2889 if t:
2887 output.append(t)
2890 output.append(t)
2888
2891
2889 # multiple bookmarks for a single parent separated by '/'
2892 # multiple bookmarks for a single parent separated by '/'
2890 bm = '/'.join(ctx.bookmarks())
2893 bm = '/'.join(ctx.bookmarks())
2891 if bm:
2894 if bm:
2892 output.append(bm)
2895 output.append(bm)
2893 else:
2896 else:
2894 if branch:
2897 if branch:
2895 output.append(ctx.branch())
2898 output.append(ctx.branch())
2896
2899
2897 if tags:
2900 if tags:
2898 output.extend(taglist)
2901 output.extend(taglist)
2899
2902
2900 if bookmarks:
2903 if bookmarks:
2901 output.extend(ctx.bookmarks())
2904 output.extend(ctx.bookmarks())
2902
2905
2903 ui.write("%s\n" % ' '.join(output))
2906 ui.write("%s\n" % ' '.join(output))
2904
2907
2905 @command('import|patch',
2908 @command('import|patch',
2906 [('p', 'strip', 1,
2909 [('p', 'strip', 1,
2907 _('directory strip option for patch. This has the same '
2910 _('directory strip option for patch. This has the same '
2908 'meaning as the corresponding patch option'), _('NUM')),
2911 'meaning as the corresponding patch option'), _('NUM')),
2909 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2912 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2910 ('e', 'edit', False, _('invoke editor on commit messages')),
2913 ('e', 'edit', False, _('invoke editor on commit messages')),
2911 ('f', 'force', None,
2914 ('f', 'force', None,
2912 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2915 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2913 ('', 'no-commit', None,
2916 ('', 'no-commit', None,
2914 _("don't commit, just update the working directory")),
2917 _("don't commit, just update the working directory")),
2915 ('', 'bypass', None,
2918 ('', 'bypass', None,
2916 _("apply patch without touching the working directory")),
2919 _("apply patch without touching the working directory")),
2917 ('', 'partial', None,
2920 ('', 'partial', None,
2918 _('commit even if some hunks fail')),
2921 _('commit even if some hunks fail')),
2919 ('', 'exact', None,
2922 ('', 'exact', None,
2920 _('abort if patch would apply lossily')),
2923 _('abort if patch would apply lossily')),
2921 ('', 'prefix', '',
2924 ('', 'prefix', '',
2922 _('apply patch to subdirectory'), _('DIR')),
2925 _('apply patch to subdirectory'), _('DIR')),
2923 ('', 'import-branch', None,
2926 ('', 'import-branch', None,
2924 _('use any branch information in patch (implied by --exact)'))] +
2927 _('use any branch information in patch (implied by --exact)'))] +
2925 commitopts + commitopts2 + similarityopts,
2928 commitopts + commitopts2 + similarityopts,
2926 _('[OPTION]... PATCH...'))
2929 _('[OPTION]... PATCH...'))
2927 def import_(ui, repo, patch1=None, *patches, **opts):
2930 def import_(ui, repo, patch1=None, *patches, **opts):
2928 """import an ordered set of patches
2931 """import an ordered set of patches
2929
2932
2930 Import a list of patches and commit them individually (unless
2933 Import a list of patches and commit them individually (unless
2931 --no-commit is specified).
2934 --no-commit is specified).
2932
2935
2933 To read a patch from standard input (stdin), use "-" as the patch
2936 To read a patch from standard input (stdin), use "-" as the patch
2934 name. If a URL is specified, the patch will be downloaded from
2937 name. If a URL is specified, the patch will be downloaded from
2935 there.
2938 there.
2936
2939
2937 Import first applies changes to the working directory (unless
2940 Import first applies changes to the working directory (unless
2938 --bypass is specified), import will abort if there are outstanding
2941 --bypass is specified), import will abort if there are outstanding
2939 changes.
2942 changes.
2940
2943
2941 Use --bypass to apply and commit patches directly to the
2944 Use --bypass to apply and commit patches directly to the
2942 repository, without affecting the working directory. Without
2945 repository, without affecting the working directory. Without
2943 --exact, patches will be applied on top of the working directory
2946 --exact, patches will be applied on top of the working directory
2944 parent revision.
2947 parent revision.
2945
2948
2946 You can import a patch straight from a mail message. Even patches
2949 You can import a patch straight from a mail message. Even patches
2947 as attachments work (to use the body part, it must have type
2950 as attachments work (to use the body part, it must have type
2948 text/plain or text/x-patch). From and Subject headers of email
2951 text/plain or text/x-patch). From and Subject headers of email
2949 message are used as default committer and commit message. All
2952 message are used as default committer and commit message. All
2950 text/plain body parts before first diff are added to the commit
2953 text/plain body parts before first diff are added to the commit
2951 message.
2954 message.
2952
2955
2953 If the imported patch was generated by :hg:`export`, user and
2956 If the imported patch was generated by :hg:`export`, user and
2954 description from patch override values from message headers and
2957 description from patch override values from message headers and
2955 body. Values given on command line with -m/--message and -u/--user
2958 body. Values given on command line with -m/--message and -u/--user
2956 override these.
2959 override these.
2957
2960
2958 If --exact is specified, import will set the working directory to
2961 If --exact is specified, import will set the working directory to
2959 the parent of each patch before applying it, and will abort if the
2962 the parent of each patch before applying it, and will abort if the
2960 resulting changeset has a different ID than the one recorded in
2963 resulting changeset has a different ID than the one recorded in
2961 the patch. This will guard against various ways that portable
2964 the patch. This will guard against various ways that portable
2962 patch formats and mail systems might fail to transfer Mercurial
2965 patch formats and mail systems might fail to transfer Mercurial
2963 data or metadata. See :hg:`bundle` for lossless transmission.
2966 data or metadata. See :hg:`bundle` for lossless transmission.
2964
2967
2965 Use --partial to ensure a changeset will be created from the patch
2968 Use --partial to ensure a changeset will be created from the patch
2966 even if some hunks fail to apply. Hunks that fail to apply will be
2969 even if some hunks fail to apply. Hunks that fail to apply will be
2967 written to a <target-file>.rej file. Conflicts can then be resolved
2970 written to a <target-file>.rej file. Conflicts can then be resolved
2968 by hand before :hg:`commit --amend` is run to update the created
2971 by hand before :hg:`commit --amend` is run to update the created
2969 changeset. This flag exists to let people import patches that
2972 changeset. This flag exists to let people import patches that
2970 partially apply without losing the associated metadata (author,
2973 partially apply without losing the associated metadata (author,
2971 date, description, ...).
2974 date, description, ...).
2972
2975
2973 .. note::
2976 .. note::
2974
2977
2975 When no hunks apply cleanly, :hg:`import --partial` will create
2978 When no hunks apply cleanly, :hg:`import --partial` will create
2976 an empty changeset, importing only the patch metadata.
2979 an empty changeset, importing only the patch metadata.
2977
2980
2978 With -s/--similarity, hg will attempt to discover renames and
2981 With -s/--similarity, hg will attempt to discover renames and
2979 copies in the patch in the same way as :hg:`addremove`.
2982 copies in the patch in the same way as :hg:`addremove`.
2980
2983
2981 It is possible to use external patch programs to perform the patch
2984 It is possible to use external patch programs to perform the patch
2982 by setting the ``ui.patch`` configuration option. For the default
2985 by setting the ``ui.patch`` configuration option. For the default
2983 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2986 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2984 See :hg:`help config` for more information about configuration
2987 See :hg:`help config` for more information about configuration
2985 files and how to use these options.
2988 files and how to use these options.
2986
2989
2987 See :hg:`help dates` for a list of formats valid for -d/--date.
2990 See :hg:`help dates` for a list of formats valid for -d/--date.
2988
2991
2989 .. container:: verbose
2992 .. container:: verbose
2990
2993
2991 Examples:
2994 Examples:
2992
2995
2993 - import a traditional patch from a website and detect renames::
2996 - import a traditional patch from a website and detect renames::
2994
2997
2995 hg import -s 80 http://example.com/bugfix.patch
2998 hg import -s 80 http://example.com/bugfix.patch
2996
2999
2997 - import a changeset from an hgweb server::
3000 - import a changeset from an hgweb server::
2998
3001
2999 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3002 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3000
3003
3001 - import all the patches in an Unix-style mbox::
3004 - import all the patches in an Unix-style mbox::
3002
3005
3003 hg import incoming-patches.mbox
3006 hg import incoming-patches.mbox
3004
3007
3005 - import patches from stdin::
3008 - import patches from stdin::
3006
3009
3007 hg import -
3010 hg import -
3008
3011
3009 - attempt to exactly restore an exported changeset (not always
3012 - attempt to exactly restore an exported changeset (not always
3010 possible)::
3013 possible)::
3011
3014
3012 hg import --exact proposed-fix.patch
3015 hg import --exact proposed-fix.patch
3013
3016
3014 - use an external tool to apply a patch which is too fuzzy for
3017 - use an external tool to apply a patch which is too fuzzy for
3015 the default internal tool.
3018 the default internal tool.
3016
3019
3017 hg import --config ui.patch="patch --merge" fuzzy.patch
3020 hg import --config ui.patch="patch --merge" fuzzy.patch
3018
3021
3019 - change the default fuzzing from 2 to a less strict 7
3022 - change the default fuzzing from 2 to a less strict 7
3020
3023
3021 hg import --config ui.fuzz=7 fuzz.patch
3024 hg import --config ui.fuzz=7 fuzz.patch
3022
3025
3023 Returns 0 on success, 1 on partial success (see --partial).
3026 Returns 0 on success, 1 on partial success (see --partial).
3024 """
3027 """
3025
3028
3026 if not patch1:
3029 if not patch1:
3027 raise error.Abort(_('need at least one patch to import'))
3030 raise error.Abort(_('need at least one patch to import'))
3028
3031
3029 patches = (patch1,) + patches
3032 patches = (patch1,) + patches
3030
3033
3031 date = opts.get('date')
3034 date = opts.get('date')
3032 if date:
3035 if date:
3033 opts['date'] = util.parsedate(date)
3036 opts['date'] = util.parsedate(date)
3034
3037
3035 exact = opts.get('exact')
3038 exact = opts.get('exact')
3036 update = not opts.get('bypass')
3039 update = not opts.get('bypass')
3037 if not update and opts.get('no_commit'):
3040 if not update and opts.get('no_commit'):
3038 raise error.Abort(_('cannot use --no-commit with --bypass'))
3041 raise error.Abort(_('cannot use --no-commit with --bypass'))
3039 try:
3042 try:
3040 sim = float(opts.get('similarity') or 0)
3043 sim = float(opts.get('similarity') or 0)
3041 except ValueError:
3044 except ValueError:
3042 raise error.Abort(_('similarity must be a number'))
3045 raise error.Abort(_('similarity must be a number'))
3043 if sim < 0 or sim > 100:
3046 if sim < 0 or sim > 100:
3044 raise error.Abort(_('similarity must be between 0 and 100'))
3047 raise error.Abort(_('similarity must be between 0 and 100'))
3045 if sim and not update:
3048 if sim and not update:
3046 raise error.Abort(_('cannot use --similarity with --bypass'))
3049 raise error.Abort(_('cannot use --similarity with --bypass'))
3047 if exact:
3050 if exact:
3048 if opts.get('edit'):
3051 if opts.get('edit'):
3049 raise error.Abort(_('cannot use --exact with --edit'))
3052 raise error.Abort(_('cannot use --exact with --edit'))
3050 if opts.get('prefix'):
3053 if opts.get('prefix'):
3051 raise error.Abort(_('cannot use --exact with --prefix'))
3054 raise error.Abort(_('cannot use --exact with --prefix'))
3052
3055
3053 base = opts["base"]
3056 base = opts["base"]
3054 wlock = dsguard = lock = tr = None
3057 wlock = dsguard = lock = tr = None
3055 msgs = []
3058 msgs = []
3056 ret = 0
3059 ret = 0
3057
3060
3058
3061
3059 try:
3062 try:
3060 wlock = repo.wlock()
3063 wlock = repo.wlock()
3061
3064
3062 if update:
3065 if update:
3063 cmdutil.checkunfinished(repo)
3066 cmdutil.checkunfinished(repo)
3064 if (exact or not opts.get('force')):
3067 if (exact or not opts.get('force')):
3065 cmdutil.bailifchanged(repo)
3068 cmdutil.bailifchanged(repo)
3066
3069
3067 if not opts.get('no_commit'):
3070 if not opts.get('no_commit'):
3068 lock = repo.lock()
3071 lock = repo.lock()
3069 tr = repo.transaction('import')
3072 tr = repo.transaction('import')
3070 else:
3073 else:
3071 dsguard = dirstateguard.dirstateguard(repo, 'import')
3074 dsguard = dirstateguard.dirstateguard(repo, 'import')
3072 parents = repo[None].parents()
3075 parents = repo[None].parents()
3073 for patchurl in patches:
3076 for patchurl in patches:
3074 if patchurl == '-':
3077 if patchurl == '-':
3075 ui.status(_('applying patch from stdin\n'))
3078 ui.status(_('applying patch from stdin\n'))
3076 patchfile = ui.fin
3079 patchfile = ui.fin
3077 patchurl = 'stdin' # for error message
3080 patchurl = 'stdin' # for error message
3078 else:
3081 else:
3079 patchurl = os.path.join(base, patchurl)
3082 patchurl = os.path.join(base, patchurl)
3080 ui.status(_('applying %s\n') % patchurl)
3083 ui.status(_('applying %s\n') % patchurl)
3081 patchfile = hg.openpath(ui, patchurl)
3084 patchfile = hg.openpath(ui, patchurl)
3082
3085
3083 haspatch = False
3086 haspatch = False
3084 for hunk in patch.split(patchfile):
3087 for hunk in patch.split(patchfile):
3085 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3088 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3086 parents, opts,
3089 parents, opts,
3087 msgs, hg.clean)
3090 msgs, hg.clean)
3088 if msg:
3091 if msg:
3089 haspatch = True
3092 haspatch = True
3090 ui.note(msg + '\n')
3093 ui.note(msg + '\n')
3091 if update or exact:
3094 if update or exact:
3092 parents = repo[None].parents()
3095 parents = repo[None].parents()
3093 else:
3096 else:
3094 parents = [repo[node]]
3097 parents = [repo[node]]
3095 if rej:
3098 if rej:
3096 ui.write_err(_("patch applied partially\n"))
3099 ui.write_err(_("patch applied partially\n"))
3097 ui.write_err(_("(fix the .rej files and run "
3100 ui.write_err(_("(fix the .rej files and run "
3098 "`hg commit --amend`)\n"))
3101 "`hg commit --amend`)\n"))
3099 ret = 1
3102 ret = 1
3100 break
3103 break
3101
3104
3102 if not haspatch:
3105 if not haspatch:
3103 raise error.Abort(_('%s: no diffs found') % patchurl)
3106 raise error.Abort(_('%s: no diffs found') % patchurl)
3104
3107
3105 if tr:
3108 if tr:
3106 tr.close()
3109 tr.close()
3107 if msgs:
3110 if msgs:
3108 repo.savecommitmessage('\n* * *\n'.join(msgs))
3111 repo.savecommitmessage('\n* * *\n'.join(msgs))
3109 if dsguard:
3112 if dsguard:
3110 dsguard.close()
3113 dsguard.close()
3111 return ret
3114 return ret
3112 finally:
3115 finally:
3113 if tr:
3116 if tr:
3114 tr.release()
3117 tr.release()
3115 release(lock, dsguard, wlock)
3118 release(lock, dsguard, wlock)
3116
3119
3117 @command('incoming|in',
3120 @command('incoming|in',
3118 [('f', 'force', None,
3121 [('f', 'force', None,
3119 _('run even if remote repository is unrelated')),
3122 _('run even if remote repository is unrelated')),
3120 ('n', 'newest-first', None, _('show newest record first')),
3123 ('n', 'newest-first', None, _('show newest record first')),
3121 ('', 'bundle', '',
3124 ('', 'bundle', '',
3122 _('file to store the bundles into'), _('FILE')),
3125 _('file to store the bundles into'), _('FILE')),
3123 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3126 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3124 ('B', 'bookmarks', False, _("compare bookmarks")),
3127 ('B', 'bookmarks', False, _("compare bookmarks")),
3125 ('b', 'branch', [],
3128 ('b', 'branch', [],
3126 _('a specific branch you would like to pull'), _('BRANCH')),
3129 _('a specific branch you would like to pull'), _('BRANCH')),
3127 ] + logopts + remoteopts + subrepoopts,
3130 ] + logopts + remoteopts + subrepoopts,
3128 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3131 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3129 def incoming(ui, repo, source="default", **opts):
3132 def incoming(ui, repo, source="default", **opts):
3130 """show new changesets found in source
3133 """show new changesets found in source
3131
3134
3132 Show new changesets found in the specified path/URL or the default
3135 Show new changesets found in the specified path/URL or the default
3133 pull location. These are the changesets that would have been pulled
3136 pull location. These are the changesets that would have been pulled
3134 if a pull at the time you issued this command.
3137 if a pull at the time you issued this command.
3135
3138
3136 See pull for valid source format details.
3139 See pull for valid source format details.
3137
3140
3138 .. container:: verbose
3141 .. container:: verbose
3139
3142
3140 With -B/--bookmarks, the result of bookmark comparison between
3143 With -B/--bookmarks, the result of bookmark comparison between
3141 local and remote repositories is displayed. With -v/--verbose,
3144 local and remote repositories is displayed. With -v/--verbose,
3142 status is also displayed for each bookmark like below::
3145 status is also displayed for each bookmark like below::
3143
3146
3144 BM1 01234567890a added
3147 BM1 01234567890a added
3145 BM2 1234567890ab advanced
3148 BM2 1234567890ab advanced
3146 BM3 234567890abc diverged
3149 BM3 234567890abc diverged
3147 BM4 34567890abcd changed
3150 BM4 34567890abcd changed
3148
3151
3149 The action taken locally when pulling depends on the
3152 The action taken locally when pulling depends on the
3150 status of each bookmark:
3153 status of each bookmark:
3151
3154
3152 :``added``: pull will create it
3155 :``added``: pull will create it
3153 :``advanced``: pull will update it
3156 :``advanced``: pull will update it
3154 :``diverged``: pull will create a divergent bookmark
3157 :``diverged``: pull will create a divergent bookmark
3155 :``changed``: result depends on remote changesets
3158 :``changed``: result depends on remote changesets
3156
3159
3157 From the point of view of pulling behavior, bookmark
3160 From the point of view of pulling behavior, bookmark
3158 existing only in the remote repository are treated as ``added``,
3161 existing only in the remote repository are treated as ``added``,
3159 even if it is in fact locally deleted.
3162 even if it is in fact locally deleted.
3160
3163
3161 .. container:: verbose
3164 .. container:: verbose
3162
3165
3163 For remote repository, using --bundle avoids downloading the
3166 For remote repository, using --bundle avoids downloading the
3164 changesets twice if the incoming is followed by a pull.
3167 changesets twice if the incoming is followed by a pull.
3165
3168
3166 Examples:
3169 Examples:
3167
3170
3168 - show incoming changes with patches and full description::
3171 - show incoming changes with patches and full description::
3169
3172
3170 hg incoming -vp
3173 hg incoming -vp
3171
3174
3172 - show incoming changes excluding merges, store a bundle::
3175 - show incoming changes excluding merges, store a bundle::
3173
3176
3174 hg in -vpM --bundle incoming.hg
3177 hg in -vpM --bundle incoming.hg
3175 hg pull incoming.hg
3178 hg pull incoming.hg
3176
3179
3177 - briefly list changes inside a bundle::
3180 - briefly list changes inside a bundle::
3178
3181
3179 hg in changes.hg -T "{desc|firstline}\\n"
3182 hg in changes.hg -T "{desc|firstline}\\n"
3180
3183
3181 Returns 0 if there are incoming changes, 1 otherwise.
3184 Returns 0 if there are incoming changes, 1 otherwise.
3182 """
3185 """
3183 if opts.get('graph'):
3186 if opts.get('graph'):
3184 cmdutil.checkunsupportedgraphflags([], opts)
3187 cmdutil.checkunsupportedgraphflags([], opts)
3185 def display(other, chlist, displayer):
3188 def display(other, chlist, displayer):
3186 revdag = cmdutil.graphrevs(other, chlist, opts)
3189 revdag = cmdutil.graphrevs(other, chlist, opts)
3187 cmdutil.displaygraph(ui, repo, revdag, displayer,
3190 cmdutil.displaygraph(ui, repo, revdag, displayer,
3188 graphmod.asciiedges)
3191 graphmod.asciiedges)
3189
3192
3190 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3193 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3191 return 0
3194 return 0
3192
3195
3193 if opts.get('bundle') and opts.get('subrepos'):
3196 if opts.get('bundle') and opts.get('subrepos'):
3194 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3197 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3195
3198
3196 if opts.get('bookmarks'):
3199 if opts.get('bookmarks'):
3197 source, branches = hg.parseurl(ui.expandpath(source),
3200 source, branches = hg.parseurl(ui.expandpath(source),
3198 opts.get('branch'))
3201 opts.get('branch'))
3199 other = hg.peer(repo, opts, source)
3202 other = hg.peer(repo, opts, source)
3200 if 'bookmarks' not in other.listkeys('namespaces'):
3203 if 'bookmarks' not in other.listkeys('namespaces'):
3201 ui.warn(_("remote doesn't support bookmarks\n"))
3204 ui.warn(_("remote doesn't support bookmarks\n"))
3202 return 0
3205 return 0
3203 ui.pager('incoming')
3206 ui.pager('incoming')
3204 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3207 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3205 return bookmarks.incoming(ui, repo, other)
3208 return bookmarks.incoming(ui, repo, other)
3206
3209
3207 repo._subtoppath = ui.expandpath(source)
3210 repo._subtoppath = ui.expandpath(source)
3208 try:
3211 try:
3209 return hg.incoming(ui, repo, source, opts)
3212 return hg.incoming(ui, repo, source, opts)
3210 finally:
3213 finally:
3211 del repo._subtoppath
3214 del repo._subtoppath
3212
3215
3213
3216
3214 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3217 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3215 norepo=True)
3218 norepo=True)
3216 def init(ui, dest=".", **opts):
3219 def init(ui, dest=".", **opts):
3217 """create a new repository in the given directory
3220 """create a new repository in the given directory
3218
3221
3219 Initialize a new repository in the given directory. If the given
3222 Initialize a new repository in the given directory. If the given
3220 directory does not exist, it will be created.
3223 directory does not exist, it will be created.
3221
3224
3222 If no directory is given, the current directory is used.
3225 If no directory is given, the current directory is used.
3223
3226
3224 It is possible to specify an ``ssh://`` URL as the destination.
3227 It is possible to specify an ``ssh://`` URL as the destination.
3225 See :hg:`help urls` for more information.
3228 See :hg:`help urls` for more information.
3226
3229
3227 Returns 0 on success.
3230 Returns 0 on success.
3228 """
3231 """
3229 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3232 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3230
3233
3231 @command('locate',
3234 @command('locate',
3232 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3235 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3233 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3236 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3234 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3237 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3235 ] + walkopts,
3238 ] + walkopts,
3236 _('[OPTION]... [PATTERN]...'))
3239 _('[OPTION]... [PATTERN]...'))
3237 def locate(ui, repo, *pats, **opts):
3240 def locate(ui, repo, *pats, **opts):
3238 """locate files matching specific patterns (DEPRECATED)
3241 """locate files matching specific patterns (DEPRECATED)
3239
3242
3240 Print files under Mercurial control in the working directory whose
3243 Print files under Mercurial control in the working directory whose
3241 names match the given patterns.
3244 names match the given patterns.
3242
3245
3243 By default, this command searches all directories in the working
3246 By default, this command searches all directories in the working
3244 directory. To search just the current directory and its
3247 directory. To search just the current directory and its
3245 subdirectories, use "--include .".
3248 subdirectories, use "--include .".
3246
3249
3247 If no patterns are given to match, this command prints the names
3250 If no patterns are given to match, this command prints the names
3248 of all files under Mercurial control in the working directory.
3251 of all files under Mercurial control in the working directory.
3249
3252
3250 If you want to feed the output of this command into the "xargs"
3253 If you want to feed the output of this command into the "xargs"
3251 command, use the -0 option to both this command and "xargs". This
3254 command, use the -0 option to both this command and "xargs". This
3252 will avoid the problem of "xargs" treating single filenames that
3255 will avoid the problem of "xargs" treating single filenames that
3253 contain whitespace as multiple filenames.
3256 contain whitespace as multiple filenames.
3254
3257
3255 See :hg:`help files` for a more versatile command.
3258 See :hg:`help files` for a more versatile command.
3256
3259
3257 Returns 0 if a match is found, 1 otherwise.
3260 Returns 0 if a match is found, 1 otherwise.
3258 """
3261 """
3259 if opts.get('print0'):
3262 if opts.get('print0'):
3260 end = '\0'
3263 end = '\0'
3261 else:
3264 else:
3262 end = '\n'
3265 end = '\n'
3263 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3266 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3264
3267
3265 ret = 1
3268 ret = 1
3266 ctx = repo[rev]
3269 ctx = repo[rev]
3267 m = scmutil.match(ctx, pats, opts, default='relglob',
3270 m = scmutil.match(ctx, pats, opts, default='relglob',
3268 badfn=lambda x, y: False)
3271 badfn=lambda x, y: False)
3269
3272
3270 ui.pager('locate')
3273 ui.pager('locate')
3271 for abs in ctx.matches(m):
3274 for abs in ctx.matches(m):
3272 if opts.get('fullpath'):
3275 if opts.get('fullpath'):
3273 ui.write(repo.wjoin(abs), end)
3276 ui.write(repo.wjoin(abs), end)
3274 else:
3277 else:
3275 ui.write(((pats and m.rel(abs)) or abs), end)
3278 ui.write(((pats and m.rel(abs)) or abs), end)
3276 ret = 0
3279 ret = 0
3277
3280
3278 return ret
3281 return ret
3279
3282
3280 @command('^log|history',
3283 @command('^log|history',
3281 [('f', 'follow', None,
3284 [('f', 'follow', None,
3282 _('follow changeset history, or file history across copies and renames')),
3285 _('follow changeset history, or file history across copies and renames')),
3283 ('', 'follow-first', None,
3286 ('', 'follow-first', None,
3284 _('only follow the first parent of merge changesets (DEPRECATED)')),
3287 _('only follow the first parent of merge changesets (DEPRECATED)')),
3285 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3288 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3286 ('C', 'copies', None, _('show copied files')),
3289 ('C', 'copies', None, _('show copied files')),
3287 ('k', 'keyword', [],
3290 ('k', 'keyword', [],
3288 _('do case-insensitive search for a given text'), _('TEXT')),
3291 _('do case-insensitive search for a given text'), _('TEXT')),
3289 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3292 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3290 ('', 'removed', None, _('include revisions where files were removed')),
3293 ('', 'removed', None, _('include revisions where files were removed')),
3291 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3294 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3292 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3295 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3293 ('', 'only-branch', [],
3296 ('', 'only-branch', [],
3294 _('show only changesets within the given named branch (DEPRECATED)'),
3297 _('show only changesets within the given named branch (DEPRECATED)'),
3295 _('BRANCH')),
3298 _('BRANCH')),
3296 ('b', 'branch', [],
3299 ('b', 'branch', [],
3297 _('show changesets within the given named branch'), _('BRANCH')),
3300 _('show changesets within the given named branch'), _('BRANCH')),
3298 ('P', 'prune', [],
3301 ('P', 'prune', [],
3299 _('do not display revision or any of its ancestors'), _('REV')),
3302 _('do not display revision or any of its ancestors'), _('REV')),
3300 ] + logopts + walkopts,
3303 ] + logopts + walkopts,
3301 _('[OPTION]... [FILE]'),
3304 _('[OPTION]... [FILE]'),
3302 inferrepo=True)
3305 inferrepo=True)
3303 def log(ui, repo, *pats, **opts):
3306 def log(ui, repo, *pats, **opts):
3304 """show revision history of entire repository or files
3307 """show revision history of entire repository or files
3305
3308
3306 Print the revision history of the specified files or the entire
3309 Print the revision history of the specified files or the entire
3307 project.
3310 project.
3308
3311
3309 If no revision range is specified, the default is ``tip:0`` unless
3312 If no revision range is specified, the default is ``tip:0`` unless
3310 --follow is set, in which case the working directory parent is
3313 --follow is set, in which case the working directory parent is
3311 used as the starting revision.
3314 used as the starting revision.
3312
3315
3313 File history is shown without following rename or copy history of
3316 File history is shown without following rename or copy history of
3314 files. Use -f/--follow with a filename to follow history across
3317 files. Use -f/--follow with a filename to follow history across
3315 renames and copies. --follow without a filename will only show
3318 renames and copies. --follow without a filename will only show
3316 ancestors or descendants of the starting revision.
3319 ancestors or descendants of the starting revision.
3317
3320
3318 By default this command prints revision number and changeset id,
3321 By default this command prints revision number and changeset id,
3319 tags, non-trivial parents, user, date and time, and a summary for
3322 tags, non-trivial parents, user, date and time, and a summary for
3320 each commit. When the -v/--verbose switch is used, the list of
3323 each commit. When the -v/--verbose switch is used, the list of
3321 changed files and full commit message are shown.
3324 changed files and full commit message are shown.
3322
3325
3323 With --graph the revisions are shown as an ASCII art DAG with the most
3326 With --graph the revisions are shown as an ASCII art DAG with the most
3324 recent changeset at the top.
3327 recent changeset at the top.
3325 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3328 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3326 and '+' represents a fork where the changeset from the lines below is a
3329 and '+' represents a fork where the changeset from the lines below is a
3327 parent of the 'o' merge on the same line.
3330 parent of the 'o' merge on the same line.
3328
3331
3329 .. note::
3332 .. note::
3330
3333
3331 :hg:`log --patch` may generate unexpected diff output for merge
3334 :hg:`log --patch` may generate unexpected diff output for merge
3332 changesets, as it will only compare the merge changeset against
3335 changesets, as it will only compare the merge changeset against
3333 its first parent. Also, only files different from BOTH parents
3336 its first parent. Also, only files different from BOTH parents
3334 will appear in files:.
3337 will appear in files:.
3335
3338
3336 .. note::
3339 .. note::
3337
3340
3338 For performance reasons, :hg:`log FILE` may omit duplicate changes
3341 For performance reasons, :hg:`log FILE` may omit duplicate changes
3339 made on branches and will not show removals or mode changes. To
3342 made on branches and will not show removals or mode changes. To
3340 see all such changes, use the --removed switch.
3343 see all such changes, use the --removed switch.
3341
3344
3342 .. container:: verbose
3345 .. container:: verbose
3343
3346
3344 Some examples:
3347 Some examples:
3345
3348
3346 - changesets with full descriptions and file lists::
3349 - changesets with full descriptions and file lists::
3347
3350
3348 hg log -v
3351 hg log -v
3349
3352
3350 - changesets ancestral to the working directory::
3353 - changesets ancestral to the working directory::
3351
3354
3352 hg log -f
3355 hg log -f
3353
3356
3354 - last 10 commits on the current branch::
3357 - last 10 commits on the current branch::
3355
3358
3356 hg log -l 10 -b .
3359 hg log -l 10 -b .
3357
3360
3358 - changesets showing all modifications of a file, including removals::
3361 - changesets showing all modifications of a file, including removals::
3359
3362
3360 hg log --removed file.c
3363 hg log --removed file.c
3361
3364
3362 - all changesets that touch a directory, with diffs, excluding merges::
3365 - all changesets that touch a directory, with diffs, excluding merges::
3363
3366
3364 hg log -Mp lib/
3367 hg log -Mp lib/
3365
3368
3366 - all revision numbers that match a keyword::
3369 - all revision numbers that match a keyword::
3367
3370
3368 hg log -k bug --template "{rev}\\n"
3371 hg log -k bug --template "{rev}\\n"
3369
3372
3370 - the full hash identifier of the working directory parent::
3373 - the full hash identifier of the working directory parent::
3371
3374
3372 hg log -r . --template "{node}\\n"
3375 hg log -r . --template "{node}\\n"
3373
3376
3374 - list available log templates::
3377 - list available log templates::
3375
3378
3376 hg log -T list
3379 hg log -T list
3377
3380
3378 - check if a given changeset is included in a tagged release::
3381 - check if a given changeset is included in a tagged release::
3379
3382
3380 hg log -r "a21ccf and ancestor(1.9)"
3383 hg log -r "a21ccf and ancestor(1.9)"
3381
3384
3382 - find all changesets by some user in a date range::
3385 - find all changesets by some user in a date range::
3383
3386
3384 hg log -k alice -d "may 2008 to jul 2008"
3387 hg log -k alice -d "may 2008 to jul 2008"
3385
3388
3386 - summary of all changesets after the last tag::
3389 - summary of all changesets after the last tag::
3387
3390
3388 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3391 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3389
3392
3390 See :hg:`help dates` for a list of formats valid for -d/--date.
3393 See :hg:`help dates` for a list of formats valid for -d/--date.
3391
3394
3392 See :hg:`help revisions` for more about specifying and ordering
3395 See :hg:`help revisions` for more about specifying and ordering
3393 revisions.
3396 revisions.
3394
3397
3395 See :hg:`help templates` for more about pre-packaged styles and
3398 See :hg:`help templates` for more about pre-packaged styles and
3396 specifying custom templates.
3399 specifying custom templates.
3397
3400
3398 Returns 0 on success.
3401 Returns 0 on success.
3399
3402
3400 """
3403 """
3401 opts = pycompat.byteskwargs(opts)
3404 opts = pycompat.byteskwargs(opts)
3402 if opts.get('follow') and opts.get('rev'):
3405 if opts.get('follow') and opts.get('rev'):
3403 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3406 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3404 del opts['follow']
3407 del opts['follow']
3405
3408
3406 if opts.get('graph'):
3409 if opts.get('graph'):
3407 return cmdutil.graphlog(ui, repo, pats, opts)
3410 return cmdutil.graphlog(ui, repo, pats, opts)
3408
3411
3409 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3412 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3410 limit = cmdutil.loglimit(opts)
3413 limit = cmdutil.loglimit(opts)
3411 count = 0
3414 count = 0
3412
3415
3413 getrenamed = None
3416 getrenamed = None
3414 if opts.get('copies'):
3417 if opts.get('copies'):
3415 endrev = None
3418 endrev = None
3416 if opts.get('rev'):
3419 if opts.get('rev'):
3417 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3420 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3418 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3421 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3419
3422
3420 ui.pager('log')
3423 ui.pager('log')
3421 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3424 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3422 for rev in revs:
3425 for rev in revs:
3423 if count == limit:
3426 if count == limit:
3424 break
3427 break
3425 ctx = repo[rev]
3428 ctx = repo[rev]
3426 copies = None
3429 copies = None
3427 if getrenamed is not None and rev:
3430 if getrenamed is not None and rev:
3428 copies = []
3431 copies = []
3429 for fn in ctx.files():
3432 for fn in ctx.files():
3430 rename = getrenamed(fn, rev)
3433 rename = getrenamed(fn, rev)
3431 if rename:
3434 if rename:
3432 copies.append((fn, rename[0]))
3435 copies.append((fn, rename[0]))
3433 if filematcher:
3436 if filematcher:
3434 revmatchfn = filematcher(ctx.rev())
3437 revmatchfn = filematcher(ctx.rev())
3435 else:
3438 else:
3436 revmatchfn = None
3439 revmatchfn = None
3437 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3440 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3438 if displayer.flush(ctx):
3441 if displayer.flush(ctx):
3439 count += 1
3442 count += 1
3440
3443
3441 displayer.close()
3444 displayer.close()
3442
3445
3443 @command('manifest',
3446 @command('manifest',
3444 [('r', 'rev', '', _('revision to display'), _('REV')),
3447 [('r', 'rev', '', _('revision to display'), _('REV')),
3445 ('', 'all', False, _("list files from all revisions"))]
3448 ('', 'all', False, _("list files from all revisions"))]
3446 + formatteropts,
3449 + formatteropts,
3447 _('[-r REV]'))
3450 _('[-r REV]'))
3448 def manifest(ui, repo, node=None, rev=None, **opts):
3451 def manifest(ui, repo, node=None, rev=None, **opts):
3449 """output the current or given revision of the project manifest
3452 """output the current or given revision of the project manifest
3450
3453
3451 Print a list of version controlled files for the given revision.
3454 Print a list of version controlled files for the given revision.
3452 If no revision is given, the first parent of the working directory
3455 If no revision is given, the first parent of the working directory
3453 is used, or the null revision if no revision is checked out.
3456 is used, or the null revision if no revision is checked out.
3454
3457
3455 With -v, print file permissions, symlink and executable bits.
3458 With -v, print file permissions, symlink and executable bits.
3456 With --debug, print file revision hashes.
3459 With --debug, print file revision hashes.
3457
3460
3458 If option --all is specified, the list of all files from all revisions
3461 If option --all is specified, the list of all files from all revisions
3459 is printed. This includes deleted and renamed files.
3462 is printed. This includes deleted and renamed files.
3460
3463
3461 Returns 0 on success.
3464 Returns 0 on success.
3462 """
3465 """
3463 fm = ui.formatter('manifest', opts)
3466 fm = ui.formatter('manifest', opts)
3464
3467
3465 if opts.get('all'):
3468 if opts.get('all'):
3466 if rev or node:
3469 if rev or node:
3467 raise error.Abort(_("can't specify a revision with --all"))
3470 raise error.Abort(_("can't specify a revision with --all"))
3468
3471
3469 res = []
3472 res = []
3470 prefix = "data/"
3473 prefix = "data/"
3471 suffix = ".i"
3474 suffix = ".i"
3472 plen = len(prefix)
3475 plen = len(prefix)
3473 slen = len(suffix)
3476 slen = len(suffix)
3474 with repo.lock():
3477 with repo.lock():
3475 for fn, b, size in repo.store.datafiles():
3478 for fn, b, size in repo.store.datafiles():
3476 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3479 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3477 res.append(fn[plen:-slen])
3480 res.append(fn[plen:-slen])
3478 ui.pager('manifest')
3481 ui.pager('manifest')
3479 for f in res:
3482 for f in res:
3480 fm.startitem()
3483 fm.startitem()
3481 fm.write("path", '%s\n', f)
3484 fm.write("path", '%s\n', f)
3482 fm.end()
3485 fm.end()
3483 return
3486 return
3484
3487
3485 if rev and node:
3488 if rev and node:
3486 raise error.Abort(_("please specify just one revision"))
3489 raise error.Abort(_("please specify just one revision"))
3487
3490
3488 if not node:
3491 if not node:
3489 node = rev
3492 node = rev
3490
3493
3491 char = {'l': '@', 'x': '*', '': ''}
3494 char = {'l': '@', 'x': '*', '': ''}
3492 mode = {'l': '644', 'x': '755', '': '644'}
3495 mode = {'l': '644', 'x': '755', '': '644'}
3493 ctx = scmutil.revsingle(repo, node)
3496 ctx = scmutil.revsingle(repo, node)
3494 mf = ctx.manifest()
3497 mf = ctx.manifest()
3495 ui.pager('manifest')
3498 ui.pager('manifest')
3496 for f in ctx:
3499 for f in ctx:
3497 fm.startitem()
3500 fm.startitem()
3498 fl = ctx[f].flags()
3501 fl = ctx[f].flags()
3499 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3502 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3500 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3503 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3501 fm.write('path', '%s\n', f)
3504 fm.write('path', '%s\n', f)
3502 fm.end()
3505 fm.end()
3503
3506
3504 @command('^merge',
3507 @command('^merge',
3505 [('f', 'force', None,
3508 [('f', 'force', None,
3506 _('force a merge including outstanding changes (DEPRECATED)')),
3509 _('force a merge including outstanding changes (DEPRECATED)')),
3507 ('r', 'rev', '', _('revision to merge'), _('REV')),
3510 ('r', 'rev', '', _('revision to merge'), _('REV')),
3508 ('P', 'preview', None,
3511 ('P', 'preview', None,
3509 _('review revisions to merge (no merge is performed)'))
3512 _('review revisions to merge (no merge is performed)'))
3510 ] + mergetoolopts,
3513 ] + mergetoolopts,
3511 _('[-P] [[-r] REV]'))
3514 _('[-P] [[-r] REV]'))
3512 def merge(ui, repo, node=None, **opts):
3515 def merge(ui, repo, node=None, **opts):
3513 """merge another revision into working directory
3516 """merge another revision into working directory
3514
3517
3515 The current working directory is updated with all changes made in
3518 The current working directory is updated with all changes made in
3516 the requested revision since the last common predecessor revision.
3519 the requested revision since the last common predecessor revision.
3517
3520
3518 Files that changed between either parent are marked as changed for
3521 Files that changed between either parent are marked as changed for
3519 the next commit and a commit must be performed before any further
3522 the next commit and a commit must be performed before any further
3520 updates to the repository are allowed. The next commit will have
3523 updates to the repository are allowed. The next commit will have
3521 two parents.
3524 two parents.
3522
3525
3523 ``--tool`` can be used to specify the merge tool used for file
3526 ``--tool`` can be used to specify the merge tool used for file
3524 merges. It overrides the HGMERGE environment variable and your
3527 merges. It overrides the HGMERGE environment variable and your
3525 configuration files. See :hg:`help merge-tools` for options.
3528 configuration files. See :hg:`help merge-tools` for options.
3526
3529
3527 If no revision is specified, the working directory's parent is a
3530 If no revision is specified, the working directory's parent is a
3528 head revision, and the current branch contains exactly one other
3531 head revision, and the current branch contains exactly one other
3529 head, the other head is merged with by default. Otherwise, an
3532 head, the other head is merged with by default. Otherwise, an
3530 explicit revision with which to merge with must be provided.
3533 explicit revision with which to merge with must be provided.
3531
3534
3532 See :hg:`help resolve` for information on handling file conflicts.
3535 See :hg:`help resolve` for information on handling file conflicts.
3533
3536
3534 To undo an uncommitted merge, use :hg:`update --clean .` which
3537 To undo an uncommitted merge, use :hg:`update --clean .` which
3535 will check out a clean copy of the original merge parent, losing
3538 will check out a clean copy of the original merge parent, losing
3536 all changes.
3539 all changes.
3537
3540
3538 Returns 0 on success, 1 if there are unresolved files.
3541 Returns 0 on success, 1 if there are unresolved files.
3539 """
3542 """
3540
3543
3541 if opts.get('rev') and node:
3544 if opts.get('rev') and node:
3542 raise error.Abort(_("please specify just one revision"))
3545 raise error.Abort(_("please specify just one revision"))
3543 if not node:
3546 if not node:
3544 node = opts.get('rev')
3547 node = opts.get('rev')
3545
3548
3546 if node:
3549 if node:
3547 node = scmutil.revsingle(repo, node).node()
3550 node = scmutil.revsingle(repo, node).node()
3548
3551
3549 if not node:
3552 if not node:
3550 node = repo[destutil.destmerge(repo)].node()
3553 node = repo[destutil.destmerge(repo)].node()
3551
3554
3552 if opts.get('preview'):
3555 if opts.get('preview'):
3553 # find nodes that are ancestors of p2 but not of p1
3556 # find nodes that are ancestors of p2 but not of p1
3554 p1 = repo.lookup('.')
3557 p1 = repo.lookup('.')
3555 p2 = repo.lookup(node)
3558 p2 = repo.lookup(node)
3556 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3559 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3557
3560
3558 displayer = cmdutil.show_changeset(ui, repo, opts)
3561 displayer = cmdutil.show_changeset(ui, repo, opts)
3559 for node in nodes:
3562 for node in nodes:
3560 displayer.show(repo[node])
3563 displayer.show(repo[node])
3561 displayer.close()
3564 displayer.close()
3562 return 0
3565 return 0
3563
3566
3564 try:
3567 try:
3565 # ui.forcemerge is an internal variable, do not document
3568 # ui.forcemerge is an internal variable, do not document
3566 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3569 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3567 force = opts.get('force')
3570 force = opts.get('force')
3568 labels = ['working copy', 'merge rev']
3571 labels = ['working copy', 'merge rev']
3569 return hg.merge(repo, node, force=force, mergeforce=force,
3572 return hg.merge(repo, node, force=force, mergeforce=force,
3570 labels=labels)
3573 labels=labels)
3571 finally:
3574 finally:
3572 ui.setconfig('ui', 'forcemerge', '', 'merge')
3575 ui.setconfig('ui', 'forcemerge', '', 'merge')
3573
3576
3574 @command('outgoing|out',
3577 @command('outgoing|out',
3575 [('f', 'force', None, _('run even when the destination is unrelated')),
3578 [('f', 'force', None, _('run even when the destination is unrelated')),
3576 ('r', 'rev', [],
3579 ('r', 'rev', [],
3577 _('a changeset intended to be included in the destination'), _('REV')),
3580 _('a changeset intended to be included in the destination'), _('REV')),
3578 ('n', 'newest-first', None, _('show newest record first')),
3581 ('n', 'newest-first', None, _('show newest record first')),
3579 ('B', 'bookmarks', False, _('compare bookmarks')),
3582 ('B', 'bookmarks', False, _('compare bookmarks')),
3580 ('b', 'branch', [], _('a specific branch you would like to push'),
3583 ('b', 'branch', [], _('a specific branch you would like to push'),
3581 _('BRANCH')),
3584 _('BRANCH')),
3582 ] + logopts + remoteopts + subrepoopts,
3585 ] + logopts + remoteopts + subrepoopts,
3583 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3586 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3584 def outgoing(ui, repo, dest=None, **opts):
3587 def outgoing(ui, repo, dest=None, **opts):
3585 """show changesets not found in the destination
3588 """show changesets not found in the destination
3586
3589
3587 Show changesets not found in the specified destination repository
3590 Show changesets not found in the specified destination repository
3588 or the default push location. These are the changesets that would
3591 or the default push location. These are the changesets that would
3589 be pushed if a push was requested.
3592 be pushed if a push was requested.
3590
3593
3591 See pull for details of valid destination formats.
3594 See pull for details of valid destination formats.
3592
3595
3593 .. container:: verbose
3596 .. container:: verbose
3594
3597
3595 With -B/--bookmarks, the result of bookmark comparison between
3598 With -B/--bookmarks, the result of bookmark comparison between
3596 local and remote repositories is displayed. With -v/--verbose,
3599 local and remote repositories is displayed. With -v/--verbose,
3597 status is also displayed for each bookmark like below::
3600 status is also displayed for each bookmark like below::
3598
3601
3599 BM1 01234567890a added
3602 BM1 01234567890a added
3600 BM2 deleted
3603 BM2 deleted
3601 BM3 234567890abc advanced
3604 BM3 234567890abc advanced
3602 BM4 34567890abcd diverged
3605 BM4 34567890abcd diverged
3603 BM5 4567890abcde changed
3606 BM5 4567890abcde changed
3604
3607
3605 The action taken when pushing depends on the
3608 The action taken when pushing depends on the
3606 status of each bookmark:
3609 status of each bookmark:
3607
3610
3608 :``added``: push with ``-B`` will create it
3611 :``added``: push with ``-B`` will create it
3609 :``deleted``: push with ``-B`` will delete it
3612 :``deleted``: push with ``-B`` will delete it
3610 :``advanced``: push will update it
3613 :``advanced``: push will update it
3611 :``diverged``: push with ``-B`` will update it
3614 :``diverged``: push with ``-B`` will update it
3612 :``changed``: push with ``-B`` will update it
3615 :``changed``: push with ``-B`` will update it
3613
3616
3614 From the point of view of pushing behavior, bookmarks
3617 From the point of view of pushing behavior, bookmarks
3615 existing only in the remote repository are treated as
3618 existing only in the remote repository are treated as
3616 ``deleted``, even if it is in fact added remotely.
3619 ``deleted``, even if it is in fact added remotely.
3617
3620
3618 Returns 0 if there are outgoing changes, 1 otherwise.
3621 Returns 0 if there are outgoing changes, 1 otherwise.
3619 """
3622 """
3620 if opts.get('graph'):
3623 if opts.get('graph'):
3621 cmdutil.checkunsupportedgraphflags([], opts)
3624 cmdutil.checkunsupportedgraphflags([], opts)
3622 o, other = hg._outgoing(ui, repo, dest, opts)
3625 o, other = hg._outgoing(ui, repo, dest, opts)
3623 if not o:
3626 if not o:
3624 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3627 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3625 return
3628 return
3626
3629
3627 revdag = cmdutil.graphrevs(repo, o, opts)
3630 revdag = cmdutil.graphrevs(repo, o, opts)
3628 ui.pager('outgoing')
3631 ui.pager('outgoing')
3629 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3632 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3630 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3633 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3631 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3634 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3632 return 0
3635 return 0
3633
3636
3634 if opts.get('bookmarks'):
3637 if opts.get('bookmarks'):
3635 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3638 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3636 dest, branches = hg.parseurl(dest, opts.get('branch'))
3639 dest, branches = hg.parseurl(dest, opts.get('branch'))
3637 other = hg.peer(repo, opts, dest)
3640 other = hg.peer(repo, opts, dest)
3638 if 'bookmarks' not in other.listkeys('namespaces'):
3641 if 'bookmarks' not in other.listkeys('namespaces'):
3639 ui.warn(_("remote doesn't support bookmarks\n"))
3642 ui.warn(_("remote doesn't support bookmarks\n"))
3640 return 0
3643 return 0
3641 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3644 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3642 ui.pager('outgoing')
3645 ui.pager('outgoing')
3643 return bookmarks.outgoing(ui, repo, other)
3646 return bookmarks.outgoing(ui, repo, other)
3644
3647
3645 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3648 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3646 try:
3649 try:
3647 return hg.outgoing(ui, repo, dest, opts)
3650 return hg.outgoing(ui, repo, dest, opts)
3648 finally:
3651 finally:
3649 del repo._subtoppath
3652 del repo._subtoppath
3650
3653
3651 @command('parents',
3654 @command('parents',
3652 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3655 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3653 ] + templateopts,
3656 ] + templateopts,
3654 _('[-r REV] [FILE]'),
3657 _('[-r REV] [FILE]'),
3655 inferrepo=True)
3658 inferrepo=True)
3656 def parents(ui, repo, file_=None, **opts):
3659 def parents(ui, repo, file_=None, **opts):
3657 """show the parents of the working directory or revision (DEPRECATED)
3660 """show the parents of the working directory or revision (DEPRECATED)
3658
3661
3659 Print the working directory's parent revisions. If a revision is
3662 Print the working directory's parent revisions. If a revision is
3660 given via -r/--rev, the parent of that revision will be printed.
3663 given via -r/--rev, the parent of that revision will be printed.
3661 If a file argument is given, the revision in which the file was
3664 If a file argument is given, the revision in which the file was
3662 last changed (before the working directory revision or the
3665 last changed (before the working directory revision or the
3663 argument to --rev if given) is printed.
3666 argument to --rev if given) is printed.
3664
3667
3665 This command is equivalent to::
3668 This command is equivalent to::
3666
3669
3667 hg log -r "p1()+p2()" or
3670 hg log -r "p1()+p2()" or
3668 hg log -r "p1(REV)+p2(REV)" or
3671 hg log -r "p1(REV)+p2(REV)" or
3669 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3672 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3670 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3673 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3671
3674
3672 See :hg:`summary` and :hg:`help revsets` for related information.
3675 See :hg:`summary` and :hg:`help revsets` for related information.
3673
3676
3674 Returns 0 on success.
3677 Returns 0 on success.
3675 """
3678 """
3676
3679
3677 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3680 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3678
3681
3679 if file_:
3682 if file_:
3680 m = scmutil.match(ctx, (file_,), opts)
3683 m = scmutil.match(ctx, (file_,), opts)
3681 if m.anypats() or len(m.files()) != 1:
3684 if m.anypats() or len(m.files()) != 1:
3682 raise error.Abort(_('can only specify an explicit filename'))
3685 raise error.Abort(_('can only specify an explicit filename'))
3683 file_ = m.files()[0]
3686 file_ = m.files()[0]
3684 filenodes = []
3687 filenodes = []
3685 for cp in ctx.parents():
3688 for cp in ctx.parents():
3686 if not cp:
3689 if not cp:
3687 continue
3690 continue
3688 try:
3691 try:
3689 filenodes.append(cp.filenode(file_))
3692 filenodes.append(cp.filenode(file_))
3690 except error.LookupError:
3693 except error.LookupError:
3691 pass
3694 pass
3692 if not filenodes:
3695 if not filenodes:
3693 raise error.Abort(_("'%s' not found in manifest!") % file_)
3696 raise error.Abort(_("'%s' not found in manifest!") % file_)
3694 p = []
3697 p = []
3695 for fn in filenodes:
3698 for fn in filenodes:
3696 fctx = repo.filectx(file_, fileid=fn)
3699 fctx = repo.filectx(file_, fileid=fn)
3697 p.append(fctx.node())
3700 p.append(fctx.node())
3698 else:
3701 else:
3699 p = [cp.node() for cp in ctx.parents()]
3702 p = [cp.node() for cp in ctx.parents()]
3700
3703
3701 displayer = cmdutil.show_changeset(ui, repo, opts)
3704 displayer = cmdutil.show_changeset(ui, repo, opts)
3702 for n in p:
3705 for n in p:
3703 if n != nullid:
3706 if n != nullid:
3704 displayer.show(repo[n])
3707 displayer.show(repo[n])
3705 displayer.close()
3708 displayer.close()
3706
3709
3707 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3710 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3708 def paths(ui, repo, search=None, **opts):
3711 def paths(ui, repo, search=None, **opts):
3709 """show aliases for remote repositories
3712 """show aliases for remote repositories
3710
3713
3711 Show definition of symbolic path name NAME. If no name is given,
3714 Show definition of symbolic path name NAME. If no name is given,
3712 show definition of all available names.
3715 show definition of all available names.
3713
3716
3714 Option -q/--quiet suppresses all output when searching for NAME
3717 Option -q/--quiet suppresses all output when searching for NAME
3715 and shows only the path names when listing all definitions.
3718 and shows only the path names when listing all definitions.
3716
3719
3717 Path names are defined in the [paths] section of your
3720 Path names are defined in the [paths] section of your
3718 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3721 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3719 repository, ``.hg/hgrc`` is used, too.
3722 repository, ``.hg/hgrc`` is used, too.
3720
3723
3721 The path names ``default`` and ``default-push`` have a special
3724 The path names ``default`` and ``default-push`` have a special
3722 meaning. When performing a push or pull operation, they are used
3725 meaning. When performing a push or pull operation, they are used
3723 as fallbacks if no location is specified on the command-line.
3726 as fallbacks if no location is specified on the command-line.
3724 When ``default-push`` is set, it will be used for push and
3727 When ``default-push`` is set, it will be used for push and
3725 ``default`` will be used for pull; otherwise ``default`` is used
3728 ``default`` will be used for pull; otherwise ``default`` is used
3726 as the fallback for both. When cloning a repository, the clone
3729 as the fallback for both. When cloning a repository, the clone
3727 source is written as ``default`` in ``.hg/hgrc``.
3730 source is written as ``default`` in ``.hg/hgrc``.
3728
3731
3729 .. note::
3732 .. note::
3730
3733
3731 ``default`` and ``default-push`` apply to all inbound (e.g.
3734 ``default`` and ``default-push`` apply to all inbound (e.g.
3732 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3735 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3733 and :hg:`bundle`) operations.
3736 and :hg:`bundle`) operations.
3734
3737
3735 See :hg:`help urls` for more information.
3738 See :hg:`help urls` for more information.
3736
3739
3737 Returns 0 on success.
3740 Returns 0 on success.
3738 """
3741 """
3739 ui.pager('paths')
3742 ui.pager('paths')
3740 if search:
3743 if search:
3741 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3744 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3742 if name == search]
3745 if name == search]
3743 else:
3746 else:
3744 pathitems = sorted(ui.paths.iteritems())
3747 pathitems = sorted(ui.paths.iteritems())
3745
3748
3746 fm = ui.formatter('paths', opts)
3749 fm = ui.formatter('paths', opts)
3747 if fm.isplain():
3750 if fm.isplain():
3748 hidepassword = util.hidepassword
3751 hidepassword = util.hidepassword
3749 else:
3752 else:
3750 hidepassword = str
3753 hidepassword = str
3751 if ui.quiet:
3754 if ui.quiet:
3752 namefmt = '%s\n'
3755 namefmt = '%s\n'
3753 else:
3756 else:
3754 namefmt = '%s = '
3757 namefmt = '%s = '
3755 showsubopts = not search and not ui.quiet
3758 showsubopts = not search and not ui.quiet
3756
3759
3757 for name, path in pathitems:
3760 for name, path in pathitems:
3758 fm.startitem()
3761 fm.startitem()
3759 fm.condwrite(not search, 'name', namefmt, name)
3762 fm.condwrite(not search, 'name', namefmt, name)
3760 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3763 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3761 for subopt, value in sorted(path.suboptions.items()):
3764 for subopt, value in sorted(path.suboptions.items()):
3762 assert subopt not in ('name', 'url')
3765 assert subopt not in ('name', 'url')
3763 if showsubopts:
3766 if showsubopts:
3764 fm.plain('%s:%s = ' % (name, subopt))
3767 fm.plain('%s:%s = ' % (name, subopt))
3765 fm.condwrite(showsubopts, subopt, '%s\n', value)
3768 fm.condwrite(showsubopts, subopt, '%s\n', value)
3766
3769
3767 fm.end()
3770 fm.end()
3768
3771
3769 if search and not pathitems:
3772 if search and not pathitems:
3770 if not ui.quiet:
3773 if not ui.quiet:
3771 ui.warn(_("not found!\n"))
3774 ui.warn(_("not found!\n"))
3772 return 1
3775 return 1
3773 else:
3776 else:
3774 return 0
3777 return 0
3775
3778
3776 @command('phase',
3779 @command('phase',
3777 [('p', 'public', False, _('set changeset phase to public')),
3780 [('p', 'public', False, _('set changeset phase to public')),
3778 ('d', 'draft', False, _('set changeset phase to draft')),
3781 ('d', 'draft', False, _('set changeset phase to draft')),
3779 ('s', 'secret', False, _('set changeset phase to secret')),
3782 ('s', 'secret', False, _('set changeset phase to secret')),
3780 ('f', 'force', False, _('allow to move boundary backward')),
3783 ('f', 'force', False, _('allow to move boundary backward')),
3781 ('r', 'rev', [], _('target revision'), _('REV')),
3784 ('r', 'rev', [], _('target revision'), _('REV')),
3782 ],
3785 ],
3783 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3786 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3784 def phase(ui, repo, *revs, **opts):
3787 def phase(ui, repo, *revs, **opts):
3785 """set or show the current phase name
3788 """set or show the current phase name
3786
3789
3787 With no argument, show the phase name of the current revision(s).
3790 With no argument, show the phase name of the current revision(s).
3788
3791
3789 With one of -p/--public, -d/--draft or -s/--secret, change the
3792 With one of -p/--public, -d/--draft or -s/--secret, change the
3790 phase value of the specified revisions.
3793 phase value of the specified revisions.
3791
3794
3792 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3795 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3793 lower phase to an higher phase. Phases are ordered as follows::
3796 lower phase to an higher phase. Phases are ordered as follows::
3794
3797
3795 public < draft < secret
3798 public < draft < secret
3796
3799
3797 Returns 0 on success, 1 if some phases could not be changed.
3800 Returns 0 on success, 1 if some phases could not be changed.
3798
3801
3799 (For more information about the phases concept, see :hg:`help phases`.)
3802 (For more information about the phases concept, see :hg:`help phases`.)
3800 """
3803 """
3801 # search for a unique phase argument
3804 # search for a unique phase argument
3802 targetphase = None
3805 targetphase = None
3803 for idx, name in enumerate(phases.phasenames):
3806 for idx, name in enumerate(phases.phasenames):
3804 if opts[name]:
3807 if opts[name]:
3805 if targetphase is not None:
3808 if targetphase is not None:
3806 raise error.Abort(_('only one phase can be specified'))
3809 raise error.Abort(_('only one phase can be specified'))
3807 targetphase = idx
3810 targetphase = idx
3808
3811
3809 # look for specified revision
3812 # look for specified revision
3810 revs = list(revs)
3813 revs = list(revs)
3811 revs.extend(opts['rev'])
3814 revs.extend(opts['rev'])
3812 if not revs:
3815 if not revs:
3813 # display both parents as the second parent phase can influence
3816 # display both parents as the second parent phase can influence
3814 # the phase of a merge commit
3817 # the phase of a merge commit
3815 revs = [c.rev() for c in repo[None].parents()]
3818 revs = [c.rev() for c in repo[None].parents()]
3816
3819
3817 revs = scmutil.revrange(repo, revs)
3820 revs = scmutil.revrange(repo, revs)
3818
3821
3819 lock = None
3822 lock = None
3820 ret = 0
3823 ret = 0
3821 if targetphase is None:
3824 if targetphase is None:
3822 # display
3825 # display
3823 for r in revs:
3826 for r in revs:
3824 ctx = repo[r]
3827 ctx = repo[r]
3825 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3828 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3826 else:
3829 else:
3827 tr = None
3830 tr = None
3828 lock = repo.lock()
3831 lock = repo.lock()
3829 try:
3832 try:
3830 tr = repo.transaction("phase")
3833 tr = repo.transaction("phase")
3831 # set phase
3834 # set phase
3832 if not revs:
3835 if not revs:
3833 raise error.Abort(_('empty revision set'))
3836 raise error.Abort(_('empty revision set'))
3834 nodes = [repo[r].node() for r in revs]
3837 nodes = [repo[r].node() for r in revs]
3835 # moving revision from public to draft may hide them
3838 # moving revision from public to draft may hide them
3836 # We have to check result on an unfiltered repository
3839 # We have to check result on an unfiltered repository
3837 unfi = repo.unfiltered()
3840 unfi = repo.unfiltered()
3838 getphase = unfi._phasecache.phase
3841 getphase = unfi._phasecache.phase
3839 olddata = [getphase(unfi, r) for r in unfi]
3842 olddata = [getphase(unfi, r) for r in unfi]
3840 phases.advanceboundary(repo, tr, targetphase, nodes)
3843 phases.advanceboundary(repo, tr, targetphase, nodes)
3841 if opts['force']:
3844 if opts['force']:
3842 phases.retractboundary(repo, tr, targetphase, nodes)
3845 phases.retractboundary(repo, tr, targetphase, nodes)
3843 tr.close()
3846 tr.close()
3844 finally:
3847 finally:
3845 if tr is not None:
3848 if tr is not None:
3846 tr.release()
3849 tr.release()
3847 lock.release()
3850 lock.release()
3848 getphase = unfi._phasecache.phase
3851 getphase = unfi._phasecache.phase
3849 newdata = [getphase(unfi, r) for r in unfi]
3852 newdata = [getphase(unfi, r) for r in unfi]
3850 changes = sum(newdata[r] != olddata[r] for r in unfi)
3853 changes = sum(newdata[r] != olddata[r] for r in unfi)
3851 cl = unfi.changelog
3854 cl = unfi.changelog
3852 rejected = [n for n in nodes
3855 rejected = [n for n in nodes
3853 if newdata[cl.rev(n)] < targetphase]
3856 if newdata[cl.rev(n)] < targetphase]
3854 if rejected:
3857 if rejected:
3855 ui.warn(_('cannot move %i changesets to a higher '
3858 ui.warn(_('cannot move %i changesets to a higher '
3856 'phase, use --force\n') % len(rejected))
3859 'phase, use --force\n') % len(rejected))
3857 ret = 1
3860 ret = 1
3858 if changes:
3861 if changes:
3859 msg = _('phase changed for %i changesets\n') % changes
3862 msg = _('phase changed for %i changesets\n') % changes
3860 if ret:
3863 if ret:
3861 ui.status(msg)
3864 ui.status(msg)
3862 else:
3865 else:
3863 ui.note(msg)
3866 ui.note(msg)
3864 else:
3867 else:
3865 ui.warn(_('no phases changed\n'))
3868 ui.warn(_('no phases changed\n'))
3866 return ret
3869 return ret
3867
3870
3868 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3871 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3869 """Run after a changegroup has been added via pull/unbundle
3872 """Run after a changegroup has been added via pull/unbundle
3870
3873
3871 This takes arguments below:
3874 This takes arguments below:
3872
3875
3873 :modheads: change of heads by pull/unbundle
3876 :modheads: change of heads by pull/unbundle
3874 :optupdate: updating working directory is needed or not
3877 :optupdate: updating working directory is needed or not
3875 :checkout: update destination revision (or None to default destination)
3878 :checkout: update destination revision (or None to default destination)
3876 :brev: a name, which might be a bookmark to be activated after updating
3879 :brev: a name, which might be a bookmark to be activated after updating
3877 """
3880 """
3878 if modheads == 0:
3881 if modheads == 0:
3879 return
3882 return
3880 if optupdate:
3883 if optupdate:
3881 try:
3884 try:
3882 return hg.updatetotally(ui, repo, checkout, brev)
3885 return hg.updatetotally(ui, repo, checkout, brev)
3883 except error.UpdateAbort as inst:
3886 except error.UpdateAbort as inst:
3884 msg = _("not updating: %s") % str(inst)
3887 msg = _("not updating: %s") % str(inst)
3885 hint = inst.hint
3888 hint = inst.hint
3886 raise error.UpdateAbort(msg, hint=hint)
3889 raise error.UpdateAbort(msg, hint=hint)
3887 if modheads > 1:
3890 if modheads > 1:
3888 currentbranchheads = len(repo.branchheads())
3891 currentbranchheads = len(repo.branchheads())
3889 if currentbranchheads == modheads:
3892 if currentbranchheads == modheads:
3890 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3893 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3891 elif currentbranchheads > 1:
3894 elif currentbranchheads > 1:
3892 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3895 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3893 "merge)\n"))
3896 "merge)\n"))
3894 else:
3897 else:
3895 ui.status(_("(run 'hg heads' to see heads)\n"))
3898 ui.status(_("(run 'hg heads' to see heads)\n"))
3896 else:
3899 else:
3897 ui.status(_("(run 'hg update' to get a working copy)\n"))
3900 ui.status(_("(run 'hg update' to get a working copy)\n"))
3898
3901
3899 @command('^pull',
3902 @command('^pull',
3900 [('u', 'update', None,
3903 [('u', 'update', None,
3901 _('update to new branch head if changesets were pulled')),
3904 _('update to new branch head if changesets were pulled')),
3902 ('f', 'force', None, _('run even when remote repository is unrelated')),
3905 ('f', 'force', None, _('run even when remote repository is unrelated')),
3903 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3906 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3904 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3907 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3905 ('b', 'branch', [], _('a specific branch you would like to pull'),
3908 ('b', 'branch', [], _('a specific branch you would like to pull'),
3906 _('BRANCH')),
3909 _('BRANCH')),
3907 ] + remoteopts,
3910 ] + remoteopts,
3908 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3911 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3909 def pull(ui, repo, source="default", **opts):
3912 def pull(ui, repo, source="default", **opts):
3910 """pull changes from the specified source
3913 """pull changes from the specified source
3911
3914
3912 Pull changes from a remote repository to a local one.
3915 Pull changes from a remote repository to a local one.
3913
3916
3914 This finds all changes from the repository at the specified path
3917 This finds all changes from the repository at the specified path
3915 or URL and adds them to a local repository (the current one unless
3918 or URL and adds them to a local repository (the current one unless
3916 -R is specified). By default, this does not update the copy of the
3919 -R is specified). By default, this does not update the copy of the
3917 project in the working directory.
3920 project in the working directory.
3918
3921
3919 Use :hg:`incoming` if you want to see what would have been added
3922 Use :hg:`incoming` if you want to see what would have been added
3920 by a pull at the time you issued this command. If you then decide
3923 by a pull at the time you issued this command. If you then decide
3921 to add those changes to the repository, you should use :hg:`pull
3924 to add those changes to the repository, you should use :hg:`pull
3922 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3925 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3923
3926
3924 If SOURCE is omitted, the 'default' path will be used.
3927 If SOURCE is omitted, the 'default' path will be used.
3925 See :hg:`help urls` for more information.
3928 See :hg:`help urls` for more information.
3926
3929
3927 Specifying bookmark as ``.`` is equivalent to specifying the active
3930 Specifying bookmark as ``.`` is equivalent to specifying the active
3928 bookmark's name.
3931 bookmark's name.
3929
3932
3930 Returns 0 on success, 1 if an update had unresolved files.
3933 Returns 0 on success, 1 if an update had unresolved files.
3931 """
3934 """
3932 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3935 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3933 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3936 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3934 other = hg.peer(repo, opts, source)
3937 other = hg.peer(repo, opts, source)
3935 try:
3938 try:
3936 revs, checkout = hg.addbranchrevs(repo, other, branches,
3939 revs, checkout = hg.addbranchrevs(repo, other, branches,
3937 opts.get('rev'))
3940 opts.get('rev'))
3938
3941
3939
3942
3940 pullopargs = {}
3943 pullopargs = {}
3941 if opts.get('bookmark'):
3944 if opts.get('bookmark'):
3942 if not revs:
3945 if not revs:
3943 revs = []
3946 revs = []
3944 # The list of bookmark used here is not the one used to actually
3947 # The list of bookmark used here is not the one used to actually
3945 # update the bookmark name. This can result in the revision pulled
3948 # update the bookmark name. This can result in the revision pulled
3946 # not ending up with the name of the bookmark because of a race
3949 # not ending up with the name of the bookmark because of a race
3947 # condition on the server. (See issue 4689 for details)
3950 # condition on the server. (See issue 4689 for details)
3948 remotebookmarks = other.listkeys('bookmarks')
3951 remotebookmarks = other.listkeys('bookmarks')
3949 pullopargs['remotebookmarks'] = remotebookmarks
3952 pullopargs['remotebookmarks'] = remotebookmarks
3950 for b in opts['bookmark']:
3953 for b in opts['bookmark']:
3951 b = repo._bookmarks.expandname(b)
3954 b = repo._bookmarks.expandname(b)
3952 if b not in remotebookmarks:
3955 if b not in remotebookmarks:
3953 raise error.Abort(_('remote bookmark %s not found!') % b)
3956 raise error.Abort(_('remote bookmark %s not found!') % b)
3954 revs.append(remotebookmarks[b])
3957 revs.append(remotebookmarks[b])
3955
3958
3956 if revs:
3959 if revs:
3957 try:
3960 try:
3958 # When 'rev' is a bookmark name, we cannot guarantee that it
3961 # When 'rev' is a bookmark name, we cannot guarantee that it
3959 # will be updated with that name because of a race condition
3962 # will be updated with that name because of a race condition
3960 # server side. (See issue 4689 for details)
3963 # server side. (See issue 4689 for details)
3961 oldrevs = revs
3964 oldrevs = revs
3962 revs = [] # actually, nodes
3965 revs = [] # actually, nodes
3963 for r in oldrevs:
3966 for r in oldrevs:
3964 node = other.lookup(r)
3967 node = other.lookup(r)
3965 revs.append(node)
3968 revs.append(node)
3966 if r == checkout:
3969 if r == checkout:
3967 checkout = node
3970 checkout = node
3968 except error.CapabilityError:
3971 except error.CapabilityError:
3969 err = _("other repository doesn't support revision lookup, "
3972 err = _("other repository doesn't support revision lookup, "
3970 "so a rev cannot be specified.")
3973 "so a rev cannot be specified.")
3971 raise error.Abort(err)
3974 raise error.Abort(err)
3972
3975
3973 pullopargs.update(opts.get('opargs', {}))
3976 pullopargs.update(opts.get('opargs', {}))
3974 modheads = exchange.pull(repo, other, heads=revs,
3977 modheads = exchange.pull(repo, other, heads=revs,
3975 force=opts.get('force'),
3978 force=opts.get('force'),
3976 bookmarks=opts.get('bookmark', ()),
3979 bookmarks=opts.get('bookmark', ()),
3977 opargs=pullopargs).cgresult
3980 opargs=pullopargs).cgresult
3978
3981
3979 # brev is a name, which might be a bookmark to be activated at
3982 # brev is a name, which might be a bookmark to be activated at
3980 # the end of the update. In other words, it is an explicit
3983 # the end of the update. In other words, it is an explicit
3981 # destination of the update
3984 # destination of the update
3982 brev = None
3985 brev = None
3983
3986
3984 if checkout:
3987 if checkout:
3985 checkout = str(repo.changelog.rev(checkout))
3988 checkout = str(repo.changelog.rev(checkout))
3986
3989
3987 # order below depends on implementation of
3990 # order below depends on implementation of
3988 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3991 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3989 # because 'checkout' is determined without it.
3992 # because 'checkout' is determined without it.
3990 if opts.get('rev'):
3993 if opts.get('rev'):
3991 brev = opts['rev'][0]
3994 brev = opts['rev'][0]
3992 elif opts.get('branch'):
3995 elif opts.get('branch'):
3993 brev = opts['branch'][0]
3996 brev = opts['branch'][0]
3994 else:
3997 else:
3995 brev = branches[0]
3998 brev = branches[0]
3996 repo._subtoppath = source
3999 repo._subtoppath = source
3997 try:
4000 try:
3998 ret = postincoming(ui, repo, modheads, opts.get('update'),
4001 ret = postincoming(ui, repo, modheads, opts.get('update'),
3999 checkout, brev)
4002 checkout, brev)
4000
4003
4001 finally:
4004 finally:
4002 del repo._subtoppath
4005 del repo._subtoppath
4003
4006
4004 finally:
4007 finally:
4005 other.close()
4008 other.close()
4006 return ret
4009 return ret
4007
4010
4008 @command('^push',
4011 @command('^push',
4009 [('f', 'force', None, _('force push')),
4012 [('f', 'force', None, _('force push')),
4010 ('r', 'rev', [],
4013 ('r', 'rev', [],
4011 _('a changeset intended to be included in the destination'),
4014 _('a changeset intended to be included in the destination'),
4012 _('REV')),
4015 _('REV')),
4013 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4016 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4014 ('b', 'branch', [],
4017 ('b', 'branch', [],
4015 _('a specific branch you would like to push'), _('BRANCH')),
4018 _('a specific branch you would like to push'), _('BRANCH')),
4016 ('', 'new-branch', False, _('allow pushing a new branch')),
4019 ('', 'new-branch', False, _('allow pushing a new branch')),
4017 ] + remoteopts,
4020 ] + remoteopts,
4018 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4021 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4019 def push(ui, repo, dest=None, **opts):
4022 def push(ui, repo, dest=None, **opts):
4020 """push changes to the specified destination
4023 """push changes to the specified destination
4021
4024
4022 Push changesets from the local repository to the specified
4025 Push changesets from the local repository to the specified
4023 destination.
4026 destination.
4024
4027
4025 This operation is symmetrical to pull: it is identical to a pull
4028 This operation is symmetrical to pull: it is identical to a pull
4026 in the destination repository from the current one.
4029 in the destination repository from the current one.
4027
4030
4028 By default, push will not allow creation of new heads at the
4031 By default, push will not allow creation of new heads at the
4029 destination, since multiple heads would make it unclear which head
4032 destination, since multiple heads would make it unclear which head
4030 to use. In this situation, it is recommended to pull and merge
4033 to use. In this situation, it is recommended to pull and merge
4031 before pushing.
4034 before pushing.
4032
4035
4033 Use --new-branch if you want to allow push to create a new named
4036 Use --new-branch if you want to allow push to create a new named
4034 branch that is not present at the destination. This allows you to
4037 branch that is not present at the destination. This allows you to
4035 only create a new branch without forcing other changes.
4038 only create a new branch without forcing other changes.
4036
4039
4037 .. note::
4040 .. note::
4038
4041
4039 Extra care should be taken with the -f/--force option,
4042 Extra care should be taken with the -f/--force option,
4040 which will push all new heads on all branches, an action which will
4043 which will push all new heads on all branches, an action which will
4041 almost always cause confusion for collaborators.
4044 almost always cause confusion for collaborators.
4042
4045
4043 If -r/--rev is used, the specified revision and all its ancestors
4046 If -r/--rev is used, the specified revision and all its ancestors
4044 will be pushed to the remote repository.
4047 will be pushed to the remote repository.
4045
4048
4046 If -B/--bookmark is used, the specified bookmarked revision, its
4049 If -B/--bookmark is used, the specified bookmarked revision, its
4047 ancestors, and the bookmark will be pushed to the remote
4050 ancestors, and the bookmark will be pushed to the remote
4048 repository. Specifying ``.`` is equivalent to specifying the active
4051 repository. Specifying ``.`` is equivalent to specifying the active
4049 bookmark's name.
4052 bookmark's name.
4050
4053
4051 Please see :hg:`help urls` for important details about ``ssh://``
4054 Please see :hg:`help urls` for important details about ``ssh://``
4052 URLs. If DESTINATION is omitted, a default path will be used.
4055 URLs. If DESTINATION is omitted, a default path will be used.
4053
4056
4054 Returns 0 if push was successful, 1 if nothing to push.
4057 Returns 0 if push was successful, 1 if nothing to push.
4055 """
4058 """
4056
4059
4057 if opts.get('bookmark'):
4060 if opts.get('bookmark'):
4058 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4061 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4059 for b in opts['bookmark']:
4062 for b in opts['bookmark']:
4060 # translate -B options to -r so changesets get pushed
4063 # translate -B options to -r so changesets get pushed
4061 b = repo._bookmarks.expandname(b)
4064 b = repo._bookmarks.expandname(b)
4062 if b in repo._bookmarks:
4065 if b in repo._bookmarks:
4063 opts.setdefault('rev', []).append(b)
4066 opts.setdefault('rev', []).append(b)
4064 else:
4067 else:
4065 # if we try to push a deleted bookmark, translate it to null
4068 # if we try to push a deleted bookmark, translate it to null
4066 # this lets simultaneous -r, -b options continue working
4069 # this lets simultaneous -r, -b options continue working
4067 opts.setdefault('rev', []).append("null")
4070 opts.setdefault('rev', []).append("null")
4068
4071
4069 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4072 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4070 if not path:
4073 if not path:
4071 raise error.Abort(_('default repository not configured!'),
4074 raise error.Abort(_('default repository not configured!'),
4072 hint=_("see 'hg help config.paths'"))
4075 hint=_("see 'hg help config.paths'"))
4073 dest = path.pushloc or path.loc
4076 dest = path.pushloc or path.loc
4074 branches = (path.branch, opts.get('branch') or [])
4077 branches = (path.branch, opts.get('branch') or [])
4075 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4078 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4076 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4079 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4077 other = hg.peer(repo, opts, dest)
4080 other = hg.peer(repo, opts, dest)
4078
4081
4079 if revs:
4082 if revs:
4080 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4083 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4081 if not revs:
4084 if not revs:
4082 raise error.Abort(_("specified revisions evaluate to an empty set"),
4085 raise error.Abort(_("specified revisions evaluate to an empty set"),
4083 hint=_("use different revision arguments"))
4086 hint=_("use different revision arguments"))
4084 elif path.pushrev:
4087 elif path.pushrev:
4085 # It doesn't make any sense to specify ancestor revisions. So limit
4088 # It doesn't make any sense to specify ancestor revisions. So limit
4086 # to DAG heads to make discovery simpler.
4089 # to DAG heads to make discovery simpler.
4087 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4090 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4088 revs = scmutil.revrange(repo, [expr])
4091 revs = scmutil.revrange(repo, [expr])
4089 revs = [repo[rev].node() for rev in revs]
4092 revs = [repo[rev].node() for rev in revs]
4090 if not revs:
4093 if not revs:
4091 raise error.Abort(_('default push revset for path evaluates to an '
4094 raise error.Abort(_('default push revset for path evaluates to an '
4092 'empty set'))
4095 'empty set'))
4093
4096
4094 repo._subtoppath = dest
4097 repo._subtoppath = dest
4095 try:
4098 try:
4096 # push subrepos depth-first for coherent ordering
4099 # push subrepos depth-first for coherent ordering
4097 c = repo['']
4100 c = repo['']
4098 subs = c.substate # only repos that are committed
4101 subs = c.substate # only repos that are committed
4099 for s in sorted(subs):
4102 for s in sorted(subs):
4100 result = c.sub(s).push(opts)
4103 result = c.sub(s).push(opts)
4101 if result == 0:
4104 if result == 0:
4102 return not result
4105 return not result
4103 finally:
4106 finally:
4104 del repo._subtoppath
4107 del repo._subtoppath
4105 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4108 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4106 newbranch=opts.get('new_branch'),
4109 newbranch=opts.get('new_branch'),
4107 bookmarks=opts.get('bookmark', ()),
4110 bookmarks=opts.get('bookmark', ()),
4108 opargs=opts.get('opargs'))
4111 opargs=opts.get('opargs'))
4109
4112
4110 result = not pushop.cgresult
4113 result = not pushop.cgresult
4111
4114
4112 if pushop.bkresult is not None:
4115 if pushop.bkresult is not None:
4113 if pushop.bkresult == 2:
4116 if pushop.bkresult == 2:
4114 result = 2
4117 result = 2
4115 elif not result and pushop.bkresult:
4118 elif not result and pushop.bkresult:
4116 result = 2
4119 result = 2
4117
4120
4118 return result
4121 return result
4119
4122
4120 @command('recover', [])
4123 @command('recover', [])
4121 def recover(ui, repo):
4124 def recover(ui, repo):
4122 """roll back an interrupted transaction
4125 """roll back an interrupted transaction
4123
4126
4124 Recover from an interrupted commit or pull.
4127 Recover from an interrupted commit or pull.
4125
4128
4126 This command tries to fix the repository status after an
4129 This command tries to fix the repository status after an
4127 interrupted operation. It should only be necessary when Mercurial
4130 interrupted operation. It should only be necessary when Mercurial
4128 suggests it.
4131 suggests it.
4129
4132
4130 Returns 0 if successful, 1 if nothing to recover or verify fails.
4133 Returns 0 if successful, 1 if nothing to recover or verify fails.
4131 """
4134 """
4132 if repo.recover():
4135 if repo.recover():
4133 return hg.verify(repo)
4136 return hg.verify(repo)
4134 return 1
4137 return 1
4135
4138
4136 @command('^remove|rm',
4139 @command('^remove|rm',
4137 [('A', 'after', None, _('record delete for missing files')),
4140 [('A', 'after', None, _('record delete for missing files')),
4138 ('f', 'force', None,
4141 ('f', 'force', None,
4139 _('forget added files, delete modified files')),
4142 _('forget added files, delete modified files')),
4140 ] + subrepoopts + walkopts,
4143 ] + subrepoopts + walkopts,
4141 _('[OPTION]... FILE...'),
4144 _('[OPTION]... FILE...'),
4142 inferrepo=True)
4145 inferrepo=True)
4143 def remove(ui, repo, *pats, **opts):
4146 def remove(ui, repo, *pats, **opts):
4144 """remove the specified files on the next commit
4147 """remove the specified files on the next commit
4145
4148
4146 Schedule the indicated files for removal from the current branch.
4149 Schedule the indicated files for removal from the current branch.
4147
4150
4148 This command schedules the files to be removed at the next commit.
4151 This command schedules the files to be removed at the next commit.
4149 To undo a remove before that, see :hg:`revert`. To undo added
4152 To undo a remove before that, see :hg:`revert`. To undo added
4150 files, see :hg:`forget`.
4153 files, see :hg:`forget`.
4151
4154
4152 .. container:: verbose
4155 .. container:: verbose
4153
4156
4154 -A/--after can be used to remove only files that have already
4157 -A/--after can be used to remove only files that have already
4155 been deleted, -f/--force can be used to force deletion, and -Af
4158 been deleted, -f/--force can be used to force deletion, and -Af
4156 can be used to remove files from the next revision without
4159 can be used to remove files from the next revision without
4157 deleting them from the working directory.
4160 deleting them from the working directory.
4158
4161
4159 The following table details the behavior of remove for different
4162 The following table details the behavior of remove for different
4160 file states (columns) and option combinations (rows). The file
4163 file states (columns) and option combinations (rows). The file
4161 states are Added [A], Clean [C], Modified [M] and Missing [!]
4164 states are Added [A], Clean [C], Modified [M] and Missing [!]
4162 (as reported by :hg:`status`). The actions are Warn, Remove
4165 (as reported by :hg:`status`). The actions are Warn, Remove
4163 (from branch) and Delete (from disk):
4166 (from branch) and Delete (from disk):
4164
4167
4165 ========= == == == ==
4168 ========= == == == ==
4166 opt/state A C M !
4169 opt/state A C M !
4167 ========= == == == ==
4170 ========= == == == ==
4168 none W RD W R
4171 none W RD W R
4169 -f R RD RD R
4172 -f R RD RD R
4170 -A W W W R
4173 -A W W W R
4171 -Af R R R R
4174 -Af R R R R
4172 ========= == == == ==
4175 ========= == == == ==
4173
4176
4174 .. note::
4177 .. note::
4175
4178
4176 :hg:`remove` never deletes files in Added [A] state from the
4179 :hg:`remove` never deletes files in Added [A] state from the
4177 working directory, not even if ``--force`` is specified.
4180 working directory, not even if ``--force`` is specified.
4178
4181
4179 Returns 0 on success, 1 if any warnings encountered.
4182 Returns 0 on success, 1 if any warnings encountered.
4180 """
4183 """
4181
4184
4182 after, force = opts.get('after'), opts.get('force')
4185 after, force = opts.get('after'), opts.get('force')
4183 if not pats and not after:
4186 if not pats and not after:
4184 raise error.Abort(_('no files specified'))
4187 raise error.Abort(_('no files specified'))
4185
4188
4186 m = scmutil.match(repo[None], pats, opts)
4189 m = scmutil.match(repo[None], pats, opts)
4187 subrepos = opts.get('subrepos')
4190 subrepos = opts.get('subrepos')
4188 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4191 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4189
4192
4190 @command('rename|move|mv',
4193 @command('rename|move|mv',
4191 [('A', 'after', None, _('record a rename that has already occurred')),
4194 [('A', 'after', None, _('record a rename that has already occurred')),
4192 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4195 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4193 ] + walkopts + dryrunopts,
4196 ] + walkopts + dryrunopts,
4194 _('[OPTION]... SOURCE... DEST'))
4197 _('[OPTION]... SOURCE... DEST'))
4195 def rename(ui, repo, *pats, **opts):
4198 def rename(ui, repo, *pats, **opts):
4196 """rename files; equivalent of copy + remove
4199 """rename files; equivalent of copy + remove
4197
4200
4198 Mark dest as copies of sources; mark sources for deletion. If dest
4201 Mark dest as copies of sources; mark sources for deletion. If dest
4199 is a directory, copies are put in that directory. If dest is a
4202 is a directory, copies are put in that directory. If dest is a
4200 file, there can only be one source.
4203 file, there can only be one source.
4201
4204
4202 By default, this command copies the contents of files as they
4205 By default, this command copies the contents of files as they
4203 exist in the working directory. If invoked with -A/--after, the
4206 exist in the working directory. If invoked with -A/--after, the
4204 operation is recorded, but no copying is performed.
4207 operation is recorded, but no copying is performed.
4205
4208
4206 This command takes effect at the next commit. To undo a rename
4209 This command takes effect at the next commit. To undo a rename
4207 before that, see :hg:`revert`.
4210 before that, see :hg:`revert`.
4208
4211
4209 Returns 0 on success, 1 if errors are encountered.
4212 Returns 0 on success, 1 if errors are encountered.
4210 """
4213 """
4211 with repo.wlock(False):
4214 with repo.wlock(False):
4212 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4215 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4213
4216
4214 @command('resolve',
4217 @command('resolve',
4215 [('a', 'all', None, _('select all unresolved files')),
4218 [('a', 'all', None, _('select all unresolved files')),
4216 ('l', 'list', None, _('list state of files needing merge')),
4219 ('l', 'list', None, _('list state of files needing merge')),
4217 ('m', 'mark', None, _('mark files as resolved')),
4220 ('m', 'mark', None, _('mark files as resolved')),
4218 ('u', 'unmark', None, _('mark files as unresolved')),
4221 ('u', 'unmark', None, _('mark files as unresolved')),
4219 ('n', 'no-status', None, _('hide status prefix'))]
4222 ('n', 'no-status', None, _('hide status prefix'))]
4220 + mergetoolopts + walkopts + formatteropts,
4223 + mergetoolopts + walkopts + formatteropts,
4221 _('[OPTION]... [FILE]...'),
4224 _('[OPTION]... [FILE]...'),
4222 inferrepo=True)
4225 inferrepo=True)
4223 def resolve(ui, repo, *pats, **opts):
4226 def resolve(ui, repo, *pats, **opts):
4224 """redo merges or set/view the merge status of files
4227 """redo merges or set/view the merge status of files
4225
4228
4226 Merges with unresolved conflicts are often the result of
4229 Merges with unresolved conflicts are often the result of
4227 non-interactive merging using the ``internal:merge`` configuration
4230 non-interactive merging using the ``internal:merge`` configuration
4228 setting, or a command-line merge tool like ``diff3``. The resolve
4231 setting, or a command-line merge tool like ``diff3``. The resolve
4229 command is used to manage the files involved in a merge, after
4232 command is used to manage the files involved in a merge, after
4230 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4233 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4231 working directory must have two parents). See :hg:`help
4234 working directory must have two parents). See :hg:`help
4232 merge-tools` for information on configuring merge tools.
4235 merge-tools` for information on configuring merge tools.
4233
4236
4234 The resolve command can be used in the following ways:
4237 The resolve command can be used in the following ways:
4235
4238
4236 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4239 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4237 files, discarding any previous merge attempts. Re-merging is not
4240 files, discarding any previous merge attempts. Re-merging is not
4238 performed for files already marked as resolved. Use ``--all/-a``
4241 performed for files already marked as resolved. Use ``--all/-a``
4239 to select all unresolved files. ``--tool`` can be used to specify
4242 to select all unresolved files. ``--tool`` can be used to specify
4240 the merge tool used for the given files. It overrides the HGMERGE
4243 the merge tool used for the given files. It overrides the HGMERGE
4241 environment variable and your configuration files. Previous file
4244 environment variable and your configuration files. Previous file
4242 contents are saved with a ``.orig`` suffix.
4245 contents are saved with a ``.orig`` suffix.
4243
4246
4244 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4247 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4245 (e.g. after having manually fixed-up the files). The default is
4248 (e.g. after having manually fixed-up the files). The default is
4246 to mark all unresolved files.
4249 to mark all unresolved files.
4247
4250
4248 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4251 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4249 default is to mark all resolved files.
4252 default is to mark all resolved files.
4250
4253
4251 - :hg:`resolve -l`: list files which had or still have conflicts.
4254 - :hg:`resolve -l`: list files which had or still have conflicts.
4252 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4255 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4253 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4256 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4254 the list. See :hg:`help filesets` for details.
4257 the list. See :hg:`help filesets` for details.
4255
4258
4256 .. note::
4259 .. note::
4257
4260
4258 Mercurial will not let you commit files with unresolved merge
4261 Mercurial will not let you commit files with unresolved merge
4259 conflicts. You must use :hg:`resolve -m ...` before you can
4262 conflicts. You must use :hg:`resolve -m ...` before you can
4260 commit after a conflicting merge.
4263 commit after a conflicting merge.
4261
4264
4262 Returns 0 on success, 1 if any files fail a resolve attempt.
4265 Returns 0 on success, 1 if any files fail a resolve attempt.
4263 """
4266 """
4264
4267
4265 flaglist = 'all mark unmark list no_status'.split()
4268 flaglist = 'all mark unmark list no_status'.split()
4266 all, mark, unmark, show, nostatus = \
4269 all, mark, unmark, show, nostatus = \
4267 [opts.get(o) for o in flaglist]
4270 [opts.get(o) for o in flaglist]
4268
4271
4269 if (show and (mark or unmark)) or (mark and unmark):
4272 if (show and (mark or unmark)) or (mark and unmark):
4270 raise error.Abort(_("too many options specified"))
4273 raise error.Abort(_("too many options specified"))
4271 if pats and all:
4274 if pats and all:
4272 raise error.Abort(_("can't specify --all and patterns"))
4275 raise error.Abort(_("can't specify --all and patterns"))
4273 if not (all or pats or show or mark or unmark):
4276 if not (all or pats or show or mark or unmark):
4274 raise error.Abort(_('no files or directories specified'),
4277 raise error.Abort(_('no files or directories specified'),
4275 hint=('use --all to re-merge all unresolved files'))
4278 hint=('use --all to re-merge all unresolved files'))
4276
4279
4277 if show:
4280 if show:
4278 ui.pager('resolve')
4281 ui.pager('resolve')
4279 fm = ui.formatter('resolve', opts)
4282 fm = ui.formatter('resolve', opts)
4280 ms = mergemod.mergestate.read(repo)
4283 ms = mergemod.mergestate.read(repo)
4281 m = scmutil.match(repo[None], pats, opts)
4284 m = scmutil.match(repo[None], pats, opts)
4282 for f in ms:
4285 for f in ms:
4283 if not m(f):
4286 if not m(f):
4284 continue
4287 continue
4285 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4288 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4286 'd': 'driverresolved'}[ms[f]]
4289 'd': 'driverresolved'}[ms[f]]
4287 fm.startitem()
4290 fm.startitem()
4288 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4291 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4289 fm.write('path', '%s\n', f, label=l)
4292 fm.write('path', '%s\n', f, label=l)
4290 fm.end()
4293 fm.end()
4291 return 0
4294 return 0
4292
4295
4293 with repo.wlock():
4296 with repo.wlock():
4294 ms = mergemod.mergestate.read(repo)
4297 ms = mergemod.mergestate.read(repo)
4295
4298
4296 if not (ms.active() or repo.dirstate.p2() != nullid):
4299 if not (ms.active() or repo.dirstate.p2() != nullid):
4297 raise error.Abort(
4300 raise error.Abort(
4298 _('resolve command not applicable when not merging'))
4301 _('resolve command not applicable when not merging'))
4299
4302
4300 wctx = repo[None]
4303 wctx = repo[None]
4301
4304
4302 if ms.mergedriver and ms.mdstate() == 'u':
4305 if ms.mergedriver and ms.mdstate() == 'u':
4303 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4306 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4304 ms.commit()
4307 ms.commit()
4305 # allow mark and unmark to go through
4308 # allow mark and unmark to go through
4306 if not mark and not unmark and not proceed:
4309 if not mark and not unmark and not proceed:
4307 return 1
4310 return 1
4308
4311
4309 m = scmutil.match(wctx, pats, opts)
4312 m = scmutil.match(wctx, pats, opts)
4310 ret = 0
4313 ret = 0
4311 didwork = False
4314 didwork = False
4312 runconclude = False
4315 runconclude = False
4313
4316
4314 tocomplete = []
4317 tocomplete = []
4315 for f in ms:
4318 for f in ms:
4316 if not m(f):
4319 if not m(f):
4317 continue
4320 continue
4318
4321
4319 didwork = True
4322 didwork = True
4320
4323
4321 # don't let driver-resolved files be marked, and run the conclude
4324 # don't let driver-resolved files be marked, and run the conclude
4322 # step if asked to resolve
4325 # step if asked to resolve
4323 if ms[f] == "d":
4326 if ms[f] == "d":
4324 exact = m.exact(f)
4327 exact = m.exact(f)
4325 if mark:
4328 if mark:
4326 if exact:
4329 if exact:
4327 ui.warn(_('not marking %s as it is driver-resolved\n')
4330 ui.warn(_('not marking %s as it is driver-resolved\n')
4328 % f)
4331 % f)
4329 elif unmark:
4332 elif unmark:
4330 if exact:
4333 if exact:
4331 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4334 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4332 % f)
4335 % f)
4333 else:
4336 else:
4334 runconclude = True
4337 runconclude = True
4335 continue
4338 continue
4336
4339
4337 if mark:
4340 if mark:
4338 ms.mark(f, "r")
4341 ms.mark(f, "r")
4339 elif unmark:
4342 elif unmark:
4340 ms.mark(f, "u")
4343 ms.mark(f, "u")
4341 else:
4344 else:
4342 # backup pre-resolve (merge uses .orig for its own purposes)
4345 # backup pre-resolve (merge uses .orig for its own purposes)
4343 a = repo.wjoin(f)
4346 a = repo.wjoin(f)
4344 try:
4347 try:
4345 util.copyfile(a, a + ".resolve")
4348 util.copyfile(a, a + ".resolve")
4346 except (IOError, OSError) as inst:
4349 except (IOError, OSError) as inst:
4347 if inst.errno != errno.ENOENT:
4350 if inst.errno != errno.ENOENT:
4348 raise
4351 raise
4349
4352
4350 try:
4353 try:
4351 # preresolve file
4354 # preresolve file
4352 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4355 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4353 'resolve')
4356 'resolve')
4354 complete, r = ms.preresolve(f, wctx)
4357 complete, r = ms.preresolve(f, wctx)
4355 if not complete:
4358 if not complete:
4356 tocomplete.append(f)
4359 tocomplete.append(f)
4357 elif r:
4360 elif r:
4358 ret = 1
4361 ret = 1
4359 finally:
4362 finally:
4360 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4363 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4361 ms.commit()
4364 ms.commit()
4362
4365
4363 # replace filemerge's .orig file with our resolve file, but only
4366 # replace filemerge's .orig file with our resolve file, but only
4364 # for merges that are complete
4367 # for merges that are complete
4365 if complete:
4368 if complete:
4366 try:
4369 try:
4367 util.rename(a + ".resolve",
4370 util.rename(a + ".resolve",
4368 scmutil.origpath(ui, repo, a))
4371 scmutil.origpath(ui, repo, a))
4369 except OSError as inst:
4372 except OSError as inst:
4370 if inst.errno != errno.ENOENT:
4373 if inst.errno != errno.ENOENT:
4371 raise
4374 raise
4372
4375
4373 for f in tocomplete:
4376 for f in tocomplete:
4374 try:
4377 try:
4375 # resolve file
4378 # resolve file
4376 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4379 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4377 'resolve')
4380 'resolve')
4378 r = ms.resolve(f, wctx)
4381 r = ms.resolve(f, wctx)
4379 if r:
4382 if r:
4380 ret = 1
4383 ret = 1
4381 finally:
4384 finally:
4382 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4385 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4383 ms.commit()
4386 ms.commit()
4384
4387
4385 # replace filemerge's .orig file with our resolve file
4388 # replace filemerge's .orig file with our resolve file
4386 a = repo.wjoin(f)
4389 a = repo.wjoin(f)
4387 try:
4390 try:
4388 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4391 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4389 except OSError as inst:
4392 except OSError as inst:
4390 if inst.errno != errno.ENOENT:
4393 if inst.errno != errno.ENOENT:
4391 raise
4394 raise
4392
4395
4393 ms.commit()
4396 ms.commit()
4394 ms.recordactions()
4397 ms.recordactions()
4395
4398
4396 if not didwork and pats:
4399 if not didwork and pats:
4397 hint = None
4400 hint = None
4398 if not any([p for p in pats if p.find(':') >= 0]):
4401 if not any([p for p in pats if p.find(':') >= 0]):
4399 pats = ['path:%s' % p for p in pats]
4402 pats = ['path:%s' % p for p in pats]
4400 m = scmutil.match(wctx, pats, opts)
4403 m = scmutil.match(wctx, pats, opts)
4401 for f in ms:
4404 for f in ms:
4402 if not m(f):
4405 if not m(f):
4403 continue
4406 continue
4404 flags = ''.join(['-%s ' % o[0] for o in flaglist
4407 flags = ''.join(['-%s ' % o[0] for o in flaglist
4405 if opts.get(o)])
4408 if opts.get(o)])
4406 hint = _("(try: hg resolve %s%s)\n") % (
4409 hint = _("(try: hg resolve %s%s)\n") % (
4407 flags,
4410 flags,
4408 ' '.join(pats))
4411 ' '.join(pats))
4409 break
4412 break
4410 ui.warn(_("arguments do not match paths that need resolving\n"))
4413 ui.warn(_("arguments do not match paths that need resolving\n"))
4411 if hint:
4414 if hint:
4412 ui.warn(hint)
4415 ui.warn(hint)
4413 elif ms.mergedriver and ms.mdstate() != 's':
4416 elif ms.mergedriver and ms.mdstate() != 's':
4414 # run conclude step when either a driver-resolved file is requested
4417 # run conclude step when either a driver-resolved file is requested
4415 # or there are no driver-resolved files
4418 # or there are no driver-resolved files
4416 # we can't use 'ret' to determine whether any files are unresolved
4419 # we can't use 'ret' to determine whether any files are unresolved
4417 # because we might not have tried to resolve some
4420 # because we might not have tried to resolve some
4418 if ((runconclude or not list(ms.driverresolved()))
4421 if ((runconclude or not list(ms.driverresolved()))
4419 and not list(ms.unresolved())):
4422 and not list(ms.unresolved())):
4420 proceed = mergemod.driverconclude(repo, ms, wctx)
4423 proceed = mergemod.driverconclude(repo, ms, wctx)
4421 ms.commit()
4424 ms.commit()
4422 if not proceed:
4425 if not proceed:
4423 return 1
4426 return 1
4424
4427
4425 # Nudge users into finishing an unfinished operation
4428 # Nudge users into finishing an unfinished operation
4426 unresolvedf = list(ms.unresolved())
4429 unresolvedf = list(ms.unresolved())
4427 driverresolvedf = list(ms.driverresolved())
4430 driverresolvedf = list(ms.driverresolved())
4428 if not unresolvedf and not driverresolvedf:
4431 if not unresolvedf and not driverresolvedf:
4429 ui.status(_('(no more unresolved files)\n'))
4432 ui.status(_('(no more unresolved files)\n'))
4430 cmdutil.checkafterresolved(repo)
4433 cmdutil.checkafterresolved(repo)
4431 elif not unresolvedf:
4434 elif not unresolvedf:
4432 ui.status(_('(no more unresolved files -- '
4435 ui.status(_('(no more unresolved files -- '
4433 'run "hg resolve --all" to conclude)\n'))
4436 'run "hg resolve --all" to conclude)\n'))
4434
4437
4435 return ret
4438 return ret
4436
4439
4437 @command('revert',
4440 @command('revert',
4438 [('a', 'all', None, _('revert all changes when no arguments given')),
4441 [('a', 'all', None, _('revert all changes when no arguments given')),
4439 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4442 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4440 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4443 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4441 ('C', 'no-backup', None, _('do not save backup copies of files')),
4444 ('C', 'no-backup', None, _('do not save backup copies of files')),
4442 ('i', 'interactive', None,
4445 ('i', 'interactive', None,
4443 _('interactively select the changes (EXPERIMENTAL)')),
4446 _('interactively select the changes (EXPERIMENTAL)')),
4444 ] + walkopts + dryrunopts,
4447 ] + walkopts + dryrunopts,
4445 _('[OPTION]... [-r REV] [NAME]...'))
4448 _('[OPTION]... [-r REV] [NAME]...'))
4446 def revert(ui, repo, *pats, **opts):
4449 def revert(ui, repo, *pats, **opts):
4447 """restore files to their checkout state
4450 """restore files to their checkout state
4448
4451
4449 .. note::
4452 .. note::
4450
4453
4451 To check out earlier revisions, you should use :hg:`update REV`.
4454 To check out earlier revisions, you should use :hg:`update REV`.
4452 To cancel an uncommitted merge (and lose your changes),
4455 To cancel an uncommitted merge (and lose your changes),
4453 use :hg:`update --clean .`.
4456 use :hg:`update --clean .`.
4454
4457
4455 With no revision specified, revert the specified files or directories
4458 With no revision specified, revert the specified files or directories
4456 to the contents they had in the parent of the working directory.
4459 to the contents they had in the parent of the working directory.
4457 This restores the contents of files to an unmodified
4460 This restores the contents of files to an unmodified
4458 state and unschedules adds, removes, copies, and renames. If the
4461 state and unschedules adds, removes, copies, and renames. If the
4459 working directory has two parents, you must explicitly specify a
4462 working directory has two parents, you must explicitly specify a
4460 revision.
4463 revision.
4461
4464
4462 Using the -r/--rev or -d/--date options, revert the given files or
4465 Using the -r/--rev or -d/--date options, revert the given files or
4463 directories to their states as of a specific revision. Because
4466 directories to their states as of a specific revision. Because
4464 revert does not change the working directory parents, this will
4467 revert does not change the working directory parents, this will
4465 cause these files to appear modified. This can be helpful to "back
4468 cause these files to appear modified. This can be helpful to "back
4466 out" some or all of an earlier change. See :hg:`backout` for a
4469 out" some or all of an earlier change. See :hg:`backout` for a
4467 related method.
4470 related method.
4468
4471
4469 Modified files are saved with a .orig suffix before reverting.
4472 Modified files are saved with a .orig suffix before reverting.
4470 To disable these backups, use --no-backup. It is possible to store
4473 To disable these backups, use --no-backup. It is possible to store
4471 the backup files in a custom directory relative to the root of the
4474 the backup files in a custom directory relative to the root of the
4472 repository by setting the ``ui.origbackuppath`` configuration
4475 repository by setting the ``ui.origbackuppath`` configuration
4473 option.
4476 option.
4474
4477
4475 See :hg:`help dates` for a list of formats valid for -d/--date.
4478 See :hg:`help dates` for a list of formats valid for -d/--date.
4476
4479
4477 See :hg:`help backout` for a way to reverse the effect of an
4480 See :hg:`help backout` for a way to reverse the effect of an
4478 earlier changeset.
4481 earlier changeset.
4479
4482
4480 Returns 0 on success.
4483 Returns 0 on success.
4481 """
4484 """
4482
4485
4483 if opts.get("date"):
4486 if opts.get("date"):
4484 if opts.get("rev"):
4487 if opts.get("rev"):
4485 raise error.Abort(_("you can't specify a revision and a date"))
4488 raise error.Abort(_("you can't specify a revision and a date"))
4486 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4489 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4487
4490
4488 parent, p2 = repo.dirstate.parents()
4491 parent, p2 = repo.dirstate.parents()
4489 if not opts.get('rev') and p2 != nullid:
4492 if not opts.get('rev') and p2 != nullid:
4490 # revert after merge is a trap for new users (issue2915)
4493 # revert after merge is a trap for new users (issue2915)
4491 raise error.Abort(_('uncommitted merge with no revision specified'),
4494 raise error.Abort(_('uncommitted merge with no revision specified'),
4492 hint=_("use 'hg update' or see 'hg help revert'"))
4495 hint=_("use 'hg update' or see 'hg help revert'"))
4493
4496
4494 ctx = scmutil.revsingle(repo, opts.get('rev'))
4497 ctx = scmutil.revsingle(repo, opts.get('rev'))
4495
4498
4496 if (not (pats or opts.get('include') or opts.get('exclude') or
4499 if (not (pats or opts.get('include') or opts.get('exclude') or
4497 opts.get('all') or opts.get('interactive'))):
4500 opts.get('all') or opts.get('interactive'))):
4498 msg = _("no files or directories specified")
4501 msg = _("no files or directories specified")
4499 if p2 != nullid:
4502 if p2 != nullid:
4500 hint = _("uncommitted merge, use --all to discard all changes,"
4503 hint = _("uncommitted merge, use --all to discard all changes,"
4501 " or 'hg update -C .' to abort the merge")
4504 " or 'hg update -C .' to abort the merge")
4502 raise error.Abort(msg, hint=hint)
4505 raise error.Abort(msg, hint=hint)
4503 dirty = any(repo.status())
4506 dirty = any(repo.status())
4504 node = ctx.node()
4507 node = ctx.node()
4505 if node != parent:
4508 if node != parent:
4506 if dirty:
4509 if dirty:
4507 hint = _("uncommitted changes, use --all to discard all"
4510 hint = _("uncommitted changes, use --all to discard all"
4508 " changes, or 'hg update %s' to update") % ctx.rev()
4511 " changes, or 'hg update %s' to update") % ctx.rev()
4509 else:
4512 else:
4510 hint = _("use --all to revert all files,"
4513 hint = _("use --all to revert all files,"
4511 " or 'hg update %s' to update") % ctx.rev()
4514 " or 'hg update %s' to update") % ctx.rev()
4512 elif dirty:
4515 elif dirty:
4513 hint = _("uncommitted changes, use --all to discard all changes")
4516 hint = _("uncommitted changes, use --all to discard all changes")
4514 else:
4517 else:
4515 hint = _("use --all to revert all files")
4518 hint = _("use --all to revert all files")
4516 raise error.Abort(msg, hint=hint)
4519 raise error.Abort(msg, hint=hint)
4517
4520
4518 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4521 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4519
4522
4520 @command('rollback', dryrunopts +
4523 @command('rollback', dryrunopts +
4521 [('f', 'force', False, _('ignore safety measures'))])
4524 [('f', 'force', False, _('ignore safety measures'))])
4522 def rollback(ui, repo, **opts):
4525 def rollback(ui, repo, **opts):
4523 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4526 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4524
4527
4525 Please use :hg:`commit --amend` instead of rollback to correct
4528 Please use :hg:`commit --amend` instead of rollback to correct
4526 mistakes in the last commit.
4529 mistakes in the last commit.
4527
4530
4528 This command should be used with care. There is only one level of
4531 This command should be used with care. There is only one level of
4529 rollback, and there is no way to undo a rollback. It will also
4532 rollback, and there is no way to undo a rollback. It will also
4530 restore the dirstate at the time of the last transaction, losing
4533 restore the dirstate at the time of the last transaction, losing
4531 any dirstate changes since that time. This command does not alter
4534 any dirstate changes since that time. This command does not alter
4532 the working directory.
4535 the working directory.
4533
4536
4534 Transactions are used to encapsulate the effects of all commands
4537 Transactions are used to encapsulate the effects of all commands
4535 that create new changesets or propagate existing changesets into a
4538 that create new changesets or propagate existing changesets into a
4536 repository.
4539 repository.
4537
4540
4538 .. container:: verbose
4541 .. container:: verbose
4539
4542
4540 For example, the following commands are transactional, and their
4543 For example, the following commands are transactional, and their
4541 effects can be rolled back:
4544 effects can be rolled back:
4542
4545
4543 - commit
4546 - commit
4544 - import
4547 - import
4545 - pull
4548 - pull
4546 - push (with this repository as the destination)
4549 - push (with this repository as the destination)
4547 - unbundle
4550 - unbundle
4548
4551
4549 To avoid permanent data loss, rollback will refuse to rollback a
4552 To avoid permanent data loss, rollback will refuse to rollback a
4550 commit transaction if it isn't checked out. Use --force to
4553 commit transaction if it isn't checked out. Use --force to
4551 override this protection.
4554 override this protection.
4552
4555
4553 The rollback command can be entirely disabled by setting the
4556 The rollback command can be entirely disabled by setting the
4554 ``ui.rollback`` configuration setting to false. If you're here
4557 ``ui.rollback`` configuration setting to false. If you're here
4555 because you want to use rollback and it's disabled, you can
4558 because you want to use rollback and it's disabled, you can
4556 re-enable the command by setting ``ui.rollback`` to true.
4559 re-enable the command by setting ``ui.rollback`` to true.
4557
4560
4558 This command is not intended for use on public repositories. Once
4561 This command is not intended for use on public repositories. Once
4559 changes are visible for pull by other users, rolling a transaction
4562 changes are visible for pull by other users, rolling a transaction
4560 back locally is ineffective (someone else may already have pulled
4563 back locally is ineffective (someone else may already have pulled
4561 the changes). Furthermore, a race is possible with readers of the
4564 the changes). Furthermore, a race is possible with readers of the
4562 repository; for example an in-progress pull from the repository
4565 repository; for example an in-progress pull from the repository
4563 may fail if a rollback is performed.
4566 may fail if a rollback is performed.
4564
4567
4565 Returns 0 on success, 1 if no rollback data is available.
4568 Returns 0 on success, 1 if no rollback data is available.
4566 """
4569 """
4567 if not ui.configbool('ui', 'rollback', True):
4570 if not ui.configbool('ui', 'rollback', True):
4568 raise error.Abort(_('rollback is disabled because it is unsafe'),
4571 raise error.Abort(_('rollback is disabled because it is unsafe'),
4569 hint=('see `hg help -v rollback` for information'))
4572 hint=('see `hg help -v rollback` for information'))
4570 return repo.rollback(dryrun=opts.get('dry_run'),
4573 return repo.rollback(dryrun=opts.get('dry_run'),
4571 force=opts.get('force'))
4574 force=opts.get('force'))
4572
4575
4573 @command('root', [])
4576 @command('root', [])
4574 def root(ui, repo):
4577 def root(ui, repo):
4575 """print the root (top) of the current working directory
4578 """print the root (top) of the current working directory
4576
4579
4577 Print the root directory of the current repository.
4580 Print the root directory of the current repository.
4578
4581
4579 Returns 0 on success.
4582 Returns 0 on success.
4580 """
4583 """
4581 ui.write(repo.root + "\n")
4584 ui.write(repo.root + "\n")
4582
4585
4583 @command('^serve',
4586 @command('^serve',
4584 [('A', 'accesslog', '', _('name of access log file to write to'),
4587 [('A', 'accesslog', '', _('name of access log file to write to'),
4585 _('FILE')),
4588 _('FILE')),
4586 ('d', 'daemon', None, _('run server in background')),
4589 ('d', 'daemon', None, _('run server in background')),
4587 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4590 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4588 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4591 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4589 # use string type, then we can check if something was passed
4592 # use string type, then we can check if something was passed
4590 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4593 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4591 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4594 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4592 _('ADDR')),
4595 _('ADDR')),
4593 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4596 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4594 _('PREFIX')),
4597 _('PREFIX')),
4595 ('n', 'name', '',
4598 ('n', 'name', '',
4596 _('name to show in web pages (default: working directory)'), _('NAME')),
4599 _('name to show in web pages (default: working directory)'), _('NAME')),
4597 ('', 'web-conf', '',
4600 ('', 'web-conf', '',
4598 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4601 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4599 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4602 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4600 _('FILE')),
4603 _('FILE')),
4601 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4604 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4602 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4605 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4603 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4606 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4604 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4607 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4605 ('', 'style', '', _('template style to use'), _('STYLE')),
4608 ('', 'style', '', _('template style to use'), _('STYLE')),
4606 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4609 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4607 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4610 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4608 _('[OPTION]...'),
4611 _('[OPTION]...'),
4609 optionalrepo=True)
4612 optionalrepo=True)
4610 def serve(ui, repo, **opts):
4613 def serve(ui, repo, **opts):
4611 """start stand-alone webserver
4614 """start stand-alone webserver
4612
4615
4613 Start a local HTTP repository browser and pull server. You can use
4616 Start a local HTTP repository browser and pull server. You can use
4614 this for ad-hoc sharing and browsing of repositories. It is
4617 this for ad-hoc sharing and browsing of repositories. It is
4615 recommended to use a real web server to serve a repository for
4618 recommended to use a real web server to serve a repository for
4616 longer periods of time.
4619 longer periods of time.
4617
4620
4618 Please note that the server does not implement access control.
4621 Please note that the server does not implement access control.
4619 This means that, by default, anybody can read from the server and
4622 This means that, by default, anybody can read from the server and
4620 nobody can write to it by default. Set the ``web.allow_push``
4623 nobody can write to it by default. Set the ``web.allow_push``
4621 option to ``*`` to allow everybody to push to the server. You
4624 option to ``*`` to allow everybody to push to the server. You
4622 should use a real web server if you need to authenticate users.
4625 should use a real web server if you need to authenticate users.
4623
4626
4624 By default, the server logs accesses to stdout and errors to
4627 By default, the server logs accesses to stdout and errors to
4625 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4628 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4626 files.
4629 files.
4627
4630
4628 To have the server choose a free port number to listen on, specify
4631 To have the server choose a free port number to listen on, specify
4629 a port number of 0; in this case, the server will print the port
4632 a port number of 0; in this case, the server will print the port
4630 number it uses.
4633 number it uses.
4631
4634
4632 Returns 0 on success.
4635 Returns 0 on success.
4633 """
4636 """
4634
4637
4635 if opts["stdio"] and opts["cmdserver"]:
4638 if opts["stdio"] and opts["cmdserver"]:
4636 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4639 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4637
4640
4638 if opts["stdio"]:
4641 if opts["stdio"]:
4639 if repo is None:
4642 if repo is None:
4640 raise error.RepoError(_("there is no Mercurial repository here"
4643 raise error.RepoError(_("there is no Mercurial repository here"
4641 " (.hg not found)"))
4644 " (.hg not found)"))
4642 s = sshserver.sshserver(ui, repo)
4645 s = sshserver.sshserver(ui, repo)
4643 s.serve_forever()
4646 s.serve_forever()
4644
4647
4645 service = server.createservice(ui, repo, opts)
4648 service = server.createservice(ui, repo, opts)
4646 return server.runservice(opts, initfn=service.init, runfn=service.run)
4649 return server.runservice(opts, initfn=service.init, runfn=service.run)
4647
4650
4648 @command('^status|st',
4651 @command('^status|st',
4649 [('A', 'all', None, _('show status of all files')),
4652 [('A', 'all', None, _('show status of all files')),
4650 ('m', 'modified', None, _('show only modified files')),
4653 ('m', 'modified', None, _('show only modified files')),
4651 ('a', 'added', None, _('show only added files')),
4654 ('a', 'added', None, _('show only added files')),
4652 ('r', 'removed', None, _('show only removed files')),
4655 ('r', 'removed', None, _('show only removed files')),
4653 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4656 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4654 ('c', 'clean', None, _('show only files without changes')),
4657 ('c', 'clean', None, _('show only files without changes')),
4655 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4658 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4656 ('i', 'ignored', None, _('show only ignored files')),
4659 ('i', 'ignored', None, _('show only ignored files')),
4657 ('n', 'no-status', None, _('hide status prefix')),
4660 ('n', 'no-status', None, _('hide status prefix')),
4658 ('C', 'copies', None, _('show source of copied files')),
4661 ('C', 'copies', None, _('show source of copied files')),
4659 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4662 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4660 ('', 'rev', [], _('show difference from revision'), _('REV')),
4663 ('', 'rev', [], _('show difference from revision'), _('REV')),
4661 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4664 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4662 ] + walkopts + subrepoopts + formatteropts,
4665 ] + walkopts + subrepoopts + formatteropts,
4663 _('[OPTION]... [FILE]...'),
4666 _('[OPTION]... [FILE]...'),
4664 inferrepo=True)
4667 inferrepo=True)
4665 def status(ui, repo, *pats, **opts):
4668 def status(ui, repo, *pats, **opts):
4666 """show changed files in the working directory
4669 """show changed files in the working directory
4667
4670
4668 Show status of files in the repository. If names are given, only
4671 Show status of files in the repository. If names are given, only
4669 files that match are shown. Files that are clean or ignored or
4672 files that match are shown. Files that are clean or ignored or
4670 the source of a copy/move operation, are not listed unless
4673 the source of a copy/move operation, are not listed unless
4671 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4674 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4672 Unless options described with "show only ..." are given, the
4675 Unless options described with "show only ..." are given, the
4673 options -mardu are used.
4676 options -mardu are used.
4674
4677
4675 Option -q/--quiet hides untracked (unknown and ignored) files
4678 Option -q/--quiet hides untracked (unknown and ignored) files
4676 unless explicitly requested with -u/--unknown or -i/--ignored.
4679 unless explicitly requested with -u/--unknown or -i/--ignored.
4677
4680
4678 .. note::
4681 .. note::
4679
4682
4680 :hg:`status` may appear to disagree with diff if permissions have
4683 :hg:`status` may appear to disagree with diff if permissions have
4681 changed or a merge has occurred. The standard diff format does
4684 changed or a merge has occurred. The standard diff format does
4682 not report permission changes and diff only reports changes
4685 not report permission changes and diff only reports changes
4683 relative to one merge parent.
4686 relative to one merge parent.
4684
4687
4685 If one revision is given, it is used as the base revision.
4688 If one revision is given, it is used as the base revision.
4686 If two revisions are given, the differences between them are
4689 If two revisions are given, the differences between them are
4687 shown. The --change option can also be used as a shortcut to list
4690 shown. The --change option can also be used as a shortcut to list
4688 the changed files of a revision from its first parent.
4691 the changed files of a revision from its first parent.
4689
4692
4690 The codes used to show the status of files are::
4693 The codes used to show the status of files are::
4691
4694
4692 M = modified
4695 M = modified
4693 A = added
4696 A = added
4694 R = removed
4697 R = removed
4695 C = clean
4698 C = clean
4696 ! = missing (deleted by non-hg command, but still tracked)
4699 ! = missing (deleted by non-hg command, but still tracked)
4697 ? = not tracked
4700 ? = not tracked
4698 I = ignored
4701 I = ignored
4699 = origin of the previous file (with --copies)
4702 = origin of the previous file (with --copies)
4700
4703
4701 .. container:: verbose
4704 .. container:: verbose
4702
4705
4703 Examples:
4706 Examples:
4704
4707
4705 - show changes in the working directory relative to a
4708 - show changes in the working directory relative to a
4706 changeset::
4709 changeset::
4707
4710
4708 hg status --rev 9353
4711 hg status --rev 9353
4709
4712
4710 - show changes in the working directory relative to the
4713 - show changes in the working directory relative to the
4711 current directory (see :hg:`help patterns` for more information)::
4714 current directory (see :hg:`help patterns` for more information)::
4712
4715
4713 hg status re:
4716 hg status re:
4714
4717
4715 - show all changes including copies in an existing changeset::
4718 - show all changes including copies in an existing changeset::
4716
4719
4717 hg status --copies --change 9353
4720 hg status --copies --change 9353
4718
4721
4719 - get a NUL separated list of added files, suitable for xargs::
4722 - get a NUL separated list of added files, suitable for xargs::
4720
4723
4721 hg status -an0
4724 hg status -an0
4722
4725
4723 Returns 0 on success.
4726 Returns 0 on success.
4724 """
4727 """
4725
4728
4726 opts = pycompat.byteskwargs(opts)
4729 opts = pycompat.byteskwargs(opts)
4727 revs = opts.get('rev')
4730 revs = opts.get('rev')
4728 change = opts.get('change')
4731 change = opts.get('change')
4729
4732
4730 if revs and change:
4733 if revs and change:
4731 msg = _('cannot specify --rev and --change at the same time')
4734 msg = _('cannot specify --rev and --change at the same time')
4732 raise error.Abort(msg)
4735 raise error.Abort(msg)
4733 elif change:
4736 elif change:
4734 node2 = scmutil.revsingle(repo, change, None).node()
4737 node2 = scmutil.revsingle(repo, change, None).node()
4735 node1 = repo[node2].p1().node()
4738 node1 = repo[node2].p1().node()
4736 else:
4739 else:
4737 node1, node2 = scmutil.revpair(repo, revs)
4740 node1, node2 = scmutil.revpair(repo, revs)
4738
4741
4739 if pats or ui.configbool('commands', 'status.relative'):
4742 if pats or ui.configbool('commands', 'status.relative'):
4740 cwd = repo.getcwd()
4743 cwd = repo.getcwd()
4741 else:
4744 else:
4742 cwd = ''
4745 cwd = ''
4743
4746
4744 if opts.get('print0'):
4747 if opts.get('print0'):
4745 end = '\0'
4748 end = '\0'
4746 else:
4749 else:
4747 end = '\n'
4750 end = '\n'
4748 copy = {}
4751 copy = {}
4749 states = 'modified added removed deleted unknown ignored clean'.split()
4752 states = 'modified added removed deleted unknown ignored clean'.split()
4750 show = [k for k in states if opts.get(k)]
4753 show = [k for k in states if opts.get(k)]
4751 if opts.get('all'):
4754 if opts.get('all'):
4752 show += ui.quiet and (states[:4] + ['clean']) or states
4755 show += ui.quiet and (states[:4] + ['clean']) or states
4753 if not show:
4756 if not show:
4754 if ui.quiet:
4757 if ui.quiet:
4755 show = states[:4]
4758 show = states[:4]
4756 else:
4759 else:
4757 show = states[:5]
4760 show = states[:5]
4758
4761
4759 m = scmutil.match(repo[node2], pats, opts)
4762 m = scmutil.match(repo[node2], pats, opts)
4760 stat = repo.status(node1, node2, m,
4763 stat = repo.status(node1, node2, m,
4761 'ignored' in show, 'clean' in show, 'unknown' in show,
4764 'ignored' in show, 'clean' in show, 'unknown' in show,
4762 opts.get('subrepos'))
4765 opts.get('subrepos'))
4763 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4766 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4764
4767
4765 if (opts.get('all') or opts.get('copies')
4768 if (opts.get('all') or opts.get('copies')
4766 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4769 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4767 copy = copies.pathcopies(repo[node1], repo[node2], m)
4770 copy = copies.pathcopies(repo[node1], repo[node2], m)
4768
4771
4769 ui.pager('status')
4772 ui.pager('status')
4770 fm = ui.formatter('status', opts)
4773 fm = ui.formatter('status', opts)
4771 fmt = '%s' + end
4774 fmt = '%s' + end
4772 showchar = not opts.get('no_status')
4775 showchar = not opts.get('no_status')
4773
4776
4774 for state, char, files in changestates:
4777 for state, char, files in changestates:
4775 if state in show:
4778 if state in show:
4776 label = 'status.' + state
4779 label = 'status.' + state
4777 for f in files:
4780 for f in files:
4778 fm.startitem()
4781 fm.startitem()
4779 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4782 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4780 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4783 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4781 if f in copy:
4784 if f in copy:
4782 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4785 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4783 label='status.copied')
4786 label='status.copied')
4784 fm.end()
4787 fm.end()
4785
4788
4786 @command('^summary|sum',
4789 @command('^summary|sum',
4787 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4790 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4788 def summary(ui, repo, **opts):
4791 def summary(ui, repo, **opts):
4789 """summarize working directory state
4792 """summarize working directory state
4790
4793
4791 This generates a brief summary of the working directory state,
4794 This generates a brief summary of the working directory state,
4792 including parents, branch, commit status, phase and available updates.
4795 including parents, branch, commit status, phase and available updates.
4793
4796
4794 With the --remote option, this will check the default paths for
4797 With the --remote option, this will check the default paths for
4795 incoming and outgoing changes. This can be time-consuming.
4798 incoming and outgoing changes. This can be time-consuming.
4796
4799
4797 Returns 0 on success.
4800 Returns 0 on success.
4798 """
4801 """
4799
4802
4800 ui.pager('summary')
4803 ui.pager('summary')
4801 ctx = repo[None]
4804 ctx = repo[None]
4802 parents = ctx.parents()
4805 parents = ctx.parents()
4803 pnode = parents[0].node()
4806 pnode = parents[0].node()
4804 marks = []
4807 marks = []
4805
4808
4806 ms = None
4809 ms = None
4807 try:
4810 try:
4808 ms = mergemod.mergestate.read(repo)
4811 ms = mergemod.mergestate.read(repo)
4809 except error.UnsupportedMergeRecords as e:
4812 except error.UnsupportedMergeRecords as e:
4810 s = ' '.join(e.recordtypes)
4813 s = ' '.join(e.recordtypes)
4811 ui.warn(
4814 ui.warn(
4812 _('warning: merge state has unsupported record types: %s\n') % s)
4815 _('warning: merge state has unsupported record types: %s\n') % s)
4813 unresolved = 0
4816 unresolved = 0
4814 else:
4817 else:
4815 unresolved = [f for f in ms if ms[f] == 'u']
4818 unresolved = [f for f in ms if ms[f] == 'u']
4816
4819
4817 for p in parents:
4820 for p in parents:
4818 # label with log.changeset (instead of log.parent) since this
4821 # label with log.changeset (instead of log.parent) since this
4819 # shows a working directory parent *changeset*:
4822 # shows a working directory parent *changeset*:
4820 # i18n: column positioning for "hg summary"
4823 # i18n: column positioning for "hg summary"
4821 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4824 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4822 label=cmdutil._changesetlabels(p))
4825 label=cmdutil._changesetlabels(p))
4823 ui.write(' '.join(p.tags()), label='log.tag')
4826 ui.write(' '.join(p.tags()), label='log.tag')
4824 if p.bookmarks():
4827 if p.bookmarks():
4825 marks.extend(p.bookmarks())
4828 marks.extend(p.bookmarks())
4826 if p.rev() == -1:
4829 if p.rev() == -1:
4827 if not len(repo):
4830 if not len(repo):
4828 ui.write(_(' (empty repository)'))
4831 ui.write(_(' (empty repository)'))
4829 else:
4832 else:
4830 ui.write(_(' (no revision checked out)'))
4833 ui.write(_(' (no revision checked out)'))
4831 if p.troubled():
4834 if p.troubled():
4832 ui.write(' ('
4835 ui.write(' ('
4833 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4836 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4834 for trouble in p.troubles())
4837 for trouble in p.troubles())
4835 + ')')
4838 + ')')
4836 ui.write('\n')
4839 ui.write('\n')
4837 if p.description():
4840 if p.description():
4838 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4841 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4839 label='log.summary')
4842 label='log.summary')
4840
4843
4841 branch = ctx.branch()
4844 branch = ctx.branch()
4842 bheads = repo.branchheads(branch)
4845 bheads = repo.branchheads(branch)
4843 # i18n: column positioning for "hg summary"
4846 # i18n: column positioning for "hg summary"
4844 m = _('branch: %s\n') % branch
4847 m = _('branch: %s\n') % branch
4845 if branch != 'default':
4848 if branch != 'default':
4846 ui.write(m, label='log.branch')
4849 ui.write(m, label='log.branch')
4847 else:
4850 else:
4848 ui.status(m, label='log.branch')
4851 ui.status(m, label='log.branch')
4849
4852
4850 if marks:
4853 if marks:
4851 active = repo._activebookmark
4854 active = repo._activebookmark
4852 # i18n: column positioning for "hg summary"
4855 # i18n: column positioning for "hg summary"
4853 ui.write(_('bookmarks:'), label='log.bookmark')
4856 ui.write(_('bookmarks:'), label='log.bookmark')
4854 if active is not None:
4857 if active is not None:
4855 if active in marks:
4858 if active in marks:
4856 ui.write(' *' + active, label=activebookmarklabel)
4859 ui.write(' *' + active, label=activebookmarklabel)
4857 marks.remove(active)
4860 marks.remove(active)
4858 else:
4861 else:
4859 ui.write(' [%s]' % active, label=activebookmarklabel)
4862 ui.write(' [%s]' % active, label=activebookmarklabel)
4860 for m in marks:
4863 for m in marks:
4861 ui.write(' ' + m, label='log.bookmark')
4864 ui.write(' ' + m, label='log.bookmark')
4862 ui.write('\n', label='log.bookmark')
4865 ui.write('\n', label='log.bookmark')
4863
4866
4864 status = repo.status(unknown=True)
4867 status = repo.status(unknown=True)
4865
4868
4866 c = repo.dirstate.copies()
4869 c = repo.dirstate.copies()
4867 copied, renamed = [], []
4870 copied, renamed = [], []
4868 for d, s in c.iteritems():
4871 for d, s in c.iteritems():
4869 if s in status.removed:
4872 if s in status.removed:
4870 status.removed.remove(s)
4873 status.removed.remove(s)
4871 renamed.append(d)
4874 renamed.append(d)
4872 else:
4875 else:
4873 copied.append(d)
4876 copied.append(d)
4874 if d in status.added:
4877 if d in status.added:
4875 status.added.remove(d)
4878 status.added.remove(d)
4876
4879
4877 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4880 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4878
4881
4879 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4882 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4880 (ui.label(_('%d added'), 'status.added'), status.added),
4883 (ui.label(_('%d added'), 'status.added'), status.added),
4881 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4884 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4882 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4885 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4883 (ui.label(_('%d copied'), 'status.copied'), copied),
4886 (ui.label(_('%d copied'), 'status.copied'), copied),
4884 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4887 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4885 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4888 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4886 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4889 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4887 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4890 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4888 t = []
4891 t = []
4889 for l, s in labels:
4892 for l, s in labels:
4890 if s:
4893 if s:
4891 t.append(l % len(s))
4894 t.append(l % len(s))
4892
4895
4893 t = ', '.join(t)
4896 t = ', '.join(t)
4894 cleanworkdir = False
4897 cleanworkdir = False
4895
4898
4896 if repo.vfs.exists('graftstate'):
4899 if repo.vfs.exists('graftstate'):
4897 t += _(' (graft in progress)')
4900 t += _(' (graft in progress)')
4898 if repo.vfs.exists('updatestate'):
4901 if repo.vfs.exists('updatestate'):
4899 t += _(' (interrupted update)')
4902 t += _(' (interrupted update)')
4900 elif len(parents) > 1:
4903 elif len(parents) > 1:
4901 t += _(' (merge)')
4904 t += _(' (merge)')
4902 elif branch != parents[0].branch():
4905 elif branch != parents[0].branch():
4903 t += _(' (new branch)')
4906 t += _(' (new branch)')
4904 elif (parents[0].closesbranch() and
4907 elif (parents[0].closesbranch() and
4905 pnode in repo.branchheads(branch, closed=True)):
4908 pnode in repo.branchheads(branch, closed=True)):
4906 t += _(' (head closed)')
4909 t += _(' (head closed)')
4907 elif not (status.modified or status.added or status.removed or renamed or
4910 elif not (status.modified or status.added or status.removed or renamed or
4908 copied or subs):
4911 copied or subs):
4909 t += _(' (clean)')
4912 t += _(' (clean)')
4910 cleanworkdir = True
4913 cleanworkdir = True
4911 elif pnode not in bheads:
4914 elif pnode not in bheads:
4912 t += _(' (new branch head)')
4915 t += _(' (new branch head)')
4913
4916
4914 if parents:
4917 if parents:
4915 pendingphase = max(p.phase() for p in parents)
4918 pendingphase = max(p.phase() for p in parents)
4916 else:
4919 else:
4917 pendingphase = phases.public
4920 pendingphase = phases.public
4918
4921
4919 if pendingphase > phases.newcommitphase(ui):
4922 if pendingphase > phases.newcommitphase(ui):
4920 t += ' (%s)' % phases.phasenames[pendingphase]
4923 t += ' (%s)' % phases.phasenames[pendingphase]
4921
4924
4922 if cleanworkdir:
4925 if cleanworkdir:
4923 # i18n: column positioning for "hg summary"
4926 # i18n: column positioning for "hg summary"
4924 ui.status(_('commit: %s\n') % t.strip())
4927 ui.status(_('commit: %s\n') % t.strip())
4925 else:
4928 else:
4926 # i18n: column positioning for "hg summary"
4929 # i18n: column positioning for "hg summary"
4927 ui.write(_('commit: %s\n') % t.strip())
4930 ui.write(_('commit: %s\n') % t.strip())
4928
4931
4929 # all ancestors of branch heads - all ancestors of parent = new csets
4932 # all ancestors of branch heads - all ancestors of parent = new csets
4930 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4933 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4931 bheads))
4934 bheads))
4932
4935
4933 if new == 0:
4936 if new == 0:
4934 # i18n: column positioning for "hg summary"
4937 # i18n: column positioning for "hg summary"
4935 ui.status(_('update: (current)\n'))
4938 ui.status(_('update: (current)\n'))
4936 elif pnode not in bheads:
4939 elif pnode not in bheads:
4937 # i18n: column positioning for "hg summary"
4940 # i18n: column positioning for "hg summary"
4938 ui.write(_('update: %d new changesets (update)\n') % new)
4941 ui.write(_('update: %d new changesets (update)\n') % new)
4939 else:
4942 else:
4940 # i18n: column positioning for "hg summary"
4943 # i18n: column positioning for "hg summary"
4941 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4944 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4942 (new, len(bheads)))
4945 (new, len(bheads)))
4943
4946
4944 t = []
4947 t = []
4945 draft = len(repo.revs('draft()'))
4948 draft = len(repo.revs('draft()'))
4946 if draft:
4949 if draft:
4947 t.append(_('%d draft') % draft)
4950 t.append(_('%d draft') % draft)
4948 secret = len(repo.revs('secret()'))
4951 secret = len(repo.revs('secret()'))
4949 if secret:
4952 if secret:
4950 t.append(_('%d secret') % secret)
4953 t.append(_('%d secret') % secret)
4951
4954
4952 if draft or secret:
4955 if draft or secret:
4953 ui.status(_('phases: %s\n') % ', '.join(t))
4956 ui.status(_('phases: %s\n') % ', '.join(t))
4954
4957
4955 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4958 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4956 for trouble in ("unstable", "divergent", "bumped"):
4959 for trouble in ("unstable", "divergent", "bumped"):
4957 numtrouble = len(repo.revs(trouble + "()"))
4960 numtrouble = len(repo.revs(trouble + "()"))
4958 # We write all the possibilities to ease translation
4961 # We write all the possibilities to ease translation
4959 troublemsg = {
4962 troublemsg = {
4960 "unstable": _("unstable: %d changesets"),
4963 "unstable": _("unstable: %d changesets"),
4961 "divergent": _("divergent: %d changesets"),
4964 "divergent": _("divergent: %d changesets"),
4962 "bumped": _("bumped: %d changesets"),
4965 "bumped": _("bumped: %d changesets"),
4963 }
4966 }
4964 if numtrouble > 0:
4967 if numtrouble > 0:
4965 ui.status(troublemsg[trouble] % numtrouble + "\n")
4968 ui.status(troublemsg[trouble] % numtrouble + "\n")
4966
4969
4967 cmdutil.summaryhooks(ui, repo)
4970 cmdutil.summaryhooks(ui, repo)
4968
4971
4969 if opts.get('remote'):
4972 if opts.get('remote'):
4970 needsincoming, needsoutgoing = True, True
4973 needsincoming, needsoutgoing = True, True
4971 else:
4974 else:
4972 needsincoming, needsoutgoing = False, False
4975 needsincoming, needsoutgoing = False, False
4973 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4976 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4974 if i:
4977 if i:
4975 needsincoming = True
4978 needsincoming = True
4976 if o:
4979 if o:
4977 needsoutgoing = True
4980 needsoutgoing = True
4978 if not needsincoming and not needsoutgoing:
4981 if not needsincoming and not needsoutgoing:
4979 return
4982 return
4980
4983
4981 def getincoming():
4984 def getincoming():
4982 source, branches = hg.parseurl(ui.expandpath('default'))
4985 source, branches = hg.parseurl(ui.expandpath('default'))
4983 sbranch = branches[0]
4986 sbranch = branches[0]
4984 try:
4987 try:
4985 other = hg.peer(repo, {}, source)
4988 other = hg.peer(repo, {}, source)
4986 except error.RepoError:
4989 except error.RepoError:
4987 if opts.get('remote'):
4990 if opts.get('remote'):
4988 raise
4991 raise
4989 return source, sbranch, None, None, None
4992 return source, sbranch, None, None, None
4990 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4993 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4991 if revs:
4994 if revs:
4992 revs = [other.lookup(rev) for rev in revs]
4995 revs = [other.lookup(rev) for rev in revs]
4993 ui.debug('comparing with %s\n' % util.hidepassword(source))
4996 ui.debug('comparing with %s\n' % util.hidepassword(source))
4994 repo.ui.pushbuffer()
4997 repo.ui.pushbuffer()
4995 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4998 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4996 repo.ui.popbuffer()
4999 repo.ui.popbuffer()
4997 return source, sbranch, other, commoninc, commoninc[1]
5000 return source, sbranch, other, commoninc, commoninc[1]
4998
5001
4999 if needsincoming:
5002 if needsincoming:
5000 source, sbranch, sother, commoninc, incoming = getincoming()
5003 source, sbranch, sother, commoninc, incoming = getincoming()
5001 else:
5004 else:
5002 source = sbranch = sother = commoninc = incoming = None
5005 source = sbranch = sother = commoninc = incoming = None
5003
5006
5004 def getoutgoing():
5007 def getoutgoing():
5005 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5008 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5006 dbranch = branches[0]
5009 dbranch = branches[0]
5007 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5010 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5008 if source != dest:
5011 if source != dest:
5009 try:
5012 try:
5010 dother = hg.peer(repo, {}, dest)
5013 dother = hg.peer(repo, {}, dest)
5011 except error.RepoError:
5014 except error.RepoError:
5012 if opts.get('remote'):
5015 if opts.get('remote'):
5013 raise
5016 raise
5014 return dest, dbranch, None, None
5017 return dest, dbranch, None, None
5015 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5018 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5016 elif sother is None:
5019 elif sother is None:
5017 # there is no explicit destination peer, but source one is invalid
5020 # there is no explicit destination peer, but source one is invalid
5018 return dest, dbranch, None, None
5021 return dest, dbranch, None, None
5019 else:
5022 else:
5020 dother = sother
5023 dother = sother
5021 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5024 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5022 common = None
5025 common = None
5023 else:
5026 else:
5024 common = commoninc
5027 common = commoninc
5025 if revs:
5028 if revs:
5026 revs = [repo.lookup(rev) for rev in revs]
5029 revs = [repo.lookup(rev) for rev in revs]
5027 repo.ui.pushbuffer()
5030 repo.ui.pushbuffer()
5028 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5031 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5029 commoninc=common)
5032 commoninc=common)
5030 repo.ui.popbuffer()
5033 repo.ui.popbuffer()
5031 return dest, dbranch, dother, outgoing
5034 return dest, dbranch, dother, outgoing
5032
5035
5033 if needsoutgoing:
5036 if needsoutgoing:
5034 dest, dbranch, dother, outgoing = getoutgoing()
5037 dest, dbranch, dother, outgoing = getoutgoing()
5035 else:
5038 else:
5036 dest = dbranch = dother = outgoing = None
5039 dest = dbranch = dother = outgoing = None
5037
5040
5038 if opts.get('remote'):
5041 if opts.get('remote'):
5039 t = []
5042 t = []
5040 if incoming:
5043 if incoming:
5041 t.append(_('1 or more incoming'))
5044 t.append(_('1 or more incoming'))
5042 o = outgoing.missing
5045 o = outgoing.missing
5043 if o:
5046 if o:
5044 t.append(_('%d outgoing') % len(o))
5047 t.append(_('%d outgoing') % len(o))
5045 other = dother or sother
5048 other = dother or sother
5046 if 'bookmarks' in other.listkeys('namespaces'):
5049 if 'bookmarks' in other.listkeys('namespaces'):
5047 counts = bookmarks.summary(repo, other)
5050 counts = bookmarks.summary(repo, other)
5048 if counts[0] > 0:
5051 if counts[0] > 0:
5049 t.append(_('%d incoming bookmarks') % counts[0])
5052 t.append(_('%d incoming bookmarks') % counts[0])
5050 if counts[1] > 0:
5053 if counts[1] > 0:
5051 t.append(_('%d outgoing bookmarks') % counts[1])
5054 t.append(_('%d outgoing bookmarks') % counts[1])
5052
5055
5053 if t:
5056 if t:
5054 # i18n: column positioning for "hg summary"
5057 # i18n: column positioning for "hg summary"
5055 ui.write(_('remote: %s\n') % (', '.join(t)))
5058 ui.write(_('remote: %s\n') % (', '.join(t)))
5056 else:
5059 else:
5057 # i18n: column positioning for "hg summary"
5060 # i18n: column positioning for "hg summary"
5058 ui.status(_('remote: (synced)\n'))
5061 ui.status(_('remote: (synced)\n'))
5059
5062
5060 cmdutil.summaryremotehooks(ui, repo, opts,
5063 cmdutil.summaryremotehooks(ui, repo, opts,
5061 ((source, sbranch, sother, commoninc),
5064 ((source, sbranch, sother, commoninc),
5062 (dest, dbranch, dother, outgoing)))
5065 (dest, dbranch, dother, outgoing)))
5063
5066
5064 @command('tag',
5067 @command('tag',
5065 [('f', 'force', None, _('force tag')),
5068 [('f', 'force', None, _('force tag')),
5066 ('l', 'local', None, _('make the tag local')),
5069 ('l', 'local', None, _('make the tag local')),
5067 ('r', 'rev', '', _('revision to tag'), _('REV')),
5070 ('r', 'rev', '', _('revision to tag'), _('REV')),
5068 ('', 'remove', None, _('remove a tag')),
5071 ('', 'remove', None, _('remove a tag')),
5069 # -l/--local is already there, commitopts cannot be used
5072 # -l/--local is already there, commitopts cannot be used
5070 ('e', 'edit', None, _('invoke editor on commit messages')),
5073 ('e', 'edit', None, _('invoke editor on commit messages')),
5071 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5074 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5072 ] + commitopts2,
5075 ] + commitopts2,
5073 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5076 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5074 def tag(ui, repo, name1, *names, **opts):
5077 def tag(ui, repo, name1, *names, **opts):
5075 """add one or more tags for the current or given revision
5078 """add one or more tags for the current or given revision
5076
5079
5077 Name a particular revision using <name>.
5080 Name a particular revision using <name>.
5078
5081
5079 Tags are used to name particular revisions of the repository and are
5082 Tags are used to name particular revisions of the repository and are
5080 very useful to compare different revisions, to go back to significant
5083 very useful to compare different revisions, to go back to significant
5081 earlier versions or to mark branch points as releases, etc. Changing
5084 earlier versions or to mark branch points as releases, etc. Changing
5082 an existing tag is normally disallowed; use -f/--force to override.
5085 an existing tag is normally disallowed; use -f/--force to override.
5083
5086
5084 If no revision is given, the parent of the working directory is
5087 If no revision is given, the parent of the working directory is
5085 used.
5088 used.
5086
5089
5087 To facilitate version control, distribution, and merging of tags,
5090 To facilitate version control, distribution, and merging of tags,
5088 they are stored as a file named ".hgtags" which is managed similarly
5091 they are stored as a file named ".hgtags" which is managed similarly
5089 to other project files and can be hand-edited if necessary. This
5092 to other project files and can be hand-edited if necessary. This
5090 also means that tagging creates a new commit. The file
5093 also means that tagging creates a new commit. The file
5091 ".hg/localtags" is used for local tags (not shared among
5094 ".hg/localtags" is used for local tags (not shared among
5092 repositories).
5095 repositories).
5093
5096
5094 Tag commits are usually made at the head of a branch. If the parent
5097 Tag commits are usually made at the head of a branch. If the parent
5095 of the working directory is not a branch head, :hg:`tag` aborts; use
5098 of the working directory is not a branch head, :hg:`tag` aborts; use
5096 -f/--force to force the tag commit to be based on a non-head
5099 -f/--force to force the tag commit to be based on a non-head
5097 changeset.
5100 changeset.
5098
5101
5099 See :hg:`help dates` for a list of formats valid for -d/--date.
5102 See :hg:`help dates` for a list of formats valid for -d/--date.
5100
5103
5101 Since tag names have priority over branch names during revision
5104 Since tag names have priority over branch names during revision
5102 lookup, using an existing branch name as a tag name is discouraged.
5105 lookup, using an existing branch name as a tag name is discouraged.
5103
5106
5104 Returns 0 on success.
5107 Returns 0 on success.
5105 """
5108 """
5106 wlock = lock = None
5109 wlock = lock = None
5107 try:
5110 try:
5108 wlock = repo.wlock()
5111 wlock = repo.wlock()
5109 lock = repo.lock()
5112 lock = repo.lock()
5110 rev_ = "."
5113 rev_ = "."
5111 names = [t.strip() for t in (name1,) + names]
5114 names = [t.strip() for t in (name1,) + names]
5112 if len(names) != len(set(names)):
5115 if len(names) != len(set(names)):
5113 raise error.Abort(_('tag names must be unique'))
5116 raise error.Abort(_('tag names must be unique'))
5114 for n in names:
5117 for n in names:
5115 scmutil.checknewlabel(repo, n, 'tag')
5118 scmutil.checknewlabel(repo, n, 'tag')
5116 if not n:
5119 if not n:
5117 raise error.Abort(_('tag names cannot consist entirely of '
5120 raise error.Abort(_('tag names cannot consist entirely of '
5118 'whitespace'))
5121 'whitespace'))
5119 if opts.get('rev') and opts.get('remove'):
5122 if opts.get('rev') and opts.get('remove'):
5120 raise error.Abort(_("--rev and --remove are incompatible"))
5123 raise error.Abort(_("--rev and --remove are incompatible"))
5121 if opts.get('rev'):
5124 if opts.get('rev'):
5122 rev_ = opts['rev']
5125 rev_ = opts['rev']
5123 message = opts.get('message')
5126 message = opts.get('message')
5124 if opts.get('remove'):
5127 if opts.get('remove'):
5125 if opts.get('local'):
5128 if opts.get('local'):
5126 expectedtype = 'local'
5129 expectedtype = 'local'
5127 else:
5130 else:
5128 expectedtype = 'global'
5131 expectedtype = 'global'
5129
5132
5130 for n in names:
5133 for n in names:
5131 if not repo.tagtype(n):
5134 if not repo.tagtype(n):
5132 raise error.Abort(_("tag '%s' does not exist") % n)
5135 raise error.Abort(_("tag '%s' does not exist") % n)
5133 if repo.tagtype(n) != expectedtype:
5136 if repo.tagtype(n) != expectedtype:
5134 if expectedtype == 'global':
5137 if expectedtype == 'global':
5135 raise error.Abort(_("tag '%s' is not a global tag") % n)
5138 raise error.Abort(_("tag '%s' is not a global tag") % n)
5136 else:
5139 else:
5137 raise error.Abort(_("tag '%s' is not a local tag") % n)
5140 raise error.Abort(_("tag '%s' is not a local tag") % n)
5138 rev_ = 'null'
5141 rev_ = 'null'
5139 if not message:
5142 if not message:
5140 # we don't translate commit messages
5143 # we don't translate commit messages
5141 message = 'Removed tag %s' % ', '.join(names)
5144 message = 'Removed tag %s' % ', '.join(names)
5142 elif not opts.get('force'):
5145 elif not opts.get('force'):
5143 for n in names:
5146 for n in names:
5144 if n in repo.tags():
5147 if n in repo.tags():
5145 raise error.Abort(_("tag '%s' already exists "
5148 raise error.Abort(_("tag '%s' already exists "
5146 "(use -f to force)") % n)
5149 "(use -f to force)") % n)
5147 if not opts.get('local'):
5150 if not opts.get('local'):
5148 p1, p2 = repo.dirstate.parents()
5151 p1, p2 = repo.dirstate.parents()
5149 if p2 != nullid:
5152 if p2 != nullid:
5150 raise error.Abort(_('uncommitted merge'))
5153 raise error.Abort(_('uncommitted merge'))
5151 bheads = repo.branchheads()
5154 bheads = repo.branchheads()
5152 if not opts.get('force') and bheads and p1 not in bheads:
5155 if not opts.get('force') and bheads and p1 not in bheads:
5153 raise error.Abort(_('working directory is not at a branch head '
5156 raise error.Abort(_('working directory is not at a branch head '
5154 '(use -f to force)'))
5157 '(use -f to force)'))
5155 r = scmutil.revsingle(repo, rev_).node()
5158 r = scmutil.revsingle(repo, rev_).node()
5156
5159
5157 if not message:
5160 if not message:
5158 # we don't translate commit messages
5161 # we don't translate commit messages
5159 message = ('Added tag %s for changeset %s' %
5162 message = ('Added tag %s for changeset %s' %
5160 (', '.join(names), short(r)))
5163 (', '.join(names), short(r)))
5161
5164
5162 date = opts.get('date')
5165 date = opts.get('date')
5163 if date:
5166 if date:
5164 date = util.parsedate(date)
5167 date = util.parsedate(date)
5165
5168
5166 if opts.get('remove'):
5169 if opts.get('remove'):
5167 editform = 'tag.remove'
5170 editform = 'tag.remove'
5168 else:
5171 else:
5169 editform = 'tag.add'
5172 editform = 'tag.add'
5170 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5173 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5171
5174
5172 # don't allow tagging the null rev
5175 # don't allow tagging the null rev
5173 if (not opts.get('remove') and
5176 if (not opts.get('remove') and
5174 scmutil.revsingle(repo, rev_).rev() == nullrev):
5177 scmutil.revsingle(repo, rev_).rev() == nullrev):
5175 raise error.Abort(_("cannot tag null revision"))
5178 raise error.Abort(_("cannot tag null revision"))
5176
5179
5177 tagsmod.tag(repo, names, r, message, opts.get('local'),
5180 tagsmod.tag(repo, names, r, message, opts.get('local'),
5178 opts.get('user'), date, editor=editor)
5181 opts.get('user'), date, editor=editor)
5179 finally:
5182 finally:
5180 release(lock, wlock)
5183 release(lock, wlock)
5181
5184
5182 @command('tags', formatteropts, '')
5185 @command('tags', formatteropts, '')
5183 def tags(ui, repo, **opts):
5186 def tags(ui, repo, **opts):
5184 """list repository tags
5187 """list repository tags
5185
5188
5186 This lists both regular and local tags. When the -v/--verbose
5189 This lists both regular and local tags. When the -v/--verbose
5187 switch is used, a third column "local" is printed for local tags.
5190 switch is used, a third column "local" is printed for local tags.
5188 When the -q/--quiet switch is used, only the tag name is printed.
5191 When the -q/--quiet switch is used, only the tag name is printed.
5189
5192
5190 Returns 0 on success.
5193 Returns 0 on success.
5191 """
5194 """
5192
5195
5193 ui.pager('tags')
5196 ui.pager('tags')
5194 fm = ui.formatter('tags', opts)
5197 fm = ui.formatter('tags', opts)
5195 hexfunc = fm.hexfunc
5198 hexfunc = fm.hexfunc
5196 tagtype = ""
5199 tagtype = ""
5197
5200
5198 for t, n in reversed(repo.tagslist()):
5201 for t, n in reversed(repo.tagslist()):
5199 hn = hexfunc(n)
5202 hn = hexfunc(n)
5200 label = 'tags.normal'
5203 label = 'tags.normal'
5201 tagtype = ''
5204 tagtype = ''
5202 if repo.tagtype(t) == 'local':
5205 if repo.tagtype(t) == 'local':
5203 label = 'tags.local'
5206 label = 'tags.local'
5204 tagtype = 'local'
5207 tagtype = 'local'
5205
5208
5206 fm.startitem()
5209 fm.startitem()
5207 fm.write('tag', '%s', t, label=label)
5210 fm.write('tag', '%s', t, label=label)
5208 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5211 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5209 fm.condwrite(not ui.quiet, 'rev node', fmt,
5212 fm.condwrite(not ui.quiet, 'rev node', fmt,
5210 repo.changelog.rev(n), hn, label=label)
5213 repo.changelog.rev(n), hn, label=label)
5211 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5214 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5212 tagtype, label=label)
5215 tagtype, label=label)
5213 fm.plain('\n')
5216 fm.plain('\n')
5214 fm.end()
5217 fm.end()
5215
5218
5216 @command('tip',
5219 @command('tip',
5217 [('p', 'patch', None, _('show patch')),
5220 [('p', 'patch', None, _('show patch')),
5218 ('g', 'git', None, _('use git extended diff format')),
5221 ('g', 'git', None, _('use git extended diff format')),
5219 ] + templateopts,
5222 ] + templateopts,
5220 _('[-p] [-g]'))
5223 _('[-p] [-g]'))
5221 def tip(ui, repo, **opts):
5224 def tip(ui, repo, **opts):
5222 """show the tip revision (DEPRECATED)
5225 """show the tip revision (DEPRECATED)
5223
5226
5224 The tip revision (usually just called the tip) is the changeset
5227 The tip revision (usually just called the tip) is the changeset
5225 most recently added to the repository (and therefore the most
5228 most recently added to the repository (and therefore the most
5226 recently changed head).
5229 recently changed head).
5227
5230
5228 If you have just made a commit, that commit will be the tip. If
5231 If you have just made a commit, that commit will be the tip. If
5229 you have just pulled changes from another repository, the tip of
5232 you have just pulled changes from another repository, the tip of
5230 that repository becomes the current tip. The "tip" tag is special
5233 that repository becomes the current tip. The "tip" tag is special
5231 and cannot be renamed or assigned to a different changeset.
5234 and cannot be renamed or assigned to a different changeset.
5232
5235
5233 This command is deprecated, please use :hg:`heads` instead.
5236 This command is deprecated, please use :hg:`heads` instead.
5234
5237
5235 Returns 0 on success.
5238 Returns 0 on success.
5236 """
5239 """
5237 displayer = cmdutil.show_changeset(ui, repo, opts)
5240 displayer = cmdutil.show_changeset(ui, repo, opts)
5238 displayer.show(repo['tip'])
5241 displayer.show(repo['tip'])
5239 displayer.close()
5242 displayer.close()
5240
5243
5241 @command('unbundle',
5244 @command('unbundle',
5242 [('u', 'update', None,
5245 [('u', 'update', None,
5243 _('update to new branch head if changesets were unbundled'))],
5246 _('update to new branch head if changesets were unbundled'))],
5244 _('[-u] FILE...'))
5247 _('[-u] FILE...'))
5245 def unbundle(ui, repo, fname1, *fnames, **opts):
5248 def unbundle(ui, repo, fname1, *fnames, **opts):
5246 """apply one or more changegroup files
5249 """apply one or more changegroup files
5247
5250
5248 Apply one or more compressed changegroup files generated by the
5251 Apply one or more compressed changegroup files generated by the
5249 bundle command.
5252 bundle command.
5250
5253
5251 Returns 0 on success, 1 if an update has unresolved files.
5254 Returns 0 on success, 1 if an update has unresolved files.
5252 """
5255 """
5253 fnames = (fname1,) + fnames
5256 fnames = (fname1,) + fnames
5254
5257
5255 with repo.lock():
5258 with repo.lock():
5256 for fname in fnames:
5259 for fname in fnames:
5257 f = hg.openpath(ui, fname)
5260 f = hg.openpath(ui, fname)
5258 gen = exchange.readbundle(ui, f, fname)
5261 gen = exchange.readbundle(ui, f, fname)
5259 if isinstance(gen, bundle2.unbundle20):
5262 if isinstance(gen, bundle2.unbundle20):
5260 tr = repo.transaction('unbundle')
5263 tr = repo.transaction('unbundle')
5261 try:
5264 try:
5262 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5265 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5263 url='bundle:' + fname)
5266 url='bundle:' + fname)
5264 tr.close()
5267 tr.close()
5265 except error.BundleUnknownFeatureError as exc:
5268 except error.BundleUnknownFeatureError as exc:
5266 raise error.Abort(_('%s: unknown bundle feature, %s')
5269 raise error.Abort(_('%s: unknown bundle feature, %s')
5267 % (fname, exc),
5270 % (fname, exc),
5268 hint=_("see https://mercurial-scm.org/"
5271 hint=_("see https://mercurial-scm.org/"
5269 "wiki/BundleFeature for more "
5272 "wiki/BundleFeature for more "
5270 "information"))
5273 "information"))
5271 finally:
5274 finally:
5272 if tr:
5275 if tr:
5273 tr.release()
5276 tr.release()
5274 changes = [r.get('return', 0)
5277 changes = [r.get('return', 0)
5275 for r in op.records['changegroup']]
5278 for r in op.records['changegroup']]
5276 modheads = changegroup.combineresults(changes)
5279 modheads = changegroup.combineresults(changes)
5277 elif isinstance(gen, streamclone.streamcloneapplier):
5280 elif isinstance(gen, streamclone.streamcloneapplier):
5278 raise error.Abort(
5281 raise error.Abort(
5279 _('packed bundles cannot be applied with '
5282 _('packed bundles cannot be applied with '
5280 '"hg unbundle"'),
5283 '"hg unbundle"'),
5281 hint=_('use "hg debugapplystreamclonebundle"'))
5284 hint=_('use "hg debugapplystreamclonebundle"'))
5282 else:
5285 else:
5283 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5286 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5284
5287
5285 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5288 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5286
5289
5287 @command('^update|up|checkout|co',
5290 @command('^update|up|checkout|co',
5288 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5291 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5289 ('c', 'check', None, _('require clean working directory')),
5292 ('c', 'check', None, _('require clean working directory')),
5290 ('m', 'merge', None, _('merge uncommitted changes')),
5293 ('m', 'merge', None, _('merge uncommitted changes')),
5291 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5294 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5292 ('r', 'rev', '', _('revision'), _('REV'))
5295 ('r', 'rev', '', _('revision'), _('REV'))
5293 ] + mergetoolopts,
5296 ] + mergetoolopts,
5294 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5297 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5295 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5298 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5296 merge=None, tool=None):
5299 merge=None, tool=None):
5297 """update working directory (or switch revisions)
5300 """update working directory (or switch revisions)
5298
5301
5299 Update the repository's working directory to the specified
5302 Update the repository's working directory to the specified
5300 changeset. If no changeset is specified, update to the tip of the
5303 changeset. If no changeset is specified, update to the tip of the
5301 current named branch and move the active bookmark (see :hg:`help
5304 current named branch and move the active bookmark (see :hg:`help
5302 bookmarks`).
5305 bookmarks`).
5303
5306
5304 Update sets the working directory's parent revision to the specified
5307 Update sets the working directory's parent revision to the specified
5305 changeset (see :hg:`help parents`).
5308 changeset (see :hg:`help parents`).
5306
5309
5307 If the changeset is not a descendant or ancestor of the working
5310 If the changeset is not a descendant or ancestor of the working
5308 directory's parent and there are uncommitted changes, the update is
5311 directory's parent and there are uncommitted changes, the update is
5309 aborted. With the -c/--check option, the working directory is checked
5312 aborted. With the -c/--check option, the working directory is checked
5310 for uncommitted changes; if none are found, the working directory is
5313 for uncommitted changes; if none are found, the working directory is
5311 updated to the specified changeset.
5314 updated to the specified changeset.
5312
5315
5313 .. container:: verbose
5316 .. container:: verbose
5314
5317
5315 The -C/--clean, -c/--check, and -m/--merge options control what
5318 The -C/--clean, -c/--check, and -m/--merge options control what
5316 happens if the working directory contains uncommitted changes.
5319 happens if the working directory contains uncommitted changes.
5317 At most of one of them can be specified.
5320 At most of one of them can be specified.
5318
5321
5319 1. If no option is specified, and if
5322 1. If no option is specified, and if
5320 the requested changeset is an ancestor or descendant of
5323 the requested changeset is an ancestor or descendant of
5321 the working directory's parent, the uncommitted changes
5324 the working directory's parent, the uncommitted changes
5322 are merged into the requested changeset and the merged
5325 are merged into the requested changeset and the merged
5323 result is left uncommitted. If the requested changeset is
5326 result is left uncommitted. If the requested changeset is
5324 not an ancestor or descendant (that is, it is on another
5327 not an ancestor or descendant (that is, it is on another
5325 branch), the update is aborted and the uncommitted changes
5328 branch), the update is aborted and the uncommitted changes
5326 are preserved.
5329 are preserved.
5327
5330
5328 2. With the -m/--merge option, the update is allowed even if the
5331 2. With the -m/--merge option, the update is allowed even if the
5329 requested changeset is not an ancestor or descendant of
5332 requested changeset is not an ancestor or descendant of
5330 the working directory's parent.
5333 the working directory's parent.
5331
5334
5332 3. With the -c/--check option, the update is aborted and the
5335 3. With the -c/--check option, the update is aborted and the
5333 uncommitted changes are preserved.
5336 uncommitted changes are preserved.
5334
5337
5335 4. With the -C/--clean option, uncommitted changes are discarded and
5338 4. With the -C/--clean option, uncommitted changes are discarded and
5336 the working directory is updated to the requested changeset.
5339 the working directory is updated to the requested changeset.
5337
5340
5338 To cancel an uncommitted merge (and lose your changes), use
5341 To cancel an uncommitted merge (and lose your changes), use
5339 :hg:`update --clean .`.
5342 :hg:`update --clean .`.
5340
5343
5341 Use null as the changeset to remove the working directory (like
5344 Use null as the changeset to remove the working directory (like
5342 :hg:`clone -U`).
5345 :hg:`clone -U`).
5343
5346
5344 If you want to revert just one file to an older revision, use
5347 If you want to revert just one file to an older revision, use
5345 :hg:`revert [-r REV] NAME`.
5348 :hg:`revert [-r REV] NAME`.
5346
5349
5347 See :hg:`help dates` for a list of formats valid for -d/--date.
5350 See :hg:`help dates` for a list of formats valid for -d/--date.
5348
5351
5349 Returns 0 on success, 1 if there are unresolved files.
5352 Returns 0 on success, 1 if there are unresolved files.
5350 """
5353 """
5351 if rev and node:
5354 if rev and node:
5352 raise error.Abort(_("please specify just one revision"))
5355 raise error.Abort(_("please specify just one revision"))
5353
5356
5354 if ui.configbool('commands', 'update.requiredest'):
5357 if ui.configbool('commands', 'update.requiredest'):
5355 if not node and not rev and not date:
5358 if not node and not rev and not date:
5356 raise error.Abort(_('you must specify a destination'),
5359 raise error.Abort(_('you must specify a destination'),
5357 hint=_('for example: hg update ".::"'))
5360 hint=_('for example: hg update ".::"'))
5358
5361
5359 if rev is None or rev == '':
5362 if rev is None or rev == '':
5360 rev = node
5363 rev = node
5361
5364
5362 if date and rev is not None:
5365 if date and rev is not None:
5363 raise error.Abort(_("you can't specify a revision and a date"))
5366 raise error.Abort(_("you can't specify a revision and a date"))
5364
5367
5365 if len([x for x in (clean, check, merge) if x]) > 1:
5368 if len([x for x in (clean, check, merge) if x]) > 1:
5366 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5369 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5367 "or -m/merge"))
5370 "or -m/merge"))
5368
5371
5369 updatecheck = None
5372 updatecheck = None
5370 if check:
5373 if check:
5371 updatecheck = 'abort'
5374 updatecheck = 'abort'
5372 elif merge:
5375 elif merge:
5373 updatecheck = 'none'
5376 updatecheck = 'none'
5374
5377
5375 with repo.wlock():
5378 with repo.wlock():
5376 cmdutil.clearunfinished(repo)
5379 cmdutil.clearunfinished(repo)
5377
5380
5378 if date:
5381 if date:
5379 rev = cmdutil.finddate(ui, repo, date)
5382 rev = cmdutil.finddate(ui, repo, date)
5380
5383
5381 # if we defined a bookmark, we have to remember the original name
5384 # if we defined a bookmark, we have to remember the original name
5382 brev = rev
5385 brev = rev
5383 rev = scmutil.revsingle(repo, rev, rev).rev()
5386 rev = scmutil.revsingle(repo, rev, rev).rev()
5384
5387
5385 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5388 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5386
5389
5387 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5390 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5388 updatecheck=updatecheck)
5391 updatecheck=updatecheck)
5389
5392
5390 @command('verify', [])
5393 @command('verify', [])
5391 def verify(ui, repo):
5394 def verify(ui, repo):
5392 """verify the integrity of the repository
5395 """verify the integrity of the repository
5393
5396
5394 Verify the integrity of the current repository.
5397 Verify the integrity of the current repository.
5395
5398
5396 This will perform an extensive check of the repository's
5399 This will perform an extensive check of the repository's
5397 integrity, validating the hashes and checksums of each entry in
5400 integrity, validating the hashes and checksums of each entry in
5398 the changelog, manifest, and tracked files, as well as the
5401 the changelog, manifest, and tracked files, as well as the
5399 integrity of their crosslinks and indices.
5402 integrity of their crosslinks and indices.
5400
5403
5401 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5404 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5402 for more information about recovery from corruption of the
5405 for more information about recovery from corruption of the
5403 repository.
5406 repository.
5404
5407
5405 Returns 0 on success, 1 if errors are encountered.
5408 Returns 0 on success, 1 if errors are encountered.
5406 """
5409 """
5407 return hg.verify(repo)
5410 return hg.verify(repo)
5408
5411
5409 @command('version', [] + formatteropts, norepo=True)
5412 @command('version', [] + formatteropts, norepo=True)
5410 def version_(ui, **opts):
5413 def version_(ui, **opts):
5411 """output version and copyright information"""
5414 """output version and copyright information"""
5412 if ui.verbose:
5415 if ui.verbose:
5413 ui.pager('version')
5416 ui.pager('version')
5414 fm = ui.formatter("version", opts)
5417 fm = ui.formatter("version", opts)
5415 fm.startitem()
5418 fm.startitem()
5416 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5419 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5417 util.version())
5420 util.version())
5418 license = _(
5421 license = _(
5419 "(see https://mercurial-scm.org for more information)\n"
5422 "(see https://mercurial-scm.org for more information)\n"
5420 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5423 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5421 "This is free software; see the source for copying conditions. "
5424 "This is free software; see the source for copying conditions. "
5422 "There is NO\nwarranty; "
5425 "There is NO\nwarranty; "
5423 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5426 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5424 )
5427 )
5425 if not ui.quiet:
5428 if not ui.quiet:
5426 fm.plain(license)
5429 fm.plain(license)
5427
5430
5428 if ui.verbose:
5431 if ui.verbose:
5429 fm.plain(_("\nEnabled extensions:\n\n"))
5432 fm.plain(_("\nEnabled extensions:\n\n"))
5430 # format names and versions into columns
5433 # format names and versions into columns
5431 names = []
5434 names = []
5432 vers = []
5435 vers = []
5433 isinternals = []
5436 isinternals = []
5434 for name, module in extensions.extensions():
5437 for name, module in extensions.extensions():
5435 names.append(name)
5438 names.append(name)
5436 vers.append(extensions.moduleversion(module) or None)
5439 vers.append(extensions.moduleversion(module) or None)
5437 isinternals.append(extensions.ismoduleinternal(module))
5440 isinternals.append(extensions.ismoduleinternal(module))
5438 fn = fm.nested("extensions")
5441 fn = fm.nested("extensions")
5439 if names:
5442 if names:
5440 namefmt = " %%-%ds " % max(len(n) for n in names)
5443 namefmt = " %%-%ds " % max(len(n) for n in names)
5441 places = [_("external"), _("internal")]
5444 places = [_("external"), _("internal")]
5442 for n, v, p in zip(names, vers, isinternals):
5445 for n, v, p in zip(names, vers, isinternals):
5443 fn.startitem()
5446 fn.startitem()
5444 fn.condwrite(ui.verbose, "name", namefmt, n)
5447 fn.condwrite(ui.verbose, "name", namefmt, n)
5445 if ui.verbose:
5448 if ui.verbose:
5446 fn.plain("%s " % places[p])
5449 fn.plain("%s " % places[p])
5447 fn.data(bundled=p)
5450 fn.data(bundled=p)
5448 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5451 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5449 if ui.verbose:
5452 if ui.verbose:
5450 fn.plain("\n")
5453 fn.plain("\n")
5451 fn.end()
5454 fn.end()
5452 fm.end()
5455 fm.end()
5453
5456
5454 def loadcmdtable(ui, name, cmdtable):
5457 def loadcmdtable(ui, name, cmdtable):
5455 """Load command functions from specified cmdtable
5458 """Load command functions from specified cmdtable
5456 """
5459 """
5457 overrides = [cmd for cmd in cmdtable if cmd in table]
5460 overrides = [cmd for cmd in cmdtable if cmd in table]
5458 if overrides:
5461 if overrides:
5459 ui.warn(_("extension '%s' overrides commands: %s\n")
5462 ui.warn(_("extension '%s' overrides commands: %s\n")
5460 % (name, " ".join(overrides)))
5463 % (name, " ".join(overrides)))
5461 table.update(cmdtable)
5464 table.update(cmdtable)
@@ -1,62 +1,68
1 # rcutil.py - utilities about config paths, special config sections etc.
1 # rcutil.py - utilities about config paths, special config sections etc.
2 #
2 #
3 # Copyright Mercurial Contributors
3 # Copyright Mercurial Contributors
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 os
10 import os
11
11
12 from . import (
12 from . import (
13 encoding,
13 encoding,
14 osutil,
14 osutil,
15 pycompat,
15 pycompat,
16 util,
16 util,
17 )
17 )
18
18
19 if pycompat.osname == 'nt':
19 if pycompat.osname == 'nt':
20 from . import scmwindows as scmplatform
20 from . import scmwindows as scmplatform
21 else:
21 else:
22 from . import scmposix as scmplatform
22 from . import scmposix as scmplatform
23
23
24 systemrcpath = scmplatform.systemrcpath
24 systemrcpath = scmplatform.systemrcpath
25 userrcpath = scmplatform.userrcpath
25 userrcpath = scmplatform.userrcpath
26
26
27 def _expandrcpath(path):
27 def _expandrcpath(path):
28 '''path could be a file or a directory. return a list of file paths'''
28 '''path could be a file or a directory. return a list of file paths'''
29 p = util.expandpath(path)
29 p = util.expandpath(path)
30 if os.path.isdir(p):
30 if os.path.isdir(p):
31 join = os.path.join
31 join = os.path.join
32 return [join(p, f) for f, k in osutil.listdir(p) if f.endswith('.rc')]
32 return [join(p, f) for f, k in osutil.listdir(p) if f.endswith('.rc')]
33 return [p]
33 return [p]
34
34
35 def defaultrcpath():
35 def defaultrcpath():
36 '''return rc paths in default.d'''
36 '''return rc paths in default.d'''
37 path = []
37 path = []
38 defaultpath = os.path.join(util.datapath, 'default.d')
38 defaultpath = os.path.join(util.datapath, 'default.d')
39 if os.path.isdir(defaultpath):
39 if os.path.isdir(defaultpath):
40 path = _expandrcpath(defaultpath)
40 path = _expandrcpath(defaultpath)
41 return path
41 return path
42
42
43 _rccomponents = None
43 _rccomponents = None
44
44
45 def rccomponents():
45 def rccomponents():
46 '''return hgrc search path. if env var HGRCPATH is set, use it.
46 '''return an ordered [(type, obj)] about where to load configs.
47 for each item in path, if directory, use files ending in .rc,
47
48 else use item.
48 respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is
49 make HGRCPATH empty to only look in .hg/hgrc of current repo.
49 used. if $HGRCPATH is not set, the platform default will be used.
50 if no HGRCPATH, use default os-specific path.'''
50
51 if a directory is provided, *.rc files under it will be used.
52
53 type could be either 'path' or 'items', if type is 'path', obj is a string,
54 and is the config file path. if type is 'items', obj is a list of (section,
55 name, value, source) that should fill the config directly.
56 '''
51 global _rccomponents
57 global _rccomponents
52 if _rccomponents is None:
58 if _rccomponents is None:
53 if 'HGRCPATH' in encoding.environ:
59 if 'HGRCPATH' in encoding.environ:
54 _rccomponents = []
60 _rccomponents = []
55 for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
61 for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
56 if not p:
62 if not p:
57 continue
63 continue
58 _rccomponents.extend(_expandrcpath(p))
64 _rccomponents.extend(('path', p) for p in _expandrcpath(p))
59 else:
65 else:
60 paths = defaultrcpath() + systemrcpath() + userrcpath()
66 paths = defaultrcpath() + systemrcpath() + userrcpath()
61 _rccomponents = pycompat.maplist(os.path.normpath, paths)
67 _rccomponents = [('path', os.path.normpath(p)) for p in paths]
62 return _rccomponents
68 return _rccomponents
@@ -1,1634 +1,1637
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits 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 atexit
10 import atexit
11 import collections
11 import collections
12 import contextlib
12 import contextlib
13 import errno
13 import errno
14 import getpass
14 import getpass
15 import inspect
15 import inspect
16 import os
16 import os
17 import re
17 import re
18 import signal
18 import signal
19 import socket
19 import socket
20 import subprocess
20 import subprocess
21 import sys
21 import sys
22 import tempfile
22 import tempfile
23 import traceback
23 import traceback
24
24
25 from .i18n import _
25 from .i18n import _
26 from .node import hex
26 from .node import hex
27
27
28 from . import (
28 from . import (
29 color,
29 color,
30 config,
30 config,
31 encoding,
31 encoding,
32 error,
32 error,
33 formatter,
33 formatter,
34 progress,
34 progress,
35 pycompat,
35 pycompat,
36 rcutil,
36 rcutil,
37 scmutil,
37 scmutil,
38 util,
38 util,
39 )
39 )
40
40
41 urlreq = util.urlreq
41 urlreq = util.urlreq
42
42
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
45 if not c.isalnum())
45 if not c.isalnum())
46
46
47 samplehgrcs = {
47 samplehgrcs = {
48 'user':
48 'user':
49 """# example user config (see 'hg help config' for more info)
49 """# example user config (see 'hg help config' for more info)
50 [ui]
50 [ui]
51 # name and email, e.g.
51 # name and email, e.g.
52 # username = Jane Doe <jdoe@example.com>
52 # username = Jane Doe <jdoe@example.com>
53 username =
53 username =
54
54
55 # uncomment to colorize command output
55 # uncomment to colorize command output
56 # color = auto
56 # color = auto
57
57
58 [extensions]
58 [extensions]
59 # uncomment these lines to enable some popular extensions
59 # uncomment these lines to enable some popular extensions
60 # (see 'hg help extensions' for more info)
60 # (see 'hg help extensions' for more info)
61 #
61 #
62 # pager =""",
62 # pager =""",
63
63
64 'cloned':
64 'cloned':
65 """# example repository config (see 'hg help config' for more info)
65 """# example repository config (see 'hg help config' for more info)
66 [paths]
66 [paths]
67 default = %s
67 default = %s
68
68
69 # path aliases to other clones of this repo in URLs or filesystem paths
69 # path aliases to other clones of this repo in URLs or filesystem paths
70 # (see 'hg help config.paths' for more info)
70 # (see 'hg help config.paths' for more info)
71 #
71 #
72 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
72 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
73 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
73 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
74 # my-clone = /home/jdoe/jdoes-clone
74 # my-clone = /home/jdoe/jdoes-clone
75
75
76 [ui]
76 [ui]
77 # name and email (local to this repository, optional), e.g.
77 # name and email (local to this repository, optional), e.g.
78 # username = Jane Doe <jdoe@example.com>
78 # username = Jane Doe <jdoe@example.com>
79 """,
79 """,
80
80
81 'local':
81 'local':
82 """# example repository config (see 'hg help config' for more info)
82 """# example repository config (see 'hg help config' for more info)
83 [paths]
83 [paths]
84 # path aliases to other clones of this repo in URLs or filesystem paths
84 # path aliases to other clones of this repo in URLs or filesystem paths
85 # (see 'hg help config.paths' for more info)
85 # (see 'hg help config.paths' for more info)
86 #
86 #
87 # default = http://example.com/hg/example-repo
87 # default = http://example.com/hg/example-repo
88 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
88 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
89 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
89 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
90 # my-clone = /home/jdoe/jdoes-clone
90 # my-clone = /home/jdoe/jdoes-clone
91
91
92 [ui]
92 [ui]
93 # name and email (local to this repository, optional), e.g.
93 # name and email (local to this repository, optional), e.g.
94 # username = Jane Doe <jdoe@example.com>
94 # username = Jane Doe <jdoe@example.com>
95 """,
95 """,
96
96
97 'global':
97 'global':
98 """# example system-wide hg config (see 'hg help config' for more info)
98 """# example system-wide hg config (see 'hg help config' for more info)
99
99
100 [ui]
100 [ui]
101 # uncomment to colorize command output
101 # uncomment to colorize command output
102 # color = auto
102 # color = auto
103
103
104 [extensions]
104 [extensions]
105 # uncomment these lines to enable some popular extensions
105 # uncomment these lines to enable some popular extensions
106 # (see 'hg help extensions' for more info)
106 # (see 'hg help extensions' for more info)
107 #
107 #
108 # blackbox =
108 # blackbox =
109 # pager =""",
109 # pager =""",
110 }
110 }
111
111
112
112
113 class httppasswordmgrdbproxy(object):
113 class httppasswordmgrdbproxy(object):
114 """Delays loading urllib2 until it's needed."""
114 """Delays loading urllib2 until it's needed."""
115 def __init__(self):
115 def __init__(self):
116 self._mgr = None
116 self._mgr = None
117
117
118 def _get_mgr(self):
118 def _get_mgr(self):
119 if self._mgr is None:
119 if self._mgr is None:
120 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
120 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
121 return self._mgr
121 return self._mgr
122
122
123 def add_password(self, *args, **kwargs):
123 def add_password(self, *args, **kwargs):
124 return self._get_mgr().add_password(*args, **kwargs)
124 return self._get_mgr().add_password(*args, **kwargs)
125
125
126 def find_user_password(self, *args, **kwargs):
126 def find_user_password(self, *args, **kwargs):
127 return self._get_mgr().find_user_password(*args, **kwargs)
127 return self._get_mgr().find_user_password(*args, **kwargs)
128
128
129 def _catchterm(*args):
129 def _catchterm(*args):
130 raise error.SignalInterrupt
130 raise error.SignalInterrupt
131
131
132 class ui(object):
132 class ui(object):
133 def __init__(self, src=None):
133 def __init__(self, src=None):
134 """Create a fresh new ui object if no src given
134 """Create a fresh new ui object if no src given
135
135
136 Use uimod.ui.load() to create a ui which knows global and user configs.
136 Use uimod.ui.load() to create a ui which knows global and user configs.
137 In most cases, you should use ui.copy() to create a copy of an existing
137 In most cases, you should use ui.copy() to create a copy of an existing
138 ui object.
138 ui object.
139 """
139 """
140 # _buffers: used for temporary capture of output
140 # _buffers: used for temporary capture of output
141 self._buffers = []
141 self._buffers = []
142 # 3-tuple describing how each buffer in the stack behaves.
142 # 3-tuple describing how each buffer in the stack behaves.
143 # Values are (capture stderr, capture subprocesses, apply labels).
143 # Values are (capture stderr, capture subprocesses, apply labels).
144 self._bufferstates = []
144 self._bufferstates = []
145 # When a buffer is active, defines whether we are expanding labels.
145 # When a buffer is active, defines whether we are expanding labels.
146 # This exists to prevent an extra list lookup.
146 # This exists to prevent an extra list lookup.
147 self._bufferapplylabels = None
147 self._bufferapplylabels = None
148 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
148 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
149 self._reportuntrusted = True
149 self._reportuntrusted = True
150 self._ocfg = config.config() # overlay
150 self._ocfg = config.config() # overlay
151 self._tcfg = config.config() # trusted
151 self._tcfg = config.config() # trusted
152 self._ucfg = config.config() # untrusted
152 self._ucfg = config.config() # untrusted
153 self._trustusers = set()
153 self._trustusers = set()
154 self._trustgroups = set()
154 self._trustgroups = set()
155 self.callhooks = True
155 self.callhooks = True
156 # Insecure server connections requested.
156 # Insecure server connections requested.
157 self.insecureconnections = False
157 self.insecureconnections = False
158 # Blocked time
158 # Blocked time
159 self.logblockedtimes = False
159 self.logblockedtimes = False
160 # color mode: see mercurial/color.py for possible value
160 # color mode: see mercurial/color.py for possible value
161 self._colormode = None
161 self._colormode = None
162 self._terminfoparams = {}
162 self._terminfoparams = {}
163 self._styles = {}
163 self._styles = {}
164
164
165 if src:
165 if src:
166 self.fout = src.fout
166 self.fout = src.fout
167 self.ferr = src.ferr
167 self.ferr = src.ferr
168 self.fin = src.fin
168 self.fin = src.fin
169 self.pageractive = src.pageractive
169 self.pageractive = src.pageractive
170 self._disablepager = src._disablepager
170 self._disablepager = src._disablepager
171
171
172 self._tcfg = src._tcfg.copy()
172 self._tcfg = src._tcfg.copy()
173 self._ucfg = src._ucfg.copy()
173 self._ucfg = src._ucfg.copy()
174 self._ocfg = src._ocfg.copy()
174 self._ocfg = src._ocfg.copy()
175 self._trustusers = src._trustusers.copy()
175 self._trustusers = src._trustusers.copy()
176 self._trustgroups = src._trustgroups.copy()
176 self._trustgroups = src._trustgroups.copy()
177 self.environ = src.environ
177 self.environ = src.environ
178 self.callhooks = src.callhooks
178 self.callhooks = src.callhooks
179 self.insecureconnections = src.insecureconnections
179 self.insecureconnections = src.insecureconnections
180 self._colormode = src._colormode
180 self._colormode = src._colormode
181 self._terminfoparams = src._terminfoparams.copy()
181 self._terminfoparams = src._terminfoparams.copy()
182 self._styles = src._styles.copy()
182 self._styles = src._styles.copy()
183
183
184 self.fixconfig()
184 self.fixconfig()
185
185
186 self.httppasswordmgrdb = src.httppasswordmgrdb
186 self.httppasswordmgrdb = src.httppasswordmgrdb
187 self._blockedtimes = src._blockedtimes
187 self._blockedtimes = src._blockedtimes
188 else:
188 else:
189 self.fout = util.stdout
189 self.fout = util.stdout
190 self.ferr = util.stderr
190 self.ferr = util.stderr
191 self.fin = util.stdin
191 self.fin = util.stdin
192 self.pageractive = False
192 self.pageractive = False
193 self._disablepager = False
193 self._disablepager = False
194
194
195 # shared read-only environment
195 # shared read-only environment
196 self.environ = encoding.environ
196 self.environ = encoding.environ
197
197
198 self.httppasswordmgrdb = httppasswordmgrdbproxy()
198 self.httppasswordmgrdb = httppasswordmgrdbproxy()
199 self._blockedtimes = collections.defaultdict(int)
199 self._blockedtimes = collections.defaultdict(int)
200
200
201 allowed = self.configlist('experimental', 'exportableenviron')
201 allowed = self.configlist('experimental', 'exportableenviron')
202 if '*' in allowed:
202 if '*' in allowed:
203 self._exportableenviron = self.environ
203 self._exportableenviron = self.environ
204 else:
204 else:
205 self._exportableenviron = {}
205 self._exportableenviron = {}
206 for k in allowed:
206 for k in allowed:
207 if k in self.environ:
207 if k in self.environ:
208 self._exportableenviron[k] = self.environ[k]
208 self._exportableenviron[k] = self.environ[k]
209
209
210 @classmethod
210 @classmethod
211 def load(cls):
211 def load(cls):
212 """Create a ui and load global and user configs"""
212 """Create a ui and load global and user configs"""
213 u = cls()
213 u = cls()
214 # we always trust global config files
214 # we always trust global config files
215 for f in rcutil.rccomponents():
215 for t, f in rcutil.rccomponents():
216 if t == 'path':
216 u.readconfig(f, trust=True)
217 u.readconfig(f, trust=True)
218 else:
219 raise error.ProgrammingError('unknown rctype: %s' % t)
217 return u
220 return u
218
221
219 def copy(self):
222 def copy(self):
220 return self.__class__(self)
223 return self.__class__(self)
221
224
222 def resetstate(self):
225 def resetstate(self):
223 """Clear internal state that shouldn't persist across commands"""
226 """Clear internal state that shouldn't persist across commands"""
224 if self._progbar:
227 if self._progbar:
225 self._progbar.resetstate() # reset last-print time of progress bar
228 self._progbar.resetstate() # reset last-print time of progress bar
226 self.httppasswordmgrdb = httppasswordmgrdbproxy()
229 self.httppasswordmgrdb = httppasswordmgrdbproxy()
227
230
228 @contextlib.contextmanager
231 @contextlib.contextmanager
229 def timeblockedsection(self, key):
232 def timeblockedsection(self, key):
230 # this is open-coded below - search for timeblockedsection to find them
233 # this is open-coded below - search for timeblockedsection to find them
231 starttime = util.timer()
234 starttime = util.timer()
232 try:
235 try:
233 yield
236 yield
234 finally:
237 finally:
235 self._blockedtimes[key + '_blocked'] += \
238 self._blockedtimes[key + '_blocked'] += \
236 (util.timer() - starttime) * 1000
239 (util.timer() - starttime) * 1000
237
240
238 def formatter(self, topic, opts):
241 def formatter(self, topic, opts):
239 return formatter.formatter(self, topic, opts)
242 return formatter.formatter(self, topic, opts)
240
243
241 def _trusted(self, fp, f):
244 def _trusted(self, fp, f):
242 st = util.fstat(fp)
245 st = util.fstat(fp)
243 if util.isowner(st):
246 if util.isowner(st):
244 return True
247 return True
245
248
246 tusers, tgroups = self._trustusers, self._trustgroups
249 tusers, tgroups = self._trustusers, self._trustgroups
247 if '*' in tusers or '*' in tgroups:
250 if '*' in tusers or '*' in tgroups:
248 return True
251 return True
249
252
250 user = util.username(st.st_uid)
253 user = util.username(st.st_uid)
251 group = util.groupname(st.st_gid)
254 group = util.groupname(st.st_gid)
252 if user in tusers or group in tgroups or user == util.username():
255 if user in tusers or group in tgroups or user == util.username():
253 return True
256 return True
254
257
255 if self._reportuntrusted:
258 if self._reportuntrusted:
256 self.warn(_('not trusting file %s from untrusted '
259 self.warn(_('not trusting file %s from untrusted '
257 'user %s, group %s\n') % (f, user, group))
260 'user %s, group %s\n') % (f, user, group))
258 return False
261 return False
259
262
260 def readconfig(self, filename, root=None, trust=False,
263 def readconfig(self, filename, root=None, trust=False,
261 sections=None, remap=None):
264 sections=None, remap=None):
262 try:
265 try:
263 fp = open(filename, u'rb')
266 fp = open(filename, u'rb')
264 except IOError:
267 except IOError:
265 if not sections: # ignore unless we were looking for something
268 if not sections: # ignore unless we were looking for something
266 return
269 return
267 raise
270 raise
268
271
269 cfg = config.config()
272 cfg = config.config()
270 trusted = sections or trust or self._trusted(fp, filename)
273 trusted = sections or trust or self._trusted(fp, filename)
271
274
272 try:
275 try:
273 cfg.read(filename, fp, sections=sections, remap=remap)
276 cfg.read(filename, fp, sections=sections, remap=remap)
274 fp.close()
277 fp.close()
275 except error.ConfigError as inst:
278 except error.ConfigError as inst:
276 if trusted:
279 if trusted:
277 raise
280 raise
278 self.warn(_("ignored: %s\n") % str(inst))
281 self.warn(_("ignored: %s\n") % str(inst))
279
282
280 if self.plain():
283 if self.plain():
281 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
284 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
282 'logtemplate', 'statuscopies', 'style',
285 'logtemplate', 'statuscopies', 'style',
283 'traceback', 'verbose'):
286 'traceback', 'verbose'):
284 if k in cfg['ui']:
287 if k in cfg['ui']:
285 del cfg['ui'][k]
288 del cfg['ui'][k]
286 for k, v in cfg.items('defaults'):
289 for k, v in cfg.items('defaults'):
287 del cfg['defaults'][k]
290 del cfg['defaults'][k]
288 for k, v in cfg.items('commands'):
291 for k, v in cfg.items('commands'):
289 del cfg['commands'][k]
292 del cfg['commands'][k]
290 # Don't remove aliases from the configuration if in the exceptionlist
293 # Don't remove aliases from the configuration if in the exceptionlist
291 if self.plain('alias'):
294 if self.plain('alias'):
292 for k, v in cfg.items('alias'):
295 for k, v in cfg.items('alias'):
293 del cfg['alias'][k]
296 del cfg['alias'][k]
294 if self.plain('revsetalias'):
297 if self.plain('revsetalias'):
295 for k, v in cfg.items('revsetalias'):
298 for k, v in cfg.items('revsetalias'):
296 del cfg['revsetalias'][k]
299 del cfg['revsetalias'][k]
297 if self.plain('templatealias'):
300 if self.plain('templatealias'):
298 for k, v in cfg.items('templatealias'):
301 for k, v in cfg.items('templatealias'):
299 del cfg['templatealias'][k]
302 del cfg['templatealias'][k]
300
303
301 if trusted:
304 if trusted:
302 self._tcfg.update(cfg)
305 self._tcfg.update(cfg)
303 self._tcfg.update(self._ocfg)
306 self._tcfg.update(self._ocfg)
304 self._ucfg.update(cfg)
307 self._ucfg.update(cfg)
305 self._ucfg.update(self._ocfg)
308 self._ucfg.update(self._ocfg)
306
309
307 if root is None:
310 if root is None:
308 root = os.path.expanduser('~')
311 root = os.path.expanduser('~')
309 self.fixconfig(root=root)
312 self.fixconfig(root=root)
310
313
311 def fixconfig(self, root=None, section=None):
314 def fixconfig(self, root=None, section=None):
312 if section in (None, 'paths'):
315 if section in (None, 'paths'):
313 # expand vars and ~
316 # expand vars and ~
314 # translate paths relative to root (or home) into absolute paths
317 # translate paths relative to root (or home) into absolute paths
315 root = root or pycompat.getcwd()
318 root = root or pycompat.getcwd()
316 for c in self._tcfg, self._ucfg, self._ocfg:
319 for c in self._tcfg, self._ucfg, self._ocfg:
317 for n, p in c.items('paths'):
320 for n, p in c.items('paths'):
318 # Ignore sub-options.
321 # Ignore sub-options.
319 if ':' in n:
322 if ':' in n:
320 continue
323 continue
321 if not p:
324 if not p:
322 continue
325 continue
323 if '%%' in p:
326 if '%%' in p:
324 s = self.configsource('paths', n) or 'none'
327 s = self.configsource('paths', n) or 'none'
325 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
328 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
326 % (n, p, s))
329 % (n, p, s))
327 p = p.replace('%%', '%')
330 p = p.replace('%%', '%')
328 p = util.expandpath(p)
331 p = util.expandpath(p)
329 if not util.hasscheme(p) and not os.path.isabs(p):
332 if not util.hasscheme(p) and not os.path.isabs(p):
330 p = os.path.normpath(os.path.join(root, p))
333 p = os.path.normpath(os.path.join(root, p))
331 c.set("paths", n, p)
334 c.set("paths", n, p)
332
335
333 if section in (None, 'ui'):
336 if section in (None, 'ui'):
334 # update ui options
337 # update ui options
335 self.debugflag = self.configbool('ui', 'debug')
338 self.debugflag = self.configbool('ui', 'debug')
336 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
339 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
337 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
340 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
338 if self.verbose and self.quiet:
341 if self.verbose and self.quiet:
339 self.quiet = self.verbose = False
342 self.quiet = self.verbose = False
340 self._reportuntrusted = self.debugflag or self.configbool("ui",
343 self._reportuntrusted = self.debugflag or self.configbool("ui",
341 "report_untrusted", True)
344 "report_untrusted", True)
342 self.tracebackflag = self.configbool('ui', 'traceback', False)
345 self.tracebackflag = self.configbool('ui', 'traceback', False)
343 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
346 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
344
347
345 if section in (None, 'trusted'):
348 if section in (None, 'trusted'):
346 # update trust information
349 # update trust information
347 self._trustusers.update(self.configlist('trusted', 'users'))
350 self._trustusers.update(self.configlist('trusted', 'users'))
348 self._trustgroups.update(self.configlist('trusted', 'groups'))
351 self._trustgroups.update(self.configlist('trusted', 'groups'))
349
352
350 def backupconfig(self, section, item):
353 def backupconfig(self, section, item):
351 return (self._ocfg.backup(section, item),
354 return (self._ocfg.backup(section, item),
352 self._tcfg.backup(section, item),
355 self._tcfg.backup(section, item),
353 self._ucfg.backup(section, item),)
356 self._ucfg.backup(section, item),)
354 def restoreconfig(self, data):
357 def restoreconfig(self, data):
355 self._ocfg.restore(data[0])
358 self._ocfg.restore(data[0])
356 self._tcfg.restore(data[1])
359 self._tcfg.restore(data[1])
357 self._ucfg.restore(data[2])
360 self._ucfg.restore(data[2])
358
361
359 def setconfig(self, section, name, value, source=''):
362 def setconfig(self, section, name, value, source=''):
360 for cfg in (self._ocfg, self._tcfg, self._ucfg):
363 for cfg in (self._ocfg, self._tcfg, self._ucfg):
361 cfg.set(section, name, value, source)
364 cfg.set(section, name, value, source)
362 self.fixconfig(section=section)
365 self.fixconfig(section=section)
363
366
364 def _data(self, untrusted):
367 def _data(self, untrusted):
365 return untrusted and self._ucfg or self._tcfg
368 return untrusted and self._ucfg or self._tcfg
366
369
367 def configsource(self, section, name, untrusted=False):
370 def configsource(self, section, name, untrusted=False):
368 return self._data(untrusted).source(section, name)
371 return self._data(untrusted).source(section, name)
369
372
370 def config(self, section, name, default=None, untrusted=False):
373 def config(self, section, name, default=None, untrusted=False):
371 if isinstance(name, list):
374 if isinstance(name, list):
372 alternates = name
375 alternates = name
373 else:
376 else:
374 alternates = [name]
377 alternates = [name]
375
378
376 for n in alternates:
379 for n in alternates:
377 value = self._data(untrusted).get(section, n, None)
380 value = self._data(untrusted).get(section, n, None)
378 if value is not None:
381 if value is not None:
379 name = n
382 name = n
380 break
383 break
381 else:
384 else:
382 value = default
385 value = default
383
386
384 if self.debugflag and not untrusted and self._reportuntrusted:
387 if self.debugflag and not untrusted and self._reportuntrusted:
385 for n in alternates:
388 for n in alternates:
386 uvalue = self._ucfg.get(section, n)
389 uvalue = self._ucfg.get(section, n)
387 if uvalue is not None and uvalue != value:
390 if uvalue is not None and uvalue != value:
388 self.debug("ignoring untrusted configuration option "
391 self.debug("ignoring untrusted configuration option "
389 "%s.%s = %s\n" % (section, n, uvalue))
392 "%s.%s = %s\n" % (section, n, uvalue))
390 return value
393 return value
391
394
392 def configsuboptions(self, section, name, default=None, untrusted=False):
395 def configsuboptions(self, section, name, default=None, untrusted=False):
393 """Get a config option and all sub-options.
396 """Get a config option and all sub-options.
394
397
395 Some config options have sub-options that are declared with the
398 Some config options have sub-options that are declared with the
396 format "key:opt = value". This method is used to return the main
399 format "key:opt = value". This method is used to return the main
397 option and all its declared sub-options.
400 option and all its declared sub-options.
398
401
399 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
402 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
400 is a dict of defined sub-options where keys and values are strings.
403 is a dict of defined sub-options where keys and values are strings.
401 """
404 """
402 data = self._data(untrusted)
405 data = self._data(untrusted)
403 main = data.get(section, name, default)
406 main = data.get(section, name, default)
404 if self.debugflag and not untrusted and self._reportuntrusted:
407 if self.debugflag and not untrusted and self._reportuntrusted:
405 uvalue = self._ucfg.get(section, name)
408 uvalue = self._ucfg.get(section, name)
406 if uvalue is not None and uvalue != main:
409 if uvalue is not None and uvalue != main:
407 self.debug('ignoring untrusted configuration option '
410 self.debug('ignoring untrusted configuration option '
408 '%s.%s = %s\n' % (section, name, uvalue))
411 '%s.%s = %s\n' % (section, name, uvalue))
409
412
410 sub = {}
413 sub = {}
411 prefix = '%s:' % name
414 prefix = '%s:' % name
412 for k, v in data.items(section):
415 for k, v in data.items(section):
413 if k.startswith(prefix):
416 if k.startswith(prefix):
414 sub[k[len(prefix):]] = v
417 sub[k[len(prefix):]] = v
415
418
416 if self.debugflag and not untrusted and self._reportuntrusted:
419 if self.debugflag and not untrusted and self._reportuntrusted:
417 for k, v in sub.items():
420 for k, v in sub.items():
418 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
421 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
419 if uvalue is not None and uvalue != v:
422 if uvalue is not None and uvalue != v:
420 self.debug('ignoring untrusted configuration option '
423 self.debug('ignoring untrusted configuration option '
421 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
424 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
422
425
423 return main, sub
426 return main, sub
424
427
425 def configpath(self, section, name, default=None, untrusted=False):
428 def configpath(self, section, name, default=None, untrusted=False):
426 'get a path config item, expanded relative to repo root or config file'
429 'get a path config item, expanded relative to repo root or config file'
427 v = self.config(section, name, default, untrusted)
430 v = self.config(section, name, default, untrusted)
428 if v is None:
431 if v is None:
429 return None
432 return None
430 if not os.path.isabs(v) or "://" not in v:
433 if not os.path.isabs(v) or "://" not in v:
431 src = self.configsource(section, name, untrusted)
434 src = self.configsource(section, name, untrusted)
432 if ':' in src:
435 if ':' in src:
433 base = os.path.dirname(src.rsplit(':')[0])
436 base = os.path.dirname(src.rsplit(':')[0])
434 v = os.path.join(base, os.path.expanduser(v))
437 v = os.path.join(base, os.path.expanduser(v))
435 return v
438 return v
436
439
437 def configbool(self, section, name, default=False, untrusted=False):
440 def configbool(self, section, name, default=False, untrusted=False):
438 """parse a configuration element as a boolean
441 """parse a configuration element as a boolean
439
442
440 >>> u = ui(); s = 'foo'
443 >>> u = ui(); s = 'foo'
441 >>> u.setconfig(s, 'true', 'yes')
444 >>> u.setconfig(s, 'true', 'yes')
442 >>> u.configbool(s, 'true')
445 >>> u.configbool(s, 'true')
443 True
446 True
444 >>> u.setconfig(s, 'false', 'no')
447 >>> u.setconfig(s, 'false', 'no')
445 >>> u.configbool(s, 'false')
448 >>> u.configbool(s, 'false')
446 False
449 False
447 >>> u.configbool(s, 'unknown')
450 >>> u.configbool(s, 'unknown')
448 False
451 False
449 >>> u.configbool(s, 'unknown', True)
452 >>> u.configbool(s, 'unknown', True)
450 True
453 True
451 >>> u.setconfig(s, 'invalid', 'somevalue')
454 >>> u.setconfig(s, 'invalid', 'somevalue')
452 >>> u.configbool(s, 'invalid')
455 >>> u.configbool(s, 'invalid')
453 Traceback (most recent call last):
456 Traceback (most recent call last):
454 ...
457 ...
455 ConfigError: foo.invalid is not a boolean ('somevalue')
458 ConfigError: foo.invalid is not a boolean ('somevalue')
456 """
459 """
457
460
458 v = self.config(section, name, None, untrusted)
461 v = self.config(section, name, None, untrusted)
459 if v is None:
462 if v is None:
460 return default
463 return default
461 if isinstance(v, bool):
464 if isinstance(v, bool):
462 return v
465 return v
463 b = util.parsebool(v)
466 b = util.parsebool(v)
464 if b is None:
467 if b is None:
465 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
468 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
466 % (section, name, v))
469 % (section, name, v))
467 return b
470 return b
468
471
469 def configwith(self, convert, section, name, default=None,
472 def configwith(self, convert, section, name, default=None,
470 desc=None, untrusted=False):
473 desc=None, untrusted=False):
471 """parse a configuration element with a conversion function
474 """parse a configuration element with a conversion function
472
475
473 >>> u = ui(); s = 'foo'
476 >>> u = ui(); s = 'foo'
474 >>> u.setconfig(s, 'float1', '42')
477 >>> u.setconfig(s, 'float1', '42')
475 >>> u.configwith(float, s, 'float1')
478 >>> u.configwith(float, s, 'float1')
476 42.0
479 42.0
477 >>> u.setconfig(s, 'float2', '-4.25')
480 >>> u.setconfig(s, 'float2', '-4.25')
478 >>> u.configwith(float, s, 'float2')
481 >>> u.configwith(float, s, 'float2')
479 -4.25
482 -4.25
480 >>> u.configwith(float, s, 'unknown', 7)
483 >>> u.configwith(float, s, 'unknown', 7)
481 7
484 7
482 >>> u.setconfig(s, 'invalid', 'somevalue')
485 >>> u.setconfig(s, 'invalid', 'somevalue')
483 >>> u.configwith(float, s, 'invalid')
486 >>> u.configwith(float, s, 'invalid')
484 Traceback (most recent call last):
487 Traceback (most recent call last):
485 ...
488 ...
486 ConfigError: foo.invalid is not a valid float ('somevalue')
489 ConfigError: foo.invalid is not a valid float ('somevalue')
487 >>> u.configwith(float, s, 'invalid', desc='womble')
490 >>> u.configwith(float, s, 'invalid', desc='womble')
488 Traceback (most recent call last):
491 Traceback (most recent call last):
489 ...
492 ...
490 ConfigError: foo.invalid is not a valid womble ('somevalue')
493 ConfigError: foo.invalid is not a valid womble ('somevalue')
491 """
494 """
492
495
493 v = self.config(section, name, None, untrusted)
496 v = self.config(section, name, None, untrusted)
494 if v is None:
497 if v is None:
495 return default
498 return default
496 try:
499 try:
497 return convert(v)
500 return convert(v)
498 except ValueError:
501 except ValueError:
499 if desc is None:
502 if desc is None:
500 desc = convert.__name__
503 desc = convert.__name__
501 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
504 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
502 % (section, name, desc, v))
505 % (section, name, desc, v))
503
506
504 def configint(self, section, name, default=None, untrusted=False):
507 def configint(self, section, name, default=None, untrusted=False):
505 """parse a configuration element as an integer
508 """parse a configuration element as an integer
506
509
507 >>> u = ui(); s = 'foo'
510 >>> u = ui(); s = 'foo'
508 >>> u.setconfig(s, 'int1', '42')
511 >>> u.setconfig(s, 'int1', '42')
509 >>> u.configint(s, 'int1')
512 >>> u.configint(s, 'int1')
510 42
513 42
511 >>> u.setconfig(s, 'int2', '-42')
514 >>> u.setconfig(s, 'int2', '-42')
512 >>> u.configint(s, 'int2')
515 >>> u.configint(s, 'int2')
513 -42
516 -42
514 >>> u.configint(s, 'unknown', 7)
517 >>> u.configint(s, 'unknown', 7)
515 7
518 7
516 >>> u.setconfig(s, 'invalid', 'somevalue')
519 >>> u.setconfig(s, 'invalid', 'somevalue')
517 >>> u.configint(s, 'invalid')
520 >>> u.configint(s, 'invalid')
518 Traceback (most recent call last):
521 Traceback (most recent call last):
519 ...
522 ...
520 ConfigError: foo.invalid is not a valid integer ('somevalue')
523 ConfigError: foo.invalid is not a valid integer ('somevalue')
521 """
524 """
522
525
523 return self.configwith(int, section, name, default, 'integer',
526 return self.configwith(int, section, name, default, 'integer',
524 untrusted)
527 untrusted)
525
528
526 def configbytes(self, section, name, default=0, untrusted=False):
529 def configbytes(self, section, name, default=0, untrusted=False):
527 """parse a configuration element as a quantity in bytes
530 """parse a configuration element as a quantity in bytes
528
531
529 Units can be specified as b (bytes), k or kb (kilobytes), m or
532 Units can be specified as b (bytes), k or kb (kilobytes), m or
530 mb (megabytes), g or gb (gigabytes).
533 mb (megabytes), g or gb (gigabytes).
531
534
532 >>> u = ui(); s = 'foo'
535 >>> u = ui(); s = 'foo'
533 >>> u.setconfig(s, 'val1', '42')
536 >>> u.setconfig(s, 'val1', '42')
534 >>> u.configbytes(s, 'val1')
537 >>> u.configbytes(s, 'val1')
535 42
538 42
536 >>> u.setconfig(s, 'val2', '42.5 kb')
539 >>> u.setconfig(s, 'val2', '42.5 kb')
537 >>> u.configbytes(s, 'val2')
540 >>> u.configbytes(s, 'val2')
538 43520
541 43520
539 >>> u.configbytes(s, 'unknown', '7 MB')
542 >>> u.configbytes(s, 'unknown', '7 MB')
540 7340032
543 7340032
541 >>> u.setconfig(s, 'invalid', 'somevalue')
544 >>> u.setconfig(s, 'invalid', 'somevalue')
542 >>> u.configbytes(s, 'invalid')
545 >>> u.configbytes(s, 'invalid')
543 Traceback (most recent call last):
546 Traceback (most recent call last):
544 ...
547 ...
545 ConfigError: foo.invalid is not a byte quantity ('somevalue')
548 ConfigError: foo.invalid is not a byte quantity ('somevalue')
546 """
549 """
547
550
548 value = self.config(section, name, None, untrusted)
551 value = self.config(section, name, None, untrusted)
549 if value is None:
552 if value is None:
550 if not isinstance(default, str):
553 if not isinstance(default, str):
551 return default
554 return default
552 value = default
555 value = default
553 try:
556 try:
554 return util.sizetoint(value)
557 return util.sizetoint(value)
555 except error.ParseError:
558 except error.ParseError:
556 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
559 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
557 % (section, name, value))
560 % (section, name, value))
558
561
559 def configlist(self, section, name, default=None, untrusted=False):
562 def configlist(self, section, name, default=None, untrusted=False):
560 """parse a configuration element as a list of comma/space separated
563 """parse a configuration element as a list of comma/space separated
561 strings
564 strings
562
565
563 >>> u = ui(); s = 'foo'
566 >>> u = ui(); s = 'foo'
564 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
567 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
565 >>> u.configlist(s, 'list1')
568 >>> u.configlist(s, 'list1')
566 ['this', 'is', 'a small', 'test']
569 ['this', 'is', 'a small', 'test']
567 """
570 """
568 # default is not always a list
571 # default is not always a list
569 if isinstance(default, bytes):
572 if isinstance(default, bytes):
570 default = config.parselist(default)
573 default = config.parselist(default)
571 return self.configwith(config.parselist, section, name, default or [],
574 return self.configwith(config.parselist, section, name, default or [],
572 'list', untrusted)
575 'list', untrusted)
573
576
574 def hasconfig(self, section, name, untrusted=False):
577 def hasconfig(self, section, name, untrusted=False):
575 return self._data(untrusted).hasitem(section, name)
578 return self._data(untrusted).hasitem(section, name)
576
579
577 def has_section(self, section, untrusted=False):
580 def has_section(self, section, untrusted=False):
578 '''tell whether section exists in config.'''
581 '''tell whether section exists in config.'''
579 return section in self._data(untrusted)
582 return section in self._data(untrusted)
580
583
581 def configitems(self, section, untrusted=False, ignoresub=False):
584 def configitems(self, section, untrusted=False, ignoresub=False):
582 items = self._data(untrusted).items(section)
585 items = self._data(untrusted).items(section)
583 if ignoresub:
586 if ignoresub:
584 newitems = {}
587 newitems = {}
585 for k, v in items:
588 for k, v in items:
586 if ':' not in k:
589 if ':' not in k:
587 newitems[k] = v
590 newitems[k] = v
588 items = newitems.items()
591 items = newitems.items()
589 if self.debugflag and not untrusted and self._reportuntrusted:
592 if self.debugflag and not untrusted and self._reportuntrusted:
590 for k, v in self._ucfg.items(section):
593 for k, v in self._ucfg.items(section):
591 if self._tcfg.get(section, k) != v:
594 if self._tcfg.get(section, k) != v:
592 self.debug("ignoring untrusted configuration option "
595 self.debug("ignoring untrusted configuration option "
593 "%s.%s = %s\n" % (section, k, v))
596 "%s.%s = %s\n" % (section, k, v))
594 return items
597 return items
595
598
596 def walkconfig(self, untrusted=False):
599 def walkconfig(self, untrusted=False):
597 cfg = self._data(untrusted)
600 cfg = self._data(untrusted)
598 for section in cfg.sections():
601 for section in cfg.sections():
599 for name, value in self.configitems(section, untrusted):
602 for name, value in self.configitems(section, untrusted):
600 yield section, name, value
603 yield section, name, value
601
604
602 def plain(self, feature=None):
605 def plain(self, feature=None):
603 '''is plain mode active?
606 '''is plain mode active?
604
607
605 Plain mode means that all configuration variables which affect
608 Plain mode means that all configuration variables which affect
606 the behavior and output of Mercurial should be
609 the behavior and output of Mercurial should be
607 ignored. Additionally, the output should be stable,
610 ignored. Additionally, the output should be stable,
608 reproducible and suitable for use in scripts or applications.
611 reproducible and suitable for use in scripts or applications.
609
612
610 The only way to trigger plain mode is by setting either the
613 The only way to trigger plain mode is by setting either the
611 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
614 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
612
615
613 The return value can either be
616 The return value can either be
614 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
617 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
615 - True otherwise
618 - True otherwise
616 '''
619 '''
617 if ('HGPLAIN' not in encoding.environ and
620 if ('HGPLAIN' not in encoding.environ and
618 'HGPLAINEXCEPT' not in encoding.environ):
621 'HGPLAINEXCEPT' not in encoding.environ):
619 return False
622 return False
620 exceptions = encoding.environ.get('HGPLAINEXCEPT',
623 exceptions = encoding.environ.get('HGPLAINEXCEPT',
621 '').strip().split(',')
624 '').strip().split(',')
622 if feature and exceptions:
625 if feature and exceptions:
623 return feature not in exceptions
626 return feature not in exceptions
624 return True
627 return True
625
628
626 def username(self):
629 def username(self):
627 """Return default username to be used in commits.
630 """Return default username to be used in commits.
628
631
629 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
632 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
630 and stop searching if one of these is set.
633 and stop searching if one of these is set.
631 If not found and ui.askusername is True, ask the user, else use
634 If not found and ui.askusername is True, ask the user, else use
632 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
635 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
633 """
636 """
634 user = encoding.environ.get("HGUSER")
637 user = encoding.environ.get("HGUSER")
635 if user is None:
638 if user is None:
636 user = self.config("ui", ["username", "user"])
639 user = self.config("ui", ["username", "user"])
637 if user is not None:
640 if user is not None:
638 user = os.path.expandvars(user)
641 user = os.path.expandvars(user)
639 if user is None:
642 if user is None:
640 user = encoding.environ.get("EMAIL")
643 user = encoding.environ.get("EMAIL")
641 if user is None and self.configbool("ui", "askusername"):
644 if user is None and self.configbool("ui", "askusername"):
642 user = self.prompt(_("enter a commit username:"), default=None)
645 user = self.prompt(_("enter a commit username:"), default=None)
643 if user is None and not self.interactive():
646 if user is None and not self.interactive():
644 try:
647 try:
645 user = '%s@%s' % (util.getuser(), socket.getfqdn())
648 user = '%s@%s' % (util.getuser(), socket.getfqdn())
646 self.warn(_("no username found, using '%s' instead\n") % user)
649 self.warn(_("no username found, using '%s' instead\n") % user)
647 except KeyError:
650 except KeyError:
648 pass
651 pass
649 if not user:
652 if not user:
650 raise error.Abort(_('no username supplied'),
653 raise error.Abort(_('no username supplied'),
651 hint=_("use 'hg config --edit' "
654 hint=_("use 'hg config --edit' "
652 'to set your username'))
655 'to set your username'))
653 if "\n" in user:
656 if "\n" in user:
654 raise error.Abort(_("username %s contains a newline\n")
657 raise error.Abort(_("username %s contains a newline\n")
655 % repr(user))
658 % repr(user))
656 return user
659 return user
657
660
658 def shortuser(self, user):
661 def shortuser(self, user):
659 """Return a short representation of a user name or email address."""
662 """Return a short representation of a user name or email address."""
660 if not self.verbose:
663 if not self.verbose:
661 user = util.shortuser(user)
664 user = util.shortuser(user)
662 return user
665 return user
663
666
664 def expandpath(self, loc, default=None):
667 def expandpath(self, loc, default=None):
665 """Return repository location relative to cwd or from [paths]"""
668 """Return repository location relative to cwd or from [paths]"""
666 try:
669 try:
667 p = self.paths.getpath(loc)
670 p = self.paths.getpath(loc)
668 if p:
671 if p:
669 return p.rawloc
672 return p.rawloc
670 except error.RepoError:
673 except error.RepoError:
671 pass
674 pass
672
675
673 if default:
676 if default:
674 try:
677 try:
675 p = self.paths.getpath(default)
678 p = self.paths.getpath(default)
676 if p:
679 if p:
677 return p.rawloc
680 return p.rawloc
678 except error.RepoError:
681 except error.RepoError:
679 pass
682 pass
680
683
681 return loc
684 return loc
682
685
683 @util.propertycache
686 @util.propertycache
684 def paths(self):
687 def paths(self):
685 return paths(self)
688 return paths(self)
686
689
687 def pushbuffer(self, error=False, subproc=False, labeled=False):
690 def pushbuffer(self, error=False, subproc=False, labeled=False):
688 """install a buffer to capture standard output of the ui object
691 """install a buffer to capture standard output of the ui object
689
692
690 If error is True, the error output will be captured too.
693 If error is True, the error output will be captured too.
691
694
692 If subproc is True, output from subprocesses (typically hooks) will be
695 If subproc is True, output from subprocesses (typically hooks) will be
693 captured too.
696 captured too.
694
697
695 If labeled is True, any labels associated with buffered
698 If labeled is True, any labels associated with buffered
696 output will be handled. By default, this has no effect
699 output will be handled. By default, this has no effect
697 on the output returned, but extensions and GUI tools may
700 on the output returned, but extensions and GUI tools may
698 handle this argument and returned styled output. If output
701 handle this argument and returned styled output. If output
699 is being buffered so it can be captured and parsed or
702 is being buffered so it can be captured and parsed or
700 processed, labeled should not be set to True.
703 processed, labeled should not be set to True.
701 """
704 """
702 self._buffers.append([])
705 self._buffers.append([])
703 self._bufferstates.append((error, subproc, labeled))
706 self._bufferstates.append((error, subproc, labeled))
704 self._bufferapplylabels = labeled
707 self._bufferapplylabels = labeled
705
708
706 def popbuffer(self):
709 def popbuffer(self):
707 '''pop the last buffer and return the buffered output'''
710 '''pop the last buffer and return the buffered output'''
708 self._bufferstates.pop()
711 self._bufferstates.pop()
709 if self._bufferstates:
712 if self._bufferstates:
710 self._bufferapplylabels = self._bufferstates[-1][2]
713 self._bufferapplylabels = self._bufferstates[-1][2]
711 else:
714 else:
712 self._bufferapplylabels = None
715 self._bufferapplylabels = None
713
716
714 return "".join(self._buffers.pop())
717 return "".join(self._buffers.pop())
715
718
716 def write(self, *args, **opts):
719 def write(self, *args, **opts):
717 '''write args to output
720 '''write args to output
718
721
719 By default, this method simply writes to the buffer or stdout.
722 By default, this method simply writes to the buffer or stdout.
720 Color mode can be set on the UI class to have the output decorated
723 Color mode can be set on the UI class to have the output decorated
721 with color modifier before being written to stdout.
724 with color modifier before being written to stdout.
722
725
723 The color used is controlled by an optional keyword argument, "label".
726 The color used is controlled by an optional keyword argument, "label".
724 This should be a string containing label names separated by space.
727 This should be a string containing label names separated by space.
725 Label names take the form of "topic.type". For example, ui.debug()
728 Label names take the form of "topic.type". For example, ui.debug()
726 issues a label of "ui.debug".
729 issues a label of "ui.debug".
727
730
728 When labeling output for a specific command, a label of
731 When labeling output for a specific command, a label of
729 "cmdname.type" is recommended. For example, status issues
732 "cmdname.type" is recommended. For example, status issues
730 a label of "status.modified" for modified files.
733 a label of "status.modified" for modified files.
731 '''
734 '''
732 if self._buffers and not opts.get('prompt', False):
735 if self._buffers and not opts.get('prompt', False):
733 if self._bufferapplylabels:
736 if self._bufferapplylabels:
734 label = opts.get('label', '')
737 label = opts.get('label', '')
735 self._buffers[-1].extend(self.label(a, label) for a in args)
738 self._buffers[-1].extend(self.label(a, label) for a in args)
736 else:
739 else:
737 self._buffers[-1].extend(args)
740 self._buffers[-1].extend(args)
738 elif self._colormode == 'win32':
741 elif self._colormode == 'win32':
739 # windows color printing is its own can of crab, defer to
742 # windows color printing is its own can of crab, defer to
740 # the color module and that is it.
743 # the color module and that is it.
741 color.win32print(self, self._write, *args, **opts)
744 color.win32print(self, self._write, *args, **opts)
742 else:
745 else:
743 msgs = args
746 msgs = args
744 if self._colormode is not None:
747 if self._colormode is not None:
745 label = opts.get('label', '')
748 label = opts.get('label', '')
746 msgs = [self.label(a, label) for a in args]
749 msgs = [self.label(a, label) for a in args]
747 self._write(*msgs, **opts)
750 self._write(*msgs, **opts)
748
751
749 def _write(self, *msgs, **opts):
752 def _write(self, *msgs, **opts):
750 self._progclear()
753 self._progclear()
751 # opencode timeblockedsection because this is a critical path
754 # opencode timeblockedsection because this is a critical path
752 starttime = util.timer()
755 starttime = util.timer()
753 try:
756 try:
754 for a in msgs:
757 for a in msgs:
755 self.fout.write(a)
758 self.fout.write(a)
756 finally:
759 finally:
757 self._blockedtimes['stdio_blocked'] += \
760 self._blockedtimes['stdio_blocked'] += \
758 (util.timer() - starttime) * 1000
761 (util.timer() - starttime) * 1000
759
762
760 def write_err(self, *args, **opts):
763 def write_err(self, *args, **opts):
761 self._progclear()
764 self._progclear()
762 if self._bufferstates and self._bufferstates[-1][0]:
765 if self._bufferstates and self._bufferstates[-1][0]:
763 self.write(*args, **opts)
766 self.write(*args, **opts)
764 elif self._colormode == 'win32':
767 elif self._colormode == 'win32':
765 # windows color printing is its own can of crab, defer to
768 # windows color printing is its own can of crab, defer to
766 # the color module and that is it.
769 # the color module and that is it.
767 color.win32print(self, self._write_err, *args, **opts)
770 color.win32print(self, self._write_err, *args, **opts)
768 else:
771 else:
769 msgs = args
772 msgs = args
770 if self._colormode is not None:
773 if self._colormode is not None:
771 label = opts.get('label', '')
774 label = opts.get('label', '')
772 msgs = [self.label(a, label) for a in args]
775 msgs = [self.label(a, label) for a in args]
773 self._write_err(*msgs, **opts)
776 self._write_err(*msgs, **opts)
774
777
775 def _write_err(self, *msgs, **opts):
778 def _write_err(self, *msgs, **opts):
776 try:
779 try:
777 with self.timeblockedsection('stdio'):
780 with self.timeblockedsection('stdio'):
778 if not getattr(self.fout, 'closed', False):
781 if not getattr(self.fout, 'closed', False):
779 self.fout.flush()
782 self.fout.flush()
780 for a in msgs:
783 for a in msgs:
781 self.ferr.write(a)
784 self.ferr.write(a)
782 # stderr may be buffered under win32 when redirected to files,
785 # stderr may be buffered under win32 when redirected to files,
783 # including stdout.
786 # including stdout.
784 if not getattr(self.ferr, 'closed', False):
787 if not getattr(self.ferr, 'closed', False):
785 self.ferr.flush()
788 self.ferr.flush()
786 except IOError as inst:
789 except IOError as inst:
787 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
790 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
788 raise
791 raise
789
792
790 def flush(self):
793 def flush(self):
791 # opencode timeblockedsection because this is a critical path
794 # opencode timeblockedsection because this is a critical path
792 starttime = util.timer()
795 starttime = util.timer()
793 try:
796 try:
794 try: self.fout.flush()
797 try: self.fout.flush()
795 except (IOError, ValueError): pass
798 except (IOError, ValueError): pass
796 try: self.ferr.flush()
799 try: self.ferr.flush()
797 except (IOError, ValueError): pass
800 except (IOError, ValueError): pass
798 finally:
801 finally:
799 self._blockedtimes['stdio_blocked'] += \
802 self._blockedtimes['stdio_blocked'] += \
800 (util.timer() - starttime) * 1000
803 (util.timer() - starttime) * 1000
801
804
802 def _isatty(self, fh):
805 def _isatty(self, fh):
803 if self.configbool('ui', 'nontty', False):
806 if self.configbool('ui', 'nontty', False):
804 return False
807 return False
805 return util.isatty(fh)
808 return util.isatty(fh)
806
809
807 def disablepager(self):
810 def disablepager(self):
808 self._disablepager = True
811 self._disablepager = True
809
812
810 def pager(self, command):
813 def pager(self, command):
811 """Start a pager for subsequent command output.
814 """Start a pager for subsequent command output.
812
815
813 Commands which produce a long stream of output should call
816 Commands which produce a long stream of output should call
814 this function to activate the user's preferred pagination
817 this function to activate the user's preferred pagination
815 mechanism (which may be no pager). Calling this function
818 mechanism (which may be no pager). Calling this function
816 precludes any future use of interactive functionality, such as
819 precludes any future use of interactive functionality, such as
817 prompting the user or activating curses.
820 prompting the user or activating curses.
818
821
819 Args:
822 Args:
820 command: The full, non-aliased name of the command. That is, "log"
823 command: The full, non-aliased name of the command. That is, "log"
821 not "history, "summary" not "summ", etc.
824 not "history, "summary" not "summ", etc.
822 """
825 """
823 if (self._disablepager
826 if (self._disablepager
824 or self.pageractive
827 or self.pageractive
825 or command in self.configlist('pager', 'ignore')
828 or command in self.configlist('pager', 'ignore')
826 or not self.configbool('pager', 'enable', True)
829 or not self.configbool('pager', 'enable', True)
827 or not self.configbool('pager', 'attend-' + command, True)
830 or not self.configbool('pager', 'attend-' + command, True)
828 # TODO: if we want to allow HGPLAINEXCEPT=pager,
831 # TODO: if we want to allow HGPLAINEXCEPT=pager,
829 # formatted() will need some adjustment.
832 # formatted() will need some adjustment.
830 or not self.formatted()
833 or not self.formatted()
831 or self.plain()
834 or self.plain()
832 # TODO: expose debugger-enabled on the UI object
835 # TODO: expose debugger-enabled on the UI object
833 or '--debugger' in pycompat.sysargv):
836 or '--debugger' in pycompat.sysargv):
834 # We only want to paginate if the ui appears to be
837 # We only want to paginate if the ui appears to be
835 # interactive, the user didn't say HGPLAIN or
838 # interactive, the user didn't say HGPLAIN or
836 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
839 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
837 return
840 return
838
841
839 # TODO: add a "system defaults" config section so this default
842 # TODO: add a "system defaults" config section so this default
840 # of more(1) can be easily replaced with a global
843 # of more(1) can be easily replaced with a global
841 # configuration file. For example, on OS X the sane default is
844 # configuration file. For example, on OS X the sane default is
842 # less(1), not more(1), and on debian it's
845 # less(1), not more(1), and on debian it's
843 # sensible-pager(1). We should probably also give the system
846 # sensible-pager(1). We should probably also give the system
844 # default editor command similar treatment.
847 # default editor command similar treatment.
845 envpager = encoding.environ.get('PAGER', 'more')
848 envpager = encoding.environ.get('PAGER', 'more')
846 pagercmd = self.config('pager', 'pager', envpager)
849 pagercmd = self.config('pager', 'pager', envpager)
847 if not pagercmd:
850 if not pagercmd:
848 return
851 return
849
852
850 self.debug('starting pager for command %r\n' % command)
853 self.debug('starting pager for command %r\n' % command)
851 self.flush()
854 self.flush()
852 self.pageractive = True
855 self.pageractive = True
853 # Preserve the formatted-ness of the UI. This is important
856 # Preserve the formatted-ness of the UI. This is important
854 # because we mess with stdout, which might confuse
857 # because we mess with stdout, which might confuse
855 # auto-detection of things being formatted.
858 # auto-detection of things being formatted.
856 self.setconfig('ui', 'formatted', self.formatted(), 'pager')
859 self.setconfig('ui', 'formatted', self.formatted(), 'pager')
857 self.setconfig('ui', 'interactive', False, 'pager')
860 self.setconfig('ui', 'interactive', False, 'pager')
858 if util.safehasattr(signal, "SIGPIPE"):
861 if util.safehasattr(signal, "SIGPIPE"):
859 signal.signal(signal.SIGPIPE, _catchterm)
862 signal.signal(signal.SIGPIPE, _catchterm)
860 self._runpager(pagercmd)
863 self._runpager(pagercmd)
861
864
862 def _runpager(self, command):
865 def _runpager(self, command):
863 """Actually start the pager and set up file descriptors.
866 """Actually start the pager and set up file descriptors.
864
867
865 This is separate in part so that extensions (like chg) can
868 This is separate in part so that extensions (like chg) can
866 override how a pager is invoked.
869 override how a pager is invoked.
867 """
870 """
868 if command == 'cat':
871 if command == 'cat':
869 # Save ourselves some work.
872 # Save ourselves some work.
870 return
873 return
871 # If the command doesn't contain any of these characters, we
874 # If the command doesn't contain any of these characters, we
872 # assume it's a binary and exec it directly. This means for
875 # assume it's a binary and exec it directly. This means for
873 # simple pager command configurations, we can degrade
876 # simple pager command configurations, we can degrade
874 # gracefully and tell the user about their broken pager.
877 # gracefully and tell the user about their broken pager.
875 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
878 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
876
879
877 if pycompat.osname == 'nt' and not shell:
880 if pycompat.osname == 'nt' and not shell:
878 # Window's built-in `more` cannot be invoked with shell=False, but
881 # Window's built-in `more` cannot be invoked with shell=False, but
879 # its `more.com` can. Hide this implementation detail from the
882 # its `more.com` can. Hide this implementation detail from the
880 # user so we can also get sane bad PAGER behavior. MSYS has
883 # user so we can also get sane bad PAGER behavior. MSYS has
881 # `more.exe`, so do a cmd.exe style resolution of the executable to
884 # `more.exe`, so do a cmd.exe style resolution of the executable to
882 # determine which one to use.
885 # determine which one to use.
883 fullcmd = util.findexe(command)
886 fullcmd = util.findexe(command)
884 if not fullcmd:
887 if not fullcmd:
885 self.warn(_("missing pager command '%s', skipping pager\n")
888 self.warn(_("missing pager command '%s', skipping pager\n")
886 % command)
889 % command)
887 return
890 return
888
891
889 command = fullcmd
892 command = fullcmd
890
893
891 try:
894 try:
892 pager = subprocess.Popen(
895 pager = subprocess.Popen(
893 command, shell=shell, bufsize=-1,
896 command, shell=shell, bufsize=-1,
894 close_fds=util.closefds, stdin=subprocess.PIPE,
897 close_fds=util.closefds, stdin=subprocess.PIPE,
895 stdout=util.stdout, stderr=util.stderr)
898 stdout=util.stdout, stderr=util.stderr)
896 except OSError as e:
899 except OSError as e:
897 if e.errno == errno.ENOENT and not shell:
900 if e.errno == errno.ENOENT and not shell:
898 self.warn(_("missing pager command '%s', skipping pager\n")
901 self.warn(_("missing pager command '%s', skipping pager\n")
899 % command)
902 % command)
900 return
903 return
901 raise
904 raise
902
905
903 # back up original file descriptors
906 # back up original file descriptors
904 stdoutfd = os.dup(util.stdout.fileno())
907 stdoutfd = os.dup(util.stdout.fileno())
905 stderrfd = os.dup(util.stderr.fileno())
908 stderrfd = os.dup(util.stderr.fileno())
906
909
907 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
910 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
908 if self._isatty(util.stderr):
911 if self._isatty(util.stderr):
909 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
912 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
910
913
911 @atexit.register
914 @atexit.register
912 def killpager():
915 def killpager():
913 if util.safehasattr(signal, "SIGINT"):
916 if util.safehasattr(signal, "SIGINT"):
914 signal.signal(signal.SIGINT, signal.SIG_IGN)
917 signal.signal(signal.SIGINT, signal.SIG_IGN)
915 # restore original fds, closing pager.stdin copies in the process
918 # restore original fds, closing pager.stdin copies in the process
916 os.dup2(stdoutfd, util.stdout.fileno())
919 os.dup2(stdoutfd, util.stdout.fileno())
917 os.dup2(stderrfd, util.stderr.fileno())
920 os.dup2(stderrfd, util.stderr.fileno())
918 pager.stdin.close()
921 pager.stdin.close()
919 pager.wait()
922 pager.wait()
920
923
921 def interface(self, feature):
924 def interface(self, feature):
922 """what interface to use for interactive console features?
925 """what interface to use for interactive console features?
923
926
924 The interface is controlled by the value of `ui.interface` but also by
927 The interface is controlled by the value of `ui.interface` but also by
925 the value of feature-specific configuration. For example:
928 the value of feature-specific configuration. For example:
926
929
927 ui.interface.histedit = text
930 ui.interface.histedit = text
928 ui.interface.chunkselector = curses
931 ui.interface.chunkselector = curses
929
932
930 Here the features are "histedit" and "chunkselector".
933 Here the features are "histedit" and "chunkselector".
931
934
932 The configuration above means that the default interfaces for commands
935 The configuration above means that the default interfaces for commands
933 is curses, the interface for histedit is text and the interface for
936 is curses, the interface for histedit is text and the interface for
934 selecting chunk is crecord (the best curses interface available).
937 selecting chunk is crecord (the best curses interface available).
935
938
936 Consider the following example:
939 Consider the following example:
937 ui.interface = curses
940 ui.interface = curses
938 ui.interface.histedit = text
941 ui.interface.histedit = text
939
942
940 Then histedit will use the text interface and chunkselector will use
943 Then histedit will use the text interface and chunkselector will use
941 the default curses interface (crecord at the moment).
944 the default curses interface (crecord at the moment).
942 """
945 """
943 alldefaults = frozenset(["text", "curses"])
946 alldefaults = frozenset(["text", "curses"])
944
947
945 featureinterfaces = {
948 featureinterfaces = {
946 "chunkselector": [
949 "chunkselector": [
947 "text",
950 "text",
948 "curses",
951 "curses",
949 ]
952 ]
950 }
953 }
951
954
952 # Feature-specific interface
955 # Feature-specific interface
953 if feature not in featureinterfaces.keys():
956 if feature not in featureinterfaces.keys():
954 # Programming error, not user error
957 # Programming error, not user error
955 raise ValueError("Unknown feature requested %s" % feature)
958 raise ValueError("Unknown feature requested %s" % feature)
956
959
957 availableinterfaces = frozenset(featureinterfaces[feature])
960 availableinterfaces = frozenset(featureinterfaces[feature])
958 if alldefaults > availableinterfaces:
961 if alldefaults > availableinterfaces:
959 # Programming error, not user error. We need a use case to
962 # Programming error, not user error. We need a use case to
960 # define the right thing to do here.
963 # define the right thing to do here.
961 raise ValueError(
964 raise ValueError(
962 "Feature %s does not handle all default interfaces" %
965 "Feature %s does not handle all default interfaces" %
963 feature)
966 feature)
964
967
965 if self.plain():
968 if self.plain():
966 return "text"
969 return "text"
967
970
968 # Default interface for all the features
971 # Default interface for all the features
969 defaultinterface = "text"
972 defaultinterface = "text"
970 i = self.config("ui", "interface", None)
973 i = self.config("ui", "interface", None)
971 if i in alldefaults:
974 if i in alldefaults:
972 defaultinterface = i
975 defaultinterface = i
973
976
974 choseninterface = defaultinterface
977 choseninterface = defaultinterface
975 f = self.config("ui", "interface.%s" % feature, None)
978 f = self.config("ui", "interface.%s" % feature, None)
976 if f in availableinterfaces:
979 if f in availableinterfaces:
977 choseninterface = f
980 choseninterface = f
978
981
979 if i is not None and defaultinterface != i:
982 if i is not None and defaultinterface != i:
980 if f is not None:
983 if f is not None:
981 self.warn(_("invalid value for ui.interface: %s\n") %
984 self.warn(_("invalid value for ui.interface: %s\n") %
982 (i,))
985 (i,))
983 else:
986 else:
984 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
987 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
985 (i, choseninterface))
988 (i, choseninterface))
986 if f is not None and choseninterface != f:
989 if f is not None and choseninterface != f:
987 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
990 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
988 (feature, f, choseninterface))
991 (feature, f, choseninterface))
989
992
990 return choseninterface
993 return choseninterface
991
994
992 def interactive(self):
995 def interactive(self):
993 '''is interactive input allowed?
996 '''is interactive input allowed?
994
997
995 An interactive session is a session where input can be reasonably read
998 An interactive session is a session where input can be reasonably read
996 from `sys.stdin'. If this function returns false, any attempt to read
999 from `sys.stdin'. If this function returns false, any attempt to read
997 from stdin should fail with an error, unless a sensible default has been
1000 from stdin should fail with an error, unless a sensible default has been
998 specified.
1001 specified.
999
1002
1000 Interactiveness is triggered by the value of the `ui.interactive'
1003 Interactiveness is triggered by the value of the `ui.interactive'
1001 configuration variable or - if it is unset - when `sys.stdin' points
1004 configuration variable or - if it is unset - when `sys.stdin' points
1002 to a terminal device.
1005 to a terminal device.
1003
1006
1004 This function refers to input only; for output, see `ui.formatted()'.
1007 This function refers to input only; for output, see `ui.formatted()'.
1005 '''
1008 '''
1006 i = self.configbool("ui", "interactive", None)
1009 i = self.configbool("ui", "interactive", None)
1007 if i is None:
1010 if i is None:
1008 # some environments replace stdin without implementing isatty
1011 # some environments replace stdin without implementing isatty
1009 # usually those are non-interactive
1012 # usually those are non-interactive
1010 return self._isatty(self.fin)
1013 return self._isatty(self.fin)
1011
1014
1012 return i
1015 return i
1013
1016
1014 def termwidth(self):
1017 def termwidth(self):
1015 '''how wide is the terminal in columns?
1018 '''how wide is the terminal in columns?
1016 '''
1019 '''
1017 if 'COLUMNS' in encoding.environ:
1020 if 'COLUMNS' in encoding.environ:
1018 try:
1021 try:
1019 return int(encoding.environ['COLUMNS'])
1022 return int(encoding.environ['COLUMNS'])
1020 except ValueError:
1023 except ValueError:
1021 pass
1024 pass
1022 return scmutil.termsize(self)[0]
1025 return scmutil.termsize(self)[0]
1023
1026
1024 def formatted(self):
1027 def formatted(self):
1025 '''should formatted output be used?
1028 '''should formatted output be used?
1026
1029
1027 It is often desirable to format the output to suite the output medium.
1030 It is often desirable to format the output to suite the output medium.
1028 Examples of this are truncating long lines or colorizing messages.
1031 Examples of this are truncating long lines or colorizing messages.
1029 However, this is not often not desirable when piping output into other
1032 However, this is not often not desirable when piping output into other
1030 utilities, e.g. `grep'.
1033 utilities, e.g. `grep'.
1031
1034
1032 Formatted output is triggered by the value of the `ui.formatted'
1035 Formatted output is triggered by the value of the `ui.formatted'
1033 configuration variable or - if it is unset - when `sys.stdout' points
1036 configuration variable or - if it is unset - when `sys.stdout' points
1034 to a terminal device. Please note that `ui.formatted' should be
1037 to a terminal device. Please note that `ui.formatted' should be
1035 considered an implementation detail; it is not intended for use outside
1038 considered an implementation detail; it is not intended for use outside
1036 Mercurial or its extensions.
1039 Mercurial or its extensions.
1037
1040
1038 This function refers to output only; for input, see `ui.interactive()'.
1041 This function refers to output only; for input, see `ui.interactive()'.
1039 This function always returns false when in plain mode, see `ui.plain()'.
1042 This function always returns false when in plain mode, see `ui.plain()'.
1040 '''
1043 '''
1041 if self.plain():
1044 if self.plain():
1042 return False
1045 return False
1043
1046
1044 i = self.configbool("ui", "formatted", None)
1047 i = self.configbool("ui", "formatted", None)
1045 if i is None:
1048 if i is None:
1046 # some environments replace stdout without implementing isatty
1049 # some environments replace stdout without implementing isatty
1047 # usually those are non-interactive
1050 # usually those are non-interactive
1048 return self._isatty(self.fout)
1051 return self._isatty(self.fout)
1049
1052
1050 return i
1053 return i
1051
1054
1052 def _readline(self, prompt=''):
1055 def _readline(self, prompt=''):
1053 if self._isatty(self.fin):
1056 if self._isatty(self.fin):
1054 try:
1057 try:
1055 # magically add command line editing support, where
1058 # magically add command line editing support, where
1056 # available
1059 # available
1057 import readline
1060 import readline
1058 # force demandimport to really load the module
1061 # force demandimport to really load the module
1059 readline.read_history_file
1062 readline.read_history_file
1060 # windows sometimes raises something other than ImportError
1063 # windows sometimes raises something other than ImportError
1061 except Exception:
1064 except Exception:
1062 pass
1065 pass
1063
1066
1064 # call write() so output goes through subclassed implementation
1067 # call write() so output goes through subclassed implementation
1065 # e.g. color extension on Windows
1068 # e.g. color extension on Windows
1066 self.write(prompt, prompt=True)
1069 self.write(prompt, prompt=True)
1067
1070
1068 # instead of trying to emulate raw_input, swap (self.fin,
1071 # instead of trying to emulate raw_input, swap (self.fin,
1069 # self.fout) with (sys.stdin, sys.stdout)
1072 # self.fout) with (sys.stdin, sys.stdout)
1070 oldin = sys.stdin
1073 oldin = sys.stdin
1071 oldout = sys.stdout
1074 oldout = sys.stdout
1072 sys.stdin = self.fin
1075 sys.stdin = self.fin
1073 sys.stdout = self.fout
1076 sys.stdout = self.fout
1074 # prompt ' ' must exist; otherwise readline may delete entire line
1077 # prompt ' ' must exist; otherwise readline may delete entire line
1075 # - http://bugs.python.org/issue12833
1078 # - http://bugs.python.org/issue12833
1076 with self.timeblockedsection('stdio'):
1079 with self.timeblockedsection('stdio'):
1077 line = raw_input(' ')
1080 line = raw_input(' ')
1078 sys.stdin = oldin
1081 sys.stdin = oldin
1079 sys.stdout = oldout
1082 sys.stdout = oldout
1080
1083
1081 # When stdin is in binary mode on Windows, it can cause
1084 # When stdin is in binary mode on Windows, it can cause
1082 # raw_input() to emit an extra trailing carriage return
1085 # raw_input() to emit an extra trailing carriage return
1083 if os.linesep == '\r\n' and line and line[-1] == '\r':
1086 if os.linesep == '\r\n' and line and line[-1] == '\r':
1084 line = line[:-1]
1087 line = line[:-1]
1085 return line
1088 return line
1086
1089
1087 def prompt(self, msg, default="y"):
1090 def prompt(self, msg, default="y"):
1088 """Prompt user with msg, read response.
1091 """Prompt user with msg, read response.
1089 If ui is not interactive, the default is returned.
1092 If ui is not interactive, the default is returned.
1090 """
1093 """
1091 if not self.interactive():
1094 if not self.interactive():
1092 self.write(msg, ' ', default or '', "\n")
1095 self.write(msg, ' ', default or '', "\n")
1093 return default
1096 return default
1094 try:
1097 try:
1095 r = self._readline(self.label(msg, 'ui.prompt'))
1098 r = self._readline(self.label(msg, 'ui.prompt'))
1096 if not r:
1099 if not r:
1097 r = default
1100 r = default
1098 if self.configbool('ui', 'promptecho'):
1101 if self.configbool('ui', 'promptecho'):
1099 self.write(r, "\n")
1102 self.write(r, "\n")
1100 return r
1103 return r
1101 except EOFError:
1104 except EOFError:
1102 raise error.ResponseExpected()
1105 raise error.ResponseExpected()
1103
1106
1104 @staticmethod
1107 @staticmethod
1105 def extractchoices(prompt):
1108 def extractchoices(prompt):
1106 """Extract prompt message and list of choices from specified prompt.
1109 """Extract prompt message and list of choices from specified prompt.
1107
1110
1108 This returns tuple "(message, choices)", and "choices" is the
1111 This returns tuple "(message, choices)", and "choices" is the
1109 list of tuple "(response character, text without &)".
1112 list of tuple "(response character, text without &)".
1110
1113
1111 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1114 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
1112 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1115 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1113 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1116 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
1114 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1117 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1115 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1118 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
1116 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1119 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1117 """
1120 """
1118
1121
1119 # Sadly, the prompt string may have been built with a filename
1122 # Sadly, the prompt string may have been built with a filename
1120 # containing "$$" so let's try to find the first valid-looking
1123 # containing "$$" so let's try to find the first valid-looking
1121 # prompt to start parsing. Sadly, we also can't rely on
1124 # prompt to start parsing. Sadly, we also can't rely on
1122 # choices containing spaces, ASCII, or basically anything
1125 # choices containing spaces, ASCII, or basically anything
1123 # except an ampersand followed by a character.
1126 # except an ampersand followed by a character.
1124 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1127 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1125 msg = m.group(1)
1128 msg = m.group(1)
1126 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1129 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1127 return (msg,
1130 return (msg,
1128 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1131 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1129 for s in choices])
1132 for s in choices])
1130
1133
1131 def promptchoice(self, prompt, default=0):
1134 def promptchoice(self, prompt, default=0):
1132 """Prompt user with a message, read response, and ensure it matches
1135 """Prompt user with a message, read response, and ensure it matches
1133 one of the provided choices. The prompt is formatted as follows:
1136 one of the provided choices. The prompt is formatted as follows:
1134
1137
1135 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1138 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1136
1139
1137 The index of the choice is returned. Responses are case
1140 The index of the choice is returned. Responses are case
1138 insensitive. If ui is not interactive, the default is
1141 insensitive. If ui is not interactive, the default is
1139 returned.
1142 returned.
1140 """
1143 """
1141
1144
1142 msg, choices = self.extractchoices(prompt)
1145 msg, choices = self.extractchoices(prompt)
1143 resps = [r for r, t in choices]
1146 resps = [r for r, t in choices]
1144 while True:
1147 while True:
1145 r = self.prompt(msg, resps[default])
1148 r = self.prompt(msg, resps[default])
1146 if r.lower() in resps:
1149 if r.lower() in resps:
1147 return resps.index(r.lower())
1150 return resps.index(r.lower())
1148 self.write(_("unrecognized response\n"))
1151 self.write(_("unrecognized response\n"))
1149
1152
1150 def getpass(self, prompt=None, default=None):
1153 def getpass(self, prompt=None, default=None):
1151 if not self.interactive():
1154 if not self.interactive():
1152 return default
1155 return default
1153 try:
1156 try:
1154 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1157 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1155 # disable getpass() only if explicitly specified. it's still valid
1158 # disable getpass() only if explicitly specified. it's still valid
1156 # to interact with tty even if fin is not a tty.
1159 # to interact with tty even if fin is not a tty.
1157 with self.timeblockedsection('stdio'):
1160 with self.timeblockedsection('stdio'):
1158 if self.configbool('ui', 'nontty'):
1161 if self.configbool('ui', 'nontty'):
1159 l = self.fin.readline()
1162 l = self.fin.readline()
1160 if not l:
1163 if not l:
1161 raise EOFError
1164 raise EOFError
1162 return l.rstrip('\n')
1165 return l.rstrip('\n')
1163 else:
1166 else:
1164 return getpass.getpass('')
1167 return getpass.getpass('')
1165 except EOFError:
1168 except EOFError:
1166 raise error.ResponseExpected()
1169 raise error.ResponseExpected()
1167 def status(self, *msg, **opts):
1170 def status(self, *msg, **opts):
1168 '''write status message to output (if ui.quiet is False)
1171 '''write status message to output (if ui.quiet is False)
1169
1172
1170 This adds an output label of "ui.status".
1173 This adds an output label of "ui.status".
1171 '''
1174 '''
1172 if not self.quiet:
1175 if not self.quiet:
1173 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1176 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1174 self.write(*msg, **opts)
1177 self.write(*msg, **opts)
1175 def warn(self, *msg, **opts):
1178 def warn(self, *msg, **opts):
1176 '''write warning message to output (stderr)
1179 '''write warning message to output (stderr)
1177
1180
1178 This adds an output label of "ui.warning".
1181 This adds an output label of "ui.warning".
1179 '''
1182 '''
1180 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1183 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1181 self.write_err(*msg, **opts)
1184 self.write_err(*msg, **opts)
1182 def note(self, *msg, **opts):
1185 def note(self, *msg, **opts):
1183 '''write note to output (if ui.verbose is True)
1186 '''write note to output (if ui.verbose is True)
1184
1187
1185 This adds an output label of "ui.note".
1188 This adds an output label of "ui.note".
1186 '''
1189 '''
1187 if self.verbose:
1190 if self.verbose:
1188 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1191 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1189 self.write(*msg, **opts)
1192 self.write(*msg, **opts)
1190 def debug(self, *msg, **opts):
1193 def debug(self, *msg, **opts):
1191 '''write debug message to output (if ui.debugflag is True)
1194 '''write debug message to output (if ui.debugflag is True)
1192
1195
1193 This adds an output label of "ui.debug".
1196 This adds an output label of "ui.debug".
1194 '''
1197 '''
1195 if self.debugflag:
1198 if self.debugflag:
1196 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1199 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1197 self.write(*msg, **opts)
1200 self.write(*msg, **opts)
1198
1201
1199 def edit(self, text, user, extra=None, editform=None, pending=None,
1202 def edit(self, text, user, extra=None, editform=None, pending=None,
1200 repopath=None):
1203 repopath=None):
1201 extra_defaults = {
1204 extra_defaults = {
1202 'prefix': 'editor',
1205 'prefix': 'editor',
1203 'suffix': '.txt',
1206 'suffix': '.txt',
1204 }
1207 }
1205 if extra is not None:
1208 if extra is not None:
1206 extra_defaults.update(extra)
1209 extra_defaults.update(extra)
1207 extra = extra_defaults
1210 extra = extra_defaults
1208
1211
1209 rdir = None
1212 rdir = None
1210 if self.configbool('experimental', 'editortmpinhg'):
1213 if self.configbool('experimental', 'editortmpinhg'):
1211 rdir = repopath
1214 rdir = repopath
1212 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1215 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1213 suffix=extra['suffix'], text=True,
1216 suffix=extra['suffix'], text=True,
1214 dir=rdir)
1217 dir=rdir)
1215 try:
1218 try:
1216 f = os.fdopen(fd, pycompat.sysstr("w"))
1219 f = os.fdopen(fd, pycompat.sysstr("w"))
1217 f.write(encoding.strfromlocal(text))
1220 f.write(encoding.strfromlocal(text))
1218 f.close()
1221 f.close()
1219
1222
1220 environ = {'HGUSER': user}
1223 environ = {'HGUSER': user}
1221 if 'transplant_source' in extra:
1224 if 'transplant_source' in extra:
1222 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1225 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1223 for label in ('intermediate-source', 'source', 'rebase_source'):
1226 for label in ('intermediate-source', 'source', 'rebase_source'):
1224 if label in extra:
1227 if label in extra:
1225 environ.update({'HGREVISION': extra[label]})
1228 environ.update({'HGREVISION': extra[label]})
1226 break
1229 break
1227 if editform:
1230 if editform:
1228 environ.update({'HGEDITFORM': editform})
1231 environ.update({'HGEDITFORM': editform})
1229 if pending:
1232 if pending:
1230 environ.update({'HG_PENDING': pending})
1233 environ.update({'HG_PENDING': pending})
1231
1234
1232 editor = self.geteditor()
1235 editor = self.geteditor()
1233
1236
1234 self.system("%s \"%s\"" % (editor, name),
1237 self.system("%s \"%s\"" % (editor, name),
1235 environ=environ,
1238 environ=environ,
1236 onerr=error.Abort, errprefix=_("edit failed"),
1239 onerr=error.Abort, errprefix=_("edit failed"),
1237 blockedtag='editor')
1240 blockedtag='editor')
1238
1241
1239 f = open(name)
1242 f = open(name)
1240 t = encoding.strtolocal(f.read())
1243 t = encoding.strtolocal(f.read())
1241 f.close()
1244 f.close()
1242 finally:
1245 finally:
1243 os.unlink(name)
1246 os.unlink(name)
1244
1247
1245 return t
1248 return t
1246
1249
1247 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1250 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1248 blockedtag=None):
1251 blockedtag=None):
1249 '''execute shell command with appropriate output stream. command
1252 '''execute shell command with appropriate output stream. command
1250 output will be redirected if fout is not stdout.
1253 output will be redirected if fout is not stdout.
1251
1254
1252 if command fails and onerr is None, return status, else raise onerr
1255 if command fails and onerr is None, return status, else raise onerr
1253 object as exception.
1256 object as exception.
1254 '''
1257 '''
1255 if blockedtag is None:
1258 if blockedtag is None:
1256 # Long cmds tend to be because of an absolute path on cmd. Keep
1259 # Long cmds tend to be because of an absolute path on cmd. Keep
1257 # the tail end instead
1260 # the tail end instead
1258 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1261 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1259 blockedtag = 'unknown_system_' + cmdsuffix
1262 blockedtag = 'unknown_system_' + cmdsuffix
1260 out = self.fout
1263 out = self.fout
1261 if any(s[1] for s in self._bufferstates):
1264 if any(s[1] for s in self._bufferstates):
1262 out = self
1265 out = self
1263 with self.timeblockedsection(blockedtag):
1266 with self.timeblockedsection(blockedtag):
1264 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1267 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1265 if rc and onerr:
1268 if rc and onerr:
1266 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1269 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1267 util.explainexit(rc)[0])
1270 util.explainexit(rc)[0])
1268 if errprefix:
1271 if errprefix:
1269 errmsg = '%s: %s' % (errprefix, errmsg)
1272 errmsg = '%s: %s' % (errprefix, errmsg)
1270 raise onerr(errmsg)
1273 raise onerr(errmsg)
1271 return rc
1274 return rc
1272
1275
1273 def _runsystem(self, cmd, environ, cwd, out):
1276 def _runsystem(self, cmd, environ, cwd, out):
1274 """actually execute the given shell command (can be overridden by
1277 """actually execute the given shell command (can be overridden by
1275 extensions like chg)"""
1278 extensions like chg)"""
1276 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1279 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1277
1280
1278 def traceback(self, exc=None, force=False):
1281 def traceback(self, exc=None, force=False):
1279 '''print exception traceback if traceback printing enabled or forced.
1282 '''print exception traceback if traceback printing enabled or forced.
1280 only to call in exception handler. returns true if traceback
1283 only to call in exception handler. returns true if traceback
1281 printed.'''
1284 printed.'''
1282 if self.tracebackflag or force:
1285 if self.tracebackflag or force:
1283 if exc is None:
1286 if exc is None:
1284 exc = sys.exc_info()
1287 exc = sys.exc_info()
1285 cause = getattr(exc[1], 'cause', None)
1288 cause = getattr(exc[1], 'cause', None)
1286
1289
1287 if cause is not None:
1290 if cause is not None:
1288 causetb = traceback.format_tb(cause[2])
1291 causetb = traceback.format_tb(cause[2])
1289 exctb = traceback.format_tb(exc[2])
1292 exctb = traceback.format_tb(exc[2])
1290 exconly = traceback.format_exception_only(cause[0], cause[1])
1293 exconly = traceback.format_exception_only(cause[0], cause[1])
1291
1294
1292 # exclude frame where 'exc' was chained and rethrown from exctb
1295 # exclude frame where 'exc' was chained and rethrown from exctb
1293 self.write_err('Traceback (most recent call last):\n',
1296 self.write_err('Traceback (most recent call last):\n',
1294 ''.join(exctb[:-1]),
1297 ''.join(exctb[:-1]),
1295 ''.join(causetb),
1298 ''.join(causetb),
1296 ''.join(exconly))
1299 ''.join(exconly))
1297 else:
1300 else:
1298 output = traceback.format_exception(exc[0], exc[1], exc[2])
1301 output = traceback.format_exception(exc[0], exc[1], exc[2])
1299 data = r''.join(output)
1302 data = r''.join(output)
1300 if pycompat.ispy3:
1303 if pycompat.ispy3:
1301 enc = pycompat.sysstr(encoding.encoding)
1304 enc = pycompat.sysstr(encoding.encoding)
1302 data = data.encode(enc, errors=r'replace')
1305 data = data.encode(enc, errors=r'replace')
1303 self.write_err(data)
1306 self.write_err(data)
1304 return self.tracebackflag or force
1307 return self.tracebackflag or force
1305
1308
1306 def geteditor(self):
1309 def geteditor(self):
1307 '''return editor to use'''
1310 '''return editor to use'''
1308 if pycompat.sysplatform == 'plan9':
1311 if pycompat.sysplatform == 'plan9':
1309 # vi is the MIPS instruction simulator on Plan 9. We
1312 # vi is the MIPS instruction simulator on Plan 9. We
1310 # instead default to E to plumb commit messages to
1313 # instead default to E to plumb commit messages to
1311 # avoid confusion.
1314 # avoid confusion.
1312 editor = 'E'
1315 editor = 'E'
1313 else:
1316 else:
1314 editor = 'vi'
1317 editor = 'vi'
1315 return (encoding.environ.get("HGEDITOR") or
1318 return (encoding.environ.get("HGEDITOR") or
1316 self.config("ui", "editor") or
1319 self.config("ui", "editor") or
1317 encoding.environ.get("VISUAL") or
1320 encoding.environ.get("VISUAL") or
1318 encoding.environ.get("EDITOR", editor))
1321 encoding.environ.get("EDITOR", editor))
1319
1322
1320 @util.propertycache
1323 @util.propertycache
1321 def _progbar(self):
1324 def _progbar(self):
1322 """setup the progbar singleton to the ui object"""
1325 """setup the progbar singleton to the ui object"""
1323 if (self.quiet or self.debugflag
1326 if (self.quiet or self.debugflag
1324 or self.configbool('progress', 'disable', False)
1327 or self.configbool('progress', 'disable', False)
1325 or not progress.shouldprint(self)):
1328 or not progress.shouldprint(self)):
1326 return None
1329 return None
1327 return getprogbar(self)
1330 return getprogbar(self)
1328
1331
1329 def _progclear(self):
1332 def _progclear(self):
1330 """clear progress bar output if any. use it before any output"""
1333 """clear progress bar output if any. use it before any output"""
1331 if '_progbar' not in vars(self): # nothing loaded yet
1334 if '_progbar' not in vars(self): # nothing loaded yet
1332 return
1335 return
1333 if self._progbar is not None and self._progbar.printed:
1336 if self._progbar is not None and self._progbar.printed:
1334 self._progbar.clear()
1337 self._progbar.clear()
1335
1338
1336 def progress(self, topic, pos, item="", unit="", total=None):
1339 def progress(self, topic, pos, item="", unit="", total=None):
1337 '''show a progress message
1340 '''show a progress message
1338
1341
1339 By default a textual progress bar will be displayed if an operation
1342 By default a textual progress bar will be displayed if an operation
1340 takes too long. 'topic' is the current operation, 'item' is a
1343 takes too long. 'topic' is the current operation, 'item' is a
1341 non-numeric marker of the current position (i.e. the currently
1344 non-numeric marker of the current position (i.e. the currently
1342 in-process file), 'pos' is the current numeric position (i.e.
1345 in-process file), 'pos' is the current numeric position (i.e.
1343 revision, bytes, etc.), unit is a corresponding unit label,
1346 revision, bytes, etc.), unit is a corresponding unit label,
1344 and total is the highest expected pos.
1347 and total is the highest expected pos.
1345
1348
1346 Multiple nested topics may be active at a time.
1349 Multiple nested topics may be active at a time.
1347
1350
1348 All topics should be marked closed by setting pos to None at
1351 All topics should be marked closed by setting pos to None at
1349 termination.
1352 termination.
1350 '''
1353 '''
1351 if self._progbar is not None:
1354 if self._progbar is not None:
1352 self._progbar.progress(topic, pos, item=item, unit=unit,
1355 self._progbar.progress(topic, pos, item=item, unit=unit,
1353 total=total)
1356 total=total)
1354 if pos is None or not self.configbool('progress', 'debug'):
1357 if pos is None or not self.configbool('progress', 'debug'):
1355 return
1358 return
1356
1359
1357 if unit:
1360 if unit:
1358 unit = ' ' + unit
1361 unit = ' ' + unit
1359 if item:
1362 if item:
1360 item = ' ' + item
1363 item = ' ' + item
1361
1364
1362 if total:
1365 if total:
1363 pct = 100.0 * pos / total
1366 pct = 100.0 * pos / total
1364 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1367 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1365 % (topic, item, pos, total, unit, pct))
1368 % (topic, item, pos, total, unit, pct))
1366 else:
1369 else:
1367 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1370 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1368
1371
1369 def log(self, service, *msg, **opts):
1372 def log(self, service, *msg, **opts):
1370 '''hook for logging facility extensions
1373 '''hook for logging facility extensions
1371
1374
1372 service should be a readily-identifiable subsystem, which will
1375 service should be a readily-identifiable subsystem, which will
1373 allow filtering.
1376 allow filtering.
1374
1377
1375 *msg should be a newline-terminated format string to log, and
1378 *msg should be a newline-terminated format string to log, and
1376 then any values to %-format into that format string.
1379 then any values to %-format into that format string.
1377
1380
1378 **opts currently has no defined meanings.
1381 **opts currently has no defined meanings.
1379 '''
1382 '''
1380
1383
1381 def label(self, msg, label):
1384 def label(self, msg, label):
1382 '''style msg based on supplied label
1385 '''style msg based on supplied label
1383
1386
1384 If some color mode is enabled, this will add the necessary control
1387 If some color mode is enabled, this will add the necessary control
1385 characters to apply such color. In addition, 'debug' color mode adds
1388 characters to apply such color. In addition, 'debug' color mode adds
1386 markup showing which label affects a piece of text.
1389 markup showing which label affects a piece of text.
1387
1390
1388 ui.write(s, 'label') is equivalent to
1391 ui.write(s, 'label') is equivalent to
1389 ui.write(ui.label(s, 'label')).
1392 ui.write(ui.label(s, 'label')).
1390 '''
1393 '''
1391 if self._colormode is not None:
1394 if self._colormode is not None:
1392 return color.colorlabel(self, msg, label)
1395 return color.colorlabel(self, msg, label)
1393 return msg
1396 return msg
1394
1397
1395 def develwarn(self, msg, stacklevel=1, config=None):
1398 def develwarn(self, msg, stacklevel=1, config=None):
1396 """issue a developer warning message
1399 """issue a developer warning message
1397
1400
1398 Use 'stacklevel' to report the offender some layers further up in the
1401 Use 'stacklevel' to report the offender some layers further up in the
1399 stack.
1402 stack.
1400 """
1403 """
1401 if not self.configbool('devel', 'all-warnings'):
1404 if not self.configbool('devel', 'all-warnings'):
1402 if config is not None and not self.configbool('devel', config):
1405 if config is not None and not self.configbool('devel', config):
1403 return
1406 return
1404 msg = 'devel-warn: ' + msg
1407 msg = 'devel-warn: ' + msg
1405 stacklevel += 1 # get in develwarn
1408 stacklevel += 1 # get in develwarn
1406 if self.tracebackflag:
1409 if self.tracebackflag:
1407 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1410 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1408 self.log('develwarn', '%s at:\n%s' %
1411 self.log('develwarn', '%s at:\n%s' %
1409 (msg, ''.join(util.getstackframes(stacklevel))))
1412 (msg, ''.join(util.getstackframes(stacklevel))))
1410 else:
1413 else:
1411 curframe = inspect.currentframe()
1414 curframe = inspect.currentframe()
1412 calframe = inspect.getouterframes(curframe, 2)
1415 calframe = inspect.getouterframes(curframe, 2)
1413 self.write_err('%s at: %s:%s (%s)\n'
1416 self.write_err('%s at: %s:%s (%s)\n'
1414 % ((msg,) + calframe[stacklevel][1:4]))
1417 % ((msg,) + calframe[stacklevel][1:4]))
1415 self.log('develwarn', '%s at: %s:%s (%s)\n',
1418 self.log('develwarn', '%s at: %s:%s (%s)\n',
1416 msg, *calframe[stacklevel][1:4])
1419 msg, *calframe[stacklevel][1:4])
1417 curframe = calframe = None # avoid cycles
1420 curframe = calframe = None # avoid cycles
1418
1421
1419 def deprecwarn(self, msg, version):
1422 def deprecwarn(self, msg, version):
1420 """issue a deprecation warning
1423 """issue a deprecation warning
1421
1424
1422 - msg: message explaining what is deprecated and how to upgrade,
1425 - msg: message explaining what is deprecated and how to upgrade,
1423 - version: last version where the API will be supported,
1426 - version: last version where the API will be supported,
1424 """
1427 """
1425 if not (self.configbool('devel', 'all-warnings')
1428 if not (self.configbool('devel', 'all-warnings')
1426 or self.configbool('devel', 'deprec-warn')):
1429 or self.configbool('devel', 'deprec-warn')):
1427 return
1430 return
1428 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1431 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1429 " update your code.)") % version
1432 " update your code.)") % version
1430 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1433 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1431
1434
1432 def exportableenviron(self):
1435 def exportableenviron(self):
1433 """The environment variables that are safe to export, e.g. through
1436 """The environment variables that are safe to export, e.g. through
1434 hgweb.
1437 hgweb.
1435 """
1438 """
1436 return self._exportableenviron
1439 return self._exportableenviron
1437
1440
1438 @contextlib.contextmanager
1441 @contextlib.contextmanager
1439 def configoverride(self, overrides, source=""):
1442 def configoverride(self, overrides, source=""):
1440 """Context manager for temporary config overrides
1443 """Context manager for temporary config overrides
1441 `overrides` must be a dict of the following structure:
1444 `overrides` must be a dict of the following structure:
1442 {(section, name) : value}"""
1445 {(section, name) : value}"""
1443 backups = {}
1446 backups = {}
1444 try:
1447 try:
1445 for (section, name), value in overrides.items():
1448 for (section, name), value in overrides.items():
1446 backups[(section, name)] = self.backupconfig(section, name)
1449 backups[(section, name)] = self.backupconfig(section, name)
1447 self.setconfig(section, name, value, source)
1450 self.setconfig(section, name, value, source)
1448 yield
1451 yield
1449 finally:
1452 finally:
1450 for __, backup in backups.items():
1453 for __, backup in backups.items():
1451 self.restoreconfig(backup)
1454 self.restoreconfig(backup)
1452 # just restoring ui.quiet config to the previous value is not enough
1455 # just restoring ui.quiet config to the previous value is not enough
1453 # as it does not update ui.quiet class member
1456 # as it does not update ui.quiet class member
1454 if ('ui', 'quiet') in overrides:
1457 if ('ui', 'quiet') in overrides:
1455 self.fixconfig(section='ui')
1458 self.fixconfig(section='ui')
1456
1459
1457 class paths(dict):
1460 class paths(dict):
1458 """Represents a collection of paths and their configs.
1461 """Represents a collection of paths and their configs.
1459
1462
1460 Data is initially derived from ui instances and the config files they have
1463 Data is initially derived from ui instances and the config files they have
1461 loaded.
1464 loaded.
1462 """
1465 """
1463 def __init__(self, ui):
1466 def __init__(self, ui):
1464 dict.__init__(self)
1467 dict.__init__(self)
1465
1468
1466 for name, loc in ui.configitems('paths', ignoresub=True):
1469 for name, loc in ui.configitems('paths', ignoresub=True):
1467 # No location is the same as not existing.
1470 # No location is the same as not existing.
1468 if not loc:
1471 if not loc:
1469 continue
1472 continue
1470 loc, sub = ui.configsuboptions('paths', name)
1473 loc, sub = ui.configsuboptions('paths', name)
1471 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1474 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1472
1475
1473 def getpath(self, name, default=None):
1476 def getpath(self, name, default=None):
1474 """Return a ``path`` from a string, falling back to default.
1477 """Return a ``path`` from a string, falling back to default.
1475
1478
1476 ``name`` can be a named path or locations. Locations are filesystem
1479 ``name`` can be a named path or locations. Locations are filesystem
1477 paths or URIs.
1480 paths or URIs.
1478
1481
1479 Returns None if ``name`` is not a registered path, a URI, or a local
1482 Returns None if ``name`` is not a registered path, a URI, or a local
1480 path to a repo.
1483 path to a repo.
1481 """
1484 """
1482 # Only fall back to default if no path was requested.
1485 # Only fall back to default if no path was requested.
1483 if name is None:
1486 if name is None:
1484 if not default:
1487 if not default:
1485 default = ()
1488 default = ()
1486 elif not isinstance(default, (tuple, list)):
1489 elif not isinstance(default, (tuple, list)):
1487 default = (default,)
1490 default = (default,)
1488 for k in default:
1491 for k in default:
1489 try:
1492 try:
1490 return self[k]
1493 return self[k]
1491 except KeyError:
1494 except KeyError:
1492 continue
1495 continue
1493 return None
1496 return None
1494
1497
1495 # Most likely empty string.
1498 # Most likely empty string.
1496 # This may need to raise in the future.
1499 # This may need to raise in the future.
1497 if not name:
1500 if not name:
1498 return None
1501 return None
1499
1502
1500 try:
1503 try:
1501 return self[name]
1504 return self[name]
1502 except KeyError:
1505 except KeyError:
1503 # Try to resolve as a local path or URI.
1506 # Try to resolve as a local path or URI.
1504 try:
1507 try:
1505 # We don't pass sub-options in, so no need to pass ui instance.
1508 # We don't pass sub-options in, so no need to pass ui instance.
1506 return path(None, None, rawloc=name)
1509 return path(None, None, rawloc=name)
1507 except ValueError:
1510 except ValueError:
1508 raise error.RepoError(_('repository %s does not exist') %
1511 raise error.RepoError(_('repository %s does not exist') %
1509 name)
1512 name)
1510
1513
1511 _pathsuboptions = {}
1514 _pathsuboptions = {}
1512
1515
1513 def pathsuboption(option, attr):
1516 def pathsuboption(option, attr):
1514 """Decorator used to declare a path sub-option.
1517 """Decorator used to declare a path sub-option.
1515
1518
1516 Arguments are the sub-option name and the attribute it should set on
1519 Arguments are the sub-option name and the attribute it should set on
1517 ``path`` instances.
1520 ``path`` instances.
1518
1521
1519 The decorated function will receive as arguments a ``ui`` instance,
1522 The decorated function will receive as arguments a ``ui`` instance,
1520 ``path`` instance, and the string value of this option from the config.
1523 ``path`` instance, and the string value of this option from the config.
1521 The function should return the value that will be set on the ``path``
1524 The function should return the value that will be set on the ``path``
1522 instance.
1525 instance.
1523
1526
1524 This decorator can be used to perform additional verification of
1527 This decorator can be used to perform additional verification of
1525 sub-options and to change the type of sub-options.
1528 sub-options and to change the type of sub-options.
1526 """
1529 """
1527 def register(func):
1530 def register(func):
1528 _pathsuboptions[option] = (attr, func)
1531 _pathsuboptions[option] = (attr, func)
1529 return func
1532 return func
1530 return register
1533 return register
1531
1534
1532 @pathsuboption('pushurl', 'pushloc')
1535 @pathsuboption('pushurl', 'pushloc')
1533 def pushurlpathoption(ui, path, value):
1536 def pushurlpathoption(ui, path, value):
1534 u = util.url(value)
1537 u = util.url(value)
1535 # Actually require a URL.
1538 # Actually require a URL.
1536 if not u.scheme:
1539 if not u.scheme:
1537 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1540 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1538 return None
1541 return None
1539
1542
1540 # Don't support the #foo syntax in the push URL to declare branch to
1543 # Don't support the #foo syntax in the push URL to declare branch to
1541 # push.
1544 # push.
1542 if u.fragment:
1545 if u.fragment:
1543 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1546 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1544 'ignoring)\n') % path.name)
1547 'ignoring)\n') % path.name)
1545 u.fragment = None
1548 u.fragment = None
1546
1549
1547 return str(u)
1550 return str(u)
1548
1551
1549 @pathsuboption('pushrev', 'pushrev')
1552 @pathsuboption('pushrev', 'pushrev')
1550 def pushrevpathoption(ui, path, value):
1553 def pushrevpathoption(ui, path, value):
1551 return value
1554 return value
1552
1555
1553 class path(object):
1556 class path(object):
1554 """Represents an individual path and its configuration."""
1557 """Represents an individual path and its configuration."""
1555
1558
1556 def __init__(self, ui, name, rawloc=None, suboptions=None):
1559 def __init__(self, ui, name, rawloc=None, suboptions=None):
1557 """Construct a path from its config options.
1560 """Construct a path from its config options.
1558
1561
1559 ``ui`` is the ``ui`` instance the path is coming from.
1562 ``ui`` is the ``ui`` instance the path is coming from.
1560 ``name`` is the symbolic name of the path.
1563 ``name`` is the symbolic name of the path.
1561 ``rawloc`` is the raw location, as defined in the config.
1564 ``rawloc`` is the raw location, as defined in the config.
1562 ``pushloc`` is the raw locations pushes should be made to.
1565 ``pushloc`` is the raw locations pushes should be made to.
1563
1566
1564 If ``name`` is not defined, we require that the location be a) a local
1567 If ``name`` is not defined, we require that the location be a) a local
1565 filesystem path with a .hg directory or b) a URL. If not,
1568 filesystem path with a .hg directory or b) a URL. If not,
1566 ``ValueError`` is raised.
1569 ``ValueError`` is raised.
1567 """
1570 """
1568 if not rawloc:
1571 if not rawloc:
1569 raise ValueError('rawloc must be defined')
1572 raise ValueError('rawloc must be defined')
1570
1573
1571 # Locations may define branches via syntax <base>#<branch>.
1574 # Locations may define branches via syntax <base>#<branch>.
1572 u = util.url(rawloc)
1575 u = util.url(rawloc)
1573 branch = None
1576 branch = None
1574 if u.fragment:
1577 if u.fragment:
1575 branch = u.fragment
1578 branch = u.fragment
1576 u.fragment = None
1579 u.fragment = None
1577
1580
1578 self.url = u
1581 self.url = u
1579 self.branch = branch
1582 self.branch = branch
1580
1583
1581 self.name = name
1584 self.name = name
1582 self.rawloc = rawloc
1585 self.rawloc = rawloc
1583 self.loc = '%s' % u
1586 self.loc = '%s' % u
1584
1587
1585 # When given a raw location but not a symbolic name, validate the
1588 # When given a raw location but not a symbolic name, validate the
1586 # location is valid.
1589 # location is valid.
1587 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1590 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1588 raise ValueError('location is not a URL or path to a local '
1591 raise ValueError('location is not a URL or path to a local '
1589 'repo: %s' % rawloc)
1592 'repo: %s' % rawloc)
1590
1593
1591 suboptions = suboptions or {}
1594 suboptions = suboptions or {}
1592
1595
1593 # Now process the sub-options. If a sub-option is registered, its
1596 # Now process the sub-options. If a sub-option is registered, its
1594 # attribute will always be present. The value will be None if there
1597 # attribute will always be present. The value will be None if there
1595 # was no valid sub-option.
1598 # was no valid sub-option.
1596 for suboption, (attr, func) in _pathsuboptions.iteritems():
1599 for suboption, (attr, func) in _pathsuboptions.iteritems():
1597 if suboption not in suboptions:
1600 if suboption not in suboptions:
1598 setattr(self, attr, None)
1601 setattr(self, attr, None)
1599 continue
1602 continue
1600
1603
1601 value = func(ui, self, suboptions[suboption])
1604 value = func(ui, self, suboptions[suboption])
1602 setattr(self, attr, value)
1605 setattr(self, attr, value)
1603
1606
1604 def _isvalidlocalpath(self, path):
1607 def _isvalidlocalpath(self, path):
1605 """Returns True if the given path is a potentially valid repository.
1608 """Returns True if the given path is a potentially valid repository.
1606 This is its own function so that extensions can change the definition of
1609 This is its own function so that extensions can change the definition of
1607 'valid' in this case (like when pulling from a git repo into a hg
1610 'valid' in this case (like when pulling from a git repo into a hg
1608 one)."""
1611 one)."""
1609 return os.path.isdir(os.path.join(path, '.hg'))
1612 return os.path.isdir(os.path.join(path, '.hg'))
1610
1613
1611 @property
1614 @property
1612 def suboptions(self):
1615 def suboptions(self):
1613 """Return sub-options and their values for this path.
1616 """Return sub-options and their values for this path.
1614
1617
1615 This is intended to be used for presentation purposes.
1618 This is intended to be used for presentation purposes.
1616 """
1619 """
1617 d = {}
1620 d = {}
1618 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1621 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1619 value = getattr(self, attr)
1622 value = getattr(self, attr)
1620 if value is not None:
1623 if value is not None:
1621 d[subopt] = value
1624 d[subopt] = value
1622 return d
1625 return d
1623
1626
1624 # we instantiate one globally shared progress bar to avoid
1627 # we instantiate one globally shared progress bar to avoid
1625 # competing progress bars when multiple UI objects get created
1628 # competing progress bars when multiple UI objects get created
1626 _progresssingleton = None
1629 _progresssingleton = None
1627
1630
1628 def getprogbar(ui):
1631 def getprogbar(ui):
1629 global _progresssingleton
1632 global _progresssingleton
1630 if _progresssingleton is None:
1633 if _progresssingleton is None:
1631 # passing 'ui' object to the singleton is fishy,
1634 # passing 'ui' object to the singleton is fishy,
1632 # this is how the extension used to work but feel free to rework it.
1635 # this is how the extension used to work but feel free to rework it.
1633 _progresssingleton = progress.progbar(ui)
1636 _progresssingleton = progress.progbar(ui)
1634 return _progresssingleton
1637 return _progresssingleton
General Comments 0
You need to be logged in to leave comments. Login now