##// END OF EJS Templates
registrar: replace "cmdtype" with an intent-based mechanism (API)...
Gregory Szorc -
r37734:dfc51a48 default
parent child Browse files
Show More
@@ -1,5652 +1,5667 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 logcmdutil,
44 logcmdutil,
45 merge as mergemod,
45 merge as mergemod,
46 obsolete,
46 obsolete,
47 obsutil,
47 obsutil,
48 patch,
48 patch,
49 phases,
49 phases,
50 pycompat,
50 pycompat,
51 rcutil,
51 rcutil,
52 registrar,
52 registrar,
53 revsetlang,
53 revsetlang,
54 rewriteutil,
54 rewriteutil,
55 scmutil,
55 scmutil,
56 server,
56 server,
57 streamclone,
57 streamclone,
58 tags as tagsmod,
58 tags as tagsmod,
59 templatekw,
59 templatekw,
60 ui as uimod,
60 ui as uimod,
61 util,
61 util,
62 wireprotoserver,
62 wireprotoserver,
63 )
63 )
64 from .utils import (
64 from .utils import (
65 dateutil,
65 dateutil,
66 procutil,
66 procutil,
67 stringutil,
67 stringutil,
68 )
68 )
69
69
70 release = lockmod.release
70 release = lockmod.release
71
71
72 table = {}
72 table = {}
73 table.update(debugcommandsmod.command._table)
73 table.update(debugcommandsmod.command._table)
74
74
75 command = registrar.command(table)
75 command = registrar.command(table)
76 readonly = registrar.command.readonly
76 INTENT_READONLY = registrar.INTENT_READONLY
77
77
78 # common command options
78 # common command options
79
79
80 globalopts = [
80 globalopts = [
81 ('R', 'repository', '',
81 ('R', 'repository', '',
82 _('repository root directory or name of overlay bundle file'),
82 _('repository root directory or name of overlay bundle file'),
83 _('REPO')),
83 _('REPO')),
84 ('', 'cwd', '',
84 ('', 'cwd', '',
85 _('change working directory'), _('DIR')),
85 _('change working directory'), _('DIR')),
86 ('y', 'noninteractive', None,
86 ('y', 'noninteractive', None,
87 _('do not prompt, automatically pick the first choice for all prompts')),
87 _('do not prompt, automatically pick the first choice for all prompts')),
88 ('q', 'quiet', None, _('suppress output')),
88 ('q', 'quiet', None, _('suppress output')),
89 ('v', 'verbose', None, _('enable additional output')),
89 ('v', 'verbose', None, _('enable additional output')),
90 ('', 'color', '',
90 ('', 'color', '',
91 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
91 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
92 # and should not be translated
92 # and should not be translated
93 _("when to colorize (boolean, always, auto, never, or debug)"),
93 _("when to colorize (boolean, always, auto, never, or debug)"),
94 _('TYPE')),
94 _('TYPE')),
95 ('', 'config', [],
95 ('', 'config', [],
96 _('set/override config option (use \'section.name=value\')'),
96 _('set/override config option (use \'section.name=value\')'),
97 _('CONFIG')),
97 _('CONFIG')),
98 ('', 'debug', None, _('enable debugging output')),
98 ('', 'debug', None, _('enable debugging output')),
99 ('', 'debugger', None, _('start debugger')),
99 ('', 'debugger', None, _('start debugger')),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
101 _('ENCODE')),
101 _('ENCODE')),
102 ('', 'encodingmode', encoding.encodingmode,
102 ('', 'encodingmode', encoding.encodingmode,
103 _('set the charset encoding mode'), _('MODE')),
103 _('set the charset encoding mode'), _('MODE')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
105 ('', 'time', None, _('time how long the command takes')),
105 ('', 'time', None, _('time how long the command takes')),
106 ('', 'profile', None, _('print command execution profile')),
106 ('', 'profile', None, _('print command execution profile')),
107 ('', 'version', None, _('output version information and exit')),
107 ('', 'version', None, _('output version information and exit')),
108 ('h', 'help', None, _('display help and exit')),
108 ('h', 'help', None, _('display help and exit')),
109 ('', 'hidden', False, _('consider hidden changesets')),
109 ('', 'hidden', False, _('consider hidden changesets')),
110 ('', 'pager', 'auto',
110 ('', 'pager', 'auto',
111 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
111 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
112 ]
112 ]
113
113
114 dryrunopts = cmdutil.dryrunopts
114 dryrunopts = cmdutil.dryrunopts
115 remoteopts = cmdutil.remoteopts
115 remoteopts = cmdutil.remoteopts
116 walkopts = cmdutil.walkopts
116 walkopts = cmdutil.walkopts
117 commitopts = cmdutil.commitopts
117 commitopts = cmdutil.commitopts
118 commitopts2 = cmdutil.commitopts2
118 commitopts2 = cmdutil.commitopts2
119 formatteropts = cmdutil.formatteropts
119 formatteropts = cmdutil.formatteropts
120 templateopts = cmdutil.templateopts
120 templateopts = cmdutil.templateopts
121 logopts = cmdutil.logopts
121 logopts = cmdutil.logopts
122 diffopts = cmdutil.diffopts
122 diffopts = cmdutil.diffopts
123 diffwsopts = cmdutil.diffwsopts
123 diffwsopts = cmdutil.diffwsopts
124 diffopts2 = cmdutil.diffopts2
124 diffopts2 = cmdutil.diffopts2
125 mergetoolopts = cmdutil.mergetoolopts
125 mergetoolopts = cmdutil.mergetoolopts
126 similarityopts = cmdutil.similarityopts
126 similarityopts = cmdutil.similarityopts
127 subrepoopts = cmdutil.subrepoopts
127 subrepoopts = cmdutil.subrepoopts
128 debugrevlogopts = cmdutil.debugrevlogopts
128 debugrevlogopts = cmdutil.debugrevlogopts
129
129
130 # Commands start here, listed alphabetically
130 # Commands start here, listed alphabetically
131
131
132 @command('^add',
132 @command('^add',
133 walkopts + subrepoopts + dryrunopts,
133 walkopts + subrepoopts + dryrunopts,
134 _('[OPTION]... [FILE]...'),
134 _('[OPTION]... [FILE]...'),
135 inferrepo=True)
135 inferrepo=True)
136 def add(ui, repo, *pats, **opts):
136 def add(ui, repo, *pats, **opts):
137 """add the specified files on the next commit
137 """add the specified files on the next commit
138
138
139 Schedule files to be version controlled and added to the
139 Schedule files to be version controlled and added to the
140 repository.
140 repository.
141
141
142 The files will be added to the repository at the next commit. To
142 The files will be added to the repository at the next commit. To
143 undo an add before that, see :hg:`forget`.
143 undo an add before that, see :hg:`forget`.
144
144
145 If no names are given, add all files to the repository (except
145 If no names are given, add all files to the repository (except
146 files matching ``.hgignore``).
146 files matching ``.hgignore``).
147
147
148 .. container:: verbose
148 .. container:: verbose
149
149
150 Examples:
150 Examples:
151
151
152 - New (unknown) files are added
152 - New (unknown) files are added
153 automatically by :hg:`add`::
153 automatically by :hg:`add`::
154
154
155 $ ls
155 $ ls
156 foo.c
156 foo.c
157 $ hg status
157 $ hg status
158 ? foo.c
158 ? foo.c
159 $ hg add
159 $ hg add
160 adding foo.c
160 adding foo.c
161 $ hg status
161 $ hg status
162 A foo.c
162 A foo.c
163
163
164 - Specific files to be added can be specified::
164 - Specific files to be added can be specified::
165
165
166 $ ls
166 $ ls
167 bar.c foo.c
167 bar.c foo.c
168 $ hg status
168 $ hg status
169 ? bar.c
169 ? bar.c
170 ? foo.c
170 ? foo.c
171 $ hg add bar.c
171 $ hg add bar.c
172 $ hg status
172 $ hg status
173 A bar.c
173 A bar.c
174 ? foo.c
174 ? foo.c
175
175
176 Returns 0 if all files are successfully added.
176 Returns 0 if all files are successfully added.
177 """
177 """
178
178
179 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
179 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
180 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
180 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
181 return rejected and 1 or 0
181 return rejected and 1 or 0
182
182
183 @command('addremove',
183 @command('addremove',
184 similarityopts + subrepoopts + walkopts + dryrunopts,
184 similarityopts + subrepoopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
185 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
186 inferrepo=True)
187 def addremove(ui, repo, *pats, **opts):
187 def addremove(ui, repo, *pats, **opts):
188 """add all new files, delete all missing files
188 """add all new files, delete all missing files
189
189
190 Add all new files and remove all missing files from the
190 Add all new files and remove all missing files from the
191 repository.
191 repository.
192
192
193 Unless names are given, new files are ignored if they match any of
193 Unless names are given, new files are ignored if they match any of
194 the patterns in ``.hgignore``. As with add, these changes take
194 the patterns in ``.hgignore``. As with add, these changes take
195 effect at the next commit.
195 effect at the next commit.
196
196
197 Use the -s/--similarity option to detect renamed files. This
197 Use the -s/--similarity option to detect renamed files. This
198 option takes a percentage between 0 (disabled) and 100 (files must
198 option takes a percentage between 0 (disabled) and 100 (files must
199 be identical) as its parameter. With a parameter greater than 0,
199 be identical) as its parameter. With a parameter greater than 0,
200 this compares every removed file with every added file and records
200 this compares every removed file with every added file and records
201 those similar enough as renames. Detecting renamed files this way
201 those similar enough as renames. Detecting renamed files this way
202 can be expensive. After using this option, :hg:`status -C` can be
202 can be expensive. After using this option, :hg:`status -C` can be
203 used to check which files were identified as moved or renamed. If
203 used to check which files were identified as moved or renamed. If
204 not specified, -s/--similarity defaults to 100 and only renames of
204 not specified, -s/--similarity defaults to 100 and only renames of
205 identical files are detected.
205 identical files are detected.
206
206
207 .. container:: verbose
207 .. container:: verbose
208
208
209 Examples:
209 Examples:
210
210
211 - A number of files (bar.c and foo.c) are new,
211 - A number of files (bar.c and foo.c) are new,
212 while foobar.c has been removed (without using :hg:`remove`)
212 while foobar.c has been removed (without using :hg:`remove`)
213 from the repository::
213 from the repository::
214
214
215 $ ls
215 $ ls
216 bar.c foo.c
216 bar.c foo.c
217 $ hg status
217 $ hg status
218 ! foobar.c
218 ! foobar.c
219 ? bar.c
219 ? bar.c
220 ? foo.c
220 ? foo.c
221 $ hg addremove
221 $ hg addremove
222 adding bar.c
222 adding bar.c
223 adding foo.c
223 adding foo.c
224 removing foobar.c
224 removing foobar.c
225 $ hg status
225 $ hg status
226 A bar.c
226 A bar.c
227 A foo.c
227 A foo.c
228 R foobar.c
228 R foobar.c
229
229
230 - A file foobar.c was moved to foo.c without using :hg:`rename`.
230 - A file foobar.c was moved to foo.c without using :hg:`rename`.
231 Afterwards, it was edited slightly::
231 Afterwards, it was edited slightly::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ! foobar.c
236 ! foobar.c
237 ? foo.c
237 ? foo.c
238 $ hg addremove --similarity 90
238 $ hg addremove --similarity 90
239 removing foobar.c
239 removing foobar.c
240 adding foo.c
240 adding foo.c
241 recording removal of foobar.c as rename to foo.c (94% similar)
241 recording removal of foobar.c as rename to foo.c (94% similar)
242 $ hg status -C
242 $ hg status -C
243 A foo.c
243 A foo.c
244 foobar.c
244 foobar.c
245 R foobar.c
245 R foobar.c
246
246
247 Returns 0 if all files are successfully added.
247 Returns 0 if all files are successfully added.
248 """
248 """
249 opts = pycompat.byteskwargs(opts)
249 opts = pycompat.byteskwargs(opts)
250 if not opts.get('similarity'):
250 if not opts.get('similarity'):
251 opts['similarity'] = '100'
251 opts['similarity'] = '100'
252 matcher = scmutil.match(repo[None], pats, opts)
252 matcher = scmutil.match(repo[None], pats, opts)
253 return scmutil.addremove(repo, matcher, "", opts)
253 return scmutil.addremove(repo, matcher, "", opts)
254
254
255 @command('^annotate|blame',
255 @command('^annotate|blame',
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 ('', 'follow', None,
257 ('', 'follow', None,
258 _('follow copies/renames and list the filename (DEPRECATED)')),
258 _('follow copies/renames and list the filename (DEPRECATED)')),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('a', 'text', None, _('treat all files as text')),
260 ('a', 'text', None, _('treat all files as text')),
261 ('u', 'user', None, _('list the author (long with -v)')),
261 ('u', 'user', None, _('list the author (long with -v)')),
262 ('f', 'file', None, _('list the filename')),
262 ('f', 'file', None, _('list the filename')),
263 ('d', 'date', None, _('list the date (short with -q)')),
263 ('d', 'date', None, _('list the date (short with -q)')),
264 ('n', 'number', None, _('list the revision number (default)')),
264 ('n', 'number', None, _('list the revision number (default)')),
265 ('c', 'changeset', None, _('list the changeset')),
265 ('c', 'changeset', None, _('list the changeset')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ] + diffwsopts + walkopts + formatteropts,
268 ] + diffwsopts + walkopts + formatteropts,
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 inferrepo=True)
270 inferrepo=True)
271 def annotate(ui, repo, *pats, **opts):
271 def annotate(ui, repo, *pats, **opts):
272 """show changeset information by line for each file
272 """show changeset information by line for each file
273
273
274 List changes in files, showing the revision id responsible for
274 List changes in files, showing the revision id responsible for
275 each line.
275 each line.
276
276
277 This command is useful for discovering when a change was made and
277 This command is useful for discovering when a change was made and
278 by whom.
278 by whom.
279
279
280 If you include --file, --user, or --date, the revision number is
280 If you include --file, --user, or --date, the revision number is
281 suppressed unless you also include --number.
281 suppressed unless you also include --number.
282
282
283 Without the -a/--text option, annotate will avoid processing files
283 Without the -a/--text option, annotate will avoid processing files
284 it detects as binary. With -a, annotate will annotate the file
284 it detects as binary. With -a, annotate will annotate the file
285 anyway, although the results will probably be neither useful
285 anyway, although the results will probably be neither useful
286 nor desirable.
286 nor desirable.
287
287
288 Returns 0 on success.
288 Returns 0 on success.
289 """
289 """
290 opts = pycompat.byteskwargs(opts)
290 opts = pycompat.byteskwargs(opts)
291 if not pats:
291 if not pats:
292 raise error.Abort(_('at least one filename or pattern is required'))
292 raise error.Abort(_('at least one filename or pattern is required'))
293
293
294 if opts.get('follow'):
294 if opts.get('follow'):
295 # --follow is deprecated and now just an alias for -f/--file
295 # --follow is deprecated and now just an alias for -f/--file
296 # to mimic the behavior of Mercurial before version 1.5
296 # to mimic the behavior of Mercurial before version 1.5
297 opts['file'] = True
297 opts['file'] = True
298
298
299 rev = opts.get('rev')
299 rev = opts.get('rev')
300 if rev:
300 if rev:
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
302 ctx = scmutil.revsingle(repo, rev)
302 ctx = scmutil.revsingle(repo, rev)
303
303
304 rootfm = ui.formatter('annotate', opts)
304 rootfm = ui.formatter('annotate', opts)
305 if ui.quiet:
305 if ui.quiet:
306 datefunc = dateutil.shortdate
306 datefunc = dateutil.shortdate
307 else:
307 else:
308 datefunc = dateutil.datestr
308 datefunc = dateutil.datestr
309 if ctx.rev() is None:
309 if ctx.rev() is None:
310 def hexfn(node):
310 def hexfn(node):
311 if node is None:
311 if node is None:
312 return None
312 return None
313 else:
313 else:
314 return rootfm.hexfunc(node)
314 return rootfm.hexfunc(node)
315 if opts.get('changeset'):
315 if opts.get('changeset'):
316 # omit "+" suffix which is appended to node hex
316 # omit "+" suffix which is appended to node hex
317 def formatrev(rev):
317 def formatrev(rev):
318 if rev is None:
318 if rev is None:
319 return '%d' % ctx.p1().rev()
319 return '%d' % ctx.p1().rev()
320 else:
320 else:
321 return '%d' % rev
321 return '%d' % rev
322 else:
322 else:
323 def formatrev(rev):
323 def formatrev(rev):
324 if rev is None:
324 if rev is None:
325 return '%d+' % ctx.p1().rev()
325 return '%d+' % ctx.p1().rev()
326 else:
326 else:
327 return '%d ' % rev
327 return '%d ' % rev
328 def formathex(hex):
328 def formathex(hex):
329 if hex is None:
329 if hex is None:
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
331 else:
331 else:
332 return '%s ' % hex
332 return '%s ' % hex
333 else:
333 else:
334 hexfn = rootfm.hexfunc
334 hexfn = rootfm.hexfunc
335 formatrev = formathex = pycompat.bytestr
335 formatrev = formathex = pycompat.bytestr
336
336
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
343 ]
343 ]
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
345
345
346 if (not opts.get('user') and not opts.get('changeset')
346 if (not opts.get('user') and not opts.get('changeset')
347 and not opts.get('date') and not opts.get('file')):
347 and not opts.get('date') and not opts.get('file')):
348 opts['number'] = True
348 opts['number'] = True
349
349
350 linenumber = opts.get('line_number') is not None
350 linenumber = opts.get('line_number') is not None
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
353
353
354 ui.pager('annotate')
354 ui.pager('annotate')
355
355
356 if rootfm.isplain():
356 if rootfm.isplain():
357 def makefunc(get, fmt):
357 def makefunc(get, fmt):
358 return lambda x: fmt(get(x))
358 return lambda x: fmt(get(x))
359 else:
359 else:
360 def makefunc(get, fmt):
360 def makefunc(get, fmt):
361 return get
361 return get
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
363 if opts.get(op)]
363 if opts.get(op)]
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
366 if opts.get(op))
366 if opts.get(op))
367
367
368 def bad(x, y):
368 def bad(x, y):
369 raise error.Abort("%s: %s" % (x, y))
369 raise error.Abort("%s: %s" % (x, y))
370
370
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
372
372
373 follow = not opts.get('no_follow')
373 follow = not opts.get('no_follow')
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
375 whitespace=True)
375 whitespace=True)
376 skiprevs = opts.get('skip')
376 skiprevs = opts.get('skip')
377 if skiprevs:
377 if skiprevs:
378 skiprevs = scmutil.revrange(repo, skiprevs)
378 skiprevs = scmutil.revrange(repo, skiprevs)
379
379
380 for abs in ctx.walk(m):
380 for abs in ctx.walk(m):
381 fctx = ctx[abs]
381 fctx = ctx[abs]
382 rootfm.startitem()
382 rootfm.startitem()
383 rootfm.data(abspath=abs, path=m.rel(abs))
383 rootfm.data(abspath=abs, path=m.rel(abs))
384 if not opts.get('text') and fctx.isbinary():
384 if not opts.get('text') and fctx.isbinary():
385 rootfm.plain(_("%s: binary file\n")
385 rootfm.plain(_("%s: binary file\n")
386 % ((pats and m.rel(abs)) or abs))
386 % ((pats and m.rel(abs)) or abs))
387 continue
387 continue
388
388
389 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
389 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
390 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
390 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
391 diffopts=diffopts)
391 diffopts=diffopts)
392 if not lines:
392 if not lines:
393 fm.end()
393 fm.end()
394 continue
394 continue
395 formats = []
395 formats = []
396 pieces = []
396 pieces = []
397
397
398 for f, sep in funcmap:
398 for f, sep in funcmap:
399 l = [f(n) for n in lines]
399 l = [f(n) for n in lines]
400 if fm.isplain():
400 if fm.isplain():
401 sizes = [encoding.colwidth(x) for x in l]
401 sizes = [encoding.colwidth(x) for x in l]
402 ml = max(sizes)
402 ml = max(sizes)
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
404 else:
404 else:
405 formats.append(['%s' for x in l])
405 formats.append(['%s' for x in l])
406 pieces.append(l)
406 pieces.append(l)
407
407
408 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
408 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
409 fm.startitem()
409 fm.startitem()
410 fm.context(fctx=n.fctx)
410 fm.context(fctx=n.fctx)
411 fm.write(fields, "".join(f), *p)
411 fm.write(fields, "".join(f), *p)
412 if n.skip:
412 if n.skip:
413 fmt = "* %s"
413 fmt = "* %s"
414 else:
414 else:
415 fmt = ": %s"
415 fmt = ": %s"
416 fm.write('line', fmt, n.text)
416 fm.write('line', fmt, n.text)
417
417
418 if not lines[-1].text.endswith('\n'):
418 if not lines[-1].text.endswith('\n'):
419 fm.plain('\n')
419 fm.plain('\n')
420 fm.end()
420 fm.end()
421
421
422 rootfm.end()
422 rootfm.end()
423
423
424 @command('archive',
424 @command('archive',
425 [('', 'no-decode', None, _('do not pass files through decoders')),
425 [('', 'no-decode', None, _('do not pass files through decoders')),
426 ('p', 'prefix', '', _('directory prefix for files in archive'),
426 ('p', 'prefix', '', _('directory prefix for files in archive'),
427 _('PREFIX')),
427 _('PREFIX')),
428 ('r', 'rev', '', _('revision to distribute'), _('REV')),
428 ('r', 'rev', '', _('revision to distribute'), _('REV')),
429 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
429 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
430 ] + subrepoopts + walkopts,
430 ] + subrepoopts + walkopts,
431 _('[OPTION]... DEST'))
431 _('[OPTION]... DEST'))
432 def archive(ui, repo, dest, **opts):
432 def archive(ui, repo, dest, **opts):
433 '''create an unversioned archive of a repository revision
433 '''create an unversioned archive of a repository revision
434
434
435 By default, the revision used is the parent of the working
435 By default, the revision used is the parent of the working
436 directory; use -r/--rev to specify a different revision.
436 directory; use -r/--rev to specify a different revision.
437
437
438 The archive type is automatically detected based on file
438 The archive type is automatically detected based on file
439 extension (to override, use -t/--type).
439 extension (to override, use -t/--type).
440
440
441 .. container:: verbose
441 .. container:: verbose
442
442
443 Examples:
443 Examples:
444
444
445 - create a zip file containing the 1.0 release::
445 - create a zip file containing the 1.0 release::
446
446
447 hg archive -r 1.0 project-1.0.zip
447 hg archive -r 1.0 project-1.0.zip
448
448
449 - create a tarball excluding .hg files::
449 - create a tarball excluding .hg files::
450
450
451 hg archive project.tar.gz -X ".hg*"
451 hg archive project.tar.gz -X ".hg*"
452
452
453 Valid types are:
453 Valid types are:
454
454
455 :``files``: a directory full of files (default)
455 :``files``: a directory full of files (default)
456 :``tar``: tar archive, uncompressed
456 :``tar``: tar archive, uncompressed
457 :``tbz2``: tar archive, compressed using bzip2
457 :``tbz2``: tar archive, compressed using bzip2
458 :``tgz``: tar archive, compressed using gzip
458 :``tgz``: tar archive, compressed using gzip
459 :``uzip``: zip archive, uncompressed
459 :``uzip``: zip archive, uncompressed
460 :``zip``: zip archive, compressed using deflate
460 :``zip``: zip archive, compressed using deflate
461
461
462 The exact name of the destination archive or directory is given
462 The exact name of the destination archive or directory is given
463 using a format string; see :hg:`help export` for details.
463 using a format string; see :hg:`help export` for details.
464
464
465 Each member added to an archive file has a directory prefix
465 Each member added to an archive file has a directory prefix
466 prepended. Use -p/--prefix to specify a format string for the
466 prepended. Use -p/--prefix to specify a format string for the
467 prefix. The default is the basename of the archive, with suffixes
467 prefix. The default is the basename of the archive, with suffixes
468 removed.
468 removed.
469
469
470 Returns 0 on success.
470 Returns 0 on success.
471 '''
471 '''
472
472
473 opts = pycompat.byteskwargs(opts)
473 opts = pycompat.byteskwargs(opts)
474 rev = opts.get('rev')
474 rev = opts.get('rev')
475 if rev:
475 if rev:
476 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
476 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
477 ctx = scmutil.revsingle(repo, rev)
477 ctx = scmutil.revsingle(repo, rev)
478 if not ctx:
478 if not ctx:
479 raise error.Abort(_('no working directory: please specify a revision'))
479 raise error.Abort(_('no working directory: please specify a revision'))
480 node = ctx.node()
480 node = ctx.node()
481 dest = cmdutil.makefilename(ctx, dest)
481 dest = cmdutil.makefilename(ctx, dest)
482 if os.path.realpath(dest) == repo.root:
482 if os.path.realpath(dest) == repo.root:
483 raise error.Abort(_('repository root cannot be destination'))
483 raise error.Abort(_('repository root cannot be destination'))
484
484
485 kind = opts.get('type') or archival.guesskind(dest) or 'files'
485 kind = opts.get('type') or archival.guesskind(dest) or 'files'
486 prefix = opts.get('prefix')
486 prefix = opts.get('prefix')
487
487
488 if dest == '-':
488 if dest == '-':
489 if kind == 'files':
489 if kind == 'files':
490 raise error.Abort(_('cannot archive plain files to stdout'))
490 raise error.Abort(_('cannot archive plain files to stdout'))
491 dest = cmdutil.makefileobj(ctx, dest)
491 dest = cmdutil.makefileobj(ctx, dest)
492 if not prefix:
492 if not prefix:
493 prefix = os.path.basename(repo.root) + '-%h'
493 prefix = os.path.basename(repo.root) + '-%h'
494
494
495 prefix = cmdutil.makefilename(ctx, prefix)
495 prefix = cmdutil.makefilename(ctx, prefix)
496 match = scmutil.match(ctx, [], opts)
496 match = scmutil.match(ctx, [], opts)
497 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
497 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
498 match, prefix, subrepos=opts.get('subrepos'))
498 match, prefix, subrepos=opts.get('subrepos'))
499
499
500 @command('backout',
500 @command('backout',
501 [('', 'merge', None, _('merge with old dirstate parent after backout')),
501 [('', 'merge', None, _('merge with old dirstate parent after backout')),
502 ('', 'commit', None,
502 ('', 'commit', None,
503 _('commit if no conflicts were encountered (DEPRECATED)')),
503 _('commit if no conflicts were encountered (DEPRECATED)')),
504 ('', 'no-commit', None, _('do not commit')),
504 ('', 'no-commit', None, _('do not commit')),
505 ('', 'parent', '',
505 ('', 'parent', '',
506 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
506 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
507 ('r', 'rev', '', _('revision to backout'), _('REV')),
507 ('r', 'rev', '', _('revision to backout'), _('REV')),
508 ('e', 'edit', False, _('invoke editor on commit messages')),
508 ('e', 'edit', False, _('invoke editor on commit messages')),
509 ] + mergetoolopts + walkopts + commitopts + commitopts2,
509 ] + mergetoolopts + walkopts + commitopts + commitopts2,
510 _('[OPTION]... [-r] REV'))
510 _('[OPTION]... [-r] REV'))
511 def backout(ui, repo, node=None, rev=None, **opts):
511 def backout(ui, repo, node=None, rev=None, **opts):
512 '''reverse effect of earlier changeset
512 '''reverse effect of earlier changeset
513
513
514 Prepare a new changeset with the effect of REV undone in the
514 Prepare a new changeset with the effect of REV undone in the
515 current working directory. If no conflicts were encountered,
515 current working directory. If no conflicts were encountered,
516 it will be committed immediately.
516 it will be committed immediately.
517
517
518 If REV is the parent of the working directory, then this new changeset
518 If REV is the parent of the working directory, then this new changeset
519 is committed automatically (unless --no-commit is specified).
519 is committed automatically (unless --no-commit is specified).
520
520
521 .. note::
521 .. note::
522
522
523 :hg:`backout` cannot be used to fix either an unwanted or
523 :hg:`backout` cannot be used to fix either an unwanted or
524 incorrect merge.
524 incorrect merge.
525
525
526 .. container:: verbose
526 .. container:: verbose
527
527
528 Examples:
528 Examples:
529
529
530 - Reverse the effect of the parent of the working directory.
530 - Reverse the effect of the parent of the working directory.
531 This backout will be committed immediately::
531 This backout will be committed immediately::
532
532
533 hg backout -r .
533 hg backout -r .
534
534
535 - Reverse the effect of previous bad revision 23::
535 - Reverse the effect of previous bad revision 23::
536
536
537 hg backout -r 23
537 hg backout -r 23
538
538
539 - Reverse the effect of previous bad revision 23 and
539 - Reverse the effect of previous bad revision 23 and
540 leave changes uncommitted::
540 leave changes uncommitted::
541
541
542 hg backout -r 23 --no-commit
542 hg backout -r 23 --no-commit
543 hg commit -m "Backout revision 23"
543 hg commit -m "Backout revision 23"
544
544
545 By default, the pending changeset will have one parent,
545 By default, the pending changeset will have one parent,
546 maintaining a linear history. With --merge, the pending
546 maintaining a linear history. With --merge, the pending
547 changeset will instead have two parents: the old parent of the
547 changeset will instead have two parents: the old parent of the
548 working directory and a new child of REV that simply undoes REV.
548 working directory and a new child of REV that simply undoes REV.
549
549
550 Before version 1.7, the behavior without --merge was equivalent
550 Before version 1.7, the behavior without --merge was equivalent
551 to specifying --merge followed by :hg:`update --clean .` to
551 to specifying --merge followed by :hg:`update --clean .` to
552 cancel the merge and leave the child of REV as a head to be
552 cancel the merge and leave the child of REV as a head to be
553 merged separately.
553 merged separately.
554
554
555 See :hg:`help dates` for a list of formats valid for -d/--date.
555 See :hg:`help dates` for a list of formats valid for -d/--date.
556
556
557 See :hg:`help revert` for a way to restore files to the state
557 See :hg:`help revert` for a way to restore files to the state
558 of another revision.
558 of another revision.
559
559
560 Returns 0 on success, 1 if nothing to backout or there are unresolved
560 Returns 0 on success, 1 if nothing to backout or there are unresolved
561 files.
561 files.
562 '''
562 '''
563 wlock = lock = None
563 wlock = lock = None
564 try:
564 try:
565 wlock = repo.wlock()
565 wlock = repo.wlock()
566 lock = repo.lock()
566 lock = repo.lock()
567 return _dobackout(ui, repo, node, rev, **opts)
567 return _dobackout(ui, repo, node, rev, **opts)
568 finally:
568 finally:
569 release(lock, wlock)
569 release(lock, wlock)
570
570
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
572 opts = pycompat.byteskwargs(opts)
572 opts = pycompat.byteskwargs(opts)
573 if opts.get('commit') and opts.get('no_commit'):
573 if opts.get('commit') and opts.get('no_commit'):
574 raise error.Abort(_("cannot use --commit with --no-commit"))
574 raise error.Abort(_("cannot use --commit with --no-commit"))
575 if opts.get('merge') and opts.get('no_commit'):
575 if opts.get('merge') and opts.get('no_commit'):
576 raise error.Abort(_("cannot use --merge with --no-commit"))
576 raise error.Abort(_("cannot use --merge with --no-commit"))
577
577
578 if rev and node:
578 if rev and node:
579 raise error.Abort(_("please specify just one revision"))
579 raise error.Abort(_("please specify just one revision"))
580
580
581 if not rev:
581 if not rev:
582 rev = node
582 rev = node
583
583
584 if not rev:
584 if not rev:
585 raise error.Abort(_("please specify a revision to backout"))
585 raise error.Abort(_("please specify a revision to backout"))
586
586
587 date = opts.get('date')
587 date = opts.get('date')
588 if date:
588 if date:
589 opts['date'] = dateutil.parsedate(date)
589 opts['date'] = dateutil.parsedate(date)
590
590
591 cmdutil.checkunfinished(repo)
591 cmdutil.checkunfinished(repo)
592 cmdutil.bailifchanged(repo)
592 cmdutil.bailifchanged(repo)
593 node = scmutil.revsingle(repo, rev).node()
593 node = scmutil.revsingle(repo, rev).node()
594
594
595 op1, op2 = repo.dirstate.parents()
595 op1, op2 = repo.dirstate.parents()
596 if not repo.changelog.isancestor(node, op1):
596 if not repo.changelog.isancestor(node, op1):
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
598
598
599 p1, p2 = repo.changelog.parents(node)
599 p1, p2 = repo.changelog.parents(node)
600 if p1 == nullid:
600 if p1 == nullid:
601 raise error.Abort(_('cannot backout a change with no parents'))
601 raise error.Abort(_('cannot backout a change with no parents'))
602 if p2 != nullid:
602 if p2 != nullid:
603 if not opts.get('parent'):
603 if not opts.get('parent'):
604 raise error.Abort(_('cannot backout a merge changeset'))
604 raise error.Abort(_('cannot backout a merge changeset'))
605 p = repo.lookup(opts['parent'])
605 p = repo.lookup(opts['parent'])
606 if p not in (p1, p2):
606 if p not in (p1, p2):
607 raise error.Abort(_('%s is not a parent of %s') %
607 raise error.Abort(_('%s is not a parent of %s') %
608 (short(p), short(node)))
608 (short(p), short(node)))
609 parent = p
609 parent = p
610 else:
610 else:
611 if opts.get('parent'):
611 if opts.get('parent'):
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
613 parent = p1
613 parent = p1
614
614
615 # the backout should appear on the same branch
615 # the backout should appear on the same branch
616 branch = repo.dirstate.branch()
616 branch = repo.dirstate.branch()
617 bheads = repo.branchheads(branch)
617 bheads = repo.branchheads(branch)
618 rctx = scmutil.revsingle(repo, hex(parent))
618 rctx = scmutil.revsingle(repo, hex(parent))
619 if not opts.get('merge') and op1 != node:
619 if not opts.get('merge') and op1 != node:
620 dsguard = dirstateguard.dirstateguard(repo, 'backout')
620 dsguard = dirstateguard.dirstateguard(repo, 'backout')
621 try:
621 try:
622 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
622 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
623 'backout')
623 'backout')
624 stats = mergemod.update(repo, parent, True, True, node, False)
624 stats = mergemod.update(repo, parent, True, True, node, False)
625 repo.setparents(op1, op2)
625 repo.setparents(op1, op2)
626 dsguard.close()
626 dsguard.close()
627 hg._showstats(repo, stats)
627 hg._showstats(repo, stats)
628 if stats.unresolvedcount:
628 if stats.unresolvedcount:
629 repo.ui.status(_("use 'hg resolve' to retry unresolved "
629 repo.ui.status(_("use 'hg resolve' to retry unresolved "
630 "file merges\n"))
630 "file merges\n"))
631 return 1
631 return 1
632 finally:
632 finally:
633 ui.setconfig('ui', 'forcemerge', '', '')
633 ui.setconfig('ui', 'forcemerge', '', '')
634 lockmod.release(dsguard)
634 lockmod.release(dsguard)
635 else:
635 else:
636 hg.clean(repo, node, show_stats=False)
636 hg.clean(repo, node, show_stats=False)
637 repo.dirstate.setbranch(branch)
637 repo.dirstate.setbranch(branch)
638 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
638 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
639
639
640 if opts.get('no_commit'):
640 if opts.get('no_commit'):
641 msg = _("changeset %s backed out, "
641 msg = _("changeset %s backed out, "
642 "don't forget to commit.\n")
642 "don't forget to commit.\n")
643 ui.status(msg % short(node))
643 ui.status(msg % short(node))
644 return 0
644 return 0
645
645
646 def commitfunc(ui, repo, message, match, opts):
646 def commitfunc(ui, repo, message, match, opts):
647 editform = 'backout'
647 editform = 'backout'
648 e = cmdutil.getcommiteditor(editform=editform,
648 e = cmdutil.getcommiteditor(editform=editform,
649 **pycompat.strkwargs(opts))
649 **pycompat.strkwargs(opts))
650 if not message:
650 if not message:
651 # we don't translate commit messages
651 # we don't translate commit messages
652 message = "Backed out changeset %s" % short(node)
652 message = "Backed out changeset %s" % short(node)
653 e = cmdutil.getcommiteditor(edit=True, editform=editform)
653 e = cmdutil.getcommiteditor(edit=True, editform=editform)
654 return repo.commit(message, opts.get('user'), opts.get('date'),
654 return repo.commit(message, opts.get('user'), opts.get('date'),
655 match, editor=e)
655 match, editor=e)
656 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
656 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
657 if not newnode:
657 if not newnode:
658 ui.status(_("nothing changed\n"))
658 ui.status(_("nothing changed\n"))
659 return 1
659 return 1
660 cmdutil.commitstatus(repo, newnode, branch, bheads)
660 cmdutil.commitstatus(repo, newnode, branch, bheads)
661
661
662 def nice(node):
662 def nice(node):
663 return '%d:%s' % (repo.changelog.rev(node), short(node))
663 return '%d:%s' % (repo.changelog.rev(node), short(node))
664 ui.status(_('changeset %s backs out changeset %s\n') %
664 ui.status(_('changeset %s backs out changeset %s\n') %
665 (nice(repo.changelog.tip()), nice(node)))
665 (nice(repo.changelog.tip()), nice(node)))
666 if opts.get('merge') and op1 != node:
666 if opts.get('merge') and op1 != node:
667 hg.clean(repo, op1, show_stats=False)
667 hg.clean(repo, op1, show_stats=False)
668 ui.status(_('merging with changeset %s\n')
668 ui.status(_('merging with changeset %s\n')
669 % nice(repo.changelog.tip()))
669 % nice(repo.changelog.tip()))
670 try:
670 try:
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
672 'backout')
672 'backout')
673 return hg.merge(repo, hex(repo.changelog.tip()))
673 return hg.merge(repo, hex(repo.changelog.tip()))
674 finally:
674 finally:
675 ui.setconfig('ui', 'forcemerge', '', '')
675 ui.setconfig('ui', 'forcemerge', '', '')
676 return 0
676 return 0
677
677
678 @command('bisect',
678 @command('bisect',
679 [('r', 'reset', False, _('reset bisect state')),
679 [('r', 'reset', False, _('reset bisect state')),
680 ('g', 'good', False, _('mark changeset good')),
680 ('g', 'good', False, _('mark changeset good')),
681 ('b', 'bad', False, _('mark changeset bad')),
681 ('b', 'bad', False, _('mark changeset bad')),
682 ('s', 'skip', False, _('skip testing changeset')),
682 ('s', 'skip', False, _('skip testing changeset')),
683 ('e', 'extend', False, _('extend the bisect range')),
683 ('e', 'extend', False, _('extend the bisect range')),
684 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
684 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
685 ('U', 'noupdate', False, _('do not update to target'))],
685 ('U', 'noupdate', False, _('do not update to target'))],
686 _("[-gbsr] [-U] [-c CMD] [REV]"))
686 _("[-gbsr] [-U] [-c CMD] [REV]"))
687 def bisect(ui, repo, rev=None, extra=None, command=None,
687 def bisect(ui, repo, rev=None, extra=None, command=None,
688 reset=None, good=None, bad=None, skip=None, extend=None,
688 reset=None, good=None, bad=None, skip=None, extend=None,
689 noupdate=None):
689 noupdate=None):
690 """subdivision search of changesets
690 """subdivision search of changesets
691
691
692 This command helps to find changesets which introduce problems. To
692 This command helps to find changesets which introduce problems. To
693 use, mark the earliest changeset you know exhibits the problem as
693 use, mark the earliest changeset you know exhibits the problem as
694 bad, then mark the latest changeset which is free from the problem
694 bad, then mark the latest changeset which is free from the problem
695 as good. Bisect will update your working directory to a revision
695 as good. Bisect will update your working directory to a revision
696 for testing (unless the -U/--noupdate option is specified). Once
696 for testing (unless the -U/--noupdate option is specified). Once
697 you have performed tests, mark the working directory as good or
697 you have performed tests, mark the working directory as good or
698 bad, and bisect will either update to another candidate changeset
698 bad, and bisect will either update to another candidate changeset
699 or announce that it has found the bad revision.
699 or announce that it has found the bad revision.
700
700
701 As a shortcut, you can also use the revision argument to mark a
701 As a shortcut, you can also use the revision argument to mark a
702 revision as good or bad without checking it out first.
702 revision as good or bad without checking it out first.
703
703
704 If you supply a command, it will be used for automatic bisection.
704 If you supply a command, it will be used for automatic bisection.
705 The environment variable HG_NODE will contain the ID of the
705 The environment variable HG_NODE will contain the ID of the
706 changeset being tested. The exit status of the command will be
706 changeset being tested. The exit status of the command will be
707 used to mark revisions as good or bad: status 0 means good, 125
707 used to mark revisions as good or bad: status 0 means good, 125
708 means to skip the revision, 127 (command not found) will abort the
708 means to skip the revision, 127 (command not found) will abort the
709 bisection, and any other non-zero exit status means the revision
709 bisection, and any other non-zero exit status means the revision
710 is bad.
710 is bad.
711
711
712 .. container:: verbose
712 .. container:: verbose
713
713
714 Some examples:
714 Some examples:
715
715
716 - start a bisection with known bad revision 34, and good revision 12::
716 - start a bisection with known bad revision 34, and good revision 12::
717
717
718 hg bisect --bad 34
718 hg bisect --bad 34
719 hg bisect --good 12
719 hg bisect --good 12
720
720
721 - advance the current bisection by marking current revision as good or
721 - advance the current bisection by marking current revision as good or
722 bad::
722 bad::
723
723
724 hg bisect --good
724 hg bisect --good
725 hg bisect --bad
725 hg bisect --bad
726
726
727 - mark the current revision, or a known revision, to be skipped (e.g. if
727 - mark the current revision, or a known revision, to be skipped (e.g. if
728 that revision is not usable because of another issue)::
728 that revision is not usable because of another issue)::
729
729
730 hg bisect --skip
730 hg bisect --skip
731 hg bisect --skip 23
731 hg bisect --skip 23
732
732
733 - skip all revisions that do not touch directories ``foo`` or ``bar``::
733 - skip all revisions that do not touch directories ``foo`` or ``bar``::
734
734
735 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
735 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
736
736
737 - forget the current bisection::
737 - forget the current bisection::
738
738
739 hg bisect --reset
739 hg bisect --reset
740
740
741 - use 'make && make tests' to automatically find the first broken
741 - use 'make && make tests' to automatically find the first broken
742 revision::
742 revision::
743
743
744 hg bisect --reset
744 hg bisect --reset
745 hg bisect --bad 34
745 hg bisect --bad 34
746 hg bisect --good 12
746 hg bisect --good 12
747 hg bisect --command "make && make tests"
747 hg bisect --command "make && make tests"
748
748
749 - see all changesets whose states are already known in the current
749 - see all changesets whose states are already known in the current
750 bisection::
750 bisection::
751
751
752 hg log -r "bisect(pruned)"
752 hg log -r "bisect(pruned)"
753
753
754 - see the changeset currently being bisected (especially useful
754 - see the changeset currently being bisected (especially useful
755 if running with -U/--noupdate)::
755 if running with -U/--noupdate)::
756
756
757 hg log -r "bisect(current)"
757 hg log -r "bisect(current)"
758
758
759 - see all changesets that took part in the current bisection::
759 - see all changesets that took part in the current bisection::
760
760
761 hg log -r "bisect(range)"
761 hg log -r "bisect(range)"
762
762
763 - you can even get a nice graph::
763 - you can even get a nice graph::
764
764
765 hg log --graph -r "bisect(range)"
765 hg log --graph -r "bisect(range)"
766
766
767 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
767 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
768
768
769 Returns 0 on success.
769 Returns 0 on success.
770 """
770 """
771 # backward compatibility
771 # backward compatibility
772 if rev in "good bad reset init".split():
772 if rev in "good bad reset init".split():
773 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
773 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
774 cmd, rev, extra = rev, extra, None
774 cmd, rev, extra = rev, extra, None
775 if cmd == "good":
775 if cmd == "good":
776 good = True
776 good = True
777 elif cmd == "bad":
777 elif cmd == "bad":
778 bad = True
778 bad = True
779 else:
779 else:
780 reset = True
780 reset = True
781 elif extra:
781 elif extra:
782 raise error.Abort(_('incompatible arguments'))
782 raise error.Abort(_('incompatible arguments'))
783
783
784 incompatibles = {
784 incompatibles = {
785 '--bad': bad,
785 '--bad': bad,
786 '--command': bool(command),
786 '--command': bool(command),
787 '--extend': extend,
787 '--extend': extend,
788 '--good': good,
788 '--good': good,
789 '--reset': reset,
789 '--reset': reset,
790 '--skip': skip,
790 '--skip': skip,
791 }
791 }
792
792
793 enabled = [x for x in incompatibles if incompatibles[x]]
793 enabled = [x for x in incompatibles if incompatibles[x]]
794
794
795 if len(enabled) > 1:
795 if len(enabled) > 1:
796 raise error.Abort(_('%s and %s are incompatible') %
796 raise error.Abort(_('%s and %s are incompatible') %
797 tuple(sorted(enabled)[0:2]))
797 tuple(sorted(enabled)[0:2]))
798
798
799 if reset:
799 if reset:
800 hbisect.resetstate(repo)
800 hbisect.resetstate(repo)
801 return
801 return
802
802
803 state = hbisect.load_state(repo)
803 state = hbisect.load_state(repo)
804
804
805 # update state
805 # update state
806 if good or bad or skip:
806 if good or bad or skip:
807 if rev:
807 if rev:
808 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
808 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
809 else:
809 else:
810 nodes = [repo.lookup('.')]
810 nodes = [repo.lookup('.')]
811 if good:
811 if good:
812 state['good'] += nodes
812 state['good'] += nodes
813 elif bad:
813 elif bad:
814 state['bad'] += nodes
814 state['bad'] += nodes
815 elif skip:
815 elif skip:
816 state['skip'] += nodes
816 state['skip'] += nodes
817 hbisect.save_state(repo, state)
817 hbisect.save_state(repo, state)
818 if not (state['good'] and state['bad']):
818 if not (state['good'] and state['bad']):
819 return
819 return
820
820
821 def mayupdate(repo, node, show_stats=True):
821 def mayupdate(repo, node, show_stats=True):
822 """common used update sequence"""
822 """common used update sequence"""
823 if noupdate:
823 if noupdate:
824 return
824 return
825 cmdutil.checkunfinished(repo)
825 cmdutil.checkunfinished(repo)
826 cmdutil.bailifchanged(repo)
826 cmdutil.bailifchanged(repo)
827 return hg.clean(repo, node, show_stats=show_stats)
827 return hg.clean(repo, node, show_stats=show_stats)
828
828
829 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
829 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
830
830
831 if command:
831 if command:
832 changesets = 1
832 changesets = 1
833 if noupdate:
833 if noupdate:
834 try:
834 try:
835 node = state['current'][0]
835 node = state['current'][0]
836 except LookupError:
836 except LookupError:
837 raise error.Abort(_('current bisect revision is unknown - '
837 raise error.Abort(_('current bisect revision is unknown - '
838 'start a new bisect to fix'))
838 'start a new bisect to fix'))
839 else:
839 else:
840 node, p2 = repo.dirstate.parents()
840 node, p2 = repo.dirstate.parents()
841 if p2 != nullid:
841 if p2 != nullid:
842 raise error.Abort(_('current bisect revision is a merge'))
842 raise error.Abort(_('current bisect revision is a merge'))
843 if rev:
843 if rev:
844 node = repo[scmutil.revsingle(repo, rev, node)].node()
844 node = repo[scmutil.revsingle(repo, rev, node)].node()
845 try:
845 try:
846 while changesets:
846 while changesets:
847 # update state
847 # update state
848 state['current'] = [node]
848 state['current'] = [node]
849 hbisect.save_state(repo, state)
849 hbisect.save_state(repo, state)
850 status = ui.system(command, environ={'HG_NODE': hex(node)},
850 status = ui.system(command, environ={'HG_NODE': hex(node)},
851 blockedtag='bisect_check')
851 blockedtag='bisect_check')
852 if status == 125:
852 if status == 125:
853 transition = "skip"
853 transition = "skip"
854 elif status == 0:
854 elif status == 0:
855 transition = "good"
855 transition = "good"
856 # status < 0 means process was killed
856 # status < 0 means process was killed
857 elif status == 127:
857 elif status == 127:
858 raise error.Abort(_("failed to execute %s") % command)
858 raise error.Abort(_("failed to execute %s") % command)
859 elif status < 0:
859 elif status < 0:
860 raise error.Abort(_("%s killed") % command)
860 raise error.Abort(_("%s killed") % command)
861 else:
861 else:
862 transition = "bad"
862 transition = "bad"
863 state[transition].append(node)
863 state[transition].append(node)
864 ctx = repo[node]
864 ctx = repo[node]
865 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
865 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
866 transition))
866 transition))
867 hbisect.checkstate(state)
867 hbisect.checkstate(state)
868 # bisect
868 # bisect
869 nodes, changesets, bgood = hbisect.bisect(repo, state)
869 nodes, changesets, bgood = hbisect.bisect(repo, state)
870 # update to next check
870 # update to next check
871 node = nodes[0]
871 node = nodes[0]
872 mayupdate(repo, node, show_stats=False)
872 mayupdate(repo, node, show_stats=False)
873 finally:
873 finally:
874 state['current'] = [node]
874 state['current'] = [node]
875 hbisect.save_state(repo, state)
875 hbisect.save_state(repo, state)
876 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
876 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
877 return
877 return
878
878
879 hbisect.checkstate(state)
879 hbisect.checkstate(state)
880
880
881 # actually bisect
881 # actually bisect
882 nodes, changesets, good = hbisect.bisect(repo, state)
882 nodes, changesets, good = hbisect.bisect(repo, state)
883 if extend:
883 if extend:
884 if not changesets:
884 if not changesets:
885 extendnode = hbisect.extendrange(repo, state, nodes, good)
885 extendnode = hbisect.extendrange(repo, state, nodes, good)
886 if extendnode is not None:
886 if extendnode is not None:
887 ui.write(_("Extending search to changeset %d:%s\n")
887 ui.write(_("Extending search to changeset %d:%s\n")
888 % (extendnode.rev(), extendnode))
888 % (extendnode.rev(), extendnode))
889 state['current'] = [extendnode.node()]
889 state['current'] = [extendnode.node()]
890 hbisect.save_state(repo, state)
890 hbisect.save_state(repo, state)
891 return mayupdate(repo, extendnode.node())
891 return mayupdate(repo, extendnode.node())
892 raise error.Abort(_("nothing to extend"))
892 raise error.Abort(_("nothing to extend"))
893
893
894 if changesets == 0:
894 if changesets == 0:
895 hbisect.printresult(ui, repo, state, displayer, nodes, good)
895 hbisect.printresult(ui, repo, state, displayer, nodes, good)
896 else:
896 else:
897 assert len(nodes) == 1 # only a single node can be tested next
897 assert len(nodes) == 1 # only a single node can be tested next
898 node = nodes[0]
898 node = nodes[0]
899 # compute the approximate number of remaining tests
899 # compute the approximate number of remaining tests
900 tests, size = 0, 2
900 tests, size = 0, 2
901 while size <= changesets:
901 while size <= changesets:
902 tests, size = tests + 1, size * 2
902 tests, size = tests + 1, size * 2
903 rev = repo.changelog.rev(node)
903 rev = repo.changelog.rev(node)
904 ui.write(_("Testing changeset %d:%s "
904 ui.write(_("Testing changeset %d:%s "
905 "(%d changesets remaining, ~%d tests)\n")
905 "(%d changesets remaining, ~%d tests)\n")
906 % (rev, short(node), changesets, tests))
906 % (rev, short(node), changesets, tests))
907 state['current'] = [node]
907 state['current'] = [node]
908 hbisect.save_state(repo, state)
908 hbisect.save_state(repo, state)
909 return mayupdate(repo, node)
909 return mayupdate(repo, node)
910
910
911 @command('bookmarks|bookmark',
911 @command('bookmarks|bookmark',
912 [('f', 'force', False, _('force')),
912 [('f', 'force', False, _('force')),
913 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
913 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
914 ('d', 'delete', False, _('delete a given bookmark')),
914 ('d', 'delete', False, _('delete a given bookmark')),
915 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
915 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
916 ('i', 'inactive', False, _('mark a bookmark inactive')),
916 ('i', 'inactive', False, _('mark a bookmark inactive')),
917 ] + formatteropts,
917 ] + formatteropts,
918 _('hg bookmarks [OPTIONS]... [NAME]...'))
918 _('hg bookmarks [OPTIONS]... [NAME]...'))
919 def bookmark(ui, repo, *names, **opts):
919 def bookmark(ui, repo, *names, **opts):
920 '''create a new bookmark or list existing bookmarks
920 '''create a new bookmark or list existing bookmarks
921
921
922 Bookmarks are labels on changesets to help track lines of development.
922 Bookmarks are labels on changesets to help track lines of development.
923 Bookmarks are unversioned and can be moved, renamed and deleted.
923 Bookmarks are unversioned and can be moved, renamed and deleted.
924 Deleting or moving a bookmark has no effect on the associated changesets.
924 Deleting or moving a bookmark has no effect on the associated changesets.
925
925
926 Creating or updating to a bookmark causes it to be marked as 'active'.
926 Creating or updating to a bookmark causes it to be marked as 'active'.
927 The active bookmark is indicated with a '*'.
927 The active bookmark is indicated with a '*'.
928 When a commit is made, the active bookmark will advance to the new commit.
928 When a commit is made, the active bookmark will advance to the new commit.
929 A plain :hg:`update` will also advance an active bookmark, if possible.
929 A plain :hg:`update` will also advance an active bookmark, if possible.
930 Updating away from a bookmark will cause it to be deactivated.
930 Updating away from a bookmark will cause it to be deactivated.
931
931
932 Bookmarks can be pushed and pulled between repositories (see
932 Bookmarks can be pushed and pulled between repositories (see
933 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
933 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
934 diverged, a new 'divergent bookmark' of the form 'name@path' will
934 diverged, a new 'divergent bookmark' of the form 'name@path' will
935 be created. Using :hg:`merge` will resolve the divergence.
935 be created. Using :hg:`merge` will resolve the divergence.
936
936
937 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
937 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
938 the active bookmark's name.
938 the active bookmark's name.
939
939
940 A bookmark named '@' has the special property that :hg:`clone` will
940 A bookmark named '@' has the special property that :hg:`clone` will
941 check it out by default if it exists.
941 check it out by default if it exists.
942
942
943 .. container:: verbose
943 .. container:: verbose
944
944
945 Examples:
945 Examples:
946
946
947 - create an active bookmark for a new line of development::
947 - create an active bookmark for a new line of development::
948
948
949 hg book new-feature
949 hg book new-feature
950
950
951 - create an inactive bookmark as a place marker::
951 - create an inactive bookmark as a place marker::
952
952
953 hg book -i reviewed
953 hg book -i reviewed
954
954
955 - create an inactive bookmark on another changeset::
955 - create an inactive bookmark on another changeset::
956
956
957 hg book -r .^ tested
957 hg book -r .^ tested
958
958
959 - rename bookmark turkey to dinner::
959 - rename bookmark turkey to dinner::
960
960
961 hg book -m turkey dinner
961 hg book -m turkey dinner
962
962
963 - move the '@' bookmark from another branch::
963 - move the '@' bookmark from another branch::
964
964
965 hg book -f @
965 hg book -f @
966 '''
966 '''
967 force = opts.get(r'force')
967 force = opts.get(r'force')
968 rev = opts.get(r'rev')
968 rev = opts.get(r'rev')
969 delete = opts.get(r'delete')
969 delete = opts.get(r'delete')
970 rename = opts.get(r'rename')
970 rename = opts.get(r'rename')
971 inactive = opts.get(r'inactive')
971 inactive = opts.get(r'inactive')
972
972
973 if delete and rename:
973 if delete and rename:
974 raise error.Abort(_("--delete and --rename are incompatible"))
974 raise error.Abort(_("--delete and --rename are incompatible"))
975 if delete and rev:
975 if delete and rev:
976 raise error.Abort(_("--rev is incompatible with --delete"))
976 raise error.Abort(_("--rev is incompatible with --delete"))
977 if rename and rev:
977 if rename and rev:
978 raise error.Abort(_("--rev is incompatible with --rename"))
978 raise error.Abort(_("--rev is incompatible with --rename"))
979 if not names and (delete or rev):
979 if not names and (delete or rev):
980 raise error.Abort(_("bookmark name required"))
980 raise error.Abort(_("bookmark name required"))
981
981
982 if delete or rename or names or inactive:
982 if delete or rename or names or inactive:
983 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
983 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
984 if delete:
984 if delete:
985 names = pycompat.maplist(repo._bookmarks.expandname, names)
985 names = pycompat.maplist(repo._bookmarks.expandname, names)
986 bookmarks.delete(repo, tr, names)
986 bookmarks.delete(repo, tr, names)
987 elif rename:
987 elif rename:
988 if not names:
988 if not names:
989 raise error.Abort(_("new bookmark name required"))
989 raise error.Abort(_("new bookmark name required"))
990 elif len(names) > 1:
990 elif len(names) > 1:
991 raise error.Abort(_("only one new bookmark name allowed"))
991 raise error.Abort(_("only one new bookmark name allowed"))
992 rename = repo._bookmarks.expandname(rename)
992 rename = repo._bookmarks.expandname(rename)
993 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
993 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
994 elif names:
994 elif names:
995 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
995 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
996 elif inactive:
996 elif inactive:
997 if len(repo._bookmarks) == 0:
997 if len(repo._bookmarks) == 0:
998 ui.status(_("no bookmarks set\n"))
998 ui.status(_("no bookmarks set\n"))
999 elif not repo._activebookmark:
999 elif not repo._activebookmark:
1000 ui.status(_("no active bookmark\n"))
1000 ui.status(_("no active bookmark\n"))
1001 else:
1001 else:
1002 bookmarks.deactivate(repo)
1002 bookmarks.deactivate(repo)
1003 else: # show bookmarks
1003 else: # show bookmarks
1004 bookmarks.printbookmarks(ui, repo, **opts)
1004 bookmarks.printbookmarks(ui, repo, **opts)
1005
1005
1006 @command('branch',
1006 @command('branch',
1007 [('f', 'force', None,
1007 [('f', 'force', None,
1008 _('set branch name even if it shadows an existing branch')),
1008 _('set branch name even if it shadows an existing branch')),
1009 ('C', 'clean', None, _('reset branch name to parent branch name')),
1009 ('C', 'clean', None, _('reset branch name to parent branch name')),
1010 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1010 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1011 ],
1011 ],
1012 _('[-fC] [NAME]'))
1012 _('[-fC] [NAME]'))
1013 def branch(ui, repo, label=None, **opts):
1013 def branch(ui, repo, label=None, **opts):
1014 """set or show the current branch name
1014 """set or show the current branch name
1015
1015
1016 .. note::
1016 .. note::
1017
1017
1018 Branch names are permanent and global. Use :hg:`bookmark` to create a
1018 Branch names are permanent and global. Use :hg:`bookmark` to create a
1019 light-weight bookmark instead. See :hg:`help glossary` for more
1019 light-weight bookmark instead. See :hg:`help glossary` for more
1020 information about named branches and bookmarks.
1020 information about named branches and bookmarks.
1021
1021
1022 With no argument, show the current branch name. With one argument,
1022 With no argument, show the current branch name. With one argument,
1023 set the working directory branch name (the branch will not exist
1023 set the working directory branch name (the branch will not exist
1024 in the repository until the next commit). Standard practice
1024 in the repository until the next commit). Standard practice
1025 recommends that primary development take place on the 'default'
1025 recommends that primary development take place on the 'default'
1026 branch.
1026 branch.
1027
1027
1028 Unless -f/--force is specified, branch will not let you set a
1028 Unless -f/--force is specified, branch will not let you set a
1029 branch name that already exists.
1029 branch name that already exists.
1030
1030
1031 Use -C/--clean to reset the working directory branch to that of
1031 Use -C/--clean to reset the working directory branch to that of
1032 the parent of the working directory, negating a previous branch
1032 the parent of the working directory, negating a previous branch
1033 change.
1033 change.
1034
1034
1035 Use the command :hg:`update` to switch to an existing branch. Use
1035 Use the command :hg:`update` to switch to an existing branch. Use
1036 :hg:`commit --close-branch` to mark this branch head as closed.
1036 :hg:`commit --close-branch` to mark this branch head as closed.
1037 When all heads of a branch are closed, the branch will be
1037 When all heads of a branch are closed, the branch will be
1038 considered closed.
1038 considered closed.
1039
1039
1040 Returns 0 on success.
1040 Returns 0 on success.
1041 """
1041 """
1042 opts = pycompat.byteskwargs(opts)
1042 opts = pycompat.byteskwargs(opts)
1043 revs = opts.get('rev')
1043 revs = opts.get('rev')
1044 if label:
1044 if label:
1045 label = label.strip()
1045 label = label.strip()
1046
1046
1047 if not opts.get('clean') and not label:
1047 if not opts.get('clean') and not label:
1048 if revs:
1048 if revs:
1049 raise error.Abort(_("no branch name specified for the revisions"))
1049 raise error.Abort(_("no branch name specified for the revisions"))
1050 ui.write("%s\n" % repo.dirstate.branch())
1050 ui.write("%s\n" % repo.dirstate.branch())
1051 return
1051 return
1052
1052
1053 with repo.wlock():
1053 with repo.wlock():
1054 if opts.get('clean'):
1054 if opts.get('clean'):
1055 label = repo[None].p1().branch()
1055 label = repo[None].p1().branch()
1056 repo.dirstate.setbranch(label)
1056 repo.dirstate.setbranch(label)
1057 ui.status(_('reset working directory to branch %s\n') % label)
1057 ui.status(_('reset working directory to branch %s\n') % label)
1058 elif label:
1058 elif label:
1059
1059
1060 scmutil.checknewlabel(repo, label, 'branch')
1060 scmutil.checknewlabel(repo, label, 'branch')
1061 if revs:
1061 if revs:
1062 return cmdutil.changebranch(ui, repo, revs, label)
1062 return cmdutil.changebranch(ui, repo, revs, label)
1063
1063
1064 if not opts.get('force') and label in repo.branchmap():
1064 if not opts.get('force') and label in repo.branchmap():
1065 if label not in [p.branch() for p in repo[None].parents()]:
1065 if label not in [p.branch() for p in repo[None].parents()]:
1066 raise error.Abort(_('a branch of the same name already'
1066 raise error.Abort(_('a branch of the same name already'
1067 ' exists'),
1067 ' exists'),
1068 # i18n: "it" refers to an existing branch
1068 # i18n: "it" refers to an existing branch
1069 hint=_("use 'hg update' to switch to it"))
1069 hint=_("use 'hg update' to switch to it"))
1070
1070
1071 repo.dirstate.setbranch(label)
1071 repo.dirstate.setbranch(label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1073
1073
1074 # find any open named branches aside from default
1074 # find any open named branches aside from default
1075 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1075 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1076 if n != "default" and not c]
1076 if n != "default" and not c]
1077 if not others:
1077 if not others:
1078 ui.status(_('(branches are permanent and global, '
1078 ui.status(_('(branches are permanent and global, '
1079 'did you want a bookmark?)\n'))
1079 'did you want a bookmark?)\n'))
1080
1080
1081 @command('branches',
1081 @command('branches',
1082 [('a', 'active', False,
1082 [('a', 'active', False,
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1085 ] + formatteropts,
1085 ] + formatteropts,
1086 _('[-c]'), cmdtype=readonly)
1086 _('[-c]'),
1087 intents={INTENT_READONLY})
1087 def branches(ui, repo, active=False, closed=False, **opts):
1088 def branches(ui, repo, active=False, closed=False, **opts):
1088 """list repository named branches
1089 """list repository named branches
1089
1090
1090 List the repository's named branches, indicating which ones are
1091 List the repository's named branches, indicating which ones are
1091 inactive. If -c/--closed is specified, also list branches which have
1092 inactive. If -c/--closed is specified, also list branches which have
1092 been marked closed (see :hg:`commit --close-branch`).
1093 been marked closed (see :hg:`commit --close-branch`).
1093
1094
1094 Use the command :hg:`update` to switch to an existing branch.
1095 Use the command :hg:`update` to switch to an existing branch.
1095
1096
1096 Returns 0.
1097 Returns 0.
1097 """
1098 """
1098
1099
1099 opts = pycompat.byteskwargs(opts)
1100 opts = pycompat.byteskwargs(opts)
1100 ui.pager('branches')
1101 ui.pager('branches')
1101 fm = ui.formatter('branches', opts)
1102 fm = ui.formatter('branches', opts)
1102 hexfunc = fm.hexfunc
1103 hexfunc = fm.hexfunc
1103
1104
1104 allheads = set(repo.heads())
1105 allheads = set(repo.heads())
1105 branches = []
1106 branches = []
1106 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1107 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1107 isactive = False
1108 isactive = False
1108 if not isclosed:
1109 if not isclosed:
1109 openheads = set(repo.branchmap().iteropen(heads))
1110 openheads = set(repo.branchmap().iteropen(heads))
1110 isactive = bool(openheads & allheads)
1111 isactive = bool(openheads & allheads)
1111 branches.append((tag, repo[tip], isactive, not isclosed))
1112 branches.append((tag, repo[tip], isactive, not isclosed))
1112 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1113 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1113 reverse=True)
1114 reverse=True)
1114
1115
1115 for tag, ctx, isactive, isopen in branches:
1116 for tag, ctx, isactive, isopen in branches:
1116 if active and not isactive:
1117 if active and not isactive:
1117 continue
1118 continue
1118 if isactive:
1119 if isactive:
1119 label = 'branches.active'
1120 label = 'branches.active'
1120 notice = ''
1121 notice = ''
1121 elif not isopen:
1122 elif not isopen:
1122 if not closed:
1123 if not closed:
1123 continue
1124 continue
1124 label = 'branches.closed'
1125 label = 'branches.closed'
1125 notice = _(' (closed)')
1126 notice = _(' (closed)')
1126 else:
1127 else:
1127 label = 'branches.inactive'
1128 label = 'branches.inactive'
1128 notice = _(' (inactive)')
1129 notice = _(' (inactive)')
1129 current = (tag == repo.dirstate.branch())
1130 current = (tag == repo.dirstate.branch())
1130 if current:
1131 if current:
1131 label = 'branches.current'
1132 label = 'branches.current'
1132
1133
1133 fm.startitem()
1134 fm.startitem()
1134 fm.write('branch', '%s', tag, label=label)
1135 fm.write('branch', '%s', tag, label=label)
1135 rev = ctx.rev()
1136 rev = ctx.rev()
1136 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1137 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1137 fmt = ' ' * padsize + ' %d:%s'
1138 fmt = ' ' * padsize + ' %d:%s'
1138 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1139 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1139 label='log.changeset changeset.%s' % ctx.phasestr())
1140 label='log.changeset changeset.%s' % ctx.phasestr())
1140 fm.context(ctx=ctx)
1141 fm.context(ctx=ctx)
1141 fm.data(active=isactive, closed=not isopen, current=current)
1142 fm.data(active=isactive, closed=not isopen, current=current)
1142 if not ui.quiet:
1143 if not ui.quiet:
1143 fm.plain(notice)
1144 fm.plain(notice)
1144 fm.plain('\n')
1145 fm.plain('\n')
1145 fm.end()
1146 fm.end()
1146
1147
1147 @command('bundle',
1148 @command('bundle',
1148 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 _('REV')),
1151 _('REV')),
1151 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 _('BRANCH')),
1153 _('BRANCH')),
1153 ('', 'base', [],
1154 ('', 'base', [],
1154 _('a base changeset assumed to be available at the destination'),
1155 _('a base changeset assumed to be available at the destination'),
1155 _('REV')),
1156 _('REV')),
1156 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 ] + remoteopts,
1159 ] + remoteopts,
1159 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 def bundle(ui, repo, fname, dest=None, **opts):
1161 def bundle(ui, repo, fname, dest=None, **opts):
1161 """create a bundle file
1162 """create a bundle file
1162
1163
1163 Generate a bundle file containing data to be transferred to another
1164 Generate a bundle file containing data to be transferred to another
1164 repository.
1165 repository.
1165
1166
1166 To create a bundle containing all changesets, use -a/--all
1167 To create a bundle containing all changesets, use -a/--all
1167 (or --base null). Otherwise, hg assumes the destination will have
1168 (or --base null). Otherwise, hg assumes the destination will have
1168 all the nodes you specify with --base parameters. Otherwise, hg
1169 all the nodes you specify with --base parameters. Otherwise, hg
1169 will assume the repository has all the nodes in destination, or
1170 will assume the repository has all the nodes in destination, or
1170 default-push/default if no destination is specified, where destination
1171 default-push/default if no destination is specified, where destination
1171 is the repository you provide through DEST option.
1172 is the repository you provide through DEST option.
1172
1173
1173 You can change bundle format with the -t/--type option. See
1174 You can change bundle format with the -t/--type option. See
1174 :hg:`help bundlespec` for documentation on this format. By default,
1175 :hg:`help bundlespec` for documentation on this format. By default,
1175 the most appropriate format is used and compression defaults to
1176 the most appropriate format is used and compression defaults to
1176 bzip2.
1177 bzip2.
1177
1178
1178 The bundle file can then be transferred using conventional means
1179 The bundle file can then be transferred using conventional means
1179 and applied to another repository with the unbundle or pull
1180 and applied to another repository with the unbundle or pull
1180 command. This is useful when direct push and pull are not
1181 command. This is useful when direct push and pull are not
1181 available or when exporting an entire repository is undesirable.
1182 available or when exporting an entire repository is undesirable.
1182
1183
1183 Applying bundles preserves all changeset contents including
1184 Applying bundles preserves all changeset contents including
1184 permissions, copy/rename information, and revision history.
1185 permissions, copy/rename information, and revision history.
1185
1186
1186 Returns 0 on success, 1 if no changes found.
1187 Returns 0 on success, 1 if no changes found.
1187 """
1188 """
1188 opts = pycompat.byteskwargs(opts)
1189 opts = pycompat.byteskwargs(opts)
1189 revs = None
1190 revs = None
1190 if 'rev' in opts:
1191 if 'rev' in opts:
1191 revstrings = opts['rev']
1192 revstrings = opts['rev']
1192 revs = scmutil.revrange(repo, revstrings)
1193 revs = scmutil.revrange(repo, revstrings)
1193 if revstrings and not revs:
1194 if revstrings and not revs:
1194 raise error.Abort(_('no commits to bundle'))
1195 raise error.Abort(_('no commits to bundle'))
1195
1196
1196 bundletype = opts.get('type', 'bzip2').lower()
1197 bundletype = opts.get('type', 'bzip2').lower()
1197 try:
1198 try:
1198 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1199 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1199 except error.UnsupportedBundleSpecification as e:
1200 except error.UnsupportedBundleSpecification as e:
1200 raise error.Abort(pycompat.bytestr(e),
1201 raise error.Abort(pycompat.bytestr(e),
1201 hint=_("see 'hg help bundlespec' for supported "
1202 hint=_("see 'hg help bundlespec' for supported "
1202 "values for --type"))
1203 "values for --type"))
1203 cgversion = bundlespec.contentopts["cg.version"]
1204 cgversion = bundlespec.contentopts["cg.version"]
1204
1205
1205 # Packed bundles are a pseudo bundle format for now.
1206 # Packed bundles are a pseudo bundle format for now.
1206 if cgversion == 's1':
1207 if cgversion == 's1':
1207 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1208 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1208 hint=_("use 'hg debugcreatestreamclonebundle'"))
1209 hint=_("use 'hg debugcreatestreamclonebundle'"))
1209
1210
1210 if opts.get('all'):
1211 if opts.get('all'):
1211 if dest:
1212 if dest:
1212 raise error.Abort(_("--all is incompatible with specifying "
1213 raise error.Abort(_("--all is incompatible with specifying "
1213 "a destination"))
1214 "a destination"))
1214 if opts.get('base'):
1215 if opts.get('base'):
1215 ui.warn(_("ignoring --base because --all was specified\n"))
1216 ui.warn(_("ignoring --base because --all was specified\n"))
1216 base = ['null']
1217 base = ['null']
1217 else:
1218 else:
1218 base = scmutil.revrange(repo, opts.get('base'))
1219 base = scmutil.revrange(repo, opts.get('base'))
1219 if cgversion not in changegroup.supportedoutgoingversions(repo):
1220 if cgversion not in changegroup.supportedoutgoingversions(repo):
1220 raise error.Abort(_("repository does not support bundle version %s") %
1221 raise error.Abort(_("repository does not support bundle version %s") %
1221 cgversion)
1222 cgversion)
1222
1223
1223 if base:
1224 if base:
1224 if dest:
1225 if dest:
1225 raise error.Abort(_("--base is incompatible with specifying "
1226 raise error.Abort(_("--base is incompatible with specifying "
1226 "a destination"))
1227 "a destination"))
1227 common = [repo[rev].node() for rev in base]
1228 common = [repo[rev].node() for rev in base]
1228 heads = [repo[r].node() for r in revs] if revs else None
1229 heads = [repo[r].node() for r in revs] if revs else None
1229 outgoing = discovery.outgoing(repo, common, heads)
1230 outgoing = discovery.outgoing(repo, common, heads)
1230 else:
1231 else:
1231 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1232 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1232 dest, branches = hg.parseurl(dest, opts.get('branch'))
1233 dest, branches = hg.parseurl(dest, opts.get('branch'))
1233 other = hg.peer(repo, opts, dest)
1234 other = hg.peer(repo, opts, dest)
1234 revs = [repo[r].hex() for r in revs]
1235 revs = [repo[r].hex() for r in revs]
1235 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1236 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1236 heads = revs and map(repo.lookup, revs) or revs
1237 heads = revs and map(repo.lookup, revs) or revs
1237 outgoing = discovery.findcommonoutgoing(repo, other,
1238 outgoing = discovery.findcommonoutgoing(repo, other,
1238 onlyheads=heads,
1239 onlyheads=heads,
1239 force=opts.get('force'),
1240 force=opts.get('force'),
1240 portable=True)
1241 portable=True)
1241
1242
1242 if not outgoing.missing:
1243 if not outgoing.missing:
1243 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1244 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1244 return 1
1245 return 1
1245
1246
1246 bcompression = bundlespec.compression
1247 bcompression = bundlespec.compression
1247 if cgversion == '01': #bundle1
1248 if cgversion == '01': #bundle1
1248 if bcompression is None:
1249 if bcompression is None:
1249 bcompression = 'UN'
1250 bcompression = 'UN'
1250 bversion = 'HG10' + bcompression
1251 bversion = 'HG10' + bcompression
1251 bcompression = None
1252 bcompression = None
1252 elif cgversion in ('02', '03'):
1253 elif cgversion in ('02', '03'):
1253 bversion = 'HG20'
1254 bversion = 'HG20'
1254 else:
1255 else:
1255 raise error.ProgrammingError(
1256 raise error.ProgrammingError(
1256 'bundle: unexpected changegroup version %s' % cgversion)
1257 'bundle: unexpected changegroup version %s' % cgversion)
1257
1258
1258 # TODO compression options should be derived from bundlespec parsing.
1259 # TODO compression options should be derived from bundlespec parsing.
1259 # This is a temporary hack to allow adjusting bundle compression
1260 # This is a temporary hack to allow adjusting bundle compression
1260 # level without a) formalizing the bundlespec changes to declare it
1261 # level without a) formalizing the bundlespec changes to declare it
1261 # b) introducing a command flag.
1262 # b) introducing a command flag.
1262 compopts = {}
1263 compopts = {}
1263 complevel = ui.configint('experimental', 'bundlecomplevel')
1264 complevel = ui.configint('experimental', 'bundlecomplevel')
1264 if complevel is not None:
1265 if complevel is not None:
1265 compopts['level'] = complevel
1266 compopts['level'] = complevel
1266
1267
1267 # Allow overriding the bundling of obsmarker in phases through
1268 # Allow overriding the bundling of obsmarker in phases through
1268 # configuration while we don't have a bundle version that include them
1269 # configuration while we don't have a bundle version that include them
1269 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1270 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1270 bundlespec.contentopts['obsolescence'] = True
1271 bundlespec.contentopts['obsolescence'] = True
1271 if repo.ui.configbool('experimental', 'bundle-phases'):
1272 if repo.ui.configbool('experimental', 'bundle-phases'):
1272 bundlespec.contentopts['phases'] = True
1273 bundlespec.contentopts['phases'] = True
1273
1274
1274 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1275 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1275 bundlespec.contentopts, compression=bcompression,
1276 bundlespec.contentopts, compression=bcompression,
1276 compopts=compopts)
1277 compopts=compopts)
1277
1278
1278 @command('cat',
1279 @command('cat',
1279 [('o', 'output', '',
1280 [('o', 'output', '',
1280 _('print output to file with formatted name'), _('FORMAT')),
1281 _('print output to file with formatted name'), _('FORMAT')),
1281 ('r', 'rev', '', _('print the given revision'), _('REV')),
1282 ('r', 'rev', '', _('print the given revision'), _('REV')),
1282 ('', 'decode', None, _('apply any matching decode filter')),
1283 ('', 'decode', None, _('apply any matching decode filter')),
1283 ] + walkopts + formatteropts,
1284 ] + walkopts + formatteropts,
1284 _('[OPTION]... FILE...'),
1285 _('[OPTION]... FILE...'),
1285 inferrepo=True, cmdtype=readonly)
1286 inferrepo=True,
1287 intents={INTENT_READONLY})
1286 def cat(ui, repo, file1, *pats, **opts):
1288 def cat(ui, repo, file1, *pats, **opts):
1287 """output the current or given revision of files
1289 """output the current or given revision of files
1288
1290
1289 Print the specified files as they were at the given revision. If
1291 Print the specified files as they were at the given revision. If
1290 no revision is given, the parent of the working directory is used.
1292 no revision is given, the parent of the working directory is used.
1291
1293
1292 Output may be to a file, in which case the name of the file is
1294 Output may be to a file, in which case the name of the file is
1293 given using a template string. See :hg:`help templates`. In addition
1295 given using a template string. See :hg:`help templates`. In addition
1294 to the common template keywords, the following formatting rules are
1296 to the common template keywords, the following formatting rules are
1295 supported:
1297 supported:
1296
1298
1297 :``%%``: literal "%" character
1299 :``%%``: literal "%" character
1298 :``%s``: basename of file being printed
1300 :``%s``: basename of file being printed
1299 :``%d``: dirname of file being printed, or '.' if in repository root
1301 :``%d``: dirname of file being printed, or '.' if in repository root
1300 :``%p``: root-relative path name of file being printed
1302 :``%p``: root-relative path name of file being printed
1301 :``%H``: changeset hash (40 hexadecimal digits)
1303 :``%H``: changeset hash (40 hexadecimal digits)
1302 :``%R``: changeset revision number
1304 :``%R``: changeset revision number
1303 :``%h``: short-form changeset hash (12 hexadecimal digits)
1305 :``%h``: short-form changeset hash (12 hexadecimal digits)
1304 :``%r``: zero-padded changeset revision number
1306 :``%r``: zero-padded changeset revision number
1305 :``%b``: basename of the exporting repository
1307 :``%b``: basename of the exporting repository
1306 :``\\``: literal "\\" character
1308 :``\\``: literal "\\" character
1307
1309
1308 Returns 0 on success.
1310 Returns 0 on success.
1309 """
1311 """
1310 opts = pycompat.byteskwargs(opts)
1312 opts = pycompat.byteskwargs(opts)
1311 rev = opts.get('rev')
1313 rev = opts.get('rev')
1312 if rev:
1314 if rev:
1313 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1315 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1314 ctx = scmutil.revsingle(repo, rev)
1316 ctx = scmutil.revsingle(repo, rev)
1315 m = scmutil.match(ctx, (file1,) + pats, opts)
1317 m = scmutil.match(ctx, (file1,) + pats, opts)
1316 fntemplate = opts.pop('output', '')
1318 fntemplate = opts.pop('output', '')
1317 if cmdutil.isstdiofilename(fntemplate):
1319 if cmdutil.isstdiofilename(fntemplate):
1318 fntemplate = ''
1320 fntemplate = ''
1319
1321
1320 if fntemplate:
1322 if fntemplate:
1321 fm = formatter.nullformatter(ui, 'cat', opts)
1323 fm = formatter.nullformatter(ui, 'cat', opts)
1322 else:
1324 else:
1323 ui.pager('cat')
1325 ui.pager('cat')
1324 fm = ui.formatter('cat', opts)
1326 fm = ui.formatter('cat', opts)
1325 with fm:
1327 with fm:
1326 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1328 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1327 **pycompat.strkwargs(opts))
1329 **pycompat.strkwargs(opts))
1328
1330
1329 @command('^clone',
1331 @command('^clone',
1330 [('U', 'noupdate', None, _('the clone will include an empty working '
1332 [('U', 'noupdate', None, _('the clone will include an empty working '
1331 'directory (only a repository)')),
1333 'directory (only a repository)')),
1332 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1334 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1333 _('REV')),
1335 _('REV')),
1334 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1336 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1335 ' and its ancestors'), _('REV')),
1337 ' and its ancestors'), _('REV')),
1336 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1338 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1337 ' changesets and their ancestors'), _('BRANCH')),
1339 ' changesets and their ancestors'), _('BRANCH')),
1338 ('', 'pull', None, _('use pull protocol to copy metadata')),
1340 ('', 'pull', None, _('use pull protocol to copy metadata')),
1339 ('', 'uncompressed', None,
1341 ('', 'uncompressed', None,
1340 _('an alias to --stream (DEPRECATED)')),
1342 _('an alias to --stream (DEPRECATED)')),
1341 ('', 'stream', None,
1343 ('', 'stream', None,
1342 _('clone with minimal data processing')),
1344 _('clone with minimal data processing')),
1343 ] + remoteopts,
1345 ] + remoteopts,
1344 _('[OPTION]... SOURCE [DEST]'),
1346 _('[OPTION]... SOURCE [DEST]'),
1345 norepo=True)
1347 norepo=True)
1346 def clone(ui, source, dest=None, **opts):
1348 def clone(ui, source, dest=None, **opts):
1347 """make a copy of an existing repository
1349 """make a copy of an existing repository
1348
1350
1349 Create a copy of an existing repository in a new directory.
1351 Create a copy of an existing repository in a new directory.
1350
1352
1351 If no destination directory name is specified, it defaults to the
1353 If no destination directory name is specified, it defaults to the
1352 basename of the source.
1354 basename of the source.
1353
1355
1354 The location of the source is added to the new repository's
1356 The location of the source is added to the new repository's
1355 ``.hg/hgrc`` file, as the default to be used for future pulls.
1357 ``.hg/hgrc`` file, as the default to be used for future pulls.
1356
1358
1357 Only local paths and ``ssh://`` URLs are supported as
1359 Only local paths and ``ssh://`` URLs are supported as
1358 destinations. For ``ssh://`` destinations, no working directory or
1360 destinations. For ``ssh://`` destinations, no working directory or
1359 ``.hg/hgrc`` will be created on the remote side.
1361 ``.hg/hgrc`` will be created on the remote side.
1360
1362
1361 If the source repository has a bookmark called '@' set, that
1363 If the source repository has a bookmark called '@' set, that
1362 revision will be checked out in the new repository by default.
1364 revision will be checked out in the new repository by default.
1363
1365
1364 To check out a particular version, use -u/--update, or
1366 To check out a particular version, use -u/--update, or
1365 -U/--noupdate to create a clone with no working directory.
1367 -U/--noupdate to create a clone with no working directory.
1366
1368
1367 To pull only a subset of changesets, specify one or more revisions
1369 To pull only a subset of changesets, specify one or more revisions
1368 identifiers with -r/--rev or branches with -b/--branch. The
1370 identifiers with -r/--rev or branches with -b/--branch. The
1369 resulting clone will contain only the specified changesets and
1371 resulting clone will contain only the specified changesets and
1370 their ancestors. These options (or 'clone src#rev dest') imply
1372 their ancestors. These options (or 'clone src#rev dest') imply
1371 --pull, even for local source repositories.
1373 --pull, even for local source repositories.
1372
1374
1373 In normal clone mode, the remote normalizes repository data into a common
1375 In normal clone mode, the remote normalizes repository data into a common
1374 exchange format and the receiving end translates this data into its local
1376 exchange format and the receiving end translates this data into its local
1375 storage format. --stream activates a different clone mode that essentially
1377 storage format. --stream activates a different clone mode that essentially
1376 copies repository files from the remote with minimal data processing. This
1378 copies repository files from the remote with minimal data processing. This
1377 significantly reduces the CPU cost of a clone both remotely and locally.
1379 significantly reduces the CPU cost of a clone both remotely and locally.
1378 However, it often increases the transferred data size by 30-40%. This can
1380 However, it often increases the transferred data size by 30-40%. This can
1379 result in substantially faster clones where I/O throughput is plentiful,
1381 result in substantially faster clones where I/O throughput is plentiful,
1380 especially for larger repositories. A side-effect of --stream clones is
1382 especially for larger repositories. A side-effect of --stream clones is
1381 that storage settings and requirements on the remote are applied locally:
1383 that storage settings and requirements on the remote are applied locally:
1382 a modern client may inherit legacy or inefficient storage used by the
1384 a modern client may inherit legacy or inefficient storage used by the
1383 remote or a legacy Mercurial client may not be able to clone from a
1385 remote or a legacy Mercurial client may not be able to clone from a
1384 modern Mercurial remote.
1386 modern Mercurial remote.
1385
1387
1386 .. note::
1388 .. note::
1387
1389
1388 Specifying a tag will include the tagged changeset but not the
1390 Specifying a tag will include the tagged changeset but not the
1389 changeset containing the tag.
1391 changeset containing the tag.
1390
1392
1391 .. container:: verbose
1393 .. container:: verbose
1392
1394
1393 For efficiency, hardlinks are used for cloning whenever the
1395 For efficiency, hardlinks are used for cloning whenever the
1394 source and destination are on the same filesystem (note this
1396 source and destination are on the same filesystem (note this
1395 applies only to the repository data, not to the working
1397 applies only to the repository data, not to the working
1396 directory). Some filesystems, such as AFS, implement hardlinking
1398 directory). Some filesystems, such as AFS, implement hardlinking
1397 incorrectly, but do not report errors. In these cases, use the
1399 incorrectly, but do not report errors. In these cases, use the
1398 --pull option to avoid hardlinking.
1400 --pull option to avoid hardlinking.
1399
1401
1400 Mercurial will update the working directory to the first applicable
1402 Mercurial will update the working directory to the first applicable
1401 revision from this list:
1403 revision from this list:
1402
1404
1403 a) null if -U or the source repository has no changesets
1405 a) null if -U or the source repository has no changesets
1404 b) if -u . and the source repository is local, the first parent of
1406 b) if -u . and the source repository is local, the first parent of
1405 the source repository's working directory
1407 the source repository's working directory
1406 c) the changeset specified with -u (if a branch name, this means the
1408 c) the changeset specified with -u (if a branch name, this means the
1407 latest head of that branch)
1409 latest head of that branch)
1408 d) the changeset specified with -r
1410 d) the changeset specified with -r
1409 e) the tipmost head specified with -b
1411 e) the tipmost head specified with -b
1410 f) the tipmost head specified with the url#branch source syntax
1412 f) the tipmost head specified with the url#branch source syntax
1411 g) the revision marked with the '@' bookmark, if present
1413 g) the revision marked with the '@' bookmark, if present
1412 h) the tipmost head of the default branch
1414 h) the tipmost head of the default branch
1413 i) tip
1415 i) tip
1414
1416
1415 When cloning from servers that support it, Mercurial may fetch
1417 When cloning from servers that support it, Mercurial may fetch
1416 pre-generated data from a server-advertised URL or inline from the
1418 pre-generated data from a server-advertised URL or inline from the
1417 same stream. When this is done, hooks operating on incoming changesets
1419 same stream. When this is done, hooks operating on incoming changesets
1418 and changegroups may fire more than once, once for each pre-generated
1420 and changegroups may fire more than once, once for each pre-generated
1419 bundle and as well as for any additional remaining data. In addition,
1421 bundle and as well as for any additional remaining data. In addition,
1420 if an error occurs, the repository may be rolled back to a partial
1422 if an error occurs, the repository may be rolled back to a partial
1421 clone. This behavior may change in future releases.
1423 clone. This behavior may change in future releases.
1422 See :hg:`help -e clonebundles` for more.
1424 See :hg:`help -e clonebundles` for more.
1423
1425
1424 Examples:
1426 Examples:
1425
1427
1426 - clone a remote repository to a new directory named hg/::
1428 - clone a remote repository to a new directory named hg/::
1427
1429
1428 hg clone https://www.mercurial-scm.org/repo/hg/
1430 hg clone https://www.mercurial-scm.org/repo/hg/
1429
1431
1430 - create a lightweight local clone::
1432 - create a lightweight local clone::
1431
1433
1432 hg clone project/ project-feature/
1434 hg clone project/ project-feature/
1433
1435
1434 - clone from an absolute path on an ssh server (note double-slash)::
1436 - clone from an absolute path on an ssh server (note double-slash)::
1435
1437
1436 hg clone ssh://user@server//home/projects/alpha/
1438 hg clone ssh://user@server//home/projects/alpha/
1437
1439
1438 - do a streaming clone while checking out a specified version::
1440 - do a streaming clone while checking out a specified version::
1439
1441
1440 hg clone --stream http://server/repo -u 1.5
1442 hg clone --stream http://server/repo -u 1.5
1441
1443
1442 - create a repository without changesets after a particular revision::
1444 - create a repository without changesets after a particular revision::
1443
1445
1444 hg clone -r 04e544 experimental/ good/
1446 hg clone -r 04e544 experimental/ good/
1445
1447
1446 - clone (and track) a particular named branch::
1448 - clone (and track) a particular named branch::
1447
1449
1448 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1450 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1449
1451
1450 See :hg:`help urls` for details on specifying URLs.
1452 See :hg:`help urls` for details on specifying URLs.
1451
1453
1452 Returns 0 on success.
1454 Returns 0 on success.
1453 """
1455 """
1454 opts = pycompat.byteskwargs(opts)
1456 opts = pycompat.byteskwargs(opts)
1455 if opts.get('noupdate') and opts.get('updaterev'):
1457 if opts.get('noupdate') and opts.get('updaterev'):
1456 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1458 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1457
1459
1458 r = hg.clone(ui, opts, source, dest,
1460 r = hg.clone(ui, opts, source, dest,
1459 pull=opts.get('pull'),
1461 pull=opts.get('pull'),
1460 stream=opts.get('stream') or opts.get('uncompressed'),
1462 stream=opts.get('stream') or opts.get('uncompressed'),
1461 revs=opts.get('rev'),
1463 revs=opts.get('rev'),
1462 update=opts.get('updaterev') or not opts.get('noupdate'),
1464 update=opts.get('updaterev') or not opts.get('noupdate'),
1463 branch=opts.get('branch'),
1465 branch=opts.get('branch'),
1464 shareopts=opts.get('shareopts'))
1466 shareopts=opts.get('shareopts'))
1465
1467
1466 return r is None
1468 return r is None
1467
1469
1468 @command('^commit|ci',
1470 @command('^commit|ci',
1469 [('A', 'addremove', None,
1471 [('A', 'addremove', None,
1470 _('mark new/missing files as added/removed before committing')),
1472 _('mark new/missing files as added/removed before committing')),
1471 ('', 'close-branch', None,
1473 ('', 'close-branch', None,
1472 _('mark a branch head as closed')),
1474 _('mark a branch head as closed')),
1473 ('', 'amend', None, _('amend the parent of the working directory')),
1475 ('', 'amend', None, _('amend the parent of the working directory')),
1474 ('s', 'secret', None, _('use the secret phase for committing')),
1476 ('s', 'secret', None, _('use the secret phase for committing')),
1475 ('e', 'edit', None, _('invoke editor on commit messages')),
1477 ('e', 'edit', None, _('invoke editor on commit messages')),
1476 ('i', 'interactive', None, _('use interactive mode')),
1478 ('i', 'interactive', None, _('use interactive mode')),
1477 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1479 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1478 _('[OPTION]... [FILE]...'),
1480 _('[OPTION]... [FILE]...'),
1479 inferrepo=True)
1481 inferrepo=True)
1480 def commit(ui, repo, *pats, **opts):
1482 def commit(ui, repo, *pats, **opts):
1481 """commit the specified files or all outstanding changes
1483 """commit the specified files or all outstanding changes
1482
1484
1483 Commit changes to the given files into the repository. Unlike a
1485 Commit changes to the given files into the repository. Unlike a
1484 centralized SCM, this operation is a local operation. See
1486 centralized SCM, this operation is a local operation. See
1485 :hg:`push` for a way to actively distribute your changes.
1487 :hg:`push` for a way to actively distribute your changes.
1486
1488
1487 If a list of files is omitted, all changes reported by :hg:`status`
1489 If a list of files is omitted, all changes reported by :hg:`status`
1488 will be committed.
1490 will be committed.
1489
1491
1490 If you are committing the result of a merge, do not provide any
1492 If you are committing the result of a merge, do not provide any
1491 filenames or -I/-X filters.
1493 filenames or -I/-X filters.
1492
1494
1493 If no commit message is specified, Mercurial starts your
1495 If no commit message is specified, Mercurial starts your
1494 configured editor where you can enter a message. In case your
1496 configured editor where you can enter a message. In case your
1495 commit fails, you will find a backup of your message in
1497 commit fails, you will find a backup of your message in
1496 ``.hg/last-message.txt``.
1498 ``.hg/last-message.txt``.
1497
1499
1498 The --close-branch flag can be used to mark the current branch
1500 The --close-branch flag can be used to mark the current branch
1499 head closed. When all heads of a branch are closed, the branch
1501 head closed. When all heads of a branch are closed, the branch
1500 will be considered closed and no longer listed.
1502 will be considered closed and no longer listed.
1501
1503
1502 The --amend flag can be used to amend the parent of the
1504 The --amend flag can be used to amend the parent of the
1503 working directory with a new commit that contains the changes
1505 working directory with a new commit that contains the changes
1504 in the parent in addition to those currently reported by :hg:`status`,
1506 in the parent in addition to those currently reported by :hg:`status`,
1505 if there are any. The old commit is stored in a backup bundle in
1507 if there are any. The old commit is stored in a backup bundle in
1506 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1508 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1507 on how to restore it).
1509 on how to restore it).
1508
1510
1509 Message, user and date are taken from the amended commit unless
1511 Message, user and date are taken from the amended commit unless
1510 specified. When a message isn't specified on the command line,
1512 specified. When a message isn't specified on the command line,
1511 the editor will open with the message of the amended commit.
1513 the editor will open with the message of the amended commit.
1512
1514
1513 It is not possible to amend public changesets (see :hg:`help phases`)
1515 It is not possible to amend public changesets (see :hg:`help phases`)
1514 or changesets that have children.
1516 or changesets that have children.
1515
1517
1516 See :hg:`help dates` for a list of formats valid for -d/--date.
1518 See :hg:`help dates` for a list of formats valid for -d/--date.
1517
1519
1518 Returns 0 on success, 1 if nothing changed.
1520 Returns 0 on success, 1 if nothing changed.
1519
1521
1520 .. container:: verbose
1522 .. container:: verbose
1521
1523
1522 Examples:
1524 Examples:
1523
1525
1524 - commit all files ending in .py::
1526 - commit all files ending in .py::
1525
1527
1526 hg commit --include "set:**.py"
1528 hg commit --include "set:**.py"
1527
1529
1528 - commit all non-binary files::
1530 - commit all non-binary files::
1529
1531
1530 hg commit --exclude "set:binary()"
1532 hg commit --exclude "set:binary()"
1531
1533
1532 - amend the current commit and set the date to now::
1534 - amend the current commit and set the date to now::
1533
1535
1534 hg commit --amend --date now
1536 hg commit --amend --date now
1535 """
1537 """
1536 wlock = lock = None
1538 wlock = lock = None
1537 try:
1539 try:
1538 wlock = repo.wlock()
1540 wlock = repo.wlock()
1539 lock = repo.lock()
1541 lock = repo.lock()
1540 return _docommit(ui, repo, *pats, **opts)
1542 return _docommit(ui, repo, *pats, **opts)
1541 finally:
1543 finally:
1542 release(lock, wlock)
1544 release(lock, wlock)
1543
1545
1544 def _docommit(ui, repo, *pats, **opts):
1546 def _docommit(ui, repo, *pats, **opts):
1545 if opts.get(r'interactive'):
1547 if opts.get(r'interactive'):
1546 opts.pop(r'interactive')
1548 opts.pop(r'interactive')
1547 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1549 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1548 cmdutil.recordfilter, *pats,
1550 cmdutil.recordfilter, *pats,
1549 **opts)
1551 **opts)
1550 # ret can be 0 (no changes to record) or the value returned by
1552 # ret can be 0 (no changes to record) or the value returned by
1551 # commit(), 1 if nothing changed or None on success.
1553 # commit(), 1 if nothing changed or None on success.
1552 return 1 if ret == 0 else ret
1554 return 1 if ret == 0 else ret
1553
1555
1554 opts = pycompat.byteskwargs(opts)
1556 opts = pycompat.byteskwargs(opts)
1555 if opts.get('subrepos'):
1557 if opts.get('subrepos'):
1556 if opts.get('amend'):
1558 if opts.get('amend'):
1557 raise error.Abort(_('cannot amend with --subrepos'))
1559 raise error.Abort(_('cannot amend with --subrepos'))
1558 # Let --subrepos on the command line override config setting.
1560 # Let --subrepos on the command line override config setting.
1559 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1561 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1560
1562
1561 cmdutil.checkunfinished(repo, commit=True)
1563 cmdutil.checkunfinished(repo, commit=True)
1562
1564
1563 branch = repo[None].branch()
1565 branch = repo[None].branch()
1564 bheads = repo.branchheads(branch)
1566 bheads = repo.branchheads(branch)
1565
1567
1566 extra = {}
1568 extra = {}
1567 if opts.get('close_branch'):
1569 if opts.get('close_branch'):
1568 extra['close'] = '1'
1570 extra['close'] = '1'
1569
1571
1570 if not bheads:
1572 if not bheads:
1571 raise error.Abort(_('can only close branch heads'))
1573 raise error.Abort(_('can only close branch heads'))
1572 elif opts.get('amend'):
1574 elif opts.get('amend'):
1573 if repo[None].parents()[0].p1().branch() != branch and \
1575 if repo[None].parents()[0].p1().branch() != branch and \
1574 repo[None].parents()[0].p2().branch() != branch:
1576 repo[None].parents()[0].p2().branch() != branch:
1575 raise error.Abort(_('can only close branch heads'))
1577 raise error.Abort(_('can only close branch heads'))
1576
1578
1577 if opts.get('amend'):
1579 if opts.get('amend'):
1578 if ui.configbool('ui', 'commitsubrepos'):
1580 if ui.configbool('ui', 'commitsubrepos'):
1579 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1581 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1580
1582
1581 old = repo['.']
1583 old = repo['.']
1582 rewriteutil.precheck(repo, [old.rev()], 'amend')
1584 rewriteutil.precheck(repo, [old.rev()], 'amend')
1583
1585
1584 # Currently histedit gets confused if an amend happens while histedit
1586 # Currently histedit gets confused if an amend happens while histedit
1585 # is in progress. Since we have a checkunfinished command, we are
1587 # is in progress. Since we have a checkunfinished command, we are
1586 # temporarily honoring it.
1588 # temporarily honoring it.
1587 #
1589 #
1588 # Note: eventually this guard will be removed. Please do not expect
1590 # Note: eventually this guard will be removed. Please do not expect
1589 # this behavior to remain.
1591 # this behavior to remain.
1590 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1592 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1591 cmdutil.checkunfinished(repo)
1593 cmdutil.checkunfinished(repo)
1592
1594
1593 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1595 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1594 if node == old.node():
1596 if node == old.node():
1595 ui.status(_("nothing changed\n"))
1597 ui.status(_("nothing changed\n"))
1596 return 1
1598 return 1
1597 else:
1599 else:
1598 def commitfunc(ui, repo, message, match, opts):
1600 def commitfunc(ui, repo, message, match, opts):
1599 overrides = {}
1601 overrides = {}
1600 if opts.get('secret'):
1602 if opts.get('secret'):
1601 overrides[('phases', 'new-commit')] = 'secret'
1603 overrides[('phases', 'new-commit')] = 'secret'
1602
1604
1603 baseui = repo.baseui
1605 baseui = repo.baseui
1604 with baseui.configoverride(overrides, 'commit'):
1606 with baseui.configoverride(overrides, 'commit'):
1605 with ui.configoverride(overrides, 'commit'):
1607 with ui.configoverride(overrides, 'commit'):
1606 editform = cmdutil.mergeeditform(repo[None],
1608 editform = cmdutil.mergeeditform(repo[None],
1607 'commit.normal')
1609 'commit.normal')
1608 editor = cmdutil.getcommiteditor(
1610 editor = cmdutil.getcommiteditor(
1609 editform=editform, **pycompat.strkwargs(opts))
1611 editform=editform, **pycompat.strkwargs(opts))
1610 return repo.commit(message,
1612 return repo.commit(message,
1611 opts.get('user'),
1613 opts.get('user'),
1612 opts.get('date'),
1614 opts.get('date'),
1613 match,
1615 match,
1614 editor=editor,
1616 editor=editor,
1615 extra=extra)
1617 extra=extra)
1616
1618
1617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1619 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1618
1620
1619 if not node:
1621 if not node:
1620 stat = cmdutil.postcommitstatus(repo, pats, opts)
1622 stat = cmdutil.postcommitstatus(repo, pats, opts)
1621 if stat[3]:
1623 if stat[3]:
1622 ui.status(_("nothing changed (%d missing files, see "
1624 ui.status(_("nothing changed (%d missing files, see "
1623 "'hg status')\n") % len(stat[3]))
1625 "'hg status')\n") % len(stat[3]))
1624 else:
1626 else:
1625 ui.status(_("nothing changed\n"))
1627 ui.status(_("nothing changed\n"))
1626 return 1
1628 return 1
1627
1629
1628 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1630 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1629
1631
1630 @command('config|showconfig|debugconfig',
1632 @command('config|showconfig|debugconfig',
1631 [('u', 'untrusted', None, _('show untrusted configuration options')),
1633 [('u', 'untrusted', None, _('show untrusted configuration options')),
1632 ('e', 'edit', None, _('edit user config')),
1634 ('e', 'edit', None, _('edit user config')),
1633 ('l', 'local', None, _('edit repository config')),
1635 ('l', 'local', None, _('edit repository config')),
1634 ('g', 'global', None, _('edit global config'))] + formatteropts,
1636 ('g', 'global', None, _('edit global config'))] + formatteropts,
1635 _('[-u] [NAME]...'),
1637 _('[-u] [NAME]...'),
1636 optionalrepo=True, cmdtype=readonly)
1638 optionalrepo=True,
1639 intents={INTENT_READONLY})
1637 def config(ui, repo, *values, **opts):
1640 def config(ui, repo, *values, **opts):
1638 """show combined config settings from all hgrc files
1641 """show combined config settings from all hgrc files
1639
1642
1640 With no arguments, print names and values of all config items.
1643 With no arguments, print names and values of all config items.
1641
1644
1642 With one argument of the form section.name, print just the value
1645 With one argument of the form section.name, print just the value
1643 of that config item.
1646 of that config item.
1644
1647
1645 With multiple arguments, print names and values of all config
1648 With multiple arguments, print names and values of all config
1646 items with matching section names or section.names.
1649 items with matching section names or section.names.
1647
1650
1648 With --edit, start an editor on the user-level config file. With
1651 With --edit, start an editor on the user-level config file. With
1649 --global, edit the system-wide config file. With --local, edit the
1652 --global, edit the system-wide config file. With --local, edit the
1650 repository-level config file.
1653 repository-level config file.
1651
1654
1652 With --debug, the source (filename and line number) is printed
1655 With --debug, the source (filename and line number) is printed
1653 for each config item.
1656 for each config item.
1654
1657
1655 See :hg:`help config` for more information about config files.
1658 See :hg:`help config` for more information about config files.
1656
1659
1657 Returns 0 on success, 1 if NAME does not exist.
1660 Returns 0 on success, 1 if NAME does not exist.
1658
1661
1659 """
1662 """
1660
1663
1661 opts = pycompat.byteskwargs(opts)
1664 opts = pycompat.byteskwargs(opts)
1662 if opts.get('edit') or opts.get('local') or opts.get('global'):
1665 if opts.get('edit') or opts.get('local') or opts.get('global'):
1663 if opts.get('local') and opts.get('global'):
1666 if opts.get('local') and opts.get('global'):
1664 raise error.Abort(_("can't use --local and --global together"))
1667 raise error.Abort(_("can't use --local and --global together"))
1665
1668
1666 if opts.get('local'):
1669 if opts.get('local'):
1667 if not repo:
1670 if not repo:
1668 raise error.Abort(_("can't use --local outside a repository"))
1671 raise error.Abort(_("can't use --local outside a repository"))
1669 paths = [repo.vfs.join('hgrc')]
1672 paths = [repo.vfs.join('hgrc')]
1670 elif opts.get('global'):
1673 elif opts.get('global'):
1671 paths = rcutil.systemrcpath()
1674 paths = rcutil.systemrcpath()
1672 else:
1675 else:
1673 paths = rcutil.userrcpath()
1676 paths = rcutil.userrcpath()
1674
1677
1675 for f in paths:
1678 for f in paths:
1676 if os.path.exists(f):
1679 if os.path.exists(f):
1677 break
1680 break
1678 else:
1681 else:
1679 if opts.get('global'):
1682 if opts.get('global'):
1680 samplehgrc = uimod.samplehgrcs['global']
1683 samplehgrc = uimod.samplehgrcs['global']
1681 elif opts.get('local'):
1684 elif opts.get('local'):
1682 samplehgrc = uimod.samplehgrcs['local']
1685 samplehgrc = uimod.samplehgrcs['local']
1683 else:
1686 else:
1684 samplehgrc = uimod.samplehgrcs['user']
1687 samplehgrc = uimod.samplehgrcs['user']
1685
1688
1686 f = paths[0]
1689 f = paths[0]
1687 fp = open(f, "wb")
1690 fp = open(f, "wb")
1688 fp.write(util.tonativeeol(samplehgrc))
1691 fp.write(util.tonativeeol(samplehgrc))
1689 fp.close()
1692 fp.close()
1690
1693
1691 editor = ui.geteditor()
1694 editor = ui.geteditor()
1692 ui.system("%s \"%s\"" % (editor, f),
1695 ui.system("%s \"%s\"" % (editor, f),
1693 onerr=error.Abort, errprefix=_("edit failed"),
1696 onerr=error.Abort, errprefix=_("edit failed"),
1694 blockedtag='config_edit')
1697 blockedtag='config_edit')
1695 return
1698 return
1696 ui.pager('config')
1699 ui.pager('config')
1697 fm = ui.formatter('config', opts)
1700 fm = ui.formatter('config', opts)
1698 for t, f in rcutil.rccomponents():
1701 for t, f in rcutil.rccomponents():
1699 if t == 'path':
1702 if t == 'path':
1700 ui.debug('read config from: %s\n' % f)
1703 ui.debug('read config from: %s\n' % f)
1701 elif t == 'items':
1704 elif t == 'items':
1702 for section, name, value, source in f:
1705 for section, name, value, source in f:
1703 ui.debug('set config by: %s\n' % source)
1706 ui.debug('set config by: %s\n' % source)
1704 else:
1707 else:
1705 raise error.ProgrammingError('unknown rctype: %s' % t)
1708 raise error.ProgrammingError('unknown rctype: %s' % t)
1706 untrusted = bool(opts.get('untrusted'))
1709 untrusted = bool(opts.get('untrusted'))
1707
1710
1708 selsections = selentries = []
1711 selsections = selentries = []
1709 if values:
1712 if values:
1710 selsections = [v for v in values if '.' not in v]
1713 selsections = [v for v in values if '.' not in v]
1711 selentries = [v for v in values if '.' in v]
1714 selentries = [v for v in values if '.' in v]
1712 uniquesel = (len(selentries) == 1 and not selsections)
1715 uniquesel = (len(selentries) == 1 and not selsections)
1713 selsections = set(selsections)
1716 selsections = set(selsections)
1714 selentries = set(selentries)
1717 selentries = set(selentries)
1715
1718
1716 matched = False
1719 matched = False
1717 for section, name, value in ui.walkconfig(untrusted=untrusted):
1720 for section, name, value in ui.walkconfig(untrusted=untrusted):
1718 source = ui.configsource(section, name, untrusted)
1721 source = ui.configsource(section, name, untrusted)
1719 value = pycompat.bytestr(value)
1722 value = pycompat.bytestr(value)
1720 if fm.isplain():
1723 if fm.isplain():
1721 source = source or 'none'
1724 source = source or 'none'
1722 value = value.replace('\n', '\\n')
1725 value = value.replace('\n', '\\n')
1723 entryname = section + '.' + name
1726 entryname = section + '.' + name
1724 if values and not (section in selsections or entryname in selentries):
1727 if values and not (section in selsections or entryname in selentries):
1725 continue
1728 continue
1726 fm.startitem()
1729 fm.startitem()
1727 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1730 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1728 if uniquesel:
1731 if uniquesel:
1729 fm.data(name=entryname)
1732 fm.data(name=entryname)
1730 fm.write('value', '%s\n', value)
1733 fm.write('value', '%s\n', value)
1731 else:
1734 else:
1732 fm.write('name value', '%s=%s\n', entryname, value)
1735 fm.write('name value', '%s=%s\n', entryname, value)
1733 matched = True
1736 matched = True
1734 fm.end()
1737 fm.end()
1735 if matched:
1738 if matched:
1736 return 0
1739 return 0
1737 return 1
1740 return 1
1738
1741
1739 @command('copy|cp',
1742 @command('copy|cp',
1740 [('A', 'after', None, _('record a copy that has already occurred')),
1743 [('A', 'after', None, _('record a copy that has already occurred')),
1741 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1744 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1742 ] + walkopts + dryrunopts,
1745 ] + walkopts + dryrunopts,
1743 _('[OPTION]... [SOURCE]... DEST'))
1746 _('[OPTION]... [SOURCE]... DEST'))
1744 def copy(ui, repo, *pats, **opts):
1747 def copy(ui, repo, *pats, **opts):
1745 """mark files as copied for the next commit
1748 """mark files as copied for the next commit
1746
1749
1747 Mark dest as having copies of source files. If dest is a
1750 Mark dest as having copies of source files. If dest is a
1748 directory, copies are put in that directory. If dest is a file,
1751 directory, copies are put in that directory. If dest is a file,
1749 the source must be a single file.
1752 the source must be a single file.
1750
1753
1751 By default, this command copies the contents of files as they
1754 By default, this command copies the contents of files as they
1752 exist in the working directory. If invoked with -A/--after, the
1755 exist in the working directory. If invoked with -A/--after, the
1753 operation is recorded, but no copying is performed.
1756 operation is recorded, but no copying is performed.
1754
1757
1755 This command takes effect with the next commit. To undo a copy
1758 This command takes effect with the next commit. To undo a copy
1756 before that, see :hg:`revert`.
1759 before that, see :hg:`revert`.
1757
1760
1758 Returns 0 on success, 1 if errors are encountered.
1761 Returns 0 on success, 1 if errors are encountered.
1759 """
1762 """
1760 opts = pycompat.byteskwargs(opts)
1763 opts = pycompat.byteskwargs(opts)
1761 with repo.wlock(False):
1764 with repo.wlock(False):
1762 return cmdutil.copy(ui, repo, pats, opts)
1765 return cmdutil.copy(ui, repo, pats, opts)
1763
1766
1764 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1767 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1765 def debugcommands(ui, cmd='', *args):
1768 def debugcommands(ui, cmd='', *args):
1766 """list all available commands and options"""
1769 """list all available commands and options"""
1767 for cmd, vals in sorted(table.iteritems()):
1770 for cmd, vals in sorted(table.iteritems()):
1768 cmd = cmd.split('|')[0].strip('^')
1771 cmd = cmd.split('|')[0].strip('^')
1769 opts = ', '.join([i[1] for i in vals[1]])
1772 opts = ', '.join([i[1] for i in vals[1]])
1770 ui.write('%s: %s\n' % (cmd, opts))
1773 ui.write('%s: %s\n' % (cmd, opts))
1771
1774
1772 @command('debugcomplete',
1775 @command('debugcomplete',
1773 [('o', 'options', None, _('show the command options'))],
1776 [('o', 'options', None, _('show the command options'))],
1774 _('[-o] CMD'),
1777 _('[-o] CMD'),
1775 norepo=True)
1778 norepo=True)
1776 def debugcomplete(ui, cmd='', **opts):
1779 def debugcomplete(ui, cmd='', **opts):
1777 """returns the completion list associated with the given command"""
1780 """returns the completion list associated with the given command"""
1778
1781
1779 if opts.get(r'options'):
1782 if opts.get(r'options'):
1780 options = []
1783 options = []
1781 otables = [globalopts]
1784 otables = [globalopts]
1782 if cmd:
1785 if cmd:
1783 aliases, entry = cmdutil.findcmd(cmd, table, False)
1786 aliases, entry = cmdutil.findcmd(cmd, table, False)
1784 otables.append(entry[1])
1787 otables.append(entry[1])
1785 for t in otables:
1788 for t in otables:
1786 for o in t:
1789 for o in t:
1787 if "(DEPRECATED)" in o[3]:
1790 if "(DEPRECATED)" in o[3]:
1788 continue
1791 continue
1789 if o[0]:
1792 if o[0]:
1790 options.append('-%s' % o[0])
1793 options.append('-%s' % o[0])
1791 options.append('--%s' % o[1])
1794 options.append('--%s' % o[1])
1792 ui.write("%s\n" % "\n".join(options))
1795 ui.write("%s\n" % "\n".join(options))
1793 return
1796 return
1794
1797
1795 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1798 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1796 if ui.verbose:
1799 if ui.verbose:
1797 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1800 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1798 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1801 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1799
1802
1800 @command('^diff',
1803 @command('^diff',
1801 [('r', 'rev', [], _('revision'), _('REV')),
1804 [('r', 'rev', [], _('revision'), _('REV')),
1802 ('c', 'change', '', _('change made by revision'), _('REV'))
1805 ('c', 'change', '', _('change made by revision'), _('REV'))
1803 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1806 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1804 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1807 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1805 inferrepo=True, cmdtype=readonly)
1808 inferrepo=True,
1809 intents={INTENT_READONLY})
1806 def diff(ui, repo, *pats, **opts):
1810 def diff(ui, repo, *pats, **opts):
1807 """diff repository (or selected files)
1811 """diff repository (or selected files)
1808
1812
1809 Show differences between revisions for the specified files.
1813 Show differences between revisions for the specified files.
1810
1814
1811 Differences between files are shown using the unified diff format.
1815 Differences between files are shown using the unified diff format.
1812
1816
1813 .. note::
1817 .. note::
1814
1818
1815 :hg:`diff` may generate unexpected results for merges, as it will
1819 :hg:`diff` may generate unexpected results for merges, as it will
1816 default to comparing against the working directory's first
1820 default to comparing against the working directory's first
1817 parent changeset if no revisions are specified.
1821 parent changeset if no revisions are specified.
1818
1822
1819 When two revision arguments are given, then changes are shown
1823 When two revision arguments are given, then changes are shown
1820 between those revisions. If only one revision is specified then
1824 between those revisions. If only one revision is specified then
1821 that revision is compared to the working directory, and, when no
1825 that revision is compared to the working directory, and, when no
1822 revisions are specified, the working directory files are compared
1826 revisions are specified, the working directory files are compared
1823 to its first parent.
1827 to its first parent.
1824
1828
1825 Alternatively you can specify -c/--change with a revision to see
1829 Alternatively you can specify -c/--change with a revision to see
1826 the changes in that changeset relative to its first parent.
1830 the changes in that changeset relative to its first parent.
1827
1831
1828 Without the -a/--text option, diff will avoid generating diffs of
1832 Without the -a/--text option, diff will avoid generating diffs of
1829 files it detects as binary. With -a, diff will generate a diff
1833 files it detects as binary. With -a, diff will generate a diff
1830 anyway, probably with undesirable results.
1834 anyway, probably with undesirable results.
1831
1835
1832 Use the -g/--git option to generate diffs in the git extended diff
1836 Use the -g/--git option to generate diffs in the git extended diff
1833 format. For more information, read :hg:`help diffs`.
1837 format. For more information, read :hg:`help diffs`.
1834
1838
1835 .. container:: verbose
1839 .. container:: verbose
1836
1840
1837 Examples:
1841 Examples:
1838
1842
1839 - compare a file in the current working directory to its parent::
1843 - compare a file in the current working directory to its parent::
1840
1844
1841 hg diff foo.c
1845 hg diff foo.c
1842
1846
1843 - compare two historical versions of a directory, with rename info::
1847 - compare two historical versions of a directory, with rename info::
1844
1848
1845 hg diff --git -r 1.0:1.2 lib/
1849 hg diff --git -r 1.0:1.2 lib/
1846
1850
1847 - get change stats relative to the last change on some date::
1851 - get change stats relative to the last change on some date::
1848
1852
1849 hg diff --stat -r "date('may 2')"
1853 hg diff --stat -r "date('may 2')"
1850
1854
1851 - diff all newly-added files that contain a keyword::
1855 - diff all newly-added files that contain a keyword::
1852
1856
1853 hg diff "set:added() and grep(GNU)"
1857 hg diff "set:added() and grep(GNU)"
1854
1858
1855 - compare a revision and its parents::
1859 - compare a revision and its parents::
1856
1860
1857 hg diff -c 9353 # compare against first parent
1861 hg diff -c 9353 # compare against first parent
1858 hg diff -r 9353^:9353 # same using revset syntax
1862 hg diff -r 9353^:9353 # same using revset syntax
1859 hg diff -r 9353^2:9353 # compare against the second parent
1863 hg diff -r 9353^2:9353 # compare against the second parent
1860
1864
1861 Returns 0 on success.
1865 Returns 0 on success.
1862 """
1866 """
1863
1867
1864 opts = pycompat.byteskwargs(opts)
1868 opts = pycompat.byteskwargs(opts)
1865 revs = opts.get('rev')
1869 revs = opts.get('rev')
1866 change = opts.get('change')
1870 change = opts.get('change')
1867 stat = opts.get('stat')
1871 stat = opts.get('stat')
1868 reverse = opts.get('reverse')
1872 reverse = opts.get('reverse')
1869
1873
1870 if revs and change:
1874 if revs and change:
1871 msg = _('cannot specify --rev and --change at the same time')
1875 msg = _('cannot specify --rev and --change at the same time')
1872 raise error.Abort(msg)
1876 raise error.Abort(msg)
1873 elif change:
1877 elif change:
1874 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1878 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1875 ctx2 = scmutil.revsingle(repo, change, None)
1879 ctx2 = scmutil.revsingle(repo, change, None)
1876 ctx1 = ctx2.p1()
1880 ctx1 = ctx2.p1()
1877 else:
1881 else:
1878 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1882 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1879 ctx1, ctx2 = scmutil.revpair(repo, revs)
1883 ctx1, ctx2 = scmutil.revpair(repo, revs)
1880 node1, node2 = ctx1.node(), ctx2.node()
1884 node1, node2 = ctx1.node(), ctx2.node()
1881
1885
1882 if reverse:
1886 if reverse:
1883 node1, node2 = node2, node1
1887 node1, node2 = node2, node1
1884
1888
1885 diffopts = patch.diffallopts(ui, opts)
1889 diffopts = patch.diffallopts(ui, opts)
1886 m = scmutil.match(ctx2, pats, opts)
1890 m = scmutil.match(ctx2, pats, opts)
1887 ui.pager('diff')
1891 ui.pager('diff')
1888 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1892 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1889 listsubrepos=opts.get('subrepos'),
1893 listsubrepos=opts.get('subrepos'),
1890 root=opts.get('root'))
1894 root=opts.get('root'))
1891
1895
1892 @command('^export',
1896 @command('^export',
1893 [('o', 'output', '',
1897 [('o', 'output', '',
1894 _('print output to file with formatted name'), _('FORMAT')),
1898 _('print output to file with formatted name'), _('FORMAT')),
1895 ('', 'switch-parent', None, _('diff against the second parent')),
1899 ('', 'switch-parent', None, _('diff against the second parent')),
1896 ('r', 'rev', [], _('revisions to export'), _('REV')),
1900 ('r', 'rev', [], _('revisions to export'), _('REV')),
1897 ] + diffopts + formatteropts,
1901 ] + diffopts + formatteropts,
1898 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1902 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1903 intents={INTENT_READONLY})
1899 def export(ui, repo, *changesets, **opts):
1904 def export(ui, repo, *changesets, **opts):
1900 """dump the header and diffs for one or more changesets
1905 """dump the header and diffs for one or more changesets
1901
1906
1902 Print the changeset header and diffs for one or more revisions.
1907 Print the changeset header and diffs for one or more revisions.
1903 If no revision is given, the parent of the working directory is used.
1908 If no revision is given, the parent of the working directory is used.
1904
1909
1905 The information shown in the changeset header is: author, date,
1910 The information shown in the changeset header is: author, date,
1906 branch name (if non-default), changeset hash, parent(s) and commit
1911 branch name (if non-default), changeset hash, parent(s) and commit
1907 comment.
1912 comment.
1908
1913
1909 .. note::
1914 .. note::
1910
1915
1911 :hg:`export` may generate unexpected diff output for merge
1916 :hg:`export` may generate unexpected diff output for merge
1912 changesets, as it will compare the merge changeset against its
1917 changesets, as it will compare the merge changeset against its
1913 first parent only.
1918 first parent only.
1914
1919
1915 Output may be to a file, in which case the name of the file is
1920 Output may be to a file, in which case the name of the file is
1916 given using a template string. See :hg:`help templates`. In addition
1921 given using a template string. See :hg:`help templates`. In addition
1917 to the common template keywords, the following formatting rules are
1922 to the common template keywords, the following formatting rules are
1918 supported:
1923 supported:
1919
1924
1920 :``%%``: literal "%" character
1925 :``%%``: literal "%" character
1921 :``%H``: changeset hash (40 hexadecimal digits)
1926 :``%H``: changeset hash (40 hexadecimal digits)
1922 :``%N``: number of patches being generated
1927 :``%N``: number of patches being generated
1923 :``%R``: changeset revision number
1928 :``%R``: changeset revision number
1924 :``%b``: basename of the exporting repository
1929 :``%b``: basename of the exporting repository
1925 :``%h``: short-form changeset hash (12 hexadecimal digits)
1930 :``%h``: short-form changeset hash (12 hexadecimal digits)
1926 :``%m``: first line of the commit message (only alphanumeric characters)
1931 :``%m``: first line of the commit message (only alphanumeric characters)
1927 :``%n``: zero-padded sequence number, starting at 1
1932 :``%n``: zero-padded sequence number, starting at 1
1928 :``%r``: zero-padded changeset revision number
1933 :``%r``: zero-padded changeset revision number
1929 :``\\``: literal "\\" character
1934 :``\\``: literal "\\" character
1930
1935
1931 Without the -a/--text option, export will avoid generating diffs
1936 Without the -a/--text option, export will avoid generating diffs
1932 of files it detects as binary. With -a, export will generate a
1937 of files it detects as binary. With -a, export will generate a
1933 diff anyway, probably with undesirable results.
1938 diff anyway, probably with undesirable results.
1934
1939
1935 Use the -g/--git option to generate diffs in the git extended diff
1940 Use the -g/--git option to generate diffs in the git extended diff
1936 format. See :hg:`help diffs` for more information.
1941 format. See :hg:`help diffs` for more information.
1937
1942
1938 With the --switch-parent option, the diff will be against the
1943 With the --switch-parent option, the diff will be against the
1939 second parent. It can be useful to review a merge.
1944 second parent. It can be useful to review a merge.
1940
1945
1941 .. container:: verbose
1946 .. container:: verbose
1942
1947
1943 Examples:
1948 Examples:
1944
1949
1945 - use export and import to transplant a bugfix to the current
1950 - use export and import to transplant a bugfix to the current
1946 branch::
1951 branch::
1947
1952
1948 hg export -r 9353 | hg import -
1953 hg export -r 9353 | hg import -
1949
1954
1950 - export all the changesets between two revisions to a file with
1955 - export all the changesets between two revisions to a file with
1951 rename information::
1956 rename information::
1952
1957
1953 hg export --git -r 123:150 > changes.txt
1958 hg export --git -r 123:150 > changes.txt
1954
1959
1955 - split outgoing changes into a series of patches with
1960 - split outgoing changes into a series of patches with
1956 descriptive names::
1961 descriptive names::
1957
1962
1958 hg export -r "outgoing()" -o "%n-%m.patch"
1963 hg export -r "outgoing()" -o "%n-%m.patch"
1959
1964
1960 Returns 0 on success.
1965 Returns 0 on success.
1961 """
1966 """
1962 opts = pycompat.byteskwargs(opts)
1967 opts = pycompat.byteskwargs(opts)
1963 changesets += tuple(opts.get('rev', []))
1968 changesets += tuple(opts.get('rev', []))
1964 if not changesets:
1969 if not changesets:
1965 changesets = ['.']
1970 changesets = ['.']
1966 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1971 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1967 revs = scmutil.revrange(repo, changesets)
1972 revs = scmutil.revrange(repo, changesets)
1968 if not revs:
1973 if not revs:
1969 raise error.Abort(_("export requires at least one changeset"))
1974 raise error.Abort(_("export requires at least one changeset"))
1970 if len(revs) > 1:
1975 if len(revs) > 1:
1971 ui.note(_('exporting patches:\n'))
1976 ui.note(_('exporting patches:\n'))
1972 else:
1977 else:
1973 ui.note(_('exporting patch:\n'))
1978 ui.note(_('exporting patch:\n'))
1974
1979
1975 fntemplate = opts.get('output')
1980 fntemplate = opts.get('output')
1976 if cmdutil.isstdiofilename(fntemplate):
1981 if cmdutil.isstdiofilename(fntemplate):
1977 fntemplate = ''
1982 fntemplate = ''
1978
1983
1979 if fntemplate:
1984 if fntemplate:
1980 fm = formatter.nullformatter(ui, 'export', opts)
1985 fm = formatter.nullformatter(ui, 'export', opts)
1981 else:
1986 else:
1982 ui.pager('export')
1987 ui.pager('export')
1983 fm = ui.formatter('export', opts)
1988 fm = ui.formatter('export', opts)
1984 with fm:
1989 with fm:
1985 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
1990 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
1986 switch_parent=opts.get('switch_parent'),
1991 switch_parent=opts.get('switch_parent'),
1987 opts=patch.diffallopts(ui, opts))
1992 opts=patch.diffallopts(ui, opts))
1988
1993
1989 @command('files',
1994 @command('files',
1990 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1995 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1991 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1996 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1992 ] + walkopts + formatteropts + subrepoopts,
1997 ] + walkopts + formatteropts + subrepoopts,
1993 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1998 _('[OPTION]... [FILE]...'),
1999 intents={INTENT_READONLY})
1994 def files(ui, repo, *pats, **opts):
2000 def files(ui, repo, *pats, **opts):
1995 """list tracked files
2001 """list tracked files
1996
2002
1997 Print files under Mercurial control in the working directory or
2003 Print files under Mercurial control in the working directory or
1998 specified revision for given files (excluding removed files).
2004 specified revision for given files (excluding removed files).
1999 Files can be specified as filenames or filesets.
2005 Files can be specified as filenames or filesets.
2000
2006
2001 If no files are given to match, this command prints the names
2007 If no files are given to match, this command prints the names
2002 of all files under Mercurial control.
2008 of all files under Mercurial control.
2003
2009
2004 .. container:: verbose
2010 .. container:: verbose
2005
2011
2006 Examples:
2012 Examples:
2007
2013
2008 - list all files under the current directory::
2014 - list all files under the current directory::
2009
2015
2010 hg files .
2016 hg files .
2011
2017
2012 - shows sizes and flags for current revision::
2018 - shows sizes and flags for current revision::
2013
2019
2014 hg files -vr .
2020 hg files -vr .
2015
2021
2016 - list all files named README::
2022 - list all files named README::
2017
2023
2018 hg files -I "**/README"
2024 hg files -I "**/README"
2019
2025
2020 - list all binary files::
2026 - list all binary files::
2021
2027
2022 hg files "set:binary()"
2028 hg files "set:binary()"
2023
2029
2024 - find files containing a regular expression::
2030 - find files containing a regular expression::
2025
2031
2026 hg files "set:grep('bob')"
2032 hg files "set:grep('bob')"
2027
2033
2028 - search tracked file contents with xargs and grep::
2034 - search tracked file contents with xargs and grep::
2029
2035
2030 hg files -0 | xargs -0 grep foo
2036 hg files -0 | xargs -0 grep foo
2031
2037
2032 See :hg:`help patterns` and :hg:`help filesets` for more information
2038 See :hg:`help patterns` and :hg:`help filesets` for more information
2033 on specifying file patterns.
2039 on specifying file patterns.
2034
2040
2035 Returns 0 if a match is found, 1 otherwise.
2041 Returns 0 if a match is found, 1 otherwise.
2036
2042
2037 """
2043 """
2038
2044
2039 opts = pycompat.byteskwargs(opts)
2045 opts = pycompat.byteskwargs(opts)
2040 rev = opts.get('rev')
2046 rev = opts.get('rev')
2041 if rev:
2047 if rev:
2042 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2048 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2043 ctx = scmutil.revsingle(repo, rev, None)
2049 ctx = scmutil.revsingle(repo, rev, None)
2044
2050
2045 end = '\n'
2051 end = '\n'
2046 if opts.get('print0'):
2052 if opts.get('print0'):
2047 end = '\0'
2053 end = '\0'
2048 fmt = '%s' + end
2054 fmt = '%s' + end
2049
2055
2050 m = scmutil.match(ctx, pats, opts)
2056 m = scmutil.match(ctx, pats, opts)
2051 ui.pager('files')
2057 ui.pager('files')
2052 with ui.formatter('files', opts) as fm:
2058 with ui.formatter('files', opts) as fm:
2053 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2059 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2054
2060
2055 @command(
2061 @command(
2056 '^forget',
2062 '^forget',
2057 walkopts + dryrunopts,
2063 walkopts + dryrunopts,
2058 _('[OPTION]... FILE...'), inferrepo=True)
2064 _('[OPTION]... FILE...'), inferrepo=True)
2059 def forget(ui, repo, *pats, **opts):
2065 def forget(ui, repo, *pats, **opts):
2060 """forget the specified files on the next commit
2066 """forget the specified files on the next commit
2061
2067
2062 Mark the specified files so they will no longer be tracked
2068 Mark the specified files so they will no longer be tracked
2063 after the next commit.
2069 after the next commit.
2064
2070
2065 This only removes files from the current branch, not from the
2071 This only removes files from the current branch, not from the
2066 entire project history, and it does not delete them from the
2072 entire project history, and it does not delete them from the
2067 working directory.
2073 working directory.
2068
2074
2069 To delete the file from the working directory, see :hg:`remove`.
2075 To delete the file from the working directory, see :hg:`remove`.
2070
2076
2071 To undo a forget before the next commit, see :hg:`add`.
2077 To undo a forget before the next commit, see :hg:`add`.
2072
2078
2073 .. container:: verbose
2079 .. container:: verbose
2074
2080
2075 Examples:
2081 Examples:
2076
2082
2077 - forget newly-added binary files::
2083 - forget newly-added binary files::
2078
2084
2079 hg forget "set:added() and binary()"
2085 hg forget "set:added() and binary()"
2080
2086
2081 - forget files that would be excluded by .hgignore::
2087 - forget files that would be excluded by .hgignore::
2082
2088
2083 hg forget "set:hgignore()"
2089 hg forget "set:hgignore()"
2084
2090
2085 Returns 0 on success.
2091 Returns 0 on success.
2086 """
2092 """
2087
2093
2088 opts = pycompat.byteskwargs(opts)
2094 opts = pycompat.byteskwargs(opts)
2089 if not pats:
2095 if not pats:
2090 raise error.Abort(_('no files specified'))
2096 raise error.Abort(_('no files specified'))
2091
2097
2092 m = scmutil.match(repo[None], pats, opts)
2098 m = scmutil.match(repo[None], pats, opts)
2093 dryrun = opts.get('dry_run')
2099 dryrun = opts.get('dry_run')
2094 rejected = cmdutil.forget(ui, repo, m, prefix="",
2100 rejected = cmdutil.forget(ui, repo, m, prefix="",
2095 explicitonly=False, dryrun=dryrun)[0]
2101 explicitonly=False, dryrun=dryrun)[0]
2096 return rejected and 1 or 0
2102 return rejected and 1 or 0
2097
2103
2098 @command(
2104 @command(
2099 'graft',
2105 'graft',
2100 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2106 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2101 ('c', 'continue', False, _('resume interrupted graft')),
2107 ('c', 'continue', False, _('resume interrupted graft')),
2102 ('e', 'edit', False, _('invoke editor on commit messages')),
2108 ('e', 'edit', False, _('invoke editor on commit messages')),
2103 ('', 'log', None, _('append graft info to log message')),
2109 ('', 'log', None, _('append graft info to log message')),
2104 ('f', 'force', False, _('force graft')),
2110 ('f', 'force', False, _('force graft')),
2105 ('D', 'currentdate', False,
2111 ('D', 'currentdate', False,
2106 _('record the current date as commit date')),
2112 _('record the current date as commit date')),
2107 ('U', 'currentuser', False,
2113 ('U', 'currentuser', False,
2108 _('record the current user as committer'), _('DATE'))]
2114 _('record the current user as committer'), _('DATE'))]
2109 + commitopts2 + mergetoolopts + dryrunopts,
2115 + commitopts2 + mergetoolopts + dryrunopts,
2110 _('[OPTION]... [-r REV]... REV...'))
2116 _('[OPTION]... [-r REV]... REV...'))
2111 def graft(ui, repo, *revs, **opts):
2117 def graft(ui, repo, *revs, **opts):
2112 '''copy changes from other branches onto the current branch
2118 '''copy changes from other branches onto the current branch
2113
2119
2114 This command uses Mercurial's merge logic to copy individual
2120 This command uses Mercurial's merge logic to copy individual
2115 changes from other branches without merging branches in the
2121 changes from other branches without merging branches in the
2116 history graph. This is sometimes known as 'backporting' or
2122 history graph. This is sometimes known as 'backporting' or
2117 'cherry-picking'. By default, graft will copy user, date, and
2123 'cherry-picking'. By default, graft will copy user, date, and
2118 description from the source changesets.
2124 description from the source changesets.
2119
2125
2120 Changesets that are ancestors of the current revision, that have
2126 Changesets that are ancestors of the current revision, that have
2121 already been grafted, or that are merges will be skipped.
2127 already been grafted, or that are merges will be skipped.
2122
2128
2123 If --log is specified, log messages will have a comment appended
2129 If --log is specified, log messages will have a comment appended
2124 of the form::
2130 of the form::
2125
2131
2126 (grafted from CHANGESETHASH)
2132 (grafted from CHANGESETHASH)
2127
2133
2128 If --force is specified, revisions will be grafted even if they
2134 If --force is specified, revisions will be grafted even if they
2129 are already ancestors of, or have been grafted to, the destination.
2135 are already ancestors of, or have been grafted to, the destination.
2130 This is useful when the revisions have since been backed out.
2136 This is useful when the revisions have since been backed out.
2131
2137
2132 If a graft merge results in conflicts, the graft process is
2138 If a graft merge results in conflicts, the graft process is
2133 interrupted so that the current merge can be manually resolved.
2139 interrupted so that the current merge can be manually resolved.
2134 Once all conflicts are addressed, the graft process can be
2140 Once all conflicts are addressed, the graft process can be
2135 continued with the -c/--continue option.
2141 continued with the -c/--continue option.
2136
2142
2137 .. note::
2143 .. note::
2138
2144
2139 The -c/--continue option does not reapply earlier options, except
2145 The -c/--continue option does not reapply earlier options, except
2140 for --force.
2146 for --force.
2141
2147
2142 .. container:: verbose
2148 .. container:: verbose
2143
2149
2144 Examples:
2150 Examples:
2145
2151
2146 - copy a single change to the stable branch and edit its description::
2152 - copy a single change to the stable branch and edit its description::
2147
2153
2148 hg update stable
2154 hg update stable
2149 hg graft --edit 9393
2155 hg graft --edit 9393
2150
2156
2151 - graft a range of changesets with one exception, updating dates::
2157 - graft a range of changesets with one exception, updating dates::
2152
2158
2153 hg graft -D "2085::2093 and not 2091"
2159 hg graft -D "2085::2093 and not 2091"
2154
2160
2155 - continue a graft after resolving conflicts::
2161 - continue a graft after resolving conflicts::
2156
2162
2157 hg graft -c
2163 hg graft -c
2158
2164
2159 - show the source of a grafted changeset::
2165 - show the source of a grafted changeset::
2160
2166
2161 hg log --debug -r .
2167 hg log --debug -r .
2162
2168
2163 - show revisions sorted by date::
2169 - show revisions sorted by date::
2164
2170
2165 hg log -r "sort(all(), date)"
2171 hg log -r "sort(all(), date)"
2166
2172
2167 See :hg:`help revisions` for more about specifying revisions.
2173 See :hg:`help revisions` for more about specifying revisions.
2168
2174
2169 Returns 0 on successful completion.
2175 Returns 0 on successful completion.
2170 '''
2176 '''
2171 with repo.wlock():
2177 with repo.wlock():
2172 return _dograft(ui, repo, *revs, **opts)
2178 return _dograft(ui, repo, *revs, **opts)
2173
2179
2174 def _dograft(ui, repo, *revs, **opts):
2180 def _dograft(ui, repo, *revs, **opts):
2175 opts = pycompat.byteskwargs(opts)
2181 opts = pycompat.byteskwargs(opts)
2176 if revs and opts.get('rev'):
2182 if revs and opts.get('rev'):
2177 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2183 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2178 'revision ordering!\n'))
2184 'revision ordering!\n'))
2179
2185
2180 revs = list(revs)
2186 revs = list(revs)
2181 revs.extend(opts.get('rev'))
2187 revs.extend(opts.get('rev'))
2182
2188
2183 if not opts.get('user') and opts.get('currentuser'):
2189 if not opts.get('user') and opts.get('currentuser'):
2184 opts['user'] = ui.username()
2190 opts['user'] = ui.username()
2185 if not opts.get('date') and opts.get('currentdate'):
2191 if not opts.get('date') and opts.get('currentdate'):
2186 opts['date'] = "%d %d" % dateutil.makedate()
2192 opts['date'] = "%d %d" % dateutil.makedate()
2187
2193
2188 editor = cmdutil.getcommiteditor(editform='graft',
2194 editor = cmdutil.getcommiteditor(editform='graft',
2189 **pycompat.strkwargs(opts))
2195 **pycompat.strkwargs(opts))
2190
2196
2191 cont = False
2197 cont = False
2192 if opts.get('continue'):
2198 if opts.get('continue'):
2193 cont = True
2199 cont = True
2194 if revs:
2200 if revs:
2195 raise error.Abort(_("can't specify --continue and revisions"))
2201 raise error.Abort(_("can't specify --continue and revisions"))
2196 # read in unfinished revisions
2202 # read in unfinished revisions
2197 try:
2203 try:
2198 nodes = repo.vfs.read('graftstate').splitlines()
2204 nodes = repo.vfs.read('graftstate').splitlines()
2199 revs = [repo[node].rev() for node in nodes]
2205 revs = [repo[node].rev() for node in nodes]
2200 except IOError as inst:
2206 except IOError as inst:
2201 if inst.errno != errno.ENOENT:
2207 if inst.errno != errno.ENOENT:
2202 raise
2208 raise
2203 cmdutil.wrongtooltocontinue(repo, _('graft'))
2209 cmdutil.wrongtooltocontinue(repo, _('graft'))
2204 else:
2210 else:
2205 if not revs:
2211 if not revs:
2206 raise error.Abort(_('no revisions specified'))
2212 raise error.Abort(_('no revisions specified'))
2207 cmdutil.checkunfinished(repo)
2213 cmdutil.checkunfinished(repo)
2208 cmdutil.bailifchanged(repo)
2214 cmdutil.bailifchanged(repo)
2209 revs = scmutil.revrange(repo, revs)
2215 revs = scmutil.revrange(repo, revs)
2210
2216
2211 skipped = set()
2217 skipped = set()
2212 # check for merges
2218 # check for merges
2213 for rev in repo.revs('%ld and merge()', revs):
2219 for rev in repo.revs('%ld and merge()', revs):
2214 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2220 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2215 skipped.add(rev)
2221 skipped.add(rev)
2216 revs = [r for r in revs if r not in skipped]
2222 revs = [r for r in revs if r not in skipped]
2217 if not revs:
2223 if not revs:
2218 return -1
2224 return -1
2219
2225
2220 # Don't check in the --continue case, in effect retaining --force across
2226 # Don't check in the --continue case, in effect retaining --force across
2221 # --continues. That's because without --force, any revisions we decided to
2227 # --continues. That's because without --force, any revisions we decided to
2222 # skip would have been filtered out here, so they wouldn't have made their
2228 # skip would have been filtered out here, so they wouldn't have made their
2223 # way to the graftstate. With --force, any revisions we would have otherwise
2229 # way to the graftstate. With --force, any revisions we would have otherwise
2224 # skipped would not have been filtered out, and if they hadn't been applied
2230 # skipped would not have been filtered out, and if they hadn't been applied
2225 # already, they'd have been in the graftstate.
2231 # already, they'd have been in the graftstate.
2226 if not (cont or opts.get('force')):
2232 if not (cont or opts.get('force')):
2227 # check for ancestors of dest branch
2233 # check for ancestors of dest branch
2228 crev = repo['.'].rev()
2234 crev = repo['.'].rev()
2229 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2235 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2230 # XXX make this lazy in the future
2236 # XXX make this lazy in the future
2231 # don't mutate while iterating, create a copy
2237 # don't mutate while iterating, create a copy
2232 for rev in list(revs):
2238 for rev in list(revs):
2233 if rev in ancestors:
2239 if rev in ancestors:
2234 ui.warn(_('skipping ancestor revision %d:%s\n') %
2240 ui.warn(_('skipping ancestor revision %d:%s\n') %
2235 (rev, repo[rev]))
2241 (rev, repo[rev]))
2236 # XXX remove on list is slow
2242 # XXX remove on list is slow
2237 revs.remove(rev)
2243 revs.remove(rev)
2238 if not revs:
2244 if not revs:
2239 return -1
2245 return -1
2240
2246
2241 # analyze revs for earlier grafts
2247 # analyze revs for earlier grafts
2242 ids = {}
2248 ids = {}
2243 for ctx in repo.set("%ld", revs):
2249 for ctx in repo.set("%ld", revs):
2244 ids[ctx.hex()] = ctx.rev()
2250 ids[ctx.hex()] = ctx.rev()
2245 n = ctx.extra().get('source')
2251 n = ctx.extra().get('source')
2246 if n:
2252 if n:
2247 ids[n] = ctx.rev()
2253 ids[n] = ctx.rev()
2248
2254
2249 # check ancestors for earlier grafts
2255 # check ancestors for earlier grafts
2250 ui.debug('scanning for duplicate grafts\n')
2256 ui.debug('scanning for duplicate grafts\n')
2251
2257
2252 # The only changesets we can be sure doesn't contain grafts of any
2258 # The only changesets we can be sure doesn't contain grafts of any
2253 # revs, are the ones that are common ancestors of *all* revs:
2259 # revs, are the ones that are common ancestors of *all* revs:
2254 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2260 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2255 ctx = repo[rev]
2261 ctx = repo[rev]
2256 n = ctx.extra().get('source')
2262 n = ctx.extra().get('source')
2257 if n in ids:
2263 if n in ids:
2258 try:
2264 try:
2259 r = repo[n].rev()
2265 r = repo[n].rev()
2260 except error.RepoLookupError:
2266 except error.RepoLookupError:
2261 r = None
2267 r = None
2262 if r in revs:
2268 if r in revs:
2263 ui.warn(_('skipping revision %d:%s '
2269 ui.warn(_('skipping revision %d:%s '
2264 '(already grafted to %d:%s)\n')
2270 '(already grafted to %d:%s)\n')
2265 % (r, repo[r], rev, ctx))
2271 % (r, repo[r], rev, ctx))
2266 revs.remove(r)
2272 revs.remove(r)
2267 elif ids[n] in revs:
2273 elif ids[n] in revs:
2268 if r is None:
2274 if r is None:
2269 ui.warn(_('skipping already grafted revision %d:%s '
2275 ui.warn(_('skipping already grafted revision %d:%s '
2270 '(%d:%s also has unknown origin %s)\n')
2276 '(%d:%s also has unknown origin %s)\n')
2271 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2277 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2272 else:
2278 else:
2273 ui.warn(_('skipping already grafted revision %d:%s '
2279 ui.warn(_('skipping already grafted revision %d:%s '
2274 '(%d:%s also has origin %d:%s)\n')
2280 '(%d:%s also has origin %d:%s)\n')
2275 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2281 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2276 revs.remove(ids[n])
2282 revs.remove(ids[n])
2277 elif ctx.hex() in ids:
2283 elif ctx.hex() in ids:
2278 r = ids[ctx.hex()]
2284 r = ids[ctx.hex()]
2279 ui.warn(_('skipping already grafted revision %d:%s '
2285 ui.warn(_('skipping already grafted revision %d:%s '
2280 '(was grafted from %d:%s)\n') %
2286 '(was grafted from %d:%s)\n') %
2281 (r, repo[r], rev, ctx))
2287 (r, repo[r], rev, ctx))
2282 revs.remove(r)
2288 revs.remove(r)
2283 if not revs:
2289 if not revs:
2284 return -1
2290 return -1
2285
2291
2286 for pos, ctx in enumerate(repo.set("%ld", revs)):
2292 for pos, ctx in enumerate(repo.set("%ld", revs)):
2287 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2293 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2288 ctx.description().split('\n', 1)[0])
2294 ctx.description().split('\n', 1)[0])
2289 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2295 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2290 if names:
2296 if names:
2291 desc += ' (%s)' % ' '.join(names)
2297 desc += ' (%s)' % ' '.join(names)
2292 ui.status(_('grafting %s\n') % desc)
2298 ui.status(_('grafting %s\n') % desc)
2293 if opts.get('dry_run'):
2299 if opts.get('dry_run'):
2294 continue
2300 continue
2295
2301
2296 source = ctx.extra().get('source')
2302 source = ctx.extra().get('source')
2297 extra = {}
2303 extra = {}
2298 if source:
2304 if source:
2299 extra['source'] = source
2305 extra['source'] = source
2300 extra['intermediate-source'] = ctx.hex()
2306 extra['intermediate-source'] = ctx.hex()
2301 else:
2307 else:
2302 extra['source'] = ctx.hex()
2308 extra['source'] = ctx.hex()
2303 user = ctx.user()
2309 user = ctx.user()
2304 if opts.get('user'):
2310 if opts.get('user'):
2305 user = opts['user']
2311 user = opts['user']
2306 date = ctx.date()
2312 date = ctx.date()
2307 if opts.get('date'):
2313 if opts.get('date'):
2308 date = opts['date']
2314 date = opts['date']
2309 message = ctx.description()
2315 message = ctx.description()
2310 if opts.get('log'):
2316 if opts.get('log'):
2311 message += '\n(grafted from %s)' % ctx.hex()
2317 message += '\n(grafted from %s)' % ctx.hex()
2312
2318
2313 # we don't merge the first commit when continuing
2319 # we don't merge the first commit when continuing
2314 if not cont:
2320 if not cont:
2315 # perform the graft merge with p1(rev) as 'ancestor'
2321 # perform the graft merge with p1(rev) as 'ancestor'
2316 try:
2322 try:
2317 # ui.forcemerge is an internal variable, do not document
2323 # ui.forcemerge is an internal variable, do not document
2318 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2324 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2319 'graft')
2325 'graft')
2320 stats = mergemod.graft(repo, ctx, ctx.p1(),
2326 stats = mergemod.graft(repo, ctx, ctx.p1(),
2321 ['local', 'graft'])
2327 ['local', 'graft'])
2322 finally:
2328 finally:
2323 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2329 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2324 # report any conflicts
2330 # report any conflicts
2325 if stats.unresolvedcount > 0:
2331 if stats.unresolvedcount > 0:
2326 # write out state for --continue
2332 # write out state for --continue
2327 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2333 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2328 repo.vfs.write('graftstate', ''.join(nodelines))
2334 repo.vfs.write('graftstate', ''.join(nodelines))
2329 extra = ''
2335 extra = ''
2330 if opts.get('user'):
2336 if opts.get('user'):
2331 extra += ' --user %s' % procutil.shellquote(opts['user'])
2337 extra += ' --user %s' % procutil.shellquote(opts['user'])
2332 if opts.get('date'):
2338 if opts.get('date'):
2333 extra += ' --date %s' % procutil.shellquote(opts['date'])
2339 extra += ' --date %s' % procutil.shellquote(opts['date'])
2334 if opts.get('log'):
2340 if opts.get('log'):
2335 extra += ' --log'
2341 extra += ' --log'
2336 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2342 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2337 raise error.Abort(
2343 raise error.Abort(
2338 _("unresolved conflicts, can't continue"),
2344 _("unresolved conflicts, can't continue"),
2339 hint=hint)
2345 hint=hint)
2340 else:
2346 else:
2341 cont = False
2347 cont = False
2342
2348
2343 # commit
2349 # commit
2344 node = repo.commit(text=message, user=user,
2350 node = repo.commit(text=message, user=user,
2345 date=date, extra=extra, editor=editor)
2351 date=date, extra=extra, editor=editor)
2346 if node is None:
2352 if node is None:
2347 ui.warn(
2353 ui.warn(
2348 _('note: graft of %d:%s created no changes to commit\n') %
2354 _('note: graft of %d:%s created no changes to commit\n') %
2349 (ctx.rev(), ctx))
2355 (ctx.rev(), ctx))
2350
2356
2351 # remove state when we complete successfully
2357 # remove state when we complete successfully
2352 if not opts.get('dry_run'):
2358 if not opts.get('dry_run'):
2353 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2359 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2354
2360
2355 return 0
2361 return 0
2356
2362
2357 @command('grep',
2363 @command('grep',
2358 [('0', 'print0', None, _('end fields with NUL')),
2364 [('0', 'print0', None, _('end fields with NUL')),
2359 ('', 'all', None, _('print all revisions that match')),
2365 ('', 'all', None, _('print all revisions that match')),
2360 ('a', 'text', None, _('treat all files as text')),
2366 ('a', 'text', None, _('treat all files as text')),
2361 ('f', 'follow', None,
2367 ('f', 'follow', None,
2362 _('follow changeset history,'
2368 _('follow changeset history,'
2363 ' or file history across copies and renames')),
2369 ' or file history across copies and renames')),
2364 ('i', 'ignore-case', None, _('ignore case when matching')),
2370 ('i', 'ignore-case', None, _('ignore case when matching')),
2365 ('l', 'files-with-matches', None,
2371 ('l', 'files-with-matches', None,
2366 _('print only filenames and revisions that match')),
2372 _('print only filenames and revisions that match')),
2367 ('n', 'line-number', None, _('print matching line numbers')),
2373 ('n', 'line-number', None, _('print matching line numbers')),
2368 ('r', 'rev', [],
2374 ('r', 'rev', [],
2369 _('only search files changed within revision range'), _('REV')),
2375 _('only search files changed within revision range'), _('REV')),
2370 ('u', 'user', None, _('list the author (long with -v)')),
2376 ('u', 'user', None, _('list the author (long with -v)')),
2371 ('d', 'date', None, _('list the date (short with -q)')),
2377 ('d', 'date', None, _('list the date (short with -q)')),
2372 ] + formatteropts + walkopts,
2378 ] + formatteropts + walkopts,
2373 _('[OPTION]... PATTERN [FILE]...'),
2379 _('[OPTION]... PATTERN [FILE]...'),
2374 inferrepo=True, cmdtype=readonly)
2380 inferrepo=True,
2381 intents={INTENT_READONLY})
2375 def grep(ui, repo, pattern, *pats, **opts):
2382 def grep(ui, repo, pattern, *pats, **opts):
2376 """search revision history for a pattern in specified files
2383 """search revision history for a pattern in specified files
2377
2384
2378 Search revision history for a regular expression in the specified
2385 Search revision history for a regular expression in the specified
2379 files or the entire project.
2386 files or the entire project.
2380
2387
2381 By default, grep prints the most recent revision number for each
2388 By default, grep prints the most recent revision number for each
2382 file in which it finds a match. To get it to print every revision
2389 file in which it finds a match. To get it to print every revision
2383 that contains a change in match status ("-" for a match that becomes
2390 that contains a change in match status ("-" for a match that becomes
2384 a non-match, or "+" for a non-match that becomes a match), use the
2391 a non-match, or "+" for a non-match that becomes a match), use the
2385 --all flag.
2392 --all flag.
2386
2393
2387 PATTERN can be any Python (roughly Perl-compatible) regular
2394 PATTERN can be any Python (roughly Perl-compatible) regular
2388 expression.
2395 expression.
2389
2396
2390 If no FILEs are specified (and -f/--follow isn't set), all files in
2397 If no FILEs are specified (and -f/--follow isn't set), all files in
2391 the repository are searched, including those that don't exist in the
2398 the repository are searched, including those that don't exist in the
2392 current branch or have been deleted in a prior changeset.
2399 current branch or have been deleted in a prior changeset.
2393
2400
2394 Returns 0 if a match is found, 1 otherwise.
2401 Returns 0 if a match is found, 1 otherwise.
2395 """
2402 """
2396 opts = pycompat.byteskwargs(opts)
2403 opts = pycompat.byteskwargs(opts)
2397 reflags = re.M
2404 reflags = re.M
2398 if opts.get('ignore_case'):
2405 if opts.get('ignore_case'):
2399 reflags |= re.I
2406 reflags |= re.I
2400 try:
2407 try:
2401 regexp = util.re.compile(pattern, reflags)
2408 regexp = util.re.compile(pattern, reflags)
2402 except re.error as inst:
2409 except re.error as inst:
2403 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2410 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2404 return 1
2411 return 1
2405 sep, eol = ':', '\n'
2412 sep, eol = ':', '\n'
2406 if opts.get('print0'):
2413 if opts.get('print0'):
2407 sep = eol = '\0'
2414 sep = eol = '\0'
2408
2415
2409 getfile = util.lrucachefunc(repo.file)
2416 getfile = util.lrucachefunc(repo.file)
2410
2417
2411 def matchlines(body):
2418 def matchlines(body):
2412 begin = 0
2419 begin = 0
2413 linenum = 0
2420 linenum = 0
2414 while begin < len(body):
2421 while begin < len(body):
2415 match = regexp.search(body, begin)
2422 match = regexp.search(body, begin)
2416 if not match:
2423 if not match:
2417 break
2424 break
2418 mstart, mend = match.span()
2425 mstart, mend = match.span()
2419 linenum += body.count('\n', begin, mstart) + 1
2426 linenum += body.count('\n', begin, mstart) + 1
2420 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2427 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2421 begin = body.find('\n', mend) + 1 or len(body) + 1
2428 begin = body.find('\n', mend) + 1 or len(body) + 1
2422 lend = begin - 1
2429 lend = begin - 1
2423 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2430 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2424
2431
2425 class linestate(object):
2432 class linestate(object):
2426 def __init__(self, line, linenum, colstart, colend):
2433 def __init__(self, line, linenum, colstart, colend):
2427 self.line = line
2434 self.line = line
2428 self.linenum = linenum
2435 self.linenum = linenum
2429 self.colstart = colstart
2436 self.colstart = colstart
2430 self.colend = colend
2437 self.colend = colend
2431
2438
2432 def __hash__(self):
2439 def __hash__(self):
2433 return hash((self.linenum, self.line))
2440 return hash((self.linenum, self.line))
2434
2441
2435 def __eq__(self, other):
2442 def __eq__(self, other):
2436 return self.line == other.line
2443 return self.line == other.line
2437
2444
2438 def findpos(self):
2445 def findpos(self):
2439 """Iterate all (start, end) indices of matches"""
2446 """Iterate all (start, end) indices of matches"""
2440 yield self.colstart, self.colend
2447 yield self.colstart, self.colend
2441 p = self.colend
2448 p = self.colend
2442 while p < len(self.line):
2449 while p < len(self.line):
2443 m = regexp.search(self.line, p)
2450 m = regexp.search(self.line, p)
2444 if not m:
2451 if not m:
2445 break
2452 break
2446 yield m.span()
2453 yield m.span()
2447 p = m.end()
2454 p = m.end()
2448
2455
2449 matches = {}
2456 matches = {}
2450 copies = {}
2457 copies = {}
2451 def grepbody(fn, rev, body):
2458 def grepbody(fn, rev, body):
2452 matches[rev].setdefault(fn, [])
2459 matches[rev].setdefault(fn, [])
2453 m = matches[rev][fn]
2460 m = matches[rev][fn]
2454 for lnum, cstart, cend, line in matchlines(body):
2461 for lnum, cstart, cend, line in matchlines(body):
2455 s = linestate(line, lnum, cstart, cend)
2462 s = linestate(line, lnum, cstart, cend)
2456 m.append(s)
2463 m.append(s)
2457
2464
2458 def difflinestates(a, b):
2465 def difflinestates(a, b):
2459 sm = difflib.SequenceMatcher(None, a, b)
2466 sm = difflib.SequenceMatcher(None, a, b)
2460 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2467 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2461 if tag == 'insert':
2468 if tag == 'insert':
2462 for i in xrange(blo, bhi):
2469 for i in xrange(blo, bhi):
2463 yield ('+', b[i])
2470 yield ('+', b[i])
2464 elif tag == 'delete':
2471 elif tag == 'delete':
2465 for i in xrange(alo, ahi):
2472 for i in xrange(alo, ahi):
2466 yield ('-', a[i])
2473 yield ('-', a[i])
2467 elif tag == 'replace':
2474 elif tag == 'replace':
2468 for i in xrange(alo, ahi):
2475 for i in xrange(alo, ahi):
2469 yield ('-', a[i])
2476 yield ('-', a[i])
2470 for i in xrange(blo, bhi):
2477 for i in xrange(blo, bhi):
2471 yield ('+', b[i])
2478 yield ('+', b[i])
2472
2479
2473 def display(fm, fn, ctx, pstates, states):
2480 def display(fm, fn, ctx, pstates, states):
2474 rev = ctx.rev()
2481 rev = ctx.rev()
2475 if fm.isplain():
2482 if fm.isplain():
2476 formatuser = ui.shortuser
2483 formatuser = ui.shortuser
2477 else:
2484 else:
2478 formatuser = str
2485 formatuser = str
2479 if ui.quiet:
2486 if ui.quiet:
2480 datefmt = '%Y-%m-%d'
2487 datefmt = '%Y-%m-%d'
2481 else:
2488 else:
2482 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2489 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2483 found = False
2490 found = False
2484 @util.cachefunc
2491 @util.cachefunc
2485 def binary():
2492 def binary():
2486 flog = getfile(fn)
2493 flog = getfile(fn)
2487 return stringutil.binary(flog.read(ctx.filenode(fn)))
2494 return stringutil.binary(flog.read(ctx.filenode(fn)))
2488
2495
2489 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2496 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2490 if opts.get('all'):
2497 if opts.get('all'):
2491 iter = difflinestates(pstates, states)
2498 iter = difflinestates(pstates, states)
2492 else:
2499 else:
2493 iter = [('', l) for l in states]
2500 iter = [('', l) for l in states]
2494 for change, l in iter:
2501 for change, l in iter:
2495 fm.startitem()
2502 fm.startitem()
2496 fm.data(node=fm.hexfunc(ctx.node()))
2503 fm.data(node=fm.hexfunc(ctx.node()))
2497 cols = [
2504 cols = [
2498 ('filename', fn, True),
2505 ('filename', fn, True),
2499 ('rev', rev, True),
2506 ('rev', rev, True),
2500 ('linenumber', l.linenum, opts.get('line_number')),
2507 ('linenumber', l.linenum, opts.get('line_number')),
2501 ]
2508 ]
2502 if opts.get('all'):
2509 if opts.get('all'):
2503 cols.append(('change', change, True))
2510 cols.append(('change', change, True))
2504 cols.extend([
2511 cols.extend([
2505 ('user', formatuser(ctx.user()), opts.get('user')),
2512 ('user', formatuser(ctx.user()), opts.get('user')),
2506 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2513 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2507 ])
2514 ])
2508 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2515 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2509 for name, data, cond in cols:
2516 for name, data, cond in cols:
2510 field = fieldnamemap.get(name, name)
2517 field = fieldnamemap.get(name, name)
2511 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2518 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2512 if cond and name != lastcol:
2519 if cond and name != lastcol:
2513 fm.plain(sep, label='grep.sep')
2520 fm.plain(sep, label='grep.sep')
2514 if not opts.get('files_with_matches'):
2521 if not opts.get('files_with_matches'):
2515 fm.plain(sep, label='grep.sep')
2522 fm.plain(sep, label='grep.sep')
2516 if not opts.get('text') and binary():
2523 if not opts.get('text') and binary():
2517 fm.plain(_(" Binary file matches"))
2524 fm.plain(_(" Binary file matches"))
2518 else:
2525 else:
2519 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2526 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2520 fm.plain(eol)
2527 fm.plain(eol)
2521 found = True
2528 found = True
2522 if opts.get('files_with_matches'):
2529 if opts.get('files_with_matches'):
2523 break
2530 break
2524 return found
2531 return found
2525
2532
2526 def displaymatches(fm, l):
2533 def displaymatches(fm, l):
2527 p = 0
2534 p = 0
2528 for s, e in l.findpos():
2535 for s, e in l.findpos():
2529 if p < s:
2536 if p < s:
2530 fm.startitem()
2537 fm.startitem()
2531 fm.write('text', '%s', l.line[p:s])
2538 fm.write('text', '%s', l.line[p:s])
2532 fm.data(matched=False)
2539 fm.data(matched=False)
2533 fm.startitem()
2540 fm.startitem()
2534 fm.write('text', '%s', l.line[s:e], label='grep.match')
2541 fm.write('text', '%s', l.line[s:e], label='grep.match')
2535 fm.data(matched=True)
2542 fm.data(matched=True)
2536 p = e
2543 p = e
2537 if p < len(l.line):
2544 if p < len(l.line):
2538 fm.startitem()
2545 fm.startitem()
2539 fm.write('text', '%s', l.line[p:])
2546 fm.write('text', '%s', l.line[p:])
2540 fm.data(matched=False)
2547 fm.data(matched=False)
2541 fm.end()
2548 fm.end()
2542
2549
2543 skip = {}
2550 skip = {}
2544 revfiles = {}
2551 revfiles = {}
2545 match = scmutil.match(repo[None], pats, opts)
2552 match = scmutil.match(repo[None], pats, opts)
2546 found = False
2553 found = False
2547 follow = opts.get('follow')
2554 follow = opts.get('follow')
2548
2555
2549 def prep(ctx, fns):
2556 def prep(ctx, fns):
2550 rev = ctx.rev()
2557 rev = ctx.rev()
2551 pctx = ctx.p1()
2558 pctx = ctx.p1()
2552 parent = pctx.rev()
2559 parent = pctx.rev()
2553 matches.setdefault(rev, {})
2560 matches.setdefault(rev, {})
2554 matches.setdefault(parent, {})
2561 matches.setdefault(parent, {})
2555 files = revfiles.setdefault(rev, [])
2562 files = revfiles.setdefault(rev, [])
2556 for fn in fns:
2563 for fn in fns:
2557 flog = getfile(fn)
2564 flog = getfile(fn)
2558 try:
2565 try:
2559 fnode = ctx.filenode(fn)
2566 fnode = ctx.filenode(fn)
2560 except error.LookupError:
2567 except error.LookupError:
2561 continue
2568 continue
2562
2569
2563 copied = flog.renamed(fnode)
2570 copied = flog.renamed(fnode)
2564 copy = follow and copied and copied[0]
2571 copy = follow and copied and copied[0]
2565 if copy:
2572 if copy:
2566 copies.setdefault(rev, {})[fn] = copy
2573 copies.setdefault(rev, {})[fn] = copy
2567 if fn in skip:
2574 if fn in skip:
2568 if copy:
2575 if copy:
2569 skip[copy] = True
2576 skip[copy] = True
2570 continue
2577 continue
2571 files.append(fn)
2578 files.append(fn)
2572
2579
2573 if fn not in matches[rev]:
2580 if fn not in matches[rev]:
2574 grepbody(fn, rev, flog.read(fnode))
2581 grepbody(fn, rev, flog.read(fnode))
2575
2582
2576 pfn = copy or fn
2583 pfn = copy or fn
2577 if pfn not in matches[parent]:
2584 if pfn not in matches[parent]:
2578 try:
2585 try:
2579 fnode = pctx.filenode(pfn)
2586 fnode = pctx.filenode(pfn)
2580 grepbody(pfn, parent, flog.read(fnode))
2587 grepbody(pfn, parent, flog.read(fnode))
2581 except error.LookupError:
2588 except error.LookupError:
2582 pass
2589 pass
2583
2590
2584 ui.pager('grep')
2591 ui.pager('grep')
2585 fm = ui.formatter('grep', opts)
2592 fm = ui.formatter('grep', opts)
2586 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2593 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2587 rev = ctx.rev()
2594 rev = ctx.rev()
2588 parent = ctx.p1().rev()
2595 parent = ctx.p1().rev()
2589 for fn in sorted(revfiles.get(rev, [])):
2596 for fn in sorted(revfiles.get(rev, [])):
2590 states = matches[rev][fn]
2597 states = matches[rev][fn]
2591 copy = copies.get(rev, {}).get(fn)
2598 copy = copies.get(rev, {}).get(fn)
2592 if fn in skip:
2599 if fn in skip:
2593 if copy:
2600 if copy:
2594 skip[copy] = True
2601 skip[copy] = True
2595 continue
2602 continue
2596 pstates = matches.get(parent, {}).get(copy or fn, [])
2603 pstates = matches.get(parent, {}).get(copy or fn, [])
2597 if pstates or states:
2604 if pstates or states:
2598 r = display(fm, fn, ctx, pstates, states)
2605 r = display(fm, fn, ctx, pstates, states)
2599 found = found or r
2606 found = found or r
2600 if r and not opts.get('all'):
2607 if r and not opts.get('all'):
2601 skip[fn] = True
2608 skip[fn] = True
2602 if copy:
2609 if copy:
2603 skip[copy] = True
2610 skip[copy] = True
2604 del revfiles[rev]
2611 del revfiles[rev]
2605 # We will keep the matches dict for the duration of the window
2612 # We will keep the matches dict for the duration of the window
2606 # clear the matches dict once the window is over
2613 # clear the matches dict once the window is over
2607 if not revfiles:
2614 if not revfiles:
2608 matches.clear()
2615 matches.clear()
2609 fm.end()
2616 fm.end()
2610
2617
2611 return not found
2618 return not found
2612
2619
2613 @command('heads',
2620 @command('heads',
2614 [('r', 'rev', '',
2621 [('r', 'rev', '',
2615 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2622 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2616 ('t', 'topo', False, _('show topological heads only')),
2623 ('t', 'topo', False, _('show topological heads only')),
2617 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2624 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2618 ('c', 'closed', False, _('show normal and closed branch heads')),
2625 ('c', 'closed', False, _('show normal and closed branch heads')),
2619 ] + templateopts,
2626 ] + templateopts,
2620 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2627 _('[-ct] [-r STARTREV] [REV]...'),
2628 intents={INTENT_READONLY})
2621 def heads(ui, repo, *branchrevs, **opts):
2629 def heads(ui, repo, *branchrevs, **opts):
2622 """show branch heads
2630 """show branch heads
2623
2631
2624 With no arguments, show all open branch heads in the repository.
2632 With no arguments, show all open branch heads in the repository.
2625 Branch heads are changesets that have no descendants on the
2633 Branch heads are changesets that have no descendants on the
2626 same branch. They are where development generally takes place and
2634 same branch. They are where development generally takes place and
2627 are the usual targets for update and merge operations.
2635 are the usual targets for update and merge operations.
2628
2636
2629 If one or more REVs are given, only open branch heads on the
2637 If one or more REVs are given, only open branch heads on the
2630 branches associated with the specified changesets are shown. This
2638 branches associated with the specified changesets are shown. This
2631 means that you can use :hg:`heads .` to see the heads on the
2639 means that you can use :hg:`heads .` to see the heads on the
2632 currently checked-out branch.
2640 currently checked-out branch.
2633
2641
2634 If -c/--closed is specified, also show branch heads marked closed
2642 If -c/--closed is specified, also show branch heads marked closed
2635 (see :hg:`commit --close-branch`).
2643 (see :hg:`commit --close-branch`).
2636
2644
2637 If STARTREV is specified, only those heads that are descendants of
2645 If STARTREV is specified, only those heads that are descendants of
2638 STARTREV will be displayed.
2646 STARTREV will be displayed.
2639
2647
2640 If -t/--topo is specified, named branch mechanics will be ignored and only
2648 If -t/--topo is specified, named branch mechanics will be ignored and only
2641 topological heads (changesets with no children) will be shown.
2649 topological heads (changesets with no children) will be shown.
2642
2650
2643 Returns 0 if matching heads are found, 1 if not.
2651 Returns 0 if matching heads are found, 1 if not.
2644 """
2652 """
2645
2653
2646 opts = pycompat.byteskwargs(opts)
2654 opts = pycompat.byteskwargs(opts)
2647 start = None
2655 start = None
2648 rev = opts.get('rev')
2656 rev = opts.get('rev')
2649 if rev:
2657 if rev:
2650 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2658 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2651 start = scmutil.revsingle(repo, rev, None).node()
2659 start = scmutil.revsingle(repo, rev, None).node()
2652
2660
2653 if opts.get('topo'):
2661 if opts.get('topo'):
2654 heads = [repo[h] for h in repo.heads(start)]
2662 heads = [repo[h] for h in repo.heads(start)]
2655 else:
2663 else:
2656 heads = []
2664 heads = []
2657 for branch in repo.branchmap():
2665 for branch in repo.branchmap():
2658 heads += repo.branchheads(branch, start, opts.get('closed'))
2666 heads += repo.branchheads(branch, start, opts.get('closed'))
2659 heads = [repo[h] for h in heads]
2667 heads = [repo[h] for h in heads]
2660
2668
2661 if branchrevs:
2669 if branchrevs:
2662 branches = set(repo[r].branch()
2670 branches = set(repo[r].branch()
2663 for r in scmutil.revrange(repo, branchrevs))
2671 for r in scmutil.revrange(repo, branchrevs))
2664 heads = [h for h in heads if h.branch() in branches]
2672 heads = [h for h in heads if h.branch() in branches]
2665
2673
2666 if opts.get('active') and branchrevs:
2674 if opts.get('active') and branchrevs:
2667 dagheads = repo.heads(start)
2675 dagheads = repo.heads(start)
2668 heads = [h for h in heads if h.node() in dagheads]
2676 heads = [h for h in heads if h.node() in dagheads]
2669
2677
2670 if branchrevs:
2678 if branchrevs:
2671 haveheads = set(h.branch() for h in heads)
2679 haveheads = set(h.branch() for h in heads)
2672 if branches - haveheads:
2680 if branches - haveheads:
2673 headless = ', '.join(b for b in branches - haveheads)
2681 headless = ', '.join(b for b in branches - haveheads)
2674 msg = _('no open branch heads found on branches %s')
2682 msg = _('no open branch heads found on branches %s')
2675 if opts.get('rev'):
2683 if opts.get('rev'):
2676 msg += _(' (started at %s)') % opts['rev']
2684 msg += _(' (started at %s)') % opts['rev']
2677 ui.warn((msg + '\n') % headless)
2685 ui.warn((msg + '\n') % headless)
2678
2686
2679 if not heads:
2687 if not heads:
2680 return 1
2688 return 1
2681
2689
2682 ui.pager('heads')
2690 ui.pager('heads')
2683 heads = sorted(heads, key=lambda x: -x.rev())
2691 heads = sorted(heads, key=lambda x: -x.rev())
2684 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2692 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2685 for ctx in heads:
2693 for ctx in heads:
2686 displayer.show(ctx)
2694 displayer.show(ctx)
2687 displayer.close()
2695 displayer.close()
2688
2696
2689 @command('help',
2697 @command('help',
2690 [('e', 'extension', None, _('show only help for extensions')),
2698 [('e', 'extension', None, _('show only help for extensions')),
2691 ('c', 'command', None, _('show only help for commands')),
2699 ('c', 'command', None, _('show only help for commands')),
2692 ('k', 'keyword', None, _('show topics matching keyword')),
2700 ('k', 'keyword', None, _('show topics matching keyword')),
2693 ('s', 'system', [], _('show help for specific platform(s)')),
2701 ('s', 'system', [], _('show help for specific platform(s)')),
2694 ],
2702 ],
2695 _('[-ecks] [TOPIC]'),
2703 _('[-ecks] [TOPIC]'),
2696 norepo=True, cmdtype=readonly)
2704 norepo=True,
2705 intents={INTENT_READONLY})
2697 def help_(ui, name=None, **opts):
2706 def help_(ui, name=None, **opts):
2698 """show help for a given topic or a help overview
2707 """show help for a given topic or a help overview
2699
2708
2700 With no arguments, print a list of commands with short help messages.
2709 With no arguments, print a list of commands with short help messages.
2701
2710
2702 Given a topic, extension, or command name, print help for that
2711 Given a topic, extension, or command name, print help for that
2703 topic.
2712 topic.
2704
2713
2705 Returns 0 if successful.
2714 Returns 0 if successful.
2706 """
2715 """
2707
2716
2708 keep = opts.get(r'system') or []
2717 keep = opts.get(r'system') or []
2709 if len(keep) == 0:
2718 if len(keep) == 0:
2710 if pycompat.sysplatform.startswith('win'):
2719 if pycompat.sysplatform.startswith('win'):
2711 keep.append('windows')
2720 keep.append('windows')
2712 elif pycompat.sysplatform == 'OpenVMS':
2721 elif pycompat.sysplatform == 'OpenVMS':
2713 keep.append('vms')
2722 keep.append('vms')
2714 elif pycompat.sysplatform == 'plan9':
2723 elif pycompat.sysplatform == 'plan9':
2715 keep.append('plan9')
2724 keep.append('plan9')
2716 else:
2725 else:
2717 keep.append('unix')
2726 keep.append('unix')
2718 keep.append(pycompat.sysplatform.lower())
2727 keep.append(pycompat.sysplatform.lower())
2719 if ui.verbose:
2728 if ui.verbose:
2720 keep.append('verbose')
2729 keep.append('verbose')
2721
2730
2722 commands = sys.modules[__name__]
2731 commands = sys.modules[__name__]
2723 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2732 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2724 ui.pager('help')
2733 ui.pager('help')
2725 ui.write(formatted)
2734 ui.write(formatted)
2726
2735
2727
2736
2728 @command('identify|id',
2737 @command('identify|id',
2729 [('r', 'rev', '',
2738 [('r', 'rev', '',
2730 _('identify the specified revision'), _('REV')),
2739 _('identify the specified revision'), _('REV')),
2731 ('n', 'num', None, _('show local revision number')),
2740 ('n', 'num', None, _('show local revision number')),
2732 ('i', 'id', None, _('show global revision id')),
2741 ('i', 'id', None, _('show global revision id')),
2733 ('b', 'branch', None, _('show branch')),
2742 ('b', 'branch', None, _('show branch')),
2734 ('t', 'tags', None, _('show tags')),
2743 ('t', 'tags', None, _('show tags')),
2735 ('B', 'bookmarks', None, _('show bookmarks')),
2744 ('B', 'bookmarks', None, _('show bookmarks')),
2736 ] + remoteopts + formatteropts,
2745 ] + remoteopts + formatteropts,
2737 _('[-nibtB] [-r REV] [SOURCE]'),
2746 _('[-nibtB] [-r REV] [SOURCE]'),
2738 optionalrepo=True, cmdtype=readonly)
2747 optionalrepo=True,
2748 intents={INTENT_READONLY})
2739 def identify(ui, repo, source=None, rev=None,
2749 def identify(ui, repo, source=None, rev=None,
2740 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2750 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2741 """identify the working directory or specified revision
2751 """identify the working directory or specified revision
2742
2752
2743 Print a summary identifying the repository state at REV using one or
2753 Print a summary identifying the repository state at REV using one or
2744 two parent hash identifiers, followed by a "+" if the working
2754 two parent hash identifiers, followed by a "+" if the working
2745 directory has uncommitted changes, the branch name (if not default),
2755 directory has uncommitted changes, the branch name (if not default),
2746 a list of tags, and a list of bookmarks.
2756 a list of tags, and a list of bookmarks.
2747
2757
2748 When REV is not given, print a summary of the current state of the
2758 When REV is not given, print a summary of the current state of the
2749 repository including the working directory. Specify -r. to get information
2759 repository including the working directory. Specify -r. to get information
2750 of the working directory parent without scanning uncommitted changes.
2760 of the working directory parent without scanning uncommitted changes.
2751
2761
2752 Specifying a path to a repository root or Mercurial bundle will
2762 Specifying a path to a repository root or Mercurial bundle will
2753 cause lookup to operate on that repository/bundle.
2763 cause lookup to operate on that repository/bundle.
2754
2764
2755 .. container:: verbose
2765 .. container:: verbose
2756
2766
2757 Examples:
2767 Examples:
2758
2768
2759 - generate a build identifier for the working directory::
2769 - generate a build identifier for the working directory::
2760
2770
2761 hg id --id > build-id.dat
2771 hg id --id > build-id.dat
2762
2772
2763 - find the revision corresponding to a tag::
2773 - find the revision corresponding to a tag::
2764
2774
2765 hg id -n -r 1.3
2775 hg id -n -r 1.3
2766
2776
2767 - check the most recent revision of a remote repository::
2777 - check the most recent revision of a remote repository::
2768
2778
2769 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2779 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2770
2780
2771 See :hg:`log` for generating more information about specific revisions,
2781 See :hg:`log` for generating more information about specific revisions,
2772 including full hash identifiers.
2782 including full hash identifiers.
2773
2783
2774 Returns 0 if successful.
2784 Returns 0 if successful.
2775 """
2785 """
2776
2786
2777 opts = pycompat.byteskwargs(opts)
2787 opts = pycompat.byteskwargs(opts)
2778 if not repo and not source:
2788 if not repo and not source:
2779 raise error.Abort(_("there is no Mercurial repository here "
2789 raise error.Abort(_("there is no Mercurial repository here "
2780 "(.hg not found)"))
2790 "(.hg not found)"))
2781
2791
2782 if ui.debugflag:
2792 if ui.debugflag:
2783 hexfunc = hex
2793 hexfunc = hex
2784 else:
2794 else:
2785 hexfunc = short
2795 hexfunc = short
2786 default = not (num or id or branch or tags or bookmarks)
2796 default = not (num or id or branch or tags or bookmarks)
2787 output = []
2797 output = []
2788 revs = []
2798 revs = []
2789
2799
2790 if source:
2800 if source:
2791 source, branches = hg.parseurl(ui.expandpath(source))
2801 source, branches = hg.parseurl(ui.expandpath(source))
2792 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2802 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2793 repo = peer.local()
2803 repo = peer.local()
2794 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2804 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2795
2805
2796 fm = ui.formatter('identify', opts)
2806 fm = ui.formatter('identify', opts)
2797 fm.startitem()
2807 fm.startitem()
2798
2808
2799 if not repo:
2809 if not repo:
2800 if num or branch or tags:
2810 if num or branch or tags:
2801 raise error.Abort(
2811 raise error.Abort(
2802 _("can't query remote revision number, branch, or tags"))
2812 _("can't query remote revision number, branch, or tags"))
2803 if not rev and revs:
2813 if not rev and revs:
2804 rev = revs[0]
2814 rev = revs[0]
2805 if not rev:
2815 if not rev:
2806 rev = "tip"
2816 rev = "tip"
2807
2817
2808 remoterev = peer.lookup(rev)
2818 remoterev = peer.lookup(rev)
2809 hexrev = hexfunc(remoterev)
2819 hexrev = hexfunc(remoterev)
2810 if default or id:
2820 if default or id:
2811 output = [hexrev]
2821 output = [hexrev]
2812 fm.data(id=hexrev)
2822 fm.data(id=hexrev)
2813
2823
2814 def getbms():
2824 def getbms():
2815 bms = []
2825 bms = []
2816
2826
2817 if 'bookmarks' in peer.listkeys('namespaces'):
2827 if 'bookmarks' in peer.listkeys('namespaces'):
2818 hexremoterev = hex(remoterev)
2828 hexremoterev = hex(remoterev)
2819 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2829 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2820 if bmr == hexremoterev]
2830 if bmr == hexremoterev]
2821
2831
2822 return sorted(bms)
2832 return sorted(bms)
2823
2833
2824 bms = getbms()
2834 bms = getbms()
2825 if bookmarks:
2835 if bookmarks:
2826 output.extend(bms)
2836 output.extend(bms)
2827 elif default and not ui.quiet:
2837 elif default and not ui.quiet:
2828 # multiple bookmarks for a single parent separated by '/'
2838 # multiple bookmarks for a single parent separated by '/'
2829 bm = '/'.join(bms)
2839 bm = '/'.join(bms)
2830 if bm:
2840 if bm:
2831 output.append(bm)
2841 output.append(bm)
2832
2842
2833 fm.data(node=hex(remoterev))
2843 fm.data(node=hex(remoterev))
2834 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2844 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2835 else:
2845 else:
2836 if rev:
2846 if rev:
2837 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2847 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2838 ctx = scmutil.revsingle(repo, rev, None)
2848 ctx = scmutil.revsingle(repo, rev, None)
2839
2849
2840 if ctx.rev() is None:
2850 if ctx.rev() is None:
2841 ctx = repo[None]
2851 ctx = repo[None]
2842 parents = ctx.parents()
2852 parents = ctx.parents()
2843 taglist = []
2853 taglist = []
2844 for p in parents:
2854 for p in parents:
2845 taglist.extend(p.tags())
2855 taglist.extend(p.tags())
2846
2856
2847 dirty = ""
2857 dirty = ""
2848 if ctx.dirty(missing=True, merge=False, branch=False):
2858 if ctx.dirty(missing=True, merge=False, branch=False):
2849 dirty = '+'
2859 dirty = '+'
2850 fm.data(dirty=dirty)
2860 fm.data(dirty=dirty)
2851
2861
2852 hexoutput = [hexfunc(p.node()) for p in parents]
2862 hexoutput = [hexfunc(p.node()) for p in parents]
2853 if default or id:
2863 if default or id:
2854 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2864 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2855 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2865 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2856
2866
2857 if num:
2867 if num:
2858 numoutput = ["%d" % p.rev() for p in parents]
2868 numoutput = ["%d" % p.rev() for p in parents]
2859 output.append("%s%s" % ('+'.join(numoutput), dirty))
2869 output.append("%s%s" % ('+'.join(numoutput), dirty))
2860
2870
2861 fn = fm.nested('parents', tmpl='{rev}:{node|formatnode}', sep=' ')
2871 fn = fm.nested('parents', tmpl='{rev}:{node|formatnode}', sep=' ')
2862 for p in parents:
2872 for p in parents:
2863 fn.startitem()
2873 fn.startitem()
2864 fn.data(rev=p.rev())
2874 fn.data(rev=p.rev())
2865 fn.data(node=p.hex())
2875 fn.data(node=p.hex())
2866 fn.context(ctx=p)
2876 fn.context(ctx=p)
2867 fn.end()
2877 fn.end()
2868 else:
2878 else:
2869 hexoutput = hexfunc(ctx.node())
2879 hexoutput = hexfunc(ctx.node())
2870 if default or id:
2880 if default or id:
2871 output = [hexoutput]
2881 output = [hexoutput]
2872 fm.data(id=hexoutput)
2882 fm.data(id=hexoutput)
2873
2883
2874 if num:
2884 if num:
2875 output.append(pycompat.bytestr(ctx.rev()))
2885 output.append(pycompat.bytestr(ctx.rev()))
2876 taglist = ctx.tags()
2886 taglist = ctx.tags()
2877
2887
2878 if default and not ui.quiet:
2888 if default and not ui.quiet:
2879 b = ctx.branch()
2889 b = ctx.branch()
2880 if b != 'default':
2890 if b != 'default':
2881 output.append("(%s)" % b)
2891 output.append("(%s)" % b)
2882
2892
2883 # multiple tags for a single parent separated by '/'
2893 # multiple tags for a single parent separated by '/'
2884 t = '/'.join(taglist)
2894 t = '/'.join(taglist)
2885 if t:
2895 if t:
2886 output.append(t)
2896 output.append(t)
2887
2897
2888 # multiple bookmarks for a single parent separated by '/'
2898 # multiple bookmarks for a single parent separated by '/'
2889 bm = '/'.join(ctx.bookmarks())
2899 bm = '/'.join(ctx.bookmarks())
2890 if bm:
2900 if bm:
2891 output.append(bm)
2901 output.append(bm)
2892 else:
2902 else:
2893 if branch:
2903 if branch:
2894 output.append(ctx.branch())
2904 output.append(ctx.branch())
2895
2905
2896 if tags:
2906 if tags:
2897 output.extend(taglist)
2907 output.extend(taglist)
2898
2908
2899 if bookmarks:
2909 if bookmarks:
2900 output.extend(ctx.bookmarks())
2910 output.extend(ctx.bookmarks())
2901
2911
2902 fm.data(node=ctx.hex())
2912 fm.data(node=ctx.hex())
2903 fm.data(branch=ctx.branch())
2913 fm.data(branch=ctx.branch())
2904 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2914 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2905 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2915 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2906 fm.context(ctx=ctx)
2916 fm.context(ctx=ctx)
2907
2917
2908 fm.plain("%s\n" % ' '.join(output))
2918 fm.plain("%s\n" % ' '.join(output))
2909 fm.end()
2919 fm.end()
2910
2920
2911 @command('import|patch',
2921 @command('import|patch',
2912 [('p', 'strip', 1,
2922 [('p', 'strip', 1,
2913 _('directory strip option for patch. This has the same '
2923 _('directory strip option for patch. This has the same '
2914 'meaning as the corresponding patch option'), _('NUM')),
2924 'meaning as the corresponding patch option'), _('NUM')),
2915 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2925 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2916 ('e', 'edit', False, _('invoke editor on commit messages')),
2926 ('e', 'edit', False, _('invoke editor on commit messages')),
2917 ('f', 'force', None,
2927 ('f', 'force', None,
2918 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2928 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2919 ('', 'no-commit', None,
2929 ('', 'no-commit', None,
2920 _("don't commit, just update the working directory")),
2930 _("don't commit, just update the working directory")),
2921 ('', 'bypass', None,
2931 ('', 'bypass', None,
2922 _("apply patch without touching the working directory")),
2932 _("apply patch without touching the working directory")),
2923 ('', 'partial', None,
2933 ('', 'partial', None,
2924 _('commit even if some hunks fail')),
2934 _('commit even if some hunks fail')),
2925 ('', 'exact', None,
2935 ('', 'exact', None,
2926 _('abort if patch would apply lossily')),
2936 _('abort if patch would apply lossily')),
2927 ('', 'prefix', '',
2937 ('', 'prefix', '',
2928 _('apply patch to subdirectory'), _('DIR')),
2938 _('apply patch to subdirectory'), _('DIR')),
2929 ('', 'import-branch', None,
2939 ('', 'import-branch', None,
2930 _('use any branch information in patch (implied by --exact)'))] +
2940 _('use any branch information in patch (implied by --exact)'))] +
2931 commitopts + commitopts2 + similarityopts,
2941 commitopts + commitopts2 + similarityopts,
2932 _('[OPTION]... PATCH...'))
2942 _('[OPTION]... PATCH...'))
2933 def import_(ui, repo, patch1=None, *patches, **opts):
2943 def import_(ui, repo, patch1=None, *patches, **opts):
2934 """import an ordered set of patches
2944 """import an ordered set of patches
2935
2945
2936 Import a list of patches and commit them individually (unless
2946 Import a list of patches and commit them individually (unless
2937 --no-commit is specified).
2947 --no-commit is specified).
2938
2948
2939 To read a patch from standard input (stdin), use "-" as the patch
2949 To read a patch from standard input (stdin), use "-" as the patch
2940 name. If a URL is specified, the patch will be downloaded from
2950 name. If a URL is specified, the patch will be downloaded from
2941 there.
2951 there.
2942
2952
2943 Import first applies changes to the working directory (unless
2953 Import first applies changes to the working directory (unless
2944 --bypass is specified), import will abort if there are outstanding
2954 --bypass is specified), import will abort if there are outstanding
2945 changes.
2955 changes.
2946
2956
2947 Use --bypass to apply and commit patches directly to the
2957 Use --bypass to apply and commit patches directly to the
2948 repository, without affecting the working directory. Without
2958 repository, without affecting the working directory. Without
2949 --exact, patches will be applied on top of the working directory
2959 --exact, patches will be applied on top of the working directory
2950 parent revision.
2960 parent revision.
2951
2961
2952 You can import a patch straight from a mail message. Even patches
2962 You can import a patch straight from a mail message. Even patches
2953 as attachments work (to use the body part, it must have type
2963 as attachments work (to use the body part, it must have type
2954 text/plain or text/x-patch). From and Subject headers of email
2964 text/plain or text/x-patch). From and Subject headers of email
2955 message are used as default committer and commit message. All
2965 message are used as default committer and commit message. All
2956 text/plain body parts before first diff are added to the commit
2966 text/plain body parts before first diff are added to the commit
2957 message.
2967 message.
2958
2968
2959 If the imported patch was generated by :hg:`export`, user and
2969 If the imported patch was generated by :hg:`export`, user and
2960 description from patch override values from message headers and
2970 description from patch override values from message headers and
2961 body. Values given on command line with -m/--message and -u/--user
2971 body. Values given on command line with -m/--message and -u/--user
2962 override these.
2972 override these.
2963
2973
2964 If --exact is specified, import will set the working directory to
2974 If --exact is specified, import will set the working directory to
2965 the parent of each patch before applying it, and will abort if the
2975 the parent of each patch before applying it, and will abort if the
2966 resulting changeset has a different ID than the one recorded in
2976 resulting changeset has a different ID than the one recorded in
2967 the patch. This will guard against various ways that portable
2977 the patch. This will guard against various ways that portable
2968 patch formats and mail systems might fail to transfer Mercurial
2978 patch formats and mail systems might fail to transfer Mercurial
2969 data or metadata. See :hg:`bundle` for lossless transmission.
2979 data or metadata. See :hg:`bundle` for lossless transmission.
2970
2980
2971 Use --partial to ensure a changeset will be created from the patch
2981 Use --partial to ensure a changeset will be created from the patch
2972 even if some hunks fail to apply. Hunks that fail to apply will be
2982 even if some hunks fail to apply. Hunks that fail to apply will be
2973 written to a <target-file>.rej file. Conflicts can then be resolved
2983 written to a <target-file>.rej file. Conflicts can then be resolved
2974 by hand before :hg:`commit --amend` is run to update the created
2984 by hand before :hg:`commit --amend` is run to update the created
2975 changeset. This flag exists to let people import patches that
2985 changeset. This flag exists to let people import patches that
2976 partially apply without losing the associated metadata (author,
2986 partially apply without losing the associated metadata (author,
2977 date, description, ...).
2987 date, description, ...).
2978
2988
2979 .. note::
2989 .. note::
2980
2990
2981 When no hunks apply cleanly, :hg:`import --partial` will create
2991 When no hunks apply cleanly, :hg:`import --partial` will create
2982 an empty changeset, importing only the patch metadata.
2992 an empty changeset, importing only the patch metadata.
2983
2993
2984 With -s/--similarity, hg will attempt to discover renames and
2994 With -s/--similarity, hg will attempt to discover renames and
2985 copies in the patch in the same way as :hg:`addremove`.
2995 copies in the patch in the same way as :hg:`addremove`.
2986
2996
2987 It is possible to use external patch programs to perform the patch
2997 It is possible to use external patch programs to perform the patch
2988 by setting the ``ui.patch`` configuration option. For the default
2998 by setting the ``ui.patch`` configuration option. For the default
2989 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2999 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2990 See :hg:`help config` for more information about configuration
3000 See :hg:`help config` for more information about configuration
2991 files and how to use these options.
3001 files and how to use these options.
2992
3002
2993 See :hg:`help dates` for a list of formats valid for -d/--date.
3003 See :hg:`help dates` for a list of formats valid for -d/--date.
2994
3004
2995 .. container:: verbose
3005 .. container:: verbose
2996
3006
2997 Examples:
3007 Examples:
2998
3008
2999 - import a traditional patch from a website and detect renames::
3009 - import a traditional patch from a website and detect renames::
3000
3010
3001 hg import -s 80 http://example.com/bugfix.patch
3011 hg import -s 80 http://example.com/bugfix.patch
3002
3012
3003 - import a changeset from an hgweb server::
3013 - import a changeset from an hgweb server::
3004
3014
3005 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3015 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3006
3016
3007 - import all the patches in an Unix-style mbox::
3017 - import all the patches in an Unix-style mbox::
3008
3018
3009 hg import incoming-patches.mbox
3019 hg import incoming-patches.mbox
3010
3020
3011 - import patches from stdin::
3021 - import patches from stdin::
3012
3022
3013 hg import -
3023 hg import -
3014
3024
3015 - attempt to exactly restore an exported changeset (not always
3025 - attempt to exactly restore an exported changeset (not always
3016 possible)::
3026 possible)::
3017
3027
3018 hg import --exact proposed-fix.patch
3028 hg import --exact proposed-fix.patch
3019
3029
3020 - use an external tool to apply a patch which is too fuzzy for
3030 - use an external tool to apply a patch which is too fuzzy for
3021 the default internal tool.
3031 the default internal tool.
3022
3032
3023 hg import --config ui.patch="patch --merge" fuzzy.patch
3033 hg import --config ui.patch="patch --merge" fuzzy.patch
3024
3034
3025 - change the default fuzzing from 2 to a less strict 7
3035 - change the default fuzzing from 2 to a less strict 7
3026
3036
3027 hg import --config ui.fuzz=7 fuzz.patch
3037 hg import --config ui.fuzz=7 fuzz.patch
3028
3038
3029 Returns 0 on success, 1 on partial success (see --partial).
3039 Returns 0 on success, 1 on partial success (see --partial).
3030 """
3040 """
3031
3041
3032 opts = pycompat.byteskwargs(opts)
3042 opts = pycompat.byteskwargs(opts)
3033 if not patch1:
3043 if not patch1:
3034 raise error.Abort(_('need at least one patch to import'))
3044 raise error.Abort(_('need at least one patch to import'))
3035
3045
3036 patches = (patch1,) + patches
3046 patches = (patch1,) + patches
3037
3047
3038 date = opts.get('date')
3048 date = opts.get('date')
3039 if date:
3049 if date:
3040 opts['date'] = dateutil.parsedate(date)
3050 opts['date'] = dateutil.parsedate(date)
3041
3051
3042 exact = opts.get('exact')
3052 exact = opts.get('exact')
3043 update = not opts.get('bypass')
3053 update = not opts.get('bypass')
3044 if not update and opts.get('no_commit'):
3054 if not update and opts.get('no_commit'):
3045 raise error.Abort(_('cannot use --no-commit with --bypass'))
3055 raise error.Abort(_('cannot use --no-commit with --bypass'))
3046 try:
3056 try:
3047 sim = float(opts.get('similarity') or 0)
3057 sim = float(opts.get('similarity') or 0)
3048 except ValueError:
3058 except ValueError:
3049 raise error.Abort(_('similarity must be a number'))
3059 raise error.Abort(_('similarity must be a number'))
3050 if sim < 0 or sim > 100:
3060 if sim < 0 or sim > 100:
3051 raise error.Abort(_('similarity must be between 0 and 100'))
3061 raise error.Abort(_('similarity must be between 0 and 100'))
3052 if sim and not update:
3062 if sim and not update:
3053 raise error.Abort(_('cannot use --similarity with --bypass'))
3063 raise error.Abort(_('cannot use --similarity with --bypass'))
3054 if exact:
3064 if exact:
3055 if opts.get('edit'):
3065 if opts.get('edit'):
3056 raise error.Abort(_('cannot use --exact with --edit'))
3066 raise error.Abort(_('cannot use --exact with --edit'))
3057 if opts.get('prefix'):
3067 if opts.get('prefix'):
3058 raise error.Abort(_('cannot use --exact with --prefix'))
3068 raise error.Abort(_('cannot use --exact with --prefix'))
3059
3069
3060 base = opts["base"]
3070 base = opts["base"]
3061 wlock = dsguard = lock = tr = None
3071 wlock = dsguard = lock = tr = None
3062 msgs = []
3072 msgs = []
3063 ret = 0
3073 ret = 0
3064
3074
3065
3075
3066 try:
3076 try:
3067 wlock = repo.wlock()
3077 wlock = repo.wlock()
3068
3078
3069 if update:
3079 if update:
3070 cmdutil.checkunfinished(repo)
3080 cmdutil.checkunfinished(repo)
3071 if (exact or not opts.get('force')):
3081 if (exact or not opts.get('force')):
3072 cmdutil.bailifchanged(repo)
3082 cmdutil.bailifchanged(repo)
3073
3083
3074 if not opts.get('no_commit'):
3084 if not opts.get('no_commit'):
3075 lock = repo.lock()
3085 lock = repo.lock()
3076 tr = repo.transaction('import')
3086 tr = repo.transaction('import')
3077 else:
3087 else:
3078 dsguard = dirstateguard.dirstateguard(repo, 'import')
3088 dsguard = dirstateguard.dirstateguard(repo, 'import')
3079 parents = repo[None].parents()
3089 parents = repo[None].parents()
3080 for patchurl in patches:
3090 for patchurl in patches:
3081 if patchurl == '-':
3091 if patchurl == '-':
3082 ui.status(_('applying patch from stdin\n'))
3092 ui.status(_('applying patch from stdin\n'))
3083 patchfile = ui.fin
3093 patchfile = ui.fin
3084 patchurl = 'stdin' # for error message
3094 patchurl = 'stdin' # for error message
3085 else:
3095 else:
3086 patchurl = os.path.join(base, patchurl)
3096 patchurl = os.path.join(base, patchurl)
3087 ui.status(_('applying %s\n') % patchurl)
3097 ui.status(_('applying %s\n') % patchurl)
3088 patchfile = hg.openpath(ui, patchurl)
3098 patchfile = hg.openpath(ui, patchurl)
3089
3099
3090 haspatch = False
3100 haspatch = False
3091 for hunk in patch.split(patchfile):
3101 for hunk in patch.split(patchfile):
3092 with patch.extract(ui, hunk) as patchdata:
3102 with patch.extract(ui, hunk) as patchdata:
3093 msg, node, rej = cmdutil.tryimportone(ui, repo, patchdata,
3103 msg, node, rej = cmdutil.tryimportone(ui, repo, patchdata,
3094 parents, opts,
3104 parents, opts,
3095 msgs, hg.clean)
3105 msgs, hg.clean)
3096 if msg:
3106 if msg:
3097 haspatch = True
3107 haspatch = True
3098 ui.note(msg + '\n')
3108 ui.note(msg + '\n')
3099 if update or exact:
3109 if update or exact:
3100 parents = repo[None].parents()
3110 parents = repo[None].parents()
3101 else:
3111 else:
3102 parents = [repo[node]]
3112 parents = [repo[node]]
3103 if rej:
3113 if rej:
3104 ui.write_err(_("patch applied partially\n"))
3114 ui.write_err(_("patch applied partially\n"))
3105 ui.write_err(_("(fix the .rej files and run "
3115 ui.write_err(_("(fix the .rej files and run "
3106 "`hg commit --amend`)\n"))
3116 "`hg commit --amend`)\n"))
3107 ret = 1
3117 ret = 1
3108 break
3118 break
3109
3119
3110 if not haspatch:
3120 if not haspatch:
3111 raise error.Abort(_('%s: no diffs found') % patchurl)
3121 raise error.Abort(_('%s: no diffs found') % patchurl)
3112
3122
3113 if tr:
3123 if tr:
3114 tr.close()
3124 tr.close()
3115 if msgs:
3125 if msgs:
3116 repo.savecommitmessage('\n* * *\n'.join(msgs))
3126 repo.savecommitmessage('\n* * *\n'.join(msgs))
3117 if dsguard:
3127 if dsguard:
3118 dsguard.close()
3128 dsguard.close()
3119 return ret
3129 return ret
3120 finally:
3130 finally:
3121 if tr:
3131 if tr:
3122 tr.release()
3132 tr.release()
3123 release(lock, dsguard, wlock)
3133 release(lock, dsguard, wlock)
3124
3134
3125 @command('incoming|in',
3135 @command('incoming|in',
3126 [('f', 'force', None,
3136 [('f', 'force', None,
3127 _('run even if remote repository is unrelated')),
3137 _('run even if remote repository is unrelated')),
3128 ('n', 'newest-first', None, _('show newest record first')),
3138 ('n', 'newest-first', None, _('show newest record first')),
3129 ('', 'bundle', '',
3139 ('', 'bundle', '',
3130 _('file to store the bundles into'), _('FILE')),
3140 _('file to store the bundles into'), _('FILE')),
3131 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3141 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3132 ('B', 'bookmarks', False, _("compare bookmarks")),
3142 ('B', 'bookmarks', False, _("compare bookmarks")),
3133 ('b', 'branch', [],
3143 ('b', 'branch', [],
3134 _('a specific branch you would like to pull'), _('BRANCH')),
3144 _('a specific branch you would like to pull'), _('BRANCH')),
3135 ] + logopts + remoteopts + subrepoopts,
3145 ] + logopts + remoteopts + subrepoopts,
3136 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3146 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3137 def incoming(ui, repo, source="default", **opts):
3147 def incoming(ui, repo, source="default", **opts):
3138 """show new changesets found in source
3148 """show new changesets found in source
3139
3149
3140 Show new changesets found in the specified path/URL or the default
3150 Show new changesets found in the specified path/URL or the default
3141 pull location. These are the changesets that would have been pulled
3151 pull location. These are the changesets that would have been pulled
3142 by :hg:`pull` at the time you issued this command.
3152 by :hg:`pull` at the time you issued this command.
3143
3153
3144 See pull for valid source format details.
3154 See pull for valid source format details.
3145
3155
3146 .. container:: verbose
3156 .. container:: verbose
3147
3157
3148 With -B/--bookmarks, the result of bookmark comparison between
3158 With -B/--bookmarks, the result of bookmark comparison between
3149 local and remote repositories is displayed. With -v/--verbose,
3159 local and remote repositories is displayed. With -v/--verbose,
3150 status is also displayed for each bookmark like below::
3160 status is also displayed for each bookmark like below::
3151
3161
3152 BM1 01234567890a added
3162 BM1 01234567890a added
3153 BM2 1234567890ab advanced
3163 BM2 1234567890ab advanced
3154 BM3 234567890abc diverged
3164 BM3 234567890abc diverged
3155 BM4 34567890abcd changed
3165 BM4 34567890abcd changed
3156
3166
3157 The action taken locally when pulling depends on the
3167 The action taken locally when pulling depends on the
3158 status of each bookmark:
3168 status of each bookmark:
3159
3169
3160 :``added``: pull will create it
3170 :``added``: pull will create it
3161 :``advanced``: pull will update it
3171 :``advanced``: pull will update it
3162 :``diverged``: pull will create a divergent bookmark
3172 :``diverged``: pull will create a divergent bookmark
3163 :``changed``: result depends on remote changesets
3173 :``changed``: result depends on remote changesets
3164
3174
3165 From the point of view of pulling behavior, bookmark
3175 From the point of view of pulling behavior, bookmark
3166 existing only in the remote repository are treated as ``added``,
3176 existing only in the remote repository are treated as ``added``,
3167 even if it is in fact locally deleted.
3177 even if it is in fact locally deleted.
3168
3178
3169 .. container:: verbose
3179 .. container:: verbose
3170
3180
3171 For remote repository, using --bundle avoids downloading the
3181 For remote repository, using --bundle avoids downloading the
3172 changesets twice if the incoming is followed by a pull.
3182 changesets twice if the incoming is followed by a pull.
3173
3183
3174 Examples:
3184 Examples:
3175
3185
3176 - show incoming changes with patches and full description::
3186 - show incoming changes with patches and full description::
3177
3187
3178 hg incoming -vp
3188 hg incoming -vp
3179
3189
3180 - show incoming changes excluding merges, store a bundle::
3190 - show incoming changes excluding merges, store a bundle::
3181
3191
3182 hg in -vpM --bundle incoming.hg
3192 hg in -vpM --bundle incoming.hg
3183 hg pull incoming.hg
3193 hg pull incoming.hg
3184
3194
3185 - briefly list changes inside a bundle::
3195 - briefly list changes inside a bundle::
3186
3196
3187 hg in changes.hg -T "{desc|firstline}\\n"
3197 hg in changes.hg -T "{desc|firstline}\\n"
3188
3198
3189 Returns 0 if there are incoming changes, 1 otherwise.
3199 Returns 0 if there are incoming changes, 1 otherwise.
3190 """
3200 """
3191 opts = pycompat.byteskwargs(opts)
3201 opts = pycompat.byteskwargs(opts)
3192 if opts.get('graph'):
3202 if opts.get('graph'):
3193 logcmdutil.checkunsupportedgraphflags([], opts)
3203 logcmdutil.checkunsupportedgraphflags([], opts)
3194 def display(other, chlist, displayer):
3204 def display(other, chlist, displayer):
3195 revdag = logcmdutil.graphrevs(other, chlist, opts)
3205 revdag = logcmdutil.graphrevs(other, chlist, opts)
3196 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3206 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3197 graphmod.asciiedges)
3207 graphmod.asciiedges)
3198
3208
3199 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3209 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3200 return 0
3210 return 0
3201
3211
3202 if opts.get('bundle') and opts.get('subrepos'):
3212 if opts.get('bundle') and opts.get('subrepos'):
3203 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3213 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3204
3214
3205 if opts.get('bookmarks'):
3215 if opts.get('bookmarks'):
3206 source, branches = hg.parseurl(ui.expandpath(source),
3216 source, branches = hg.parseurl(ui.expandpath(source),
3207 opts.get('branch'))
3217 opts.get('branch'))
3208 other = hg.peer(repo, opts, source)
3218 other = hg.peer(repo, opts, source)
3209 if 'bookmarks' not in other.listkeys('namespaces'):
3219 if 'bookmarks' not in other.listkeys('namespaces'):
3210 ui.warn(_("remote doesn't support bookmarks\n"))
3220 ui.warn(_("remote doesn't support bookmarks\n"))
3211 return 0
3221 return 0
3212 ui.pager('incoming')
3222 ui.pager('incoming')
3213 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3223 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3214 return bookmarks.incoming(ui, repo, other)
3224 return bookmarks.incoming(ui, repo, other)
3215
3225
3216 repo._subtoppath = ui.expandpath(source)
3226 repo._subtoppath = ui.expandpath(source)
3217 try:
3227 try:
3218 return hg.incoming(ui, repo, source, opts)
3228 return hg.incoming(ui, repo, source, opts)
3219 finally:
3229 finally:
3220 del repo._subtoppath
3230 del repo._subtoppath
3221
3231
3222
3232
3223 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3233 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3224 norepo=True)
3234 norepo=True)
3225 def init(ui, dest=".", **opts):
3235 def init(ui, dest=".", **opts):
3226 """create a new repository in the given directory
3236 """create a new repository in the given directory
3227
3237
3228 Initialize a new repository in the given directory. If the given
3238 Initialize a new repository in the given directory. If the given
3229 directory does not exist, it will be created.
3239 directory does not exist, it will be created.
3230
3240
3231 If no directory is given, the current directory is used.
3241 If no directory is given, the current directory is used.
3232
3242
3233 It is possible to specify an ``ssh://`` URL as the destination.
3243 It is possible to specify an ``ssh://`` URL as the destination.
3234 See :hg:`help urls` for more information.
3244 See :hg:`help urls` for more information.
3235
3245
3236 Returns 0 on success.
3246 Returns 0 on success.
3237 """
3247 """
3238 opts = pycompat.byteskwargs(opts)
3248 opts = pycompat.byteskwargs(opts)
3239 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3249 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3240
3250
3241 @command('locate',
3251 @command('locate',
3242 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3252 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3243 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3253 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3244 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3254 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3245 ] + walkopts,
3255 ] + walkopts,
3246 _('[OPTION]... [PATTERN]...'))
3256 _('[OPTION]... [PATTERN]...'))
3247 def locate(ui, repo, *pats, **opts):
3257 def locate(ui, repo, *pats, **opts):
3248 """locate files matching specific patterns (DEPRECATED)
3258 """locate files matching specific patterns (DEPRECATED)
3249
3259
3250 Print files under Mercurial control in the working directory whose
3260 Print files under Mercurial control in the working directory whose
3251 names match the given patterns.
3261 names match the given patterns.
3252
3262
3253 By default, this command searches all directories in the working
3263 By default, this command searches all directories in the working
3254 directory. To search just the current directory and its
3264 directory. To search just the current directory and its
3255 subdirectories, use "--include .".
3265 subdirectories, use "--include .".
3256
3266
3257 If no patterns are given to match, this command prints the names
3267 If no patterns are given to match, this command prints the names
3258 of all files under Mercurial control in the working directory.
3268 of all files under Mercurial control in the working directory.
3259
3269
3260 If you want to feed the output of this command into the "xargs"
3270 If you want to feed the output of this command into the "xargs"
3261 command, use the -0 option to both this command and "xargs". This
3271 command, use the -0 option to both this command and "xargs". This
3262 will avoid the problem of "xargs" treating single filenames that
3272 will avoid the problem of "xargs" treating single filenames that
3263 contain whitespace as multiple filenames.
3273 contain whitespace as multiple filenames.
3264
3274
3265 See :hg:`help files` for a more versatile command.
3275 See :hg:`help files` for a more versatile command.
3266
3276
3267 Returns 0 if a match is found, 1 otherwise.
3277 Returns 0 if a match is found, 1 otherwise.
3268 """
3278 """
3269 opts = pycompat.byteskwargs(opts)
3279 opts = pycompat.byteskwargs(opts)
3270 if opts.get('print0'):
3280 if opts.get('print0'):
3271 end = '\0'
3281 end = '\0'
3272 else:
3282 else:
3273 end = '\n'
3283 end = '\n'
3274 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3284 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3275
3285
3276 ret = 1
3286 ret = 1
3277 m = scmutil.match(ctx, pats, opts, default='relglob',
3287 m = scmutil.match(ctx, pats, opts, default='relglob',
3278 badfn=lambda x, y: False)
3288 badfn=lambda x, y: False)
3279
3289
3280 ui.pager('locate')
3290 ui.pager('locate')
3281 for abs in ctx.matches(m):
3291 for abs in ctx.matches(m):
3282 if opts.get('fullpath'):
3292 if opts.get('fullpath'):
3283 ui.write(repo.wjoin(abs), end)
3293 ui.write(repo.wjoin(abs), end)
3284 else:
3294 else:
3285 ui.write(((pats and m.rel(abs)) or abs), end)
3295 ui.write(((pats and m.rel(abs)) or abs), end)
3286 ret = 0
3296 ret = 0
3287
3297
3288 return ret
3298 return ret
3289
3299
3290 @command('^log|history',
3300 @command('^log|history',
3291 [('f', 'follow', None,
3301 [('f', 'follow', None,
3292 _('follow changeset history, or file history across copies and renames')),
3302 _('follow changeset history, or file history across copies and renames')),
3293 ('', 'follow-first', None,
3303 ('', 'follow-first', None,
3294 _('only follow the first parent of merge changesets (DEPRECATED)')),
3304 _('only follow the first parent of merge changesets (DEPRECATED)')),
3295 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3305 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3296 ('C', 'copies', None, _('show copied files')),
3306 ('C', 'copies', None, _('show copied files')),
3297 ('k', 'keyword', [],
3307 ('k', 'keyword', [],
3298 _('do case-insensitive search for a given text'), _('TEXT')),
3308 _('do case-insensitive search for a given text'), _('TEXT')),
3299 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3309 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3300 ('L', 'line-range', [],
3310 ('L', 'line-range', [],
3301 _('follow line range of specified file (EXPERIMENTAL)'),
3311 _('follow line range of specified file (EXPERIMENTAL)'),
3302 _('FILE,RANGE')),
3312 _('FILE,RANGE')),
3303 ('', 'removed', None, _('include revisions where files were removed')),
3313 ('', 'removed', None, _('include revisions where files were removed')),
3304 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3314 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3305 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3315 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3306 ('', 'only-branch', [],
3316 ('', 'only-branch', [],
3307 _('show only changesets within the given named branch (DEPRECATED)'),
3317 _('show only changesets within the given named branch (DEPRECATED)'),
3308 _('BRANCH')),
3318 _('BRANCH')),
3309 ('b', 'branch', [],
3319 ('b', 'branch', [],
3310 _('show changesets within the given named branch'), _('BRANCH')),
3320 _('show changesets within the given named branch'), _('BRANCH')),
3311 ('P', 'prune', [],
3321 ('P', 'prune', [],
3312 _('do not display revision or any of its ancestors'), _('REV')),
3322 _('do not display revision or any of its ancestors'), _('REV')),
3313 ] + logopts + walkopts,
3323 ] + logopts + walkopts,
3314 _('[OPTION]... [FILE]'),
3324 _('[OPTION]... [FILE]'),
3315 inferrepo=True, cmdtype=readonly)
3325 inferrepo=True,
3326 intents={INTENT_READONLY})
3316 def log(ui, repo, *pats, **opts):
3327 def log(ui, repo, *pats, **opts):
3317 """show revision history of entire repository or files
3328 """show revision history of entire repository or files
3318
3329
3319 Print the revision history of the specified files or the entire
3330 Print the revision history of the specified files or the entire
3320 project.
3331 project.
3321
3332
3322 If no revision range is specified, the default is ``tip:0`` unless
3333 If no revision range is specified, the default is ``tip:0`` unless
3323 --follow is set, in which case the working directory parent is
3334 --follow is set, in which case the working directory parent is
3324 used as the starting revision.
3335 used as the starting revision.
3325
3336
3326 File history is shown without following rename or copy history of
3337 File history is shown without following rename or copy history of
3327 files. Use -f/--follow with a filename to follow history across
3338 files. Use -f/--follow with a filename to follow history across
3328 renames and copies. --follow without a filename will only show
3339 renames and copies. --follow without a filename will only show
3329 ancestors of the starting revision.
3340 ancestors of the starting revision.
3330
3341
3331 By default this command prints revision number and changeset id,
3342 By default this command prints revision number and changeset id,
3332 tags, non-trivial parents, user, date and time, and a summary for
3343 tags, non-trivial parents, user, date and time, and a summary for
3333 each commit. When the -v/--verbose switch is used, the list of
3344 each commit. When the -v/--verbose switch is used, the list of
3334 changed files and full commit message are shown.
3345 changed files and full commit message are shown.
3335
3346
3336 With --graph the revisions are shown as an ASCII art DAG with the most
3347 With --graph the revisions are shown as an ASCII art DAG with the most
3337 recent changeset at the top.
3348 recent changeset at the top.
3338 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3349 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3339 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3350 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3340 changeset from the lines below is a parent of the 'o' merge on the same
3351 changeset from the lines below is a parent of the 'o' merge on the same
3341 line.
3352 line.
3342 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3353 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3343 of a '|' indicates one or more revisions in a path are omitted.
3354 of a '|' indicates one or more revisions in a path are omitted.
3344
3355
3345 .. container:: verbose
3356 .. container:: verbose
3346
3357
3347 Use -L/--line-range FILE,M:N options to follow the history of lines
3358 Use -L/--line-range FILE,M:N options to follow the history of lines
3348 from M to N in FILE. With -p/--patch only diff hunks affecting
3359 from M to N in FILE. With -p/--patch only diff hunks affecting
3349 specified line range will be shown. This option requires --follow;
3360 specified line range will be shown. This option requires --follow;
3350 it can be specified multiple times. Currently, this option is not
3361 it can be specified multiple times. Currently, this option is not
3351 compatible with --graph. This option is experimental.
3362 compatible with --graph. This option is experimental.
3352
3363
3353 .. note::
3364 .. note::
3354
3365
3355 :hg:`log --patch` may generate unexpected diff output for merge
3366 :hg:`log --patch` may generate unexpected diff output for merge
3356 changesets, as it will only compare the merge changeset against
3367 changesets, as it will only compare the merge changeset against
3357 its first parent. Also, only files different from BOTH parents
3368 its first parent. Also, only files different from BOTH parents
3358 will appear in files:.
3369 will appear in files:.
3359
3370
3360 .. note::
3371 .. note::
3361
3372
3362 For performance reasons, :hg:`log FILE` may omit duplicate changes
3373 For performance reasons, :hg:`log FILE` may omit duplicate changes
3363 made on branches and will not show removals or mode changes. To
3374 made on branches and will not show removals or mode changes. To
3364 see all such changes, use the --removed switch.
3375 see all such changes, use the --removed switch.
3365
3376
3366 .. container:: verbose
3377 .. container:: verbose
3367
3378
3368 .. note::
3379 .. note::
3369
3380
3370 The history resulting from -L/--line-range options depends on diff
3381 The history resulting from -L/--line-range options depends on diff
3371 options; for instance if white-spaces are ignored, respective changes
3382 options; for instance if white-spaces are ignored, respective changes
3372 with only white-spaces in specified line range will not be listed.
3383 with only white-spaces in specified line range will not be listed.
3373
3384
3374 .. container:: verbose
3385 .. container:: verbose
3375
3386
3376 Some examples:
3387 Some examples:
3377
3388
3378 - changesets with full descriptions and file lists::
3389 - changesets with full descriptions and file lists::
3379
3390
3380 hg log -v
3391 hg log -v
3381
3392
3382 - changesets ancestral to the working directory::
3393 - changesets ancestral to the working directory::
3383
3394
3384 hg log -f
3395 hg log -f
3385
3396
3386 - last 10 commits on the current branch::
3397 - last 10 commits on the current branch::
3387
3398
3388 hg log -l 10 -b .
3399 hg log -l 10 -b .
3389
3400
3390 - changesets showing all modifications of a file, including removals::
3401 - changesets showing all modifications of a file, including removals::
3391
3402
3392 hg log --removed file.c
3403 hg log --removed file.c
3393
3404
3394 - all changesets that touch a directory, with diffs, excluding merges::
3405 - all changesets that touch a directory, with diffs, excluding merges::
3395
3406
3396 hg log -Mp lib/
3407 hg log -Mp lib/
3397
3408
3398 - all revision numbers that match a keyword::
3409 - all revision numbers that match a keyword::
3399
3410
3400 hg log -k bug --template "{rev}\\n"
3411 hg log -k bug --template "{rev}\\n"
3401
3412
3402 - the full hash identifier of the working directory parent::
3413 - the full hash identifier of the working directory parent::
3403
3414
3404 hg log -r . --template "{node}\\n"
3415 hg log -r . --template "{node}\\n"
3405
3416
3406 - list available log templates::
3417 - list available log templates::
3407
3418
3408 hg log -T list
3419 hg log -T list
3409
3420
3410 - check if a given changeset is included in a tagged release::
3421 - check if a given changeset is included in a tagged release::
3411
3422
3412 hg log -r "a21ccf and ancestor(1.9)"
3423 hg log -r "a21ccf and ancestor(1.9)"
3413
3424
3414 - find all changesets by some user in a date range::
3425 - find all changesets by some user in a date range::
3415
3426
3416 hg log -k alice -d "may 2008 to jul 2008"
3427 hg log -k alice -d "may 2008 to jul 2008"
3417
3428
3418 - summary of all changesets after the last tag::
3429 - summary of all changesets after the last tag::
3419
3430
3420 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3431 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3421
3432
3422 - changesets touching lines 13 to 23 for file.c::
3433 - changesets touching lines 13 to 23 for file.c::
3423
3434
3424 hg log -L file.c,13:23
3435 hg log -L file.c,13:23
3425
3436
3426 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3437 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3427 main.c with patch::
3438 main.c with patch::
3428
3439
3429 hg log -L file.c,13:23 -L main.c,2:6 -p
3440 hg log -L file.c,13:23 -L main.c,2:6 -p
3430
3441
3431 See :hg:`help dates` for a list of formats valid for -d/--date.
3442 See :hg:`help dates` for a list of formats valid for -d/--date.
3432
3443
3433 See :hg:`help revisions` for more about specifying and ordering
3444 See :hg:`help revisions` for more about specifying and ordering
3434 revisions.
3445 revisions.
3435
3446
3436 See :hg:`help templates` for more about pre-packaged styles and
3447 See :hg:`help templates` for more about pre-packaged styles and
3437 specifying custom templates. The default template used by the log
3448 specifying custom templates. The default template used by the log
3438 command can be customized via the ``ui.logtemplate`` configuration
3449 command can be customized via the ``ui.logtemplate`` configuration
3439 setting.
3450 setting.
3440
3451
3441 Returns 0 on success.
3452 Returns 0 on success.
3442
3453
3443 """
3454 """
3444 opts = pycompat.byteskwargs(opts)
3455 opts = pycompat.byteskwargs(opts)
3445 linerange = opts.get('line_range')
3456 linerange = opts.get('line_range')
3446
3457
3447 if linerange and not opts.get('follow'):
3458 if linerange and not opts.get('follow'):
3448 raise error.Abort(_('--line-range requires --follow'))
3459 raise error.Abort(_('--line-range requires --follow'))
3449
3460
3450 if linerange and pats:
3461 if linerange and pats:
3451 # TODO: take pats as patterns with no line-range filter
3462 # TODO: take pats as patterns with no line-range filter
3452 raise error.Abort(
3463 raise error.Abort(
3453 _('FILE arguments are not compatible with --line-range option')
3464 _('FILE arguments are not compatible with --line-range option')
3454 )
3465 )
3455
3466
3456 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3467 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3457 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3468 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3458 if linerange:
3469 if linerange:
3459 # TODO: should follow file history from logcmdutil._initialrevs(),
3470 # TODO: should follow file history from logcmdutil._initialrevs(),
3460 # then filter the result by logcmdutil._makerevset() and --limit
3471 # then filter the result by logcmdutil._makerevset() and --limit
3461 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3472 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3462
3473
3463 getrenamed = None
3474 getrenamed = None
3464 if opts.get('copies'):
3475 if opts.get('copies'):
3465 endrev = None
3476 endrev = None
3466 if opts.get('rev'):
3477 if opts.get('rev'):
3467 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3478 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3468 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3479 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3469
3480
3470 ui.pager('log')
3481 ui.pager('log')
3471 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3482 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3472 buffered=True)
3483 buffered=True)
3473 if opts.get('graph'):
3484 if opts.get('graph'):
3474 displayfn = logcmdutil.displaygraphrevs
3485 displayfn = logcmdutil.displaygraphrevs
3475 else:
3486 else:
3476 displayfn = logcmdutil.displayrevs
3487 displayfn = logcmdutil.displayrevs
3477 displayfn(ui, repo, revs, displayer, getrenamed)
3488 displayfn(ui, repo, revs, displayer, getrenamed)
3478
3489
3479 @command('manifest',
3490 @command('manifest',
3480 [('r', 'rev', '', _('revision to display'), _('REV')),
3491 [('r', 'rev', '', _('revision to display'), _('REV')),
3481 ('', 'all', False, _("list files from all revisions"))]
3492 ('', 'all', False, _("list files from all revisions"))]
3482 + formatteropts,
3493 + formatteropts,
3483 _('[-r REV]'), cmdtype=readonly)
3494 _('[-r REV]'),
3495 intents={INTENT_READONLY})
3484 def manifest(ui, repo, node=None, rev=None, **opts):
3496 def manifest(ui, repo, node=None, rev=None, **opts):
3485 """output the current or given revision of the project manifest
3497 """output the current or given revision of the project manifest
3486
3498
3487 Print a list of version controlled files for the given revision.
3499 Print a list of version controlled files for the given revision.
3488 If no revision is given, the first parent of the working directory
3500 If no revision is given, the first parent of the working directory
3489 is used, or the null revision if no revision is checked out.
3501 is used, or the null revision if no revision is checked out.
3490
3502
3491 With -v, print file permissions, symlink and executable bits.
3503 With -v, print file permissions, symlink and executable bits.
3492 With --debug, print file revision hashes.
3504 With --debug, print file revision hashes.
3493
3505
3494 If option --all is specified, the list of all files from all revisions
3506 If option --all is specified, the list of all files from all revisions
3495 is printed. This includes deleted and renamed files.
3507 is printed. This includes deleted and renamed files.
3496
3508
3497 Returns 0 on success.
3509 Returns 0 on success.
3498 """
3510 """
3499 opts = pycompat.byteskwargs(opts)
3511 opts = pycompat.byteskwargs(opts)
3500 fm = ui.formatter('manifest', opts)
3512 fm = ui.formatter('manifest', opts)
3501
3513
3502 if opts.get('all'):
3514 if opts.get('all'):
3503 if rev or node:
3515 if rev or node:
3504 raise error.Abort(_("can't specify a revision with --all"))
3516 raise error.Abort(_("can't specify a revision with --all"))
3505
3517
3506 res = set()
3518 res = set()
3507 for rev in repo:
3519 for rev in repo:
3508 ctx = repo[rev]
3520 ctx = repo[rev]
3509 res |= set(ctx.files())
3521 res |= set(ctx.files())
3510
3522
3511 ui.pager('manifest')
3523 ui.pager('manifest')
3512 for f in sorted(res):
3524 for f in sorted(res):
3513 fm.startitem()
3525 fm.startitem()
3514 fm.write("path", '%s\n', f)
3526 fm.write("path", '%s\n', f)
3515 fm.end()
3527 fm.end()
3516 return
3528 return
3517
3529
3518 if rev and node:
3530 if rev and node:
3519 raise error.Abort(_("please specify just one revision"))
3531 raise error.Abort(_("please specify just one revision"))
3520
3532
3521 if not node:
3533 if not node:
3522 node = rev
3534 node = rev
3523
3535
3524 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3536 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3525 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3537 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3526 if node:
3538 if node:
3527 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3539 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3528 ctx = scmutil.revsingle(repo, node)
3540 ctx = scmutil.revsingle(repo, node)
3529 mf = ctx.manifest()
3541 mf = ctx.manifest()
3530 ui.pager('manifest')
3542 ui.pager('manifest')
3531 for f in ctx:
3543 for f in ctx:
3532 fm.startitem()
3544 fm.startitem()
3533 fl = ctx[f].flags()
3545 fl = ctx[f].flags()
3534 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3546 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3535 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3547 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3536 fm.write('path', '%s\n', f)
3548 fm.write('path', '%s\n', f)
3537 fm.end()
3549 fm.end()
3538
3550
3539 @command('^merge',
3551 @command('^merge',
3540 [('f', 'force', None,
3552 [('f', 'force', None,
3541 _('force a merge including outstanding changes (DEPRECATED)')),
3553 _('force a merge including outstanding changes (DEPRECATED)')),
3542 ('r', 'rev', '', _('revision to merge'), _('REV')),
3554 ('r', 'rev', '', _('revision to merge'), _('REV')),
3543 ('P', 'preview', None,
3555 ('P', 'preview', None,
3544 _('review revisions to merge (no merge is performed)')),
3556 _('review revisions to merge (no merge is performed)')),
3545 ('', 'abort', None, _('abort the ongoing merge')),
3557 ('', 'abort', None, _('abort the ongoing merge')),
3546 ] + mergetoolopts,
3558 ] + mergetoolopts,
3547 _('[-P] [[-r] REV]'))
3559 _('[-P] [[-r] REV]'))
3548 def merge(ui, repo, node=None, **opts):
3560 def merge(ui, repo, node=None, **opts):
3549 """merge another revision into working directory
3561 """merge another revision into working directory
3550
3562
3551 The current working directory is updated with all changes made in
3563 The current working directory is updated with all changes made in
3552 the requested revision since the last common predecessor revision.
3564 the requested revision since the last common predecessor revision.
3553
3565
3554 Files that changed between either parent are marked as changed for
3566 Files that changed between either parent are marked as changed for
3555 the next commit and a commit must be performed before any further
3567 the next commit and a commit must be performed before any further
3556 updates to the repository are allowed. The next commit will have
3568 updates to the repository are allowed. The next commit will have
3557 two parents.
3569 two parents.
3558
3570
3559 ``--tool`` can be used to specify the merge tool used for file
3571 ``--tool`` can be used to specify the merge tool used for file
3560 merges. It overrides the HGMERGE environment variable and your
3572 merges. It overrides the HGMERGE environment variable and your
3561 configuration files. See :hg:`help merge-tools` for options.
3573 configuration files. See :hg:`help merge-tools` for options.
3562
3574
3563 If no revision is specified, the working directory's parent is a
3575 If no revision is specified, the working directory's parent is a
3564 head revision, and the current branch contains exactly one other
3576 head revision, and the current branch contains exactly one other
3565 head, the other head is merged with by default. Otherwise, an
3577 head, the other head is merged with by default. Otherwise, an
3566 explicit revision with which to merge with must be provided.
3578 explicit revision with which to merge with must be provided.
3567
3579
3568 See :hg:`help resolve` for information on handling file conflicts.
3580 See :hg:`help resolve` for information on handling file conflicts.
3569
3581
3570 To undo an uncommitted merge, use :hg:`merge --abort` which
3582 To undo an uncommitted merge, use :hg:`merge --abort` which
3571 will check out a clean copy of the original merge parent, losing
3583 will check out a clean copy of the original merge parent, losing
3572 all changes.
3584 all changes.
3573
3585
3574 Returns 0 on success, 1 if there are unresolved files.
3586 Returns 0 on success, 1 if there are unresolved files.
3575 """
3587 """
3576
3588
3577 opts = pycompat.byteskwargs(opts)
3589 opts = pycompat.byteskwargs(opts)
3578 abort = opts.get('abort')
3590 abort = opts.get('abort')
3579 if abort and repo.dirstate.p2() == nullid:
3591 if abort and repo.dirstate.p2() == nullid:
3580 cmdutil.wrongtooltocontinue(repo, _('merge'))
3592 cmdutil.wrongtooltocontinue(repo, _('merge'))
3581 if abort:
3593 if abort:
3582 if node:
3594 if node:
3583 raise error.Abort(_("cannot specify a node with --abort"))
3595 raise error.Abort(_("cannot specify a node with --abort"))
3584 if opts.get('rev'):
3596 if opts.get('rev'):
3585 raise error.Abort(_("cannot specify both --rev and --abort"))
3597 raise error.Abort(_("cannot specify both --rev and --abort"))
3586 if opts.get('preview'):
3598 if opts.get('preview'):
3587 raise error.Abort(_("cannot specify --preview with --abort"))
3599 raise error.Abort(_("cannot specify --preview with --abort"))
3588 if opts.get('rev') and node:
3600 if opts.get('rev') and node:
3589 raise error.Abort(_("please specify just one revision"))
3601 raise error.Abort(_("please specify just one revision"))
3590 if not node:
3602 if not node:
3591 node = opts.get('rev')
3603 node = opts.get('rev')
3592
3604
3593 if node:
3605 if node:
3594 node = scmutil.revsingle(repo, node).node()
3606 node = scmutil.revsingle(repo, node).node()
3595
3607
3596 if not node and not abort:
3608 if not node and not abort:
3597 node = repo[destutil.destmerge(repo)].node()
3609 node = repo[destutil.destmerge(repo)].node()
3598
3610
3599 if opts.get('preview'):
3611 if opts.get('preview'):
3600 # find nodes that are ancestors of p2 but not of p1
3612 # find nodes that are ancestors of p2 but not of p1
3601 p1 = repo.lookup('.')
3613 p1 = repo.lookup('.')
3602 p2 = node
3614 p2 = node
3603 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3615 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3604
3616
3605 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3617 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3606 for node in nodes:
3618 for node in nodes:
3607 displayer.show(repo[node])
3619 displayer.show(repo[node])
3608 displayer.close()
3620 displayer.close()
3609 return 0
3621 return 0
3610
3622
3611 try:
3623 try:
3612 # ui.forcemerge is an internal variable, do not document
3624 # ui.forcemerge is an internal variable, do not document
3613 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3625 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3614 force = opts.get('force')
3626 force = opts.get('force')
3615 labels = ['working copy', 'merge rev']
3627 labels = ['working copy', 'merge rev']
3616 return hg.merge(repo, node, force=force, mergeforce=force,
3628 return hg.merge(repo, node, force=force, mergeforce=force,
3617 labels=labels, abort=abort)
3629 labels=labels, abort=abort)
3618 finally:
3630 finally:
3619 ui.setconfig('ui', 'forcemerge', '', 'merge')
3631 ui.setconfig('ui', 'forcemerge', '', 'merge')
3620
3632
3621 @command('outgoing|out',
3633 @command('outgoing|out',
3622 [('f', 'force', None, _('run even when the destination is unrelated')),
3634 [('f', 'force', None, _('run even when the destination is unrelated')),
3623 ('r', 'rev', [],
3635 ('r', 'rev', [],
3624 _('a changeset intended to be included in the destination'), _('REV')),
3636 _('a changeset intended to be included in the destination'), _('REV')),
3625 ('n', 'newest-first', None, _('show newest record first')),
3637 ('n', 'newest-first', None, _('show newest record first')),
3626 ('B', 'bookmarks', False, _('compare bookmarks')),
3638 ('B', 'bookmarks', False, _('compare bookmarks')),
3627 ('b', 'branch', [], _('a specific branch you would like to push'),
3639 ('b', 'branch', [], _('a specific branch you would like to push'),
3628 _('BRANCH')),
3640 _('BRANCH')),
3629 ] + logopts + remoteopts + subrepoopts,
3641 ] + logopts + remoteopts + subrepoopts,
3630 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3642 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3631 def outgoing(ui, repo, dest=None, **opts):
3643 def outgoing(ui, repo, dest=None, **opts):
3632 """show changesets not found in the destination
3644 """show changesets not found in the destination
3633
3645
3634 Show changesets not found in the specified destination repository
3646 Show changesets not found in the specified destination repository
3635 or the default push location. These are the changesets that would
3647 or the default push location. These are the changesets that would
3636 be pushed if a push was requested.
3648 be pushed if a push was requested.
3637
3649
3638 See pull for details of valid destination formats.
3650 See pull for details of valid destination formats.
3639
3651
3640 .. container:: verbose
3652 .. container:: verbose
3641
3653
3642 With -B/--bookmarks, the result of bookmark comparison between
3654 With -B/--bookmarks, the result of bookmark comparison between
3643 local and remote repositories is displayed. With -v/--verbose,
3655 local and remote repositories is displayed. With -v/--verbose,
3644 status is also displayed for each bookmark like below::
3656 status is also displayed for each bookmark like below::
3645
3657
3646 BM1 01234567890a added
3658 BM1 01234567890a added
3647 BM2 deleted
3659 BM2 deleted
3648 BM3 234567890abc advanced
3660 BM3 234567890abc advanced
3649 BM4 34567890abcd diverged
3661 BM4 34567890abcd diverged
3650 BM5 4567890abcde changed
3662 BM5 4567890abcde changed
3651
3663
3652 The action taken when pushing depends on the
3664 The action taken when pushing depends on the
3653 status of each bookmark:
3665 status of each bookmark:
3654
3666
3655 :``added``: push with ``-B`` will create it
3667 :``added``: push with ``-B`` will create it
3656 :``deleted``: push with ``-B`` will delete it
3668 :``deleted``: push with ``-B`` will delete it
3657 :``advanced``: push will update it
3669 :``advanced``: push will update it
3658 :``diverged``: push with ``-B`` will update it
3670 :``diverged``: push with ``-B`` will update it
3659 :``changed``: push with ``-B`` will update it
3671 :``changed``: push with ``-B`` will update it
3660
3672
3661 From the point of view of pushing behavior, bookmarks
3673 From the point of view of pushing behavior, bookmarks
3662 existing only in the remote repository are treated as
3674 existing only in the remote repository are treated as
3663 ``deleted``, even if it is in fact added remotely.
3675 ``deleted``, even if it is in fact added remotely.
3664
3676
3665 Returns 0 if there are outgoing changes, 1 otherwise.
3677 Returns 0 if there are outgoing changes, 1 otherwise.
3666 """
3678 """
3667 opts = pycompat.byteskwargs(opts)
3679 opts = pycompat.byteskwargs(opts)
3668 if opts.get('graph'):
3680 if opts.get('graph'):
3669 logcmdutil.checkunsupportedgraphflags([], opts)
3681 logcmdutil.checkunsupportedgraphflags([], opts)
3670 o, other = hg._outgoing(ui, repo, dest, opts)
3682 o, other = hg._outgoing(ui, repo, dest, opts)
3671 if not o:
3683 if not o:
3672 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3684 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3673 return
3685 return
3674
3686
3675 revdag = logcmdutil.graphrevs(repo, o, opts)
3687 revdag = logcmdutil.graphrevs(repo, o, opts)
3676 ui.pager('outgoing')
3688 ui.pager('outgoing')
3677 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3689 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3678 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3690 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3679 graphmod.asciiedges)
3691 graphmod.asciiedges)
3680 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3692 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3681 return 0
3693 return 0
3682
3694
3683 if opts.get('bookmarks'):
3695 if opts.get('bookmarks'):
3684 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3696 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3685 dest, branches = hg.parseurl(dest, opts.get('branch'))
3697 dest, branches = hg.parseurl(dest, opts.get('branch'))
3686 other = hg.peer(repo, opts, dest)
3698 other = hg.peer(repo, opts, dest)
3687 if 'bookmarks' not in other.listkeys('namespaces'):
3699 if 'bookmarks' not in other.listkeys('namespaces'):
3688 ui.warn(_("remote doesn't support bookmarks\n"))
3700 ui.warn(_("remote doesn't support bookmarks\n"))
3689 return 0
3701 return 0
3690 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3702 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3691 ui.pager('outgoing')
3703 ui.pager('outgoing')
3692 return bookmarks.outgoing(ui, repo, other)
3704 return bookmarks.outgoing(ui, repo, other)
3693
3705
3694 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3706 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3695 try:
3707 try:
3696 return hg.outgoing(ui, repo, dest, opts)
3708 return hg.outgoing(ui, repo, dest, opts)
3697 finally:
3709 finally:
3698 del repo._subtoppath
3710 del repo._subtoppath
3699
3711
3700 @command('parents',
3712 @command('parents',
3701 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3713 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3702 ] + templateopts,
3714 ] + templateopts,
3703 _('[-r REV] [FILE]'),
3715 _('[-r REV] [FILE]'),
3704 inferrepo=True)
3716 inferrepo=True)
3705 def parents(ui, repo, file_=None, **opts):
3717 def parents(ui, repo, file_=None, **opts):
3706 """show the parents of the working directory or revision (DEPRECATED)
3718 """show the parents of the working directory or revision (DEPRECATED)
3707
3719
3708 Print the working directory's parent revisions. If a revision is
3720 Print the working directory's parent revisions. If a revision is
3709 given via -r/--rev, the parent of that revision will be printed.
3721 given via -r/--rev, the parent of that revision will be printed.
3710 If a file argument is given, the revision in which the file was
3722 If a file argument is given, the revision in which the file was
3711 last changed (before the working directory revision or the
3723 last changed (before the working directory revision or the
3712 argument to --rev if given) is printed.
3724 argument to --rev if given) is printed.
3713
3725
3714 This command is equivalent to::
3726 This command is equivalent to::
3715
3727
3716 hg log -r "p1()+p2()" or
3728 hg log -r "p1()+p2()" or
3717 hg log -r "p1(REV)+p2(REV)" or
3729 hg log -r "p1(REV)+p2(REV)" or
3718 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3730 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3719 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3731 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3720
3732
3721 See :hg:`summary` and :hg:`help revsets` for related information.
3733 See :hg:`summary` and :hg:`help revsets` for related information.
3722
3734
3723 Returns 0 on success.
3735 Returns 0 on success.
3724 """
3736 """
3725
3737
3726 opts = pycompat.byteskwargs(opts)
3738 opts = pycompat.byteskwargs(opts)
3727 rev = opts.get('rev')
3739 rev = opts.get('rev')
3728 if rev:
3740 if rev:
3729 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3741 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3730 ctx = scmutil.revsingle(repo, rev, None)
3742 ctx = scmutil.revsingle(repo, rev, None)
3731
3743
3732 if file_:
3744 if file_:
3733 m = scmutil.match(ctx, (file_,), opts)
3745 m = scmutil.match(ctx, (file_,), opts)
3734 if m.anypats() or len(m.files()) != 1:
3746 if m.anypats() or len(m.files()) != 1:
3735 raise error.Abort(_('can only specify an explicit filename'))
3747 raise error.Abort(_('can only specify an explicit filename'))
3736 file_ = m.files()[0]
3748 file_ = m.files()[0]
3737 filenodes = []
3749 filenodes = []
3738 for cp in ctx.parents():
3750 for cp in ctx.parents():
3739 if not cp:
3751 if not cp:
3740 continue
3752 continue
3741 try:
3753 try:
3742 filenodes.append(cp.filenode(file_))
3754 filenodes.append(cp.filenode(file_))
3743 except error.LookupError:
3755 except error.LookupError:
3744 pass
3756 pass
3745 if not filenodes:
3757 if not filenodes:
3746 raise error.Abort(_("'%s' not found in manifest!") % file_)
3758 raise error.Abort(_("'%s' not found in manifest!") % file_)
3747 p = []
3759 p = []
3748 for fn in filenodes:
3760 for fn in filenodes:
3749 fctx = repo.filectx(file_, fileid=fn)
3761 fctx = repo.filectx(file_, fileid=fn)
3750 p.append(fctx.node())
3762 p.append(fctx.node())
3751 else:
3763 else:
3752 p = [cp.node() for cp in ctx.parents()]
3764 p = [cp.node() for cp in ctx.parents()]
3753
3765
3754 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3766 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3755 for n in p:
3767 for n in p:
3756 if n != nullid:
3768 if n != nullid:
3757 displayer.show(repo[n])
3769 displayer.show(repo[n])
3758 displayer.close()
3770 displayer.close()
3759
3771
3760 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3772 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3761 cmdtype=readonly)
3773 intents={INTENT_READONLY})
3762 def paths(ui, repo, search=None, **opts):
3774 def paths(ui, repo, search=None, **opts):
3763 """show aliases for remote repositories
3775 """show aliases for remote repositories
3764
3776
3765 Show definition of symbolic path name NAME. If no name is given,
3777 Show definition of symbolic path name NAME. If no name is given,
3766 show definition of all available names.
3778 show definition of all available names.
3767
3779
3768 Option -q/--quiet suppresses all output when searching for NAME
3780 Option -q/--quiet suppresses all output when searching for NAME
3769 and shows only the path names when listing all definitions.
3781 and shows only the path names when listing all definitions.
3770
3782
3771 Path names are defined in the [paths] section of your
3783 Path names are defined in the [paths] section of your
3772 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3784 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3773 repository, ``.hg/hgrc`` is used, too.
3785 repository, ``.hg/hgrc`` is used, too.
3774
3786
3775 The path names ``default`` and ``default-push`` have a special
3787 The path names ``default`` and ``default-push`` have a special
3776 meaning. When performing a push or pull operation, they are used
3788 meaning. When performing a push or pull operation, they are used
3777 as fallbacks if no location is specified on the command-line.
3789 as fallbacks if no location is specified on the command-line.
3778 When ``default-push`` is set, it will be used for push and
3790 When ``default-push`` is set, it will be used for push and
3779 ``default`` will be used for pull; otherwise ``default`` is used
3791 ``default`` will be used for pull; otherwise ``default`` is used
3780 as the fallback for both. When cloning a repository, the clone
3792 as the fallback for both. When cloning a repository, the clone
3781 source is written as ``default`` in ``.hg/hgrc``.
3793 source is written as ``default`` in ``.hg/hgrc``.
3782
3794
3783 .. note::
3795 .. note::
3784
3796
3785 ``default`` and ``default-push`` apply to all inbound (e.g.
3797 ``default`` and ``default-push`` apply to all inbound (e.g.
3786 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3798 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3787 and :hg:`bundle`) operations.
3799 and :hg:`bundle`) operations.
3788
3800
3789 See :hg:`help urls` for more information.
3801 See :hg:`help urls` for more information.
3790
3802
3791 Returns 0 on success.
3803 Returns 0 on success.
3792 """
3804 """
3793
3805
3794 opts = pycompat.byteskwargs(opts)
3806 opts = pycompat.byteskwargs(opts)
3795 ui.pager('paths')
3807 ui.pager('paths')
3796 if search:
3808 if search:
3797 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3809 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3798 if name == search]
3810 if name == search]
3799 else:
3811 else:
3800 pathitems = sorted(ui.paths.iteritems())
3812 pathitems = sorted(ui.paths.iteritems())
3801
3813
3802 fm = ui.formatter('paths', opts)
3814 fm = ui.formatter('paths', opts)
3803 if fm.isplain():
3815 if fm.isplain():
3804 hidepassword = util.hidepassword
3816 hidepassword = util.hidepassword
3805 else:
3817 else:
3806 hidepassword = bytes
3818 hidepassword = bytes
3807 if ui.quiet:
3819 if ui.quiet:
3808 namefmt = '%s\n'
3820 namefmt = '%s\n'
3809 else:
3821 else:
3810 namefmt = '%s = '
3822 namefmt = '%s = '
3811 showsubopts = not search and not ui.quiet
3823 showsubopts = not search and not ui.quiet
3812
3824
3813 for name, path in pathitems:
3825 for name, path in pathitems:
3814 fm.startitem()
3826 fm.startitem()
3815 fm.condwrite(not search, 'name', namefmt, name)
3827 fm.condwrite(not search, 'name', namefmt, name)
3816 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3828 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3817 for subopt, value in sorted(path.suboptions.items()):
3829 for subopt, value in sorted(path.suboptions.items()):
3818 assert subopt not in ('name', 'url')
3830 assert subopt not in ('name', 'url')
3819 if showsubopts:
3831 if showsubopts:
3820 fm.plain('%s:%s = ' % (name, subopt))
3832 fm.plain('%s:%s = ' % (name, subopt))
3821 fm.condwrite(showsubopts, subopt, '%s\n', value)
3833 fm.condwrite(showsubopts, subopt, '%s\n', value)
3822
3834
3823 fm.end()
3835 fm.end()
3824
3836
3825 if search and not pathitems:
3837 if search and not pathitems:
3826 if not ui.quiet:
3838 if not ui.quiet:
3827 ui.warn(_("not found!\n"))
3839 ui.warn(_("not found!\n"))
3828 return 1
3840 return 1
3829 else:
3841 else:
3830 return 0
3842 return 0
3831
3843
3832 @command('phase',
3844 @command('phase',
3833 [('p', 'public', False, _('set changeset phase to public')),
3845 [('p', 'public', False, _('set changeset phase to public')),
3834 ('d', 'draft', False, _('set changeset phase to draft')),
3846 ('d', 'draft', False, _('set changeset phase to draft')),
3835 ('s', 'secret', False, _('set changeset phase to secret')),
3847 ('s', 'secret', False, _('set changeset phase to secret')),
3836 ('f', 'force', False, _('allow to move boundary backward')),
3848 ('f', 'force', False, _('allow to move boundary backward')),
3837 ('r', 'rev', [], _('target revision'), _('REV')),
3849 ('r', 'rev', [], _('target revision'), _('REV')),
3838 ],
3850 ],
3839 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3851 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3840 def phase(ui, repo, *revs, **opts):
3852 def phase(ui, repo, *revs, **opts):
3841 """set or show the current phase name
3853 """set or show the current phase name
3842
3854
3843 With no argument, show the phase name of the current revision(s).
3855 With no argument, show the phase name of the current revision(s).
3844
3856
3845 With one of -p/--public, -d/--draft or -s/--secret, change the
3857 With one of -p/--public, -d/--draft or -s/--secret, change the
3846 phase value of the specified revisions.
3858 phase value of the specified revisions.
3847
3859
3848 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3860 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3849 lower phase to a higher phase. Phases are ordered as follows::
3861 lower phase to a higher phase. Phases are ordered as follows::
3850
3862
3851 public < draft < secret
3863 public < draft < secret
3852
3864
3853 Returns 0 on success, 1 if some phases could not be changed.
3865 Returns 0 on success, 1 if some phases could not be changed.
3854
3866
3855 (For more information about the phases concept, see :hg:`help phases`.)
3867 (For more information about the phases concept, see :hg:`help phases`.)
3856 """
3868 """
3857 opts = pycompat.byteskwargs(opts)
3869 opts = pycompat.byteskwargs(opts)
3858 # search for a unique phase argument
3870 # search for a unique phase argument
3859 targetphase = None
3871 targetphase = None
3860 for idx, name in enumerate(phases.phasenames):
3872 for idx, name in enumerate(phases.phasenames):
3861 if opts[name]:
3873 if opts[name]:
3862 if targetphase is not None:
3874 if targetphase is not None:
3863 raise error.Abort(_('only one phase can be specified'))
3875 raise error.Abort(_('only one phase can be specified'))
3864 targetphase = idx
3876 targetphase = idx
3865
3877
3866 # look for specified revision
3878 # look for specified revision
3867 revs = list(revs)
3879 revs = list(revs)
3868 revs.extend(opts['rev'])
3880 revs.extend(opts['rev'])
3869 if not revs:
3881 if not revs:
3870 # display both parents as the second parent phase can influence
3882 # display both parents as the second parent phase can influence
3871 # the phase of a merge commit
3883 # the phase of a merge commit
3872 revs = [c.rev() for c in repo[None].parents()]
3884 revs = [c.rev() for c in repo[None].parents()]
3873
3885
3874 revs = scmutil.revrange(repo, revs)
3886 revs = scmutil.revrange(repo, revs)
3875
3887
3876 ret = 0
3888 ret = 0
3877 if targetphase is None:
3889 if targetphase is None:
3878 # display
3890 # display
3879 for r in revs:
3891 for r in revs:
3880 ctx = repo[r]
3892 ctx = repo[r]
3881 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3893 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3882 else:
3894 else:
3883 with repo.lock(), repo.transaction("phase") as tr:
3895 with repo.lock(), repo.transaction("phase") as tr:
3884 # set phase
3896 # set phase
3885 if not revs:
3897 if not revs:
3886 raise error.Abort(_('empty revision set'))
3898 raise error.Abort(_('empty revision set'))
3887 nodes = [repo[r].node() for r in revs]
3899 nodes = [repo[r].node() for r in revs]
3888 # moving revision from public to draft may hide them
3900 # moving revision from public to draft may hide them
3889 # We have to check result on an unfiltered repository
3901 # We have to check result on an unfiltered repository
3890 unfi = repo.unfiltered()
3902 unfi = repo.unfiltered()
3891 getphase = unfi._phasecache.phase
3903 getphase = unfi._phasecache.phase
3892 olddata = [getphase(unfi, r) for r in unfi]
3904 olddata = [getphase(unfi, r) for r in unfi]
3893 phases.advanceboundary(repo, tr, targetphase, nodes)
3905 phases.advanceboundary(repo, tr, targetphase, nodes)
3894 if opts['force']:
3906 if opts['force']:
3895 phases.retractboundary(repo, tr, targetphase, nodes)
3907 phases.retractboundary(repo, tr, targetphase, nodes)
3896 getphase = unfi._phasecache.phase
3908 getphase = unfi._phasecache.phase
3897 newdata = [getphase(unfi, r) for r in unfi]
3909 newdata = [getphase(unfi, r) for r in unfi]
3898 changes = sum(newdata[r] != olddata[r] for r in unfi)
3910 changes = sum(newdata[r] != olddata[r] for r in unfi)
3899 cl = unfi.changelog
3911 cl = unfi.changelog
3900 rejected = [n for n in nodes
3912 rejected = [n for n in nodes
3901 if newdata[cl.rev(n)] < targetphase]
3913 if newdata[cl.rev(n)] < targetphase]
3902 if rejected:
3914 if rejected:
3903 ui.warn(_('cannot move %i changesets to a higher '
3915 ui.warn(_('cannot move %i changesets to a higher '
3904 'phase, use --force\n') % len(rejected))
3916 'phase, use --force\n') % len(rejected))
3905 ret = 1
3917 ret = 1
3906 if changes:
3918 if changes:
3907 msg = _('phase changed for %i changesets\n') % changes
3919 msg = _('phase changed for %i changesets\n') % changes
3908 if ret:
3920 if ret:
3909 ui.status(msg)
3921 ui.status(msg)
3910 else:
3922 else:
3911 ui.note(msg)
3923 ui.note(msg)
3912 else:
3924 else:
3913 ui.warn(_('no phases changed\n'))
3925 ui.warn(_('no phases changed\n'))
3914 return ret
3926 return ret
3915
3927
3916 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3928 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3917 """Run after a changegroup has been added via pull/unbundle
3929 """Run after a changegroup has been added via pull/unbundle
3918
3930
3919 This takes arguments below:
3931 This takes arguments below:
3920
3932
3921 :modheads: change of heads by pull/unbundle
3933 :modheads: change of heads by pull/unbundle
3922 :optupdate: updating working directory is needed or not
3934 :optupdate: updating working directory is needed or not
3923 :checkout: update destination revision (or None to default destination)
3935 :checkout: update destination revision (or None to default destination)
3924 :brev: a name, which might be a bookmark to be activated after updating
3936 :brev: a name, which might be a bookmark to be activated after updating
3925 """
3937 """
3926 if modheads == 0:
3938 if modheads == 0:
3927 return
3939 return
3928 if optupdate:
3940 if optupdate:
3929 try:
3941 try:
3930 return hg.updatetotally(ui, repo, checkout, brev)
3942 return hg.updatetotally(ui, repo, checkout, brev)
3931 except error.UpdateAbort as inst:
3943 except error.UpdateAbort as inst:
3932 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
3944 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
3933 hint = inst.hint
3945 hint = inst.hint
3934 raise error.UpdateAbort(msg, hint=hint)
3946 raise error.UpdateAbort(msg, hint=hint)
3935 if modheads > 1:
3947 if modheads > 1:
3936 currentbranchheads = len(repo.branchheads())
3948 currentbranchheads = len(repo.branchheads())
3937 if currentbranchheads == modheads:
3949 if currentbranchheads == modheads:
3938 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3950 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3939 elif currentbranchheads > 1:
3951 elif currentbranchheads > 1:
3940 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3952 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3941 "merge)\n"))
3953 "merge)\n"))
3942 else:
3954 else:
3943 ui.status(_("(run 'hg heads' to see heads)\n"))
3955 ui.status(_("(run 'hg heads' to see heads)\n"))
3944 elif not ui.configbool('commands', 'update.requiredest'):
3956 elif not ui.configbool('commands', 'update.requiredest'):
3945 ui.status(_("(run 'hg update' to get a working copy)\n"))
3957 ui.status(_("(run 'hg update' to get a working copy)\n"))
3946
3958
3947 @command('^pull',
3959 @command('^pull',
3948 [('u', 'update', None,
3960 [('u', 'update', None,
3949 _('update to new branch head if new descendants were pulled')),
3961 _('update to new branch head if new descendants were pulled')),
3950 ('f', 'force', None, _('run even when remote repository is unrelated')),
3962 ('f', 'force', None, _('run even when remote repository is unrelated')),
3951 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3963 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3952 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3964 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3953 ('b', 'branch', [], _('a specific branch you would like to pull'),
3965 ('b', 'branch', [], _('a specific branch you would like to pull'),
3954 _('BRANCH')),
3966 _('BRANCH')),
3955 ] + remoteopts,
3967 ] + remoteopts,
3956 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3968 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3957 def pull(ui, repo, source="default", **opts):
3969 def pull(ui, repo, source="default", **opts):
3958 """pull changes from the specified source
3970 """pull changes from the specified source
3959
3971
3960 Pull changes from a remote repository to a local one.
3972 Pull changes from a remote repository to a local one.
3961
3973
3962 This finds all changes from the repository at the specified path
3974 This finds all changes from the repository at the specified path
3963 or URL and adds them to a local repository (the current one unless
3975 or URL and adds them to a local repository (the current one unless
3964 -R is specified). By default, this does not update the copy of the
3976 -R is specified). By default, this does not update the copy of the
3965 project in the working directory.
3977 project in the working directory.
3966
3978
3967 When cloning from servers that support it, Mercurial may fetch
3979 When cloning from servers that support it, Mercurial may fetch
3968 pre-generated data. When this is done, hooks operating on incoming
3980 pre-generated data. When this is done, hooks operating on incoming
3969 changesets and changegroups may fire more than once, once for each
3981 changesets and changegroups may fire more than once, once for each
3970 pre-generated bundle and as well as for any additional remaining
3982 pre-generated bundle and as well as for any additional remaining
3971 data. See :hg:`help -e clonebundles` for more.
3983 data. See :hg:`help -e clonebundles` for more.
3972
3984
3973 Use :hg:`incoming` if you want to see what would have been added
3985 Use :hg:`incoming` if you want to see what would have been added
3974 by a pull at the time you issued this command. If you then decide
3986 by a pull at the time you issued this command. If you then decide
3975 to add those changes to the repository, you should use :hg:`pull
3987 to add those changes to the repository, you should use :hg:`pull
3976 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3988 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3977
3989
3978 If SOURCE is omitted, the 'default' path will be used.
3990 If SOURCE is omitted, the 'default' path will be used.
3979 See :hg:`help urls` for more information.
3991 See :hg:`help urls` for more information.
3980
3992
3981 Specifying bookmark as ``.`` is equivalent to specifying the active
3993 Specifying bookmark as ``.`` is equivalent to specifying the active
3982 bookmark's name.
3994 bookmark's name.
3983
3995
3984 Returns 0 on success, 1 if an update had unresolved files.
3996 Returns 0 on success, 1 if an update had unresolved files.
3985 """
3997 """
3986
3998
3987 opts = pycompat.byteskwargs(opts)
3999 opts = pycompat.byteskwargs(opts)
3988 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4000 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3989 msg = _('update destination required by configuration')
4001 msg = _('update destination required by configuration')
3990 hint = _('use hg pull followed by hg update DEST')
4002 hint = _('use hg pull followed by hg update DEST')
3991 raise error.Abort(msg, hint=hint)
4003 raise error.Abort(msg, hint=hint)
3992
4004
3993 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4005 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3994 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4006 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3995 other = hg.peer(repo, opts, source)
4007 other = hg.peer(repo, opts, source)
3996 try:
4008 try:
3997 revs, checkout = hg.addbranchrevs(repo, other, branches,
4009 revs, checkout = hg.addbranchrevs(repo, other, branches,
3998 opts.get('rev'))
4010 opts.get('rev'))
3999
4011
4000
4012
4001 pullopargs = {}
4013 pullopargs = {}
4002 if opts.get('bookmark'):
4014 if opts.get('bookmark'):
4003 if not revs:
4015 if not revs:
4004 revs = []
4016 revs = []
4005 # The list of bookmark used here is not the one used to actually
4017 # The list of bookmark used here is not the one used to actually
4006 # update the bookmark name. This can result in the revision pulled
4018 # update the bookmark name. This can result in the revision pulled
4007 # not ending up with the name of the bookmark because of a race
4019 # not ending up with the name of the bookmark because of a race
4008 # condition on the server. (See issue 4689 for details)
4020 # condition on the server. (See issue 4689 for details)
4009 remotebookmarks = other.listkeys('bookmarks')
4021 remotebookmarks = other.listkeys('bookmarks')
4010 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4022 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4011 pullopargs['remotebookmarks'] = remotebookmarks
4023 pullopargs['remotebookmarks'] = remotebookmarks
4012 for b in opts['bookmark']:
4024 for b in opts['bookmark']:
4013 b = repo._bookmarks.expandname(b)
4025 b = repo._bookmarks.expandname(b)
4014 if b not in remotebookmarks:
4026 if b not in remotebookmarks:
4015 raise error.Abort(_('remote bookmark %s not found!') % b)
4027 raise error.Abort(_('remote bookmark %s not found!') % b)
4016 revs.append(hex(remotebookmarks[b]))
4028 revs.append(hex(remotebookmarks[b]))
4017
4029
4018 if revs:
4030 if revs:
4019 try:
4031 try:
4020 # When 'rev' is a bookmark name, we cannot guarantee that it
4032 # When 'rev' is a bookmark name, we cannot guarantee that it
4021 # will be updated with that name because of a race condition
4033 # will be updated with that name because of a race condition
4022 # server side. (See issue 4689 for details)
4034 # server side. (See issue 4689 for details)
4023 oldrevs = revs
4035 oldrevs = revs
4024 revs = [] # actually, nodes
4036 revs = [] # actually, nodes
4025 for r in oldrevs:
4037 for r in oldrevs:
4026 node = other.lookup(r)
4038 node = other.lookup(r)
4027 revs.append(node)
4039 revs.append(node)
4028 if r == checkout:
4040 if r == checkout:
4029 checkout = node
4041 checkout = node
4030 except error.CapabilityError:
4042 except error.CapabilityError:
4031 err = _("other repository doesn't support revision lookup, "
4043 err = _("other repository doesn't support revision lookup, "
4032 "so a rev cannot be specified.")
4044 "so a rev cannot be specified.")
4033 raise error.Abort(err)
4045 raise error.Abort(err)
4034
4046
4035 wlock = util.nullcontextmanager()
4047 wlock = util.nullcontextmanager()
4036 if opts.get('update'):
4048 if opts.get('update'):
4037 wlock = repo.wlock()
4049 wlock = repo.wlock()
4038 with wlock:
4050 with wlock:
4039 pullopargs.update(opts.get('opargs', {}))
4051 pullopargs.update(opts.get('opargs', {}))
4040 modheads = exchange.pull(repo, other, heads=revs,
4052 modheads = exchange.pull(repo, other, heads=revs,
4041 force=opts.get('force'),
4053 force=opts.get('force'),
4042 bookmarks=opts.get('bookmark', ()),
4054 bookmarks=opts.get('bookmark', ()),
4043 opargs=pullopargs).cgresult
4055 opargs=pullopargs).cgresult
4044
4056
4045 # brev is a name, which might be a bookmark to be activated at
4057 # brev is a name, which might be a bookmark to be activated at
4046 # the end of the update. In other words, it is an explicit
4058 # the end of the update. In other words, it is an explicit
4047 # destination of the update
4059 # destination of the update
4048 brev = None
4060 brev = None
4049
4061
4050 if checkout:
4062 if checkout:
4051 checkout = repo.changelog.rev(checkout)
4063 checkout = repo.changelog.rev(checkout)
4052
4064
4053 # order below depends on implementation of
4065 # order below depends on implementation of
4054 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4066 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4055 # because 'checkout' is determined without it.
4067 # because 'checkout' is determined without it.
4056 if opts.get('rev'):
4068 if opts.get('rev'):
4057 brev = opts['rev'][0]
4069 brev = opts['rev'][0]
4058 elif opts.get('branch'):
4070 elif opts.get('branch'):
4059 brev = opts['branch'][0]
4071 brev = opts['branch'][0]
4060 else:
4072 else:
4061 brev = branches[0]
4073 brev = branches[0]
4062 repo._subtoppath = source
4074 repo._subtoppath = source
4063 try:
4075 try:
4064 ret = postincoming(ui, repo, modheads, opts.get('update'),
4076 ret = postincoming(ui, repo, modheads, opts.get('update'),
4065 checkout, brev)
4077 checkout, brev)
4066
4078
4067 finally:
4079 finally:
4068 del repo._subtoppath
4080 del repo._subtoppath
4069
4081
4070 finally:
4082 finally:
4071 other.close()
4083 other.close()
4072 return ret
4084 return ret
4073
4085
4074 @command('^push',
4086 @command('^push',
4075 [('f', 'force', None, _('force push')),
4087 [('f', 'force', None, _('force push')),
4076 ('r', 'rev', [],
4088 ('r', 'rev', [],
4077 _('a changeset intended to be included in the destination'),
4089 _('a changeset intended to be included in the destination'),
4078 _('REV')),
4090 _('REV')),
4079 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4091 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4080 ('b', 'branch', [],
4092 ('b', 'branch', [],
4081 _('a specific branch you would like to push'), _('BRANCH')),
4093 _('a specific branch you would like to push'), _('BRANCH')),
4082 ('', 'new-branch', False, _('allow pushing a new branch')),
4094 ('', 'new-branch', False, _('allow pushing a new branch')),
4083 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4095 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4084 ] + remoteopts,
4096 ] + remoteopts,
4085 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4097 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4086 def push(ui, repo, dest=None, **opts):
4098 def push(ui, repo, dest=None, **opts):
4087 """push changes to the specified destination
4099 """push changes to the specified destination
4088
4100
4089 Push changesets from the local repository to the specified
4101 Push changesets from the local repository to the specified
4090 destination.
4102 destination.
4091
4103
4092 This operation is symmetrical to pull: it is identical to a pull
4104 This operation is symmetrical to pull: it is identical to a pull
4093 in the destination repository from the current one.
4105 in the destination repository from the current one.
4094
4106
4095 By default, push will not allow creation of new heads at the
4107 By default, push will not allow creation of new heads at the
4096 destination, since multiple heads would make it unclear which head
4108 destination, since multiple heads would make it unclear which head
4097 to use. In this situation, it is recommended to pull and merge
4109 to use. In this situation, it is recommended to pull and merge
4098 before pushing.
4110 before pushing.
4099
4111
4100 Use --new-branch if you want to allow push to create a new named
4112 Use --new-branch if you want to allow push to create a new named
4101 branch that is not present at the destination. This allows you to
4113 branch that is not present at the destination. This allows you to
4102 only create a new branch without forcing other changes.
4114 only create a new branch without forcing other changes.
4103
4115
4104 .. note::
4116 .. note::
4105
4117
4106 Extra care should be taken with the -f/--force option,
4118 Extra care should be taken with the -f/--force option,
4107 which will push all new heads on all branches, an action which will
4119 which will push all new heads on all branches, an action which will
4108 almost always cause confusion for collaborators.
4120 almost always cause confusion for collaborators.
4109
4121
4110 If -r/--rev is used, the specified revision and all its ancestors
4122 If -r/--rev is used, the specified revision and all its ancestors
4111 will be pushed to the remote repository.
4123 will be pushed to the remote repository.
4112
4124
4113 If -B/--bookmark is used, the specified bookmarked revision, its
4125 If -B/--bookmark is used, the specified bookmarked revision, its
4114 ancestors, and the bookmark will be pushed to the remote
4126 ancestors, and the bookmark will be pushed to the remote
4115 repository. Specifying ``.`` is equivalent to specifying the active
4127 repository. Specifying ``.`` is equivalent to specifying the active
4116 bookmark's name.
4128 bookmark's name.
4117
4129
4118 Please see :hg:`help urls` for important details about ``ssh://``
4130 Please see :hg:`help urls` for important details about ``ssh://``
4119 URLs. If DESTINATION is omitted, a default path will be used.
4131 URLs. If DESTINATION is omitted, a default path will be used.
4120
4132
4121 .. container:: verbose
4133 .. container:: verbose
4122
4134
4123 The --pushvars option sends strings to the server that become
4135 The --pushvars option sends strings to the server that become
4124 environment variables prepended with ``HG_USERVAR_``. For example,
4136 environment variables prepended with ``HG_USERVAR_``. For example,
4125 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4137 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4126 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4138 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4127
4139
4128 pushvars can provide for user-overridable hooks as well as set debug
4140 pushvars can provide for user-overridable hooks as well as set debug
4129 levels. One example is having a hook that blocks commits containing
4141 levels. One example is having a hook that blocks commits containing
4130 conflict markers, but enables the user to override the hook if the file
4142 conflict markers, but enables the user to override the hook if the file
4131 is using conflict markers for testing purposes or the file format has
4143 is using conflict markers for testing purposes or the file format has
4132 strings that look like conflict markers.
4144 strings that look like conflict markers.
4133
4145
4134 By default, servers will ignore `--pushvars`. To enable it add the
4146 By default, servers will ignore `--pushvars`. To enable it add the
4135 following to your configuration file::
4147 following to your configuration file::
4136
4148
4137 [push]
4149 [push]
4138 pushvars.server = true
4150 pushvars.server = true
4139
4151
4140 Returns 0 if push was successful, 1 if nothing to push.
4152 Returns 0 if push was successful, 1 if nothing to push.
4141 """
4153 """
4142
4154
4143 opts = pycompat.byteskwargs(opts)
4155 opts = pycompat.byteskwargs(opts)
4144 if opts.get('bookmark'):
4156 if opts.get('bookmark'):
4145 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4157 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4146 for b in opts['bookmark']:
4158 for b in opts['bookmark']:
4147 # translate -B options to -r so changesets get pushed
4159 # translate -B options to -r so changesets get pushed
4148 b = repo._bookmarks.expandname(b)
4160 b = repo._bookmarks.expandname(b)
4149 if b in repo._bookmarks:
4161 if b in repo._bookmarks:
4150 opts.setdefault('rev', []).append(b)
4162 opts.setdefault('rev', []).append(b)
4151 else:
4163 else:
4152 # if we try to push a deleted bookmark, translate it to null
4164 # if we try to push a deleted bookmark, translate it to null
4153 # this lets simultaneous -r, -b options continue working
4165 # this lets simultaneous -r, -b options continue working
4154 opts.setdefault('rev', []).append("null")
4166 opts.setdefault('rev', []).append("null")
4155
4167
4156 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4168 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4157 if not path:
4169 if not path:
4158 raise error.Abort(_('default repository not configured!'),
4170 raise error.Abort(_('default repository not configured!'),
4159 hint=_("see 'hg help config.paths'"))
4171 hint=_("see 'hg help config.paths'"))
4160 dest = path.pushloc or path.loc
4172 dest = path.pushloc or path.loc
4161 branches = (path.branch, opts.get('branch') or [])
4173 branches = (path.branch, opts.get('branch') or [])
4162 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4174 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4163 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4175 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4164 other = hg.peer(repo, opts, dest)
4176 other = hg.peer(repo, opts, dest)
4165
4177
4166 if revs:
4178 if revs:
4167 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4179 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4168 if not revs:
4180 if not revs:
4169 raise error.Abort(_("specified revisions evaluate to an empty set"),
4181 raise error.Abort(_("specified revisions evaluate to an empty set"),
4170 hint=_("use different revision arguments"))
4182 hint=_("use different revision arguments"))
4171 elif path.pushrev:
4183 elif path.pushrev:
4172 # It doesn't make any sense to specify ancestor revisions. So limit
4184 # It doesn't make any sense to specify ancestor revisions. So limit
4173 # to DAG heads to make discovery simpler.
4185 # to DAG heads to make discovery simpler.
4174 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4186 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4175 revs = scmutil.revrange(repo, [expr])
4187 revs = scmutil.revrange(repo, [expr])
4176 revs = [repo[rev].node() for rev in revs]
4188 revs = [repo[rev].node() for rev in revs]
4177 if not revs:
4189 if not revs:
4178 raise error.Abort(_('default push revset for path evaluates to an '
4190 raise error.Abort(_('default push revset for path evaluates to an '
4179 'empty set'))
4191 'empty set'))
4180
4192
4181 repo._subtoppath = dest
4193 repo._subtoppath = dest
4182 try:
4194 try:
4183 # push subrepos depth-first for coherent ordering
4195 # push subrepos depth-first for coherent ordering
4184 c = repo['.']
4196 c = repo['.']
4185 subs = c.substate # only repos that are committed
4197 subs = c.substate # only repos that are committed
4186 for s in sorted(subs):
4198 for s in sorted(subs):
4187 result = c.sub(s).push(opts)
4199 result = c.sub(s).push(opts)
4188 if result == 0:
4200 if result == 0:
4189 return not result
4201 return not result
4190 finally:
4202 finally:
4191 del repo._subtoppath
4203 del repo._subtoppath
4192
4204
4193 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4205 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4194 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4206 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4195
4207
4196 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4208 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4197 newbranch=opts.get('new_branch'),
4209 newbranch=opts.get('new_branch'),
4198 bookmarks=opts.get('bookmark', ()),
4210 bookmarks=opts.get('bookmark', ()),
4199 opargs=opargs)
4211 opargs=opargs)
4200
4212
4201 result = not pushop.cgresult
4213 result = not pushop.cgresult
4202
4214
4203 if pushop.bkresult is not None:
4215 if pushop.bkresult is not None:
4204 if pushop.bkresult == 2:
4216 if pushop.bkresult == 2:
4205 result = 2
4217 result = 2
4206 elif not result and pushop.bkresult:
4218 elif not result and pushop.bkresult:
4207 result = 2
4219 result = 2
4208
4220
4209 return result
4221 return result
4210
4222
4211 @command('recover', [])
4223 @command('recover', [])
4212 def recover(ui, repo):
4224 def recover(ui, repo):
4213 """roll back an interrupted transaction
4225 """roll back an interrupted transaction
4214
4226
4215 Recover from an interrupted commit or pull.
4227 Recover from an interrupted commit or pull.
4216
4228
4217 This command tries to fix the repository status after an
4229 This command tries to fix the repository status after an
4218 interrupted operation. It should only be necessary when Mercurial
4230 interrupted operation. It should only be necessary when Mercurial
4219 suggests it.
4231 suggests it.
4220
4232
4221 Returns 0 if successful, 1 if nothing to recover or verify fails.
4233 Returns 0 if successful, 1 if nothing to recover or verify fails.
4222 """
4234 """
4223 if repo.recover():
4235 if repo.recover():
4224 return hg.verify(repo)
4236 return hg.verify(repo)
4225 return 1
4237 return 1
4226
4238
4227 @command('^remove|rm',
4239 @command('^remove|rm',
4228 [('A', 'after', None, _('record delete for missing files')),
4240 [('A', 'after', None, _('record delete for missing files')),
4229 ('f', 'force', None,
4241 ('f', 'force', None,
4230 _('forget added files, delete modified files')),
4242 _('forget added files, delete modified files')),
4231 ] + subrepoopts + walkopts + dryrunopts,
4243 ] + subrepoopts + walkopts + dryrunopts,
4232 _('[OPTION]... FILE...'),
4244 _('[OPTION]... FILE...'),
4233 inferrepo=True)
4245 inferrepo=True)
4234 def remove(ui, repo, *pats, **opts):
4246 def remove(ui, repo, *pats, **opts):
4235 """remove the specified files on the next commit
4247 """remove the specified files on the next commit
4236
4248
4237 Schedule the indicated files for removal from the current branch.
4249 Schedule the indicated files for removal from the current branch.
4238
4250
4239 This command schedules the files to be removed at the next commit.
4251 This command schedules the files to be removed at the next commit.
4240 To undo a remove before that, see :hg:`revert`. To undo added
4252 To undo a remove before that, see :hg:`revert`. To undo added
4241 files, see :hg:`forget`.
4253 files, see :hg:`forget`.
4242
4254
4243 .. container:: verbose
4255 .. container:: verbose
4244
4256
4245 -A/--after can be used to remove only files that have already
4257 -A/--after can be used to remove only files that have already
4246 been deleted, -f/--force can be used to force deletion, and -Af
4258 been deleted, -f/--force can be used to force deletion, and -Af
4247 can be used to remove files from the next revision without
4259 can be used to remove files from the next revision without
4248 deleting them from the working directory.
4260 deleting them from the working directory.
4249
4261
4250 The following table details the behavior of remove for different
4262 The following table details the behavior of remove for different
4251 file states (columns) and option combinations (rows). The file
4263 file states (columns) and option combinations (rows). The file
4252 states are Added [A], Clean [C], Modified [M] and Missing [!]
4264 states are Added [A], Clean [C], Modified [M] and Missing [!]
4253 (as reported by :hg:`status`). The actions are Warn, Remove
4265 (as reported by :hg:`status`). The actions are Warn, Remove
4254 (from branch) and Delete (from disk):
4266 (from branch) and Delete (from disk):
4255
4267
4256 ========= == == == ==
4268 ========= == == == ==
4257 opt/state A C M !
4269 opt/state A C M !
4258 ========= == == == ==
4270 ========= == == == ==
4259 none W RD W R
4271 none W RD W R
4260 -f R RD RD R
4272 -f R RD RD R
4261 -A W W W R
4273 -A W W W R
4262 -Af R R R R
4274 -Af R R R R
4263 ========= == == == ==
4275 ========= == == == ==
4264
4276
4265 .. note::
4277 .. note::
4266
4278
4267 :hg:`remove` never deletes files in Added [A] state from the
4279 :hg:`remove` never deletes files in Added [A] state from the
4268 working directory, not even if ``--force`` is specified.
4280 working directory, not even if ``--force`` is specified.
4269
4281
4270 Returns 0 on success, 1 if any warnings encountered.
4282 Returns 0 on success, 1 if any warnings encountered.
4271 """
4283 """
4272
4284
4273 opts = pycompat.byteskwargs(opts)
4285 opts = pycompat.byteskwargs(opts)
4274 after, force = opts.get('after'), opts.get('force')
4286 after, force = opts.get('after'), opts.get('force')
4275 dryrun = opts.get('dry_run')
4287 dryrun = opts.get('dry_run')
4276 if not pats and not after:
4288 if not pats and not after:
4277 raise error.Abort(_('no files specified'))
4289 raise error.Abort(_('no files specified'))
4278
4290
4279 m = scmutil.match(repo[None], pats, opts)
4291 m = scmutil.match(repo[None], pats, opts)
4280 subrepos = opts.get('subrepos')
4292 subrepos = opts.get('subrepos')
4281 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4293 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4282 dryrun=dryrun)
4294 dryrun=dryrun)
4283
4295
4284 @command('rename|move|mv',
4296 @command('rename|move|mv',
4285 [('A', 'after', None, _('record a rename that has already occurred')),
4297 [('A', 'after', None, _('record a rename that has already occurred')),
4286 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4298 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4287 ] + walkopts + dryrunopts,
4299 ] + walkopts + dryrunopts,
4288 _('[OPTION]... SOURCE... DEST'))
4300 _('[OPTION]... SOURCE... DEST'))
4289 def rename(ui, repo, *pats, **opts):
4301 def rename(ui, repo, *pats, **opts):
4290 """rename files; equivalent of copy + remove
4302 """rename files; equivalent of copy + remove
4291
4303
4292 Mark dest as copies of sources; mark sources for deletion. If dest
4304 Mark dest as copies of sources; mark sources for deletion. If dest
4293 is a directory, copies are put in that directory. If dest is a
4305 is a directory, copies are put in that directory. If dest is a
4294 file, there can only be one source.
4306 file, there can only be one source.
4295
4307
4296 By default, this command copies the contents of files as they
4308 By default, this command copies the contents of files as they
4297 exist in the working directory. If invoked with -A/--after, the
4309 exist in the working directory. If invoked with -A/--after, the
4298 operation is recorded, but no copying is performed.
4310 operation is recorded, but no copying is performed.
4299
4311
4300 This command takes effect at the next commit. To undo a rename
4312 This command takes effect at the next commit. To undo a rename
4301 before that, see :hg:`revert`.
4313 before that, see :hg:`revert`.
4302
4314
4303 Returns 0 on success, 1 if errors are encountered.
4315 Returns 0 on success, 1 if errors are encountered.
4304 """
4316 """
4305 opts = pycompat.byteskwargs(opts)
4317 opts = pycompat.byteskwargs(opts)
4306 with repo.wlock(False):
4318 with repo.wlock(False):
4307 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4319 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4308
4320
4309 @command('resolve',
4321 @command('resolve',
4310 [('a', 'all', None, _('select all unresolved files')),
4322 [('a', 'all', None, _('select all unresolved files')),
4311 ('l', 'list', None, _('list state of files needing merge')),
4323 ('l', 'list', None, _('list state of files needing merge')),
4312 ('m', 'mark', None, _('mark files as resolved')),
4324 ('m', 'mark', None, _('mark files as resolved')),
4313 ('u', 'unmark', None, _('mark files as unresolved')),
4325 ('u', 'unmark', None, _('mark files as unresolved')),
4314 ('n', 'no-status', None, _('hide status prefix'))]
4326 ('n', 'no-status', None, _('hide status prefix'))]
4315 + mergetoolopts + walkopts + formatteropts,
4327 + mergetoolopts + walkopts + formatteropts,
4316 _('[OPTION]... [FILE]...'),
4328 _('[OPTION]... [FILE]...'),
4317 inferrepo=True)
4329 inferrepo=True)
4318 def resolve(ui, repo, *pats, **opts):
4330 def resolve(ui, repo, *pats, **opts):
4319 """redo merges or set/view the merge status of files
4331 """redo merges or set/view the merge status of files
4320
4332
4321 Merges with unresolved conflicts are often the result of
4333 Merges with unresolved conflicts are often the result of
4322 non-interactive merging using the ``internal:merge`` configuration
4334 non-interactive merging using the ``internal:merge`` configuration
4323 setting, or a command-line merge tool like ``diff3``. The resolve
4335 setting, or a command-line merge tool like ``diff3``. The resolve
4324 command is used to manage the files involved in a merge, after
4336 command is used to manage the files involved in a merge, after
4325 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4337 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4326 working directory must have two parents). See :hg:`help
4338 working directory must have two parents). See :hg:`help
4327 merge-tools` for information on configuring merge tools.
4339 merge-tools` for information on configuring merge tools.
4328
4340
4329 The resolve command can be used in the following ways:
4341 The resolve command can be used in the following ways:
4330
4342
4331 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4343 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4332 files, discarding any previous merge attempts. Re-merging is not
4344 files, discarding any previous merge attempts. Re-merging is not
4333 performed for files already marked as resolved. Use ``--all/-a``
4345 performed for files already marked as resolved. Use ``--all/-a``
4334 to select all unresolved files. ``--tool`` can be used to specify
4346 to select all unresolved files. ``--tool`` can be used to specify
4335 the merge tool used for the given files. It overrides the HGMERGE
4347 the merge tool used for the given files. It overrides the HGMERGE
4336 environment variable and your configuration files. Previous file
4348 environment variable and your configuration files. Previous file
4337 contents are saved with a ``.orig`` suffix.
4349 contents are saved with a ``.orig`` suffix.
4338
4350
4339 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4351 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4340 (e.g. after having manually fixed-up the files). The default is
4352 (e.g. after having manually fixed-up the files). The default is
4341 to mark all unresolved files.
4353 to mark all unresolved files.
4342
4354
4343 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4355 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4344 default is to mark all resolved files.
4356 default is to mark all resolved files.
4345
4357
4346 - :hg:`resolve -l`: list files which had or still have conflicts.
4358 - :hg:`resolve -l`: list files which had or still have conflicts.
4347 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4359 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4348 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4360 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4349 the list. See :hg:`help filesets` for details.
4361 the list. See :hg:`help filesets` for details.
4350
4362
4351 .. note::
4363 .. note::
4352
4364
4353 Mercurial will not let you commit files with unresolved merge
4365 Mercurial will not let you commit files with unresolved merge
4354 conflicts. You must use :hg:`resolve -m ...` before you can
4366 conflicts. You must use :hg:`resolve -m ...` before you can
4355 commit after a conflicting merge.
4367 commit after a conflicting merge.
4356
4368
4357 Returns 0 on success, 1 if any files fail a resolve attempt.
4369 Returns 0 on success, 1 if any files fail a resolve attempt.
4358 """
4370 """
4359
4371
4360 opts = pycompat.byteskwargs(opts)
4372 opts = pycompat.byteskwargs(opts)
4361 flaglist = 'all mark unmark list no_status'.split()
4373 flaglist = 'all mark unmark list no_status'.split()
4362 all, mark, unmark, show, nostatus = \
4374 all, mark, unmark, show, nostatus = \
4363 [opts.get(o) for o in flaglist]
4375 [opts.get(o) for o in flaglist]
4364
4376
4365 if (show and (mark or unmark)) or (mark and unmark):
4377 if (show and (mark or unmark)) or (mark and unmark):
4366 raise error.Abort(_("too many options specified"))
4378 raise error.Abort(_("too many options specified"))
4367 if pats and all:
4379 if pats and all:
4368 raise error.Abort(_("can't specify --all and patterns"))
4380 raise error.Abort(_("can't specify --all and patterns"))
4369 if not (all or pats or show or mark or unmark):
4381 if not (all or pats or show or mark or unmark):
4370 raise error.Abort(_('no files or directories specified'),
4382 raise error.Abort(_('no files or directories specified'),
4371 hint=('use --all to re-merge all unresolved files'))
4383 hint=('use --all to re-merge all unresolved files'))
4372
4384
4373 if show:
4385 if show:
4374 ui.pager('resolve')
4386 ui.pager('resolve')
4375 fm = ui.formatter('resolve', opts)
4387 fm = ui.formatter('resolve', opts)
4376 ms = mergemod.mergestate.read(repo)
4388 ms = mergemod.mergestate.read(repo)
4377 m = scmutil.match(repo[None], pats, opts)
4389 m = scmutil.match(repo[None], pats, opts)
4378
4390
4379 # Labels and keys based on merge state. Unresolved path conflicts show
4391 # Labels and keys based on merge state. Unresolved path conflicts show
4380 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4392 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4381 # resolved conflicts.
4393 # resolved conflicts.
4382 mergestateinfo = {
4394 mergestateinfo = {
4383 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4395 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4384 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4396 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4385 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4397 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4386 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4398 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4387 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4399 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4388 'D'),
4400 'D'),
4389 }
4401 }
4390
4402
4391 for f in ms:
4403 for f in ms:
4392 if not m(f):
4404 if not m(f):
4393 continue
4405 continue
4394
4406
4395 label, key = mergestateinfo[ms[f]]
4407 label, key = mergestateinfo[ms[f]]
4396 fm.startitem()
4408 fm.startitem()
4397 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4409 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4398 fm.write('path', '%s\n', f, label=label)
4410 fm.write('path', '%s\n', f, label=label)
4399 fm.end()
4411 fm.end()
4400 return 0
4412 return 0
4401
4413
4402 with repo.wlock():
4414 with repo.wlock():
4403 ms = mergemod.mergestate.read(repo)
4415 ms = mergemod.mergestate.read(repo)
4404
4416
4405 if not (ms.active() or repo.dirstate.p2() != nullid):
4417 if not (ms.active() or repo.dirstate.p2() != nullid):
4406 raise error.Abort(
4418 raise error.Abort(
4407 _('resolve command not applicable when not merging'))
4419 _('resolve command not applicable when not merging'))
4408
4420
4409 wctx = repo[None]
4421 wctx = repo[None]
4410
4422
4411 if (ms.mergedriver
4423 if (ms.mergedriver
4412 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4424 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4413 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4425 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4414 ms.commit()
4426 ms.commit()
4415 # allow mark and unmark to go through
4427 # allow mark and unmark to go through
4416 if not mark and not unmark and not proceed:
4428 if not mark and not unmark and not proceed:
4417 return 1
4429 return 1
4418
4430
4419 m = scmutil.match(wctx, pats, opts)
4431 m = scmutil.match(wctx, pats, opts)
4420 ret = 0
4432 ret = 0
4421 didwork = False
4433 didwork = False
4422 runconclude = False
4434 runconclude = False
4423
4435
4424 tocomplete = []
4436 tocomplete = []
4425 for f in ms:
4437 for f in ms:
4426 if not m(f):
4438 if not m(f):
4427 continue
4439 continue
4428
4440
4429 didwork = True
4441 didwork = True
4430
4442
4431 # don't let driver-resolved files be marked, and run the conclude
4443 # don't let driver-resolved files be marked, and run the conclude
4432 # step if asked to resolve
4444 # step if asked to resolve
4433 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4445 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4434 exact = m.exact(f)
4446 exact = m.exact(f)
4435 if mark:
4447 if mark:
4436 if exact:
4448 if exact:
4437 ui.warn(_('not marking %s as it is driver-resolved\n')
4449 ui.warn(_('not marking %s as it is driver-resolved\n')
4438 % f)
4450 % f)
4439 elif unmark:
4451 elif unmark:
4440 if exact:
4452 if exact:
4441 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4453 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4442 % f)
4454 % f)
4443 else:
4455 else:
4444 runconclude = True
4456 runconclude = True
4445 continue
4457 continue
4446
4458
4447 # path conflicts must be resolved manually
4459 # path conflicts must be resolved manually
4448 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4460 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4449 mergemod.MERGE_RECORD_RESOLVED_PATH):
4461 mergemod.MERGE_RECORD_RESOLVED_PATH):
4450 if mark:
4462 if mark:
4451 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4463 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4452 elif unmark:
4464 elif unmark:
4453 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4465 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4454 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4466 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4455 ui.warn(_('%s: path conflict must be resolved manually\n')
4467 ui.warn(_('%s: path conflict must be resolved manually\n')
4456 % f)
4468 % f)
4457 continue
4469 continue
4458
4470
4459 if mark:
4471 if mark:
4460 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4472 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4461 elif unmark:
4473 elif unmark:
4462 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4474 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4463 else:
4475 else:
4464 # backup pre-resolve (merge uses .orig for its own purposes)
4476 # backup pre-resolve (merge uses .orig for its own purposes)
4465 a = repo.wjoin(f)
4477 a = repo.wjoin(f)
4466 try:
4478 try:
4467 util.copyfile(a, a + ".resolve")
4479 util.copyfile(a, a + ".resolve")
4468 except (IOError, OSError) as inst:
4480 except (IOError, OSError) as inst:
4469 if inst.errno != errno.ENOENT:
4481 if inst.errno != errno.ENOENT:
4470 raise
4482 raise
4471
4483
4472 try:
4484 try:
4473 # preresolve file
4485 # preresolve file
4474 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4486 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4475 'resolve')
4487 'resolve')
4476 complete, r = ms.preresolve(f, wctx)
4488 complete, r = ms.preresolve(f, wctx)
4477 if not complete:
4489 if not complete:
4478 tocomplete.append(f)
4490 tocomplete.append(f)
4479 elif r:
4491 elif r:
4480 ret = 1
4492 ret = 1
4481 finally:
4493 finally:
4482 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4494 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4483 ms.commit()
4495 ms.commit()
4484
4496
4485 # replace filemerge's .orig file with our resolve file, but only
4497 # replace filemerge's .orig file with our resolve file, but only
4486 # for merges that are complete
4498 # for merges that are complete
4487 if complete:
4499 if complete:
4488 try:
4500 try:
4489 util.rename(a + ".resolve",
4501 util.rename(a + ".resolve",
4490 scmutil.origpath(ui, repo, a))
4502 scmutil.origpath(ui, repo, a))
4491 except OSError as inst:
4503 except OSError as inst:
4492 if inst.errno != errno.ENOENT:
4504 if inst.errno != errno.ENOENT:
4493 raise
4505 raise
4494
4506
4495 for f in tocomplete:
4507 for f in tocomplete:
4496 try:
4508 try:
4497 # resolve file
4509 # resolve file
4498 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4510 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4499 'resolve')
4511 'resolve')
4500 r = ms.resolve(f, wctx)
4512 r = ms.resolve(f, wctx)
4501 if r:
4513 if r:
4502 ret = 1
4514 ret = 1
4503 finally:
4515 finally:
4504 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4516 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4505 ms.commit()
4517 ms.commit()
4506
4518
4507 # replace filemerge's .orig file with our resolve file
4519 # replace filemerge's .orig file with our resolve file
4508 a = repo.wjoin(f)
4520 a = repo.wjoin(f)
4509 try:
4521 try:
4510 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4522 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4511 except OSError as inst:
4523 except OSError as inst:
4512 if inst.errno != errno.ENOENT:
4524 if inst.errno != errno.ENOENT:
4513 raise
4525 raise
4514
4526
4515 ms.commit()
4527 ms.commit()
4516 ms.recordactions()
4528 ms.recordactions()
4517
4529
4518 if not didwork and pats:
4530 if not didwork and pats:
4519 hint = None
4531 hint = None
4520 if not any([p for p in pats if p.find(':') >= 0]):
4532 if not any([p for p in pats if p.find(':') >= 0]):
4521 pats = ['path:%s' % p for p in pats]
4533 pats = ['path:%s' % p for p in pats]
4522 m = scmutil.match(wctx, pats, opts)
4534 m = scmutil.match(wctx, pats, opts)
4523 for f in ms:
4535 for f in ms:
4524 if not m(f):
4536 if not m(f):
4525 continue
4537 continue
4526 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4538 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4527 if opts.get(o)])
4539 if opts.get(o)])
4528 hint = _("(try: hg resolve %s%s)\n") % (
4540 hint = _("(try: hg resolve %s%s)\n") % (
4529 flags,
4541 flags,
4530 ' '.join(pats))
4542 ' '.join(pats))
4531 break
4543 break
4532 ui.warn(_("arguments do not match paths that need resolving\n"))
4544 ui.warn(_("arguments do not match paths that need resolving\n"))
4533 if hint:
4545 if hint:
4534 ui.warn(hint)
4546 ui.warn(hint)
4535 elif ms.mergedriver and ms.mdstate() != 's':
4547 elif ms.mergedriver and ms.mdstate() != 's':
4536 # run conclude step when either a driver-resolved file is requested
4548 # run conclude step when either a driver-resolved file is requested
4537 # or there are no driver-resolved files
4549 # or there are no driver-resolved files
4538 # we can't use 'ret' to determine whether any files are unresolved
4550 # we can't use 'ret' to determine whether any files are unresolved
4539 # because we might not have tried to resolve some
4551 # because we might not have tried to resolve some
4540 if ((runconclude or not list(ms.driverresolved()))
4552 if ((runconclude or not list(ms.driverresolved()))
4541 and not list(ms.unresolved())):
4553 and not list(ms.unresolved())):
4542 proceed = mergemod.driverconclude(repo, ms, wctx)
4554 proceed = mergemod.driverconclude(repo, ms, wctx)
4543 ms.commit()
4555 ms.commit()
4544 if not proceed:
4556 if not proceed:
4545 return 1
4557 return 1
4546
4558
4547 # Nudge users into finishing an unfinished operation
4559 # Nudge users into finishing an unfinished operation
4548 unresolvedf = list(ms.unresolved())
4560 unresolvedf = list(ms.unresolved())
4549 driverresolvedf = list(ms.driverresolved())
4561 driverresolvedf = list(ms.driverresolved())
4550 if not unresolvedf and not driverresolvedf:
4562 if not unresolvedf and not driverresolvedf:
4551 ui.status(_('(no more unresolved files)\n'))
4563 ui.status(_('(no more unresolved files)\n'))
4552 cmdutil.checkafterresolved(repo)
4564 cmdutil.checkafterresolved(repo)
4553 elif not unresolvedf:
4565 elif not unresolvedf:
4554 ui.status(_('(no more unresolved files -- '
4566 ui.status(_('(no more unresolved files -- '
4555 'run "hg resolve --all" to conclude)\n'))
4567 'run "hg resolve --all" to conclude)\n'))
4556
4568
4557 return ret
4569 return ret
4558
4570
4559 @command('revert',
4571 @command('revert',
4560 [('a', 'all', None, _('revert all changes when no arguments given')),
4572 [('a', 'all', None, _('revert all changes when no arguments given')),
4561 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4573 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4562 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4574 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4563 ('C', 'no-backup', None, _('do not save backup copies of files')),
4575 ('C', 'no-backup', None, _('do not save backup copies of files')),
4564 ('i', 'interactive', None, _('interactively select the changes')),
4576 ('i', 'interactive', None, _('interactively select the changes')),
4565 ] + walkopts + dryrunopts,
4577 ] + walkopts + dryrunopts,
4566 _('[OPTION]... [-r REV] [NAME]...'))
4578 _('[OPTION]... [-r REV] [NAME]...'))
4567 def revert(ui, repo, *pats, **opts):
4579 def revert(ui, repo, *pats, **opts):
4568 """restore files to their checkout state
4580 """restore files to their checkout state
4569
4581
4570 .. note::
4582 .. note::
4571
4583
4572 To check out earlier revisions, you should use :hg:`update REV`.
4584 To check out earlier revisions, you should use :hg:`update REV`.
4573 To cancel an uncommitted merge (and lose your changes),
4585 To cancel an uncommitted merge (and lose your changes),
4574 use :hg:`merge --abort`.
4586 use :hg:`merge --abort`.
4575
4587
4576 With no revision specified, revert the specified files or directories
4588 With no revision specified, revert the specified files or directories
4577 to the contents they had in the parent of the working directory.
4589 to the contents they had in the parent of the working directory.
4578 This restores the contents of files to an unmodified
4590 This restores the contents of files to an unmodified
4579 state and unschedules adds, removes, copies, and renames. If the
4591 state and unschedules adds, removes, copies, and renames. If the
4580 working directory has two parents, you must explicitly specify a
4592 working directory has two parents, you must explicitly specify a
4581 revision.
4593 revision.
4582
4594
4583 Using the -r/--rev or -d/--date options, revert the given files or
4595 Using the -r/--rev or -d/--date options, revert the given files or
4584 directories to their states as of a specific revision. Because
4596 directories to their states as of a specific revision. Because
4585 revert does not change the working directory parents, this will
4597 revert does not change the working directory parents, this will
4586 cause these files to appear modified. This can be helpful to "back
4598 cause these files to appear modified. This can be helpful to "back
4587 out" some or all of an earlier change. See :hg:`backout` for a
4599 out" some or all of an earlier change. See :hg:`backout` for a
4588 related method.
4600 related method.
4589
4601
4590 Modified files are saved with a .orig suffix before reverting.
4602 Modified files are saved with a .orig suffix before reverting.
4591 To disable these backups, use --no-backup. It is possible to store
4603 To disable these backups, use --no-backup. It is possible to store
4592 the backup files in a custom directory relative to the root of the
4604 the backup files in a custom directory relative to the root of the
4593 repository by setting the ``ui.origbackuppath`` configuration
4605 repository by setting the ``ui.origbackuppath`` configuration
4594 option.
4606 option.
4595
4607
4596 See :hg:`help dates` for a list of formats valid for -d/--date.
4608 See :hg:`help dates` for a list of formats valid for -d/--date.
4597
4609
4598 See :hg:`help backout` for a way to reverse the effect of an
4610 See :hg:`help backout` for a way to reverse the effect of an
4599 earlier changeset.
4611 earlier changeset.
4600
4612
4601 Returns 0 on success.
4613 Returns 0 on success.
4602 """
4614 """
4603
4615
4604 opts = pycompat.byteskwargs(opts)
4616 opts = pycompat.byteskwargs(opts)
4605 if opts.get("date"):
4617 if opts.get("date"):
4606 if opts.get("rev"):
4618 if opts.get("rev"):
4607 raise error.Abort(_("you can't specify a revision and a date"))
4619 raise error.Abort(_("you can't specify a revision and a date"))
4608 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4620 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4609
4621
4610 parent, p2 = repo.dirstate.parents()
4622 parent, p2 = repo.dirstate.parents()
4611 if not opts.get('rev') and p2 != nullid:
4623 if not opts.get('rev') and p2 != nullid:
4612 # revert after merge is a trap for new users (issue2915)
4624 # revert after merge is a trap for new users (issue2915)
4613 raise error.Abort(_('uncommitted merge with no revision specified'),
4625 raise error.Abort(_('uncommitted merge with no revision specified'),
4614 hint=_("use 'hg update' or see 'hg help revert'"))
4626 hint=_("use 'hg update' or see 'hg help revert'"))
4615
4627
4616 rev = opts.get('rev')
4628 rev = opts.get('rev')
4617 if rev:
4629 if rev:
4618 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4630 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4619 ctx = scmutil.revsingle(repo, rev)
4631 ctx = scmutil.revsingle(repo, rev)
4620
4632
4621 if (not (pats or opts.get('include') or opts.get('exclude') or
4633 if (not (pats or opts.get('include') or opts.get('exclude') or
4622 opts.get('all') or opts.get('interactive'))):
4634 opts.get('all') or opts.get('interactive'))):
4623 msg = _("no files or directories specified")
4635 msg = _("no files or directories specified")
4624 if p2 != nullid:
4636 if p2 != nullid:
4625 hint = _("uncommitted merge, use --all to discard all changes,"
4637 hint = _("uncommitted merge, use --all to discard all changes,"
4626 " or 'hg update -C .' to abort the merge")
4638 " or 'hg update -C .' to abort the merge")
4627 raise error.Abort(msg, hint=hint)
4639 raise error.Abort(msg, hint=hint)
4628 dirty = any(repo.status())
4640 dirty = any(repo.status())
4629 node = ctx.node()
4641 node = ctx.node()
4630 if node != parent:
4642 if node != parent:
4631 if dirty:
4643 if dirty:
4632 hint = _("uncommitted changes, use --all to discard all"
4644 hint = _("uncommitted changes, use --all to discard all"
4633 " changes, or 'hg update %s' to update") % ctx.rev()
4645 " changes, or 'hg update %s' to update") % ctx.rev()
4634 else:
4646 else:
4635 hint = _("use --all to revert all files,"
4647 hint = _("use --all to revert all files,"
4636 " or 'hg update %s' to update") % ctx.rev()
4648 " or 'hg update %s' to update") % ctx.rev()
4637 elif dirty:
4649 elif dirty:
4638 hint = _("uncommitted changes, use --all to discard all changes")
4650 hint = _("uncommitted changes, use --all to discard all changes")
4639 else:
4651 else:
4640 hint = _("use --all to revert all files")
4652 hint = _("use --all to revert all files")
4641 raise error.Abort(msg, hint=hint)
4653 raise error.Abort(msg, hint=hint)
4642
4654
4643 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4655 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4644 **pycompat.strkwargs(opts))
4656 **pycompat.strkwargs(opts))
4645
4657
4646 @command('rollback', dryrunopts +
4658 @command('rollback', dryrunopts +
4647 [('f', 'force', False, _('ignore safety measures'))])
4659 [('f', 'force', False, _('ignore safety measures'))])
4648 def rollback(ui, repo, **opts):
4660 def rollback(ui, repo, **opts):
4649 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4661 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4650
4662
4651 Please use :hg:`commit --amend` instead of rollback to correct
4663 Please use :hg:`commit --amend` instead of rollback to correct
4652 mistakes in the last commit.
4664 mistakes in the last commit.
4653
4665
4654 This command should be used with care. There is only one level of
4666 This command should be used with care. There is only one level of
4655 rollback, and there is no way to undo a rollback. It will also
4667 rollback, and there is no way to undo a rollback. It will also
4656 restore the dirstate at the time of the last transaction, losing
4668 restore the dirstate at the time of the last transaction, losing
4657 any dirstate changes since that time. This command does not alter
4669 any dirstate changes since that time. This command does not alter
4658 the working directory.
4670 the working directory.
4659
4671
4660 Transactions are used to encapsulate the effects of all commands
4672 Transactions are used to encapsulate the effects of all commands
4661 that create new changesets or propagate existing changesets into a
4673 that create new changesets or propagate existing changesets into a
4662 repository.
4674 repository.
4663
4675
4664 .. container:: verbose
4676 .. container:: verbose
4665
4677
4666 For example, the following commands are transactional, and their
4678 For example, the following commands are transactional, and their
4667 effects can be rolled back:
4679 effects can be rolled back:
4668
4680
4669 - commit
4681 - commit
4670 - import
4682 - import
4671 - pull
4683 - pull
4672 - push (with this repository as the destination)
4684 - push (with this repository as the destination)
4673 - unbundle
4685 - unbundle
4674
4686
4675 To avoid permanent data loss, rollback will refuse to rollback a
4687 To avoid permanent data loss, rollback will refuse to rollback a
4676 commit transaction if it isn't checked out. Use --force to
4688 commit transaction if it isn't checked out. Use --force to
4677 override this protection.
4689 override this protection.
4678
4690
4679 The rollback command can be entirely disabled by setting the
4691 The rollback command can be entirely disabled by setting the
4680 ``ui.rollback`` configuration setting to false. If you're here
4692 ``ui.rollback`` configuration setting to false. If you're here
4681 because you want to use rollback and it's disabled, you can
4693 because you want to use rollback and it's disabled, you can
4682 re-enable the command by setting ``ui.rollback`` to true.
4694 re-enable the command by setting ``ui.rollback`` to true.
4683
4695
4684 This command is not intended for use on public repositories. Once
4696 This command is not intended for use on public repositories. Once
4685 changes are visible for pull by other users, rolling a transaction
4697 changes are visible for pull by other users, rolling a transaction
4686 back locally is ineffective (someone else may already have pulled
4698 back locally is ineffective (someone else may already have pulled
4687 the changes). Furthermore, a race is possible with readers of the
4699 the changes). Furthermore, a race is possible with readers of the
4688 repository; for example an in-progress pull from the repository
4700 repository; for example an in-progress pull from the repository
4689 may fail if a rollback is performed.
4701 may fail if a rollback is performed.
4690
4702
4691 Returns 0 on success, 1 if no rollback data is available.
4703 Returns 0 on success, 1 if no rollback data is available.
4692 """
4704 """
4693 if not ui.configbool('ui', 'rollback'):
4705 if not ui.configbool('ui', 'rollback'):
4694 raise error.Abort(_('rollback is disabled because it is unsafe'),
4706 raise error.Abort(_('rollback is disabled because it is unsafe'),
4695 hint=('see `hg help -v rollback` for information'))
4707 hint=('see `hg help -v rollback` for information'))
4696 return repo.rollback(dryrun=opts.get(r'dry_run'),
4708 return repo.rollback(dryrun=opts.get(r'dry_run'),
4697 force=opts.get(r'force'))
4709 force=opts.get(r'force'))
4698
4710
4699 @command('root', [], cmdtype=readonly)
4711 @command('root', [], intents={INTENT_READONLY})
4700 def root(ui, repo):
4712 def root(ui, repo):
4701 """print the root (top) of the current working directory
4713 """print the root (top) of the current working directory
4702
4714
4703 Print the root directory of the current repository.
4715 Print the root directory of the current repository.
4704
4716
4705 Returns 0 on success.
4717 Returns 0 on success.
4706 """
4718 """
4707 ui.write(repo.root + "\n")
4719 ui.write(repo.root + "\n")
4708
4720
4709 @command('^serve',
4721 @command('^serve',
4710 [('A', 'accesslog', '', _('name of access log file to write to'),
4722 [('A', 'accesslog', '', _('name of access log file to write to'),
4711 _('FILE')),
4723 _('FILE')),
4712 ('d', 'daemon', None, _('run server in background')),
4724 ('d', 'daemon', None, _('run server in background')),
4713 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4725 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4714 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4726 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4715 # use string type, then we can check if something was passed
4727 # use string type, then we can check if something was passed
4716 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4728 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4717 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4729 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4718 _('ADDR')),
4730 _('ADDR')),
4719 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4731 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4720 _('PREFIX')),
4732 _('PREFIX')),
4721 ('n', 'name', '',
4733 ('n', 'name', '',
4722 _('name to show in web pages (default: working directory)'), _('NAME')),
4734 _('name to show in web pages (default: working directory)'), _('NAME')),
4723 ('', 'web-conf', '',
4735 ('', 'web-conf', '',
4724 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4736 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4725 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4737 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4726 _('FILE')),
4738 _('FILE')),
4727 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4739 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4728 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4740 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4729 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4741 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4730 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4742 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4731 ('', 'style', '', _('template style to use'), _('STYLE')),
4743 ('', 'style', '', _('template style to use'), _('STYLE')),
4732 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4744 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4733 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4745 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4734 + subrepoopts,
4746 + subrepoopts,
4735 _('[OPTION]...'),
4747 _('[OPTION]...'),
4736 optionalrepo=True)
4748 optionalrepo=True)
4737 def serve(ui, repo, **opts):
4749 def serve(ui, repo, **opts):
4738 """start stand-alone webserver
4750 """start stand-alone webserver
4739
4751
4740 Start a local HTTP repository browser and pull server. You can use
4752 Start a local HTTP repository browser and pull server. You can use
4741 this for ad-hoc sharing and browsing of repositories. It is
4753 this for ad-hoc sharing and browsing of repositories. It is
4742 recommended to use a real web server to serve a repository for
4754 recommended to use a real web server to serve a repository for
4743 longer periods of time.
4755 longer periods of time.
4744
4756
4745 Please note that the server does not implement access control.
4757 Please note that the server does not implement access control.
4746 This means that, by default, anybody can read from the server and
4758 This means that, by default, anybody can read from the server and
4747 nobody can write to it by default. Set the ``web.allow-push``
4759 nobody can write to it by default. Set the ``web.allow-push``
4748 option to ``*`` to allow everybody to push to the server. You
4760 option to ``*`` to allow everybody to push to the server. You
4749 should use a real web server if you need to authenticate users.
4761 should use a real web server if you need to authenticate users.
4750
4762
4751 By default, the server logs accesses to stdout and errors to
4763 By default, the server logs accesses to stdout and errors to
4752 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4764 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4753 files.
4765 files.
4754
4766
4755 To have the server choose a free port number to listen on, specify
4767 To have the server choose a free port number to listen on, specify
4756 a port number of 0; in this case, the server will print the port
4768 a port number of 0; in this case, the server will print the port
4757 number it uses.
4769 number it uses.
4758
4770
4759 Returns 0 on success.
4771 Returns 0 on success.
4760 """
4772 """
4761
4773
4762 opts = pycompat.byteskwargs(opts)
4774 opts = pycompat.byteskwargs(opts)
4763 if opts["stdio"] and opts["cmdserver"]:
4775 if opts["stdio"] and opts["cmdserver"]:
4764 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4776 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4765
4777
4766 if opts["stdio"]:
4778 if opts["stdio"]:
4767 if repo is None:
4779 if repo is None:
4768 raise error.RepoError(_("there is no Mercurial repository here"
4780 raise error.RepoError(_("there is no Mercurial repository here"
4769 " (.hg not found)"))
4781 " (.hg not found)"))
4770 s = wireprotoserver.sshserver(ui, repo)
4782 s = wireprotoserver.sshserver(ui, repo)
4771 s.serve_forever()
4783 s.serve_forever()
4772
4784
4773 service = server.createservice(ui, repo, opts)
4785 service = server.createservice(ui, repo, opts)
4774 return server.runservice(opts, initfn=service.init, runfn=service.run)
4786 return server.runservice(opts, initfn=service.init, runfn=service.run)
4775
4787
4776 @command('^status|st',
4788 @command('^status|st',
4777 [('A', 'all', None, _('show status of all files')),
4789 [('A', 'all', None, _('show status of all files')),
4778 ('m', 'modified', None, _('show only modified files')),
4790 ('m', 'modified', None, _('show only modified files')),
4779 ('a', 'added', None, _('show only added files')),
4791 ('a', 'added', None, _('show only added files')),
4780 ('r', 'removed', None, _('show only removed files')),
4792 ('r', 'removed', None, _('show only removed files')),
4781 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4793 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4782 ('c', 'clean', None, _('show only files without changes')),
4794 ('c', 'clean', None, _('show only files without changes')),
4783 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4795 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4784 ('i', 'ignored', None, _('show only ignored files')),
4796 ('i', 'ignored', None, _('show only ignored files')),
4785 ('n', 'no-status', None, _('hide status prefix')),
4797 ('n', 'no-status', None, _('hide status prefix')),
4786 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4798 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4787 ('C', 'copies', None, _('show source of copied files')),
4799 ('C', 'copies', None, _('show source of copied files')),
4788 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4800 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4789 ('', 'rev', [], _('show difference from revision'), _('REV')),
4801 ('', 'rev', [], _('show difference from revision'), _('REV')),
4790 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4802 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4791 ] + walkopts + subrepoopts + formatteropts,
4803 ] + walkopts + subrepoopts + formatteropts,
4792 _('[OPTION]... [FILE]...'),
4804 _('[OPTION]... [FILE]...'),
4793 inferrepo=True, cmdtype=readonly)
4805 inferrepo=True,
4806 intents={INTENT_READONLY})
4794 def status(ui, repo, *pats, **opts):
4807 def status(ui, repo, *pats, **opts):
4795 """show changed files in the working directory
4808 """show changed files in the working directory
4796
4809
4797 Show status of files in the repository. If names are given, only
4810 Show status of files in the repository. If names are given, only
4798 files that match are shown. Files that are clean or ignored or
4811 files that match are shown. Files that are clean or ignored or
4799 the source of a copy/move operation, are not listed unless
4812 the source of a copy/move operation, are not listed unless
4800 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4813 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4801 Unless options described with "show only ..." are given, the
4814 Unless options described with "show only ..." are given, the
4802 options -mardu are used.
4815 options -mardu are used.
4803
4816
4804 Option -q/--quiet hides untracked (unknown and ignored) files
4817 Option -q/--quiet hides untracked (unknown and ignored) files
4805 unless explicitly requested with -u/--unknown or -i/--ignored.
4818 unless explicitly requested with -u/--unknown or -i/--ignored.
4806
4819
4807 .. note::
4820 .. note::
4808
4821
4809 :hg:`status` may appear to disagree with diff if permissions have
4822 :hg:`status` may appear to disagree with diff if permissions have
4810 changed or a merge has occurred. The standard diff format does
4823 changed or a merge has occurred. The standard diff format does
4811 not report permission changes and diff only reports changes
4824 not report permission changes and diff only reports changes
4812 relative to one merge parent.
4825 relative to one merge parent.
4813
4826
4814 If one revision is given, it is used as the base revision.
4827 If one revision is given, it is used as the base revision.
4815 If two revisions are given, the differences between them are
4828 If two revisions are given, the differences between them are
4816 shown. The --change option can also be used as a shortcut to list
4829 shown. The --change option can also be used as a shortcut to list
4817 the changed files of a revision from its first parent.
4830 the changed files of a revision from its first parent.
4818
4831
4819 The codes used to show the status of files are::
4832 The codes used to show the status of files are::
4820
4833
4821 M = modified
4834 M = modified
4822 A = added
4835 A = added
4823 R = removed
4836 R = removed
4824 C = clean
4837 C = clean
4825 ! = missing (deleted by non-hg command, but still tracked)
4838 ! = missing (deleted by non-hg command, but still tracked)
4826 ? = not tracked
4839 ? = not tracked
4827 I = ignored
4840 I = ignored
4828 = origin of the previous file (with --copies)
4841 = origin of the previous file (with --copies)
4829
4842
4830 .. container:: verbose
4843 .. container:: verbose
4831
4844
4832 The -t/--terse option abbreviates the output by showing only the directory
4845 The -t/--terse option abbreviates the output by showing only the directory
4833 name if all the files in it share the same status. The option takes an
4846 name if all the files in it share the same status. The option takes an
4834 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4847 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4835 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4848 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4836 for 'ignored' and 'c' for clean.
4849 for 'ignored' and 'c' for clean.
4837
4850
4838 It abbreviates only those statuses which are passed. Note that clean and
4851 It abbreviates only those statuses which are passed. Note that clean and
4839 ignored files are not displayed with '--terse ic' unless the -c/--clean
4852 ignored files are not displayed with '--terse ic' unless the -c/--clean
4840 and -i/--ignored options are also used.
4853 and -i/--ignored options are also used.
4841
4854
4842 The -v/--verbose option shows information when the repository is in an
4855 The -v/--verbose option shows information when the repository is in an
4843 unfinished merge, shelve, rebase state etc. You can have this behavior
4856 unfinished merge, shelve, rebase state etc. You can have this behavior
4844 turned on by default by enabling the ``commands.status.verbose`` option.
4857 turned on by default by enabling the ``commands.status.verbose`` option.
4845
4858
4846 You can skip displaying some of these states by setting
4859 You can skip displaying some of these states by setting
4847 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4860 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4848 'histedit', 'merge', 'rebase', or 'unshelve'.
4861 'histedit', 'merge', 'rebase', or 'unshelve'.
4849
4862
4850 Examples:
4863 Examples:
4851
4864
4852 - show changes in the working directory relative to a
4865 - show changes in the working directory relative to a
4853 changeset::
4866 changeset::
4854
4867
4855 hg status --rev 9353
4868 hg status --rev 9353
4856
4869
4857 - show changes in the working directory relative to the
4870 - show changes in the working directory relative to the
4858 current directory (see :hg:`help patterns` for more information)::
4871 current directory (see :hg:`help patterns` for more information)::
4859
4872
4860 hg status re:
4873 hg status re:
4861
4874
4862 - show all changes including copies in an existing changeset::
4875 - show all changes including copies in an existing changeset::
4863
4876
4864 hg status --copies --change 9353
4877 hg status --copies --change 9353
4865
4878
4866 - get a NUL separated list of added files, suitable for xargs::
4879 - get a NUL separated list of added files, suitable for xargs::
4867
4880
4868 hg status -an0
4881 hg status -an0
4869
4882
4870 - show more information about the repository status, abbreviating
4883 - show more information about the repository status, abbreviating
4871 added, removed, modified, deleted, and untracked paths::
4884 added, removed, modified, deleted, and untracked paths::
4872
4885
4873 hg status -v -t mardu
4886 hg status -v -t mardu
4874
4887
4875 Returns 0 on success.
4888 Returns 0 on success.
4876
4889
4877 """
4890 """
4878
4891
4879 opts = pycompat.byteskwargs(opts)
4892 opts = pycompat.byteskwargs(opts)
4880 revs = opts.get('rev')
4893 revs = opts.get('rev')
4881 change = opts.get('change')
4894 change = opts.get('change')
4882 terse = opts.get('terse')
4895 terse = opts.get('terse')
4883
4896
4884 if revs and change:
4897 if revs and change:
4885 msg = _('cannot specify --rev and --change at the same time')
4898 msg = _('cannot specify --rev and --change at the same time')
4886 raise error.Abort(msg)
4899 raise error.Abort(msg)
4887 elif revs and terse:
4900 elif revs and terse:
4888 msg = _('cannot use --terse with --rev')
4901 msg = _('cannot use --terse with --rev')
4889 raise error.Abort(msg)
4902 raise error.Abort(msg)
4890 elif change:
4903 elif change:
4891 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4904 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4892 ctx2 = scmutil.revsingle(repo, change, None)
4905 ctx2 = scmutil.revsingle(repo, change, None)
4893 ctx1 = ctx2.p1()
4906 ctx1 = ctx2.p1()
4894 else:
4907 else:
4895 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4908 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4896 ctx1, ctx2 = scmutil.revpair(repo, revs)
4909 ctx1, ctx2 = scmutil.revpair(repo, revs)
4897
4910
4898 if pats or ui.configbool('commands', 'status.relative'):
4911 if pats or ui.configbool('commands', 'status.relative'):
4899 cwd = repo.getcwd()
4912 cwd = repo.getcwd()
4900 else:
4913 else:
4901 cwd = ''
4914 cwd = ''
4902
4915
4903 if opts.get('print0'):
4916 if opts.get('print0'):
4904 end = '\0'
4917 end = '\0'
4905 else:
4918 else:
4906 end = '\n'
4919 end = '\n'
4907 copy = {}
4920 copy = {}
4908 states = 'modified added removed deleted unknown ignored clean'.split()
4921 states = 'modified added removed deleted unknown ignored clean'.split()
4909 show = [k for k in states if opts.get(k)]
4922 show = [k for k in states if opts.get(k)]
4910 if opts.get('all'):
4923 if opts.get('all'):
4911 show += ui.quiet and (states[:4] + ['clean']) or states
4924 show += ui.quiet and (states[:4] + ['clean']) or states
4912
4925
4913 if not show:
4926 if not show:
4914 if ui.quiet:
4927 if ui.quiet:
4915 show = states[:4]
4928 show = states[:4]
4916 else:
4929 else:
4917 show = states[:5]
4930 show = states[:5]
4918
4931
4919 m = scmutil.match(ctx2, pats, opts)
4932 m = scmutil.match(ctx2, pats, opts)
4920 if terse:
4933 if terse:
4921 # we need to compute clean and unknown to terse
4934 # we need to compute clean and unknown to terse
4922 stat = repo.status(ctx1.node(), ctx2.node(), m,
4935 stat = repo.status(ctx1.node(), ctx2.node(), m,
4923 'ignored' in show or 'i' in terse,
4936 'ignored' in show or 'i' in terse,
4924 True, True, opts.get('subrepos'))
4937 True, True, opts.get('subrepos'))
4925
4938
4926 stat = cmdutil.tersedir(stat, terse)
4939 stat = cmdutil.tersedir(stat, terse)
4927 else:
4940 else:
4928 stat = repo.status(ctx1.node(), ctx2.node(), m,
4941 stat = repo.status(ctx1.node(), ctx2.node(), m,
4929 'ignored' in show, 'clean' in show,
4942 'ignored' in show, 'clean' in show,
4930 'unknown' in show, opts.get('subrepos'))
4943 'unknown' in show, opts.get('subrepos'))
4931
4944
4932 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4945 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4933
4946
4934 if (opts.get('all') or opts.get('copies')
4947 if (opts.get('all') or opts.get('copies')
4935 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4948 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4936 copy = copies.pathcopies(ctx1, ctx2, m)
4949 copy = copies.pathcopies(ctx1, ctx2, m)
4937
4950
4938 ui.pager('status')
4951 ui.pager('status')
4939 fm = ui.formatter('status', opts)
4952 fm = ui.formatter('status', opts)
4940 fmt = '%s' + end
4953 fmt = '%s' + end
4941 showchar = not opts.get('no_status')
4954 showchar = not opts.get('no_status')
4942
4955
4943 for state, char, files in changestates:
4956 for state, char, files in changestates:
4944 if state in show:
4957 if state in show:
4945 label = 'status.' + state
4958 label = 'status.' + state
4946 for f in files:
4959 for f in files:
4947 fm.startitem()
4960 fm.startitem()
4948 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4961 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4949 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4962 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4950 if f in copy:
4963 if f in copy:
4951 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4964 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4952 label='status.copied')
4965 label='status.copied')
4953
4966
4954 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4967 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4955 and not ui.plain()):
4968 and not ui.plain()):
4956 cmdutil.morestatus(repo, fm)
4969 cmdutil.morestatus(repo, fm)
4957 fm.end()
4970 fm.end()
4958
4971
4959 @command('^summary|sum',
4972 @command('^summary|sum',
4960 [('', 'remote', None, _('check for push and pull'))],
4973 [('', 'remote', None, _('check for push and pull'))],
4961 '[--remote]', cmdtype=readonly)
4974 '[--remote]',
4975 intents={INTENT_READONLY})
4962 def summary(ui, repo, **opts):
4976 def summary(ui, repo, **opts):
4963 """summarize working directory state
4977 """summarize working directory state
4964
4978
4965 This generates a brief summary of the working directory state,
4979 This generates a brief summary of the working directory state,
4966 including parents, branch, commit status, phase and available updates.
4980 including parents, branch, commit status, phase and available updates.
4967
4981
4968 With the --remote option, this will check the default paths for
4982 With the --remote option, this will check the default paths for
4969 incoming and outgoing changes. This can be time-consuming.
4983 incoming and outgoing changes. This can be time-consuming.
4970
4984
4971 Returns 0 on success.
4985 Returns 0 on success.
4972 """
4986 """
4973
4987
4974 opts = pycompat.byteskwargs(opts)
4988 opts = pycompat.byteskwargs(opts)
4975 ui.pager('summary')
4989 ui.pager('summary')
4976 ctx = repo[None]
4990 ctx = repo[None]
4977 parents = ctx.parents()
4991 parents = ctx.parents()
4978 pnode = parents[0].node()
4992 pnode = parents[0].node()
4979 marks = []
4993 marks = []
4980
4994
4981 ms = None
4995 ms = None
4982 try:
4996 try:
4983 ms = mergemod.mergestate.read(repo)
4997 ms = mergemod.mergestate.read(repo)
4984 except error.UnsupportedMergeRecords as e:
4998 except error.UnsupportedMergeRecords as e:
4985 s = ' '.join(e.recordtypes)
4999 s = ' '.join(e.recordtypes)
4986 ui.warn(
5000 ui.warn(
4987 _('warning: merge state has unsupported record types: %s\n') % s)
5001 _('warning: merge state has unsupported record types: %s\n') % s)
4988 unresolved = []
5002 unresolved = []
4989 else:
5003 else:
4990 unresolved = list(ms.unresolved())
5004 unresolved = list(ms.unresolved())
4991
5005
4992 for p in parents:
5006 for p in parents:
4993 # label with log.changeset (instead of log.parent) since this
5007 # label with log.changeset (instead of log.parent) since this
4994 # shows a working directory parent *changeset*:
5008 # shows a working directory parent *changeset*:
4995 # i18n: column positioning for "hg summary"
5009 # i18n: column positioning for "hg summary"
4996 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5010 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4997 label=logcmdutil.changesetlabels(p))
5011 label=logcmdutil.changesetlabels(p))
4998 ui.write(' '.join(p.tags()), label='log.tag')
5012 ui.write(' '.join(p.tags()), label='log.tag')
4999 if p.bookmarks():
5013 if p.bookmarks():
5000 marks.extend(p.bookmarks())
5014 marks.extend(p.bookmarks())
5001 if p.rev() == -1:
5015 if p.rev() == -1:
5002 if not len(repo):
5016 if not len(repo):
5003 ui.write(_(' (empty repository)'))
5017 ui.write(_(' (empty repository)'))
5004 else:
5018 else:
5005 ui.write(_(' (no revision checked out)'))
5019 ui.write(_(' (no revision checked out)'))
5006 if p.obsolete():
5020 if p.obsolete():
5007 ui.write(_(' (obsolete)'))
5021 ui.write(_(' (obsolete)'))
5008 if p.isunstable():
5022 if p.isunstable():
5009 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5023 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5010 for instability in p.instabilities())
5024 for instability in p.instabilities())
5011 ui.write(' ('
5025 ui.write(' ('
5012 + ', '.join(instabilities)
5026 + ', '.join(instabilities)
5013 + ')')
5027 + ')')
5014 ui.write('\n')
5028 ui.write('\n')
5015 if p.description():
5029 if p.description():
5016 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5030 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5017 label='log.summary')
5031 label='log.summary')
5018
5032
5019 branch = ctx.branch()
5033 branch = ctx.branch()
5020 bheads = repo.branchheads(branch)
5034 bheads = repo.branchheads(branch)
5021 # i18n: column positioning for "hg summary"
5035 # i18n: column positioning for "hg summary"
5022 m = _('branch: %s\n') % branch
5036 m = _('branch: %s\n') % branch
5023 if branch != 'default':
5037 if branch != 'default':
5024 ui.write(m, label='log.branch')
5038 ui.write(m, label='log.branch')
5025 else:
5039 else:
5026 ui.status(m, label='log.branch')
5040 ui.status(m, label='log.branch')
5027
5041
5028 if marks:
5042 if marks:
5029 active = repo._activebookmark
5043 active = repo._activebookmark
5030 # i18n: column positioning for "hg summary"
5044 # i18n: column positioning for "hg summary"
5031 ui.write(_('bookmarks:'), label='log.bookmark')
5045 ui.write(_('bookmarks:'), label='log.bookmark')
5032 if active is not None:
5046 if active is not None:
5033 if active in marks:
5047 if active in marks:
5034 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5048 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5035 marks.remove(active)
5049 marks.remove(active)
5036 else:
5050 else:
5037 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5051 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5038 for m in marks:
5052 for m in marks:
5039 ui.write(' ' + m, label='log.bookmark')
5053 ui.write(' ' + m, label='log.bookmark')
5040 ui.write('\n', label='log.bookmark')
5054 ui.write('\n', label='log.bookmark')
5041
5055
5042 status = repo.status(unknown=True)
5056 status = repo.status(unknown=True)
5043
5057
5044 c = repo.dirstate.copies()
5058 c = repo.dirstate.copies()
5045 copied, renamed = [], []
5059 copied, renamed = [], []
5046 for d, s in c.iteritems():
5060 for d, s in c.iteritems():
5047 if s in status.removed:
5061 if s in status.removed:
5048 status.removed.remove(s)
5062 status.removed.remove(s)
5049 renamed.append(d)
5063 renamed.append(d)
5050 else:
5064 else:
5051 copied.append(d)
5065 copied.append(d)
5052 if d in status.added:
5066 if d in status.added:
5053 status.added.remove(d)
5067 status.added.remove(d)
5054
5068
5055 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5069 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5056
5070
5057 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5071 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5058 (ui.label(_('%d added'), 'status.added'), status.added),
5072 (ui.label(_('%d added'), 'status.added'), status.added),
5059 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5073 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5060 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5074 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5061 (ui.label(_('%d copied'), 'status.copied'), copied),
5075 (ui.label(_('%d copied'), 'status.copied'), copied),
5062 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5076 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5063 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5077 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5064 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5078 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5065 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5079 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5066 t = []
5080 t = []
5067 for l, s in labels:
5081 for l, s in labels:
5068 if s:
5082 if s:
5069 t.append(l % len(s))
5083 t.append(l % len(s))
5070
5084
5071 t = ', '.join(t)
5085 t = ', '.join(t)
5072 cleanworkdir = False
5086 cleanworkdir = False
5073
5087
5074 if repo.vfs.exists('graftstate'):
5088 if repo.vfs.exists('graftstate'):
5075 t += _(' (graft in progress)')
5089 t += _(' (graft in progress)')
5076 if repo.vfs.exists('updatestate'):
5090 if repo.vfs.exists('updatestate'):
5077 t += _(' (interrupted update)')
5091 t += _(' (interrupted update)')
5078 elif len(parents) > 1:
5092 elif len(parents) > 1:
5079 t += _(' (merge)')
5093 t += _(' (merge)')
5080 elif branch != parents[0].branch():
5094 elif branch != parents[0].branch():
5081 t += _(' (new branch)')
5095 t += _(' (new branch)')
5082 elif (parents[0].closesbranch() and
5096 elif (parents[0].closesbranch() and
5083 pnode in repo.branchheads(branch, closed=True)):
5097 pnode in repo.branchheads(branch, closed=True)):
5084 t += _(' (head closed)')
5098 t += _(' (head closed)')
5085 elif not (status.modified or status.added or status.removed or renamed or
5099 elif not (status.modified or status.added or status.removed or renamed or
5086 copied or subs):
5100 copied or subs):
5087 t += _(' (clean)')
5101 t += _(' (clean)')
5088 cleanworkdir = True
5102 cleanworkdir = True
5089 elif pnode not in bheads:
5103 elif pnode not in bheads:
5090 t += _(' (new branch head)')
5104 t += _(' (new branch head)')
5091
5105
5092 if parents:
5106 if parents:
5093 pendingphase = max(p.phase() for p in parents)
5107 pendingphase = max(p.phase() for p in parents)
5094 else:
5108 else:
5095 pendingphase = phases.public
5109 pendingphase = phases.public
5096
5110
5097 if pendingphase > phases.newcommitphase(ui):
5111 if pendingphase > phases.newcommitphase(ui):
5098 t += ' (%s)' % phases.phasenames[pendingphase]
5112 t += ' (%s)' % phases.phasenames[pendingphase]
5099
5113
5100 if cleanworkdir:
5114 if cleanworkdir:
5101 # i18n: column positioning for "hg summary"
5115 # i18n: column positioning for "hg summary"
5102 ui.status(_('commit: %s\n') % t.strip())
5116 ui.status(_('commit: %s\n') % t.strip())
5103 else:
5117 else:
5104 # i18n: column positioning for "hg summary"
5118 # i18n: column positioning for "hg summary"
5105 ui.write(_('commit: %s\n') % t.strip())
5119 ui.write(_('commit: %s\n') % t.strip())
5106
5120
5107 # all ancestors of branch heads - all ancestors of parent = new csets
5121 # all ancestors of branch heads - all ancestors of parent = new csets
5108 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5122 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5109 bheads))
5123 bheads))
5110
5124
5111 if new == 0:
5125 if new == 0:
5112 # i18n: column positioning for "hg summary"
5126 # i18n: column positioning for "hg summary"
5113 ui.status(_('update: (current)\n'))
5127 ui.status(_('update: (current)\n'))
5114 elif pnode not in bheads:
5128 elif pnode not in bheads:
5115 # i18n: column positioning for "hg summary"
5129 # i18n: column positioning for "hg summary"
5116 ui.write(_('update: %d new changesets (update)\n') % new)
5130 ui.write(_('update: %d new changesets (update)\n') % new)
5117 else:
5131 else:
5118 # i18n: column positioning for "hg summary"
5132 # i18n: column positioning for "hg summary"
5119 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5133 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5120 (new, len(bheads)))
5134 (new, len(bheads)))
5121
5135
5122 t = []
5136 t = []
5123 draft = len(repo.revs('draft()'))
5137 draft = len(repo.revs('draft()'))
5124 if draft:
5138 if draft:
5125 t.append(_('%d draft') % draft)
5139 t.append(_('%d draft') % draft)
5126 secret = len(repo.revs('secret()'))
5140 secret = len(repo.revs('secret()'))
5127 if secret:
5141 if secret:
5128 t.append(_('%d secret') % secret)
5142 t.append(_('%d secret') % secret)
5129
5143
5130 if draft or secret:
5144 if draft or secret:
5131 ui.status(_('phases: %s\n') % ', '.join(t))
5145 ui.status(_('phases: %s\n') % ', '.join(t))
5132
5146
5133 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5147 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5134 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5148 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5135 numtrouble = len(repo.revs(trouble + "()"))
5149 numtrouble = len(repo.revs(trouble + "()"))
5136 # We write all the possibilities to ease translation
5150 # We write all the possibilities to ease translation
5137 troublemsg = {
5151 troublemsg = {
5138 "orphan": _("orphan: %d changesets"),
5152 "orphan": _("orphan: %d changesets"),
5139 "contentdivergent": _("content-divergent: %d changesets"),
5153 "contentdivergent": _("content-divergent: %d changesets"),
5140 "phasedivergent": _("phase-divergent: %d changesets"),
5154 "phasedivergent": _("phase-divergent: %d changesets"),
5141 }
5155 }
5142 if numtrouble > 0:
5156 if numtrouble > 0:
5143 ui.status(troublemsg[trouble] % numtrouble + "\n")
5157 ui.status(troublemsg[trouble] % numtrouble + "\n")
5144
5158
5145 cmdutil.summaryhooks(ui, repo)
5159 cmdutil.summaryhooks(ui, repo)
5146
5160
5147 if opts.get('remote'):
5161 if opts.get('remote'):
5148 needsincoming, needsoutgoing = True, True
5162 needsincoming, needsoutgoing = True, True
5149 else:
5163 else:
5150 needsincoming, needsoutgoing = False, False
5164 needsincoming, needsoutgoing = False, False
5151 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5165 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5152 if i:
5166 if i:
5153 needsincoming = True
5167 needsincoming = True
5154 if o:
5168 if o:
5155 needsoutgoing = True
5169 needsoutgoing = True
5156 if not needsincoming and not needsoutgoing:
5170 if not needsincoming and not needsoutgoing:
5157 return
5171 return
5158
5172
5159 def getincoming():
5173 def getincoming():
5160 source, branches = hg.parseurl(ui.expandpath('default'))
5174 source, branches = hg.parseurl(ui.expandpath('default'))
5161 sbranch = branches[0]
5175 sbranch = branches[0]
5162 try:
5176 try:
5163 other = hg.peer(repo, {}, source)
5177 other = hg.peer(repo, {}, source)
5164 except error.RepoError:
5178 except error.RepoError:
5165 if opts.get('remote'):
5179 if opts.get('remote'):
5166 raise
5180 raise
5167 return source, sbranch, None, None, None
5181 return source, sbranch, None, None, None
5168 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5182 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5169 if revs:
5183 if revs:
5170 revs = [other.lookup(rev) for rev in revs]
5184 revs = [other.lookup(rev) for rev in revs]
5171 ui.debug('comparing with %s\n' % util.hidepassword(source))
5185 ui.debug('comparing with %s\n' % util.hidepassword(source))
5172 repo.ui.pushbuffer()
5186 repo.ui.pushbuffer()
5173 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5187 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5174 repo.ui.popbuffer()
5188 repo.ui.popbuffer()
5175 return source, sbranch, other, commoninc, commoninc[1]
5189 return source, sbranch, other, commoninc, commoninc[1]
5176
5190
5177 if needsincoming:
5191 if needsincoming:
5178 source, sbranch, sother, commoninc, incoming = getincoming()
5192 source, sbranch, sother, commoninc, incoming = getincoming()
5179 else:
5193 else:
5180 source = sbranch = sother = commoninc = incoming = None
5194 source = sbranch = sother = commoninc = incoming = None
5181
5195
5182 def getoutgoing():
5196 def getoutgoing():
5183 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5197 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5184 dbranch = branches[0]
5198 dbranch = branches[0]
5185 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5199 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5186 if source != dest:
5200 if source != dest:
5187 try:
5201 try:
5188 dother = hg.peer(repo, {}, dest)
5202 dother = hg.peer(repo, {}, dest)
5189 except error.RepoError:
5203 except error.RepoError:
5190 if opts.get('remote'):
5204 if opts.get('remote'):
5191 raise
5205 raise
5192 return dest, dbranch, None, None
5206 return dest, dbranch, None, None
5193 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5207 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5194 elif sother is None:
5208 elif sother is None:
5195 # there is no explicit destination peer, but source one is invalid
5209 # there is no explicit destination peer, but source one is invalid
5196 return dest, dbranch, None, None
5210 return dest, dbranch, None, None
5197 else:
5211 else:
5198 dother = sother
5212 dother = sother
5199 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5213 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5200 common = None
5214 common = None
5201 else:
5215 else:
5202 common = commoninc
5216 common = commoninc
5203 if revs:
5217 if revs:
5204 revs = [repo.lookup(rev) for rev in revs]
5218 revs = [repo.lookup(rev) for rev in revs]
5205 repo.ui.pushbuffer()
5219 repo.ui.pushbuffer()
5206 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5220 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5207 commoninc=common)
5221 commoninc=common)
5208 repo.ui.popbuffer()
5222 repo.ui.popbuffer()
5209 return dest, dbranch, dother, outgoing
5223 return dest, dbranch, dother, outgoing
5210
5224
5211 if needsoutgoing:
5225 if needsoutgoing:
5212 dest, dbranch, dother, outgoing = getoutgoing()
5226 dest, dbranch, dother, outgoing = getoutgoing()
5213 else:
5227 else:
5214 dest = dbranch = dother = outgoing = None
5228 dest = dbranch = dother = outgoing = None
5215
5229
5216 if opts.get('remote'):
5230 if opts.get('remote'):
5217 t = []
5231 t = []
5218 if incoming:
5232 if incoming:
5219 t.append(_('1 or more incoming'))
5233 t.append(_('1 or more incoming'))
5220 o = outgoing.missing
5234 o = outgoing.missing
5221 if o:
5235 if o:
5222 t.append(_('%d outgoing') % len(o))
5236 t.append(_('%d outgoing') % len(o))
5223 other = dother or sother
5237 other = dother or sother
5224 if 'bookmarks' in other.listkeys('namespaces'):
5238 if 'bookmarks' in other.listkeys('namespaces'):
5225 counts = bookmarks.summary(repo, other)
5239 counts = bookmarks.summary(repo, other)
5226 if counts[0] > 0:
5240 if counts[0] > 0:
5227 t.append(_('%d incoming bookmarks') % counts[0])
5241 t.append(_('%d incoming bookmarks') % counts[0])
5228 if counts[1] > 0:
5242 if counts[1] > 0:
5229 t.append(_('%d outgoing bookmarks') % counts[1])
5243 t.append(_('%d outgoing bookmarks') % counts[1])
5230
5244
5231 if t:
5245 if t:
5232 # i18n: column positioning for "hg summary"
5246 # i18n: column positioning for "hg summary"
5233 ui.write(_('remote: %s\n') % (', '.join(t)))
5247 ui.write(_('remote: %s\n') % (', '.join(t)))
5234 else:
5248 else:
5235 # i18n: column positioning for "hg summary"
5249 # i18n: column positioning for "hg summary"
5236 ui.status(_('remote: (synced)\n'))
5250 ui.status(_('remote: (synced)\n'))
5237
5251
5238 cmdutil.summaryremotehooks(ui, repo, opts,
5252 cmdutil.summaryremotehooks(ui, repo, opts,
5239 ((source, sbranch, sother, commoninc),
5253 ((source, sbranch, sother, commoninc),
5240 (dest, dbranch, dother, outgoing)))
5254 (dest, dbranch, dother, outgoing)))
5241
5255
5242 @command('tag',
5256 @command('tag',
5243 [('f', 'force', None, _('force tag')),
5257 [('f', 'force', None, _('force tag')),
5244 ('l', 'local', None, _('make the tag local')),
5258 ('l', 'local', None, _('make the tag local')),
5245 ('r', 'rev', '', _('revision to tag'), _('REV')),
5259 ('r', 'rev', '', _('revision to tag'), _('REV')),
5246 ('', 'remove', None, _('remove a tag')),
5260 ('', 'remove', None, _('remove a tag')),
5247 # -l/--local is already there, commitopts cannot be used
5261 # -l/--local is already there, commitopts cannot be used
5248 ('e', 'edit', None, _('invoke editor on commit messages')),
5262 ('e', 'edit', None, _('invoke editor on commit messages')),
5249 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5263 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5250 ] + commitopts2,
5264 ] + commitopts2,
5251 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5265 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5252 def tag(ui, repo, name1, *names, **opts):
5266 def tag(ui, repo, name1, *names, **opts):
5253 """add one or more tags for the current or given revision
5267 """add one or more tags for the current or given revision
5254
5268
5255 Name a particular revision using <name>.
5269 Name a particular revision using <name>.
5256
5270
5257 Tags are used to name particular revisions of the repository and are
5271 Tags are used to name particular revisions of the repository and are
5258 very useful to compare different revisions, to go back to significant
5272 very useful to compare different revisions, to go back to significant
5259 earlier versions or to mark branch points as releases, etc. Changing
5273 earlier versions or to mark branch points as releases, etc. Changing
5260 an existing tag is normally disallowed; use -f/--force to override.
5274 an existing tag is normally disallowed; use -f/--force to override.
5261
5275
5262 If no revision is given, the parent of the working directory is
5276 If no revision is given, the parent of the working directory is
5263 used.
5277 used.
5264
5278
5265 To facilitate version control, distribution, and merging of tags,
5279 To facilitate version control, distribution, and merging of tags,
5266 they are stored as a file named ".hgtags" which is managed similarly
5280 they are stored as a file named ".hgtags" which is managed similarly
5267 to other project files and can be hand-edited if necessary. This
5281 to other project files and can be hand-edited if necessary. This
5268 also means that tagging creates a new commit. The file
5282 also means that tagging creates a new commit. The file
5269 ".hg/localtags" is used for local tags (not shared among
5283 ".hg/localtags" is used for local tags (not shared among
5270 repositories).
5284 repositories).
5271
5285
5272 Tag commits are usually made at the head of a branch. If the parent
5286 Tag commits are usually made at the head of a branch. If the parent
5273 of the working directory is not a branch head, :hg:`tag` aborts; use
5287 of the working directory is not a branch head, :hg:`tag` aborts; use
5274 -f/--force to force the tag commit to be based on a non-head
5288 -f/--force to force the tag commit to be based on a non-head
5275 changeset.
5289 changeset.
5276
5290
5277 See :hg:`help dates` for a list of formats valid for -d/--date.
5291 See :hg:`help dates` for a list of formats valid for -d/--date.
5278
5292
5279 Since tag names have priority over branch names during revision
5293 Since tag names have priority over branch names during revision
5280 lookup, using an existing branch name as a tag name is discouraged.
5294 lookup, using an existing branch name as a tag name is discouraged.
5281
5295
5282 Returns 0 on success.
5296 Returns 0 on success.
5283 """
5297 """
5284 opts = pycompat.byteskwargs(opts)
5298 opts = pycompat.byteskwargs(opts)
5285 wlock = lock = None
5299 wlock = lock = None
5286 try:
5300 try:
5287 wlock = repo.wlock()
5301 wlock = repo.wlock()
5288 lock = repo.lock()
5302 lock = repo.lock()
5289 rev_ = "."
5303 rev_ = "."
5290 names = [t.strip() for t in (name1,) + names]
5304 names = [t.strip() for t in (name1,) + names]
5291 if len(names) != len(set(names)):
5305 if len(names) != len(set(names)):
5292 raise error.Abort(_('tag names must be unique'))
5306 raise error.Abort(_('tag names must be unique'))
5293 for n in names:
5307 for n in names:
5294 scmutil.checknewlabel(repo, n, 'tag')
5308 scmutil.checknewlabel(repo, n, 'tag')
5295 if not n:
5309 if not n:
5296 raise error.Abort(_('tag names cannot consist entirely of '
5310 raise error.Abort(_('tag names cannot consist entirely of '
5297 'whitespace'))
5311 'whitespace'))
5298 if opts.get('rev') and opts.get('remove'):
5312 if opts.get('rev') and opts.get('remove'):
5299 raise error.Abort(_("--rev and --remove are incompatible"))
5313 raise error.Abort(_("--rev and --remove are incompatible"))
5300 if opts.get('rev'):
5314 if opts.get('rev'):
5301 rev_ = opts['rev']
5315 rev_ = opts['rev']
5302 message = opts.get('message')
5316 message = opts.get('message')
5303 if opts.get('remove'):
5317 if opts.get('remove'):
5304 if opts.get('local'):
5318 if opts.get('local'):
5305 expectedtype = 'local'
5319 expectedtype = 'local'
5306 else:
5320 else:
5307 expectedtype = 'global'
5321 expectedtype = 'global'
5308
5322
5309 for n in names:
5323 for n in names:
5310 if not repo.tagtype(n):
5324 if not repo.tagtype(n):
5311 raise error.Abort(_("tag '%s' does not exist") % n)
5325 raise error.Abort(_("tag '%s' does not exist") % n)
5312 if repo.tagtype(n) != expectedtype:
5326 if repo.tagtype(n) != expectedtype:
5313 if expectedtype == 'global':
5327 if expectedtype == 'global':
5314 raise error.Abort(_("tag '%s' is not a global tag") % n)
5328 raise error.Abort(_("tag '%s' is not a global tag") % n)
5315 else:
5329 else:
5316 raise error.Abort(_("tag '%s' is not a local tag") % n)
5330 raise error.Abort(_("tag '%s' is not a local tag") % n)
5317 rev_ = 'null'
5331 rev_ = 'null'
5318 if not message:
5332 if not message:
5319 # we don't translate commit messages
5333 # we don't translate commit messages
5320 message = 'Removed tag %s' % ', '.join(names)
5334 message = 'Removed tag %s' % ', '.join(names)
5321 elif not opts.get('force'):
5335 elif not opts.get('force'):
5322 for n in names:
5336 for n in names:
5323 if n in repo.tags():
5337 if n in repo.tags():
5324 raise error.Abort(_("tag '%s' already exists "
5338 raise error.Abort(_("tag '%s' already exists "
5325 "(use -f to force)") % n)
5339 "(use -f to force)") % n)
5326 if not opts.get('local'):
5340 if not opts.get('local'):
5327 p1, p2 = repo.dirstate.parents()
5341 p1, p2 = repo.dirstate.parents()
5328 if p2 != nullid:
5342 if p2 != nullid:
5329 raise error.Abort(_('uncommitted merge'))
5343 raise error.Abort(_('uncommitted merge'))
5330 bheads = repo.branchheads()
5344 bheads = repo.branchheads()
5331 if not opts.get('force') and bheads and p1 not in bheads:
5345 if not opts.get('force') and bheads and p1 not in bheads:
5332 raise error.Abort(_('working directory is not at a branch head '
5346 raise error.Abort(_('working directory is not at a branch head '
5333 '(use -f to force)'))
5347 '(use -f to force)'))
5334 node = scmutil.revsingle(repo, rev_).node()
5348 node = scmutil.revsingle(repo, rev_).node()
5335
5349
5336 if not message:
5350 if not message:
5337 # we don't translate commit messages
5351 # we don't translate commit messages
5338 message = ('Added tag %s for changeset %s' %
5352 message = ('Added tag %s for changeset %s' %
5339 (', '.join(names), short(node)))
5353 (', '.join(names), short(node)))
5340
5354
5341 date = opts.get('date')
5355 date = opts.get('date')
5342 if date:
5356 if date:
5343 date = dateutil.parsedate(date)
5357 date = dateutil.parsedate(date)
5344
5358
5345 if opts.get('remove'):
5359 if opts.get('remove'):
5346 editform = 'tag.remove'
5360 editform = 'tag.remove'
5347 else:
5361 else:
5348 editform = 'tag.add'
5362 editform = 'tag.add'
5349 editor = cmdutil.getcommiteditor(editform=editform,
5363 editor = cmdutil.getcommiteditor(editform=editform,
5350 **pycompat.strkwargs(opts))
5364 **pycompat.strkwargs(opts))
5351
5365
5352 # don't allow tagging the null rev
5366 # don't allow tagging the null rev
5353 if (not opts.get('remove') and
5367 if (not opts.get('remove') and
5354 scmutil.revsingle(repo, rev_).rev() == nullrev):
5368 scmutil.revsingle(repo, rev_).rev() == nullrev):
5355 raise error.Abort(_("cannot tag null revision"))
5369 raise error.Abort(_("cannot tag null revision"))
5356
5370
5357 tagsmod.tag(repo, names, node, message, opts.get('local'),
5371 tagsmod.tag(repo, names, node, message, opts.get('local'),
5358 opts.get('user'), date, editor=editor)
5372 opts.get('user'), date, editor=editor)
5359 finally:
5373 finally:
5360 release(lock, wlock)
5374 release(lock, wlock)
5361
5375
5362 @command('tags', formatteropts, '', cmdtype=readonly)
5376 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5363 def tags(ui, repo, **opts):
5377 def tags(ui, repo, **opts):
5364 """list repository tags
5378 """list repository tags
5365
5379
5366 This lists both regular and local tags. When the -v/--verbose
5380 This lists both regular and local tags. When the -v/--verbose
5367 switch is used, a third column "local" is printed for local tags.
5381 switch is used, a third column "local" is printed for local tags.
5368 When the -q/--quiet switch is used, only the tag name is printed.
5382 When the -q/--quiet switch is used, only the tag name is printed.
5369
5383
5370 Returns 0 on success.
5384 Returns 0 on success.
5371 """
5385 """
5372
5386
5373 opts = pycompat.byteskwargs(opts)
5387 opts = pycompat.byteskwargs(opts)
5374 ui.pager('tags')
5388 ui.pager('tags')
5375 fm = ui.formatter('tags', opts)
5389 fm = ui.formatter('tags', opts)
5376 hexfunc = fm.hexfunc
5390 hexfunc = fm.hexfunc
5377 tagtype = ""
5391 tagtype = ""
5378
5392
5379 for t, n in reversed(repo.tagslist()):
5393 for t, n in reversed(repo.tagslist()):
5380 hn = hexfunc(n)
5394 hn = hexfunc(n)
5381 label = 'tags.normal'
5395 label = 'tags.normal'
5382 tagtype = ''
5396 tagtype = ''
5383 if repo.tagtype(t) == 'local':
5397 if repo.tagtype(t) == 'local':
5384 label = 'tags.local'
5398 label = 'tags.local'
5385 tagtype = 'local'
5399 tagtype = 'local'
5386
5400
5387 fm.startitem()
5401 fm.startitem()
5388 fm.write('tag', '%s', t, label=label)
5402 fm.write('tag', '%s', t, label=label)
5389 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5403 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5390 fm.condwrite(not ui.quiet, 'rev node', fmt,
5404 fm.condwrite(not ui.quiet, 'rev node', fmt,
5391 repo.changelog.rev(n), hn, label=label)
5405 repo.changelog.rev(n), hn, label=label)
5392 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5406 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5393 tagtype, label=label)
5407 tagtype, label=label)
5394 fm.plain('\n')
5408 fm.plain('\n')
5395 fm.end()
5409 fm.end()
5396
5410
5397 @command('tip',
5411 @command('tip',
5398 [('p', 'patch', None, _('show patch')),
5412 [('p', 'patch', None, _('show patch')),
5399 ('g', 'git', None, _('use git extended diff format')),
5413 ('g', 'git', None, _('use git extended diff format')),
5400 ] + templateopts,
5414 ] + templateopts,
5401 _('[-p] [-g]'))
5415 _('[-p] [-g]'))
5402 def tip(ui, repo, **opts):
5416 def tip(ui, repo, **opts):
5403 """show the tip revision (DEPRECATED)
5417 """show the tip revision (DEPRECATED)
5404
5418
5405 The tip revision (usually just called the tip) is the changeset
5419 The tip revision (usually just called the tip) is the changeset
5406 most recently added to the repository (and therefore the most
5420 most recently added to the repository (and therefore the most
5407 recently changed head).
5421 recently changed head).
5408
5422
5409 If you have just made a commit, that commit will be the tip. If
5423 If you have just made a commit, that commit will be the tip. If
5410 you have just pulled changes from another repository, the tip of
5424 you have just pulled changes from another repository, the tip of
5411 that repository becomes the current tip. The "tip" tag is special
5425 that repository becomes the current tip. The "tip" tag is special
5412 and cannot be renamed or assigned to a different changeset.
5426 and cannot be renamed or assigned to a different changeset.
5413
5427
5414 This command is deprecated, please use :hg:`heads` instead.
5428 This command is deprecated, please use :hg:`heads` instead.
5415
5429
5416 Returns 0 on success.
5430 Returns 0 on success.
5417 """
5431 """
5418 opts = pycompat.byteskwargs(opts)
5432 opts = pycompat.byteskwargs(opts)
5419 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5433 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5420 displayer.show(repo['tip'])
5434 displayer.show(repo['tip'])
5421 displayer.close()
5435 displayer.close()
5422
5436
5423 @command('unbundle',
5437 @command('unbundle',
5424 [('u', 'update', None,
5438 [('u', 'update', None,
5425 _('update to new branch head if changesets were unbundled'))],
5439 _('update to new branch head if changesets were unbundled'))],
5426 _('[-u] FILE...'))
5440 _('[-u] FILE...'))
5427 def unbundle(ui, repo, fname1, *fnames, **opts):
5441 def unbundle(ui, repo, fname1, *fnames, **opts):
5428 """apply one or more bundle files
5442 """apply one or more bundle files
5429
5443
5430 Apply one or more bundle files generated by :hg:`bundle`.
5444 Apply one or more bundle files generated by :hg:`bundle`.
5431
5445
5432 Returns 0 on success, 1 if an update has unresolved files.
5446 Returns 0 on success, 1 if an update has unresolved files.
5433 """
5447 """
5434 fnames = (fname1,) + fnames
5448 fnames = (fname1,) + fnames
5435
5449
5436 with repo.lock():
5450 with repo.lock():
5437 for fname in fnames:
5451 for fname in fnames:
5438 f = hg.openpath(ui, fname)
5452 f = hg.openpath(ui, fname)
5439 gen = exchange.readbundle(ui, f, fname)
5453 gen = exchange.readbundle(ui, f, fname)
5440 if isinstance(gen, streamclone.streamcloneapplier):
5454 if isinstance(gen, streamclone.streamcloneapplier):
5441 raise error.Abort(
5455 raise error.Abort(
5442 _('packed bundles cannot be applied with '
5456 _('packed bundles cannot be applied with '
5443 '"hg unbundle"'),
5457 '"hg unbundle"'),
5444 hint=_('use "hg debugapplystreamclonebundle"'))
5458 hint=_('use "hg debugapplystreamclonebundle"'))
5445 url = 'bundle:' + fname
5459 url = 'bundle:' + fname
5446 try:
5460 try:
5447 txnname = 'unbundle'
5461 txnname = 'unbundle'
5448 if not isinstance(gen, bundle2.unbundle20):
5462 if not isinstance(gen, bundle2.unbundle20):
5449 txnname = 'unbundle\n%s' % util.hidepassword(url)
5463 txnname = 'unbundle\n%s' % util.hidepassword(url)
5450 with repo.transaction(txnname) as tr:
5464 with repo.transaction(txnname) as tr:
5451 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5465 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5452 url=url)
5466 url=url)
5453 except error.BundleUnknownFeatureError as exc:
5467 except error.BundleUnknownFeatureError as exc:
5454 raise error.Abort(
5468 raise error.Abort(
5455 _('%s: unknown bundle feature, %s') % (fname, exc),
5469 _('%s: unknown bundle feature, %s') % (fname, exc),
5456 hint=_("see https://mercurial-scm.org/"
5470 hint=_("see https://mercurial-scm.org/"
5457 "wiki/BundleFeature for more "
5471 "wiki/BundleFeature for more "
5458 "information"))
5472 "information"))
5459 modheads = bundle2.combinechangegroupresults(op)
5473 modheads = bundle2.combinechangegroupresults(op)
5460
5474
5461 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5475 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5462
5476
5463 @command('^update|up|checkout|co',
5477 @command('^update|up|checkout|co',
5464 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5478 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5465 ('c', 'check', None, _('require clean working directory')),
5479 ('c', 'check', None, _('require clean working directory')),
5466 ('m', 'merge', None, _('merge uncommitted changes')),
5480 ('m', 'merge', None, _('merge uncommitted changes')),
5467 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5481 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5468 ('r', 'rev', '', _('revision'), _('REV'))
5482 ('r', 'rev', '', _('revision'), _('REV'))
5469 ] + mergetoolopts,
5483 ] + mergetoolopts,
5470 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5484 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5471 def update(ui, repo, node=None, **opts):
5485 def update(ui, repo, node=None, **opts):
5472 """update working directory (or switch revisions)
5486 """update working directory (or switch revisions)
5473
5487
5474 Update the repository's working directory to the specified
5488 Update the repository's working directory to the specified
5475 changeset. If no changeset is specified, update to the tip of the
5489 changeset. If no changeset is specified, update to the tip of the
5476 current named branch and move the active bookmark (see :hg:`help
5490 current named branch and move the active bookmark (see :hg:`help
5477 bookmarks`).
5491 bookmarks`).
5478
5492
5479 Update sets the working directory's parent revision to the specified
5493 Update sets the working directory's parent revision to the specified
5480 changeset (see :hg:`help parents`).
5494 changeset (see :hg:`help parents`).
5481
5495
5482 If the changeset is not a descendant or ancestor of the working
5496 If the changeset is not a descendant or ancestor of the working
5483 directory's parent and there are uncommitted changes, the update is
5497 directory's parent and there are uncommitted changes, the update is
5484 aborted. With the -c/--check option, the working directory is checked
5498 aborted. With the -c/--check option, the working directory is checked
5485 for uncommitted changes; if none are found, the working directory is
5499 for uncommitted changes; if none are found, the working directory is
5486 updated to the specified changeset.
5500 updated to the specified changeset.
5487
5501
5488 .. container:: verbose
5502 .. container:: verbose
5489
5503
5490 The -C/--clean, -c/--check, and -m/--merge options control what
5504 The -C/--clean, -c/--check, and -m/--merge options control what
5491 happens if the working directory contains uncommitted changes.
5505 happens if the working directory contains uncommitted changes.
5492 At most of one of them can be specified.
5506 At most of one of them can be specified.
5493
5507
5494 1. If no option is specified, and if
5508 1. If no option is specified, and if
5495 the requested changeset is an ancestor or descendant of
5509 the requested changeset is an ancestor or descendant of
5496 the working directory's parent, the uncommitted changes
5510 the working directory's parent, the uncommitted changes
5497 are merged into the requested changeset and the merged
5511 are merged into the requested changeset and the merged
5498 result is left uncommitted. If the requested changeset is
5512 result is left uncommitted. If the requested changeset is
5499 not an ancestor or descendant (that is, it is on another
5513 not an ancestor or descendant (that is, it is on another
5500 branch), the update is aborted and the uncommitted changes
5514 branch), the update is aborted and the uncommitted changes
5501 are preserved.
5515 are preserved.
5502
5516
5503 2. With the -m/--merge option, the update is allowed even if the
5517 2. With the -m/--merge option, the update is allowed even if the
5504 requested changeset is not an ancestor or descendant of
5518 requested changeset is not an ancestor or descendant of
5505 the working directory's parent.
5519 the working directory's parent.
5506
5520
5507 3. With the -c/--check option, the update is aborted and the
5521 3. With the -c/--check option, the update is aborted and the
5508 uncommitted changes are preserved.
5522 uncommitted changes are preserved.
5509
5523
5510 4. With the -C/--clean option, uncommitted changes are discarded and
5524 4. With the -C/--clean option, uncommitted changes are discarded and
5511 the working directory is updated to the requested changeset.
5525 the working directory is updated to the requested changeset.
5512
5526
5513 To cancel an uncommitted merge (and lose your changes), use
5527 To cancel an uncommitted merge (and lose your changes), use
5514 :hg:`merge --abort`.
5528 :hg:`merge --abort`.
5515
5529
5516 Use null as the changeset to remove the working directory (like
5530 Use null as the changeset to remove the working directory (like
5517 :hg:`clone -U`).
5531 :hg:`clone -U`).
5518
5532
5519 If you want to revert just one file to an older revision, use
5533 If you want to revert just one file to an older revision, use
5520 :hg:`revert [-r REV] NAME`.
5534 :hg:`revert [-r REV] NAME`.
5521
5535
5522 See :hg:`help dates` for a list of formats valid for -d/--date.
5536 See :hg:`help dates` for a list of formats valid for -d/--date.
5523
5537
5524 Returns 0 on success, 1 if there are unresolved files.
5538 Returns 0 on success, 1 if there are unresolved files.
5525 """
5539 """
5526 rev = opts.get(r'rev')
5540 rev = opts.get(r'rev')
5527 date = opts.get(r'date')
5541 date = opts.get(r'date')
5528 clean = opts.get(r'clean')
5542 clean = opts.get(r'clean')
5529 check = opts.get(r'check')
5543 check = opts.get(r'check')
5530 merge = opts.get(r'merge')
5544 merge = opts.get(r'merge')
5531 if rev and node:
5545 if rev and node:
5532 raise error.Abort(_("please specify just one revision"))
5546 raise error.Abort(_("please specify just one revision"))
5533
5547
5534 if ui.configbool('commands', 'update.requiredest'):
5548 if ui.configbool('commands', 'update.requiredest'):
5535 if not node and not rev and not date:
5549 if not node and not rev and not date:
5536 raise error.Abort(_('you must specify a destination'),
5550 raise error.Abort(_('you must specify a destination'),
5537 hint=_('for example: hg update ".::"'))
5551 hint=_('for example: hg update ".::"'))
5538
5552
5539 if rev is None or rev == '':
5553 if rev is None or rev == '':
5540 rev = node
5554 rev = node
5541
5555
5542 if date and rev is not None:
5556 if date and rev is not None:
5543 raise error.Abort(_("you can't specify a revision and a date"))
5557 raise error.Abort(_("you can't specify a revision and a date"))
5544
5558
5545 if len([x for x in (clean, check, merge) if x]) > 1:
5559 if len([x for x in (clean, check, merge) if x]) > 1:
5546 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5560 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5547 "or -m/--merge"))
5561 "or -m/--merge"))
5548
5562
5549 updatecheck = None
5563 updatecheck = None
5550 if check:
5564 if check:
5551 updatecheck = 'abort'
5565 updatecheck = 'abort'
5552 elif merge:
5566 elif merge:
5553 updatecheck = 'none'
5567 updatecheck = 'none'
5554
5568
5555 with repo.wlock():
5569 with repo.wlock():
5556 cmdutil.clearunfinished(repo)
5570 cmdutil.clearunfinished(repo)
5557
5571
5558 if date:
5572 if date:
5559 rev = cmdutil.finddate(ui, repo, date)
5573 rev = cmdutil.finddate(ui, repo, date)
5560
5574
5561 # if we defined a bookmark, we have to remember the original name
5575 # if we defined a bookmark, we have to remember the original name
5562 brev = rev
5576 brev = rev
5563 if rev:
5577 if rev:
5564 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5578 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5565 ctx = scmutil.revsingle(repo, rev, rev)
5579 ctx = scmutil.revsingle(repo, rev, rev)
5566 rev = ctx.rev()
5580 rev = ctx.rev()
5567 if ctx.hidden():
5581 if ctx.hidden():
5568 ctxstr = ctx.hex()[:12]
5582 ctxstr = ctx.hex()[:12]
5569 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5583 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5570
5584
5571 if ctx.obsolete():
5585 if ctx.obsolete():
5572 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5586 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5573 ui.warn("(%s)\n" % obsfatemsg)
5587 ui.warn("(%s)\n" % obsfatemsg)
5574
5588
5575 repo.ui.setconfig('ui', 'forcemerge', opts.get(r'tool'), 'update')
5589 repo.ui.setconfig('ui', 'forcemerge', opts.get(r'tool'), 'update')
5576
5590
5577 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5591 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5578 updatecheck=updatecheck)
5592 updatecheck=updatecheck)
5579
5593
5580 @command('verify', [])
5594 @command('verify', [])
5581 def verify(ui, repo):
5595 def verify(ui, repo):
5582 """verify the integrity of the repository
5596 """verify the integrity of the repository
5583
5597
5584 Verify the integrity of the current repository.
5598 Verify the integrity of the current repository.
5585
5599
5586 This will perform an extensive check of the repository's
5600 This will perform an extensive check of the repository's
5587 integrity, validating the hashes and checksums of each entry in
5601 integrity, validating the hashes and checksums of each entry in
5588 the changelog, manifest, and tracked files, as well as the
5602 the changelog, manifest, and tracked files, as well as the
5589 integrity of their crosslinks and indices.
5603 integrity of their crosslinks and indices.
5590
5604
5591 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5605 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5592 for more information about recovery from corruption of the
5606 for more information about recovery from corruption of the
5593 repository.
5607 repository.
5594
5608
5595 Returns 0 on success, 1 if errors are encountered.
5609 Returns 0 on success, 1 if errors are encountered.
5596 """
5610 """
5597 return hg.verify(repo)
5611 return hg.verify(repo)
5598
5612
5599 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5613 @command('version', [] + formatteropts, norepo=True,
5614 intents={INTENT_READONLY})
5600 def version_(ui, **opts):
5615 def version_(ui, **opts):
5601 """output version and copyright information"""
5616 """output version and copyright information"""
5602 opts = pycompat.byteskwargs(opts)
5617 opts = pycompat.byteskwargs(opts)
5603 if ui.verbose:
5618 if ui.verbose:
5604 ui.pager('version')
5619 ui.pager('version')
5605 fm = ui.formatter("version", opts)
5620 fm = ui.formatter("version", opts)
5606 fm.startitem()
5621 fm.startitem()
5607 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5622 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5608 util.version())
5623 util.version())
5609 license = _(
5624 license = _(
5610 "(see https://mercurial-scm.org for more information)\n"
5625 "(see https://mercurial-scm.org for more information)\n"
5611 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5626 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5612 "This is free software; see the source for copying conditions. "
5627 "This is free software; see the source for copying conditions. "
5613 "There is NO\nwarranty; "
5628 "There is NO\nwarranty; "
5614 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5629 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5615 )
5630 )
5616 if not ui.quiet:
5631 if not ui.quiet:
5617 fm.plain(license)
5632 fm.plain(license)
5618
5633
5619 if ui.verbose:
5634 if ui.verbose:
5620 fm.plain(_("\nEnabled extensions:\n\n"))
5635 fm.plain(_("\nEnabled extensions:\n\n"))
5621 # format names and versions into columns
5636 # format names and versions into columns
5622 names = []
5637 names = []
5623 vers = []
5638 vers = []
5624 isinternals = []
5639 isinternals = []
5625 for name, module in extensions.extensions():
5640 for name, module in extensions.extensions():
5626 names.append(name)
5641 names.append(name)
5627 vers.append(extensions.moduleversion(module) or None)
5642 vers.append(extensions.moduleversion(module) or None)
5628 isinternals.append(extensions.ismoduleinternal(module))
5643 isinternals.append(extensions.ismoduleinternal(module))
5629 fn = fm.nested("extensions", tmpl='{name}\n')
5644 fn = fm.nested("extensions", tmpl='{name}\n')
5630 if names:
5645 if names:
5631 namefmt = " %%-%ds " % max(len(n) for n in names)
5646 namefmt = " %%-%ds " % max(len(n) for n in names)
5632 places = [_("external"), _("internal")]
5647 places = [_("external"), _("internal")]
5633 for n, v, p in zip(names, vers, isinternals):
5648 for n, v, p in zip(names, vers, isinternals):
5634 fn.startitem()
5649 fn.startitem()
5635 fn.condwrite(ui.verbose, "name", namefmt, n)
5650 fn.condwrite(ui.verbose, "name", namefmt, n)
5636 if ui.verbose:
5651 if ui.verbose:
5637 fn.plain("%s " % places[p])
5652 fn.plain("%s " % places[p])
5638 fn.data(bundled=p)
5653 fn.data(bundled=p)
5639 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5654 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5640 if ui.verbose:
5655 if ui.verbose:
5641 fn.plain("\n")
5656 fn.plain("\n")
5642 fn.end()
5657 fn.end()
5643 fm.end()
5658 fm.end()
5644
5659
5645 def loadcmdtable(ui, name, cmdtable):
5660 def loadcmdtable(ui, name, cmdtable):
5646 """Load command functions from specified cmdtable
5661 """Load command functions from specified cmdtable
5647 """
5662 """
5648 overrides = [cmd for cmd in cmdtable if cmd in table]
5663 overrides = [cmd for cmd in cmdtable if cmd in table]
5649 if overrides:
5664 if overrides:
5650 ui.warn(_("extension '%s' overrides commands: %s\n")
5665 ui.warn(_("extension '%s' overrides commands: %s\n")
5651 % (name, " ".join(overrides)))
5666 % (name, " ".join(overrides)))
5652 table.update(cmdtable)
5667 table.update(cmdtable)
@@ -1,1055 +1,1052 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching 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, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import getopt
12 import getopt
13 import os
13 import os
14 import pdb
14 import pdb
15 import re
15 import re
16 import signal
16 import signal
17 import sys
17 import sys
18 import time
18 import time
19 import traceback
19 import traceback
20
20
21
21
22 from .i18n import _
22 from .i18n import _
23
23
24 from . import (
24 from . import (
25 cmdutil,
25 cmdutil,
26 color,
26 color,
27 commands,
27 commands,
28 demandimport,
28 demandimport,
29 encoding,
29 encoding,
30 error,
30 error,
31 extensions,
31 extensions,
32 fancyopts,
32 fancyopts,
33 help,
33 help,
34 hg,
34 hg,
35 hook,
35 hook,
36 profiling,
36 profiling,
37 pycompat,
37 pycompat,
38 registrar,
39 scmutil,
38 scmutil,
40 ui as uimod,
39 ui as uimod,
41 util,
40 util,
42 )
41 )
43
42
44 from .utils import (
43 from .utils import (
45 procutil,
44 procutil,
46 stringutil,
45 stringutil,
47 )
46 )
48
47
49 unrecoverablewrite = registrar.command.unrecoverablewrite
50
51 class request(object):
48 class request(object):
52 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
49 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
53 ferr=None, prereposetups=None):
50 ferr=None, prereposetups=None):
54 self.args = args
51 self.args = args
55 self.ui = ui
52 self.ui = ui
56 self.repo = repo
53 self.repo = repo
57
54
58 # input/output/error streams
55 # input/output/error streams
59 self.fin = fin
56 self.fin = fin
60 self.fout = fout
57 self.fout = fout
61 self.ferr = ferr
58 self.ferr = ferr
62
59
63 # remember options pre-parsed by _earlyparseopts()
60 # remember options pre-parsed by _earlyparseopts()
64 self.earlyoptions = {}
61 self.earlyoptions = {}
65
62
66 # reposetups which run before extensions, useful for chg to pre-fill
63 # reposetups which run before extensions, useful for chg to pre-fill
67 # low-level repo state (for example, changelog) before extensions.
64 # low-level repo state (for example, changelog) before extensions.
68 self.prereposetups = prereposetups or []
65 self.prereposetups = prereposetups or []
69
66
70 def _runexithandlers(self):
67 def _runexithandlers(self):
71 exc = None
68 exc = None
72 handlers = self.ui._exithandlers
69 handlers = self.ui._exithandlers
73 try:
70 try:
74 while handlers:
71 while handlers:
75 func, args, kwargs = handlers.pop()
72 func, args, kwargs = handlers.pop()
76 try:
73 try:
77 func(*args, **kwargs)
74 func(*args, **kwargs)
78 except: # re-raises below
75 except: # re-raises below
79 if exc is None:
76 if exc is None:
80 exc = sys.exc_info()[1]
77 exc = sys.exc_info()[1]
81 self.ui.warn(('error in exit handlers:\n'))
78 self.ui.warn(('error in exit handlers:\n'))
82 self.ui.traceback(force=True)
79 self.ui.traceback(force=True)
83 finally:
80 finally:
84 if exc is not None:
81 if exc is not None:
85 raise exc
82 raise exc
86
83
87 def run():
84 def run():
88 "run the command in sys.argv"
85 "run the command in sys.argv"
89 _initstdio()
86 _initstdio()
90 req = request(pycompat.sysargv[1:])
87 req = request(pycompat.sysargv[1:])
91 err = None
88 err = None
92 try:
89 try:
93 status = (dispatch(req) or 0)
90 status = (dispatch(req) or 0)
94 except error.StdioError as e:
91 except error.StdioError as e:
95 err = e
92 err = e
96 status = -1
93 status = -1
97 if util.safehasattr(req.ui, 'fout'):
94 if util.safehasattr(req.ui, 'fout'):
98 try:
95 try:
99 req.ui.fout.flush()
96 req.ui.fout.flush()
100 except IOError as e:
97 except IOError as e:
101 err = e
98 err = e
102 status = -1
99 status = -1
103 if util.safehasattr(req.ui, 'ferr'):
100 if util.safehasattr(req.ui, 'ferr'):
104 try:
101 try:
105 if err is not None and err.errno != errno.EPIPE:
102 if err is not None and err.errno != errno.EPIPE:
106 req.ui.ferr.write('abort: %s\n' %
103 req.ui.ferr.write('abort: %s\n' %
107 encoding.strtolocal(err.strerror))
104 encoding.strtolocal(err.strerror))
108 req.ui.ferr.flush()
105 req.ui.ferr.flush()
109 # There's not much we can do about an I/O error here. So (possibly)
106 # There's not much we can do about an I/O error here. So (possibly)
110 # change the status code and move on.
107 # change the status code and move on.
111 except IOError:
108 except IOError:
112 status = -1
109 status = -1
113
110
114 _silencestdio()
111 _silencestdio()
115 sys.exit(status & 255)
112 sys.exit(status & 255)
116
113
117 if pycompat.ispy3:
114 if pycompat.ispy3:
118 def _initstdio():
115 def _initstdio():
119 pass
116 pass
120
117
121 def _silencestdio():
118 def _silencestdio():
122 for fp in (sys.stdout, sys.stderr):
119 for fp in (sys.stdout, sys.stderr):
123 # Check if the file is okay
120 # Check if the file is okay
124 try:
121 try:
125 fp.flush()
122 fp.flush()
126 continue
123 continue
127 except IOError:
124 except IOError:
128 pass
125 pass
129 # Otherwise mark it as closed to silence "Exception ignored in"
126 # Otherwise mark it as closed to silence "Exception ignored in"
130 # message emitted by the interpreter finalizer. Be careful to
127 # message emitted by the interpreter finalizer. Be careful to
131 # not close procutil.stdout, which may be a fdopen-ed file object
128 # not close procutil.stdout, which may be a fdopen-ed file object
132 # and its close() actually closes the underlying file descriptor.
129 # and its close() actually closes the underlying file descriptor.
133 try:
130 try:
134 fp.close()
131 fp.close()
135 except IOError:
132 except IOError:
136 pass
133 pass
137 else:
134 else:
138 def _initstdio():
135 def _initstdio():
139 for fp in (sys.stdin, sys.stdout, sys.stderr):
136 for fp in (sys.stdin, sys.stdout, sys.stderr):
140 procutil.setbinary(fp)
137 procutil.setbinary(fp)
141
138
142 def _silencestdio():
139 def _silencestdio():
143 pass
140 pass
144
141
145 def _getsimilar(symbols, value):
142 def _getsimilar(symbols, value):
146 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
143 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
147 # The cutoff for similarity here is pretty arbitrary. It should
144 # The cutoff for similarity here is pretty arbitrary. It should
148 # probably be investigated and tweaked.
145 # probably be investigated and tweaked.
149 return [s for s in symbols if sim(s) > 0.6]
146 return [s for s in symbols if sim(s) > 0.6]
150
147
151 def _reportsimilar(write, similar):
148 def _reportsimilar(write, similar):
152 if len(similar) == 1:
149 if len(similar) == 1:
153 write(_("(did you mean %s?)\n") % similar[0])
150 write(_("(did you mean %s?)\n") % similar[0])
154 elif similar:
151 elif similar:
155 ss = ", ".join(sorted(similar))
152 ss = ", ".join(sorted(similar))
156 write(_("(did you mean one of %s?)\n") % ss)
153 write(_("(did you mean one of %s?)\n") % ss)
157
154
158 def _formatparse(write, inst):
155 def _formatparse(write, inst):
159 similar = []
156 similar = []
160 if isinstance(inst, error.UnknownIdentifier):
157 if isinstance(inst, error.UnknownIdentifier):
161 # make sure to check fileset first, as revset can invoke fileset
158 # make sure to check fileset first, as revset can invoke fileset
162 similar = _getsimilar(inst.symbols, inst.function)
159 similar = _getsimilar(inst.symbols, inst.function)
163 if len(inst.args) > 1:
160 if len(inst.args) > 1:
164 write(_("hg: parse error at %s: %s\n") %
161 write(_("hg: parse error at %s: %s\n") %
165 (pycompat.bytestr(inst.args[1]), inst.args[0]))
162 (pycompat.bytestr(inst.args[1]), inst.args[0]))
166 if inst.args[0].startswith(' '):
163 if inst.args[0].startswith(' '):
167 write(_("unexpected leading whitespace\n"))
164 write(_("unexpected leading whitespace\n"))
168 else:
165 else:
169 write(_("hg: parse error: %s\n") % inst.args[0])
166 write(_("hg: parse error: %s\n") % inst.args[0])
170 _reportsimilar(write, similar)
167 _reportsimilar(write, similar)
171 if inst.hint:
168 if inst.hint:
172 write(_("(%s)\n") % inst.hint)
169 write(_("(%s)\n") % inst.hint)
173
170
174 def _formatargs(args):
171 def _formatargs(args):
175 return ' '.join(procutil.shellquote(a) for a in args)
172 return ' '.join(procutil.shellquote(a) for a in args)
176
173
177 def dispatch(req):
174 def dispatch(req):
178 "run the command specified in req.args"
175 "run the command specified in req.args"
179 if req.ferr:
176 if req.ferr:
180 ferr = req.ferr
177 ferr = req.ferr
181 elif req.ui:
178 elif req.ui:
182 ferr = req.ui.ferr
179 ferr = req.ui.ferr
183 else:
180 else:
184 ferr = procutil.stderr
181 ferr = procutil.stderr
185
182
186 try:
183 try:
187 if not req.ui:
184 if not req.ui:
188 req.ui = uimod.ui.load()
185 req.ui = uimod.ui.load()
189 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
186 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
190 if req.earlyoptions['traceback']:
187 if req.earlyoptions['traceback']:
191 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
188 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
192
189
193 # set ui streams from the request
190 # set ui streams from the request
194 if req.fin:
191 if req.fin:
195 req.ui.fin = req.fin
192 req.ui.fin = req.fin
196 if req.fout:
193 if req.fout:
197 req.ui.fout = req.fout
194 req.ui.fout = req.fout
198 if req.ferr:
195 if req.ferr:
199 req.ui.ferr = req.ferr
196 req.ui.ferr = req.ferr
200 except error.Abort as inst:
197 except error.Abort as inst:
201 ferr.write(_("abort: %s\n") % inst)
198 ferr.write(_("abort: %s\n") % inst)
202 if inst.hint:
199 if inst.hint:
203 ferr.write(_("(%s)\n") % inst.hint)
200 ferr.write(_("(%s)\n") % inst.hint)
204 return -1
201 return -1
205 except error.ParseError as inst:
202 except error.ParseError as inst:
206 _formatparse(ferr.write, inst)
203 _formatparse(ferr.write, inst)
207 return -1
204 return -1
208
205
209 msg = _formatargs(req.args)
206 msg = _formatargs(req.args)
210 starttime = util.timer()
207 starttime = util.timer()
211 ret = None
208 ret = None
212 try:
209 try:
213 ret = _runcatch(req)
210 ret = _runcatch(req)
214 except error.ProgrammingError as inst:
211 except error.ProgrammingError as inst:
215 req.ui.warn(_('** ProgrammingError: %s\n') % inst)
212 req.ui.warn(_('** ProgrammingError: %s\n') % inst)
216 if inst.hint:
213 if inst.hint:
217 req.ui.warn(_('** (%s)\n') % inst.hint)
214 req.ui.warn(_('** (%s)\n') % inst.hint)
218 raise
215 raise
219 except KeyboardInterrupt as inst:
216 except KeyboardInterrupt as inst:
220 try:
217 try:
221 if isinstance(inst, error.SignalInterrupt):
218 if isinstance(inst, error.SignalInterrupt):
222 msg = _("killed!\n")
219 msg = _("killed!\n")
223 else:
220 else:
224 msg = _("interrupted!\n")
221 msg = _("interrupted!\n")
225 req.ui.warn(msg)
222 req.ui.warn(msg)
226 except error.SignalInterrupt:
223 except error.SignalInterrupt:
227 # maybe pager would quit without consuming all the output, and
224 # maybe pager would quit without consuming all the output, and
228 # SIGPIPE was raised. we cannot print anything in this case.
225 # SIGPIPE was raised. we cannot print anything in this case.
229 pass
226 pass
230 except IOError as inst:
227 except IOError as inst:
231 if inst.errno != errno.EPIPE:
228 if inst.errno != errno.EPIPE:
232 raise
229 raise
233 ret = -1
230 ret = -1
234 finally:
231 finally:
235 duration = util.timer() - starttime
232 duration = util.timer() - starttime
236 req.ui.flush()
233 req.ui.flush()
237 if req.ui.logblockedtimes:
234 if req.ui.logblockedtimes:
238 req.ui._blockedtimes['command_duration'] = duration * 1000
235 req.ui._blockedtimes['command_duration'] = duration * 1000
239 req.ui.log('uiblocked', 'ui blocked ms',
236 req.ui.log('uiblocked', 'ui blocked ms',
240 **pycompat.strkwargs(req.ui._blockedtimes))
237 **pycompat.strkwargs(req.ui._blockedtimes))
241 req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n",
238 req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n",
242 msg, ret or 0, duration)
239 msg, ret or 0, duration)
243 try:
240 try:
244 req._runexithandlers()
241 req._runexithandlers()
245 except: # exiting, so no re-raises
242 except: # exiting, so no re-raises
246 ret = ret or -1
243 ret = ret or -1
247 return ret
244 return ret
248
245
249 def _runcatch(req):
246 def _runcatch(req):
250 def catchterm(*args):
247 def catchterm(*args):
251 raise error.SignalInterrupt
248 raise error.SignalInterrupt
252
249
253 ui = req.ui
250 ui = req.ui
254 try:
251 try:
255 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
252 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
256 num = getattr(signal, name, None)
253 num = getattr(signal, name, None)
257 if num:
254 if num:
258 signal.signal(num, catchterm)
255 signal.signal(num, catchterm)
259 except ValueError:
256 except ValueError:
260 pass # happens if called in a thread
257 pass # happens if called in a thread
261
258
262 def _runcatchfunc():
259 def _runcatchfunc():
263 realcmd = None
260 realcmd = None
264 try:
261 try:
265 cmdargs = fancyopts.fancyopts(req.args[:], commands.globalopts, {})
262 cmdargs = fancyopts.fancyopts(req.args[:], commands.globalopts, {})
266 cmd = cmdargs[0]
263 cmd = cmdargs[0]
267 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
264 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
268 realcmd = aliases[0]
265 realcmd = aliases[0]
269 except (error.UnknownCommand, error.AmbiguousCommand,
266 except (error.UnknownCommand, error.AmbiguousCommand,
270 IndexError, getopt.GetoptError):
267 IndexError, getopt.GetoptError):
271 # Don't handle this here. We know the command is
268 # Don't handle this here. We know the command is
272 # invalid, but all we're worried about for now is that
269 # invalid, but all we're worried about for now is that
273 # it's not a command that server operators expect to
270 # it's not a command that server operators expect to
274 # be safe to offer to users in a sandbox.
271 # be safe to offer to users in a sandbox.
275 pass
272 pass
276 if realcmd == 'serve' and '--stdio' in cmdargs:
273 if realcmd == 'serve' and '--stdio' in cmdargs:
277 # We want to constrain 'hg serve --stdio' instances pretty
274 # We want to constrain 'hg serve --stdio' instances pretty
278 # closely, as many shared-ssh access tools want to grant
275 # closely, as many shared-ssh access tools want to grant
279 # access to run *only* 'hg -R $repo serve --stdio'. We
276 # access to run *only* 'hg -R $repo serve --stdio'. We
280 # restrict to exactly that set of arguments, and prohibit
277 # restrict to exactly that set of arguments, and prohibit
281 # any repo name that starts with '--' to prevent
278 # any repo name that starts with '--' to prevent
282 # shenanigans wherein a user does something like pass
279 # shenanigans wherein a user does something like pass
283 # --debugger or --config=ui.debugger=1 as a repo
280 # --debugger or --config=ui.debugger=1 as a repo
284 # name. This used to actually run the debugger.
281 # name. This used to actually run the debugger.
285 if (len(req.args) != 4 or
282 if (len(req.args) != 4 or
286 req.args[0] != '-R' or
283 req.args[0] != '-R' or
287 req.args[1].startswith('--') or
284 req.args[1].startswith('--') or
288 req.args[2] != 'serve' or
285 req.args[2] != 'serve' or
289 req.args[3] != '--stdio'):
286 req.args[3] != '--stdio'):
290 raise error.Abort(
287 raise error.Abort(
291 _('potentially unsafe serve --stdio invocation: %r') %
288 _('potentially unsafe serve --stdio invocation: %r') %
292 (req.args,))
289 (req.args,))
293
290
294 try:
291 try:
295 debugger = 'pdb'
292 debugger = 'pdb'
296 debugtrace = {
293 debugtrace = {
297 'pdb': pdb.set_trace
294 'pdb': pdb.set_trace
298 }
295 }
299 debugmortem = {
296 debugmortem = {
300 'pdb': pdb.post_mortem
297 'pdb': pdb.post_mortem
301 }
298 }
302
299
303 # read --config before doing anything else
300 # read --config before doing anything else
304 # (e.g. to change trust settings for reading .hg/hgrc)
301 # (e.g. to change trust settings for reading .hg/hgrc)
305 cfgs = _parseconfig(req.ui, req.earlyoptions['config'])
302 cfgs = _parseconfig(req.ui, req.earlyoptions['config'])
306
303
307 if req.repo:
304 if req.repo:
308 # copy configs that were passed on the cmdline (--config) to
305 # copy configs that were passed on the cmdline (--config) to
309 # the repo ui
306 # the repo ui
310 for sec, name, val in cfgs:
307 for sec, name, val in cfgs:
311 req.repo.ui.setconfig(sec, name, val, source='--config')
308 req.repo.ui.setconfig(sec, name, val, source='--config')
312
309
313 # developer config: ui.debugger
310 # developer config: ui.debugger
314 debugger = ui.config("ui", "debugger")
311 debugger = ui.config("ui", "debugger")
315 debugmod = pdb
312 debugmod = pdb
316 if not debugger or ui.plain():
313 if not debugger or ui.plain():
317 # if we are in HGPLAIN mode, then disable custom debugging
314 # if we are in HGPLAIN mode, then disable custom debugging
318 debugger = 'pdb'
315 debugger = 'pdb'
319 elif req.earlyoptions['debugger']:
316 elif req.earlyoptions['debugger']:
320 # This import can be slow for fancy debuggers, so only
317 # This import can be slow for fancy debuggers, so only
321 # do it when absolutely necessary, i.e. when actual
318 # do it when absolutely necessary, i.e. when actual
322 # debugging has been requested
319 # debugging has been requested
323 with demandimport.deactivated():
320 with demandimport.deactivated():
324 try:
321 try:
325 debugmod = __import__(debugger)
322 debugmod = __import__(debugger)
326 except ImportError:
323 except ImportError:
327 pass # Leave debugmod = pdb
324 pass # Leave debugmod = pdb
328
325
329 debugtrace[debugger] = debugmod.set_trace
326 debugtrace[debugger] = debugmod.set_trace
330 debugmortem[debugger] = debugmod.post_mortem
327 debugmortem[debugger] = debugmod.post_mortem
331
328
332 # enter the debugger before command execution
329 # enter the debugger before command execution
333 if req.earlyoptions['debugger']:
330 if req.earlyoptions['debugger']:
334 ui.warn(_("entering debugger - "
331 ui.warn(_("entering debugger - "
335 "type c to continue starting hg or h for help\n"))
332 "type c to continue starting hg or h for help\n"))
336
333
337 if (debugger != 'pdb' and
334 if (debugger != 'pdb' and
338 debugtrace[debugger] == debugtrace['pdb']):
335 debugtrace[debugger] == debugtrace['pdb']):
339 ui.warn(_("%s debugger specified "
336 ui.warn(_("%s debugger specified "
340 "but its module was not found\n") % debugger)
337 "but its module was not found\n") % debugger)
341 with demandimport.deactivated():
338 with demandimport.deactivated():
342 debugtrace[debugger]()
339 debugtrace[debugger]()
343 try:
340 try:
344 return _dispatch(req)
341 return _dispatch(req)
345 finally:
342 finally:
346 ui.flush()
343 ui.flush()
347 except: # re-raises
344 except: # re-raises
348 # enter the debugger when we hit an exception
345 # enter the debugger when we hit an exception
349 if req.earlyoptions['debugger']:
346 if req.earlyoptions['debugger']:
350 traceback.print_exc()
347 traceback.print_exc()
351 debugmortem[debugger](sys.exc_info()[2])
348 debugmortem[debugger](sys.exc_info()[2])
352 raise
349 raise
353
350
354 return _callcatch(ui, _runcatchfunc)
351 return _callcatch(ui, _runcatchfunc)
355
352
356 def _callcatch(ui, func):
353 def _callcatch(ui, func):
357 """like scmutil.callcatch but handles more high-level exceptions about
354 """like scmutil.callcatch but handles more high-level exceptions about
358 config parsing and commands. besides, use handlecommandexception to handle
355 config parsing and commands. besides, use handlecommandexception to handle
359 uncaught exceptions.
356 uncaught exceptions.
360 """
357 """
361 try:
358 try:
362 return scmutil.callcatch(ui, func)
359 return scmutil.callcatch(ui, func)
363 except error.AmbiguousCommand as inst:
360 except error.AmbiguousCommand as inst:
364 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
361 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
365 (inst.args[0], " ".join(inst.args[1])))
362 (inst.args[0], " ".join(inst.args[1])))
366 except error.CommandError as inst:
363 except error.CommandError as inst:
367 if inst.args[0]:
364 if inst.args[0]:
368 ui.pager('help')
365 ui.pager('help')
369 msgbytes = pycompat.bytestr(inst.args[1])
366 msgbytes = pycompat.bytestr(inst.args[1])
370 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes))
367 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes))
371 commands.help_(ui, inst.args[0], full=False, command=True)
368 commands.help_(ui, inst.args[0], full=False, command=True)
372 else:
369 else:
373 ui.pager('help')
370 ui.pager('help')
374 ui.warn(_("hg: %s\n") % inst.args[1])
371 ui.warn(_("hg: %s\n") % inst.args[1])
375 commands.help_(ui, 'shortlist')
372 commands.help_(ui, 'shortlist')
376 except error.ParseError as inst:
373 except error.ParseError as inst:
377 _formatparse(ui.warn, inst)
374 _formatparse(ui.warn, inst)
378 return -1
375 return -1
379 except error.UnknownCommand as inst:
376 except error.UnknownCommand as inst:
380 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
377 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
381 try:
378 try:
382 # check if the command is in a disabled extension
379 # check if the command is in a disabled extension
383 # (but don't check for extensions themselves)
380 # (but don't check for extensions themselves)
384 formatted = help.formattedhelp(ui, commands, inst.args[0],
381 formatted = help.formattedhelp(ui, commands, inst.args[0],
385 unknowncmd=True)
382 unknowncmd=True)
386 ui.warn(nocmdmsg)
383 ui.warn(nocmdmsg)
387 ui.write(formatted)
384 ui.write(formatted)
388 except (error.UnknownCommand, error.Abort):
385 except (error.UnknownCommand, error.Abort):
389 suggested = False
386 suggested = False
390 if len(inst.args) == 2:
387 if len(inst.args) == 2:
391 sim = _getsimilar(inst.args[1], inst.args[0])
388 sim = _getsimilar(inst.args[1], inst.args[0])
392 if sim:
389 if sim:
393 ui.warn(nocmdmsg)
390 ui.warn(nocmdmsg)
394 _reportsimilar(ui.warn, sim)
391 _reportsimilar(ui.warn, sim)
395 suggested = True
392 suggested = True
396 if not suggested:
393 if not suggested:
397 ui.pager('help')
394 ui.pager('help')
398 ui.warn(nocmdmsg)
395 ui.warn(nocmdmsg)
399 commands.help_(ui, 'shortlist')
396 commands.help_(ui, 'shortlist')
400 except IOError:
397 except IOError:
401 raise
398 raise
402 except KeyboardInterrupt:
399 except KeyboardInterrupt:
403 raise
400 raise
404 except: # probably re-raises
401 except: # probably re-raises
405 if not handlecommandexception(ui):
402 if not handlecommandexception(ui):
406 raise
403 raise
407
404
408 return -1
405 return -1
409
406
410 def aliasargs(fn, givenargs):
407 def aliasargs(fn, givenargs):
411 args = []
408 args = []
412 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction
409 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction
413 if not util.safehasattr(fn, '_origfunc'):
410 if not util.safehasattr(fn, '_origfunc'):
414 args = getattr(fn, 'args', args)
411 args = getattr(fn, 'args', args)
415 if args:
412 if args:
416 cmd = ' '.join(map(procutil.shellquote, args))
413 cmd = ' '.join(map(procutil.shellquote, args))
417
414
418 nums = []
415 nums = []
419 def replacer(m):
416 def replacer(m):
420 num = int(m.group(1)) - 1
417 num = int(m.group(1)) - 1
421 nums.append(num)
418 nums.append(num)
422 if num < len(givenargs):
419 if num < len(givenargs):
423 return givenargs[num]
420 return givenargs[num]
424 raise error.Abort(_('too few arguments for command alias'))
421 raise error.Abort(_('too few arguments for command alias'))
425 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
422 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
426 givenargs = [x for i, x in enumerate(givenargs)
423 givenargs = [x for i, x in enumerate(givenargs)
427 if i not in nums]
424 if i not in nums]
428 args = pycompat.shlexsplit(cmd)
425 args = pycompat.shlexsplit(cmd)
429 return args + givenargs
426 return args + givenargs
430
427
431 def aliasinterpolate(name, args, cmd):
428 def aliasinterpolate(name, args, cmd):
432 '''interpolate args into cmd for shell aliases
429 '''interpolate args into cmd for shell aliases
433
430
434 This also handles $0, $@ and "$@".
431 This also handles $0, $@ and "$@".
435 '''
432 '''
436 # util.interpolate can't deal with "$@" (with quotes) because it's only
433 # util.interpolate can't deal with "$@" (with quotes) because it's only
437 # built to match prefix + patterns.
434 # built to match prefix + patterns.
438 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
435 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
439 replacemap['$0'] = name
436 replacemap['$0'] = name
440 replacemap['$$'] = '$'
437 replacemap['$$'] = '$'
441 replacemap['$@'] = ' '.join(args)
438 replacemap['$@'] = ' '.join(args)
442 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
439 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
443 # parameters, separated out into words. Emulate the same behavior here by
440 # parameters, separated out into words. Emulate the same behavior here by
444 # quoting the arguments individually. POSIX shells will then typically
441 # quoting the arguments individually. POSIX shells will then typically
445 # tokenize each argument into exactly one word.
442 # tokenize each argument into exactly one word.
446 replacemap['"$@"'] = ' '.join(procutil.shellquote(arg) for arg in args)
443 replacemap['"$@"'] = ' '.join(procutil.shellquote(arg) for arg in args)
447 # escape '\$' for regex
444 # escape '\$' for regex
448 regex = '|'.join(replacemap.keys()).replace('$', br'\$')
445 regex = '|'.join(replacemap.keys()).replace('$', br'\$')
449 r = re.compile(regex)
446 r = re.compile(regex)
450 return r.sub(lambda x: replacemap[x.group()], cmd)
447 return r.sub(lambda x: replacemap[x.group()], cmd)
451
448
452 class cmdalias(object):
449 class cmdalias(object):
453 def __init__(self, ui, name, definition, cmdtable, source):
450 def __init__(self, ui, name, definition, cmdtable, source):
454 self.name = self.cmd = name
451 self.name = self.cmd = name
455 self.cmdname = ''
452 self.cmdname = ''
456 self.definition = definition
453 self.definition = definition
457 self.fn = None
454 self.fn = None
458 self.givenargs = []
455 self.givenargs = []
459 self.opts = []
456 self.opts = []
460 self.help = ''
457 self.help = ''
461 self.badalias = None
458 self.badalias = None
462 self.unknowncmd = False
459 self.unknowncmd = False
463 self.source = source
460 self.source = source
464
461
465 try:
462 try:
466 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
463 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
467 for alias, e in cmdtable.iteritems():
464 for alias, e in cmdtable.iteritems():
468 if e is entry:
465 if e is entry:
469 self.cmd = alias
466 self.cmd = alias
470 break
467 break
471 self.shadows = True
468 self.shadows = True
472 except error.UnknownCommand:
469 except error.UnknownCommand:
473 self.shadows = False
470 self.shadows = False
474
471
475 if not self.definition:
472 if not self.definition:
476 self.badalias = _("no definition for alias '%s'") % self.name
473 self.badalias = _("no definition for alias '%s'") % self.name
477 return
474 return
478
475
479 if self.definition.startswith('!'):
476 if self.definition.startswith('!'):
480 shdef = self.definition[1:]
477 shdef = self.definition[1:]
481 self.shell = True
478 self.shell = True
482 def fn(ui, *args):
479 def fn(ui, *args):
483 env = {'HG_ARGS': ' '.join((self.name,) + args)}
480 env = {'HG_ARGS': ' '.join((self.name,) + args)}
484 def _checkvar(m):
481 def _checkvar(m):
485 if m.groups()[0] == '$':
482 if m.groups()[0] == '$':
486 return m.group()
483 return m.group()
487 elif int(m.groups()[0]) <= len(args):
484 elif int(m.groups()[0]) <= len(args):
488 return m.group()
485 return m.group()
489 else:
486 else:
490 ui.debug("No argument found for substitution "
487 ui.debug("No argument found for substitution "
491 "of %i variable in alias '%s' definition.\n"
488 "of %i variable in alias '%s' definition.\n"
492 % (int(m.groups()[0]), self.name))
489 % (int(m.groups()[0]), self.name))
493 return ''
490 return ''
494 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
491 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
495 cmd = aliasinterpolate(self.name, args, cmd)
492 cmd = aliasinterpolate(self.name, args, cmd)
496 return ui.system(cmd, environ=env,
493 return ui.system(cmd, environ=env,
497 blockedtag='alias_%s' % self.name)
494 blockedtag='alias_%s' % self.name)
498 self.fn = fn
495 self.fn = fn
499 self._populatehelp(ui, name, shdef, self.fn)
496 self._populatehelp(ui, name, shdef, self.fn)
500 return
497 return
501
498
502 try:
499 try:
503 args = pycompat.shlexsplit(self.definition)
500 args = pycompat.shlexsplit(self.definition)
504 except ValueError as inst:
501 except ValueError as inst:
505 self.badalias = (_("error in definition for alias '%s': %s")
502 self.badalias = (_("error in definition for alias '%s': %s")
506 % (self.name, stringutil.forcebytestr(inst)))
503 % (self.name, stringutil.forcebytestr(inst)))
507 return
504 return
508 earlyopts, args = _earlysplitopts(args)
505 earlyopts, args = _earlysplitopts(args)
509 if earlyopts:
506 if earlyopts:
510 self.badalias = (_("error in definition for alias '%s': %s may "
507 self.badalias = (_("error in definition for alias '%s': %s may "
511 "only be given on the command line")
508 "only be given on the command line")
512 % (self.name, '/'.join(pycompat.ziplist(*earlyopts)
509 % (self.name, '/'.join(pycompat.ziplist(*earlyopts)
513 [0])))
510 [0])))
514 return
511 return
515 self.cmdname = cmd = args.pop(0)
512 self.cmdname = cmd = args.pop(0)
516 self.givenargs = args
513 self.givenargs = args
517
514
518 try:
515 try:
519 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
516 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
520 if len(tableentry) > 2:
517 if len(tableentry) > 2:
521 self.fn, self.opts, cmdhelp = tableentry
518 self.fn, self.opts, cmdhelp = tableentry
522 else:
519 else:
523 self.fn, self.opts = tableentry
520 self.fn, self.opts = tableentry
524 cmdhelp = None
521 cmdhelp = None
525
522
526 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
523 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
527
524
528 except error.UnknownCommand:
525 except error.UnknownCommand:
529 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
526 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
530 % (self.name, cmd))
527 % (self.name, cmd))
531 self.unknowncmd = True
528 self.unknowncmd = True
532 except error.AmbiguousCommand:
529 except error.AmbiguousCommand:
533 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
530 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
534 % (self.name, cmd))
531 % (self.name, cmd))
535
532
536 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
533 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
537 # confine strings to be passed to i18n.gettext()
534 # confine strings to be passed to i18n.gettext()
538 cfg = {}
535 cfg = {}
539 for k in ('doc', 'help'):
536 for k in ('doc', 'help'):
540 v = ui.config('alias', '%s:%s' % (name, k), None)
537 v = ui.config('alias', '%s:%s' % (name, k), None)
541 if v is None:
538 if v is None:
542 continue
539 continue
543 if not encoding.isasciistr(v):
540 if not encoding.isasciistr(v):
544 self.badalias = (_("non-ASCII character in alias definition "
541 self.badalias = (_("non-ASCII character in alias definition "
545 "'%s:%s'") % (name, k))
542 "'%s:%s'") % (name, k))
546 return
543 return
547 cfg[k] = v
544 cfg[k] = v
548
545
549 self.help = cfg.get('help', defaulthelp or '')
546 self.help = cfg.get('help', defaulthelp or '')
550 if self.help and self.help.startswith("hg " + cmd):
547 if self.help and self.help.startswith("hg " + cmd):
551 # drop prefix in old-style help lines so hg shows the alias
548 # drop prefix in old-style help lines so hg shows the alias
552 self.help = self.help[4 + len(cmd):]
549 self.help = self.help[4 + len(cmd):]
553
550
554 doc = cfg.get('doc', pycompat.getdoc(fn))
551 doc = cfg.get('doc', pycompat.getdoc(fn))
555 if doc is not None:
552 if doc is not None:
556 doc = pycompat.sysstr(doc)
553 doc = pycompat.sysstr(doc)
557 self.__doc__ = doc
554 self.__doc__ = doc
558
555
559 @property
556 @property
560 def args(self):
557 def args(self):
561 args = pycompat.maplist(util.expandpath, self.givenargs)
558 args = pycompat.maplist(util.expandpath, self.givenargs)
562 return aliasargs(self.fn, args)
559 return aliasargs(self.fn, args)
563
560
564 def __getattr__(self, name):
561 def __getattr__(self, name):
565 adefaults = {r'norepo': True, r'cmdtype': unrecoverablewrite,
562 adefaults = {r'norepo': True, r'intents': set(),
566 r'optionalrepo': False, r'inferrepo': False}
563 r'optionalrepo': False, r'inferrepo': False}
567 if name not in adefaults:
564 if name not in adefaults:
568 raise AttributeError(name)
565 raise AttributeError(name)
569 if self.badalias or util.safehasattr(self, 'shell'):
566 if self.badalias or util.safehasattr(self, 'shell'):
570 return adefaults[name]
567 return adefaults[name]
571 return getattr(self.fn, name)
568 return getattr(self.fn, name)
572
569
573 def __call__(self, ui, *args, **opts):
570 def __call__(self, ui, *args, **opts):
574 if self.badalias:
571 if self.badalias:
575 hint = None
572 hint = None
576 if self.unknowncmd:
573 if self.unknowncmd:
577 try:
574 try:
578 # check if the command is in a disabled extension
575 # check if the command is in a disabled extension
579 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
576 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
580 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
577 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
581 except error.UnknownCommand:
578 except error.UnknownCommand:
582 pass
579 pass
583 raise error.Abort(self.badalias, hint=hint)
580 raise error.Abort(self.badalias, hint=hint)
584 if self.shadows:
581 if self.shadows:
585 ui.debug("alias '%s' shadows command '%s'\n" %
582 ui.debug("alias '%s' shadows command '%s'\n" %
586 (self.name, self.cmdname))
583 (self.name, self.cmdname))
587
584
588 ui.log('commandalias', "alias '%s' expands to '%s'\n",
585 ui.log('commandalias', "alias '%s' expands to '%s'\n",
589 self.name, self.definition)
586 self.name, self.definition)
590 if util.safehasattr(self, 'shell'):
587 if util.safehasattr(self, 'shell'):
591 return self.fn(ui, *args, **opts)
588 return self.fn(ui, *args, **opts)
592 else:
589 else:
593 try:
590 try:
594 return util.checksignature(self.fn)(ui, *args, **opts)
591 return util.checksignature(self.fn)(ui, *args, **opts)
595 except error.SignatureError:
592 except error.SignatureError:
596 args = ' '.join([self.cmdname] + self.args)
593 args = ' '.join([self.cmdname] + self.args)
597 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
594 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
598 raise
595 raise
599
596
600 class lazyaliasentry(object):
597 class lazyaliasentry(object):
601 """like a typical command entry (func, opts, help), but is lazy"""
598 """like a typical command entry (func, opts, help), but is lazy"""
602
599
603 def __init__(self, ui, name, definition, cmdtable, source):
600 def __init__(self, ui, name, definition, cmdtable, source):
604 self.ui = ui
601 self.ui = ui
605 self.name = name
602 self.name = name
606 self.definition = definition
603 self.definition = definition
607 self.cmdtable = cmdtable.copy()
604 self.cmdtable = cmdtable.copy()
608 self.source = source
605 self.source = source
609
606
610 @util.propertycache
607 @util.propertycache
611 def _aliasdef(self):
608 def _aliasdef(self):
612 return cmdalias(self.ui, self.name, self.definition, self.cmdtable,
609 return cmdalias(self.ui, self.name, self.definition, self.cmdtable,
613 self.source)
610 self.source)
614
611
615 def __getitem__(self, n):
612 def __getitem__(self, n):
616 aliasdef = self._aliasdef
613 aliasdef = self._aliasdef
617 if n == 0:
614 if n == 0:
618 return aliasdef
615 return aliasdef
619 elif n == 1:
616 elif n == 1:
620 return aliasdef.opts
617 return aliasdef.opts
621 elif n == 2:
618 elif n == 2:
622 return aliasdef.help
619 return aliasdef.help
623 else:
620 else:
624 raise IndexError
621 raise IndexError
625
622
626 def __iter__(self):
623 def __iter__(self):
627 for i in range(3):
624 for i in range(3):
628 yield self[i]
625 yield self[i]
629
626
630 def __len__(self):
627 def __len__(self):
631 return 3
628 return 3
632
629
633 def addaliases(ui, cmdtable):
630 def addaliases(ui, cmdtable):
634 # aliases are processed after extensions have been loaded, so they
631 # aliases are processed after extensions have been loaded, so they
635 # may use extension commands. Aliases can also use other alias definitions,
632 # may use extension commands. Aliases can also use other alias definitions,
636 # but only if they have been defined prior to the current definition.
633 # but only if they have been defined prior to the current definition.
637 for alias, definition in ui.configitems('alias', ignoresub=True):
634 for alias, definition in ui.configitems('alias', ignoresub=True):
638 try:
635 try:
639 if cmdtable[alias].definition == definition:
636 if cmdtable[alias].definition == definition:
640 continue
637 continue
641 except (KeyError, AttributeError):
638 except (KeyError, AttributeError):
642 # definition might not exist or it might not be a cmdalias
639 # definition might not exist or it might not be a cmdalias
643 pass
640 pass
644
641
645 source = ui.configsource('alias', alias)
642 source = ui.configsource('alias', alias)
646 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
643 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
647 cmdtable[alias] = entry
644 cmdtable[alias] = entry
648
645
649 def _parse(ui, args):
646 def _parse(ui, args):
650 options = {}
647 options = {}
651 cmdoptions = {}
648 cmdoptions = {}
652
649
653 try:
650 try:
654 args = fancyopts.fancyopts(args, commands.globalopts, options)
651 args = fancyopts.fancyopts(args, commands.globalopts, options)
655 except getopt.GetoptError as inst:
652 except getopt.GetoptError as inst:
656 raise error.CommandError(None, stringutil.forcebytestr(inst))
653 raise error.CommandError(None, stringutil.forcebytestr(inst))
657
654
658 if args:
655 if args:
659 cmd, args = args[0], args[1:]
656 cmd, args = args[0], args[1:]
660 aliases, entry = cmdutil.findcmd(cmd, commands.table,
657 aliases, entry = cmdutil.findcmd(cmd, commands.table,
661 ui.configbool("ui", "strict"))
658 ui.configbool("ui", "strict"))
662 cmd = aliases[0]
659 cmd = aliases[0]
663 args = aliasargs(entry[0], args)
660 args = aliasargs(entry[0], args)
664 defaults = ui.config("defaults", cmd)
661 defaults = ui.config("defaults", cmd)
665 if defaults:
662 if defaults:
666 args = pycompat.maplist(
663 args = pycompat.maplist(
667 util.expandpath, pycompat.shlexsplit(defaults)) + args
664 util.expandpath, pycompat.shlexsplit(defaults)) + args
668 c = list(entry[1])
665 c = list(entry[1])
669 else:
666 else:
670 cmd = None
667 cmd = None
671 c = []
668 c = []
672
669
673 # combine global options into local
670 # combine global options into local
674 for o in commands.globalopts:
671 for o in commands.globalopts:
675 c.append((o[0], o[1], options[o[1]], o[3]))
672 c.append((o[0], o[1], options[o[1]], o[3]))
676
673
677 try:
674 try:
678 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
675 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
679 except getopt.GetoptError as inst:
676 except getopt.GetoptError as inst:
680 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
677 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
681
678
682 # separate global options back out
679 # separate global options back out
683 for o in commands.globalopts:
680 for o in commands.globalopts:
684 n = o[1]
681 n = o[1]
685 options[n] = cmdoptions[n]
682 options[n] = cmdoptions[n]
686 del cmdoptions[n]
683 del cmdoptions[n]
687
684
688 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
685 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
689
686
690 def _parseconfig(ui, config):
687 def _parseconfig(ui, config):
691 """parse the --config options from the command line"""
688 """parse the --config options from the command line"""
692 configs = []
689 configs = []
693
690
694 for cfg in config:
691 for cfg in config:
695 try:
692 try:
696 name, value = [cfgelem.strip()
693 name, value = [cfgelem.strip()
697 for cfgelem in cfg.split('=', 1)]
694 for cfgelem in cfg.split('=', 1)]
698 section, name = name.split('.', 1)
695 section, name = name.split('.', 1)
699 if not section or not name:
696 if not section or not name:
700 raise IndexError
697 raise IndexError
701 ui.setconfig(section, name, value, '--config')
698 ui.setconfig(section, name, value, '--config')
702 configs.append((section, name, value))
699 configs.append((section, name, value))
703 except (IndexError, ValueError):
700 except (IndexError, ValueError):
704 raise error.Abort(_('malformed --config option: %r '
701 raise error.Abort(_('malformed --config option: %r '
705 '(use --config section.name=value)')
702 '(use --config section.name=value)')
706 % pycompat.bytestr(cfg))
703 % pycompat.bytestr(cfg))
707
704
708 return configs
705 return configs
709
706
710 def _earlyparseopts(ui, args):
707 def _earlyparseopts(ui, args):
711 options = {}
708 options = {}
712 fancyopts.fancyopts(args, commands.globalopts, options,
709 fancyopts.fancyopts(args, commands.globalopts, options,
713 gnu=not ui.plain('strictflags'), early=True,
710 gnu=not ui.plain('strictflags'), early=True,
714 optaliases={'repository': ['repo']})
711 optaliases={'repository': ['repo']})
715 return options
712 return options
716
713
717 def _earlysplitopts(args):
714 def _earlysplitopts(args):
718 """Split args into a list of possible early options and remainder args"""
715 """Split args into a list of possible early options and remainder args"""
719 shortoptions = 'R:'
716 shortoptions = 'R:'
720 # TODO: perhaps 'debugger' should be included
717 # TODO: perhaps 'debugger' should be included
721 longoptions = ['cwd=', 'repository=', 'repo=', 'config=']
718 longoptions = ['cwd=', 'repository=', 'repo=', 'config=']
722 return fancyopts.earlygetopt(args, shortoptions, longoptions,
719 return fancyopts.earlygetopt(args, shortoptions, longoptions,
723 gnu=True, keepsep=True)
720 gnu=True, keepsep=True)
724
721
725 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
722 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
726 # run pre-hook, and abort if it fails
723 # run pre-hook, and abort if it fails
727 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
724 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
728 pats=cmdpats, opts=cmdoptions)
725 pats=cmdpats, opts=cmdoptions)
729 try:
726 try:
730 ret = _runcommand(ui, options, cmd, d)
727 ret = _runcommand(ui, options, cmd, d)
731 # run post-hook, passing command result
728 # run post-hook, passing command result
732 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
729 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
733 result=ret, pats=cmdpats, opts=cmdoptions)
730 result=ret, pats=cmdpats, opts=cmdoptions)
734 except Exception:
731 except Exception:
735 # run failure hook and re-raise
732 # run failure hook and re-raise
736 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
733 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
737 pats=cmdpats, opts=cmdoptions)
734 pats=cmdpats, opts=cmdoptions)
738 raise
735 raise
739 return ret
736 return ret
740
737
741 def _getlocal(ui, rpath, wd=None):
738 def _getlocal(ui, rpath, wd=None):
742 """Return (path, local ui object) for the given target path.
739 """Return (path, local ui object) for the given target path.
743
740
744 Takes paths in [cwd]/.hg/hgrc into account."
741 Takes paths in [cwd]/.hg/hgrc into account."
745 """
742 """
746 if wd is None:
743 if wd is None:
747 try:
744 try:
748 wd = pycompat.getcwd()
745 wd = pycompat.getcwd()
749 except OSError as e:
746 except OSError as e:
750 raise error.Abort(_("error getting current working directory: %s") %
747 raise error.Abort(_("error getting current working directory: %s") %
751 encoding.strtolocal(e.strerror))
748 encoding.strtolocal(e.strerror))
752 path = cmdutil.findrepo(wd) or ""
749 path = cmdutil.findrepo(wd) or ""
753 if not path:
750 if not path:
754 lui = ui
751 lui = ui
755 else:
752 else:
756 lui = ui.copy()
753 lui = ui.copy()
757 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
754 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
758
755
759 if rpath:
756 if rpath:
760 path = lui.expandpath(rpath)
757 path = lui.expandpath(rpath)
761 lui = ui.copy()
758 lui = ui.copy()
762 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
759 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
763
760
764 return path, lui
761 return path, lui
765
762
766 def _checkshellalias(lui, ui, args):
763 def _checkshellalias(lui, ui, args):
767 """Return the function to run the shell alias, if it is required"""
764 """Return the function to run the shell alias, if it is required"""
768 options = {}
765 options = {}
769
766
770 try:
767 try:
771 args = fancyopts.fancyopts(args, commands.globalopts, options)
768 args = fancyopts.fancyopts(args, commands.globalopts, options)
772 except getopt.GetoptError:
769 except getopt.GetoptError:
773 return
770 return
774
771
775 if not args:
772 if not args:
776 return
773 return
777
774
778 cmdtable = commands.table
775 cmdtable = commands.table
779
776
780 cmd = args[0]
777 cmd = args[0]
781 try:
778 try:
782 strict = ui.configbool("ui", "strict")
779 strict = ui.configbool("ui", "strict")
783 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
780 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
784 except (error.AmbiguousCommand, error.UnknownCommand):
781 except (error.AmbiguousCommand, error.UnknownCommand):
785 return
782 return
786
783
787 cmd = aliases[0]
784 cmd = aliases[0]
788 fn = entry[0]
785 fn = entry[0]
789
786
790 if cmd and util.safehasattr(fn, 'shell'):
787 if cmd and util.safehasattr(fn, 'shell'):
791 # shell alias shouldn't receive early options which are consumed by hg
788 # shell alias shouldn't receive early options which are consumed by hg
792 _earlyopts, args = _earlysplitopts(args)
789 _earlyopts, args = _earlysplitopts(args)
793 d = lambda: fn(ui, *args[1:])
790 d = lambda: fn(ui, *args[1:])
794 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
791 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
795 [], {})
792 [], {})
796
793
797 def _dispatch(req):
794 def _dispatch(req):
798 args = req.args
795 args = req.args
799 ui = req.ui
796 ui = req.ui
800
797
801 # check for cwd
798 # check for cwd
802 cwd = req.earlyoptions['cwd']
799 cwd = req.earlyoptions['cwd']
803 if cwd:
800 if cwd:
804 os.chdir(cwd)
801 os.chdir(cwd)
805
802
806 rpath = req.earlyoptions['repository']
803 rpath = req.earlyoptions['repository']
807 path, lui = _getlocal(ui, rpath)
804 path, lui = _getlocal(ui, rpath)
808
805
809 uis = {ui, lui}
806 uis = {ui, lui}
810
807
811 if req.repo:
808 if req.repo:
812 uis.add(req.repo.ui)
809 uis.add(req.repo.ui)
813
810
814 if req.earlyoptions['profile']:
811 if req.earlyoptions['profile']:
815 for ui_ in uis:
812 for ui_ in uis:
816 ui_.setconfig('profiling', 'enabled', 'true', '--profile')
813 ui_.setconfig('profiling', 'enabled', 'true', '--profile')
817
814
818 profile = lui.configbool('profiling', 'enabled')
815 profile = lui.configbool('profiling', 'enabled')
819 with profiling.profile(lui, enabled=profile) as profiler:
816 with profiling.profile(lui, enabled=profile) as profiler:
820 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
817 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
821 # reposetup
818 # reposetup
822 extensions.loadall(lui)
819 extensions.loadall(lui)
823 # Propagate any changes to lui.__class__ by extensions
820 # Propagate any changes to lui.__class__ by extensions
824 ui.__class__ = lui.__class__
821 ui.__class__ = lui.__class__
825
822
826 # (uisetup and extsetup are handled in extensions.loadall)
823 # (uisetup and extsetup are handled in extensions.loadall)
827
824
828 # (reposetup is handled in hg.repository)
825 # (reposetup is handled in hg.repository)
829
826
830 addaliases(lui, commands.table)
827 addaliases(lui, commands.table)
831
828
832 # All aliases and commands are completely defined, now.
829 # All aliases and commands are completely defined, now.
833 # Check abbreviation/ambiguity of shell alias.
830 # Check abbreviation/ambiguity of shell alias.
834 shellaliasfn = _checkshellalias(lui, ui, args)
831 shellaliasfn = _checkshellalias(lui, ui, args)
835 if shellaliasfn:
832 if shellaliasfn:
836 return shellaliasfn()
833 return shellaliasfn()
837
834
838 # check for fallback encoding
835 # check for fallback encoding
839 fallback = lui.config('ui', 'fallbackencoding')
836 fallback = lui.config('ui', 'fallbackencoding')
840 if fallback:
837 if fallback:
841 encoding.fallbackencoding = fallback
838 encoding.fallbackencoding = fallback
842
839
843 fullargs = args
840 fullargs = args
844 cmd, func, args, options, cmdoptions = _parse(lui, args)
841 cmd, func, args, options, cmdoptions = _parse(lui, args)
845
842
846 if options["config"] != req.earlyoptions["config"]:
843 if options["config"] != req.earlyoptions["config"]:
847 raise error.Abort(_("option --config may not be abbreviated!"))
844 raise error.Abort(_("option --config may not be abbreviated!"))
848 if options["cwd"] != req.earlyoptions["cwd"]:
845 if options["cwd"] != req.earlyoptions["cwd"]:
849 raise error.Abort(_("option --cwd may not be abbreviated!"))
846 raise error.Abort(_("option --cwd may not be abbreviated!"))
850 if options["repository"] != req.earlyoptions["repository"]:
847 if options["repository"] != req.earlyoptions["repository"]:
851 raise error.Abort(_(
848 raise error.Abort(_(
852 "option -R has to be separated from other options (e.g. not "
849 "option -R has to be separated from other options (e.g. not "
853 "-qR) and --repository may only be abbreviated as --repo!"))
850 "-qR) and --repository may only be abbreviated as --repo!"))
854 if options["debugger"] != req.earlyoptions["debugger"]:
851 if options["debugger"] != req.earlyoptions["debugger"]:
855 raise error.Abort(_("option --debugger may not be abbreviated!"))
852 raise error.Abort(_("option --debugger may not be abbreviated!"))
856 # don't validate --profile/--traceback, which can be enabled from now
853 # don't validate --profile/--traceback, which can be enabled from now
857
854
858 if options["encoding"]:
855 if options["encoding"]:
859 encoding.encoding = options["encoding"]
856 encoding.encoding = options["encoding"]
860 if options["encodingmode"]:
857 if options["encodingmode"]:
861 encoding.encodingmode = options["encodingmode"]
858 encoding.encodingmode = options["encodingmode"]
862 if options["time"]:
859 if options["time"]:
863 def get_times():
860 def get_times():
864 t = os.times()
861 t = os.times()
865 if t[4] == 0.0:
862 if t[4] == 0.0:
866 # Windows leaves this as zero, so use time.clock()
863 # Windows leaves this as zero, so use time.clock()
867 t = (t[0], t[1], t[2], t[3], time.clock())
864 t = (t[0], t[1], t[2], t[3], time.clock())
868 return t
865 return t
869 s = get_times()
866 s = get_times()
870 def print_time():
867 def print_time():
871 t = get_times()
868 t = get_times()
872 ui.warn(
869 ui.warn(
873 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
870 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
874 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
871 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
875 ui.atexit(print_time)
872 ui.atexit(print_time)
876 if options["profile"]:
873 if options["profile"]:
877 profiler.start()
874 profiler.start()
878
875
879 if options['verbose'] or options['debug'] or options['quiet']:
876 if options['verbose'] or options['debug'] or options['quiet']:
880 for opt in ('verbose', 'debug', 'quiet'):
877 for opt in ('verbose', 'debug', 'quiet'):
881 val = pycompat.bytestr(bool(options[opt]))
878 val = pycompat.bytestr(bool(options[opt]))
882 for ui_ in uis:
879 for ui_ in uis:
883 ui_.setconfig('ui', opt, val, '--' + opt)
880 ui_.setconfig('ui', opt, val, '--' + opt)
884
881
885 if options['traceback']:
882 if options['traceback']:
886 for ui_ in uis:
883 for ui_ in uis:
887 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
884 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
888
885
889 if options['noninteractive']:
886 if options['noninteractive']:
890 for ui_ in uis:
887 for ui_ in uis:
891 ui_.setconfig('ui', 'interactive', 'off', '-y')
888 ui_.setconfig('ui', 'interactive', 'off', '-y')
892
889
893 if cmdoptions.get('insecure', False):
890 if cmdoptions.get('insecure', False):
894 for ui_ in uis:
891 for ui_ in uis:
895 ui_.insecureconnections = True
892 ui_.insecureconnections = True
896
893
897 # setup color handling before pager, because setting up pager
894 # setup color handling before pager, because setting up pager
898 # might cause incorrect console information
895 # might cause incorrect console information
899 coloropt = options['color']
896 coloropt = options['color']
900 for ui_ in uis:
897 for ui_ in uis:
901 if coloropt:
898 if coloropt:
902 ui_.setconfig('ui', 'color', coloropt, '--color')
899 ui_.setconfig('ui', 'color', coloropt, '--color')
903 color.setup(ui_)
900 color.setup(ui_)
904
901
905 if stringutil.parsebool(options['pager']):
902 if stringutil.parsebool(options['pager']):
906 # ui.pager() expects 'internal-always-' prefix in this case
903 # ui.pager() expects 'internal-always-' prefix in this case
907 ui.pager('internal-always-' + cmd)
904 ui.pager('internal-always-' + cmd)
908 elif options['pager'] != 'auto':
905 elif options['pager'] != 'auto':
909 for ui_ in uis:
906 for ui_ in uis:
910 ui_.disablepager()
907 ui_.disablepager()
911
908
912 if options['version']:
909 if options['version']:
913 return commands.version_(ui)
910 return commands.version_(ui)
914 if options['help']:
911 if options['help']:
915 return commands.help_(ui, cmd, command=cmd is not None)
912 return commands.help_(ui, cmd, command=cmd is not None)
916 elif not cmd:
913 elif not cmd:
917 return commands.help_(ui, 'shortlist')
914 return commands.help_(ui, 'shortlist')
918
915
919 repo = None
916 repo = None
920 cmdpats = args[:]
917 cmdpats = args[:]
921 if not func.norepo:
918 if not func.norepo:
922 # use the repo from the request only if we don't have -R
919 # use the repo from the request only if we don't have -R
923 if not rpath and not cwd:
920 if not rpath and not cwd:
924 repo = req.repo
921 repo = req.repo
925
922
926 if repo:
923 if repo:
927 # set the descriptors of the repo ui to those of ui
924 # set the descriptors of the repo ui to those of ui
928 repo.ui.fin = ui.fin
925 repo.ui.fin = ui.fin
929 repo.ui.fout = ui.fout
926 repo.ui.fout = ui.fout
930 repo.ui.ferr = ui.ferr
927 repo.ui.ferr = ui.ferr
931 else:
928 else:
932 try:
929 try:
933 repo = hg.repository(ui, path=path,
930 repo = hg.repository(ui, path=path,
934 presetupfuncs=req.prereposetups)
931 presetupfuncs=req.prereposetups)
935 if not repo.local():
932 if not repo.local():
936 raise error.Abort(_("repository '%s' is not local")
933 raise error.Abort(_("repository '%s' is not local")
937 % path)
934 % path)
938 repo.ui.setconfig("bundle", "mainreporoot", repo.root,
935 repo.ui.setconfig("bundle", "mainreporoot", repo.root,
939 'repo')
936 'repo')
940 except error.RequirementError:
937 except error.RequirementError:
941 raise
938 raise
942 except error.RepoError:
939 except error.RepoError:
943 if rpath: # invalid -R path
940 if rpath: # invalid -R path
944 raise
941 raise
945 if not func.optionalrepo:
942 if not func.optionalrepo:
946 if func.inferrepo and args and not path:
943 if func.inferrepo and args and not path:
947 # try to infer -R from command args
944 # try to infer -R from command args
948 repos = pycompat.maplist(cmdutil.findrepo, args)
945 repos = pycompat.maplist(cmdutil.findrepo, args)
949 guess = repos[0]
946 guess = repos[0]
950 if guess and repos.count(guess) == len(repos):
947 if guess and repos.count(guess) == len(repos):
951 req.args = ['--repository', guess] + fullargs
948 req.args = ['--repository', guess] + fullargs
952 req.earlyoptions['repository'] = guess
949 req.earlyoptions['repository'] = guess
953 return _dispatch(req)
950 return _dispatch(req)
954 if not path:
951 if not path:
955 raise error.RepoError(_("no repository found in"
952 raise error.RepoError(_("no repository found in"
956 " '%s' (.hg not found)")
953 " '%s' (.hg not found)")
957 % pycompat.getcwd())
954 % pycompat.getcwd())
958 raise
955 raise
959 if repo:
956 if repo:
960 ui = repo.ui
957 ui = repo.ui
961 if options['hidden']:
958 if options['hidden']:
962 repo = repo.unfiltered()
959 repo = repo.unfiltered()
963 args.insert(0, repo)
960 args.insert(0, repo)
964 elif rpath:
961 elif rpath:
965 ui.warn(_("warning: --repository ignored\n"))
962 ui.warn(_("warning: --repository ignored\n"))
966
963
967 msg = _formatargs(fullargs)
964 msg = _formatargs(fullargs)
968 ui.log("command", '%s\n', msg)
965 ui.log("command", '%s\n', msg)
969 strcmdopt = pycompat.strkwargs(cmdoptions)
966 strcmdopt = pycompat.strkwargs(cmdoptions)
970 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
967 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
971 try:
968 try:
972 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
969 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
973 cmdpats, cmdoptions)
970 cmdpats, cmdoptions)
974 finally:
971 finally:
975 if repo and repo != req.repo:
972 if repo and repo != req.repo:
976 repo.close()
973 repo.close()
977
974
978 def _runcommand(ui, options, cmd, cmdfunc):
975 def _runcommand(ui, options, cmd, cmdfunc):
979 """Run a command function, possibly with profiling enabled."""
976 """Run a command function, possibly with profiling enabled."""
980 try:
977 try:
981 return cmdfunc()
978 return cmdfunc()
982 except error.SignatureError:
979 except error.SignatureError:
983 raise error.CommandError(cmd, _('invalid arguments'))
980 raise error.CommandError(cmd, _('invalid arguments'))
984
981
985 def _exceptionwarning(ui):
982 def _exceptionwarning(ui):
986 """Produce a warning message for the current active exception"""
983 """Produce a warning message for the current active exception"""
987
984
988 # For compatibility checking, we discard the portion of the hg
985 # For compatibility checking, we discard the portion of the hg
989 # version after the + on the assumption that if a "normal
986 # version after the + on the assumption that if a "normal
990 # user" is running a build with a + in it the packager
987 # user" is running a build with a + in it the packager
991 # probably built from fairly close to a tag and anyone with a
988 # probably built from fairly close to a tag and anyone with a
992 # 'make local' copy of hg (where the version number can be out
989 # 'make local' copy of hg (where the version number can be out
993 # of date) will be clueful enough to notice the implausible
990 # of date) will be clueful enough to notice the implausible
994 # version number and try updating.
991 # version number and try updating.
995 ct = util.versiontuple(n=2)
992 ct = util.versiontuple(n=2)
996 worst = None, ct, ''
993 worst = None, ct, ''
997 if ui.config('ui', 'supportcontact') is None:
994 if ui.config('ui', 'supportcontact') is None:
998 for name, mod in extensions.extensions():
995 for name, mod in extensions.extensions():
999 # 'testedwith' should be bytes, but not all extensions are ported
996 # 'testedwith' should be bytes, but not all extensions are ported
1000 # to py3 and we don't want UnicodeException because of that.
997 # to py3 and we don't want UnicodeException because of that.
1001 testedwith = stringutil.forcebytestr(getattr(mod, 'testedwith', ''))
998 testedwith = stringutil.forcebytestr(getattr(mod, 'testedwith', ''))
1002 report = getattr(mod, 'buglink', _('the extension author.'))
999 report = getattr(mod, 'buglink', _('the extension author.'))
1003 if not testedwith.strip():
1000 if not testedwith.strip():
1004 # We found an untested extension. It's likely the culprit.
1001 # We found an untested extension. It's likely the culprit.
1005 worst = name, 'unknown', report
1002 worst = name, 'unknown', report
1006 break
1003 break
1007
1004
1008 # Never blame on extensions bundled with Mercurial.
1005 # Never blame on extensions bundled with Mercurial.
1009 if extensions.ismoduleinternal(mod):
1006 if extensions.ismoduleinternal(mod):
1010 continue
1007 continue
1011
1008
1012 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1009 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1013 if ct in tested:
1010 if ct in tested:
1014 continue
1011 continue
1015
1012
1016 lower = [t for t in tested if t < ct]
1013 lower = [t for t in tested if t < ct]
1017 nearest = max(lower or tested)
1014 nearest = max(lower or tested)
1018 if worst[0] is None or nearest < worst[1]:
1015 if worst[0] is None or nearest < worst[1]:
1019 worst = name, nearest, report
1016 worst = name, nearest, report
1020 if worst[0] is not None:
1017 if worst[0] is not None:
1021 name, testedwith, report = worst
1018 name, testedwith, report = worst
1022 if not isinstance(testedwith, (bytes, str)):
1019 if not isinstance(testedwith, (bytes, str)):
1023 testedwith = '.'.join([stringutil.forcebytestr(c)
1020 testedwith = '.'.join([stringutil.forcebytestr(c)
1024 for c in testedwith])
1021 for c in testedwith])
1025 warning = (_('** Unknown exception encountered with '
1022 warning = (_('** Unknown exception encountered with '
1026 'possibly-broken third-party extension %s\n'
1023 'possibly-broken third-party extension %s\n'
1027 '** which supports versions %s of Mercurial.\n'
1024 '** which supports versions %s of Mercurial.\n'
1028 '** Please disable %s and try your action again.\n'
1025 '** Please disable %s and try your action again.\n'
1029 '** If that fixes the bug please report it to %s\n')
1026 '** If that fixes the bug please report it to %s\n')
1030 % (name, testedwith, name, report))
1027 % (name, testedwith, name, report))
1031 else:
1028 else:
1032 bugtracker = ui.config('ui', 'supportcontact')
1029 bugtracker = ui.config('ui', 'supportcontact')
1033 if bugtracker is None:
1030 if bugtracker is None:
1034 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
1031 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
1035 warning = (_("** unknown exception encountered, "
1032 warning = (_("** unknown exception encountered, "
1036 "please report by visiting\n** ") + bugtracker + '\n')
1033 "please report by visiting\n** ") + bugtracker + '\n')
1037 sysversion = pycompat.sysbytes(sys.version).replace('\n', '')
1034 sysversion = pycompat.sysbytes(sys.version).replace('\n', '')
1038 warning += ((_("** Python %s\n") % sysversion) +
1035 warning += ((_("** Python %s\n") % sysversion) +
1039 (_("** Mercurial Distributed SCM (version %s)\n") %
1036 (_("** Mercurial Distributed SCM (version %s)\n") %
1040 util.version()) +
1037 util.version()) +
1041 (_("** Extensions loaded: %s\n") %
1038 (_("** Extensions loaded: %s\n") %
1042 ", ".join([x[0] for x in extensions.extensions()])))
1039 ", ".join([x[0] for x in extensions.extensions()])))
1043 return warning
1040 return warning
1044
1041
1045 def handlecommandexception(ui):
1042 def handlecommandexception(ui):
1046 """Produce a warning message for broken commands
1043 """Produce a warning message for broken commands
1047
1044
1048 Called when handling an exception; the exception is reraised if
1045 Called when handling an exception; the exception is reraised if
1049 this function returns False, ignored otherwise.
1046 this function returns False, ignored otherwise.
1050 """
1047 """
1051 warning = _exceptionwarning(ui)
1048 warning = _exceptionwarning(ui)
1052 ui.log("commandexception", "%s\n%s\n", warning,
1049 ui.log("commandexception", "%s\n%s\n", warning,
1053 pycompat.sysbytes(traceback.format_exc()))
1050 pycompat.sysbytes(traceback.format_exc()))
1054 ui.warn(warning)
1051 ui.warn(warning)
1055 return False # re-raise the exception
1052 return False # re-raise the exception
@@ -1,443 +1,439 b''
1 # registrar.py - utilities to register function for specific purpose
1 # registrar.py - utilities to register function for specific purpose
2 #
2 #
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
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 from . import (
10 from . import (
11 configitems,
11 configitems,
12 error,
12 error,
13 pycompat,
13 pycompat,
14 util,
14 util,
15 )
15 )
16
16
17 # unlike the other registered items, config options are neither functions or
17 # unlike the other registered items, config options are neither functions or
18 # classes. Registering the option is just small function call.
18 # classes. Registering the option is just small function call.
19 #
19 #
20 # We still add the official API to the registrar module for consistency with
20 # We still add the official API to the registrar module for consistency with
21 # the other items extensions want might to register.
21 # the other items extensions want might to register.
22 configitem = configitems.getitemregister
22 configitem = configitems.getitemregister
23
23
24 class _funcregistrarbase(object):
24 class _funcregistrarbase(object):
25 """Base of decorator to register a function for specific purpose
25 """Base of decorator to register a function for specific purpose
26
26
27 This decorator stores decorated functions into own dict 'table'.
27 This decorator stores decorated functions into own dict 'table'.
28
28
29 The least derived class can be defined by overriding 'formatdoc',
29 The least derived class can be defined by overriding 'formatdoc',
30 for example::
30 for example::
31
31
32 class keyword(_funcregistrarbase):
32 class keyword(_funcregistrarbase):
33 _docformat = ":%s: %s"
33 _docformat = ":%s: %s"
34
34
35 This should be used as below:
35 This should be used as below:
36
36
37 keyword = registrar.keyword()
37 keyword = registrar.keyword()
38
38
39 @keyword('bar')
39 @keyword('bar')
40 def barfunc(*args, **kwargs):
40 def barfunc(*args, **kwargs):
41 '''Explanation of bar keyword ....
41 '''Explanation of bar keyword ....
42 '''
42 '''
43 pass
43 pass
44
44
45 In this case:
45 In this case:
46
46
47 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
47 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
48 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
48 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
49 """
49 """
50 def __init__(self, table=None):
50 def __init__(self, table=None):
51 if table is None:
51 if table is None:
52 self._table = {}
52 self._table = {}
53 else:
53 else:
54 self._table = table
54 self._table = table
55
55
56 def __call__(self, decl, *args, **kwargs):
56 def __call__(self, decl, *args, **kwargs):
57 return lambda func: self._doregister(func, decl, *args, **kwargs)
57 return lambda func: self._doregister(func, decl, *args, **kwargs)
58
58
59 def _doregister(self, func, decl, *args, **kwargs):
59 def _doregister(self, func, decl, *args, **kwargs):
60 name = self._getname(decl)
60 name = self._getname(decl)
61
61
62 if name in self._table:
62 if name in self._table:
63 msg = 'duplicate registration for name: "%s"' % name
63 msg = 'duplicate registration for name: "%s"' % name
64 raise error.ProgrammingError(msg)
64 raise error.ProgrammingError(msg)
65
65
66 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
66 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
67 doc = pycompat.sysbytes(func.__doc__).strip()
67 doc = pycompat.sysbytes(func.__doc__).strip()
68 func._origdoc = doc
68 func._origdoc = doc
69 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
69 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
70
70
71 self._table[name] = func
71 self._table[name] = func
72 self._extrasetup(name, func, *args, **kwargs)
72 self._extrasetup(name, func, *args, **kwargs)
73
73
74 return func
74 return func
75
75
76 def _parsefuncdecl(self, decl):
76 def _parsefuncdecl(self, decl):
77 """Parse function declaration and return the name of function in it
77 """Parse function declaration and return the name of function in it
78 """
78 """
79 i = decl.find('(')
79 i = decl.find('(')
80 if i >= 0:
80 if i >= 0:
81 return decl[:i]
81 return decl[:i]
82 else:
82 else:
83 return decl
83 return decl
84
84
85 def _getname(self, decl):
85 def _getname(self, decl):
86 """Return the name of the registered function from decl
86 """Return the name of the registered function from decl
87
87
88 Derived class should override this, if it allows more
88 Derived class should override this, if it allows more
89 descriptive 'decl' string than just a name.
89 descriptive 'decl' string than just a name.
90 """
90 """
91 return decl
91 return decl
92
92
93 _docformat = None
93 _docformat = None
94
94
95 def _formatdoc(self, decl, doc):
95 def _formatdoc(self, decl, doc):
96 """Return formatted document of the registered function for help
96 """Return formatted document of the registered function for help
97
97
98 'doc' is '__doc__.strip()' of the registered function.
98 'doc' is '__doc__.strip()' of the registered function.
99 """
99 """
100 return self._docformat % (decl, doc)
100 return self._docformat % (decl, doc)
101
101
102 def _extrasetup(self, name, func):
102 def _extrasetup(self, name, func):
103 """Execute exra setup for registered function, if needed
103 """Execute exra setup for registered function, if needed
104 """
104 """
105
105
106 class command(_funcregistrarbase):
106 class command(_funcregistrarbase):
107 """Decorator to register a command function to table
107 """Decorator to register a command function to table
108
108
109 This class receives a command table as its argument. The table should
109 This class receives a command table as its argument. The table should
110 be a dict.
110 be a dict.
111
111
112 The created object can be used as a decorator for adding commands to
112 The created object can be used as a decorator for adding commands to
113 that command table. This accepts multiple arguments to define a command.
113 that command table. This accepts multiple arguments to define a command.
114
114
115 The first argument is the command name (as bytes).
115 The first argument is the command name (as bytes).
116
116
117 The `options` keyword argument is an iterable of tuples defining command
117 The `options` keyword argument is an iterable of tuples defining command
118 arguments. See ``mercurial.fancyopts.fancyopts()`` for the format of each
118 arguments. See ``mercurial.fancyopts.fancyopts()`` for the format of each
119 tuple.
119 tuple.
120
120
121 The `synopsis` argument defines a short, one line summary of how to use the
121 The `synopsis` argument defines a short, one line summary of how to use the
122 command. This shows up in the help output.
122 command. This shows up in the help output.
123
123
124 There are three arguments that control what repository (if any) is found
124 There are three arguments that control what repository (if any) is found
125 and passed to the decorated function: `norepo`, `optionalrepo`, and
125 and passed to the decorated function: `norepo`, `optionalrepo`, and
126 `inferrepo`.
126 `inferrepo`.
127
127
128 The `norepo` argument defines whether the command does not require a
128 The `norepo` argument defines whether the command does not require a
129 local repository. Most commands operate against a repository, thus the
129 local repository. Most commands operate against a repository, thus the
130 default is False. When True, no repository will be passed.
130 default is False. When True, no repository will be passed.
131
131
132 The `optionalrepo` argument defines whether the command optionally requires
132 The `optionalrepo` argument defines whether the command optionally requires
133 a local repository. If no repository can be found, None will be passed
133 a local repository. If no repository can be found, None will be passed
134 to the decorated function.
134 to the decorated function.
135
135
136 The `inferrepo` argument defines whether to try to find a repository from
136 The `inferrepo` argument defines whether to try to find a repository from
137 the command line arguments. If True, arguments will be examined for
137 the command line arguments. If True, arguments will be examined for
138 potential repository locations. See ``findrepo()``. If a repository is
138 potential repository locations. See ``findrepo()``. If a repository is
139 found, it will be used and passed to the decorated function.
139 found, it will be used and passed to the decorated function.
140
140
141 There are three constants in the class which tells what type of the command
141 The `intents` argument defines a set of intended actions or capabilities
142 that is. That information will be helpful at various places. It will be also
142 the command is taking. These intents can be used to affect the construction
143 be used to decide what level of access the command has on hidden commits.
143 of the repository object passed to the command. For example, commands
144 The constants are:
144 declaring that they are read-only could receive a repository that doesn't
145 have any methods allowing repository mutation. Other intents could be used
146 to prevent the command from running if the requested intent could not be
147 fulfilled.
145
148
146 `unrecoverablewrite` is for those write commands which can't be recovered
149 The following intents are defined:
147 like push.
150
148 `recoverablewrite` is for write commands which can be recovered like commit.
151 readonly
149 `readonly` is for commands which are read only.
152 The command is read-only
150
153
151 The signature of the decorated function looks like this:
154 The signature of the decorated function looks like this:
152 def cmd(ui[, repo] [, <args>] [, <options>])
155 def cmd(ui[, repo] [, <args>] [, <options>])
153
156
154 `repo` is required if `norepo` is False.
157 `repo` is required if `norepo` is False.
155 `<args>` are positional args (or `*args`) arguments, of non-option
158 `<args>` are positional args (or `*args`) arguments, of non-option
156 arguments from the command line.
159 arguments from the command line.
157 `<options>` are keyword arguments (or `**options`) of option arguments
160 `<options>` are keyword arguments (or `**options`) of option arguments
158 from the command line.
161 from the command line.
159
162
160 See the WritingExtensions and MercurialApi documentation for more exhaustive
163 See the WritingExtensions and MercurialApi documentation for more exhaustive
161 descriptions and examples.
164 descriptions and examples.
162 """
165 """
163
166
164 unrecoverablewrite = "unrecoverable"
165 recoverablewrite = "recoverable"
166 readonly = "readonly"
167
168 possiblecmdtypes = {unrecoverablewrite, recoverablewrite, readonly}
169
170 def _doregister(self, func, name, options=(), synopsis=None,
167 def _doregister(self, func, name, options=(), synopsis=None,
171 norepo=False, optionalrepo=False, inferrepo=False,
168 norepo=False, optionalrepo=False, inferrepo=False,
172 cmdtype=unrecoverablewrite):
169 intents=None):
173
170
174 if cmdtype not in self.possiblecmdtypes:
175 raise error.ProgrammingError("unknown cmdtype value '%s' for "
176 "'%s' command" % (cmdtype, name))
177 func.norepo = norepo
171 func.norepo = norepo
178 func.optionalrepo = optionalrepo
172 func.optionalrepo = optionalrepo
179 func.inferrepo = inferrepo
173 func.inferrepo = inferrepo
180 func.cmdtype = cmdtype
174 func.intents = intents or set()
181 if synopsis:
175 if synopsis:
182 self._table[name] = func, list(options), synopsis
176 self._table[name] = func, list(options), synopsis
183 else:
177 else:
184 self._table[name] = func, list(options)
178 self._table[name] = func, list(options)
185 return func
179 return func
186
180
181 INTENT_READONLY = b'readonly'
182
187 class revsetpredicate(_funcregistrarbase):
183 class revsetpredicate(_funcregistrarbase):
188 """Decorator to register revset predicate
184 """Decorator to register revset predicate
189
185
190 Usage::
186 Usage::
191
187
192 revsetpredicate = registrar.revsetpredicate()
188 revsetpredicate = registrar.revsetpredicate()
193
189
194 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
190 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
195 def mypredicatefunc(repo, subset, x):
191 def mypredicatefunc(repo, subset, x):
196 '''Explanation of this revset predicate ....
192 '''Explanation of this revset predicate ....
197 '''
193 '''
198 pass
194 pass
199
195
200 The first string argument is used also in online help.
196 The first string argument is used also in online help.
201
197
202 Optional argument 'safe' indicates whether a predicate is safe for
198 Optional argument 'safe' indicates whether a predicate is safe for
203 DoS attack (False by default).
199 DoS attack (False by default).
204
200
205 Optional argument 'takeorder' indicates whether a predicate function
201 Optional argument 'takeorder' indicates whether a predicate function
206 takes ordering policy as the last argument.
202 takes ordering policy as the last argument.
207
203
208 Optional argument 'weight' indicates the estimated run-time cost, useful
204 Optional argument 'weight' indicates the estimated run-time cost, useful
209 for static optimization, default is 1. Higher weight means more expensive.
205 for static optimization, default is 1. Higher weight means more expensive.
210 Usually, revsets that are fast and return only one revision has a weight of
206 Usually, revsets that are fast and return only one revision has a weight of
211 0.5 (ex. a symbol); revsets with O(changelog) complexity and read only the
207 0.5 (ex. a symbol); revsets with O(changelog) complexity and read only the
212 changelog have weight 10 (ex. author); revsets reading manifest deltas have
208 changelog have weight 10 (ex. author); revsets reading manifest deltas have
213 weight 30 (ex. adds); revset reading manifest contents have weight 100
209 weight 30 (ex. adds); revset reading manifest contents have weight 100
214 (ex. contains). Note: those values are flexible. If the revset has a
210 (ex. contains). Note: those values are flexible. If the revset has a
215 same big-O time complexity as 'contains', but with a smaller constant, it
211 same big-O time complexity as 'contains', but with a smaller constant, it
216 might have a weight of 90.
212 might have a weight of 90.
217
213
218 'revsetpredicate' instance in example above can be used to
214 'revsetpredicate' instance in example above can be used to
219 decorate multiple functions.
215 decorate multiple functions.
220
216
221 Decorated functions are registered automatically at loading
217 Decorated functions are registered automatically at loading
222 extension, if an instance named as 'revsetpredicate' is used for
218 extension, if an instance named as 'revsetpredicate' is used for
223 decorating in extension.
219 decorating in extension.
224
220
225 Otherwise, explicit 'revset.loadpredicate()' is needed.
221 Otherwise, explicit 'revset.loadpredicate()' is needed.
226 """
222 """
227 _getname = _funcregistrarbase._parsefuncdecl
223 _getname = _funcregistrarbase._parsefuncdecl
228 _docformat = "``%s``\n %s"
224 _docformat = "``%s``\n %s"
229
225
230 def _extrasetup(self, name, func, safe=False, takeorder=False, weight=1):
226 def _extrasetup(self, name, func, safe=False, takeorder=False, weight=1):
231 func._safe = safe
227 func._safe = safe
232 func._takeorder = takeorder
228 func._takeorder = takeorder
233 func._weight = weight
229 func._weight = weight
234
230
235 class filesetpredicate(_funcregistrarbase):
231 class filesetpredicate(_funcregistrarbase):
236 """Decorator to register fileset predicate
232 """Decorator to register fileset predicate
237
233
238 Usage::
234 Usage::
239
235
240 filesetpredicate = registrar.filesetpredicate()
236 filesetpredicate = registrar.filesetpredicate()
241
237
242 @filesetpredicate('mypredicate()')
238 @filesetpredicate('mypredicate()')
243 def mypredicatefunc(mctx, x):
239 def mypredicatefunc(mctx, x):
244 '''Explanation of this fileset predicate ....
240 '''Explanation of this fileset predicate ....
245 '''
241 '''
246 pass
242 pass
247
243
248 The first string argument is used also in online help.
244 The first string argument is used also in online help.
249
245
250 Optional argument 'callstatus' indicates whether a predicate
246 Optional argument 'callstatus' indicates whether a predicate
251 implies 'matchctx.status()' at runtime or not (False, by
247 implies 'matchctx.status()' at runtime or not (False, by
252 default).
248 default).
253
249
254 Optional argument 'callexisting' indicates whether a predicate
250 Optional argument 'callexisting' indicates whether a predicate
255 implies 'matchctx.existing()' at runtime or not (False, by
251 implies 'matchctx.existing()' at runtime or not (False, by
256 default).
252 default).
257
253
258 'filesetpredicate' instance in example above can be used to
254 'filesetpredicate' instance in example above can be used to
259 decorate multiple functions.
255 decorate multiple functions.
260
256
261 Decorated functions are registered automatically at loading
257 Decorated functions are registered automatically at loading
262 extension, if an instance named as 'filesetpredicate' is used for
258 extension, if an instance named as 'filesetpredicate' is used for
263 decorating in extension.
259 decorating in extension.
264
260
265 Otherwise, explicit 'fileset.loadpredicate()' is needed.
261 Otherwise, explicit 'fileset.loadpredicate()' is needed.
266 """
262 """
267 _getname = _funcregistrarbase._parsefuncdecl
263 _getname = _funcregistrarbase._parsefuncdecl
268 _docformat = "``%s``\n %s"
264 _docformat = "``%s``\n %s"
269
265
270 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
266 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
271 func._callstatus = callstatus
267 func._callstatus = callstatus
272 func._callexisting = callexisting
268 func._callexisting = callexisting
273
269
274 class _templateregistrarbase(_funcregistrarbase):
270 class _templateregistrarbase(_funcregistrarbase):
275 """Base of decorator to register functions as template specific one
271 """Base of decorator to register functions as template specific one
276 """
272 """
277 _docformat = ":%s: %s"
273 _docformat = ":%s: %s"
278
274
279 class templatekeyword(_templateregistrarbase):
275 class templatekeyword(_templateregistrarbase):
280 """Decorator to register template keyword
276 """Decorator to register template keyword
281
277
282 Usage::
278 Usage::
283
279
284 templatekeyword = registrar.templatekeyword()
280 templatekeyword = registrar.templatekeyword()
285
281
286 # new API (since Mercurial 4.6)
282 # new API (since Mercurial 4.6)
287 @templatekeyword('mykeyword', requires={'repo', 'ctx'})
283 @templatekeyword('mykeyword', requires={'repo', 'ctx'})
288 def mykeywordfunc(context, mapping):
284 def mykeywordfunc(context, mapping):
289 '''Explanation of this template keyword ....
285 '''Explanation of this template keyword ....
290 '''
286 '''
291 pass
287 pass
292
288
293 # old API
289 # old API
294 @templatekeyword('mykeyword')
290 @templatekeyword('mykeyword')
295 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
291 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
296 '''Explanation of this template keyword ....
292 '''Explanation of this template keyword ....
297 '''
293 '''
298 pass
294 pass
299
295
300 The first string argument is used also in online help.
296 The first string argument is used also in online help.
301
297
302 Optional argument 'requires' should be a collection of resource names
298 Optional argument 'requires' should be a collection of resource names
303 which the template keyword depends on. This also serves as a flag to
299 which the template keyword depends on. This also serves as a flag to
304 switch to the new API. If 'requires' is unspecified, all template
300 switch to the new API. If 'requires' is unspecified, all template
305 keywords and resources are expanded to the function arguments.
301 keywords and resources are expanded to the function arguments.
306
302
307 'templatekeyword' instance in example above can be used to
303 'templatekeyword' instance in example above can be used to
308 decorate multiple functions.
304 decorate multiple functions.
309
305
310 Decorated functions are registered automatically at loading
306 Decorated functions are registered automatically at loading
311 extension, if an instance named as 'templatekeyword' is used for
307 extension, if an instance named as 'templatekeyword' is used for
312 decorating in extension.
308 decorating in extension.
313
309
314 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
310 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
315 """
311 """
316
312
317 def _extrasetup(self, name, func, requires=None):
313 def _extrasetup(self, name, func, requires=None):
318 func._requires = requires
314 func._requires = requires
319
315
320 class templatefilter(_templateregistrarbase):
316 class templatefilter(_templateregistrarbase):
321 """Decorator to register template filer
317 """Decorator to register template filer
322
318
323 Usage::
319 Usage::
324
320
325 templatefilter = registrar.templatefilter()
321 templatefilter = registrar.templatefilter()
326
322
327 @templatefilter('myfilter', intype=bytes)
323 @templatefilter('myfilter', intype=bytes)
328 def myfilterfunc(text):
324 def myfilterfunc(text):
329 '''Explanation of this template filter ....
325 '''Explanation of this template filter ....
330 '''
326 '''
331 pass
327 pass
332
328
333 The first string argument is used also in online help.
329 The first string argument is used also in online help.
334
330
335 Optional argument 'intype' defines the type of the input argument,
331 Optional argument 'intype' defines the type of the input argument,
336 which should be (bytes, int, templateutil.date, or None for any.)
332 which should be (bytes, int, templateutil.date, or None for any.)
337
333
338 'templatefilter' instance in example above can be used to
334 'templatefilter' instance in example above can be used to
339 decorate multiple functions.
335 decorate multiple functions.
340
336
341 Decorated functions are registered automatically at loading
337 Decorated functions are registered automatically at loading
342 extension, if an instance named as 'templatefilter' is used for
338 extension, if an instance named as 'templatefilter' is used for
343 decorating in extension.
339 decorating in extension.
344
340
345 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
341 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
346 """
342 """
347
343
348 def _extrasetup(self, name, func, intype=None):
344 def _extrasetup(self, name, func, intype=None):
349 func._intype = intype
345 func._intype = intype
350
346
351 class templatefunc(_templateregistrarbase):
347 class templatefunc(_templateregistrarbase):
352 """Decorator to register template function
348 """Decorator to register template function
353
349
354 Usage::
350 Usage::
355
351
356 templatefunc = registrar.templatefunc()
352 templatefunc = registrar.templatefunc()
357
353
358 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3')
354 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3')
359 def myfuncfunc(context, mapping, args):
355 def myfuncfunc(context, mapping, args):
360 '''Explanation of this template function ....
356 '''Explanation of this template function ....
361 '''
357 '''
362 pass
358 pass
363
359
364 The first string argument is used also in online help.
360 The first string argument is used also in online help.
365
361
366 If optional 'argspec' is defined, the function will receive 'args' as
362 If optional 'argspec' is defined, the function will receive 'args' as
367 a dict of named arguments. Otherwise 'args' is a list of positional
363 a dict of named arguments. Otherwise 'args' is a list of positional
368 arguments.
364 arguments.
369
365
370 'templatefunc' instance in example above can be used to
366 'templatefunc' instance in example above can be used to
371 decorate multiple functions.
367 decorate multiple functions.
372
368
373 Decorated functions are registered automatically at loading
369 Decorated functions are registered automatically at loading
374 extension, if an instance named as 'templatefunc' is used for
370 extension, if an instance named as 'templatefunc' is used for
375 decorating in extension.
371 decorating in extension.
376
372
377 Otherwise, explicit 'templatefuncs.loadfunction()' is needed.
373 Otherwise, explicit 'templatefuncs.loadfunction()' is needed.
378 """
374 """
379 _getname = _funcregistrarbase._parsefuncdecl
375 _getname = _funcregistrarbase._parsefuncdecl
380
376
381 def _extrasetup(self, name, func, argspec=None):
377 def _extrasetup(self, name, func, argspec=None):
382 func._argspec = argspec
378 func._argspec = argspec
383
379
384 class internalmerge(_funcregistrarbase):
380 class internalmerge(_funcregistrarbase):
385 """Decorator to register in-process merge tool
381 """Decorator to register in-process merge tool
386
382
387 Usage::
383 Usage::
388
384
389 internalmerge = registrar.internalmerge()
385 internalmerge = registrar.internalmerge()
390
386
391 @internalmerge('mymerge', internalmerge.mergeonly,
387 @internalmerge('mymerge', internalmerge.mergeonly,
392 onfailure=None, precheck=None):
388 onfailure=None, precheck=None):
393 def mymergefunc(repo, mynode, orig, fcd, fco, fca,
389 def mymergefunc(repo, mynode, orig, fcd, fco, fca,
394 toolconf, files, labels=None):
390 toolconf, files, labels=None):
395 '''Explanation of this internal merge tool ....
391 '''Explanation of this internal merge tool ....
396 '''
392 '''
397 return 1, False # means "conflicted", "no deletion needed"
393 return 1, False # means "conflicted", "no deletion needed"
398
394
399 The first string argument is used to compose actual merge tool name,
395 The first string argument is used to compose actual merge tool name,
400 ":name" and "internal:name" (the latter is historical one).
396 ":name" and "internal:name" (the latter is historical one).
401
397
402 The second argument is one of merge types below:
398 The second argument is one of merge types below:
403
399
404 ========== ======== ======== =========
400 ========== ======== ======== =========
405 merge type precheck premerge fullmerge
401 merge type precheck premerge fullmerge
406 ========== ======== ======== =========
402 ========== ======== ======== =========
407 nomerge x x x
403 nomerge x x x
408 mergeonly o x o
404 mergeonly o x o
409 fullmerge o o o
405 fullmerge o o o
410 ========== ======== ======== =========
406 ========== ======== ======== =========
411
407
412 Optional argument 'onfailure' is the format of warning message
408 Optional argument 'onfailure' is the format of warning message
413 to be used at failure of merging (target filename is specified
409 to be used at failure of merging (target filename is specified
414 at formatting). Or, None or so, if warning message should be
410 at formatting). Or, None or so, if warning message should be
415 suppressed.
411 suppressed.
416
412
417 Optional argument 'precheck' is the function to be used
413 Optional argument 'precheck' is the function to be used
418 before actual invocation of internal merge tool itself.
414 before actual invocation of internal merge tool itself.
419 It takes as same arguments as internal merge tool does, other than
415 It takes as same arguments as internal merge tool does, other than
420 'files' and 'labels'. If it returns false value, merging is aborted
416 'files' and 'labels'. If it returns false value, merging is aborted
421 immediately (and file is marked as "unresolved").
417 immediately (and file is marked as "unresolved").
422
418
423 'internalmerge' instance in example above can be used to
419 'internalmerge' instance in example above can be used to
424 decorate multiple functions.
420 decorate multiple functions.
425
421
426 Decorated functions are registered automatically at loading
422 Decorated functions are registered automatically at loading
427 extension, if an instance named as 'internalmerge' is used for
423 extension, if an instance named as 'internalmerge' is used for
428 decorating in extension.
424 decorating in extension.
429
425
430 Otherwise, explicit 'filemerge.loadinternalmerge()' is needed.
426 Otherwise, explicit 'filemerge.loadinternalmerge()' is needed.
431 """
427 """
432 _docformat = "``:%s``\n %s"
428 _docformat = "``:%s``\n %s"
433
429
434 # merge type definitions:
430 # merge type definitions:
435 nomerge = None
431 nomerge = None
436 mergeonly = 'mergeonly' # just the full merge, no premerge
432 mergeonly = 'mergeonly' # just the full merge, no premerge
437 fullmerge = 'fullmerge' # both premerge and merge
433 fullmerge = 'fullmerge' # both premerge and merge
438
434
439 def _extrasetup(self, name, func, mergetype,
435 def _extrasetup(self, name, func, mergetype,
440 onfailure=None, precheck=None):
436 onfailure=None, precheck=None):
441 func.mergetype = mergetype
437 func.mergetype = mergetype
442 func.onfailure = onfailure
438 func.onfailure = onfailure
443 func.precheck = precheck
439 func.precheck = precheck
@@ -1,214 +1,214 b''
1 Tests for access level on hidden commits by various commands on based of their
1 Tests for access level on hidden commits by various commands on based of their
2 type.
2 type.
3
3
4 Setting the required config to start this
4 Setting the required config to start this
5
5
6 $ cat >> $HGRCPATH <<EOF
6 $ cat >> $HGRCPATH <<EOF
7 > [experimental]
7 > [experimental]
8 > evolution=createmarkers, allowunstable
8 > evolution=createmarkers, allowunstable
9 > directaccess=True
9 > directaccess=True
10 > directaccess.revnums=True
10 > directaccess.revnums=True
11 > [extensions]
11 > [extensions]
12 > amend =
12 > amend =
13 > EOF
13 > EOF
14
14
15 $ hg init repo
15 $ hg init repo
16 $ cd repo
16 $ cd repo
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
18
18
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
21 |
21 |
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
23 |
23 |
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
25
25
26 $ echo "bar" >> c
26 $ echo "bar" >> c
27 $ hg amend
27 $ hg amend
28
28
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
31 |
31 |
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
33 |/
33 |/
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
35 |
35 |
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
37
37
38 Testing read only commands on the hidden revision
38 Testing read only commands on the hidden revision
39
39
40 Testing with rev number
40 Testing with rev number
41
41
42 $ hg exp 2 --config experimental.directaccess.revnums=False
42 $ hg exp 2 --config experimental.directaccess.revnums=False
43 abort: hidden revision '2' was rewritten as: 2443a0e66469!
43 abort: hidden revision '2' was rewritten as: 2443a0e66469!
44 (use --hidden to access hidden revisions)
44 (use --hidden to access hidden revisions)
45 [255]
45 [255]
46
46
47 $ hg exp 2
47 $ hg exp 2
48 # HG changeset patch
48 # HG changeset patch
49 # User test
49 # User test
50 # Date 0 0
50 # Date 0 0
51 # Thu Jan 01 00:00:00 1970 +0000
51 # Thu Jan 01 00:00:00 1970 +0000
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
54 Added c
54 Added c
55
55
56 diff -r 29becc82797a -r 28ad74487de9 c
56 diff -r 29becc82797a -r 28ad74487de9 c
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
59 @@ -0,0 +1,1 @@
59 @@ -0,0 +1,1 @@
60 +foo
60 +foo
61
61
62 $ hg log -r 2
62 $ hg log -r 2
63 changeset: 2:28ad74487de9
63 changeset: 2:28ad74487de9
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:00 1970 +0000
65 date: Thu Jan 01 00:00:00 1970 +0000
66 obsolete: rewritten using amend as 3:2443a0e66469
66 obsolete: rewritten using amend as 3:2443a0e66469
67 summary: Added c
67 summary: Added c
68
68
69 $ hg identify -r 2
69 $ hg identify -r 2
70 28ad74487de9
70 28ad74487de9
71
71
72 $ hg status --change 2
72 $ hg status --change 2
73 A c
73 A c
74
74
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
76 abort: hidden revision '2' was rewritten as: 2443a0e66469!
76 abort: hidden revision '2' was rewritten as: 2443a0e66469!
77 (use --hidden to access hidden revisions)
77 (use --hidden to access hidden revisions)
78 [255]
78 [255]
79
79
80 $ hg diff -c 2
80 $ hg diff -c 2
81 diff -r 29becc82797a -r 28ad74487de9 c
81 diff -r 29becc82797a -r 28ad74487de9 c
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
84 @@ -0,0 +1,1 @@
84 @@ -0,0 +1,1 @@
85 +foo
85 +foo
86
86
87 Testing with hash
87 Testing with hash
88
88
89 `hg export`
89 `hg export`
90
90
91 $ hg exp 28ad74
91 $ hg exp 28ad74
92 # HG changeset patch
92 # HG changeset patch
93 # User test
93 # User test
94 # Date 0 0
94 # Date 0 0
95 # Thu Jan 01 00:00:00 1970 +0000
95 # Thu Jan 01 00:00:00 1970 +0000
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
98 Added c
98 Added c
99
99
100 diff -r 29becc82797a -r 28ad74487de9 c
100 diff -r 29becc82797a -r 28ad74487de9 c
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
103 @@ -0,0 +1,1 @@
103 @@ -0,0 +1,1 @@
104 +foo
104 +foo
105
105
106 `hg log`
106 `hg log`
107
107
108 $ hg log -r 28ad74
108 $ hg log -r 28ad74
109 changeset: 2:28ad74487de9
109 changeset: 2:28ad74487de9
110 user: test
110 user: test
111 date: Thu Jan 01 00:00:00 1970 +0000
111 date: Thu Jan 01 00:00:00 1970 +0000
112 obsolete: rewritten using amend as 3:2443a0e66469
112 obsolete: rewritten using amend as 3:2443a0e66469
113 summary: Added c
113 summary: Added c
114
114
115 `hg cat`
115 `hg cat`
116
116
117 $ hg cat -r 28ad74 c
117 $ hg cat -r 28ad74 c
118 foo
118 foo
119
119
120 `hg diff`
120 `hg diff`
121
121
122 $ hg diff -c 28ad74
122 $ hg diff -c 28ad74
123 diff -r 29becc82797a -r 28ad74487de9 c
123 diff -r 29becc82797a -r 28ad74487de9 c
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
126 @@ -0,0 +1,1 @@
126 @@ -0,0 +1,1 @@
127 +foo
127 +foo
128
128
129 `hg files`
129 `hg files`
130
130
131 $ hg files -r 28ad74
131 $ hg files -r 28ad74
132 a
132 a
133 b
133 b
134 c
134 c
135
135
136 `hg identify`
136 `hg identify`
137
137
138 $ hg identify -r 28ad74
138 $ hg identify -r 28ad74
139 28ad74487de9
139 28ad74487de9
140
140
141 `hg annotate`
141 `hg annotate`
142
142
143 $ hg annotate -r 28ad74 a
143 $ hg annotate -r 28ad74 a
144 0: foo
144 0: foo
145
145
146 `hg status`
146 `hg status`
147
147
148 $ hg status --change 28ad74
148 $ hg status --change 28ad74
149 A c
149 A c
150
150
151 `hg archive`
151 `hg archive`
152
152
153 This should not throw error
153 This should not throw error
154 $ hg archive -r 28ad74 foo
154 $ hg archive -r 28ad74 foo
155
155
156 `hg update`
156 `hg update`
157
157
158 $ hg up 28ad74
158 $ hg up 28ad74
159 updating to a hidden changeset 28ad74487de9
159 updating to a hidden changeset 28ad74487de9
160 (hidden revision '28ad74487de9' was rewritten as: 2443a0e66469)
160 (hidden revision '28ad74487de9' was rewritten as: 2443a0e66469)
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162
162
163 $ hg up 3
163 $ hg up 3
164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165
165
166 $ hg up
166 $ hg up
167 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
168
168
169 `hg revert`
169 `hg revert`
170
170
171 $ hg revert -r 28ad74 --all
171 $ hg revert -r 28ad74 --all
172 reverting c
172 reverting c
173
173
174 $ hg diff
174 $ hg diff
175 diff -r 2443a0e66469 c
175 diff -r 2443a0e66469 c
176 --- a/c Thu Jan 01 00:00:00 1970 +0000
176 --- a/c Thu Jan 01 00:00:00 1970 +0000
177 +++ b/c Thu Jan 01 00:00:00 1970 +0000
177 +++ b/c Thu Jan 01 00:00:00 1970 +0000
178 @@ -1,2 +1,1 @@
178 @@ -1,2 +1,1 @@
179 foo
179 foo
180 -bar
180 -bar
181
181
182 Test special hash/rev
182 Test special hash/rev
183
183
184 $ hg log -qr 'null:wdir() & 000000000000'
184 $ hg log -qr 'null:wdir() & 000000000000'
185 -1:000000000000
185 -1:000000000000
186 $ hg log -qr 'null:wdir() & ffffffffffff'
186 $ hg log -qr 'null:wdir() & ffffffffffff'
187 2147483647:ffffffffffff
187 2147483647:ffffffffffff
188 $ hg log -qr 'null:wdir() & rev(-1)'
188 $ hg log -qr 'null:wdir() & rev(-1)'
189 -1:000000000000
189 -1:000000000000
190 $ hg log -qr 'null:wdir() & rev(2147483647)'
190 $ hg log -qr 'null:wdir() & rev(2147483647)'
191 2147483647:ffffffffffff
191 2147483647:ffffffffffff
192 $ hg log -qr 'null:wdir() & 2147483647'
192 $ hg log -qr 'null:wdir() & 2147483647'
193 2147483647:ffffffffffff
193 2147483647:ffffffffffff
194
194
195 Commands with undefined cmdtype should not work right now
195 Commands with undefined intent should not work right now
196
196
197 $ hg phase -r 28ad74
197 $ hg phase -r 28ad74
198 abort: hidden revision '28ad74' was rewritten as: 2443a0e66469!
198 abort: hidden revision '28ad74' was rewritten as: 2443a0e66469!
199 (use --hidden to access hidden revisions)
199 (use --hidden to access hidden revisions)
200 [255]
200 [255]
201
201
202 $ hg phase -r 2
202 $ hg phase -r 2
203 abort: hidden revision '2' was rewritten as: 2443a0e66469!
203 abort: hidden revision '2' was rewritten as: 2443a0e66469!
204 (use --hidden to access hidden revisions)
204 (use --hidden to access hidden revisions)
205 [255]
205 [255]
206
206
207 Setting a bookmark will make that changeset unhidden, so this should come in end
207 Setting a bookmark will make that changeset unhidden, so this should come in end
208
208
209 $ hg bookmarks -r 28ad74 book
209 $ hg bookmarks -r 28ad74 book
210 bookmarking hidden changeset 28ad74487de9
210 bookmarking hidden changeset 28ad74487de9
211 (hidden revision '28ad74487de9' was rewritten as: 2443a0e66469)
211 (hidden revision '28ad74487de9' was rewritten as: 2443a0e66469)
212
212
213 $ hg bookmarks
213 $ hg bookmarks
214 book 2:28ad74487de9
214 book 2:28ad74487de9
General Comments 0
You need to be logged in to leave comments. Login now