##// END OF EJS Templates
narrow: intersect provided matcher with narrowmatcher in `hg diff`...
spectral -
r39918:ee7ee0c5 default
parent child Browse files
Show More
@@ -1,5912 +1,5914 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 filemerge,
38 filemerge,
39 formatter,
39 formatter,
40 graphmod,
40 graphmod,
41 hbisect,
41 hbisect,
42 help,
42 help,
43 hg,
43 hg,
44 logcmdutil,
44 logcmdutil,
45 match as matchmod,
45 merge as mergemod,
46 merge as mergemod,
46 narrowspec,
47 narrowspec,
47 obsolete,
48 obsolete,
48 obsutil,
49 obsutil,
49 patch,
50 patch,
50 phases,
51 phases,
51 pycompat,
52 pycompat,
52 rcutil,
53 rcutil,
53 registrar,
54 registrar,
54 repair,
55 repair,
55 revsetlang,
56 revsetlang,
56 rewriteutil,
57 rewriteutil,
57 scmutil,
58 scmutil,
58 server,
59 server,
59 state as statemod,
60 state as statemod,
60 streamclone,
61 streamclone,
61 tags as tagsmod,
62 tags as tagsmod,
62 templatekw,
63 templatekw,
63 ui as uimod,
64 ui as uimod,
64 util,
65 util,
65 wireprotoserver,
66 wireprotoserver,
66 )
67 )
67 from .utils import (
68 from .utils import (
68 dateutil,
69 dateutil,
69 stringutil,
70 stringutil,
70 )
71 )
71
72
72 table = {}
73 table = {}
73 table.update(debugcommandsmod.command._table)
74 table.update(debugcommandsmod.command._table)
74
75
75 command = registrar.command(table)
76 command = registrar.command(table)
76 INTENT_READONLY = registrar.INTENT_READONLY
77 INTENT_READONLY = registrar.INTENT_READONLY
77
78
78 # common command options
79 # common command options
79
80
80 globalopts = [
81 globalopts = [
81 ('R', 'repository', '',
82 ('R', 'repository', '',
82 _('repository root directory or name of overlay bundle file'),
83 _('repository root directory or name of overlay bundle file'),
83 _('REPO')),
84 _('REPO')),
84 ('', 'cwd', '',
85 ('', 'cwd', '',
85 _('change working directory'), _('DIR')),
86 _('change working directory'), _('DIR')),
86 ('y', 'noninteractive', None,
87 ('y', 'noninteractive', None,
87 _('do not prompt, automatically pick the first choice for all prompts')),
88 _('do not prompt, automatically pick the first choice for all prompts')),
88 ('q', 'quiet', None, _('suppress output')),
89 ('q', 'quiet', None, _('suppress output')),
89 ('v', 'verbose', None, _('enable additional output')),
90 ('v', 'verbose', None, _('enable additional output')),
90 ('', 'color', '',
91 ('', 'color', '',
91 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
92 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
92 # and should not be translated
93 # and should not be translated
93 _("when to colorize (boolean, always, auto, never, or debug)"),
94 _("when to colorize (boolean, always, auto, never, or debug)"),
94 _('TYPE')),
95 _('TYPE')),
95 ('', 'config', [],
96 ('', 'config', [],
96 _('set/override config option (use \'section.name=value\')'),
97 _('set/override config option (use \'section.name=value\')'),
97 _('CONFIG')),
98 _('CONFIG')),
98 ('', 'debug', None, _('enable debugging output')),
99 ('', 'debug', None, _('enable debugging output')),
99 ('', 'debugger', None, _('start debugger')),
100 ('', 'debugger', None, _('start debugger')),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
101 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
101 _('ENCODE')),
102 _('ENCODE')),
102 ('', 'encodingmode', encoding.encodingmode,
103 ('', 'encodingmode', encoding.encodingmode,
103 _('set the charset encoding mode'), _('MODE')),
104 _('set the charset encoding mode'), _('MODE')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
105 ('', 'traceback', None, _('always print a traceback on exception')),
105 ('', 'time', None, _('time how long the command takes')),
106 ('', 'time', None, _('time how long the command takes')),
106 ('', 'profile', None, _('print command execution profile')),
107 ('', 'profile', None, _('print command execution profile')),
107 ('', 'version', None, _('output version information and exit')),
108 ('', 'version', None, _('output version information and exit')),
108 ('h', 'help', None, _('display help and exit')),
109 ('h', 'help', None, _('display help and exit')),
109 ('', 'hidden', False, _('consider hidden changesets')),
110 ('', 'hidden', False, _('consider hidden changesets')),
110 ('', 'pager', 'auto',
111 ('', 'pager', 'auto',
111 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
112 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
112 ]
113 ]
113
114
114 dryrunopts = cmdutil.dryrunopts
115 dryrunopts = cmdutil.dryrunopts
115 remoteopts = cmdutil.remoteopts
116 remoteopts = cmdutil.remoteopts
116 walkopts = cmdutil.walkopts
117 walkopts = cmdutil.walkopts
117 commitopts = cmdutil.commitopts
118 commitopts = cmdutil.commitopts
118 commitopts2 = cmdutil.commitopts2
119 commitopts2 = cmdutil.commitopts2
119 formatteropts = cmdutil.formatteropts
120 formatteropts = cmdutil.formatteropts
120 templateopts = cmdutil.templateopts
121 templateopts = cmdutil.templateopts
121 logopts = cmdutil.logopts
122 logopts = cmdutil.logopts
122 diffopts = cmdutil.diffopts
123 diffopts = cmdutil.diffopts
123 diffwsopts = cmdutil.diffwsopts
124 diffwsopts = cmdutil.diffwsopts
124 diffopts2 = cmdutil.diffopts2
125 diffopts2 = cmdutil.diffopts2
125 mergetoolopts = cmdutil.mergetoolopts
126 mergetoolopts = cmdutil.mergetoolopts
126 similarityopts = cmdutil.similarityopts
127 similarityopts = cmdutil.similarityopts
127 subrepoopts = cmdutil.subrepoopts
128 subrepoopts = cmdutil.subrepoopts
128 debugrevlogopts = cmdutil.debugrevlogopts
129 debugrevlogopts = cmdutil.debugrevlogopts
129
130
130 # Commands start here, listed alphabetically
131 # Commands start here, listed alphabetically
131
132
132 @command('^add',
133 @command('^add',
133 walkopts + subrepoopts + dryrunopts,
134 walkopts + subrepoopts + dryrunopts,
134 _('[OPTION]... [FILE]...'),
135 _('[OPTION]... [FILE]...'),
135 inferrepo=True)
136 inferrepo=True)
136 def add(ui, repo, *pats, **opts):
137 def add(ui, repo, *pats, **opts):
137 """add the specified files on the next commit
138 """add the specified files on the next commit
138
139
139 Schedule files to be version controlled and added to the
140 Schedule files to be version controlled and added to the
140 repository.
141 repository.
141
142
142 The files will be added to the repository at the next commit. To
143 The files will be added to the repository at the next commit. To
143 undo an add before that, see :hg:`forget`.
144 undo an add before that, see :hg:`forget`.
144
145
145 If no names are given, add all files to the repository (except
146 If no names are given, add all files to the repository (except
146 files matching ``.hgignore``).
147 files matching ``.hgignore``).
147
148
148 .. container:: verbose
149 .. container:: verbose
149
150
150 Examples:
151 Examples:
151
152
152 - New (unknown) files are added
153 - New (unknown) files are added
153 automatically by :hg:`add`::
154 automatically by :hg:`add`::
154
155
155 $ ls
156 $ ls
156 foo.c
157 foo.c
157 $ hg status
158 $ hg status
158 ? foo.c
159 ? foo.c
159 $ hg add
160 $ hg add
160 adding foo.c
161 adding foo.c
161 $ hg status
162 $ hg status
162 A foo.c
163 A foo.c
163
164
164 - Specific files to be added can be specified::
165 - Specific files to be added can be specified::
165
166
166 $ ls
167 $ ls
167 bar.c foo.c
168 bar.c foo.c
168 $ hg status
169 $ hg status
169 ? bar.c
170 ? bar.c
170 ? foo.c
171 ? foo.c
171 $ hg add bar.c
172 $ hg add bar.c
172 $ hg status
173 $ hg status
173 A bar.c
174 A bar.c
174 ? foo.c
175 ? foo.c
175
176
176 Returns 0 if all files are successfully added.
177 Returns 0 if all files are successfully added.
177 """
178 """
178
179
179 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
180 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
180 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
181 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
181 return rejected and 1 or 0
182 return rejected and 1 or 0
182
183
183 @command('addremove',
184 @command('addremove',
184 similarityopts + subrepoopts + walkopts + dryrunopts,
185 similarityopts + subrepoopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
186 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
187 inferrepo=True)
187 def addremove(ui, repo, *pats, **opts):
188 def addremove(ui, repo, *pats, **opts):
188 """add all new files, delete all missing files
189 """add all new files, delete all missing files
189
190
190 Add all new files and remove all missing files from the
191 Add all new files and remove all missing files from the
191 repository.
192 repository.
192
193
193 Unless names are given, new files are ignored if they match any of
194 Unless names are given, new files are ignored if they match any of
194 the patterns in ``.hgignore``. As with add, these changes take
195 the patterns in ``.hgignore``. As with add, these changes take
195 effect at the next commit.
196 effect at the next commit.
196
197
197 Use the -s/--similarity option to detect renamed files. This
198 Use the -s/--similarity option to detect renamed files. This
198 option takes a percentage between 0 (disabled) and 100 (files must
199 option takes a percentage between 0 (disabled) and 100 (files must
199 be identical) as its parameter. With a parameter greater than 0,
200 be identical) as its parameter. With a parameter greater than 0,
200 this compares every removed file with every added file and records
201 this compares every removed file with every added file and records
201 those similar enough as renames. Detecting renamed files this way
202 those similar enough as renames. Detecting renamed files this way
202 can be expensive. After using this option, :hg:`status -C` can be
203 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
204 used to check which files were identified as moved or renamed. If
204 not specified, -s/--similarity defaults to 100 and only renames of
205 not specified, -s/--similarity defaults to 100 and only renames of
205 identical files are detected.
206 identical files are detected.
206
207
207 .. container:: verbose
208 .. container:: verbose
208
209
209 Examples:
210 Examples:
210
211
211 - A number of files (bar.c and foo.c) are new,
212 - A number of files (bar.c and foo.c) are new,
212 while foobar.c has been removed (without using :hg:`remove`)
213 while foobar.c has been removed (without using :hg:`remove`)
213 from the repository::
214 from the repository::
214
215
215 $ ls
216 $ ls
216 bar.c foo.c
217 bar.c foo.c
217 $ hg status
218 $ hg status
218 ! foobar.c
219 ! foobar.c
219 ? bar.c
220 ? bar.c
220 ? foo.c
221 ? foo.c
221 $ hg addremove
222 $ hg addremove
222 adding bar.c
223 adding bar.c
223 adding foo.c
224 adding foo.c
224 removing foobar.c
225 removing foobar.c
225 $ hg status
226 $ hg status
226 A bar.c
227 A bar.c
227 A foo.c
228 A foo.c
228 R foobar.c
229 R foobar.c
229
230
230 - A file foobar.c was moved to foo.c without using :hg:`rename`.
231 - A file foobar.c was moved to foo.c without using :hg:`rename`.
231 Afterwards, it was edited slightly::
232 Afterwards, it was edited slightly::
232
233
233 $ ls
234 $ ls
234 foo.c
235 foo.c
235 $ hg status
236 $ hg status
236 ! foobar.c
237 ! foobar.c
237 ? foo.c
238 ? foo.c
238 $ hg addremove --similarity 90
239 $ hg addremove --similarity 90
239 removing foobar.c
240 removing foobar.c
240 adding foo.c
241 adding foo.c
241 recording removal of foobar.c as rename to foo.c (94% similar)
242 recording removal of foobar.c as rename to foo.c (94% similar)
242 $ hg status -C
243 $ hg status -C
243 A foo.c
244 A foo.c
244 foobar.c
245 foobar.c
245 R foobar.c
246 R foobar.c
246
247
247 Returns 0 if all files are successfully added.
248 Returns 0 if all files are successfully added.
248 """
249 """
249 opts = pycompat.byteskwargs(opts)
250 opts = pycompat.byteskwargs(opts)
250 if not opts.get('similarity'):
251 if not opts.get('similarity'):
251 opts['similarity'] = '100'
252 opts['similarity'] = '100'
252 matcher = scmutil.match(repo[None], pats, opts)
253 matcher = scmutil.match(repo[None], pats, opts)
253 return scmutil.addremove(repo, matcher, "", opts)
254 return scmutil.addremove(repo, matcher, "", opts)
254
255
255 @command('^annotate|blame',
256 @command('^annotate|blame',
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 ('', 'follow', None,
258 ('', 'follow', None,
258 _('follow copies/renames and list the filename (DEPRECATED)')),
259 _('follow copies/renames and list the filename (DEPRECATED)')),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('a', 'text', None, _('treat all files as text')),
261 ('a', 'text', None, _('treat all files as text')),
261 ('u', 'user', None, _('list the author (long with -v)')),
262 ('u', 'user', None, _('list the author (long with -v)')),
262 ('f', 'file', None, _('list the filename')),
263 ('f', 'file', None, _('list the filename')),
263 ('d', 'date', None, _('list the date (short with -q)')),
264 ('d', 'date', None, _('list the date (short with -q)')),
264 ('n', 'number', None, _('list the revision number (default)')),
265 ('n', 'number', None, _('list the revision number (default)')),
265 ('c', 'changeset', None, _('list the changeset')),
266 ('c', 'changeset', None, _('list the changeset')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ] + diffwsopts + walkopts + formatteropts,
269 ] + diffwsopts + walkopts + formatteropts,
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 inferrepo=True)
271 inferrepo=True)
271 def annotate(ui, repo, *pats, **opts):
272 def annotate(ui, repo, *pats, **opts):
272 """show changeset information by line for each file
273 """show changeset information by line for each file
273
274
274 List changes in files, showing the revision id responsible for
275 List changes in files, showing the revision id responsible for
275 each line.
276 each line.
276
277
277 This command is useful for discovering when a change was made and
278 This command is useful for discovering when a change was made and
278 by whom.
279 by whom.
279
280
280 If you include --file, --user, or --date, the revision number is
281 If you include --file, --user, or --date, the revision number is
281 suppressed unless you also include --number.
282 suppressed unless you also include --number.
282
283
283 Without the -a/--text option, annotate will avoid processing files
284 Without the -a/--text option, annotate will avoid processing files
284 it detects as binary. With -a, annotate will annotate the file
285 it detects as binary. With -a, annotate will annotate the file
285 anyway, although the results will probably be neither useful
286 anyway, although the results will probably be neither useful
286 nor desirable.
287 nor desirable.
287
288
288 Returns 0 on success.
289 Returns 0 on success.
289 """
290 """
290 opts = pycompat.byteskwargs(opts)
291 opts = pycompat.byteskwargs(opts)
291 if not pats:
292 if not pats:
292 raise error.Abort(_('at least one filename or pattern is required'))
293 raise error.Abort(_('at least one filename or pattern is required'))
293
294
294 if opts.get('follow'):
295 if opts.get('follow'):
295 # --follow is deprecated and now just an alias for -f/--file
296 # --follow is deprecated and now just an alias for -f/--file
296 # to mimic the behavior of Mercurial before version 1.5
297 # to mimic the behavior of Mercurial before version 1.5
297 opts['file'] = True
298 opts['file'] = True
298
299
299 rev = opts.get('rev')
300 rev = opts.get('rev')
300 if rev:
301 if rev:
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
302 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
302 ctx = scmutil.revsingle(repo, rev)
303 ctx = scmutil.revsingle(repo, rev)
303
304
304 rootfm = ui.formatter('annotate', opts)
305 rootfm = ui.formatter('annotate', opts)
305 if ui.quiet:
306 if ui.quiet:
306 datefunc = dateutil.shortdate
307 datefunc = dateutil.shortdate
307 else:
308 else:
308 datefunc = dateutil.datestr
309 datefunc = dateutil.datestr
309 if ctx.rev() is None:
310 if ctx.rev() is None:
310 def hexfn(node):
311 def hexfn(node):
311 if node is None:
312 if node is None:
312 return None
313 return None
313 else:
314 else:
314 return rootfm.hexfunc(node)
315 return rootfm.hexfunc(node)
315 if opts.get('changeset'):
316 if opts.get('changeset'):
316 # omit "+" suffix which is appended to node hex
317 # omit "+" suffix which is appended to node hex
317 def formatrev(rev):
318 def formatrev(rev):
318 if rev is None:
319 if rev is None:
319 return '%d' % ctx.p1().rev()
320 return '%d' % ctx.p1().rev()
320 else:
321 else:
321 return '%d' % rev
322 return '%d' % rev
322 else:
323 else:
323 def formatrev(rev):
324 def formatrev(rev):
324 if rev is None:
325 if rev is None:
325 return '%d+' % ctx.p1().rev()
326 return '%d+' % ctx.p1().rev()
326 else:
327 else:
327 return '%d ' % rev
328 return '%d ' % rev
328 def formathex(hex):
329 def formathex(hex):
329 if hex is None:
330 if hex is None:
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
331 return '%s+' % rootfm.hexfunc(ctx.p1().node())
331 else:
332 else:
332 return '%s ' % hex
333 return '%s ' % hex
333 else:
334 else:
334 hexfn = rootfm.hexfunc
335 hexfn = rootfm.hexfunc
335 formatrev = formathex = pycompat.bytestr
336 formatrev = formathex = pycompat.bytestr
336
337
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
338 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
338 ('rev', ' ', lambda x: x.fctx.rev(), formatrev),
339 ('rev', ' ', lambda x: x.fctx.rev(), formatrev),
339 ('node', ' ', lambda x: hexfn(x.fctx.node()), formathex),
340 ('node', ' ', lambda x: hexfn(x.fctx.node()), formathex),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
341 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
341 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
342 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
343 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
343 ]
344 ]
344 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
345 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
345
346
346 if (not opts.get('user') and not opts.get('changeset')
347 if (not opts.get('user') and not opts.get('changeset')
347 and not opts.get('date') and not opts.get('file')):
348 and not opts.get('date') and not opts.get('file')):
348 opts['number'] = True
349 opts['number'] = True
349
350
350 linenumber = opts.get('line_number') is not None
351 linenumber = opts.get('line_number') is not None
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
352 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'))
353 raise error.Abort(_('at least one of -n/-c is required for -l'))
353
354
354 ui.pager('annotate')
355 ui.pager('annotate')
355
356
356 if rootfm.isplain():
357 if rootfm.isplain():
357 def makefunc(get, fmt):
358 def makefunc(get, fmt):
358 return lambda x: fmt(get(x))
359 return lambda x: fmt(get(x))
359 else:
360 else:
360 def makefunc(get, fmt):
361 def makefunc(get, fmt):
361 return get
362 return get
362 datahint = rootfm.datahint()
363 datahint = rootfm.datahint()
363 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
364 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
364 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
365 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
365 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
366 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
366 fields = ' '.join(fn for fn, sep, get, fmt in opmap
367 fields = ' '.join(fn for fn, sep, get, fmt in opmap
367 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
368 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
368
369
369 def bad(x, y):
370 def bad(x, y):
370 raise error.Abort("%s: %s" % (x, y))
371 raise error.Abort("%s: %s" % (x, y))
371
372
372 m = scmutil.match(ctx, pats, opts, badfn=bad)
373 m = scmutil.match(ctx, pats, opts, badfn=bad)
373
374
374 follow = not opts.get('no_follow')
375 follow = not opts.get('no_follow')
375 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
376 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
376 whitespace=True)
377 whitespace=True)
377 skiprevs = opts.get('skip')
378 skiprevs = opts.get('skip')
378 if skiprevs:
379 if skiprevs:
379 skiprevs = scmutil.revrange(repo, skiprevs)
380 skiprevs = scmutil.revrange(repo, skiprevs)
380
381
381 for abs in ctx.walk(m):
382 for abs in ctx.walk(m):
382 fctx = ctx[abs]
383 fctx = ctx[abs]
383 rootfm.startitem()
384 rootfm.startitem()
384 rootfm.data(path=abs)
385 rootfm.data(path=abs)
385 if not opts.get('text') and fctx.isbinary():
386 if not opts.get('text') and fctx.isbinary():
386 rootfm.plain(_("%s: binary file\n")
387 rootfm.plain(_("%s: binary file\n")
387 % ((pats and m.rel(abs)) or abs))
388 % ((pats and m.rel(abs)) or abs))
388 continue
389 continue
389
390
390 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
391 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
391 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
392 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
392 diffopts=diffopts)
393 diffopts=diffopts)
393 if not lines:
394 if not lines:
394 fm.end()
395 fm.end()
395 continue
396 continue
396 formats = []
397 formats = []
397 pieces = []
398 pieces = []
398
399
399 for f, sep in funcmap:
400 for f, sep in funcmap:
400 l = [f(n) for n in lines]
401 l = [f(n) for n in lines]
401 if fm.isplain():
402 if fm.isplain():
402 sizes = [encoding.colwidth(x) for x in l]
403 sizes = [encoding.colwidth(x) for x in l]
403 ml = max(sizes)
404 ml = max(sizes)
404 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
405 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
405 else:
406 else:
406 formats.append(['%s' for x in l])
407 formats.append(['%s' for x in l])
407 pieces.append(l)
408 pieces.append(l)
408
409
409 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
410 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
410 fm.startitem()
411 fm.startitem()
411 fm.context(fctx=n.fctx)
412 fm.context(fctx=n.fctx)
412 fm.write(fields, "".join(f), *p)
413 fm.write(fields, "".join(f), *p)
413 if n.skip:
414 if n.skip:
414 fmt = "* %s"
415 fmt = "* %s"
415 else:
416 else:
416 fmt = ": %s"
417 fmt = ": %s"
417 fm.write('line', fmt, n.text)
418 fm.write('line', fmt, n.text)
418
419
419 if not lines[-1].text.endswith('\n'):
420 if not lines[-1].text.endswith('\n'):
420 fm.plain('\n')
421 fm.plain('\n')
421 fm.end()
422 fm.end()
422
423
423 rootfm.end()
424 rootfm.end()
424
425
425 @command('archive',
426 @command('archive',
426 [('', 'no-decode', None, _('do not pass files through decoders')),
427 [('', 'no-decode', None, _('do not pass files through decoders')),
427 ('p', 'prefix', '', _('directory prefix for files in archive'),
428 ('p', 'prefix', '', _('directory prefix for files in archive'),
428 _('PREFIX')),
429 _('PREFIX')),
429 ('r', 'rev', '', _('revision to distribute'), _('REV')),
430 ('r', 'rev', '', _('revision to distribute'), _('REV')),
430 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
431 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
431 ] + subrepoopts + walkopts,
432 ] + subrepoopts + walkopts,
432 _('[OPTION]... DEST'))
433 _('[OPTION]... DEST'))
433 def archive(ui, repo, dest, **opts):
434 def archive(ui, repo, dest, **opts):
434 '''create an unversioned archive of a repository revision
435 '''create an unversioned archive of a repository revision
435
436
436 By default, the revision used is the parent of the working
437 By default, the revision used is the parent of the working
437 directory; use -r/--rev to specify a different revision.
438 directory; use -r/--rev to specify a different revision.
438
439
439 The archive type is automatically detected based on file
440 The archive type is automatically detected based on file
440 extension (to override, use -t/--type).
441 extension (to override, use -t/--type).
441
442
442 .. container:: verbose
443 .. container:: verbose
443
444
444 Examples:
445 Examples:
445
446
446 - create a zip file containing the 1.0 release::
447 - create a zip file containing the 1.0 release::
447
448
448 hg archive -r 1.0 project-1.0.zip
449 hg archive -r 1.0 project-1.0.zip
449
450
450 - create a tarball excluding .hg files::
451 - create a tarball excluding .hg files::
451
452
452 hg archive project.tar.gz -X ".hg*"
453 hg archive project.tar.gz -X ".hg*"
453
454
454 Valid types are:
455 Valid types are:
455
456
456 :``files``: a directory full of files (default)
457 :``files``: a directory full of files (default)
457 :``tar``: tar archive, uncompressed
458 :``tar``: tar archive, uncompressed
458 :``tbz2``: tar archive, compressed using bzip2
459 :``tbz2``: tar archive, compressed using bzip2
459 :``tgz``: tar archive, compressed using gzip
460 :``tgz``: tar archive, compressed using gzip
460 :``uzip``: zip archive, uncompressed
461 :``uzip``: zip archive, uncompressed
461 :``zip``: zip archive, compressed using deflate
462 :``zip``: zip archive, compressed using deflate
462
463
463 The exact name of the destination archive or directory is given
464 The exact name of the destination archive or directory is given
464 using a format string; see :hg:`help export` for details.
465 using a format string; see :hg:`help export` for details.
465
466
466 Each member added to an archive file has a directory prefix
467 Each member added to an archive file has a directory prefix
467 prepended. Use -p/--prefix to specify a format string for the
468 prepended. Use -p/--prefix to specify a format string for the
468 prefix. The default is the basename of the archive, with suffixes
469 prefix. The default is the basename of the archive, with suffixes
469 removed.
470 removed.
470
471
471 Returns 0 on success.
472 Returns 0 on success.
472 '''
473 '''
473
474
474 opts = pycompat.byteskwargs(opts)
475 opts = pycompat.byteskwargs(opts)
475 rev = opts.get('rev')
476 rev = opts.get('rev')
476 if rev:
477 if rev:
477 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
478 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
478 ctx = scmutil.revsingle(repo, rev)
479 ctx = scmutil.revsingle(repo, rev)
479 if not ctx:
480 if not ctx:
480 raise error.Abort(_('no working directory: please specify a revision'))
481 raise error.Abort(_('no working directory: please specify a revision'))
481 node = ctx.node()
482 node = ctx.node()
482 dest = cmdutil.makefilename(ctx, dest)
483 dest = cmdutil.makefilename(ctx, dest)
483 if os.path.realpath(dest) == repo.root:
484 if os.path.realpath(dest) == repo.root:
484 raise error.Abort(_('repository root cannot be destination'))
485 raise error.Abort(_('repository root cannot be destination'))
485
486
486 kind = opts.get('type') or archival.guesskind(dest) or 'files'
487 kind = opts.get('type') or archival.guesskind(dest) or 'files'
487 prefix = opts.get('prefix')
488 prefix = opts.get('prefix')
488
489
489 if dest == '-':
490 if dest == '-':
490 if kind == 'files':
491 if kind == 'files':
491 raise error.Abort(_('cannot archive plain files to stdout'))
492 raise error.Abort(_('cannot archive plain files to stdout'))
492 dest = cmdutil.makefileobj(ctx, dest)
493 dest = cmdutil.makefileobj(ctx, dest)
493 if not prefix:
494 if not prefix:
494 prefix = os.path.basename(repo.root) + '-%h'
495 prefix = os.path.basename(repo.root) + '-%h'
495
496
496 prefix = cmdutil.makefilename(ctx, prefix)
497 prefix = cmdutil.makefilename(ctx, prefix)
497 match = scmutil.match(ctx, [], opts)
498 match = scmutil.match(ctx, [], opts)
498 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
499 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
499 match, prefix, subrepos=opts.get('subrepos'))
500 match, prefix, subrepos=opts.get('subrepos'))
500
501
501 @command('backout',
502 @command('backout',
502 [('', 'merge', None, _('merge with old dirstate parent after backout')),
503 [('', 'merge', None, _('merge with old dirstate parent after backout')),
503 ('', 'commit', None,
504 ('', 'commit', None,
504 _('commit if no conflicts were encountered (DEPRECATED)')),
505 _('commit if no conflicts were encountered (DEPRECATED)')),
505 ('', 'no-commit', None, _('do not commit')),
506 ('', 'no-commit', None, _('do not commit')),
506 ('', 'parent', '',
507 ('', 'parent', '',
507 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
508 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
508 ('r', 'rev', '', _('revision to backout'), _('REV')),
509 ('r', 'rev', '', _('revision to backout'), _('REV')),
509 ('e', 'edit', False, _('invoke editor on commit messages')),
510 ('e', 'edit', False, _('invoke editor on commit messages')),
510 ] + mergetoolopts + walkopts + commitopts + commitopts2,
511 ] + mergetoolopts + walkopts + commitopts + commitopts2,
511 _('[OPTION]... [-r] REV'))
512 _('[OPTION]... [-r] REV'))
512 def backout(ui, repo, node=None, rev=None, **opts):
513 def backout(ui, repo, node=None, rev=None, **opts):
513 '''reverse effect of earlier changeset
514 '''reverse effect of earlier changeset
514
515
515 Prepare a new changeset with the effect of REV undone in the
516 Prepare a new changeset with the effect of REV undone in the
516 current working directory. If no conflicts were encountered,
517 current working directory. If no conflicts were encountered,
517 it will be committed immediately.
518 it will be committed immediately.
518
519
519 If REV is the parent of the working directory, then this new changeset
520 If REV is the parent of the working directory, then this new changeset
520 is committed automatically (unless --no-commit is specified).
521 is committed automatically (unless --no-commit is specified).
521
522
522 .. note::
523 .. note::
523
524
524 :hg:`backout` cannot be used to fix either an unwanted or
525 :hg:`backout` cannot be used to fix either an unwanted or
525 incorrect merge.
526 incorrect merge.
526
527
527 .. container:: verbose
528 .. container:: verbose
528
529
529 Examples:
530 Examples:
530
531
531 - Reverse the effect of the parent of the working directory.
532 - Reverse the effect of the parent of the working directory.
532 This backout will be committed immediately::
533 This backout will be committed immediately::
533
534
534 hg backout -r .
535 hg backout -r .
535
536
536 - Reverse the effect of previous bad revision 23::
537 - Reverse the effect of previous bad revision 23::
537
538
538 hg backout -r 23
539 hg backout -r 23
539
540
540 - Reverse the effect of previous bad revision 23 and
541 - Reverse the effect of previous bad revision 23 and
541 leave changes uncommitted::
542 leave changes uncommitted::
542
543
543 hg backout -r 23 --no-commit
544 hg backout -r 23 --no-commit
544 hg commit -m "Backout revision 23"
545 hg commit -m "Backout revision 23"
545
546
546 By default, the pending changeset will have one parent,
547 By default, the pending changeset will have one parent,
547 maintaining a linear history. With --merge, the pending
548 maintaining a linear history. With --merge, the pending
548 changeset will instead have two parents: the old parent of the
549 changeset will instead have two parents: the old parent of the
549 working directory and a new child of REV that simply undoes REV.
550 working directory and a new child of REV that simply undoes REV.
550
551
551 Before version 1.7, the behavior without --merge was equivalent
552 Before version 1.7, the behavior without --merge was equivalent
552 to specifying --merge followed by :hg:`update --clean .` to
553 to specifying --merge followed by :hg:`update --clean .` to
553 cancel the merge and leave the child of REV as a head to be
554 cancel the merge and leave the child of REV as a head to be
554 merged separately.
555 merged separately.
555
556
556 See :hg:`help dates` for a list of formats valid for -d/--date.
557 See :hg:`help dates` for a list of formats valid for -d/--date.
557
558
558 See :hg:`help revert` for a way to restore files to the state
559 See :hg:`help revert` for a way to restore files to the state
559 of another revision.
560 of another revision.
560
561
561 Returns 0 on success, 1 if nothing to backout or there are unresolved
562 Returns 0 on success, 1 if nothing to backout or there are unresolved
562 files.
563 files.
563 '''
564 '''
564 with repo.wlock(), repo.lock():
565 with repo.wlock(), repo.lock():
565 return _dobackout(ui, repo, node, rev, **opts)
566 return _dobackout(ui, repo, node, rev, **opts)
566
567
567 def _dobackout(ui, repo, node=None, rev=None, **opts):
568 def _dobackout(ui, repo, node=None, rev=None, **opts):
568 opts = pycompat.byteskwargs(opts)
569 opts = pycompat.byteskwargs(opts)
569 if opts.get('commit') and opts.get('no_commit'):
570 if opts.get('commit') and opts.get('no_commit'):
570 raise error.Abort(_("cannot use --commit with --no-commit"))
571 raise error.Abort(_("cannot use --commit with --no-commit"))
571 if opts.get('merge') and opts.get('no_commit'):
572 if opts.get('merge') and opts.get('no_commit'):
572 raise error.Abort(_("cannot use --merge with --no-commit"))
573 raise error.Abort(_("cannot use --merge with --no-commit"))
573
574
574 if rev and node:
575 if rev and node:
575 raise error.Abort(_("please specify just one revision"))
576 raise error.Abort(_("please specify just one revision"))
576
577
577 if not rev:
578 if not rev:
578 rev = node
579 rev = node
579
580
580 if not rev:
581 if not rev:
581 raise error.Abort(_("please specify a revision to backout"))
582 raise error.Abort(_("please specify a revision to backout"))
582
583
583 date = opts.get('date')
584 date = opts.get('date')
584 if date:
585 if date:
585 opts['date'] = dateutil.parsedate(date)
586 opts['date'] = dateutil.parsedate(date)
586
587
587 cmdutil.checkunfinished(repo)
588 cmdutil.checkunfinished(repo)
588 cmdutil.bailifchanged(repo)
589 cmdutil.bailifchanged(repo)
589 node = scmutil.revsingle(repo, rev).node()
590 node = scmutil.revsingle(repo, rev).node()
590
591
591 op1, op2 = repo.dirstate.parents()
592 op1, op2 = repo.dirstate.parents()
592 if not repo.changelog.isancestor(node, op1):
593 if not repo.changelog.isancestor(node, op1):
593 raise error.Abort(_('cannot backout change that is not an ancestor'))
594 raise error.Abort(_('cannot backout change that is not an ancestor'))
594
595
595 p1, p2 = repo.changelog.parents(node)
596 p1, p2 = repo.changelog.parents(node)
596 if p1 == nullid:
597 if p1 == nullid:
597 raise error.Abort(_('cannot backout a change with no parents'))
598 raise error.Abort(_('cannot backout a change with no parents'))
598 if p2 != nullid:
599 if p2 != nullid:
599 if not opts.get('parent'):
600 if not opts.get('parent'):
600 raise error.Abort(_('cannot backout a merge changeset'))
601 raise error.Abort(_('cannot backout a merge changeset'))
601 p = repo.lookup(opts['parent'])
602 p = repo.lookup(opts['parent'])
602 if p not in (p1, p2):
603 if p not in (p1, p2):
603 raise error.Abort(_('%s is not a parent of %s') %
604 raise error.Abort(_('%s is not a parent of %s') %
604 (short(p), short(node)))
605 (short(p), short(node)))
605 parent = p
606 parent = p
606 else:
607 else:
607 if opts.get('parent'):
608 if opts.get('parent'):
608 raise error.Abort(_('cannot use --parent on non-merge changeset'))
609 raise error.Abort(_('cannot use --parent on non-merge changeset'))
609 parent = p1
610 parent = p1
610
611
611 # the backout should appear on the same branch
612 # the backout should appear on the same branch
612 branch = repo.dirstate.branch()
613 branch = repo.dirstate.branch()
613 bheads = repo.branchheads(branch)
614 bheads = repo.branchheads(branch)
614 rctx = scmutil.revsingle(repo, hex(parent))
615 rctx = scmutil.revsingle(repo, hex(parent))
615 if not opts.get('merge') and op1 != node:
616 if not opts.get('merge') and op1 != node:
616 with dirstateguard.dirstateguard(repo, 'backout'):
617 with dirstateguard.dirstateguard(repo, 'backout'):
617 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
618 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
618 with ui.configoverride(overrides, 'backout'):
619 with ui.configoverride(overrides, 'backout'):
619 stats = mergemod.update(repo, parent, True, True, node, False)
620 stats = mergemod.update(repo, parent, True, True, node, False)
620 repo.setparents(op1, op2)
621 repo.setparents(op1, op2)
621 hg._showstats(repo, stats)
622 hg._showstats(repo, stats)
622 if stats.unresolvedcount:
623 if stats.unresolvedcount:
623 repo.ui.status(_("use 'hg resolve' to retry unresolved "
624 repo.ui.status(_("use 'hg resolve' to retry unresolved "
624 "file merges\n"))
625 "file merges\n"))
625 return 1
626 return 1
626 else:
627 else:
627 hg.clean(repo, node, show_stats=False)
628 hg.clean(repo, node, show_stats=False)
628 repo.dirstate.setbranch(branch)
629 repo.dirstate.setbranch(branch)
629 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
630 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
630
631
631 if opts.get('no_commit'):
632 if opts.get('no_commit'):
632 msg = _("changeset %s backed out, "
633 msg = _("changeset %s backed out, "
633 "don't forget to commit.\n")
634 "don't forget to commit.\n")
634 ui.status(msg % short(node))
635 ui.status(msg % short(node))
635 return 0
636 return 0
636
637
637 def commitfunc(ui, repo, message, match, opts):
638 def commitfunc(ui, repo, message, match, opts):
638 editform = 'backout'
639 editform = 'backout'
639 e = cmdutil.getcommiteditor(editform=editform,
640 e = cmdutil.getcommiteditor(editform=editform,
640 **pycompat.strkwargs(opts))
641 **pycompat.strkwargs(opts))
641 if not message:
642 if not message:
642 # we don't translate commit messages
643 # we don't translate commit messages
643 message = "Backed out changeset %s" % short(node)
644 message = "Backed out changeset %s" % short(node)
644 e = cmdutil.getcommiteditor(edit=True, editform=editform)
645 e = cmdutil.getcommiteditor(edit=True, editform=editform)
645 return repo.commit(message, opts.get('user'), opts.get('date'),
646 return repo.commit(message, opts.get('user'), opts.get('date'),
646 match, editor=e)
647 match, editor=e)
647 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
648 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
648 if not newnode:
649 if not newnode:
649 ui.status(_("nothing changed\n"))
650 ui.status(_("nothing changed\n"))
650 return 1
651 return 1
651 cmdutil.commitstatus(repo, newnode, branch, bheads)
652 cmdutil.commitstatus(repo, newnode, branch, bheads)
652
653
653 def nice(node):
654 def nice(node):
654 return '%d:%s' % (repo.changelog.rev(node), short(node))
655 return '%d:%s' % (repo.changelog.rev(node), short(node))
655 ui.status(_('changeset %s backs out changeset %s\n') %
656 ui.status(_('changeset %s backs out changeset %s\n') %
656 (nice(repo.changelog.tip()), nice(node)))
657 (nice(repo.changelog.tip()), nice(node)))
657 if opts.get('merge') and op1 != node:
658 if opts.get('merge') and op1 != node:
658 hg.clean(repo, op1, show_stats=False)
659 hg.clean(repo, op1, show_stats=False)
659 ui.status(_('merging with changeset %s\n')
660 ui.status(_('merging with changeset %s\n')
660 % nice(repo.changelog.tip()))
661 % nice(repo.changelog.tip()))
661 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
662 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
662 with ui.configoverride(overrides, 'backout'):
663 with ui.configoverride(overrides, 'backout'):
663 return hg.merge(repo, hex(repo.changelog.tip()))
664 return hg.merge(repo, hex(repo.changelog.tip()))
664 return 0
665 return 0
665
666
666 @command('bisect',
667 @command('bisect',
667 [('r', 'reset', False, _('reset bisect state')),
668 [('r', 'reset', False, _('reset bisect state')),
668 ('g', 'good', False, _('mark changeset good')),
669 ('g', 'good', False, _('mark changeset good')),
669 ('b', 'bad', False, _('mark changeset bad')),
670 ('b', 'bad', False, _('mark changeset bad')),
670 ('s', 'skip', False, _('skip testing changeset')),
671 ('s', 'skip', False, _('skip testing changeset')),
671 ('e', 'extend', False, _('extend the bisect range')),
672 ('e', 'extend', False, _('extend the bisect range')),
672 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
673 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
673 ('U', 'noupdate', False, _('do not update to target'))],
674 ('U', 'noupdate', False, _('do not update to target'))],
674 _("[-gbsr] [-U] [-c CMD] [REV]"))
675 _("[-gbsr] [-U] [-c CMD] [REV]"))
675 def bisect(ui, repo, rev=None, extra=None, command=None,
676 def bisect(ui, repo, rev=None, extra=None, command=None,
676 reset=None, good=None, bad=None, skip=None, extend=None,
677 reset=None, good=None, bad=None, skip=None, extend=None,
677 noupdate=None):
678 noupdate=None):
678 """subdivision search of changesets
679 """subdivision search of changesets
679
680
680 This command helps to find changesets which introduce problems. To
681 This command helps to find changesets which introduce problems. To
681 use, mark the earliest changeset you know exhibits the problem as
682 use, mark the earliest changeset you know exhibits the problem as
682 bad, then mark the latest changeset which is free from the problem
683 bad, then mark the latest changeset which is free from the problem
683 as good. Bisect will update your working directory to a revision
684 as good. Bisect will update your working directory to a revision
684 for testing (unless the -U/--noupdate option is specified). Once
685 for testing (unless the -U/--noupdate option is specified). Once
685 you have performed tests, mark the working directory as good or
686 you have performed tests, mark the working directory as good or
686 bad, and bisect will either update to another candidate changeset
687 bad, and bisect will either update to another candidate changeset
687 or announce that it has found the bad revision.
688 or announce that it has found the bad revision.
688
689
689 As a shortcut, you can also use the revision argument to mark a
690 As a shortcut, you can also use the revision argument to mark a
690 revision as good or bad without checking it out first.
691 revision as good or bad without checking it out first.
691
692
692 If you supply a command, it will be used for automatic bisection.
693 If you supply a command, it will be used for automatic bisection.
693 The environment variable HG_NODE will contain the ID of the
694 The environment variable HG_NODE will contain the ID of the
694 changeset being tested. The exit status of the command will be
695 changeset being tested. The exit status of the command will be
695 used to mark revisions as good or bad: status 0 means good, 125
696 used to mark revisions as good or bad: status 0 means good, 125
696 means to skip the revision, 127 (command not found) will abort the
697 means to skip the revision, 127 (command not found) will abort the
697 bisection, and any other non-zero exit status means the revision
698 bisection, and any other non-zero exit status means the revision
698 is bad.
699 is bad.
699
700
700 .. container:: verbose
701 .. container:: verbose
701
702
702 Some examples:
703 Some examples:
703
704
704 - start a bisection with known bad revision 34, and good revision 12::
705 - start a bisection with known bad revision 34, and good revision 12::
705
706
706 hg bisect --bad 34
707 hg bisect --bad 34
707 hg bisect --good 12
708 hg bisect --good 12
708
709
709 - advance the current bisection by marking current revision as good or
710 - advance the current bisection by marking current revision as good or
710 bad::
711 bad::
711
712
712 hg bisect --good
713 hg bisect --good
713 hg bisect --bad
714 hg bisect --bad
714
715
715 - mark the current revision, or a known revision, to be skipped (e.g. if
716 - mark the current revision, or a known revision, to be skipped (e.g. if
716 that revision is not usable because of another issue)::
717 that revision is not usable because of another issue)::
717
718
718 hg bisect --skip
719 hg bisect --skip
719 hg bisect --skip 23
720 hg bisect --skip 23
720
721
721 - skip all revisions that do not touch directories ``foo`` or ``bar``::
722 - skip all revisions that do not touch directories ``foo`` or ``bar``::
722
723
723 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
724 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
724
725
725 - forget the current bisection::
726 - forget the current bisection::
726
727
727 hg bisect --reset
728 hg bisect --reset
728
729
729 - use 'make && make tests' to automatically find the first broken
730 - use 'make && make tests' to automatically find the first broken
730 revision::
731 revision::
731
732
732 hg bisect --reset
733 hg bisect --reset
733 hg bisect --bad 34
734 hg bisect --bad 34
734 hg bisect --good 12
735 hg bisect --good 12
735 hg bisect --command "make && make tests"
736 hg bisect --command "make && make tests"
736
737
737 - see all changesets whose states are already known in the current
738 - see all changesets whose states are already known in the current
738 bisection::
739 bisection::
739
740
740 hg log -r "bisect(pruned)"
741 hg log -r "bisect(pruned)"
741
742
742 - see the changeset currently being bisected (especially useful
743 - see the changeset currently being bisected (especially useful
743 if running with -U/--noupdate)::
744 if running with -U/--noupdate)::
744
745
745 hg log -r "bisect(current)"
746 hg log -r "bisect(current)"
746
747
747 - see all changesets that took part in the current bisection::
748 - see all changesets that took part in the current bisection::
748
749
749 hg log -r "bisect(range)"
750 hg log -r "bisect(range)"
750
751
751 - you can even get a nice graph::
752 - you can even get a nice graph::
752
753
753 hg log --graph -r "bisect(range)"
754 hg log --graph -r "bisect(range)"
754
755
755 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
756 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
756
757
757 Returns 0 on success.
758 Returns 0 on success.
758 """
759 """
759 # backward compatibility
760 # backward compatibility
760 if rev in "good bad reset init".split():
761 if rev in "good bad reset init".split():
761 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
762 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
762 cmd, rev, extra = rev, extra, None
763 cmd, rev, extra = rev, extra, None
763 if cmd == "good":
764 if cmd == "good":
764 good = True
765 good = True
765 elif cmd == "bad":
766 elif cmd == "bad":
766 bad = True
767 bad = True
767 else:
768 else:
768 reset = True
769 reset = True
769 elif extra:
770 elif extra:
770 raise error.Abort(_('incompatible arguments'))
771 raise error.Abort(_('incompatible arguments'))
771
772
772 incompatibles = {
773 incompatibles = {
773 '--bad': bad,
774 '--bad': bad,
774 '--command': bool(command),
775 '--command': bool(command),
775 '--extend': extend,
776 '--extend': extend,
776 '--good': good,
777 '--good': good,
777 '--reset': reset,
778 '--reset': reset,
778 '--skip': skip,
779 '--skip': skip,
779 }
780 }
780
781
781 enabled = [x for x in incompatibles if incompatibles[x]]
782 enabled = [x for x in incompatibles if incompatibles[x]]
782
783
783 if len(enabled) > 1:
784 if len(enabled) > 1:
784 raise error.Abort(_('%s and %s are incompatible') %
785 raise error.Abort(_('%s and %s are incompatible') %
785 tuple(sorted(enabled)[0:2]))
786 tuple(sorted(enabled)[0:2]))
786
787
787 if reset:
788 if reset:
788 hbisect.resetstate(repo)
789 hbisect.resetstate(repo)
789 return
790 return
790
791
791 state = hbisect.load_state(repo)
792 state = hbisect.load_state(repo)
792
793
793 # update state
794 # update state
794 if good or bad or skip:
795 if good or bad or skip:
795 if rev:
796 if rev:
796 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
797 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
797 else:
798 else:
798 nodes = [repo.lookup('.')]
799 nodes = [repo.lookup('.')]
799 if good:
800 if good:
800 state['good'] += nodes
801 state['good'] += nodes
801 elif bad:
802 elif bad:
802 state['bad'] += nodes
803 state['bad'] += nodes
803 elif skip:
804 elif skip:
804 state['skip'] += nodes
805 state['skip'] += nodes
805 hbisect.save_state(repo, state)
806 hbisect.save_state(repo, state)
806 if not (state['good'] and state['bad']):
807 if not (state['good'] and state['bad']):
807 return
808 return
808
809
809 def mayupdate(repo, node, show_stats=True):
810 def mayupdate(repo, node, show_stats=True):
810 """common used update sequence"""
811 """common used update sequence"""
811 if noupdate:
812 if noupdate:
812 return
813 return
813 cmdutil.checkunfinished(repo)
814 cmdutil.checkunfinished(repo)
814 cmdutil.bailifchanged(repo)
815 cmdutil.bailifchanged(repo)
815 return hg.clean(repo, node, show_stats=show_stats)
816 return hg.clean(repo, node, show_stats=show_stats)
816
817
817 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
818 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
818
819
819 if command:
820 if command:
820 changesets = 1
821 changesets = 1
821 if noupdate:
822 if noupdate:
822 try:
823 try:
823 node = state['current'][0]
824 node = state['current'][0]
824 except LookupError:
825 except LookupError:
825 raise error.Abort(_('current bisect revision is unknown - '
826 raise error.Abort(_('current bisect revision is unknown - '
826 'start a new bisect to fix'))
827 'start a new bisect to fix'))
827 else:
828 else:
828 node, p2 = repo.dirstate.parents()
829 node, p2 = repo.dirstate.parents()
829 if p2 != nullid:
830 if p2 != nullid:
830 raise error.Abort(_('current bisect revision is a merge'))
831 raise error.Abort(_('current bisect revision is a merge'))
831 if rev:
832 if rev:
832 node = repo[scmutil.revsingle(repo, rev, node)].node()
833 node = repo[scmutil.revsingle(repo, rev, node)].node()
833 try:
834 try:
834 while changesets:
835 while changesets:
835 # update state
836 # update state
836 state['current'] = [node]
837 state['current'] = [node]
837 hbisect.save_state(repo, state)
838 hbisect.save_state(repo, state)
838 status = ui.system(command, environ={'HG_NODE': hex(node)},
839 status = ui.system(command, environ={'HG_NODE': hex(node)},
839 blockedtag='bisect_check')
840 blockedtag='bisect_check')
840 if status == 125:
841 if status == 125:
841 transition = "skip"
842 transition = "skip"
842 elif status == 0:
843 elif status == 0:
843 transition = "good"
844 transition = "good"
844 # status < 0 means process was killed
845 # status < 0 means process was killed
845 elif status == 127:
846 elif status == 127:
846 raise error.Abort(_("failed to execute %s") % command)
847 raise error.Abort(_("failed to execute %s") % command)
847 elif status < 0:
848 elif status < 0:
848 raise error.Abort(_("%s killed") % command)
849 raise error.Abort(_("%s killed") % command)
849 else:
850 else:
850 transition = "bad"
851 transition = "bad"
851 state[transition].append(node)
852 state[transition].append(node)
852 ctx = repo[node]
853 ctx = repo[node]
853 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
854 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
854 transition))
855 transition))
855 hbisect.checkstate(state)
856 hbisect.checkstate(state)
856 # bisect
857 # bisect
857 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 # update to next check
859 # update to next check
859 node = nodes[0]
860 node = nodes[0]
860 mayupdate(repo, node, show_stats=False)
861 mayupdate(repo, node, show_stats=False)
861 finally:
862 finally:
862 state['current'] = [node]
863 state['current'] = [node]
863 hbisect.save_state(repo, state)
864 hbisect.save_state(repo, state)
864 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 return
866 return
866
867
867 hbisect.checkstate(state)
868 hbisect.checkstate(state)
868
869
869 # actually bisect
870 # actually bisect
870 nodes, changesets, good = hbisect.bisect(repo, state)
871 nodes, changesets, good = hbisect.bisect(repo, state)
871 if extend:
872 if extend:
872 if not changesets:
873 if not changesets:
873 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 if extendnode is not None:
875 if extendnode is not None:
875 ui.write(_("Extending search to changeset %d:%s\n")
876 ui.write(_("Extending search to changeset %d:%s\n")
876 % (extendnode.rev(), extendnode))
877 % (extendnode.rev(), extendnode))
877 state['current'] = [extendnode.node()]
878 state['current'] = [extendnode.node()]
878 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
879 return mayupdate(repo, extendnode.node())
880 return mayupdate(repo, extendnode.node())
880 raise error.Abort(_("nothing to extend"))
881 raise error.Abort(_("nothing to extend"))
881
882
882 if changesets == 0:
883 if changesets == 0:
883 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 else:
885 else:
885 assert len(nodes) == 1 # only a single node can be tested next
886 assert len(nodes) == 1 # only a single node can be tested next
886 node = nodes[0]
887 node = nodes[0]
887 # compute the approximate number of remaining tests
888 # compute the approximate number of remaining tests
888 tests, size = 0, 2
889 tests, size = 0, 2
889 while size <= changesets:
890 while size <= changesets:
890 tests, size = tests + 1, size * 2
891 tests, size = tests + 1, size * 2
891 rev = repo.changelog.rev(node)
892 rev = repo.changelog.rev(node)
892 ui.write(_("Testing changeset %d:%s "
893 ui.write(_("Testing changeset %d:%s "
893 "(%d changesets remaining, ~%d tests)\n")
894 "(%d changesets remaining, ~%d tests)\n")
894 % (rev, short(node), changesets, tests))
895 % (rev, short(node), changesets, tests))
895 state['current'] = [node]
896 state['current'] = [node]
896 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
897 return mayupdate(repo, node)
898 return mayupdate(repo, node)
898
899
899 @command('bookmarks|bookmark',
900 @command('bookmarks|bookmark',
900 [('f', 'force', False, _('force')),
901 [('f', 'force', False, _('force')),
901 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('d', 'delete', False, _('delete a given bookmark')),
903 ('d', 'delete', False, _('delete a given bookmark')),
903 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('', 'active', False, _('display the active bookmark')),
906 ('', 'active', False, _('display the active bookmark')),
906 ] + formatteropts,
907 ] + formatteropts,
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 def bookmark(ui, repo, *names, **opts):
909 def bookmark(ui, repo, *names, **opts):
909 '''create a new bookmark or list existing bookmarks
910 '''create a new bookmark or list existing bookmarks
910
911
911 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Deleting or moving a bookmark has no effect on the associated changesets.
914 Deleting or moving a bookmark has no effect on the associated changesets.
914
915
915 Creating or updating to a bookmark causes it to be marked as 'active'.
916 Creating or updating to a bookmark causes it to be marked as 'active'.
916 The active bookmark is indicated with a '*'.
917 The active bookmark is indicated with a '*'.
917 When a commit is made, the active bookmark will advance to the new commit.
918 When a commit is made, the active bookmark will advance to the new commit.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
919 A plain :hg:`update` will also advance an active bookmark, if possible.
919 Updating away from a bookmark will cause it to be deactivated.
920 Updating away from a bookmark will cause it to be deactivated.
920
921
921 Bookmarks can be pushed and pulled between repositories (see
922 Bookmarks can be pushed and pulled between repositories (see
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 be created. Using :hg:`merge` will resolve the divergence.
925 be created. Using :hg:`merge` will resolve the divergence.
925
926
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
927 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
927 the active bookmark's name.
928 the active bookmark's name.
928
929
929 A bookmark named '@' has the special property that :hg:`clone` will
930 A bookmark named '@' has the special property that :hg:`clone` will
930 check it out by default if it exists.
931 check it out by default if it exists.
931
932
932 The '--active' flag will display the current bookmark or return non-zero,
933 The '--active' flag will display the current bookmark or return non-zero,
933 if combined with other action, they will be performed on the active
934 if combined with other action, they will be performed on the active
934 bookmark.
935 bookmark.
935
936
936 .. container:: verbose
937 .. container:: verbose
937
938
938 Examples:
939 Examples:
939
940
940 - create an active bookmark for a new line of development::
941 - create an active bookmark for a new line of development::
941
942
942 hg book new-feature
943 hg book new-feature
943
944
944 - create an inactive bookmark as a place marker::
945 - create an inactive bookmark as a place marker::
945
946
946 hg book -i reviewed
947 hg book -i reviewed
947
948
948 - create an inactive bookmark on another changeset::
949 - create an inactive bookmark on another changeset::
949
950
950 hg book -r .^ tested
951 hg book -r .^ tested
951
952
952 - rename bookmark turkey to dinner::
953 - rename bookmark turkey to dinner::
953
954
954 hg book -m turkey dinner
955 hg book -m turkey dinner
955
956
956 - move the '@' bookmark from another branch::
957 - move the '@' bookmark from another branch::
957
958
958 hg book -f @
959 hg book -f @
959 '''
960 '''
960 force = opts.get(r'force')
961 force = opts.get(r'force')
961 rev = opts.get(r'rev')
962 rev = opts.get(r'rev')
962 delete = opts.get(r'delete')
963 delete = opts.get(r'delete')
963 rename = opts.get(r'rename')
964 rename = opts.get(r'rename')
964 inactive = opts.get(r'inactive')
965 inactive = opts.get(r'inactive')
965 active = opts.get(r'active')
966 active = opts.get(r'active')
966
967
967 if delete and rename:
968 if delete and rename:
968 raise error.Abort(_("--delete and --rename are incompatible"))
969 raise error.Abort(_("--delete and --rename are incompatible"))
969 if delete and rev:
970 if delete and rev:
970 raise error.Abort(_("--rev is incompatible with --delete"))
971 raise error.Abort(_("--rev is incompatible with --delete"))
971 if rename and rev:
972 if rename and rev:
972 raise error.Abort(_("--rev is incompatible with --rename"))
973 raise error.Abort(_("--rev is incompatible with --rename"))
973 if delete and active:
974 if delete and active:
974 raise error.Abort(_("--delete is incompatible with --active"))
975 raise error.Abort(_("--delete is incompatible with --active"))
975 if rev and active:
976 if rev and active:
976 raise error.Abort(_("--rev is incompatible with --active"))
977 raise error.Abort(_("--rev is incompatible with --active"))
977 if rename and active:
978 if rename and active:
978 raise error.Abort(_("--rename is incompatible with --active"))
979 raise error.Abort(_("--rename is incompatible with --active"))
979 if names and active:
980 if names and active:
980 raise error.Abort(_("NAMES is incompatible with --active"))
981 raise error.Abort(_("NAMES is incompatible with --active"))
981 if inactive and active:
982 if inactive and active:
982 raise error.Abort(_("--inactive is incompatible with --active"))
983 raise error.Abort(_("--inactive is incompatible with --active"))
983 if not names and (delete or rev):
984 if not names and (delete or rev):
984 raise error.Abort(_("bookmark name required"))
985 raise error.Abort(_("bookmark name required"))
985
986
986 if delete or rename or names or inactive:
987 if delete or rename or names or inactive:
987 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
988 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
988 if delete:
989 if delete:
989 names = pycompat.maplist(repo._bookmarks.expandname, names)
990 names = pycompat.maplist(repo._bookmarks.expandname, names)
990 bookmarks.delete(repo, tr, names)
991 bookmarks.delete(repo, tr, names)
991 elif rename:
992 elif rename:
992 if not names:
993 if not names:
993 raise error.Abort(_("new bookmark name required"))
994 raise error.Abort(_("new bookmark name required"))
994 elif len(names) > 1:
995 elif len(names) > 1:
995 raise error.Abort(_("only one new bookmark name allowed"))
996 raise error.Abort(_("only one new bookmark name allowed"))
996 rename = repo._bookmarks.expandname(rename)
997 rename = repo._bookmarks.expandname(rename)
997 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
998 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
998 elif names:
999 elif names:
999 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1000 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1000 elif inactive:
1001 elif inactive:
1001 if len(repo._bookmarks) == 0:
1002 if len(repo._bookmarks) == 0:
1002 ui.status(_("no bookmarks set\n"))
1003 ui.status(_("no bookmarks set\n"))
1003 elif not repo._activebookmark:
1004 elif not repo._activebookmark:
1004 ui.status(_("no active bookmark\n"))
1005 ui.status(_("no active bookmark\n"))
1005 else:
1006 else:
1006 bookmarks.deactivate(repo)
1007 bookmarks.deactivate(repo)
1007 elif active:
1008 elif active:
1008 book = repo._activebookmark
1009 book = repo._activebookmark
1009 if book is None:
1010 if book is None:
1010 return 1
1011 return 1
1011 ui.write("%s\n" % book, label=bookmarks.activebookmarklabel)
1012 ui.write("%s\n" % book, label=bookmarks.activebookmarklabel)
1012 else: # show bookmarks
1013 else: # show bookmarks
1013 bookmarks.printbookmarks(ui, repo, **opts)
1014 bookmarks.printbookmarks(ui, repo, **opts)
1014
1015
1015 @command('branch',
1016 @command('branch',
1016 [('f', 'force', None,
1017 [('f', 'force', None,
1017 _('set branch name even if it shadows an existing branch')),
1018 _('set branch name even if it shadows an existing branch')),
1018 ('C', 'clean', None, _('reset branch name to parent branch name')),
1019 ('C', 'clean', None, _('reset branch name to parent branch name')),
1019 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1020 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1020 ],
1021 ],
1021 _('[-fC] [NAME]'))
1022 _('[-fC] [NAME]'))
1022 def branch(ui, repo, label=None, **opts):
1023 def branch(ui, repo, label=None, **opts):
1023 """set or show the current branch name
1024 """set or show the current branch name
1024
1025
1025 .. note::
1026 .. note::
1026
1027
1027 Branch names are permanent and global. Use :hg:`bookmark` to create a
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1028 light-weight bookmark instead. See :hg:`help glossary` for more
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1029 information about named branches and bookmarks.
1030 information about named branches and bookmarks.
1030
1031
1031 With no argument, show the current branch name. With one argument,
1032 With no argument, show the current branch name. With one argument,
1032 set the working directory branch name (the branch will not exist
1033 set the working directory branch name (the branch will not exist
1033 in the repository until the next commit). Standard practice
1034 in the repository until the next commit). Standard practice
1034 recommends that primary development take place on the 'default'
1035 recommends that primary development take place on the 'default'
1035 branch.
1036 branch.
1036
1037
1037 Unless -f/--force is specified, branch will not let you set a
1038 Unless -f/--force is specified, branch will not let you set a
1038 branch name that already exists.
1039 branch name that already exists.
1039
1040
1040 Use -C/--clean to reset the working directory branch to that of
1041 Use -C/--clean to reset the working directory branch to that of
1041 the parent of the working directory, negating a previous branch
1042 the parent of the working directory, negating a previous branch
1042 change.
1043 change.
1043
1044
1044 Use the command :hg:`update` to switch to an existing branch. Use
1045 Use the command :hg:`update` to switch to an existing branch. Use
1045 :hg:`commit --close-branch` to mark this branch head as closed.
1046 :hg:`commit --close-branch` to mark this branch head as closed.
1046 When all heads of a branch are closed, the branch will be
1047 When all heads of a branch are closed, the branch will be
1047 considered closed.
1048 considered closed.
1048
1049
1049 Returns 0 on success.
1050 Returns 0 on success.
1050 """
1051 """
1051 opts = pycompat.byteskwargs(opts)
1052 opts = pycompat.byteskwargs(opts)
1052 revs = opts.get('rev')
1053 revs = opts.get('rev')
1053 if label:
1054 if label:
1054 label = label.strip()
1055 label = label.strip()
1055
1056
1056 if not opts.get('clean') and not label:
1057 if not opts.get('clean') and not label:
1057 if revs:
1058 if revs:
1058 raise error.Abort(_("no branch name specified for the revisions"))
1059 raise error.Abort(_("no branch name specified for the revisions"))
1059 ui.write("%s\n" % repo.dirstate.branch())
1060 ui.write("%s\n" % repo.dirstate.branch())
1060 return
1061 return
1061
1062
1062 with repo.wlock():
1063 with repo.wlock():
1063 if opts.get('clean'):
1064 if opts.get('clean'):
1064 label = repo[None].p1().branch()
1065 label = repo[None].p1().branch()
1065 repo.dirstate.setbranch(label)
1066 repo.dirstate.setbranch(label)
1066 ui.status(_('reset working directory to branch %s\n') % label)
1067 ui.status(_('reset working directory to branch %s\n') % label)
1067 elif label:
1068 elif label:
1068
1069
1069 scmutil.checknewlabel(repo, label, 'branch')
1070 scmutil.checknewlabel(repo, label, 'branch')
1070 if revs:
1071 if revs:
1071 return cmdutil.changebranch(ui, repo, revs, label)
1072 return cmdutil.changebranch(ui, repo, revs, label)
1072
1073
1073 if not opts.get('force') and label in repo.branchmap():
1074 if not opts.get('force') and label in repo.branchmap():
1074 if label not in [p.branch() for p in repo[None].parents()]:
1075 if label not in [p.branch() for p in repo[None].parents()]:
1075 raise error.Abort(_('a branch of the same name already'
1076 raise error.Abort(_('a branch of the same name already'
1076 ' exists'),
1077 ' exists'),
1077 # i18n: "it" refers to an existing branch
1078 # i18n: "it" refers to an existing branch
1078 hint=_("use 'hg update' to switch to it"))
1079 hint=_("use 'hg update' to switch to it"))
1079
1080
1080 repo.dirstate.setbranch(label)
1081 repo.dirstate.setbranch(label)
1081 ui.status(_('marked working directory as branch %s\n') % label)
1082 ui.status(_('marked working directory as branch %s\n') % label)
1082
1083
1083 # find any open named branches aside from default
1084 # find any open named branches aside from default
1084 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1085 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1085 if n != "default" and not c]
1086 if n != "default" and not c]
1086 if not others:
1087 if not others:
1087 ui.status(_('(branches are permanent and global, '
1088 ui.status(_('(branches are permanent and global, '
1088 'did you want a bookmark?)\n'))
1089 'did you want a bookmark?)\n'))
1089
1090
1090 @command('branches',
1091 @command('branches',
1091 [('a', 'active', False,
1092 [('a', 'active', False,
1092 _('show only branches that have unmerged heads (DEPRECATED)')),
1093 _('show only branches that have unmerged heads (DEPRECATED)')),
1093 ('c', 'closed', False, _('show normal and closed branches')),
1094 ('c', 'closed', False, _('show normal and closed branches')),
1094 ] + formatteropts,
1095 ] + formatteropts,
1095 _('[-c]'),
1096 _('[-c]'),
1096 intents={INTENT_READONLY})
1097 intents={INTENT_READONLY})
1097 def branches(ui, repo, active=False, closed=False, **opts):
1098 def branches(ui, repo, active=False, closed=False, **opts):
1098 """list repository named branches
1099 """list repository named branches
1099
1100
1100 List the repository's named branches, indicating which ones are
1101 List the repository's named branches, indicating which ones are
1101 inactive. If -c/--closed is specified, also list branches which have
1102 inactive. If -c/--closed is specified, also list branches which have
1102 been marked closed (see :hg:`commit --close-branch`).
1103 been marked closed (see :hg:`commit --close-branch`).
1103
1104
1104 Use the command :hg:`update` to switch to an existing branch.
1105 Use the command :hg:`update` to switch to an existing branch.
1105
1106
1106 Returns 0.
1107 Returns 0.
1107 """
1108 """
1108
1109
1109 opts = pycompat.byteskwargs(opts)
1110 opts = pycompat.byteskwargs(opts)
1110 ui.pager('branches')
1111 ui.pager('branches')
1111 fm = ui.formatter('branches', opts)
1112 fm = ui.formatter('branches', opts)
1112 hexfunc = fm.hexfunc
1113 hexfunc = fm.hexfunc
1113
1114
1114 allheads = set(repo.heads())
1115 allheads = set(repo.heads())
1115 branches = []
1116 branches = []
1116 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1117 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1117 isactive = False
1118 isactive = False
1118 if not isclosed:
1119 if not isclosed:
1119 openheads = set(repo.branchmap().iteropen(heads))
1120 openheads = set(repo.branchmap().iteropen(heads))
1120 isactive = bool(openheads & allheads)
1121 isactive = bool(openheads & allheads)
1121 branches.append((tag, repo[tip], isactive, not isclosed))
1122 branches.append((tag, repo[tip], isactive, not isclosed))
1122 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1123 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1123 reverse=True)
1124 reverse=True)
1124
1125
1125 for tag, ctx, isactive, isopen in branches:
1126 for tag, ctx, isactive, isopen in branches:
1126 if active and not isactive:
1127 if active and not isactive:
1127 continue
1128 continue
1128 if isactive:
1129 if isactive:
1129 label = 'branches.active'
1130 label = 'branches.active'
1130 notice = ''
1131 notice = ''
1131 elif not isopen:
1132 elif not isopen:
1132 if not closed:
1133 if not closed:
1133 continue
1134 continue
1134 label = 'branches.closed'
1135 label = 'branches.closed'
1135 notice = _(' (closed)')
1136 notice = _(' (closed)')
1136 else:
1137 else:
1137 label = 'branches.inactive'
1138 label = 'branches.inactive'
1138 notice = _(' (inactive)')
1139 notice = _(' (inactive)')
1139 current = (tag == repo.dirstate.branch())
1140 current = (tag == repo.dirstate.branch())
1140 if current:
1141 if current:
1141 label = 'branches.current'
1142 label = 'branches.current'
1142
1143
1143 fm.startitem()
1144 fm.startitem()
1144 fm.write('branch', '%s', tag, label=label)
1145 fm.write('branch', '%s', tag, label=label)
1145 rev = ctx.rev()
1146 rev = ctx.rev()
1146 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1147 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1147 fmt = ' ' * padsize + ' %d:%s'
1148 fmt = ' ' * padsize + ' %d:%s'
1148 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1149 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1149 label='log.changeset changeset.%s' % ctx.phasestr())
1150 label='log.changeset changeset.%s' % ctx.phasestr())
1150 fm.context(ctx=ctx)
1151 fm.context(ctx=ctx)
1151 fm.data(active=isactive, closed=not isopen, current=current)
1152 fm.data(active=isactive, closed=not isopen, current=current)
1152 if not ui.quiet:
1153 if not ui.quiet:
1153 fm.plain(notice)
1154 fm.plain(notice)
1154 fm.plain('\n')
1155 fm.plain('\n')
1155 fm.end()
1156 fm.end()
1156
1157
1157 @command('bundle',
1158 @command('bundle',
1158 [('f', 'force', None, _('run even when the destination is unrelated')),
1159 [('f', 'force', None, _('run even when the destination is unrelated')),
1159 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1160 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1160 _('REV')),
1161 _('REV')),
1161 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1162 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1162 _('BRANCH')),
1163 _('BRANCH')),
1163 ('', 'base', [],
1164 ('', 'base', [],
1164 _('a base changeset assumed to be available at the destination'),
1165 _('a base changeset assumed to be available at the destination'),
1165 _('REV')),
1166 _('REV')),
1166 ('a', 'all', None, _('bundle all changesets in the repository')),
1167 ('a', 'all', None, _('bundle all changesets in the repository')),
1167 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1168 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1168 ] + remoteopts,
1169 ] + remoteopts,
1169 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1170 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1170 def bundle(ui, repo, fname, dest=None, **opts):
1171 def bundle(ui, repo, fname, dest=None, **opts):
1171 """create a bundle file
1172 """create a bundle file
1172
1173
1173 Generate a bundle file containing data to be transferred to another
1174 Generate a bundle file containing data to be transferred to another
1174 repository.
1175 repository.
1175
1176
1176 To create a bundle containing all changesets, use -a/--all
1177 To create a bundle containing all changesets, use -a/--all
1177 (or --base null). Otherwise, hg assumes the destination will have
1178 (or --base null). Otherwise, hg assumes the destination will have
1178 all the nodes you specify with --base parameters. Otherwise, hg
1179 all the nodes you specify with --base parameters. Otherwise, hg
1179 will assume the repository has all the nodes in destination, or
1180 will assume the repository has all the nodes in destination, or
1180 default-push/default if no destination is specified, where destination
1181 default-push/default if no destination is specified, where destination
1181 is the repository you provide through DEST option.
1182 is the repository you provide through DEST option.
1182
1183
1183 You can change bundle format with the -t/--type option. See
1184 You can change bundle format with the -t/--type option. See
1184 :hg:`help bundlespec` for documentation on this format. By default,
1185 :hg:`help bundlespec` for documentation on this format. By default,
1185 the most appropriate format is used and compression defaults to
1186 the most appropriate format is used and compression defaults to
1186 bzip2.
1187 bzip2.
1187
1188
1188 The bundle file can then be transferred using conventional means
1189 The bundle file can then be transferred using conventional means
1189 and applied to another repository with the unbundle or pull
1190 and applied to another repository with the unbundle or pull
1190 command. This is useful when direct push and pull are not
1191 command. This is useful when direct push and pull are not
1191 available or when exporting an entire repository is undesirable.
1192 available or when exporting an entire repository is undesirable.
1192
1193
1193 Applying bundles preserves all changeset contents including
1194 Applying bundles preserves all changeset contents including
1194 permissions, copy/rename information, and revision history.
1195 permissions, copy/rename information, and revision history.
1195
1196
1196 Returns 0 on success, 1 if no changes found.
1197 Returns 0 on success, 1 if no changes found.
1197 """
1198 """
1198 opts = pycompat.byteskwargs(opts)
1199 opts = pycompat.byteskwargs(opts)
1199 revs = None
1200 revs = None
1200 if 'rev' in opts:
1201 if 'rev' in opts:
1201 revstrings = opts['rev']
1202 revstrings = opts['rev']
1202 revs = scmutil.revrange(repo, revstrings)
1203 revs = scmutil.revrange(repo, revstrings)
1203 if revstrings and not revs:
1204 if revstrings and not revs:
1204 raise error.Abort(_('no commits to bundle'))
1205 raise error.Abort(_('no commits to bundle'))
1205
1206
1206 bundletype = opts.get('type', 'bzip2').lower()
1207 bundletype = opts.get('type', 'bzip2').lower()
1207 try:
1208 try:
1208 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1209 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1209 except error.UnsupportedBundleSpecification as e:
1210 except error.UnsupportedBundleSpecification as e:
1210 raise error.Abort(pycompat.bytestr(e),
1211 raise error.Abort(pycompat.bytestr(e),
1211 hint=_("see 'hg help bundlespec' for supported "
1212 hint=_("see 'hg help bundlespec' for supported "
1212 "values for --type"))
1213 "values for --type"))
1213 cgversion = bundlespec.contentopts["cg.version"]
1214 cgversion = bundlespec.contentopts["cg.version"]
1214
1215
1215 # Packed bundles are a pseudo bundle format for now.
1216 # Packed bundles are a pseudo bundle format for now.
1216 if cgversion == 's1':
1217 if cgversion == 's1':
1217 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1218 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1218 hint=_("use 'hg debugcreatestreamclonebundle'"))
1219 hint=_("use 'hg debugcreatestreamclonebundle'"))
1219
1220
1220 if opts.get('all'):
1221 if opts.get('all'):
1221 if dest:
1222 if dest:
1222 raise error.Abort(_("--all is incompatible with specifying "
1223 raise error.Abort(_("--all is incompatible with specifying "
1223 "a destination"))
1224 "a destination"))
1224 if opts.get('base'):
1225 if opts.get('base'):
1225 ui.warn(_("ignoring --base because --all was specified\n"))
1226 ui.warn(_("ignoring --base because --all was specified\n"))
1226 base = ['null']
1227 base = ['null']
1227 else:
1228 else:
1228 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1229 if cgversion not in changegroup.supportedoutgoingversions(repo):
1230 if cgversion not in changegroup.supportedoutgoingversions(repo):
1230 raise error.Abort(_("repository does not support bundle version %s") %
1231 raise error.Abort(_("repository does not support bundle version %s") %
1231 cgversion)
1232 cgversion)
1232
1233
1233 if base:
1234 if base:
1234 if dest:
1235 if dest:
1235 raise error.Abort(_("--base is incompatible with specifying "
1236 raise error.Abort(_("--base is incompatible with specifying "
1236 "a destination"))
1237 "a destination"))
1237 common = [repo[rev].node() for rev in base]
1238 common = [repo[rev].node() for rev in base]
1238 heads = [repo[r].node() for r in revs] if revs else None
1239 heads = [repo[r].node() for r in revs] if revs else None
1239 outgoing = discovery.outgoing(repo, common, heads)
1240 outgoing = discovery.outgoing(repo, common, heads)
1240 else:
1241 else:
1241 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1244 revs = [repo[r].hex() for r in revs]
1245 revs = [repo[r].hex() for r in revs]
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1247 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1248 outgoing = discovery.findcommonoutgoing(repo, other,
1248 onlyheads=heads,
1249 onlyheads=heads,
1249 force=opts.get('force'),
1250 force=opts.get('force'),
1250 portable=True)
1251 portable=True)
1251
1252
1252 if not outgoing.missing:
1253 if not outgoing.missing:
1253 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1254 return 1
1255 return 1
1255
1256
1256 if cgversion == '01': #bundle1
1257 if cgversion == '01': #bundle1
1257 bversion = 'HG10' + bundlespec.wirecompression
1258 bversion = 'HG10' + bundlespec.wirecompression
1258 bcompression = None
1259 bcompression = None
1259 elif cgversion in ('02', '03'):
1260 elif cgversion in ('02', '03'):
1260 bversion = 'HG20'
1261 bversion = 'HG20'
1261 bcompression = bundlespec.wirecompression
1262 bcompression = bundlespec.wirecompression
1262 else:
1263 else:
1263 raise error.ProgrammingError(
1264 raise error.ProgrammingError(
1264 'bundle: unexpected changegroup version %s' % cgversion)
1265 'bundle: unexpected changegroup version %s' % cgversion)
1265
1266
1266 # TODO compression options should be derived from bundlespec parsing.
1267 # TODO compression options should be derived from bundlespec parsing.
1267 # This is a temporary hack to allow adjusting bundle compression
1268 # This is a temporary hack to allow adjusting bundle compression
1268 # level without a) formalizing the bundlespec changes to declare it
1269 # level without a) formalizing the bundlespec changes to declare it
1269 # b) introducing a command flag.
1270 # b) introducing a command flag.
1270 compopts = {}
1271 compopts = {}
1271 complevel = ui.configint('experimental',
1272 complevel = ui.configint('experimental',
1272 'bundlecomplevel.' + bundlespec.compression)
1273 'bundlecomplevel.' + bundlespec.compression)
1273 if complevel is None:
1274 if complevel is None:
1274 complevel = ui.configint('experimental', 'bundlecomplevel')
1275 complevel = ui.configint('experimental', 'bundlecomplevel')
1275 if complevel is not None:
1276 if complevel is not None:
1276 compopts['level'] = complevel
1277 compopts['level'] = complevel
1277
1278
1278 # Allow overriding the bundling of obsmarker in phases through
1279 # Allow overriding the bundling of obsmarker in phases through
1279 # configuration while we don't have a bundle version that include them
1280 # configuration while we don't have a bundle version that include them
1280 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1281 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1281 bundlespec.contentopts['obsolescence'] = True
1282 bundlespec.contentopts['obsolescence'] = True
1282 if repo.ui.configbool('experimental', 'bundle-phases'):
1283 if repo.ui.configbool('experimental', 'bundle-phases'):
1283 bundlespec.contentopts['phases'] = True
1284 bundlespec.contentopts['phases'] = True
1284
1285
1285 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1286 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1286 bundlespec.contentopts, compression=bcompression,
1287 bundlespec.contentopts, compression=bcompression,
1287 compopts=compopts)
1288 compopts=compopts)
1288
1289
1289 @command('cat',
1290 @command('cat',
1290 [('o', 'output', '',
1291 [('o', 'output', '',
1291 _('print output to file with formatted name'), _('FORMAT')),
1292 _('print output to file with formatted name'), _('FORMAT')),
1292 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('', 'decode', None, _('apply any matching decode filter')),
1294 ('', 'decode', None, _('apply any matching decode filter')),
1294 ] + walkopts + formatteropts,
1295 ] + walkopts + formatteropts,
1295 _('[OPTION]... FILE...'),
1296 _('[OPTION]... FILE...'),
1296 inferrepo=True,
1297 inferrepo=True,
1297 intents={INTENT_READONLY})
1298 intents={INTENT_READONLY})
1298 def cat(ui, repo, file1, *pats, **opts):
1299 def cat(ui, repo, file1, *pats, **opts):
1299 """output the current or given revision of files
1300 """output the current or given revision of files
1300
1301
1301 Print the specified files as they were at the given revision. If
1302 Print the specified files as they were at the given revision. If
1302 no revision is given, the parent of the working directory is used.
1303 no revision is given, the parent of the working directory is used.
1303
1304
1304 Output may be to a file, in which case the name of the file is
1305 Output may be to a file, in which case the name of the file is
1305 given using a template string. See :hg:`help templates`. In addition
1306 given using a template string. See :hg:`help templates`. In addition
1306 to the common template keywords, the following formatting rules are
1307 to the common template keywords, the following formatting rules are
1307 supported:
1308 supported:
1308
1309
1309 :``%%``: literal "%" character
1310 :``%%``: literal "%" character
1310 :``%s``: basename of file being printed
1311 :``%s``: basename of file being printed
1311 :``%d``: dirname of file being printed, or '.' if in repository root
1312 :``%d``: dirname of file being printed, or '.' if in repository root
1312 :``%p``: root-relative path name of file being printed
1313 :``%p``: root-relative path name of file being printed
1313 :``%H``: changeset hash (40 hexadecimal digits)
1314 :``%H``: changeset hash (40 hexadecimal digits)
1314 :``%R``: changeset revision number
1315 :``%R``: changeset revision number
1315 :``%h``: short-form changeset hash (12 hexadecimal digits)
1316 :``%h``: short-form changeset hash (12 hexadecimal digits)
1316 :``%r``: zero-padded changeset revision number
1317 :``%r``: zero-padded changeset revision number
1317 :``%b``: basename of the exporting repository
1318 :``%b``: basename of the exporting repository
1318 :``\\``: literal "\\" character
1319 :``\\``: literal "\\" character
1319
1320
1320 Returns 0 on success.
1321 Returns 0 on success.
1321 """
1322 """
1322 opts = pycompat.byteskwargs(opts)
1323 opts = pycompat.byteskwargs(opts)
1323 rev = opts.get('rev')
1324 rev = opts.get('rev')
1324 if rev:
1325 if rev:
1325 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1326 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1326 ctx = scmutil.revsingle(repo, rev)
1327 ctx = scmutil.revsingle(repo, rev)
1327 m = scmutil.match(ctx, (file1,) + pats, opts)
1328 m = scmutil.match(ctx, (file1,) + pats, opts)
1328 fntemplate = opts.pop('output', '')
1329 fntemplate = opts.pop('output', '')
1329 if cmdutil.isstdiofilename(fntemplate):
1330 if cmdutil.isstdiofilename(fntemplate):
1330 fntemplate = ''
1331 fntemplate = ''
1331
1332
1332 if fntemplate:
1333 if fntemplate:
1333 fm = formatter.nullformatter(ui, 'cat', opts)
1334 fm = formatter.nullformatter(ui, 'cat', opts)
1334 else:
1335 else:
1335 ui.pager('cat')
1336 ui.pager('cat')
1336 fm = ui.formatter('cat', opts)
1337 fm = ui.formatter('cat', opts)
1337 with fm:
1338 with fm:
1338 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1339 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1339 **pycompat.strkwargs(opts))
1340 **pycompat.strkwargs(opts))
1340
1341
1341 @command('^clone',
1342 @command('^clone',
1342 [('U', 'noupdate', None, _('the clone will include an empty working '
1343 [('U', 'noupdate', None, _('the clone will include an empty working '
1343 'directory (only a repository)')),
1344 'directory (only a repository)')),
1344 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1345 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1345 _('REV')),
1346 _('REV')),
1346 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1347 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1347 ' and its ancestors'), _('REV')),
1348 ' and its ancestors'), _('REV')),
1348 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1349 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1349 ' changesets and their ancestors'), _('BRANCH')),
1350 ' changesets and their ancestors'), _('BRANCH')),
1350 ('', 'pull', None, _('use pull protocol to copy metadata')),
1351 ('', 'pull', None, _('use pull protocol to copy metadata')),
1351 ('', 'uncompressed', None,
1352 ('', 'uncompressed', None,
1352 _('an alias to --stream (DEPRECATED)')),
1353 _('an alias to --stream (DEPRECATED)')),
1353 ('', 'stream', None,
1354 ('', 'stream', None,
1354 _('clone with minimal data processing')),
1355 _('clone with minimal data processing')),
1355 ] + remoteopts,
1356 ] + remoteopts,
1356 _('[OPTION]... SOURCE [DEST]'),
1357 _('[OPTION]... SOURCE [DEST]'),
1357 norepo=True)
1358 norepo=True)
1358 def clone(ui, source, dest=None, **opts):
1359 def clone(ui, source, dest=None, **opts):
1359 """make a copy of an existing repository
1360 """make a copy of an existing repository
1360
1361
1361 Create a copy of an existing repository in a new directory.
1362 Create a copy of an existing repository in a new directory.
1362
1363
1363 If no destination directory name is specified, it defaults to the
1364 If no destination directory name is specified, it defaults to the
1364 basename of the source.
1365 basename of the source.
1365
1366
1366 The location of the source is added to the new repository's
1367 The location of the source is added to the new repository's
1367 ``.hg/hgrc`` file, as the default to be used for future pulls.
1368 ``.hg/hgrc`` file, as the default to be used for future pulls.
1368
1369
1369 Only local paths and ``ssh://`` URLs are supported as
1370 Only local paths and ``ssh://`` URLs are supported as
1370 destinations. For ``ssh://`` destinations, no working directory or
1371 destinations. For ``ssh://`` destinations, no working directory or
1371 ``.hg/hgrc`` will be created on the remote side.
1372 ``.hg/hgrc`` will be created on the remote side.
1372
1373
1373 If the source repository has a bookmark called '@' set, that
1374 If the source repository has a bookmark called '@' set, that
1374 revision will be checked out in the new repository by default.
1375 revision will be checked out in the new repository by default.
1375
1376
1376 To check out a particular version, use -u/--update, or
1377 To check out a particular version, use -u/--update, or
1377 -U/--noupdate to create a clone with no working directory.
1378 -U/--noupdate to create a clone with no working directory.
1378
1379
1379 To pull only a subset of changesets, specify one or more revisions
1380 To pull only a subset of changesets, specify one or more revisions
1380 identifiers with -r/--rev or branches with -b/--branch. The
1381 identifiers with -r/--rev or branches with -b/--branch. The
1381 resulting clone will contain only the specified changesets and
1382 resulting clone will contain only the specified changesets and
1382 their ancestors. These options (or 'clone src#rev dest') imply
1383 their ancestors. These options (or 'clone src#rev dest') imply
1383 --pull, even for local source repositories.
1384 --pull, even for local source repositories.
1384
1385
1385 In normal clone mode, the remote normalizes repository data into a common
1386 In normal clone mode, the remote normalizes repository data into a common
1386 exchange format and the receiving end translates this data into its local
1387 exchange format and the receiving end translates this data into its local
1387 storage format. --stream activates a different clone mode that essentially
1388 storage format. --stream activates a different clone mode that essentially
1388 copies repository files from the remote with minimal data processing. This
1389 copies repository files from the remote with minimal data processing. This
1389 significantly reduces the CPU cost of a clone both remotely and locally.
1390 significantly reduces the CPU cost of a clone both remotely and locally.
1390 However, it often increases the transferred data size by 30-40%. This can
1391 However, it often increases the transferred data size by 30-40%. This can
1391 result in substantially faster clones where I/O throughput is plentiful,
1392 result in substantially faster clones where I/O throughput is plentiful,
1392 especially for larger repositories. A side-effect of --stream clones is
1393 especially for larger repositories. A side-effect of --stream clones is
1393 that storage settings and requirements on the remote are applied locally:
1394 that storage settings and requirements on the remote are applied locally:
1394 a modern client may inherit legacy or inefficient storage used by the
1395 a modern client may inherit legacy or inefficient storage used by the
1395 remote or a legacy Mercurial client may not be able to clone from a
1396 remote or a legacy Mercurial client may not be able to clone from a
1396 modern Mercurial remote.
1397 modern Mercurial remote.
1397
1398
1398 .. note::
1399 .. note::
1399
1400
1400 Specifying a tag will include the tagged changeset but not the
1401 Specifying a tag will include the tagged changeset but not the
1401 changeset containing the tag.
1402 changeset containing the tag.
1402
1403
1403 .. container:: verbose
1404 .. container:: verbose
1404
1405
1405 For efficiency, hardlinks are used for cloning whenever the
1406 For efficiency, hardlinks are used for cloning whenever the
1406 source and destination are on the same filesystem (note this
1407 source and destination are on the same filesystem (note this
1407 applies only to the repository data, not to the working
1408 applies only to the repository data, not to the working
1408 directory). Some filesystems, such as AFS, implement hardlinking
1409 directory). Some filesystems, such as AFS, implement hardlinking
1409 incorrectly, but do not report errors. In these cases, use the
1410 incorrectly, but do not report errors. In these cases, use the
1410 --pull option to avoid hardlinking.
1411 --pull option to avoid hardlinking.
1411
1412
1412 Mercurial will update the working directory to the first applicable
1413 Mercurial will update the working directory to the first applicable
1413 revision from this list:
1414 revision from this list:
1414
1415
1415 a) null if -U or the source repository has no changesets
1416 a) null if -U or the source repository has no changesets
1416 b) if -u . and the source repository is local, the first parent of
1417 b) if -u . and the source repository is local, the first parent of
1417 the source repository's working directory
1418 the source repository's working directory
1418 c) the changeset specified with -u (if a branch name, this means the
1419 c) the changeset specified with -u (if a branch name, this means the
1419 latest head of that branch)
1420 latest head of that branch)
1420 d) the changeset specified with -r
1421 d) the changeset specified with -r
1421 e) the tipmost head specified with -b
1422 e) the tipmost head specified with -b
1422 f) the tipmost head specified with the url#branch source syntax
1423 f) the tipmost head specified with the url#branch source syntax
1423 g) the revision marked with the '@' bookmark, if present
1424 g) the revision marked with the '@' bookmark, if present
1424 h) the tipmost head of the default branch
1425 h) the tipmost head of the default branch
1425 i) tip
1426 i) tip
1426
1427
1427 When cloning from servers that support it, Mercurial may fetch
1428 When cloning from servers that support it, Mercurial may fetch
1428 pre-generated data from a server-advertised URL or inline from the
1429 pre-generated data from a server-advertised URL or inline from the
1429 same stream. When this is done, hooks operating on incoming changesets
1430 same stream. When this is done, hooks operating on incoming changesets
1430 and changegroups may fire more than once, once for each pre-generated
1431 and changegroups may fire more than once, once for each pre-generated
1431 bundle and as well as for any additional remaining data. In addition,
1432 bundle and as well as for any additional remaining data. In addition,
1432 if an error occurs, the repository may be rolled back to a partial
1433 if an error occurs, the repository may be rolled back to a partial
1433 clone. This behavior may change in future releases.
1434 clone. This behavior may change in future releases.
1434 See :hg:`help -e clonebundles` for more.
1435 See :hg:`help -e clonebundles` for more.
1435
1436
1436 Examples:
1437 Examples:
1437
1438
1438 - clone a remote repository to a new directory named hg/::
1439 - clone a remote repository to a new directory named hg/::
1439
1440
1440 hg clone https://www.mercurial-scm.org/repo/hg/
1441 hg clone https://www.mercurial-scm.org/repo/hg/
1441
1442
1442 - create a lightweight local clone::
1443 - create a lightweight local clone::
1443
1444
1444 hg clone project/ project-feature/
1445 hg clone project/ project-feature/
1445
1446
1446 - clone from an absolute path on an ssh server (note double-slash)::
1447 - clone from an absolute path on an ssh server (note double-slash)::
1447
1448
1448 hg clone ssh://user@server//home/projects/alpha/
1449 hg clone ssh://user@server//home/projects/alpha/
1449
1450
1450 - do a streaming clone while checking out a specified version::
1451 - do a streaming clone while checking out a specified version::
1451
1452
1452 hg clone --stream http://server/repo -u 1.5
1453 hg clone --stream http://server/repo -u 1.5
1453
1454
1454 - create a repository without changesets after a particular revision::
1455 - create a repository without changesets after a particular revision::
1455
1456
1456 hg clone -r 04e544 experimental/ good/
1457 hg clone -r 04e544 experimental/ good/
1457
1458
1458 - clone (and track) a particular named branch::
1459 - clone (and track) a particular named branch::
1459
1460
1460 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1461 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1461
1462
1462 See :hg:`help urls` for details on specifying URLs.
1463 See :hg:`help urls` for details on specifying URLs.
1463
1464
1464 Returns 0 on success.
1465 Returns 0 on success.
1465 """
1466 """
1466 opts = pycompat.byteskwargs(opts)
1467 opts = pycompat.byteskwargs(opts)
1467 if opts.get('noupdate') and opts.get('updaterev'):
1468 if opts.get('noupdate') and opts.get('updaterev'):
1468 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1469 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1469
1470
1470 # --include/--exclude can come from narrow or sparse.
1471 # --include/--exclude can come from narrow or sparse.
1471 includepats, excludepats = None, None
1472 includepats, excludepats = None, None
1472
1473
1473 # hg.clone() differentiates between None and an empty set. So make sure
1474 # hg.clone() differentiates between None and an empty set. So make sure
1474 # patterns are sets if narrow is requested without patterns.
1475 # patterns are sets if narrow is requested without patterns.
1475 if opts.get('narrow'):
1476 if opts.get('narrow'):
1476 includepats = set()
1477 includepats = set()
1477 excludepats = set()
1478 excludepats = set()
1478
1479
1479 if opts.get('include'):
1480 if opts.get('include'):
1480 includepats = narrowspec.parsepatterns(opts.get('include'))
1481 includepats = narrowspec.parsepatterns(opts.get('include'))
1481 if opts.get('exclude'):
1482 if opts.get('exclude'):
1482 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1483 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1483
1484
1484 r = hg.clone(ui, opts, source, dest,
1485 r = hg.clone(ui, opts, source, dest,
1485 pull=opts.get('pull'),
1486 pull=opts.get('pull'),
1486 stream=opts.get('stream') or opts.get('uncompressed'),
1487 stream=opts.get('stream') or opts.get('uncompressed'),
1487 revs=opts.get('rev'),
1488 revs=opts.get('rev'),
1488 update=opts.get('updaterev') or not opts.get('noupdate'),
1489 update=opts.get('updaterev') or not opts.get('noupdate'),
1489 branch=opts.get('branch'),
1490 branch=opts.get('branch'),
1490 shareopts=opts.get('shareopts'),
1491 shareopts=opts.get('shareopts'),
1491 storeincludepats=includepats,
1492 storeincludepats=includepats,
1492 storeexcludepats=excludepats)
1493 storeexcludepats=excludepats)
1493
1494
1494 return r is None
1495 return r is None
1495
1496
1496 @command('^commit|ci',
1497 @command('^commit|ci',
1497 [('A', 'addremove', None,
1498 [('A', 'addremove', None,
1498 _('mark new/missing files as added/removed before committing')),
1499 _('mark new/missing files as added/removed before committing')),
1499 ('', 'close-branch', None,
1500 ('', 'close-branch', None,
1500 _('mark a branch head as closed')),
1501 _('mark a branch head as closed')),
1501 ('', 'amend', None, _('amend the parent of the working directory')),
1502 ('', 'amend', None, _('amend the parent of the working directory')),
1502 ('s', 'secret', None, _('use the secret phase for committing')),
1503 ('s', 'secret', None, _('use the secret phase for committing')),
1503 ('e', 'edit', None, _('invoke editor on commit messages')),
1504 ('e', 'edit', None, _('invoke editor on commit messages')),
1504 ('i', 'interactive', None, _('use interactive mode')),
1505 ('i', 'interactive', None, _('use interactive mode')),
1505 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1506 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1506 _('[OPTION]... [FILE]...'),
1507 _('[OPTION]... [FILE]...'),
1507 inferrepo=True)
1508 inferrepo=True)
1508 def commit(ui, repo, *pats, **opts):
1509 def commit(ui, repo, *pats, **opts):
1509 """commit the specified files or all outstanding changes
1510 """commit the specified files or all outstanding changes
1510
1511
1511 Commit changes to the given files into the repository. Unlike a
1512 Commit changes to the given files into the repository. Unlike a
1512 centralized SCM, this operation is a local operation. See
1513 centralized SCM, this operation is a local operation. See
1513 :hg:`push` for a way to actively distribute your changes.
1514 :hg:`push` for a way to actively distribute your changes.
1514
1515
1515 If a list of files is omitted, all changes reported by :hg:`status`
1516 If a list of files is omitted, all changes reported by :hg:`status`
1516 will be committed.
1517 will be committed.
1517
1518
1518 If you are committing the result of a merge, do not provide any
1519 If you are committing the result of a merge, do not provide any
1519 filenames or -I/-X filters.
1520 filenames or -I/-X filters.
1520
1521
1521 If no commit message is specified, Mercurial starts your
1522 If no commit message is specified, Mercurial starts your
1522 configured editor where you can enter a message. In case your
1523 configured editor where you can enter a message. In case your
1523 commit fails, you will find a backup of your message in
1524 commit fails, you will find a backup of your message in
1524 ``.hg/last-message.txt``.
1525 ``.hg/last-message.txt``.
1525
1526
1526 The --close-branch flag can be used to mark the current branch
1527 The --close-branch flag can be used to mark the current branch
1527 head closed. When all heads of a branch are closed, the branch
1528 head closed. When all heads of a branch are closed, the branch
1528 will be considered closed and no longer listed.
1529 will be considered closed and no longer listed.
1529
1530
1530 The --amend flag can be used to amend the parent of the
1531 The --amend flag can be used to amend the parent of the
1531 working directory with a new commit that contains the changes
1532 working directory with a new commit that contains the changes
1532 in the parent in addition to those currently reported by :hg:`status`,
1533 in the parent in addition to those currently reported by :hg:`status`,
1533 if there are any. The old commit is stored in a backup bundle in
1534 if there are any. The old commit is stored in a backup bundle in
1534 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1535 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1535 on how to restore it).
1536 on how to restore it).
1536
1537
1537 Message, user and date are taken from the amended commit unless
1538 Message, user and date are taken from the amended commit unless
1538 specified. When a message isn't specified on the command line,
1539 specified. When a message isn't specified on the command line,
1539 the editor will open with the message of the amended commit.
1540 the editor will open with the message of the amended commit.
1540
1541
1541 It is not possible to amend public changesets (see :hg:`help phases`)
1542 It is not possible to amend public changesets (see :hg:`help phases`)
1542 or changesets that have children.
1543 or changesets that have children.
1543
1544
1544 See :hg:`help dates` for a list of formats valid for -d/--date.
1545 See :hg:`help dates` for a list of formats valid for -d/--date.
1545
1546
1546 Returns 0 on success, 1 if nothing changed.
1547 Returns 0 on success, 1 if nothing changed.
1547
1548
1548 .. container:: verbose
1549 .. container:: verbose
1549
1550
1550 Examples:
1551 Examples:
1551
1552
1552 - commit all files ending in .py::
1553 - commit all files ending in .py::
1553
1554
1554 hg commit --include "set:**.py"
1555 hg commit --include "set:**.py"
1555
1556
1556 - commit all non-binary files::
1557 - commit all non-binary files::
1557
1558
1558 hg commit --exclude "set:binary()"
1559 hg commit --exclude "set:binary()"
1559
1560
1560 - amend the current commit and set the date to now::
1561 - amend the current commit and set the date to now::
1561
1562
1562 hg commit --amend --date now
1563 hg commit --amend --date now
1563 """
1564 """
1564 with repo.wlock(), repo.lock():
1565 with repo.wlock(), repo.lock():
1565 return _docommit(ui, repo, *pats, **opts)
1566 return _docommit(ui, repo, *pats, **opts)
1566
1567
1567 def _docommit(ui, repo, *pats, **opts):
1568 def _docommit(ui, repo, *pats, **opts):
1568 if opts.get(r'interactive'):
1569 if opts.get(r'interactive'):
1569 opts.pop(r'interactive')
1570 opts.pop(r'interactive')
1570 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1571 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1571 cmdutil.recordfilter, *pats,
1572 cmdutil.recordfilter, *pats,
1572 **opts)
1573 **opts)
1573 # ret can be 0 (no changes to record) or the value returned by
1574 # ret can be 0 (no changes to record) or the value returned by
1574 # commit(), 1 if nothing changed or None on success.
1575 # commit(), 1 if nothing changed or None on success.
1575 return 1 if ret == 0 else ret
1576 return 1 if ret == 0 else ret
1576
1577
1577 opts = pycompat.byteskwargs(opts)
1578 opts = pycompat.byteskwargs(opts)
1578 if opts.get('subrepos'):
1579 if opts.get('subrepos'):
1579 if opts.get('amend'):
1580 if opts.get('amend'):
1580 raise error.Abort(_('cannot amend with --subrepos'))
1581 raise error.Abort(_('cannot amend with --subrepos'))
1581 # Let --subrepos on the command line override config setting.
1582 # Let --subrepos on the command line override config setting.
1582 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1583 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1583
1584
1584 cmdutil.checkunfinished(repo, commit=True)
1585 cmdutil.checkunfinished(repo, commit=True)
1585
1586
1586 branch = repo[None].branch()
1587 branch = repo[None].branch()
1587 bheads = repo.branchheads(branch)
1588 bheads = repo.branchheads(branch)
1588
1589
1589 extra = {}
1590 extra = {}
1590 if opts.get('close_branch'):
1591 if opts.get('close_branch'):
1591 extra['close'] = '1'
1592 extra['close'] = '1'
1592
1593
1593 if not bheads:
1594 if not bheads:
1594 raise error.Abort(_('can only close branch heads'))
1595 raise error.Abort(_('can only close branch heads'))
1595 elif opts.get('amend'):
1596 elif opts.get('amend'):
1596 if repo[None].parents()[0].p1().branch() != branch and \
1597 if repo[None].parents()[0].p1().branch() != branch and \
1597 repo[None].parents()[0].p2().branch() != branch:
1598 repo[None].parents()[0].p2().branch() != branch:
1598 raise error.Abort(_('can only close branch heads'))
1599 raise error.Abort(_('can only close branch heads'))
1599
1600
1600 if opts.get('amend'):
1601 if opts.get('amend'):
1601 if ui.configbool('ui', 'commitsubrepos'):
1602 if ui.configbool('ui', 'commitsubrepos'):
1602 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1603 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1603
1604
1604 old = repo['.']
1605 old = repo['.']
1605 rewriteutil.precheck(repo, [old.rev()], 'amend')
1606 rewriteutil.precheck(repo, [old.rev()], 'amend')
1606
1607
1607 # Currently histedit gets confused if an amend happens while histedit
1608 # Currently histedit gets confused if an amend happens while histedit
1608 # is in progress. Since we have a checkunfinished command, we are
1609 # is in progress. Since we have a checkunfinished command, we are
1609 # temporarily honoring it.
1610 # temporarily honoring it.
1610 #
1611 #
1611 # Note: eventually this guard will be removed. Please do not expect
1612 # Note: eventually this guard will be removed. Please do not expect
1612 # this behavior to remain.
1613 # this behavior to remain.
1613 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1614 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1614 cmdutil.checkunfinished(repo)
1615 cmdutil.checkunfinished(repo)
1615
1616
1616 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1617 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1617 if node == old.node():
1618 if node == old.node():
1618 ui.status(_("nothing changed\n"))
1619 ui.status(_("nothing changed\n"))
1619 return 1
1620 return 1
1620 else:
1621 else:
1621 def commitfunc(ui, repo, message, match, opts):
1622 def commitfunc(ui, repo, message, match, opts):
1622 overrides = {}
1623 overrides = {}
1623 if opts.get('secret'):
1624 if opts.get('secret'):
1624 overrides[('phases', 'new-commit')] = 'secret'
1625 overrides[('phases', 'new-commit')] = 'secret'
1625
1626
1626 baseui = repo.baseui
1627 baseui = repo.baseui
1627 with baseui.configoverride(overrides, 'commit'):
1628 with baseui.configoverride(overrides, 'commit'):
1628 with ui.configoverride(overrides, 'commit'):
1629 with ui.configoverride(overrides, 'commit'):
1629 editform = cmdutil.mergeeditform(repo[None],
1630 editform = cmdutil.mergeeditform(repo[None],
1630 'commit.normal')
1631 'commit.normal')
1631 editor = cmdutil.getcommiteditor(
1632 editor = cmdutil.getcommiteditor(
1632 editform=editform, **pycompat.strkwargs(opts))
1633 editform=editform, **pycompat.strkwargs(opts))
1633 return repo.commit(message,
1634 return repo.commit(message,
1634 opts.get('user'),
1635 opts.get('user'),
1635 opts.get('date'),
1636 opts.get('date'),
1636 match,
1637 match,
1637 editor=editor,
1638 editor=editor,
1638 extra=extra)
1639 extra=extra)
1639
1640
1640 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1641 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1641
1642
1642 if not node:
1643 if not node:
1643 stat = cmdutil.postcommitstatus(repo, pats, opts)
1644 stat = cmdutil.postcommitstatus(repo, pats, opts)
1644 if stat[3]:
1645 if stat[3]:
1645 ui.status(_("nothing changed (%d missing files, see "
1646 ui.status(_("nothing changed (%d missing files, see "
1646 "'hg status')\n") % len(stat[3]))
1647 "'hg status')\n") % len(stat[3]))
1647 else:
1648 else:
1648 ui.status(_("nothing changed\n"))
1649 ui.status(_("nothing changed\n"))
1649 return 1
1650 return 1
1650
1651
1651 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1652 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1652
1653
1653 @command('config|showconfig|debugconfig',
1654 @command('config|showconfig|debugconfig',
1654 [('u', 'untrusted', None, _('show untrusted configuration options')),
1655 [('u', 'untrusted', None, _('show untrusted configuration options')),
1655 ('e', 'edit', None, _('edit user config')),
1656 ('e', 'edit', None, _('edit user config')),
1656 ('l', 'local', None, _('edit repository config')),
1657 ('l', 'local', None, _('edit repository config')),
1657 ('g', 'global', None, _('edit global config'))] + formatteropts,
1658 ('g', 'global', None, _('edit global config'))] + formatteropts,
1658 _('[-u] [NAME]...'),
1659 _('[-u] [NAME]...'),
1659 optionalrepo=True,
1660 optionalrepo=True,
1660 intents={INTENT_READONLY})
1661 intents={INTENT_READONLY})
1661 def config(ui, repo, *values, **opts):
1662 def config(ui, repo, *values, **opts):
1662 """show combined config settings from all hgrc files
1663 """show combined config settings from all hgrc files
1663
1664
1664 With no arguments, print names and values of all config items.
1665 With no arguments, print names and values of all config items.
1665
1666
1666 With one argument of the form section.name, print just the value
1667 With one argument of the form section.name, print just the value
1667 of that config item.
1668 of that config item.
1668
1669
1669 With multiple arguments, print names and values of all config
1670 With multiple arguments, print names and values of all config
1670 items with matching section names or section.names.
1671 items with matching section names or section.names.
1671
1672
1672 With --edit, start an editor on the user-level config file. With
1673 With --edit, start an editor on the user-level config file. With
1673 --global, edit the system-wide config file. With --local, edit the
1674 --global, edit the system-wide config file. With --local, edit the
1674 repository-level config file.
1675 repository-level config file.
1675
1676
1676 With --debug, the source (filename and line number) is printed
1677 With --debug, the source (filename and line number) is printed
1677 for each config item.
1678 for each config item.
1678
1679
1679 See :hg:`help config` for more information about config files.
1680 See :hg:`help config` for more information about config files.
1680
1681
1681 Returns 0 on success, 1 if NAME does not exist.
1682 Returns 0 on success, 1 if NAME does not exist.
1682
1683
1683 """
1684 """
1684
1685
1685 opts = pycompat.byteskwargs(opts)
1686 opts = pycompat.byteskwargs(opts)
1686 if opts.get('edit') or opts.get('local') or opts.get('global'):
1687 if opts.get('edit') or opts.get('local') or opts.get('global'):
1687 if opts.get('local') and opts.get('global'):
1688 if opts.get('local') and opts.get('global'):
1688 raise error.Abort(_("can't use --local and --global together"))
1689 raise error.Abort(_("can't use --local and --global together"))
1689
1690
1690 if opts.get('local'):
1691 if opts.get('local'):
1691 if not repo:
1692 if not repo:
1692 raise error.Abort(_("can't use --local outside a repository"))
1693 raise error.Abort(_("can't use --local outside a repository"))
1693 paths = [repo.vfs.join('hgrc')]
1694 paths = [repo.vfs.join('hgrc')]
1694 elif opts.get('global'):
1695 elif opts.get('global'):
1695 paths = rcutil.systemrcpath()
1696 paths = rcutil.systemrcpath()
1696 else:
1697 else:
1697 paths = rcutil.userrcpath()
1698 paths = rcutil.userrcpath()
1698
1699
1699 for f in paths:
1700 for f in paths:
1700 if os.path.exists(f):
1701 if os.path.exists(f):
1701 break
1702 break
1702 else:
1703 else:
1703 if opts.get('global'):
1704 if opts.get('global'):
1704 samplehgrc = uimod.samplehgrcs['global']
1705 samplehgrc = uimod.samplehgrcs['global']
1705 elif opts.get('local'):
1706 elif opts.get('local'):
1706 samplehgrc = uimod.samplehgrcs['local']
1707 samplehgrc = uimod.samplehgrcs['local']
1707 else:
1708 else:
1708 samplehgrc = uimod.samplehgrcs['user']
1709 samplehgrc = uimod.samplehgrcs['user']
1709
1710
1710 f = paths[0]
1711 f = paths[0]
1711 fp = open(f, "wb")
1712 fp = open(f, "wb")
1712 fp.write(util.tonativeeol(samplehgrc))
1713 fp.write(util.tonativeeol(samplehgrc))
1713 fp.close()
1714 fp.close()
1714
1715
1715 editor = ui.geteditor()
1716 editor = ui.geteditor()
1716 ui.system("%s \"%s\"" % (editor, f),
1717 ui.system("%s \"%s\"" % (editor, f),
1717 onerr=error.Abort, errprefix=_("edit failed"),
1718 onerr=error.Abort, errprefix=_("edit failed"),
1718 blockedtag='config_edit')
1719 blockedtag='config_edit')
1719 return
1720 return
1720 ui.pager('config')
1721 ui.pager('config')
1721 fm = ui.formatter('config', opts)
1722 fm = ui.formatter('config', opts)
1722 for t, f in rcutil.rccomponents():
1723 for t, f in rcutil.rccomponents():
1723 if t == 'path':
1724 if t == 'path':
1724 ui.debug('read config from: %s\n' % f)
1725 ui.debug('read config from: %s\n' % f)
1725 elif t == 'items':
1726 elif t == 'items':
1726 for section, name, value, source in f:
1727 for section, name, value, source in f:
1727 ui.debug('set config by: %s\n' % source)
1728 ui.debug('set config by: %s\n' % source)
1728 else:
1729 else:
1729 raise error.ProgrammingError('unknown rctype: %s' % t)
1730 raise error.ProgrammingError('unknown rctype: %s' % t)
1730 untrusted = bool(opts.get('untrusted'))
1731 untrusted = bool(opts.get('untrusted'))
1731
1732
1732 selsections = selentries = []
1733 selsections = selentries = []
1733 if values:
1734 if values:
1734 selsections = [v for v in values if '.' not in v]
1735 selsections = [v for v in values if '.' not in v]
1735 selentries = [v for v in values if '.' in v]
1736 selentries = [v for v in values if '.' in v]
1736 uniquesel = (len(selentries) == 1 and not selsections)
1737 uniquesel = (len(selentries) == 1 and not selsections)
1737 selsections = set(selsections)
1738 selsections = set(selsections)
1738 selentries = set(selentries)
1739 selentries = set(selentries)
1739
1740
1740 matched = False
1741 matched = False
1741 for section, name, value in ui.walkconfig(untrusted=untrusted):
1742 for section, name, value in ui.walkconfig(untrusted=untrusted):
1742 source = ui.configsource(section, name, untrusted)
1743 source = ui.configsource(section, name, untrusted)
1743 value = pycompat.bytestr(value)
1744 value = pycompat.bytestr(value)
1744 if fm.isplain():
1745 if fm.isplain():
1745 source = source or 'none'
1746 source = source or 'none'
1746 value = value.replace('\n', '\\n')
1747 value = value.replace('\n', '\\n')
1747 entryname = section + '.' + name
1748 entryname = section + '.' + name
1748 if values and not (section in selsections or entryname in selentries):
1749 if values and not (section in selsections or entryname in selentries):
1749 continue
1750 continue
1750 fm.startitem()
1751 fm.startitem()
1751 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1752 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1752 if uniquesel:
1753 if uniquesel:
1753 fm.data(name=entryname)
1754 fm.data(name=entryname)
1754 fm.write('value', '%s\n', value)
1755 fm.write('value', '%s\n', value)
1755 else:
1756 else:
1756 fm.write('name value', '%s=%s\n', entryname, value)
1757 fm.write('name value', '%s=%s\n', entryname, value)
1757 matched = True
1758 matched = True
1758 fm.end()
1759 fm.end()
1759 if matched:
1760 if matched:
1760 return 0
1761 return 0
1761 return 1
1762 return 1
1762
1763
1763 @command('copy|cp',
1764 @command('copy|cp',
1764 [('A', 'after', None, _('record a copy that has already occurred')),
1765 [('A', 'after', None, _('record a copy that has already occurred')),
1765 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1766 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1766 ] + walkopts + dryrunopts,
1767 ] + walkopts + dryrunopts,
1767 _('[OPTION]... [SOURCE]... DEST'))
1768 _('[OPTION]... [SOURCE]... DEST'))
1768 def copy(ui, repo, *pats, **opts):
1769 def copy(ui, repo, *pats, **opts):
1769 """mark files as copied for the next commit
1770 """mark files as copied for the next commit
1770
1771
1771 Mark dest as having copies of source files. If dest is a
1772 Mark dest as having copies of source files. If dest is a
1772 directory, copies are put in that directory. If dest is a file,
1773 directory, copies are put in that directory. If dest is a file,
1773 the source must be a single file.
1774 the source must be a single file.
1774
1775
1775 By default, this command copies the contents of files as they
1776 By default, this command copies the contents of files as they
1776 exist in the working directory. If invoked with -A/--after, the
1777 exist in the working directory. If invoked with -A/--after, the
1777 operation is recorded, but no copying is performed.
1778 operation is recorded, but no copying is performed.
1778
1779
1779 This command takes effect with the next commit. To undo a copy
1780 This command takes effect with the next commit. To undo a copy
1780 before that, see :hg:`revert`.
1781 before that, see :hg:`revert`.
1781
1782
1782 Returns 0 on success, 1 if errors are encountered.
1783 Returns 0 on success, 1 if errors are encountered.
1783 """
1784 """
1784 opts = pycompat.byteskwargs(opts)
1785 opts = pycompat.byteskwargs(opts)
1785 with repo.wlock(False):
1786 with repo.wlock(False):
1786 return cmdutil.copy(ui, repo, pats, opts)
1787 return cmdutil.copy(ui, repo, pats, opts)
1787
1788
1788 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1789 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1789 def debugcommands(ui, cmd='', *args):
1790 def debugcommands(ui, cmd='', *args):
1790 """list all available commands and options"""
1791 """list all available commands and options"""
1791 for cmd, vals in sorted(table.iteritems()):
1792 for cmd, vals in sorted(table.iteritems()):
1792 cmd = cmd.split('|')[0].strip('^')
1793 cmd = cmd.split('|')[0].strip('^')
1793 opts = ', '.join([i[1] for i in vals[1]])
1794 opts = ', '.join([i[1] for i in vals[1]])
1794 ui.write('%s: %s\n' % (cmd, opts))
1795 ui.write('%s: %s\n' % (cmd, opts))
1795
1796
1796 @command('debugcomplete',
1797 @command('debugcomplete',
1797 [('o', 'options', None, _('show the command options'))],
1798 [('o', 'options', None, _('show the command options'))],
1798 _('[-o] CMD'),
1799 _('[-o] CMD'),
1799 norepo=True)
1800 norepo=True)
1800 def debugcomplete(ui, cmd='', **opts):
1801 def debugcomplete(ui, cmd='', **opts):
1801 """returns the completion list associated with the given command"""
1802 """returns the completion list associated with the given command"""
1802
1803
1803 if opts.get(r'options'):
1804 if opts.get(r'options'):
1804 options = []
1805 options = []
1805 otables = [globalopts]
1806 otables = [globalopts]
1806 if cmd:
1807 if cmd:
1807 aliases, entry = cmdutil.findcmd(cmd, table, False)
1808 aliases, entry = cmdutil.findcmd(cmd, table, False)
1808 otables.append(entry[1])
1809 otables.append(entry[1])
1809 for t in otables:
1810 for t in otables:
1810 for o in t:
1811 for o in t:
1811 if "(DEPRECATED)" in o[3]:
1812 if "(DEPRECATED)" in o[3]:
1812 continue
1813 continue
1813 if o[0]:
1814 if o[0]:
1814 options.append('-%s' % o[0])
1815 options.append('-%s' % o[0])
1815 options.append('--%s' % o[1])
1816 options.append('--%s' % o[1])
1816 ui.write("%s\n" % "\n".join(options))
1817 ui.write("%s\n" % "\n".join(options))
1817 return
1818 return
1818
1819
1819 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1820 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1820 if ui.verbose:
1821 if ui.verbose:
1821 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1822 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1822 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1823 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1823
1824
1824 @command('^diff',
1825 @command('^diff',
1825 [('r', 'rev', [], _('revision'), _('REV')),
1826 [('r', 'rev', [], _('revision'), _('REV')),
1826 ('c', 'change', '', _('change made by revision'), _('REV'))
1827 ('c', 'change', '', _('change made by revision'), _('REV'))
1827 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1828 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1828 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1829 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1829 inferrepo=True,
1830 inferrepo=True,
1830 intents={INTENT_READONLY})
1831 intents={INTENT_READONLY})
1831 def diff(ui, repo, *pats, **opts):
1832 def diff(ui, repo, *pats, **opts):
1832 """diff repository (or selected files)
1833 """diff repository (or selected files)
1833
1834
1834 Show differences between revisions for the specified files.
1835 Show differences between revisions for the specified files.
1835
1836
1836 Differences between files are shown using the unified diff format.
1837 Differences between files are shown using the unified diff format.
1837
1838
1838 .. note::
1839 .. note::
1839
1840
1840 :hg:`diff` may generate unexpected results for merges, as it will
1841 :hg:`diff` may generate unexpected results for merges, as it will
1841 default to comparing against the working directory's first
1842 default to comparing against the working directory's first
1842 parent changeset if no revisions are specified.
1843 parent changeset if no revisions are specified.
1843
1844
1844 When two revision arguments are given, then changes are shown
1845 When two revision arguments are given, then changes are shown
1845 between those revisions. If only one revision is specified then
1846 between those revisions. If only one revision is specified then
1846 that revision is compared to the working directory, and, when no
1847 that revision is compared to the working directory, and, when no
1847 revisions are specified, the working directory files are compared
1848 revisions are specified, the working directory files are compared
1848 to its first parent.
1849 to its first parent.
1849
1850
1850 Alternatively you can specify -c/--change with a revision to see
1851 Alternatively you can specify -c/--change with a revision to see
1851 the changes in that changeset relative to its first parent.
1852 the changes in that changeset relative to its first parent.
1852
1853
1853 Without the -a/--text option, diff will avoid generating diffs of
1854 Without the -a/--text option, diff will avoid generating diffs of
1854 files it detects as binary. With -a, diff will generate a diff
1855 files it detects as binary. With -a, diff will generate a diff
1855 anyway, probably with undesirable results.
1856 anyway, probably with undesirable results.
1856
1857
1857 Use the -g/--git option to generate diffs in the git extended diff
1858 Use the -g/--git option to generate diffs in the git extended diff
1858 format. For more information, read :hg:`help diffs`.
1859 format. For more information, read :hg:`help diffs`.
1859
1860
1860 .. container:: verbose
1861 .. container:: verbose
1861
1862
1862 Examples:
1863 Examples:
1863
1864
1864 - compare a file in the current working directory to its parent::
1865 - compare a file in the current working directory to its parent::
1865
1866
1866 hg diff foo.c
1867 hg diff foo.c
1867
1868
1868 - compare two historical versions of a directory, with rename info::
1869 - compare two historical versions of a directory, with rename info::
1869
1870
1870 hg diff --git -r 1.0:1.2 lib/
1871 hg diff --git -r 1.0:1.2 lib/
1871
1872
1872 - get change stats relative to the last change on some date::
1873 - get change stats relative to the last change on some date::
1873
1874
1874 hg diff --stat -r "date('may 2')"
1875 hg diff --stat -r "date('may 2')"
1875
1876
1876 - diff all newly-added files that contain a keyword::
1877 - diff all newly-added files that contain a keyword::
1877
1878
1878 hg diff "set:added() and grep(GNU)"
1879 hg diff "set:added() and grep(GNU)"
1879
1880
1880 - compare a revision and its parents::
1881 - compare a revision and its parents::
1881
1882
1882 hg diff -c 9353 # compare against first parent
1883 hg diff -c 9353 # compare against first parent
1883 hg diff -r 9353^:9353 # same using revset syntax
1884 hg diff -r 9353^:9353 # same using revset syntax
1884 hg diff -r 9353^2:9353 # compare against the second parent
1885 hg diff -r 9353^2:9353 # compare against the second parent
1885
1886
1886 Returns 0 on success.
1887 Returns 0 on success.
1887 """
1888 """
1888
1889
1889 opts = pycompat.byteskwargs(opts)
1890 opts = pycompat.byteskwargs(opts)
1890 revs = opts.get('rev')
1891 revs = opts.get('rev')
1891 change = opts.get('change')
1892 change = opts.get('change')
1892 stat = opts.get('stat')
1893 stat = opts.get('stat')
1893 reverse = opts.get('reverse')
1894 reverse = opts.get('reverse')
1894
1895
1895 if revs and change:
1896 if revs and change:
1896 msg = _('cannot specify --rev and --change at the same time')
1897 msg = _('cannot specify --rev and --change at the same time')
1897 raise error.Abort(msg)
1898 raise error.Abort(msg)
1898 elif change:
1899 elif change:
1899 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1900 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1900 ctx2 = scmutil.revsingle(repo, change, None)
1901 ctx2 = scmutil.revsingle(repo, change, None)
1901 ctx1 = ctx2.p1()
1902 ctx1 = ctx2.p1()
1902 else:
1903 else:
1903 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1904 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1904 ctx1, ctx2 = scmutil.revpair(repo, revs)
1905 ctx1, ctx2 = scmutil.revpair(repo, revs)
1905 node1, node2 = ctx1.node(), ctx2.node()
1906 node1, node2 = ctx1.node(), ctx2.node()
1906
1907
1907 if reverse:
1908 if reverse:
1908 node1, node2 = node2, node1
1909 node1, node2 = node2, node1
1909
1910
1910 diffopts = patch.diffallopts(ui, opts)
1911 diffopts = patch.diffallopts(ui, opts)
1911 m = scmutil.match(ctx2, pats, opts)
1912 m = scmutil.match(ctx2, pats, opts)
1913 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1912 ui.pager('diff')
1914 ui.pager('diff')
1913 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1915 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1914 listsubrepos=opts.get('subrepos'),
1916 listsubrepos=opts.get('subrepos'),
1915 root=opts.get('root'))
1917 root=opts.get('root'))
1916
1918
1917 @command('^export',
1919 @command('^export',
1918 [('B', 'bookmark', '',
1920 [('B', 'bookmark', '',
1919 _('export changes only reachable by given bookmark')),
1921 _('export changes only reachable by given bookmark')),
1920 ('o', 'output', '',
1922 ('o', 'output', '',
1921 _('print output to file with formatted name'), _('FORMAT')),
1923 _('print output to file with formatted name'), _('FORMAT')),
1922 ('', 'switch-parent', None, _('diff against the second parent')),
1924 ('', 'switch-parent', None, _('diff against the second parent')),
1923 ('r', 'rev', [], _('revisions to export'), _('REV')),
1925 ('r', 'rev', [], _('revisions to export'), _('REV')),
1924 ] + diffopts + formatteropts,
1926 ] + diffopts + formatteropts,
1925 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1927 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1926 intents={INTENT_READONLY})
1928 intents={INTENT_READONLY})
1927 def export(ui, repo, *changesets, **opts):
1929 def export(ui, repo, *changesets, **opts):
1928 """dump the header and diffs for one or more changesets
1930 """dump the header and diffs for one or more changesets
1929
1931
1930 Print the changeset header and diffs for one or more revisions.
1932 Print the changeset header and diffs for one or more revisions.
1931 If no revision is given, the parent of the working directory is used.
1933 If no revision is given, the parent of the working directory is used.
1932
1934
1933 The information shown in the changeset header is: author, date,
1935 The information shown in the changeset header is: author, date,
1934 branch name (if non-default), changeset hash, parent(s) and commit
1936 branch name (if non-default), changeset hash, parent(s) and commit
1935 comment.
1937 comment.
1936
1938
1937 .. note::
1939 .. note::
1938
1940
1939 :hg:`export` may generate unexpected diff output for merge
1941 :hg:`export` may generate unexpected diff output for merge
1940 changesets, as it will compare the merge changeset against its
1942 changesets, as it will compare the merge changeset against its
1941 first parent only.
1943 first parent only.
1942
1944
1943 Output may be to a file, in which case the name of the file is
1945 Output may be to a file, in which case the name of the file is
1944 given using a template string. See :hg:`help templates`. In addition
1946 given using a template string. See :hg:`help templates`. In addition
1945 to the common template keywords, the following formatting rules are
1947 to the common template keywords, the following formatting rules are
1946 supported:
1948 supported:
1947
1949
1948 :``%%``: literal "%" character
1950 :``%%``: literal "%" character
1949 :``%H``: changeset hash (40 hexadecimal digits)
1951 :``%H``: changeset hash (40 hexadecimal digits)
1950 :``%N``: number of patches being generated
1952 :``%N``: number of patches being generated
1951 :``%R``: changeset revision number
1953 :``%R``: changeset revision number
1952 :``%b``: basename of the exporting repository
1954 :``%b``: basename of the exporting repository
1953 :``%h``: short-form changeset hash (12 hexadecimal digits)
1955 :``%h``: short-form changeset hash (12 hexadecimal digits)
1954 :``%m``: first line of the commit message (only alphanumeric characters)
1956 :``%m``: first line of the commit message (only alphanumeric characters)
1955 :``%n``: zero-padded sequence number, starting at 1
1957 :``%n``: zero-padded sequence number, starting at 1
1956 :``%r``: zero-padded changeset revision number
1958 :``%r``: zero-padded changeset revision number
1957 :``\\``: literal "\\" character
1959 :``\\``: literal "\\" character
1958
1960
1959 Without the -a/--text option, export will avoid generating diffs
1961 Without the -a/--text option, export will avoid generating diffs
1960 of files it detects as binary. With -a, export will generate a
1962 of files it detects as binary. With -a, export will generate a
1961 diff anyway, probably with undesirable results.
1963 diff anyway, probably with undesirable results.
1962
1964
1963 With -B/--bookmark changesets reachable by the given bookmark are
1965 With -B/--bookmark changesets reachable by the given bookmark are
1964 selected.
1966 selected.
1965
1967
1966 Use the -g/--git option to generate diffs in the git extended diff
1968 Use the -g/--git option to generate diffs in the git extended diff
1967 format. See :hg:`help diffs` for more information.
1969 format. See :hg:`help diffs` for more information.
1968
1970
1969 With the --switch-parent option, the diff will be against the
1971 With the --switch-parent option, the diff will be against the
1970 second parent. It can be useful to review a merge.
1972 second parent. It can be useful to review a merge.
1971
1973
1972 .. container:: verbose
1974 .. container:: verbose
1973
1975
1974 Examples:
1976 Examples:
1975
1977
1976 - use export and import to transplant a bugfix to the current
1978 - use export and import to transplant a bugfix to the current
1977 branch::
1979 branch::
1978
1980
1979 hg export -r 9353 | hg import -
1981 hg export -r 9353 | hg import -
1980
1982
1981 - export all the changesets between two revisions to a file with
1983 - export all the changesets between two revisions to a file with
1982 rename information::
1984 rename information::
1983
1985
1984 hg export --git -r 123:150 > changes.txt
1986 hg export --git -r 123:150 > changes.txt
1985
1987
1986 - split outgoing changes into a series of patches with
1988 - split outgoing changes into a series of patches with
1987 descriptive names::
1989 descriptive names::
1988
1990
1989 hg export -r "outgoing()" -o "%n-%m.patch"
1991 hg export -r "outgoing()" -o "%n-%m.patch"
1990
1992
1991 Returns 0 on success.
1993 Returns 0 on success.
1992 """
1994 """
1993 opts = pycompat.byteskwargs(opts)
1995 opts = pycompat.byteskwargs(opts)
1994 bookmark = opts.get('bookmark')
1996 bookmark = opts.get('bookmark')
1995 changesets += tuple(opts.get('rev', []))
1997 changesets += tuple(opts.get('rev', []))
1996
1998
1997 if bookmark and changesets:
1999 if bookmark and changesets:
1998 raise error.Abort(_("-r and -B are mutually exclusive"))
2000 raise error.Abort(_("-r and -B are mutually exclusive"))
1999
2001
2000 if bookmark:
2002 if bookmark:
2001 if bookmark not in repo._bookmarks:
2003 if bookmark not in repo._bookmarks:
2002 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2004 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2003
2005
2004 revs = scmutil.bookmarkrevs(repo, bookmark)
2006 revs = scmutil.bookmarkrevs(repo, bookmark)
2005 else:
2007 else:
2006 if not changesets:
2008 if not changesets:
2007 changesets = ['.']
2009 changesets = ['.']
2008
2010
2009 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2011 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2010 revs = scmutil.revrange(repo, changesets)
2012 revs = scmutil.revrange(repo, changesets)
2011
2013
2012 if not revs:
2014 if not revs:
2013 raise error.Abort(_("export requires at least one changeset"))
2015 raise error.Abort(_("export requires at least one changeset"))
2014 if len(revs) > 1:
2016 if len(revs) > 1:
2015 ui.note(_('exporting patches:\n'))
2017 ui.note(_('exporting patches:\n'))
2016 else:
2018 else:
2017 ui.note(_('exporting patch:\n'))
2019 ui.note(_('exporting patch:\n'))
2018
2020
2019 fntemplate = opts.get('output')
2021 fntemplate = opts.get('output')
2020 if cmdutil.isstdiofilename(fntemplate):
2022 if cmdutil.isstdiofilename(fntemplate):
2021 fntemplate = ''
2023 fntemplate = ''
2022
2024
2023 if fntemplate:
2025 if fntemplate:
2024 fm = formatter.nullformatter(ui, 'export', opts)
2026 fm = formatter.nullformatter(ui, 'export', opts)
2025 else:
2027 else:
2026 ui.pager('export')
2028 ui.pager('export')
2027 fm = ui.formatter('export', opts)
2029 fm = ui.formatter('export', opts)
2028 with fm:
2030 with fm:
2029 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2031 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2030 switch_parent=opts.get('switch_parent'),
2032 switch_parent=opts.get('switch_parent'),
2031 opts=patch.diffallopts(ui, opts))
2033 opts=patch.diffallopts(ui, opts))
2032
2034
2033 @command('files',
2035 @command('files',
2034 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2036 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2035 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2037 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2036 ] + walkopts + formatteropts + subrepoopts,
2038 ] + walkopts + formatteropts + subrepoopts,
2037 _('[OPTION]... [FILE]...'),
2039 _('[OPTION]... [FILE]...'),
2038 intents={INTENT_READONLY})
2040 intents={INTENT_READONLY})
2039 def files(ui, repo, *pats, **opts):
2041 def files(ui, repo, *pats, **opts):
2040 """list tracked files
2042 """list tracked files
2041
2043
2042 Print files under Mercurial control in the working directory or
2044 Print files under Mercurial control in the working directory or
2043 specified revision for given files (excluding removed files).
2045 specified revision for given files (excluding removed files).
2044 Files can be specified as filenames or filesets.
2046 Files can be specified as filenames or filesets.
2045
2047
2046 If no files are given to match, this command prints the names
2048 If no files are given to match, this command prints the names
2047 of all files under Mercurial control.
2049 of all files under Mercurial control.
2048
2050
2049 .. container:: verbose
2051 .. container:: verbose
2050
2052
2051 Examples:
2053 Examples:
2052
2054
2053 - list all files under the current directory::
2055 - list all files under the current directory::
2054
2056
2055 hg files .
2057 hg files .
2056
2058
2057 - shows sizes and flags for current revision::
2059 - shows sizes and flags for current revision::
2058
2060
2059 hg files -vr .
2061 hg files -vr .
2060
2062
2061 - list all files named README::
2063 - list all files named README::
2062
2064
2063 hg files -I "**/README"
2065 hg files -I "**/README"
2064
2066
2065 - list all binary files::
2067 - list all binary files::
2066
2068
2067 hg files "set:binary()"
2069 hg files "set:binary()"
2068
2070
2069 - find files containing a regular expression::
2071 - find files containing a regular expression::
2070
2072
2071 hg files "set:grep('bob')"
2073 hg files "set:grep('bob')"
2072
2074
2073 - search tracked file contents with xargs and grep::
2075 - search tracked file contents with xargs and grep::
2074
2076
2075 hg files -0 | xargs -0 grep foo
2077 hg files -0 | xargs -0 grep foo
2076
2078
2077 See :hg:`help patterns` and :hg:`help filesets` for more information
2079 See :hg:`help patterns` and :hg:`help filesets` for more information
2078 on specifying file patterns.
2080 on specifying file patterns.
2079
2081
2080 Returns 0 if a match is found, 1 otherwise.
2082 Returns 0 if a match is found, 1 otherwise.
2081
2083
2082 """
2084 """
2083
2085
2084 opts = pycompat.byteskwargs(opts)
2086 opts = pycompat.byteskwargs(opts)
2085 rev = opts.get('rev')
2087 rev = opts.get('rev')
2086 if rev:
2088 if rev:
2087 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2089 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2088 ctx = scmutil.revsingle(repo, rev, None)
2090 ctx = scmutil.revsingle(repo, rev, None)
2089
2091
2090 end = '\n'
2092 end = '\n'
2091 if opts.get('print0'):
2093 if opts.get('print0'):
2092 end = '\0'
2094 end = '\0'
2093 fmt = '%s' + end
2095 fmt = '%s' + end
2094
2096
2095 m = scmutil.match(ctx, pats, opts)
2097 m = scmutil.match(ctx, pats, opts)
2096 ui.pager('files')
2098 ui.pager('files')
2097 with ui.formatter('files', opts) as fm:
2099 with ui.formatter('files', opts) as fm:
2098 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2100 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2099
2101
2100 @command(
2102 @command(
2101 '^forget',
2103 '^forget',
2102 [('i', 'interactive', None, _('use interactive mode')),
2104 [('i', 'interactive', None, _('use interactive mode')),
2103 ] + walkopts + dryrunopts,
2105 ] + walkopts + dryrunopts,
2104 _('[OPTION]... FILE...'), inferrepo=True)
2106 _('[OPTION]... FILE...'), inferrepo=True)
2105 def forget(ui, repo, *pats, **opts):
2107 def forget(ui, repo, *pats, **opts):
2106 """forget the specified files on the next commit
2108 """forget the specified files on the next commit
2107
2109
2108 Mark the specified files so they will no longer be tracked
2110 Mark the specified files so they will no longer be tracked
2109 after the next commit.
2111 after the next commit.
2110
2112
2111 This only removes files from the current branch, not from the
2113 This only removes files from the current branch, not from the
2112 entire project history, and it does not delete them from the
2114 entire project history, and it does not delete them from the
2113 working directory.
2115 working directory.
2114
2116
2115 To delete the file from the working directory, see :hg:`remove`.
2117 To delete the file from the working directory, see :hg:`remove`.
2116
2118
2117 To undo a forget before the next commit, see :hg:`add`.
2119 To undo a forget before the next commit, see :hg:`add`.
2118
2120
2119 .. container:: verbose
2121 .. container:: verbose
2120
2122
2121 Examples:
2123 Examples:
2122
2124
2123 - forget newly-added binary files::
2125 - forget newly-added binary files::
2124
2126
2125 hg forget "set:added() and binary()"
2127 hg forget "set:added() and binary()"
2126
2128
2127 - forget files that would be excluded by .hgignore::
2129 - forget files that would be excluded by .hgignore::
2128
2130
2129 hg forget "set:hgignore()"
2131 hg forget "set:hgignore()"
2130
2132
2131 Returns 0 on success.
2133 Returns 0 on success.
2132 """
2134 """
2133
2135
2134 opts = pycompat.byteskwargs(opts)
2136 opts = pycompat.byteskwargs(opts)
2135 if not pats:
2137 if not pats:
2136 raise error.Abort(_('no files specified'))
2138 raise error.Abort(_('no files specified'))
2137
2139
2138 m = scmutil.match(repo[None], pats, opts)
2140 m = scmutil.match(repo[None], pats, opts)
2139 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2141 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2140 rejected = cmdutil.forget(ui, repo, m, prefix="",
2142 rejected = cmdutil.forget(ui, repo, m, prefix="",
2141 explicitonly=False, dryrun=dryrun,
2143 explicitonly=False, dryrun=dryrun,
2142 interactive=interactive)[0]
2144 interactive=interactive)[0]
2143 return rejected and 1 or 0
2145 return rejected and 1 or 0
2144
2146
2145 @command(
2147 @command(
2146 'graft',
2148 'graft',
2147 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2149 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2148 ('c', 'continue', False, _('resume interrupted graft')),
2150 ('c', 'continue', False, _('resume interrupted graft')),
2149 ('', 'stop', False, _('stop interrupted graft')),
2151 ('', 'stop', False, _('stop interrupted graft')),
2150 ('', 'abort', False, _('abort interrupted graft')),
2152 ('', 'abort', False, _('abort interrupted graft')),
2151 ('e', 'edit', False, _('invoke editor on commit messages')),
2153 ('e', 'edit', False, _('invoke editor on commit messages')),
2152 ('', 'log', None, _('append graft info to log message')),
2154 ('', 'log', None, _('append graft info to log message')),
2153 ('', 'no-commit', None,
2155 ('', 'no-commit', None,
2154 _("don't commit, just apply the changes in working directory")),
2156 _("don't commit, just apply the changes in working directory")),
2155 ('f', 'force', False, _('force graft')),
2157 ('f', 'force', False, _('force graft')),
2156 ('D', 'currentdate', False,
2158 ('D', 'currentdate', False,
2157 _('record the current date as commit date')),
2159 _('record the current date as commit date')),
2158 ('U', 'currentuser', False,
2160 ('U', 'currentuser', False,
2159 _('record the current user as committer'), _('DATE'))]
2161 _('record the current user as committer'), _('DATE'))]
2160 + commitopts2 + mergetoolopts + dryrunopts,
2162 + commitopts2 + mergetoolopts + dryrunopts,
2161 _('[OPTION]... [-r REV]... REV...'))
2163 _('[OPTION]... [-r REV]... REV...'))
2162 def graft(ui, repo, *revs, **opts):
2164 def graft(ui, repo, *revs, **opts):
2163 '''copy changes from other branches onto the current branch
2165 '''copy changes from other branches onto the current branch
2164
2166
2165 This command uses Mercurial's merge logic to copy individual
2167 This command uses Mercurial's merge logic to copy individual
2166 changes from other branches without merging branches in the
2168 changes from other branches without merging branches in the
2167 history graph. This is sometimes known as 'backporting' or
2169 history graph. This is sometimes known as 'backporting' or
2168 'cherry-picking'. By default, graft will copy user, date, and
2170 'cherry-picking'. By default, graft will copy user, date, and
2169 description from the source changesets.
2171 description from the source changesets.
2170
2172
2171 Changesets that are ancestors of the current revision, that have
2173 Changesets that are ancestors of the current revision, that have
2172 already been grafted, or that are merges will be skipped.
2174 already been grafted, or that are merges will be skipped.
2173
2175
2174 If --log is specified, log messages will have a comment appended
2176 If --log is specified, log messages will have a comment appended
2175 of the form::
2177 of the form::
2176
2178
2177 (grafted from CHANGESETHASH)
2179 (grafted from CHANGESETHASH)
2178
2180
2179 If --force is specified, revisions will be grafted even if they
2181 If --force is specified, revisions will be grafted even if they
2180 are already ancestors of, or have been grafted to, the destination.
2182 are already ancestors of, or have been grafted to, the destination.
2181 This is useful when the revisions have since been backed out.
2183 This is useful when the revisions have since been backed out.
2182
2184
2183 If a graft merge results in conflicts, the graft process is
2185 If a graft merge results in conflicts, the graft process is
2184 interrupted so that the current merge can be manually resolved.
2186 interrupted so that the current merge can be manually resolved.
2185 Once all conflicts are addressed, the graft process can be
2187 Once all conflicts are addressed, the graft process can be
2186 continued with the -c/--continue option.
2188 continued with the -c/--continue option.
2187
2189
2188 The -c/--continue option reapplies all the earlier options.
2190 The -c/--continue option reapplies all the earlier options.
2189
2191
2190 .. container:: verbose
2192 .. container:: verbose
2191
2193
2192 Examples:
2194 Examples:
2193
2195
2194 - copy a single change to the stable branch and edit its description::
2196 - copy a single change to the stable branch and edit its description::
2195
2197
2196 hg update stable
2198 hg update stable
2197 hg graft --edit 9393
2199 hg graft --edit 9393
2198
2200
2199 - graft a range of changesets with one exception, updating dates::
2201 - graft a range of changesets with one exception, updating dates::
2200
2202
2201 hg graft -D "2085::2093 and not 2091"
2203 hg graft -D "2085::2093 and not 2091"
2202
2204
2203 - continue a graft after resolving conflicts::
2205 - continue a graft after resolving conflicts::
2204
2206
2205 hg graft -c
2207 hg graft -c
2206
2208
2207 - show the source of a grafted changeset::
2209 - show the source of a grafted changeset::
2208
2210
2209 hg log --debug -r .
2211 hg log --debug -r .
2210
2212
2211 - show revisions sorted by date::
2213 - show revisions sorted by date::
2212
2214
2213 hg log -r "sort(all(), date)"
2215 hg log -r "sort(all(), date)"
2214
2216
2215 See :hg:`help revisions` for more about specifying revisions.
2217 See :hg:`help revisions` for more about specifying revisions.
2216
2218
2217 Returns 0 on successful completion.
2219 Returns 0 on successful completion.
2218 '''
2220 '''
2219 with repo.wlock():
2221 with repo.wlock():
2220 return _dograft(ui, repo, *revs, **opts)
2222 return _dograft(ui, repo, *revs, **opts)
2221
2223
2222 def _dograft(ui, repo, *revs, **opts):
2224 def _dograft(ui, repo, *revs, **opts):
2223 opts = pycompat.byteskwargs(opts)
2225 opts = pycompat.byteskwargs(opts)
2224 if revs and opts.get('rev'):
2226 if revs and opts.get('rev'):
2225 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2227 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2226 'revision ordering!\n'))
2228 'revision ordering!\n'))
2227
2229
2228 revs = list(revs)
2230 revs = list(revs)
2229 revs.extend(opts.get('rev'))
2231 revs.extend(opts.get('rev'))
2230 # a dict of data to be stored in state file
2232 # a dict of data to be stored in state file
2231 statedata = {}
2233 statedata = {}
2232 # list of new nodes created by ongoing graft
2234 # list of new nodes created by ongoing graft
2233 statedata['newnodes'] = []
2235 statedata['newnodes'] = []
2234
2236
2235 if not opts.get('user') and opts.get('currentuser'):
2237 if not opts.get('user') and opts.get('currentuser'):
2236 opts['user'] = ui.username()
2238 opts['user'] = ui.username()
2237 if not opts.get('date') and opts.get('currentdate'):
2239 if not opts.get('date') and opts.get('currentdate'):
2238 opts['date'] = "%d %d" % dateutil.makedate()
2240 opts['date'] = "%d %d" % dateutil.makedate()
2239
2241
2240 editor = cmdutil.getcommiteditor(editform='graft',
2242 editor = cmdutil.getcommiteditor(editform='graft',
2241 **pycompat.strkwargs(opts))
2243 **pycompat.strkwargs(opts))
2242
2244
2243 cont = False
2245 cont = False
2244 if opts.get('no_commit'):
2246 if opts.get('no_commit'):
2245 if opts.get('edit'):
2247 if opts.get('edit'):
2246 raise error.Abort(_("cannot specify --no-commit and "
2248 raise error.Abort(_("cannot specify --no-commit and "
2247 "--edit together"))
2249 "--edit together"))
2248 if opts.get('currentuser'):
2250 if opts.get('currentuser'):
2249 raise error.Abort(_("cannot specify --no-commit and "
2251 raise error.Abort(_("cannot specify --no-commit and "
2250 "--currentuser together"))
2252 "--currentuser together"))
2251 if opts.get('currentdate'):
2253 if opts.get('currentdate'):
2252 raise error.Abort(_("cannot specify --no-commit and "
2254 raise error.Abort(_("cannot specify --no-commit and "
2253 "--currentdate together"))
2255 "--currentdate together"))
2254 if opts.get('log'):
2256 if opts.get('log'):
2255 raise error.Abort(_("cannot specify --no-commit and "
2257 raise error.Abort(_("cannot specify --no-commit and "
2256 "--log together"))
2258 "--log together"))
2257
2259
2258 graftstate = statemod.cmdstate(repo, 'graftstate')
2260 graftstate = statemod.cmdstate(repo, 'graftstate')
2259
2261
2260 if opts.get('stop'):
2262 if opts.get('stop'):
2261 if opts.get('continue'):
2263 if opts.get('continue'):
2262 raise error.Abort(_("cannot use '--continue' and "
2264 raise error.Abort(_("cannot use '--continue' and "
2263 "'--stop' together"))
2265 "'--stop' together"))
2264 if opts.get('abort'):
2266 if opts.get('abort'):
2265 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2267 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2266
2268
2267 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2269 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2268 opts.get('date'), opts.get('currentdate'),
2270 opts.get('date'), opts.get('currentdate'),
2269 opts.get('currentuser'), opts.get('rev'))):
2271 opts.get('currentuser'), opts.get('rev'))):
2270 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2272 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2271 return _stopgraft(ui, repo, graftstate)
2273 return _stopgraft(ui, repo, graftstate)
2272 elif opts.get('abort'):
2274 elif opts.get('abort'):
2273 if opts.get('continue'):
2275 if opts.get('continue'):
2274 raise error.Abort(_("cannot use '--continue' and "
2276 raise error.Abort(_("cannot use '--continue' and "
2275 "'--abort' together"))
2277 "'--abort' together"))
2276 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2278 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2277 opts.get('date'), opts.get('currentdate'),
2279 opts.get('date'), opts.get('currentdate'),
2278 opts.get('currentuser'), opts.get('rev'))):
2280 opts.get('currentuser'), opts.get('rev'))):
2279 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2281 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2280
2282
2281 return _abortgraft(ui, repo, graftstate)
2283 return _abortgraft(ui, repo, graftstate)
2282 elif opts.get('continue'):
2284 elif opts.get('continue'):
2283 cont = True
2285 cont = True
2284 if revs:
2286 if revs:
2285 raise error.Abort(_("can't specify --continue and revisions"))
2287 raise error.Abort(_("can't specify --continue and revisions"))
2286 # read in unfinished revisions
2288 # read in unfinished revisions
2287 if graftstate.exists():
2289 if graftstate.exists():
2288 statedata = _readgraftstate(repo, graftstate)
2290 statedata = _readgraftstate(repo, graftstate)
2289 if statedata.get('date'):
2291 if statedata.get('date'):
2290 opts['date'] = statedata['date']
2292 opts['date'] = statedata['date']
2291 if statedata.get('user'):
2293 if statedata.get('user'):
2292 opts['user'] = statedata['user']
2294 opts['user'] = statedata['user']
2293 if statedata.get('log'):
2295 if statedata.get('log'):
2294 opts['log'] = True
2296 opts['log'] = True
2295 if statedata.get('no_commit'):
2297 if statedata.get('no_commit'):
2296 opts['no_commit'] = statedata.get('no_commit')
2298 opts['no_commit'] = statedata.get('no_commit')
2297 nodes = statedata['nodes']
2299 nodes = statedata['nodes']
2298 revs = [repo[node].rev() for node in nodes]
2300 revs = [repo[node].rev() for node in nodes]
2299 else:
2301 else:
2300 cmdutil.wrongtooltocontinue(repo, _('graft'))
2302 cmdutil.wrongtooltocontinue(repo, _('graft'))
2301 else:
2303 else:
2302 if not revs:
2304 if not revs:
2303 raise error.Abort(_('no revisions specified'))
2305 raise error.Abort(_('no revisions specified'))
2304 cmdutil.checkunfinished(repo)
2306 cmdutil.checkunfinished(repo)
2305 cmdutil.bailifchanged(repo)
2307 cmdutil.bailifchanged(repo)
2306 revs = scmutil.revrange(repo, revs)
2308 revs = scmutil.revrange(repo, revs)
2307
2309
2308 skipped = set()
2310 skipped = set()
2309 # check for merges
2311 # check for merges
2310 for rev in repo.revs('%ld and merge()', revs):
2312 for rev in repo.revs('%ld and merge()', revs):
2311 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2313 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2312 skipped.add(rev)
2314 skipped.add(rev)
2313 revs = [r for r in revs if r not in skipped]
2315 revs = [r for r in revs if r not in skipped]
2314 if not revs:
2316 if not revs:
2315 return -1
2317 return -1
2316
2318
2317 # Don't check in the --continue case, in effect retaining --force across
2319 # Don't check in the --continue case, in effect retaining --force across
2318 # --continues. That's because without --force, any revisions we decided to
2320 # --continues. That's because without --force, any revisions we decided to
2319 # skip would have been filtered out here, so they wouldn't have made their
2321 # skip would have been filtered out here, so they wouldn't have made their
2320 # way to the graftstate. With --force, any revisions we would have otherwise
2322 # way to the graftstate. With --force, any revisions we would have otherwise
2321 # skipped would not have been filtered out, and if they hadn't been applied
2323 # skipped would not have been filtered out, and if they hadn't been applied
2322 # already, they'd have been in the graftstate.
2324 # already, they'd have been in the graftstate.
2323 if not (cont or opts.get('force')):
2325 if not (cont or opts.get('force')):
2324 # check for ancestors of dest branch
2326 # check for ancestors of dest branch
2325 crev = repo['.'].rev()
2327 crev = repo['.'].rev()
2326 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2328 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2327 # XXX make this lazy in the future
2329 # XXX make this lazy in the future
2328 # don't mutate while iterating, create a copy
2330 # don't mutate while iterating, create a copy
2329 for rev in list(revs):
2331 for rev in list(revs):
2330 if rev in ancestors:
2332 if rev in ancestors:
2331 ui.warn(_('skipping ancestor revision %d:%s\n') %
2333 ui.warn(_('skipping ancestor revision %d:%s\n') %
2332 (rev, repo[rev]))
2334 (rev, repo[rev]))
2333 # XXX remove on list is slow
2335 # XXX remove on list is slow
2334 revs.remove(rev)
2336 revs.remove(rev)
2335 if not revs:
2337 if not revs:
2336 return -1
2338 return -1
2337
2339
2338 # analyze revs for earlier grafts
2340 # analyze revs for earlier grafts
2339 ids = {}
2341 ids = {}
2340 for ctx in repo.set("%ld", revs):
2342 for ctx in repo.set("%ld", revs):
2341 ids[ctx.hex()] = ctx.rev()
2343 ids[ctx.hex()] = ctx.rev()
2342 n = ctx.extra().get('source')
2344 n = ctx.extra().get('source')
2343 if n:
2345 if n:
2344 ids[n] = ctx.rev()
2346 ids[n] = ctx.rev()
2345
2347
2346 # check ancestors for earlier grafts
2348 # check ancestors for earlier grafts
2347 ui.debug('scanning for duplicate grafts\n')
2349 ui.debug('scanning for duplicate grafts\n')
2348
2350
2349 # The only changesets we can be sure doesn't contain grafts of any
2351 # The only changesets we can be sure doesn't contain grafts of any
2350 # revs, are the ones that are common ancestors of *all* revs:
2352 # revs, are the ones that are common ancestors of *all* revs:
2351 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2353 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2352 ctx = repo[rev]
2354 ctx = repo[rev]
2353 n = ctx.extra().get('source')
2355 n = ctx.extra().get('source')
2354 if n in ids:
2356 if n in ids:
2355 try:
2357 try:
2356 r = repo[n].rev()
2358 r = repo[n].rev()
2357 except error.RepoLookupError:
2359 except error.RepoLookupError:
2358 r = None
2360 r = None
2359 if r in revs:
2361 if r in revs:
2360 ui.warn(_('skipping revision %d:%s '
2362 ui.warn(_('skipping revision %d:%s '
2361 '(already grafted to %d:%s)\n')
2363 '(already grafted to %d:%s)\n')
2362 % (r, repo[r], rev, ctx))
2364 % (r, repo[r], rev, ctx))
2363 revs.remove(r)
2365 revs.remove(r)
2364 elif ids[n] in revs:
2366 elif ids[n] in revs:
2365 if r is None:
2367 if r is None:
2366 ui.warn(_('skipping already grafted revision %d:%s '
2368 ui.warn(_('skipping already grafted revision %d:%s '
2367 '(%d:%s also has unknown origin %s)\n')
2369 '(%d:%s also has unknown origin %s)\n')
2368 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2370 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2369 else:
2371 else:
2370 ui.warn(_('skipping already grafted revision %d:%s '
2372 ui.warn(_('skipping already grafted revision %d:%s '
2371 '(%d:%s also has origin %d:%s)\n')
2373 '(%d:%s also has origin %d:%s)\n')
2372 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2374 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2373 revs.remove(ids[n])
2375 revs.remove(ids[n])
2374 elif ctx.hex() in ids:
2376 elif ctx.hex() in ids:
2375 r = ids[ctx.hex()]
2377 r = ids[ctx.hex()]
2376 ui.warn(_('skipping already grafted revision %d:%s '
2378 ui.warn(_('skipping already grafted revision %d:%s '
2377 '(was grafted from %d:%s)\n') %
2379 '(was grafted from %d:%s)\n') %
2378 (r, repo[r], rev, ctx))
2380 (r, repo[r], rev, ctx))
2379 revs.remove(r)
2381 revs.remove(r)
2380 if not revs:
2382 if not revs:
2381 return -1
2383 return -1
2382
2384
2383 if opts.get('no_commit'):
2385 if opts.get('no_commit'):
2384 statedata['no_commit'] = True
2386 statedata['no_commit'] = True
2385 for pos, ctx in enumerate(repo.set("%ld", revs)):
2387 for pos, ctx in enumerate(repo.set("%ld", revs)):
2386 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2388 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2387 ctx.description().split('\n', 1)[0])
2389 ctx.description().split('\n', 1)[0])
2388 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2390 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2389 if names:
2391 if names:
2390 desc += ' (%s)' % ' '.join(names)
2392 desc += ' (%s)' % ' '.join(names)
2391 ui.status(_('grafting %s\n') % desc)
2393 ui.status(_('grafting %s\n') % desc)
2392 if opts.get('dry_run'):
2394 if opts.get('dry_run'):
2393 continue
2395 continue
2394
2396
2395 source = ctx.extra().get('source')
2397 source = ctx.extra().get('source')
2396 extra = {}
2398 extra = {}
2397 if source:
2399 if source:
2398 extra['source'] = source
2400 extra['source'] = source
2399 extra['intermediate-source'] = ctx.hex()
2401 extra['intermediate-source'] = ctx.hex()
2400 else:
2402 else:
2401 extra['source'] = ctx.hex()
2403 extra['source'] = ctx.hex()
2402 user = ctx.user()
2404 user = ctx.user()
2403 if opts.get('user'):
2405 if opts.get('user'):
2404 user = opts['user']
2406 user = opts['user']
2405 statedata['user'] = user
2407 statedata['user'] = user
2406 date = ctx.date()
2408 date = ctx.date()
2407 if opts.get('date'):
2409 if opts.get('date'):
2408 date = opts['date']
2410 date = opts['date']
2409 statedata['date'] = date
2411 statedata['date'] = date
2410 message = ctx.description()
2412 message = ctx.description()
2411 if opts.get('log'):
2413 if opts.get('log'):
2412 message += '\n(grafted from %s)' % ctx.hex()
2414 message += '\n(grafted from %s)' % ctx.hex()
2413 statedata['log'] = True
2415 statedata['log'] = True
2414
2416
2415 # we don't merge the first commit when continuing
2417 # we don't merge the first commit when continuing
2416 if not cont:
2418 if not cont:
2417 # perform the graft merge with p1(rev) as 'ancestor'
2419 # perform the graft merge with p1(rev) as 'ancestor'
2418 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2420 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2419 with ui.configoverride(overrides, 'graft'):
2421 with ui.configoverride(overrides, 'graft'):
2420 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2422 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2421 # report any conflicts
2423 # report any conflicts
2422 if stats.unresolvedcount > 0:
2424 if stats.unresolvedcount > 0:
2423 # write out state for --continue
2425 # write out state for --continue
2424 nodes = [repo[rev].hex() for rev in revs[pos:]]
2426 nodes = [repo[rev].hex() for rev in revs[pos:]]
2425 statedata['nodes'] = nodes
2427 statedata['nodes'] = nodes
2426 stateversion = 1
2428 stateversion = 1
2427 graftstate.save(stateversion, statedata)
2429 graftstate.save(stateversion, statedata)
2428 hint = _("use 'hg resolve' and 'hg graft --continue'")
2430 hint = _("use 'hg resolve' and 'hg graft --continue'")
2429 raise error.Abort(
2431 raise error.Abort(
2430 _("unresolved conflicts, can't continue"),
2432 _("unresolved conflicts, can't continue"),
2431 hint=hint)
2433 hint=hint)
2432 else:
2434 else:
2433 cont = False
2435 cont = False
2434
2436
2435 # commit if --no-commit is false
2437 # commit if --no-commit is false
2436 if not opts.get('no_commit'):
2438 if not opts.get('no_commit'):
2437 node = repo.commit(text=message, user=user, date=date, extra=extra,
2439 node = repo.commit(text=message, user=user, date=date, extra=extra,
2438 editor=editor)
2440 editor=editor)
2439 if node is None:
2441 if node is None:
2440 ui.warn(
2442 ui.warn(
2441 _('note: graft of %d:%s created no changes to commit\n') %
2443 _('note: graft of %d:%s created no changes to commit\n') %
2442 (ctx.rev(), ctx))
2444 (ctx.rev(), ctx))
2443 # checking that newnodes exist because old state files won't have it
2445 # checking that newnodes exist because old state files won't have it
2444 elif statedata.get('newnodes') is not None:
2446 elif statedata.get('newnodes') is not None:
2445 statedata['newnodes'].append(node)
2447 statedata['newnodes'].append(node)
2446
2448
2447 # remove state when we complete successfully
2449 # remove state when we complete successfully
2448 if not opts.get('dry_run'):
2450 if not opts.get('dry_run'):
2449 graftstate.delete()
2451 graftstate.delete()
2450
2452
2451 return 0
2453 return 0
2452
2454
2453 def _abortgraft(ui, repo, graftstate):
2455 def _abortgraft(ui, repo, graftstate):
2454 """abort the interrupted graft and rollbacks to the state before interrupted
2456 """abort the interrupted graft and rollbacks to the state before interrupted
2455 graft"""
2457 graft"""
2456 if not graftstate.exists():
2458 if not graftstate.exists():
2457 raise error.Abort(_("no interrupted graft to abort"))
2459 raise error.Abort(_("no interrupted graft to abort"))
2458 statedata = _readgraftstate(repo, graftstate)
2460 statedata = _readgraftstate(repo, graftstate)
2459 newnodes = statedata.get('newnodes')
2461 newnodes = statedata.get('newnodes')
2460 if newnodes is None:
2462 if newnodes is None:
2461 # and old graft state which does not have all the data required to abort
2463 # and old graft state which does not have all the data required to abort
2462 # the graft
2464 # the graft
2463 raise error.Abort(_("cannot abort using an old graftstate"))
2465 raise error.Abort(_("cannot abort using an old graftstate"))
2464
2466
2465 # changeset from which graft operation was started
2467 # changeset from which graft operation was started
2466 startctx = None
2468 startctx = None
2467 if len(newnodes) > 0:
2469 if len(newnodes) > 0:
2468 startctx = repo[newnodes[0]].p1()
2470 startctx = repo[newnodes[0]].p1()
2469 else:
2471 else:
2470 startctx = repo['.']
2472 startctx = repo['.']
2471 # whether to strip or not
2473 # whether to strip or not
2472 cleanup = False
2474 cleanup = False
2473 if newnodes:
2475 if newnodes:
2474 newnodes = [repo[r].rev() for r in newnodes]
2476 newnodes = [repo[r].rev() for r in newnodes]
2475 cleanup = True
2477 cleanup = True
2476 # checking that none of the newnodes turned public or is public
2478 # checking that none of the newnodes turned public or is public
2477 immutable = [c for c in newnodes if not repo[c].mutable()]
2479 immutable = [c for c in newnodes if not repo[c].mutable()]
2478 if immutable:
2480 if immutable:
2479 repo.ui.warn(_("cannot clean up public changesets %s\n")
2481 repo.ui.warn(_("cannot clean up public changesets %s\n")
2480 % ', '.join(bytes(repo[r]) for r in immutable),
2482 % ', '.join(bytes(repo[r]) for r in immutable),
2481 hint=_("see 'hg help phases' for details"))
2483 hint=_("see 'hg help phases' for details"))
2482 cleanup = False
2484 cleanup = False
2483
2485
2484 # checking that no new nodes are created on top of grafted revs
2486 # checking that no new nodes are created on top of grafted revs
2485 desc = set(repo.changelog.descendants(newnodes))
2487 desc = set(repo.changelog.descendants(newnodes))
2486 if desc - set(newnodes):
2488 if desc - set(newnodes):
2487 repo.ui.warn(_("new changesets detected on destination "
2489 repo.ui.warn(_("new changesets detected on destination "
2488 "branch, can't strip\n"))
2490 "branch, can't strip\n"))
2489 cleanup = False
2491 cleanup = False
2490
2492
2491 if cleanup:
2493 if cleanup:
2492 with repo.wlock(), repo.lock():
2494 with repo.wlock(), repo.lock():
2493 hg.updaterepo(repo, startctx.node(), overwrite=True)
2495 hg.updaterepo(repo, startctx.node(), overwrite=True)
2494 # stripping the new nodes created
2496 # stripping the new nodes created
2495 strippoints = [c.node() for c in repo.set("roots(%ld)",
2497 strippoints = [c.node() for c in repo.set("roots(%ld)",
2496 newnodes)]
2498 newnodes)]
2497 repair.strip(repo.ui, repo, strippoints, backup=False)
2499 repair.strip(repo.ui, repo, strippoints, backup=False)
2498
2500
2499 if not cleanup:
2501 if not cleanup:
2500 # we don't update to the startnode if we can't strip
2502 # we don't update to the startnode if we can't strip
2501 startctx = repo['.']
2503 startctx = repo['.']
2502 hg.updaterepo(repo, startctx.node(), overwrite=True)
2504 hg.updaterepo(repo, startctx.node(), overwrite=True)
2503
2505
2504 ui.status(_("graft aborted\n"))
2506 ui.status(_("graft aborted\n"))
2505 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2507 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2506 graftstate.delete()
2508 graftstate.delete()
2507 return 0
2509 return 0
2508
2510
2509 def _readgraftstate(repo, graftstate):
2511 def _readgraftstate(repo, graftstate):
2510 """read the graft state file and return a dict of the data stored in it"""
2512 """read the graft state file and return a dict of the data stored in it"""
2511 try:
2513 try:
2512 return graftstate.read()
2514 return graftstate.read()
2513 except error.CorruptedState:
2515 except error.CorruptedState:
2514 nodes = repo.vfs.read('graftstate').splitlines()
2516 nodes = repo.vfs.read('graftstate').splitlines()
2515 return {'nodes': nodes}
2517 return {'nodes': nodes}
2516
2518
2517 def _stopgraft(ui, repo, graftstate):
2519 def _stopgraft(ui, repo, graftstate):
2518 """stop the interrupted graft"""
2520 """stop the interrupted graft"""
2519 if not graftstate.exists():
2521 if not graftstate.exists():
2520 raise error.Abort(_("no interrupted graft found"))
2522 raise error.Abort(_("no interrupted graft found"))
2521 pctx = repo['.']
2523 pctx = repo['.']
2522 hg.updaterepo(repo, pctx.node(), overwrite=True)
2524 hg.updaterepo(repo, pctx.node(), overwrite=True)
2523 graftstate.delete()
2525 graftstate.delete()
2524 ui.status(_("stopped the interrupted graft\n"))
2526 ui.status(_("stopped the interrupted graft\n"))
2525 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2527 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2526 return 0
2528 return 0
2527
2529
2528 @command('grep',
2530 @command('grep',
2529 [('0', 'print0', None, _('end fields with NUL')),
2531 [('0', 'print0', None, _('end fields with NUL')),
2530 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2532 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2531 ('', 'diff', None, _('print all revisions when the term was introduced '
2533 ('', 'diff', None, _('print all revisions when the term was introduced '
2532 'or removed')),
2534 'or removed')),
2533 ('a', 'text', None, _('treat all files as text')),
2535 ('a', 'text', None, _('treat all files as text')),
2534 ('f', 'follow', None,
2536 ('f', 'follow', None,
2535 _('follow changeset history,'
2537 _('follow changeset history,'
2536 ' or file history across copies and renames')),
2538 ' or file history across copies and renames')),
2537 ('i', 'ignore-case', None, _('ignore case when matching')),
2539 ('i', 'ignore-case', None, _('ignore case when matching')),
2538 ('l', 'files-with-matches', None,
2540 ('l', 'files-with-matches', None,
2539 _('print only filenames and revisions that match')),
2541 _('print only filenames and revisions that match')),
2540 ('n', 'line-number', None, _('print matching line numbers')),
2542 ('n', 'line-number', None, _('print matching line numbers')),
2541 ('r', 'rev', [],
2543 ('r', 'rev', [],
2542 _('only search files changed within revision range'), _('REV')),
2544 _('only search files changed within revision range'), _('REV')),
2543 ('', 'all-files', None,
2545 ('', 'all-files', None,
2544 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2546 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2545 ('u', 'user', None, _('list the author (long with -v)')),
2547 ('u', 'user', None, _('list the author (long with -v)')),
2546 ('d', 'date', None, _('list the date (short with -q)')),
2548 ('d', 'date', None, _('list the date (short with -q)')),
2547 ] + formatteropts + walkopts,
2549 ] + formatteropts + walkopts,
2548 _('[OPTION]... PATTERN [FILE]...'),
2550 _('[OPTION]... PATTERN [FILE]...'),
2549 inferrepo=True,
2551 inferrepo=True,
2550 intents={INTENT_READONLY})
2552 intents={INTENT_READONLY})
2551 def grep(ui, repo, pattern, *pats, **opts):
2553 def grep(ui, repo, pattern, *pats, **opts):
2552 """search revision history for a pattern in specified files
2554 """search revision history for a pattern in specified files
2553
2555
2554 Search revision history for a regular expression in the specified
2556 Search revision history for a regular expression in the specified
2555 files or the entire project.
2557 files or the entire project.
2556
2558
2557 By default, grep prints the most recent revision number for each
2559 By default, grep prints the most recent revision number for each
2558 file in which it finds a match. To get it to print every revision
2560 file in which it finds a match. To get it to print every revision
2559 that contains a change in match status ("-" for a match that becomes
2561 that contains a change in match status ("-" for a match that becomes
2560 a non-match, or "+" for a non-match that becomes a match), use the
2562 a non-match, or "+" for a non-match that becomes a match), use the
2561 --diff flag.
2563 --diff flag.
2562
2564
2563 PATTERN can be any Python (roughly Perl-compatible) regular
2565 PATTERN can be any Python (roughly Perl-compatible) regular
2564 expression.
2566 expression.
2565
2567
2566 If no FILEs are specified (and -f/--follow isn't set), all files in
2568 If no FILEs are specified (and -f/--follow isn't set), all files in
2567 the repository are searched, including those that don't exist in the
2569 the repository are searched, including those that don't exist in the
2568 current branch or have been deleted in a prior changeset.
2570 current branch or have been deleted in a prior changeset.
2569
2571
2570 Returns 0 if a match is found, 1 otherwise.
2572 Returns 0 if a match is found, 1 otherwise.
2571 """
2573 """
2572 opts = pycompat.byteskwargs(opts)
2574 opts = pycompat.byteskwargs(opts)
2573 diff = opts.get('all') or opts.get('diff')
2575 diff = opts.get('all') or opts.get('diff')
2574 all_files = opts.get('all_files')
2576 all_files = opts.get('all_files')
2575 if diff and opts.get('all_files'):
2577 if diff and opts.get('all_files'):
2576 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2578 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2577 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2579 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2578 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2580 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2579 # experimental config: commands.grep.all-files
2581 # experimental config: commands.grep.all-files
2580 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2582 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2581 plaingrep = opts.get('all_files') and not opts.get('rev')
2583 plaingrep = opts.get('all_files') and not opts.get('rev')
2582 if plaingrep:
2584 if plaingrep:
2583 opts['rev'] = ['wdir()']
2585 opts['rev'] = ['wdir()']
2584
2586
2585 reflags = re.M
2587 reflags = re.M
2586 if opts.get('ignore_case'):
2588 if opts.get('ignore_case'):
2587 reflags |= re.I
2589 reflags |= re.I
2588 try:
2590 try:
2589 regexp = util.re.compile(pattern, reflags)
2591 regexp = util.re.compile(pattern, reflags)
2590 except re.error as inst:
2592 except re.error as inst:
2591 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2593 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2592 return 1
2594 return 1
2593 sep, eol = ':', '\n'
2595 sep, eol = ':', '\n'
2594 if opts.get('print0'):
2596 if opts.get('print0'):
2595 sep = eol = '\0'
2597 sep = eol = '\0'
2596
2598
2597 getfile = util.lrucachefunc(repo.file)
2599 getfile = util.lrucachefunc(repo.file)
2598
2600
2599 def matchlines(body):
2601 def matchlines(body):
2600 begin = 0
2602 begin = 0
2601 linenum = 0
2603 linenum = 0
2602 while begin < len(body):
2604 while begin < len(body):
2603 match = regexp.search(body, begin)
2605 match = regexp.search(body, begin)
2604 if not match:
2606 if not match:
2605 break
2607 break
2606 mstart, mend = match.span()
2608 mstart, mend = match.span()
2607 linenum += body.count('\n', begin, mstart) + 1
2609 linenum += body.count('\n', begin, mstart) + 1
2608 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2609 begin = body.find('\n', mend) + 1 or len(body) + 1
2611 begin = body.find('\n', mend) + 1 or len(body) + 1
2610 lend = begin - 1
2612 lend = begin - 1
2611 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2612
2614
2613 class linestate(object):
2615 class linestate(object):
2614 def __init__(self, line, linenum, colstart, colend):
2616 def __init__(self, line, linenum, colstart, colend):
2615 self.line = line
2617 self.line = line
2616 self.linenum = linenum
2618 self.linenum = linenum
2617 self.colstart = colstart
2619 self.colstart = colstart
2618 self.colend = colend
2620 self.colend = colend
2619
2621
2620 def __hash__(self):
2622 def __hash__(self):
2621 return hash((self.linenum, self.line))
2623 return hash((self.linenum, self.line))
2622
2624
2623 def __eq__(self, other):
2625 def __eq__(self, other):
2624 return self.line == other.line
2626 return self.line == other.line
2625
2627
2626 def findpos(self):
2628 def findpos(self):
2627 """Iterate all (start, end) indices of matches"""
2629 """Iterate all (start, end) indices of matches"""
2628 yield self.colstart, self.colend
2630 yield self.colstart, self.colend
2629 p = self.colend
2631 p = self.colend
2630 while p < len(self.line):
2632 while p < len(self.line):
2631 m = regexp.search(self.line, p)
2633 m = regexp.search(self.line, p)
2632 if not m:
2634 if not m:
2633 break
2635 break
2634 yield m.span()
2636 yield m.span()
2635 p = m.end()
2637 p = m.end()
2636
2638
2637 matches = {}
2639 matches = {}
2638 copies = {}
2640 copies = {}
2639 def grepbody(fn, rev, body):
2641 def grepbody(fn, rev, body):
2640 matches[rev].setdefault(fn, [])
2642 matches[rev].setdefault(fn, [])
2641 m = matches[rev][fn]
2643 m = matches[rev][fn]
2642 for lnum, cstart, cend, line in matchlines(body):
2644 for lnum, cstart, cend, line in matchlines(body):
2643 s = linestate(line, lnum, cstart, cend)
2645 s = linestate(line, lnum, cstart, cend)
2644 m.append(s)
2646 m.append(s)
2645
2647
2646 def difflinestates(a, b):
2648 def difflinestates(a, b):
2647 sm = difflib.SequenceMatcher(None, a, b)
2649 sm = difflib.SequenceMatcher(None, a, b)
2648 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2650 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2649 if tag == r'insert':
2651 if tag == r'insert':
2650 for i in pycompat.xrange(blo, bhi):
2652 for i in pycompat.xrange(blo, bhi):
2651 yield ('+', b[i])
2653 yield ('+', b[i])
2652 elif tag == r'delete':
2654 elif tag == r'delete':
2653 for i in pycompat.xrange(alo, ahi):
2655 for i in pycompat.xrange(alo, ahi):
2654 yield ('-', a[i])
2656 yield ('-', a[i])
2655 elif tag == r'replace':
2657 elif tag == r'replace':
2656 for i in pycompat.xrange(alo, ahi):
2658 for i in pycompat.xrange(alo, ahi):
2657 yield ('-', a[i])
2659 yield ('-', a[i])
2658 for i in pycompat.xrange(blo, bhi):
2660 for i in pycompat.xrange(blo, bhi):
2659 yield ('+', b[i])
2661 yield ('+', b[i])
2660
2662
2661 def display(fm, fn, ctx, pstates, states):
2663 def display(fm, fn, ctx, pstates, states):
2662 rev = scmutil.intrev(ctx)
2664 rev = scmutil.intrev(ctx)
2663 if fm.isplain():
2665 if fm.isplain():
2664 formatuser = ui.shortuser
2666 formatuser = ui.shortuser
2665 else:
2667 else:
2666 formatuser = pycompat.bytestr
2668 formatuser = pycompat.bytestr
2667 if ui.quiet:
2669 if ui.quiet:
2668 datefmt = '%Y-%m-%d'
2670 datefmt = '%Y-%m-%d'
2669 else:
2671 else:
2670 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2672 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2671 found = False
2673 found = False
2672 @util.cachefunc
2674 @util.cachefunc
2673 def binary():
2675 def binary():
2674 flog = getfile(fn)
2676 flog = getfile(fn)
2675 try:
2677 try:
2676 return stringutil.binary(flog.read(ctx.filenode(fn)))
2678 return stringutil.binary(flog.read(ctx.filenode(fn)))
2677 except error.WdirUnsupported:
2679 except error.WdirUnsupported:
2678 return ctx[fn].isbinary()
2680 return ctx[fn].isbinary()
2679
2681
2680 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2682 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2681 if diff:
2683 if diff:
2682 iter = difflinestates(pstates, states)
2684 iter = difflinestates(pstates, states)
2683 else:
2685 else:
2684 iter = [('', l) for l in states]
2686 iter = [('', l) for l in states]
2685 for change, l in iter:
2687 for change, l in iter:
2686 fm.startitem()
2688 fm.startitem()
2687 fm.context(ctx=ctx)
2689 fm.context(ctx=ctx)
2688 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2690 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2689
2691
2690 cols = [
2692 cols = [
2691 ('filename', '%s', fn, True),
2693 ('filename', '%s', fn, True),
2692 ('rev', '%d', rev, not plaingrep),
2694 ('rev', '%d', rev, not plaingrep),
2693 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2695 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2694 ]
2696 ]
2695 if diff:
2697 if diff:
2696 cols.append(('change', '%s', change, True))
2698 cols.append(('change', '%s', change, True))
2697 cols.extend([
2699 cols.extend([
2698 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2700 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2699 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2701 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2700 opts.get('date')),
2702 opts.get('date')),
2701 ])
2703 ])
2702 lastcol = next(
2704 lastcol = next(
2703 name for name, fmt, data, cond in reversed(cols) if cond)
2705 name for name, fmt, data, cond in reversed(cols) if cond)
2704 for name, fmt, data, cond in cols:
2706 for name, fmt, data, cond in cols:
2705 field = fieldnamemap.get(name, name)
2707 field = fieldnamemap.get(name, name)
2706 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2708 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2707 if cond and name != lastcol:
2709 if cond and name != lastcol:
2708 fm.plain(sep, label='grep.sep')
2710 fm.plain(sep, label='grep.sep')
2709 if not opts.get('files_with_matches'):
2711 if not opts.get('files_with_matches'):
2710 fm.plain(sep, label='grep.sep')
2712 fm.plain(sep, label='grep.sep')
2711 if not opts.get('text') and binary():
2713 if not opts.get('text') and binary():
2712 fm.plain(_(" Binary file matches"))
2714 fm.plain(_(" Binary file matches"))
2713 else:
2715 else:
2714 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2716 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2715 fm.plain(eol)
2717 fm.plain(eol)
2716 found = True
2718 found = True
2717 if opts.get('files_with_matches'):
2719 if opts.get('files_with_matches'):
2718 break
2720 break
2719 return found
2721 return found
2720
2722
2721 def displaymatches(fm, l):
2723 def displaymatches(fm, l):
2722 p = 0
2724 p = 0
2723 for s, e in l.findpos():
2725 for s, e in l.findpos():
2724 if p < s:
2726 if p < s:
2725 fm.startitem()
2727 fm.startitem()
2726 fm.write('text', '%s', l.line[p:s])
2728 fm.write('text', '%s', l.line[p:s])
2727 fm.data(matched=False)
2729 fm.data(matched=False)
2728 fm.startitem()
2730 fm.startitem()
2729 fm.write('text', '%s', l.line[s:e], label='grep.match')
2731 fm.write('text', '%s', l.line[s:e], label='grep.match')
2730 fm.data(matched=True)
2732 fm.data(matched=True)
2731 p = e
2733 p = e
2732 if p < len(l.line):
2734 if p < len(l.line):
2733 fm.startitem()
2735 fm.startitem()
2734 fm.write('text', '%s', l.line[p:])
2736 fm.write('text', '%s', l.line[p:])
2735 fm.data(matched=False)
2737 fm.data(matched=False)
2736 fm.end()
2738 fm.end()
2737
2739
2738 skip = {}
2740 skip = {}
2739 revfiles = {}
2741 revfiles = {}
2740 match = scmutil.match(repo[None], pats, opts)
2742 match = scmutil.match(repo[None], pats, opts)
2741 found = False
2743 found = False
2742 follow = opts.get('follow')
2744 follow = opts.get('follow')
2743
2745
2744 def prep(ctx, fns):
2746 def prep(ctx, fns):
2745 rev = ctx.rev()
2747 rev = ctx.rev()
2746 pctx = ctx.p1()
2748 pctx = ctx.p1()
2747 parent = pctx.rev()
2749 parent = pctx.rev()
2748 matches.setdefault(rev, {})
2750 matches.setdefault(rev, {})
2749 matches.setdefault(parent, {})
2751 matches.setdefault(parent, {})
2750 files = revfiles.setdefault(rev, [])
2752 files = revfiles.setdefault(rev, [])
2751 for fn in fns:
2753 for fn in fns:
2752 flog = getfile(fn)
2754 flog = getfile(fn)
2753 try:
2755 try:
2754 fnode = ctx.filenode(fn)
2756 fnode = ctx.filenode(fn)
2755 except error.LookupError:
2757 except error.LookupError:
2756 continue
2758 continue
2757 try:
2759 try:
2758 copied = flog.renamed(fnode)
2760 copied = flog.renamed(fnode)
2759 except error.WdirUnsupported:
2761 except error.WdirUnsupported:
2760 copied = ctx[fn].renamed()
2762 copied = ctx[fn].renamed()
2761 copy = follow and copied and copied[0]
2763 copy = follow and copied and copied[0]
2762 if copy:
2764 if copy:
2763 copies.setdefault(rev, {})[fn] = copy
2765 copies.setdefault(rev, {})[fn] = copy
2764 if fn in skip:
2766 if fn in skip:
2765 if copy:
2767 if copy:
2766 skip[copy] = True
2768 skip[copy] = True
2767 continue
2769 continue
2768 files.append(fn)
2770 files.append(fn)
2769
2771
2770 if fn not in matches[rev]:
2772 if fn not in matches[rev]:
2771 try:
2773 try:
2772 content = flog.read(fnode)
2774 content = flog.read(fnode)
2773 except error.WdirUnsupported:
2775 except error.WdirUnsupported:
2774 content = ctx[fn].data()
2776 content = ctx[fn].data()
2775 grepbody(fn, rev, content)
2777 grepbody(fn, rev, content)
2776
2778
2777 pfn = copy or fn
2779 pfn = copy or fn
2778 if pfn not in matches[parent]:
2780 if pfn not in matches[parent]:
2779 try:
2781 try:
2780 fnode = pctx.filenode(pfn)
2782 fnode = pctx.filenode(pfn)
2781 grepbody(pfn, parent, flog.read(fnode))
2783 grepbody(pfn, parent, flog.read(fnode))
2782 except error.LookupError:
2784 except error.LookupError:
2783 pass
2785 pass
2784
2786
2785 ui.pager('grep')
2787 ui.pager('grep')
2786 fm = ui.formatter('grep', opts)
2788 fm = ui.formatter('grep', opts)
2787 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2789 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2788 rev = ctx.rev()
2790 rev = ctx.rev()
2789 parent = ctx.p1().rev()
2791 parent = ctx.p1().rev()
2790 for fn in sorted(revfiles.get(rev, [])):
2792 for fn in sorted(revfiles.get(rev, [])):
2791 states = matches[rev][fn]
2793 states = matches[rev][fn]
2792 copy = copies.get(rev, {}).get(fn)
2794 copy = copies.get(rev, {}).get(fn)
2793 if fn in skip:
2795 if fn in skip:
2794 if copy:
2796 if copy:
2795 skip[copy] = True
2797 skip[copy] = True
2796 continue
2798 continue
2797 pstates = matches.get(parent, {}).get(copy or fn, [])
2799 pstates = matches.get(parent, {}).get(copy or fn, [])
2798 if pstates or states:
2800 if pstates or states:
2799 r = display(fm, fn, ctx, pstates, states)
2801 r = display(fm, fn, ctx, pstates, states)
2800 found = found or r
2802 found = found or r
2801 if r and not diff and not all_files:
2803 if r and not diff and not all_files:
2802 skip[fn] = True
2804 skip[fn] = True
2803 if copy:
2805 if copy:
2804 skip[copy] = True
2806 skip[copy] = True
2805 del revfiles[rev]
2807 del revfiles[rev]
2806 # We will keep the matches dict for the duration of the window
2808 # We will keep the matches dict for the duration of the window
2807 # clear the matches dict once the window is over
2809 # clear the matches dict once the window is over
2808 if not revfiles:
2810 if not revfiles:
2809 matches.clear()
2811 matches.clear()
2810 fm.end()
2812 fm.end()
2811
2813
2812 return not found
2814 return not found
2813
2815
2814 @command('heads',
2816 @command('heads',
2815 [('r', 'rev', '',
2817 [('r', 'rev', '',
2816 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2818 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2817 ('t', 'topo', False, _('show topological heads only')),
2819 ('t', 'topo', False, _('show topological heads only')),
2818 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2820 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2819 ('c', 'closed', False, _('show normal and closed branch heads')),
2821 ('c', 'closed', False, _('show normal and closed branch heads')),
2820 ] + templateopts,
2822 ] + templateopts,
2821 _('[-ct] [-r STARTREV] [REV]...'),
2823 _('[-ct] [-r STARTREV] [REV]...'),
2822 intents={INTENT_READONLY})
2824 intents={INTENT_READONLY})
2823 def heads(ui, repo, *branchrevs, **opts):
2825 def heads(ui, repo, *branchrevs, **opts):
2824 """show branch heads
2826 """show branch heads
2825
2827
2826 With no arguments, show all open branch heads in the repository.
2828 With no arguments, show all open branch heads in the repository.
2827 Branch heads are changesets that have no descendants on the
2829 Branch heads are changesets that have no descendants on the
2828 same branch. They are where development generally takes place and
2830 same branch. They are where development generally takes place and
2829 are the usual targets for update and merge operations.
2831 are the usual targets for update and merge operations.
2830
2832
2831 If one or more REVs are given, only open branch heads on the
2833 If one or more REVs are given, only open branch heads on the
2832 branches associated with the specified changesets are shown. This
2834 branches associated with the specified changesets are shown. This
2833 means that you can use :hg:`heads .` to see the heads on the
2835 means that you can use :hg:`heads .` to see the heads on the
2834 currently checked-out branch.
2836 currently checked-out branch.
2835
2837
2836 If -c/--closed is specified, also show branch heads marked closed
2838 If -c/--closed is specified, also show branch heads marked closed
2837 (see :hg:`commit --close-branch`).
2839 (see :hg:`commit --close-branch`).
2838
2840
2839 If STARTREV is specified, only those heads that are descendants of
2841 If STARTREV is specified, only those heads that are descendants of
2840 STARTREV will be displayed.
2842 STARTREV will be displayed.
2841
2843
2842 If -t/--topo is specified, named branch mechanics will be ignored and only
2844 If -t/--topo is specified, named branch mechanics will be ignored and only
2843 topological heads (changesets with no children) will be shown.
2845 topological heads (changesets with no children) will be shown.
2844
2846
2845 Returns 0 if matching heads are found, 1 if not.
2847 Returns 0 if matching heads are found, 1 if not.
2846 """
2848 """
2847
2849
2848 opts = pycompat.byteskwargs(opts)
2850 opts = pycompat.byteskwargs(opts)
2849 start = None
2851 start = None
2850 rev = opts.get('rev')
2852 rev = opts.get('rev')
2851 if rev:
2853 if rev:
2852 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2854 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2853 start = scmutil.revsingle(repo, rev, None).node()
2855 start = scmutil.revsingle(repo, rev, None).node()
2854
2856
2855 if opts.get('topo'):
2857 if opts.get('topo'):
2856 heads = [repo[h] for h in repo.heads(start)]
2858 heads = [repo[h] for h in repo.heads(start)]
2857 else:
2859 else:
2858 heads = []
2860 heads = []
2859 for branch in repo.branchmap():
2861 for branch in repo.branchmap():
2860 heads += repo.branchheads(branch, start, opts.get('closed'))
2862 heads += repo.branchheads(branch, start, opts.get('closed'))
2861 heads = [repo[h] for h in heads]
2863 heads = [repo[h] for h in heads]
2862
2864
2863 if branchrevs:
2865 if branchrevs:
2864 branches = set(repo[r].branch()
2866 branches = set(repo[r].branch()
2865 for r in scmutil.revrange(repo, branchrevs))
2867 for r in scmutil.revrange(repo, branchrevs))
2866 heads = [h for h in heads if h.branch() in branches]
2868 heads = [h for h in heads if h.branch() in branches]
2867
2869
2868 if opts.get('active') and branchrevs:
2870 if opts.get('active') and branchrevs:
2869 dagheads = repo.heads(start)
2871 dagheads = repo.heads(start)
2870 heads = [h for h in heads if h.node() in dagheads]
2872 heads = [h for h in heads if h.node() in dagheads]
2871
2873
2872 if branchrevs:
2874 if branchrevs:
2873 haveheads = set(h.branch() for h in heads)
2875 haveheads = set(h.branch() for h in heads)
2874 if branches - haveheads:
2876 if branches - haveheads:
2875 headless = ', '.join(b for b in branches - haveheads)
2877 headless = ', '.join(b for b in branches - haveheads)
2876 msg = _('no open branch heads found on branches %s')
2878 msg = _('no open branch heads found on branches %s')
2877 if opts.get('rev'):
2879 if opts.get('rev'):
2878 msg += _(' (started at %s)') % opts['rev']
2880 msg += _(' (started at %s)') % opts['rev']
2879 ui.warn((msg + '\n') % headless)
2881 ui.warn((msg + '\n') % headless)
2880
2882
2881 if not heads:
2883 if not heads:
2882 return 1
2884 return 1
2883
2885
2884 ui.pager('heads')
2886 ui.pager('heads')
2885 heads = sorted(heads, key=lambda x: -x.rev())
2887 heads = sorted(heads, key=lambda x: -x.rev())
2886 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2887 for ctx in heads:
2889 for ctx in heads:
2888 displayer.show(ctx)
2890 displayer.show(ctx)
2889 displayer.close()
2891 displayer.close()
2890
2892
2891 @command('help',
2893 @command('help',
2892 [('e', 'extension', None, _('show only help for extensions')),
2894 [('e', 'extension', None, _('show only help for extensions')),
2893 ('c', 'command', None, _('show only help for commands')),
2895 ('c', 'command', None, _('show only help for commands')),
2894 ('k', 'keyword', None, _('show topics matching keyword')),
2896 ('k', 'keyword', None, _('show topics matching keyword')),
2895 ('s', 'system', [], _('show help for specific platform(s)')),
2897 ('s', 'system', [], _('show help for specific platform(s)')),
2896 ],
2898 ],
2897 _('[-ecks] [TOPIC]'),
2899 _('[-ecks] [TOPIC]'),
2898 norepo=True,
2900 norepo=True,
2899 intents={INTENT_READONLY})
2901 intents={INTENT_READONLY})
2900 def help_(ui, name=None, **opts):
2902 def help_(ui, name=None, **opts):
2901 """show help for a given topic or a help overview
2903 """show help for a given topic or a help overview
2902
2904
2903 With no arguments, print a list of commands with short help messages.
2905 With no arguments, print a list of commands with short help messages.
2904
2906
2905 Given a topic, extension, or command name, print help for that
2907 Given a topic, extension, or command name, print help for that
2906 topic.
2908 topic.
2907
2909
2908 Returns 0 if successful.
2910 Returns 0 if successful.
2909 """
2911 """
2910
2912
2911 keep = opts.get(r'system') or []
2913 keep = opts.get(r'system') or []
2912 if len(keep) == 0:
2914 if len(keep) == 0:
2913 if pycompat.sysplatform.startswith('win'):
2915 if pycompat.sysplatform.startswith('win'):
2914 keep.append('windows')
2916 keep.append('windows')
2915 elif pycompat.sysplatform == 'OpenVMS':
2917 elif pycompat.sysplatform == 'OpenVMS':
2916 keep.append('vms')
2918 keep.append('vms')
2917 elif pycompat.sysplatform == 'plan9':
2919 elif pycompat.sysplatform == 'plan9':
2918 keep.append('plan9')
2920 keep.append('plan9')
2919 else:
2921 else:
2920 keep.append('unix')
2922 keep.append('unix')
2921 keep.append(pycompat.sysplatform.lower())
2923 keep.append(pycompat.sysplatform.lower())
2922 if ui.verbose:
2924 if ui.verbose:
2923 keep.append('verbose')
2925 keep.append('verbose')
2924
2926
2925 commands = sys.modules[__name__]
2927 commands = sys.modules[__name__]
2926 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2928 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2927 ui.pager('help')
2929 ui.pager('help')
2928 ui.write(formatted)
2930 ui.write(formatted)
2929
2931
2930
2932
2931 @command('identify|id',
2933 @command('identify|id',
2932 [('r', 'rev', '',
2934 [('r', 'rev', '',
2933 _('identify the specified revision'), _('REV')),
2935 _('identify the specified revision'), _('REV')),
2934 ('n', 'num', None, _('show local revision number')),
2936 ('n', 'num', None, _('show local revision number')),
2935 ('i', 'id', None, _('show global revision id')),
2937 ('i', 'id', None, _('show global revision id')),
2936 ('b', 'branch', None, _('show branch')),
2938 ('b', 'branch', None, _('show branch')),
2937 ('t', 'tags', None, _('show tags')),
2939 ('t', 'tags', None, _('show tags')),
2938 ('B', 'bookmarks', None, _('show bookmarks')),
2940 ('B', 'bookmarks', None, _('show bookmarks')),
2939 ] + remoteopts + formatteropts,
2941 ] + remoteopts + formatteropts,
2940 _('[-nibtB] [-r REV] [SOURCE]'),
2942 _('[-nibtB] [-r REV] [SOURCE]'),
2941 optionalrepo=True,
2943 optionalrepo=True,
2942 intents={INTENT_READONLY})
2944 intents={INTENT_READONLY})
2943 def identify(ui, repo, source=None, rev=None,
2945 def identify(ui, repo, source=None, rev=None,
2944 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2946 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2945 """identify the working directory or specified revision
2947 """identify the working directory or specified revision
2946
2948
2947 Print a summary identifying the repository state at REV using one or
2949 Print a summary identifying the repository state at REV using one or
2948 two parent hash identifiers, followed by a "+" if the working
2950 two parent hash identifiers, followed by a "+" if the working
2949 directory has uncommitted changes, the branch name (if not default),
2951 directory has uncommitted changes, the branch name (if not default),
2950 a list of tags, and a list of bookmarks.
2952 a list of tags, and a list of bookmarks.
2951
2953
2952 When REV is not given, print a summary of the current state of the
2954 When REV is not given, print a summary of the current state of the
2953 repository including the working directory. Specify -r. to get information
2955 repository including the working directory. Specify -r. to get information
2954 of the working directory parent without scanning uncommitted changes.
2956 of the working directory parent without scanning uncommitted changes.
2955
2957
2956 Specifying a path to a repository root or Mercurial bundle will
2958 Specifying a path to a repository root or Mercurial bundle will
2957 cause lookup to operate on that repository/bundle.
2959 cause lookup to operate on that repository/bundle.
2958
2960
2959 .. container:: verbose
2961 .. container:: verbose
2960
2962
2961 Examples:
2963 Examples:
2962
2964
2963 - generate a build identifier for the working directory::
2965 - generate a build identifier for the working directory::
2964
2966
2965 hg id --id > build-id.dat
2967 hg id --id > build-id.dat
2966
2968
2967 - find the revision corresponding to a tag::
2969 - find the revision corresponding to a tag::
2968
2970
2969 hg id -n -r 1.3
2971 hg id -n -r 1.3
2970
2972
2971 - check the most recent revision of a remote repository::
2973 - check the most recent revision of a remote repository::
2972
2974
2973 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2975 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2974
2976
2975 See :hg:`log` for generating more information about specific revisions,
2977 See :hg:`log` for generating more information about specific revisions,
2976 including full hash identifiers.
2978 including full hash identifiers.
2977
2979
2978 Returns 0 if successful.
2980 Returns 0 if successful.
2979 """
2981 """
2980
2982
2981 opts = pycompat.byteskwargs(opts)
2983 opts = pycompat.byteskwargs(opts)
2982 if not repo and not source:
2984 if not repo and not source:
2983 raise error.Abort(_("there is no Mercurial repository here "
2985 raise error.Abort(_("there is no Mercurial repository here "
2984 "(.hg not found)"))
2986 "(.hg not found)"))
2985
2987
2986 default = not (num or id or branch or tags or bookmarks)
2988 default = not (num or id or branch or tags or bookmarks)
2987 output = []
2989 output = []
2988 revs = []
2990 revs = []
2989
2991
2990 if source:
2992 if source:
2991 source, branches = hg.parseurl(ui.expandpath(source))
2993 source, branches = hg.parseurl(ui.expandpath(source))
2992 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2994 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2993 repo = peer.local()
2995 repo = peer.local()
2994 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2996 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2995
2997
2996 fm = ui.formatter('identify', opts)
2998 fm = ui.formatter('identify', opts)
2997 fm.startitem()
2999 fm.startitem()
2998
3000
2999 if not repo:
3001 if not repo:
3000 if num or branch or tags:
3002 if num or branch or tags:
3001 raise error.Abort(
3003 raise error.Abort(
3002 _("can't query remote revision number, branch, or tags"))
3004 _("can't query remote revision number, branch, or tags"))
3003 if not rev and revs:
3005 if not rev and revs:
3004 rev = revs[0]
3006 rev = revs[0]
3005 if not rev:
3007 if not rev:
3006 rev = "tip"
3008 rev = "tip"
3007
3009
3008 remoterev = peer.lookup(rev)
3010 remoterev = peer.lookup(rev)
3009 hexrev = fm.hexfunc(remoterev)
3011 hexrev = fm.hexfunc(remoterev)
3010 if default or id:
3012 if default or id:
3011 output = [hexrev]
3013 output = [hexrev]
3012 fm.data(id=hexrev)
3014 fm.data(id=hexrev)
3013
3015
3014 def getbms():
3016 def getbms():
3015 bms = []
3017 bms = []
3016
3018
3017 if 'bookmarks' in peer.listkeys('namespaces'):
3019 if 'bookmarks' in peer.listkeys('namespaces'):
3018 hexremoterev = hex(remoterev)
3020 hexremoterev = hex(remoterev)
3019 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3021 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3020 if bmr == hexremoterev]
3022 if bmr == hexremoterev]
3021
3023
3022 return sorted(bms)
3024 return sorted(bms)
3023
3025
3024 bms = getbms()
3026 bms = getbms()
3025 if bookmarks:
3027 if bookmarks:
3026 output.extend(bms)
3028 output.extend(bms)
3027 elif default and not ui.quiet:
3029 elif default and not ui.quiet:
3028 # multiple bookmarks for a single parent separated by '/'
3030 # multiple bookmarks for a single parent separated by '/'
3029 bm = '/'.join(bms)
3031 bm = '/'.join(bms)
3030 if bm:
3032 if bm:
3031 output.append(bm)
3033 output.append(bm)
3032
3034
3033 fm.data(node=hex(remoterev))
3035 fm.data(node=hex(remoterev))
3034 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3036 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3035 else:
3037 else:
3036 if rev:
3038 if rev:
3037 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3038 ctx = scmutil.revsingle(repo, rev, None)
3040 ctx = scmutil.revsingle(repo, rev, None)
3039
3041
3040 if ctx.rev() is None:
3042 if ctx.rev() is None:
3041 ctx = repo[None]
3043 ctx = repo[None]
3042 parents = ctx.parents()
3044 parents = ctx.parents()
3043 taglist = []
3045 taglist = []
3044 for p in parents:
3046 for p in parents:
3045 taglist.extend(p.tags())
3047 taglist.extend(p.tags())
3046
3048
3047 dirty = ""
3049 dirty = ""
3048 if ctx.dirty(missing=True, merge=False, branch=False):
3050 if ctx.dirty(missing=True, merge=False, branch=False):
3049 dirty = '+'
3051 dirty = '+'
3050 fm.data(dirty=dirty)
3052 fm.data(dirty=dirty)
3051
3053
3052 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3054 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3053 if default or id:
3055 if default or id:
3054 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3056 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3055 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3057 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3056
3058
3057 if num:
3059 if num:
3058 numoutput = ["%d" % p.rev() for p in parents]
3060 numoutput = ["%d" % p.rev() for p in parents]
3059 output.append("%s%s" % ('+'.join(numoutput), dirty))
3061 output.append("%s%s" % ('+'.join(numoutput), dirty))
3060
3062
3061 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3063 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3062 for p in parents], name='node'))
3064 for p in parents], name='node'))
3063 else:
3065 else:
3064 hexoutput = fm.hexfunc(ctx.node())
3066 hexoutput = fm.hexfunc(ctx.node())
3065 if default or id:
3067 if default or id:
3066 output = [hexoutput]
3068 output = [hexoutput]
3067 fm.data(id=hexoutput)
3069 fm.data(id=hexoutput)
3068
3070
3069 if num:
3071 if num:
3070 output.append(pycompat.bytestr(ctx.rev()))
3072 output.append(pycompat.bytestr(ctx.rev()))
3071 taglist = ctx.tags()
3073 taglist = ctx.tags()
3072
3074
3073 if default and not ui.quiet:
3075 if default and not ui.quiet:
3074 b = ctx.branch()
3076 b = ctx.branch()
3075 if b != 'default':
3077 if b != 'default':
3076 output.append("(%s)" % b)
3078 output.append("(%s)" % b)
3077
3079
3078 # multiple tags for a single parent separated by '/'
3080 # multiple tags for a single parent separated by '/'
3079 t = '/'.join(taglist)
3081 t = '/'.join(taglist)
3080 if t:
3082 if t:
3081 output.append(t)
3083 output.append(t)
3082
3084
3083 # multiple bookmarks for a single parent separated by '/'
3085 # multiple bookmarks for a single parent separated by '/'
3084 bm = '/'.join(ctx.bookmarks())
3086 bm = '/'.join(ctx.bookmarks())
3085 if bm:
3087 if bm:
3086 output.append(bm)
3088 output.append(bm)
3087 else:
3089 else:
3088 if branch:
3090 if branch:
3089 output.append(ctx.branch())
3091 output.append(ctx.branch())
3090
3092
3091 if tags:
3093 if tags:
3092 output.extend(taglist)
3094 output.extend(taglist)
3093
3095
3094 if bookmarks:
3096 if bookmarks:
3095 output.extend(ctx.bookmarks())
3097 output.extend(ctx.bookmarks())
3096
3098
3097 fm.data(node=ctx.hex())
3099 fm.data(node=ctx.hex())
3098 fm.data(branch=ctx.branch())
3100 fm.data(branch=ctx.branch())
3099 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3101 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3100 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3102 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3101 fm.context(ctx=ctx)
3103 fm.context(ctx=ctx)
3102
3104
3103 fm.plain("%s\n" % ' '.join(output))
3105 fm.plain("%s\n" % ' '.join(output))
3104 fm.end()
3106 fm.end()
3105
3107
3106 @command('import|patch',
3108 @command('import|patch',
3107 [('p', 'strip', 1,
3109 [('p', 'strip', 1,
3108 _('directory strip option for patch. This has the same '
3110 _('directory strip option for patch. This has the same '
3109 'meaning as the corresponding patch option'), _('NUM')),
3111 'meaning as the corresponding patch option'), _('NUM')),
3110 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3112 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3111 ('e', 'edit', False, _('invoke editor on commit messages')),
3113 ('e', 'edit', False, _('invoke editor on commit messages')),
3112 ('f', 'force', None,
3114 ('f', 'force', None,
3113 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3115 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3114 ('', 'no-commit', None,
3116 ('', 'no-commit', None,
3115 _("don't commit, just update the working directory")),
3117 _("don't commit, just update the working directory")),
3116 ('', 'bypass', None,
3118 ('', 'bypass', None,
3117 _("apply patch without touching the working directory")),
3119 _("apply patch without touching the working directory")),
3118 ('', 'partial', None,
3120 ('', 'partial', None,
3119 _('commit even if some hunks fail')),
3121 _('commit even if some hunks fail')),
3120 ('', 'exact', None,
3122 ('', 'exact', None,
3121 _('abort if patch would apply lossily')),
3123 _('abort if patch would apply lossily')),
3122 ('', 'prefix', '',
3124 ('', 'prefix', '',
3123 _('apply patch to subdirectory'), _('DIR')),
3125 _('apply patch to subdirectory'), _('DIR')),
3124 ('', 'import-branch', None,
3126 ('', 'import-branch', None,
3125 _('use any branch information in patch (implied by --exact)'))] +
3127 _('use any branch information in patch (implied by --exact)'))] +
3126 commitopts + commitopts2 + similarityopts,
3128 commitopts + commitopts2 + similarityopts,
3127 _('[OPTION]... PATCH...'))
3129 _('[OPTION]... PATCH...'))
3128 def import_(ui, repo, patch1=None, *patches, **opts):
3130 def import_(ui, repo, patch1=None, *patches, **opts):
3129 """import an ordered set of patches
3131 """import an ordered set of patches
3130
3132
3131 Import a list of patches and commit them individually (unless
3133 Import a list of patches and commit them individually (unless
3132 --no-commit is specified).
3134 --no-commit is specified).
3133
3135
3134 To read a patch from standard input (stdin), use "-" as the patch
3136 To read a patch from standard input (stdin), use "-" as the patch
3135 name. If a URL is specified, the patch will be downloaded from
3137 name. If a URL is specified, the patch will be downloaded from
3136 there.
3138 there.
3137
3139
3138 Import first applies changes to the working directory (unless
3140 Import first applies changes to the working directory (unless
3139 --bypass is specified), import will abort if there are outstanding
3141 --bypass is specified), import will abort if there are outstanding
3140 changes.
3142 changes.
3141
3143
3142 Use --bypass to apply and commit patches directly to the
3144 Use --bypass to apply and commit patches directly to the
3143 repository, without affecting the working directory. Without
3145 repository, without affecting the working directory. Without
3144 --exact, patches will be applied on top of the working directory
3146 --exact, patches will be applied on top of the working directory
3145 parent revision.
3147 parent revision.
3146
3148
3147 You can import a patch straight from a mail message. Even patches
3149 You can import a patch straight from a mail message. Even patches
3148 as attachments work (to use the body part, it must have type
3150 as attachments work (to use the body part, it must have type
3149 text/plain or text/x-patch). From and Subject headers of email
3151 text/plain or text/x-patch). From and Subject headers of email
3150 message are used as default committer and commit message. All
3152 message are used as default committer and commit message. All
3151 text/plain body parts before first diff are added to the commit
3153 text/plain body parts before first diff are added to the commit
3152 message.
3154 message.
3153
3155
3154 If the imported patch was generated by :hg:`export`, user and
3156 If the imported patch was generated by :hg:`export`, user and
3155 description from patch override values from message headers and
3157 description from patch override values from message headers and
3156 body. Values given on command line with -m/--message and -u/--user
3158 body. Values given on command line with -m/--message and -u/--user
3157 override these.
3159 override these.
3158
3160
3159 If --exact is specified, import will set the working directory to
3161 If --exact is specified, import will set the working directory to
3160 the parent of each patch before applying it, and will abort if the
3162 the parent of each patch before applying it, and will abort if the
3161 resulting changeset has a different ID than the one recorded in
3163 resulting changeset has a different ID than the one recorded in
3162 the patch. This will guard against various ways that portable
3164 the patch. This will guard against various ways that portable
3163 patch formats and mail systems might fail to transfer Mercurial
3165 patch formats and mail systems might fail to transfer Mercurial
3164 data or metadata. See :hg:`bundle` for lossless transmission.
3166 data or metadata. See :hg:`bundle` for lossless transmission.
3165
3167
3166 Use --partial to ensure a changeset will be created from the patch
3168 Use --partial to ensure a changeset will be created from the patch
3167 even if some hunks fail to apply. Hunks that fail to apply will be
3169 even if some hunks fail to apply. Hunks that fail to apply will be
3168 written to a <target-file>.rej file. Conflicts can then be resolved
3170 written to a <target-file>.rej file. Conflicts can then be resolved
3169 by hand before :hg:`commit --amend` is run to update the created
3171 by hand before :hg:`commit --amend` is run to update the created
3170 changeset. This flag exists to let people import patches that
3172 changeset. This flag exists to let people import patches that
3171 partially apply without losing the associated metadata (author,
3173 partially apply without losing the associated metadata (author,
3172 date, description, ...).
3174 date, description, ...).
3173
3175
3174 .. note::
3176 .. note::
3175
3177
3176 When no hunks apply cleanly, :hg:`import --partial` will create
3178 When no hunks apply cleanly, :hg:`import --partial` will create
3177 an empty changeset, importing only the patch metadata.
3179 an empty changeset, importing only the patch metadata.
3178
3180
3179 With -s/--similarity, hg will attempt to discover renames and
3181 With -s/--similarity, hg will attempt to discover renames and
3180 copies in the patch in the same way as :hg:`addremove`.
3182 copies in the patch in the same way as :hg:`addremove`.
3181
3183
3182 It is possible to use external patch programs to perform the patch
3184 It is possible to use external patch programs to perform the patch
3183 by setting the ``ui.patch`` configuration option. For the default
3185 by setting the ``ui.patch`` configuration option. For the default
3184 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3186 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3185 See :hg:`help config` for more information about configuration
3187 See :hg:`help config` for more information about configuration
3186 files and how to use these options.
3188 files and how to use these options.
3187
3189
3188 See :hg:`help dates` for a list of formats valid for -d/--date.
3190 See :hg:`help dates` for a list of formats valid for -d/--date.
3189
3191
3190 .. container:: verbose
3192 .. container:: verbose
3191
3193
3192 Examples:
3194 Examples:
3193
3195
3194 - import a traditional patch from a website and detect renames::
3196 - import a traditional patch from a website and detect renames::
3195
3197
3196 hg import -s 80 http://example.com/bugfix.patch
3198 hg import -s 80 http://example.com/bugfix.patch
3197
3199
3198 - import a changeset from an hgweb server::
3200 - import a changeset from an hgweb server::
3199
3201
3200 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3202 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3201
3203
3202 - import all the patches in an Unix-style mbox::
3204 - import all the patches in an Unix-style mbox::
3203
3205
3204 hg import incoming-patches.mbox
3206 hg import incoming-patches.mbox
3205
3207
3206 - import patches from stdin::
3208 - import patches from stdin::
3207
3209
3208 hg import -
3210 hg import -
3209
3211
3210 - attempt to exactly restore an exported changeset (not always
3212 - attempt to exactly restore an exported changeset (not always
3211 possible)::
3213 possible)::
3212
3214
3213 hg import --exact proposed-fix.patch
3215 hg import --exact proposed-fix.patch
3214
3216
3215 - use an external tool to apply a patch which is too fuzzy for
3217 - use an external tool to apply a patch which is too fuzzy for
3216 the default internal tool.
3218 the default internal tool.
3217
3219
3218 hg import --config ui.patch="patch --merge" fuzzy.patch
3220 hg import --config ui.patch="patch --merge" fuzzy.patch
3219
3221
3220 - change the default fuzzing from 2 to a less strict 7
3222 - change the default fuzzing from 2 to a less strict 7
3221
3223
3222 hg import --config ui.fuzz=7 fuzz.patch
3224 hg import --config ui.fuzz=7 fuzz.patch
3223
3225
3224 Returns 0 on success, 1 on partial success (see --partial).
3226 Returns 0 on success, 1 on partial success (see --partial).
3225 """
3227 """
3226
3228
3227 opts = pycompat.byteskwargs(opts)
3229 opts = pycompat.byteskwargs(opts)
3228 if not patch1:
3230 if not patch1:
3229 raise error.Abort(_('need at least one patch to import'))
3231 raise error.Abort(_('need at least one patch to import'))
3230
3232
3231 patches = (patch1,) + patches
3233 patches = (patch1,) + patches
3232
3234
3233 date = opts.get('date')
3235 date = opts.get('date')
3234 if date:
3236 if date:
3235 opts['date'] = dateutil.parsedate(date)
3237 opts['date'] = dateutil.parsedate(date)
3236
3238
3237 exact = opts.get('exact')
3239 exact = opts.get('exact')
3238 update = not opts.get('bypass')
3240 update = not opts.get('bypass')
3239 if not update and opts.get('no_commit'):
3241 if not update and opts.get('no_commit'):
3240 raise error.Abort(_('cannot use --no-commit with --bypass'))
3242 raise error.Abort(_('cannot use --no-commit with --bypass'))
3241 try:
3243 try:
3242 sim = float(opts.get('similarity') or 0)
3244 sim = float(opts.get('similarity') or 0)
3243 except ValueError:
3245 except ValueError:
3244 raise error.Abort(_('similarity must be a number'))
3246 raise error.Abort(_('similarity must be a number'))
3245 if sim < 0 or sim > 100:
3247 if sim < 0 or sim > 100:
3246 raise error.Abort(_('similarity must be between 0 and 100'))
3248 raise error.Abort(_('similarity must be between 0 and 100'))
3247 if sim and not update:
3249 if sim and not update:
3248 raise error.Abort(_('cannot use --similarity with --bypass'))
3250 raise error.Abort(_('cannot use --similarity with --bypass'))
3249 if exact:
3251 if exact:
3250 if opts.get('edit'):
3252 if opts.get('edit'):
3251 raise error.Abort(_('cannot use --exact with --edit'))
3253 raise error.Abort(_('cannot use --exact with --edit'))
3252 if opts.get('prefix'):
3254 if opts.get('prefix'):
3253 raise error.Abort(_('cannot use --exact with --prefix'))
3255 raise error.Abort(_('cannot use --exact with --prefix'))
3254
3256
3255 base = opts["base"]
3257 base = opts["base"]
3256 msgs = []
3258 msgs = []
3257 ret = 0
3259 ret = 0
3258
3260
3259 with repo.wlock():
3261 with repo.wlock():
3260 if update:
3262 if update:
3261 cmdutil.checkunfinished(repo)
3263 cmdutil.checkunfinished(repo)
3262 if (exact or not opts.get('force')):
3264 if (exact or not opts.get('force')):
3263 cmdutil.bailifchanged(repo)
3265 cmdutil.bailifchanged(repo)
3264
3266
3265 if not opts.get('no_commit'):
3267 if not opts.get('no_commit'):
3266 lock = repo.lock
3268 lock = repo.lock
3267 tr = lambda: repo.transaction('import')
3269 tr = lambda: repo.transaction('import')
3268 dsguard = util.nullcontextmanager
3270 dsguard = util.nullcontextmanager
3269 else:
3271 else:
3270 lock = util.nullcontextmanager
3272 lock = util.nullcontextmanager
3271 tr = util.nullcontextmanager
3273 tr = util.nullcontextmanager
3272 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3274 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3273 with lock(), tr(), dsguard():
3275 with lock(), tr(), dsguard():
3274 parents = repo[None].parents()
3276 parents = repo[None].parents()
3275 for patchurl in patches:
3277 for patchurl in patches:
3276 if patchurl == '-':
3278 if patchurl == '-':
3277 ui.status(_('applying patch from stdin\n'))
3279 ui.status(_('applying patch from stdin\n'))
3278 patchfile = ui.fin
3280 patchfile = ui.fin
3279 patchurl = 'stdin' # for error message
3281 patchurl = 'stdin' # for error message
3280 else:
3282 else:
3281 patchurl = os.path.join(base, patchurl)
3283 patchurl = os.path.join(base, patchurl)
3282 ui.status(_('applying %s\n') % patchurl)
3284 ui.status(_('applying %s\n') % patchurl)
3283 patchfile = hg.openpath(ui, patchurl)
3285 patchfile = hg.openpath(ui, patchurl)
3284
3286
3285 haspatch = False
3287 haspatch = False
3286 for hunk in patch.split(patchfile):
3288 for hunk in patch.split(patchfile):
3287 with patch.extract(ui, hunk) as patchdata:
3289 with patch.extract(ui, hunk) as patchdata:
3288 msg, node, rej = cmdutil.tryimportone(ui, repo,
3290 msg, node, rej = cmdutil.tryimportone(ui, repo,
3289 patchdata,
3291 patchdata,
3290 parents, opts,
3292 parents, opts,
3291 msgs, hg.clean)
3293 msgs, hg.clean)
3292 if msg:
3294 if msg:
3293 haspatch = True
3295 haspatch = True
3294 ui.note(msg + '\n')
3296 ui.note(msg + '\n')
3295 if update or exact:
3297 if update or exact:
3296 parents = repo[None].parents()
3298 parents = repo[None].parents()
3297 else:
3299 else:
3298 parents = [repo[node]]
3300 parents = [repo[node]]
3299 if rej:
3301 if rej:
3300 ui.write_err(_("patch applied partially\n"))
3302 ui.write_err(_("patch applied partially\n"))
3301 ui.write_err(_("(fix the .rej files and run "
3303 ui.write_err(_("(fix the .rej files and run "
3302 "`hg commit --amend`)\n"))
3304 "`hg commit --amend`)\n"))
3303 ret = 1
3305 ret = 1
3304 break
3306 break
3305
3307
3306 if not haspatch:
3308 if not haspatch:
3307 raise error.Abort(_('%s: no diffs found') % patchurl)
3309 raise error.Abort(_('%s: no diffs found') % patchurl)
3308
3310
3309 if msgs:
3311 if msgs:
3310 repo.savecommitmessage('\n* * *\n'.join(msgs))
3312 repo.savecommitmessage('\n* * *\n'.join(msgs))
3311 return ret
3313 return ret
3312
3314
3313 @command('incoming|in',
3315 @command('incoming|in',
3314 [('f', 'force', None,
3316 [('f', 'force', None,
3315 _('run even if remote repository is unrelated')),
3317 _('run even if remote repository is unrelated')),
3316 ('n', 'newest-first', None, _('show newest record first')),
3318 ('n', 'newest-first', None, _('show newest record first')),
3317 ('', 'bundle', '',
3319 ('', 'bundle', '',
3318 _('file to store the bundles into'), _('FILE')),
3320 _('file to store the bundles into'), _('FILE')),
3319 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3321 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3320 ('B', 'bookmarks', False, _("compare bookmarks")),
3322 ('B', 'bookmarks', False, _("compare bookmarks")),
3321 ('b', 'branch', [],
3323 ('b', 'branch', [],
3322 _('a specific branch you would like to pull'), _('BRANCH')),
3324 _('a specific branch you would like to pull'), _('BRANCH')),
3323 ] + logopts + remoteopts + subrepoopts,
3325 ] + logopts + remoteopts + subrepoopts,
3324 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3326 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3325 def incoming(ui, repo, source="default", **opts):
3327 def incoming(ui, repo, source="default", **opts):
3326 """show new changesets found in source
3328 """show new changesets found in source
3327
3329
3328 Show new changesets found in the specified path/URL or the default
3330 Show new changesets found in the specified path/URL or the default
3329 pull location. These are the changesets that would have been pulled
3331 pull location. These are the changesets that would have been pulled
3330 by :hg:`pull` at the time you issued this command.
3332 by :hg:`pull` at the time you issued this command.
3331
3333
3332 See pull for valid source format details.
3334 See pull for valid source format details.
3333
3335
3334 .. container:: verbose
3336 .. container:: verbose
3335
3337
3336 With -B/--bookmarks, the result of bookmark comparison between
3338 With -B/--bookmarks, the result of bookmark comparison between
3337 local and remote repositories is displayed. With -v/--verbose,
3339 local and remote repositories is displayed. With -v/--verbose,
3338 status is also displayed for each bookmark like below::
3340 status is also displayed for each bookmark like below::
3339
3341
3340 BM1 01234567890a added
3342 BM1 01234567890a added
3341 BM2 1234567890ab advanced
3343 BM2 1234567890ab advanced
3342 BM3 234567890abc diverged
3344 BM3 234567890abc diverged
3343 BM4 34567890abcd changed
3345 BM4 34567890abcd changed
3344
3346
3345 The action taken locally when pulling depends on the
3347 The action taken locally when pulling depends on the
3346 status of each bookmark:
3348 status of each bookmark:
3347
3349
3348 :``added``: pull will create it
3350 :``added``: pull will create it
3349 :``advanced``: pull will update it
3351 :``advanced``: pull will update it
3350 :``diverged``: pull will create a divergent bookmark
3352 :``diverged``: pull will create a divergent bookmark
3351 :``changed``: result depends on remote changesets
3353 :``changed``: result depends on remote changesets
3352
3354
3353 From the point of view of pulling behavior, bookmark
3355 From the point of view of pulling behavior, bookmark
3354 existing only in the remote repository are treated as ``added``,
3356 existing only in the remote repository are treated as ``added``,
3355 even if it is in fact locally deleted.
3357 even if it is in fact locally deleted.
3356
3358
3357 .. container:: verbose
3359 .. container:: verbose
3358
3360
3359 For remote repository, using --bundle avoids downloading the
3361 For remote repository, using --bundle avoids downloading the
3360 changesets twice if the incoming is followed by a pull.
3362 changesets twice if the incoming is followed by a pull.
3361
3363
3362 Examples:
3364 Examples:
3363
3365
3364 - show incoming changes with patches and full description::
3366 - show incoming changes with patches and full description::
3365
3367
3366 hg incoming -vp
3368 hg incoming -vp
3367
3369
3368 - show incoming changes excluding merges, store a bundle::
3370 - show incoming changes excluding merges, store a bundle::
3369
3371
3370 hg in -vpM --bundle incoming.hg
3372 hg in -vpM --bundle incoming.hg
3371 hg pull incoming.hg
3373 hg pull incoming.hg
3372
3374
3373 - briefly list changes inside a bundle::
3375 - briefly list changes inside a bundle::
3374
3376
3375 hg in changes.hg -T "{desc|firstline}\\n"
3377 hg in changes.hg -T "{desc|firstline}\\n"
3376
3378
3377 Returns 0 if there are incoming changes, 1 otherwise.
3379 Returns 0 if there are incoming changes, 1 otherwise.
3378 """
3380 """
3379 opts = pycompat.byteskwargs(opts)
3381 opts = pycompat.byteskwargs(opts)
3380 if opts.get('graph'):
3382 if opts.get('graph'):
3381 logcmdutil.checkunsupportedgraphflags([], opts)
3383 logcmdutil.checkunsupportedgraphflags([], opts)
3382 def display(other, chlist, displayer):
3384 def display(other, chlist, displayer):
3383 revdag = logcmdutil.graphrevs(other, chlist, opts)
3385 revdag = logcmdutil.graphrevs(other, chlist, opts)
3384 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3386 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3385 graphmod.asciiedges)
3387 graphmod.asciiedges)
3386
3388
3387 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3389 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3388 return 0
3390 return 0
3389
3391
3390 if opts.get('bundle') and opts.get('subrepos'):
3392 if opts.get('bundle') and opts.get('subrepos'):
3391 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3393 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3392
3394
3393 if opts.get('bookmarks'):
3395 if opts.get('bookmarks'):
3394 source, branches = hg.parseurl(ui.expandpath(source),
3396 source, branches = hg.parseurl(ui.expandpath(source),
3395 opts.get('branch'))
3397 opts.get('branch'))
3396 other = hg.peer(repo, opts, source)
3398 other = hg.peer(repo, opts, source)
3397 if 'bookmarks' not in other.listkeys('namespaces'):
3399 if 'bookmarks' not in other.listkeys('namespaces'):
3398 ui.warn(_("remote doesn't support bookmarks\n"))
3400 ui.warn(_("remote doesn't support bookmarks\n"))
3399 return 0
3401 return 0
3400 ui.pager('incoming')
3402 ui.pager('incoming')
3401 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3403 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3402 return bookmarks.incoming(ui, repo, other)
3404 return bookmarks.incoming(ui, repo, other)
3403
3405
3404 repo._subtoppath = ui.expandpath(source)
3406 repo._subtoppath = ui.expandpath(source)
3405 try:
3407 try:
3406 return hg.incoming(ui, repo, source, opts)
3408 return hg.incoming(ui, repo, source, opts)
3407 finally:
3409 finally:
3408 del repo._subtoppath
3410 del repo._subtoppath
3409
3411
3410
3412
3411 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3413 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3412 norepo=True)
3414 norepo=True)
3413 def init(ui, dest=".", **opts):
3415 def init(ui, dest=".", **opts):
3414 """create a new repository in the given directory
3416 """create a new repository in the given directory
3415
3417
3416 Initialize a new repository in the given directory. If the given
3418 Initialize a new repository in the given directory. If the given
3417 directory does not exist, it will be created.
3419 directory does not exist, it will be created.
3418
3420
3419 If no directory is given, the current directory is used.
3421 If no directory is given, the current directory is used.
3420
3422
3421 It is possible to specify an ``ssh://`` URL as the destination.
3423 It is possible to specify an ``ssh://`` URL as the destination.
3422 See :hg:`help urls` for more information.
3424 See :hg:`help urls` for more information.
3423
3425
3424 Returns 0 on success.
3426 Returns 0 on success.
3425 """
3427 """
3426 opts = pycompat.byteskwargs(opts)
3428 opts = pycompat.byteskwargs(opts)
3427 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3429 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3428
3430
3429 @command('locate',
3431 @command('locate',
3430 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3432 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3431 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3433 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3432 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3434 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3433 ] + walkopts,
3435 ] + walkopts,
3434 _('[OPTION]... [PATTERN]...'))
3436 _('[OPTION]... [PATTERN]...'))
3435 def locate(ui, repo, *pats, **opts):
3437 def locate(ui, repo, *pats, **opts):
3436 """locate files matching specific patterns (DEPRECATED)
3438 """locate files matching specific patterns (DEPRECATED)
3437
3439
3438 Print files under Mercurial control in the working directory whose
3440 Print files under Mercurial control in the working directory whose
3439 names match the given patterns.
3441 names match the given patterns.
3440
3442
3441 By default, this command searches all directories in the working
3443 By default, this command searches all directories in the working
3442 directory. To search just the current directory and its
3444 directory. To search just the current directory and its
3443 subdirectories, use "--include .".
3445 subdirectories, use "--include .".
3444
3446
3445 If no patterns are given to match, this command prints the names
3447 If no patterns are given to match, this command prints the names
3446 of all files under Mercurial control in the working directory.
3448 of all files under Mercurial control in the working directory.
3447
3449
3448 If you want to feed the output of this command into the "xargs"
3450 If you want to feed the output of this command into the "xargs"
3449 command, use the -0 option to both this command and "xargs". This
3451 command, use the -0 option to both this command and "xargs". This
3450 will avoid the problem of "xargs" treating single filenames that
3452 will avoid the problem of "xargs" treating single filenames that
3451 contain whitespace as multiple filenames.
3453 contain whitespace as multiple filenames.
3452
3454
3453 See :hg:`help files` for a more versatile command.
3455 See :hg:`help files` for a more versatile command.
3454
3456
3455 Returns 0 if a match is found, 1 otherwise.
3457 Returns 0 if a match is found, 1 otherwise.
3456 """
3458 """
3457 opts = pycompat.byteskwargs(opts)
3459 opts = pycompat.byteskwargs(opts)
3458 if opts.get('print0'):
3460 if opts.get('print0'):
3459 end = '\0'
3461 end = '\0'
3460 else:
3462 else:
3461 end = '\n'
3463 end = '\n'
3462 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3464 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3463
3465
3464 ret = 1
3466 ret = 1
3465 m = scmutil.match(ctx, pats, opts, default='relglob',
3467 m = scmutil.match(ctx, pats, opts, default='relglob',
3466 badfn=lambda x, y: False)
3468 badfn=lambda x, y: False)
3467
3469
3468 ui.pager('locate')
3470 ui.pager('locate')
3469 if ctx.rev() is None:
3471 if ctx.rev() is None:
3470 # When run on the working copy, "locate" includes removed files, so
3472 # When run on the working copy, "locate" includes removed files, so
3471 # we get the list of files from the dirstate.
3473 # we get the list of files from the dirstate.
3472 filesgen = sorted(repo.dirstate.matches(m))
3474 filesgen = sorted(repo.dirstate.matches(m))
3473 else:
3475 else:
3474 filesgen = ctx.matches(m)
3476 filesgen = ctx.matches(m)
3475 for abs in filesgen:
3477 for abs in filesgen:
3476 if opts.get('fullpath'):
3478 if opts.get('fullpath'):
3477 ui.write(repo.wjoin(abs), end)
3479 ui.write(repo.wjoin(abs), end)
3478 else:
3480 else:
3479 ui.write(((pats and m.rel(abs)) or abs), end)
3481 ui.write(((pats and m.rel(abs)) or abs), end)
3480 ret = 0
3482 ret = 0
3481
3483
3482 return ret
3484 return ret
3483
3485
3484 @command('^log|history',
3486 @command('^log|history',
3485 [('f', 'follow', None,
3487 [('f', 'follow', None,
3486 _('follow changeset history, or file history across copies and renames')),
3488 _('follow changeset history, or file history across copies and renames')),
3487 ('', 'follow-first', None,
3489 ('', 'follow-first', None,
3488 _('only follow the first parent of merge changesets (DEPRECATED)')),
3490 _('only follow the first parent of merge changesets (DEPRECATED)')),
3489 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3491 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3490 ('C', 'copies', None, _('show copied files')),
3492 ('C', 'copies', None, _('show copied files')),
3491 ('k', 'keyword', [],
3493 ('k', 'keyword', [],
3492 _('do case-insensitive search for a given text'), _('TEXT')),
3494 _('do case-insensitive search for a given text'), _('TEXT')),
3493 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3495 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3494 ('L', 'line-range', [],
3496 ('L', 'line-range', [],
3495 _('follow line range of specified file (EXPERIMENTAL)'),
3497 _('follow line range of specified file (EXPERIMENTAL)'),
3496 _('FILE,RANGE')),
3498 _('FILE,RANGE')),
3497 ('', 'removed', None, _('include revisions where files were removed')),
3499 ('', 'removed', None, _('include revisions where files were removed')),
3498 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3500 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3499 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3501 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3500 ('', 'only-branch', [],
3502 ('', 'only-branch', [],
3501 _('show only changesets within the given named branch (DEPRECATED)'),
3503 _('show only changesets within the given named branch (DEPRECATED)'),
3502 _('BRANCH')),
3504 _('BRANCH')),
3503 ('b', 'branch', [],
3505 ('b', 'branch', [],
3504 _('show changesets within the given named branch'), _('BRANCH')),
3506 _('show changesets within the given named branch'), _('BRANCH')),
3505 ('P', 'prune', [],
3507 ('P', 'prune', [],
3506 _('do not display revision or any of its ancestors'), _('REV')),
3508 _('do not display revision or any of its ancestors'), _('REV')),
3507 ] + logopts + walkopts,
3509 ] + logopts + walkopts,
3508 _('[OPTION]... [FILE]'),
3510 _('[OPTION]... [FILE]'),
3509 inferrepo=True,
3511 inferrepo=True,
3510 intents={INTENT_READONLY})
3512 intents={INTENT_READONLY})
3511 def log(ui, repo, *pats, **opts):
3513 def log(ui, repo, *pats, **opts):
3512 """show revision history of entire repository or files
3514 """show revision history of entire repository or files
3513
3515
3514 Print the revision history of the specified files or the entire
3516 Print the revision history of the specified files or the entire
3515 project.
3517 project.
3516
3518
3517 If no revision range is specified, the default is ``tip:0`` unless
3519 If no revision range is specified, the default is ``tip:0`` unless
3518 --follow is set, in which case the working directory parent is
3520 --follow is set, in which case the working directory parent is
3519 used as the starting revision.
3521 used as the starting revision.
3520
3522
3521 File history is shown without following rename or copy history of
3523 File history is shown without following rename or copy history of
3522 files. Use -f/--follow with a filename to follow history across
3524 files. Use -f/--follow with a filename to follow history across
3523 renames and copies. --follow without a filename will only show
3525 renames and copies. --follow without a filename will only show
3524 ancestors of the starting revision.
3526 ancestors of the starting revision.
3525
3527
3526 By default this command prints revision number and changeset id,
3528 By default this command prints revision number and changeset id,
3527 tags, non-trivial parents, user, date and time, and a summary for
3529 tags, non-trivial parents, user, date and time, and a summary for
3528 each commit. When the -v/--verbose switch is used, the list of
3530 each commit. When the -v/--verbose switch is used, the list of
3529 changed files and full commit message are shown.
3531 changed files and full commit message are shown.
3530
3532
3531 With --graph the revisions are shown as an ASCII art DAG with the most
3533 With --graph the revisions are shown as an ASCII art DAG with the most
3532 recent changeset at the top.
3534 recent changeset at the top.
3533 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3535 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3534 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3536 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3535 changeset from the lines below is a parent of the 'o' merge on the same
3537 changeset from the lines below is a parent of the 'o' merge on the same
3536 line.
3538 line.
3537 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3539 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3538 of a '|' indicates one or more revisions in a path are omitted.
3540 of a '|' indicates one or more revisions in a path are omitted.
3539
3541
3540 .. container:: verbose
3542 .. container:: verbose
3541
3543
3542 Use -L/--line-range FILE,M:N options to follow the history of lines
3544 Use -L/--line-range FILE,M:N options to follow the history of lines
3543 from M to N in FILE. With -p/--patch only diff hunks affecting
3545 from M to N in FILE. With -p/--patch only diff hunks affecting
3544 specified line range will be shown. This option requires --follow;
3546 specified line range will be shown. This option requires --follow;
3545 it can be specified multiple times. Currently, this option is not
3547 it can be specified multiple times. Currently, this option is not
3546 compatible with --graph. This option is experimental.
3548 compatible with --graph. This option is experimental.
3547
3549
3548 .. note::
3550 .. note::
3549
3551
3550 :hg:`log --patch` may generate unexpected diff output for merge
3552 :hg:`log --patch` may generate unexpected diff output for merge
3551 changesets, as it will only compare the merge changeset against
3553 changesets, as it will only compare the merge changeset against
3552 its first parent. Also, only files different from BOTH parents
3554 its first parent. Also, only files different from BOTH parents
3553 will appear in files:.
3555 will appear in files:.
3554
3556
3555 .. note::
3557 .. note::
3556
3558
3557 For performance reasons, :hg:`log FILE` may omit duplicate changes
3559 For performance reasons, :hg:`log FILE` may omit duplicate changes
3558 made on branches and will not show removals or mode changes. To
3560 made on branches and will not show removals or mode changes. To
3559 see all such changes, use the --removed switch.
3561 see all such changes, use the --removed switch.
3560
3562
3561 .. container:: verbose
3563 .. container:: verbose
3562
3564
3563 .. note::
3565 .. note::
3564
3566
3565 The history resulting from -L/--line-range options depends on diff
3567 The history resulting from -L/--line-range options depends on diff
3566 options; for instance if white-spaces are ignored, respective changes
3568 options; for instance if white-spaces are ignored, respective changes
3567 with only white-spaces in specified line range will not be listed.
3569 with only white-spaces in specified line range will not be listed.
3568
3570
3569 .. container:: verbose
3571 .. container:: verbose
3570
3572
3571 Some examples:
3573 Some examples:
3572
3574
3573 - changesets with full descriptions and file lists::
3575 - changesets with full descriptions and file lists::
3574
3576
3575 hg log -v
3577 hg log -v
3576
3578
3577 - changesets ancestral to the working directory::
3579 - changesets ancestral to the working directory::
3578
3580
3579 hg log -f
3581 hg log -f
3580
3582
3581 - last 10 commits on the current branch::
3583 - last 10 commits on the current branch::
3582
3584
3583 hg log -l 10 -b .
3585 hg log -l 10 -b .
3584
3586
3585 - changesets showing all modifications of a file, including removals::
3587 - changesets showing all modifications of a file, including removals::
3586
3588
3587 hg log --removed file.c
3589 hg log --removed file.c
3588
3590
3589 - all changesets that touch a directory, with diffs, excluding merges::
3591 - all changesets that touch a directory, with diffs, excluding merges::
3590
3592
3591 hg log -Mp lib/
3593 hg log -Mp lib/
3592
3594
3593 - all revision numbers that match a keyword::
3595 - all revision numbers that match a keyword::
3594
3596
3595 hg log -k bug --template "{rev}\\n"
3597 hg log -k bug --template "{rev}\\n"
3596
3598
3597 - the full hash identifier of the working directory parent::
3599 - the full hash identifier of the working directory parent::
3598
3600
3599 hg log -r . --template "{node}\\n"
3601 hg log -r . --template "{node}\\n"
3600
3602
3601 - list available log templates::
3603 - list available log templates::
3602
3604
3603 hg log -T list
3605 hg log -T list
3604
3606
3605 - check if a given changeset is included in a tagged release::
3607 - check if a given changeset is included in a tagged release::
3606
3608
3607 hg log -r "a21ccf and ancestor(1.9)"
3609 hg log -r "a21ccf and ancestor(1.9)"
3608
3610
3609 - find all changesets by some user in a date range::
3611 - find all changesets by some user in a date range::
3610
3612
3611 hg log -k alice -d "may 2008 to jul 2008"
3613 hg log -k alice -d "may 2008 to jul 2008"
3612
3614
3613 - summary of all changesets after the last tag::
3615 - summary of all changesets after the last tag::
3614
3616
3615 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3617 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3616
3618
3617 - changesets touching lines 13 to 23 for file.c::
3619 - changesets touching lines 13 to 23 for file.c::
3618
3620
3619 hg log -L file.c,13:23
3621 hg log -L file.c,13:23
3620
3622
3621 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3623 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3622 main.c with patch::
3624 main.c with patch::
3623
3625
3624 hg log -L file.c,13:23 -L main.c,2:6 -p
3626 hg log -L file.c,13:23 -L main.c,2:6 -p
3625
3627
3626 See :hg:`help dates` for a list of formats valid for -d/--date.
3628 See :hg:`help dates` for a list of formats valid for -d/--date.
3627
3629
3628 See :hg:`help revisions` for more about specifying and ordering
3630 See :hg:`help revisions` for more about specifying and ordering
3629 revisions.
3631 revisions.
3630
3632
3631 See :hg:`help templates` for more about pre-packaged styles and
3633 See :hg:`help templates` for more about pre-packaged styles and
3632 specifying custom templates. The default template used by the log
3634 specifying custom templates. The default template used by the log
3633 command can be customized via the ``ui.logtemplate`` configuration
3635 command can be customized via the ``ui.logtemplate`` configuration
3634 setting.
3636 setting.
3635
3637
3636 Returns 0 on success.
3638 Returns 0 on success.
3637
3639
3638 """
3640 """
3639 opts = pycompat.byteskwargs(opts)
3641 opts = pycompat.byteskwargs(opts)
3640 linerange = opts.get('line_range')
3642 linerange = opts.get('line_range')
3641
3643
3642 if linerange and not opts.get('follow'):
3644 if linerange and not opts.get('follow'):
3643 raise error.Abort(_('--line-range requires --follow'))
3645 raise error.Abort(_('--line-range requires --follow'))
3644
3646
3645 if linerange and pats:
3647 if linerange and pats:
3646 # TODO: take pats as patterns with no line-range filter
3648 # TODO: take pats as patterns with no line-range filter
3647 raise error.Abort(
3649 raise error.Abort(
3648 _('FILE arguments are not compatible with --line-range option')
3650 _('FILE arguments are not compatible with --line-range option')
3649 )
3651 )
3650
3652
3651 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3653 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3652 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3654 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3653 if linerange:
3655 if linerange:
3654 # TODO: should follow file history from logcmdutil._initialrevs(),
3656 # TODO: should follow file history from logcmdutil._initialrevs(),
3655 # then filter the result by logcmdutil._makerevset() and --limit
3657 # then filter the result by logcmdutil._makerevset() and --limit
3656 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3658 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3657
3659
3658 getrenamed = None
3660 getrenamed = None
3659 if opts.get('copies'):
3661 if opts.get('copies'):
3660 endrev = None
3662 endrev = None
3661 if revs:
3663 if revs:
3662 endrev = revs.max() + 1
3664 endrev = revs.max() + 1
3663 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3665 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3664
3666
3665 ui.pager('log')
3667 ui.pager('log')
3666 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3668 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3667 buffered=True)
3669 buffered=True)
3668 if opts.get('graph'):
3670 if opts.get('graph'):
3669 displayfn = logcmdutil.displaygraphrevs
3671 displayfn = logcmdutil.displaygraphrevs
3670 else:
3672 else:
3671 displayfn = logcmdutil.displayrevs
3673 displayfn = logcmdutil.displayrevs
3672 displayfn(ui, repo, revs, displayer, getrenamed)
3674 displayfn(ui, repo, revs, displayer, getrenamed)
3673
3675
3674 @command('manifest',
3676 @command('manifest',
3675 [('r', 'rev', '', _('revision to display'), _('REV')),
3677 [('r', 'rev', '', _('revision to display'), _('REV')),
3676 ('', 'all', False, _("list files from all revisions"))]
3678 ('', 'all', False, _("list files from all revisions"))]
3677 + formatteropts,
3679 + formatteropts,
3678 _('[-r REV]'),
3680 _('[-r REV]'),
3679 intents={INTENT_READONLY})
3681 intents={INTENT_READONLY})
3680 def manifest(ui, repo, node=None, rev=None, **opts):
3682 def manifest(ui, repo, node=None, rev=None, **opts):
3681 """output the current or given revision of the project manifest
3683 """output the current or given revision of the project manifest
3682
3684
3683 Print a list of version controlled files for the given revision.
3685 Print a list of version controlled files for the given revision.
3684 If no revision is given, the first parent of the working directory
3686 If no revision is given, the first parent of the working directory
3685 is used, or the null revision if no revision is checked out.
3687 is used, or the null revision if no revision is checked out.
3686
3688
3687 With -v, print file permissions, symlink and executable bits.
3689 With -v, print file permissions, symlink and executable bits.
3688 With --debug, print file revision hashes.
3690 With --debug, print file revision hashes.
3689
3691
3690 If option --all is specified, the list of all files from all revisions
3692 If option --all is specified, the list of all files from all revisions
3691 is printed. This includes deleted and renamed files.
3693 is printed. This includes deleted and renamed files.
3692
3694
3693 Returns 0 on success.
3695 Returns 0 on success.
3694 """
3696 """
3695 opts = pycompat.byteskwargs(opts)
3697 opts = pycompat.byteskwargs(opts)
3696 fm = ui.formatter('manifest', opts)
3698 fm = ui.formatter('manifest', opts)
3697
3699
3698 if opts.get('all'):
3700 if opts.get('all'):
3699 if rev or node:
3701 if rev or node:
3700 raise error.Abort(_("can't specify a revision with --all"))
3702 raise error.Abort(_("can't specify a revision with --all"))
3701
3703
3702 res = set()
3704 res = set()
3703 for rev in repo:
3705 for rev in repo:
3704 ctx = repo[rev]
3706 ctx = repo[rev]
3705 res |= set(ctx.files())
3707 res |= set(ctx.files())
3706
3708
3707 ui.pager('manifest')
3709 ui.pager('manifest')
3708 for f in sorted(res):
3710 for f in sorted(res):
3709 fm.startitem()
3711 fm.startitem()
3710 fm.write("path", '%s\n', f)
3712 fm.write("path", '%s\n', f)
3711 fm.end()
3713 fm.end()
3712 return
3714 return
3713
3715
3714 if rev and node:
3716 if rev and node:
3715 raise error.Abort(_("please specify just one revision"))
3717 raise error.Abort(_("please specify just one revision"))
3716
3718
3717 if not node:
3719 if not node:
3718 node = rev
3720 node = rev
3719
3721
3720 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3722 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3721 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3723 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3722 if node:
3724 if node:
3723 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3725 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3724 ctx = scmutil.revsingle(repo, node)
3726 ctx = scmutil.revsingle(repo, node)
3725 mf = ctx.manifest()
3727 mf = ctx.manifest()
3726 ui.pager('manifest')
3728 ui.pager('manifest')
3727 for f in ctx:
3729 for f in ctx:
3728 fm.startitem()
3730 fm.startitem()
3729 fm.context(ctx=ctx)
3731 fm.context(ctx=ctx)
3730 fl = ctx[f].flags()
3732 fl = ctx[f].flags()
3731 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3733 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3732 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3734 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3733 fm.write('path', '%s\n', f)
3735 fm.write('path', '%s\n', f)
3734 fm.end()
3736 fm.end()
3735
3737
3736 @command('^merge',
3738 @command('^merge',
3737 [('f', 'force', None,
3739 [('f', 'force', None,
3738 _('force a merge including outstanding changes (DEPRECATED)')),
3740 _('force a merge including outstanding changes (DEPRECATED)')),
3739 ('r', 'rev', '', _('revision to merge'), _('REV')),
3741 ('r', 'rev', '', _('revision to merge'), _('REV')),
3740 ('P', 'preview', None,
3742 ('P', 'preview', None,
3741 _('review revisions to merge (no merge is performed)')),
3743 _('review revisions to merge (no merge is performed)')),
3742 ('', 'abort', None, _('abort the ongoing merge')),
3744 ('', 'abort', None, _('abort the ongoing merge')),
3743 ] + mergetoolopts,
3745 ] + mergetoolopts,
3744 _('[-P] [[-r] REV]'))
3746 _('[-P] [[-r] REV]'))
3745 def merge(ui, repo, node=None, **opts):
3747 def merge(ui, repo, node=None, **opts):
3746 """merge another revision into working directory
3748 """merge another revision into working directory
3747
3749
3748 The current working directory is updated with all changes made in
3750 The current working directory is updated with all changes made in
3749 the requested revision since the last common predecessor revision.
3751 the requested revision since the last common predecessor revision.
3750
3752
3751 Files that changed between either parent are marked as changed for
3753 Files that changed between either parent are marked as changed for
3752 the next commit and a commit must be performed before any further
3754 the next commit and a commit must be performed before any further
3753 updates to the repository are allowed. The next commit will have
3755 updates to the repository are allowed. The next commit will have
3754 two parents.
3756 two parents.
3755
3757
3756 ``--tool`` can be used to specify the merge tool used for file
3758 ``--tool`` can be used to specify the merge tool used for file
3757 merges. It overrides the HGMERGE environment variable and your
3759 merges. It overrides the HGMERGE environment variable and your
3758 configuration files. See :hg:`help merge-tools` for options.
3760 configuration files. See :hg:`help merge-tools` for options.
3759
3761
3760 If no revision is specified, the working directory's parent is a
3762 If no revision is specified, the working directory's parent is a
3761 head revision, and the current branch contains exactly one other
3763 head revision, and the current branch contains exactly one other
3762 head, the other head is merged with by default. Otherwise, an
3764 head, the other head is merged with by default. Otherwise, an
3763 explicit revision with which to merge with must be provided.
3765 explicit revision with which to merge with must be provided.
3764
3766
3765 See :hg:`help resolve` for information on handling file conflicts.
3767 See :hg:`help resolve` for information on handling file conflicts.
3766
3768
3767 To undo an uncommitted merge, use :hg:`merge --abort` which
3769 To undo an uncommitted merge, use :hg:`merge --abort` which
3768 will check out a clean copy of the original merge parent, losing
3770 will check out a clean copy of the original merge parent, losing
3769 all changes.
3771 all changes.
3770
3772
3771 Returns 0 on success, 1 if there are unresolved files.
3773 Returns 0 on success, 1 if there are unresolved files.
3772 """
3774 """
3773
3775
3774 opts = pycompat.byteskwargs(opts)
3776 opts = pycompat.byteskwargs(opts)
3775 abort = opts.get('abort')
3777 abort = opts.get('abort')
3776 if abort and repo.dirstate.p2() == nullid:
3778 if abort and repo.dirstate.p2() == nullid:
3777 cmdutil.wrongtooltocontinue(repo, _('merge'))
3779 cmdutil.wrongtooltocontinue(repo, _('merge'))
3778 if abort:
3780 if abort:
3779 if node:
3781 if node:
3780 raise error.Abort(_("cannot specify a node with --abort"))
3782 raise error.Abort(_("cannot specify a node with --abort"))
3781 if opts.get('rev'):
3783 if opts.get('rev'):
3782 raise error.Abort(_("cannot specify both --rev and --abort"))
3784 raise error.Abort(_("cannot specify both --rev and --abort"))
3783 if opts.get('preview'):
3785 if opts.get('preview'):
3784 raise error.Abort(_("cannot specify --preview with --abort"))
3786 raise error.Abort(_("cannot specify --preview with --abort"))
3785 if opts.get('rev') and node:
3787 if opts.get('rev') and node:
3786 raise error.Abort(_("please specify just one revision"))
3788 raise error.Abort(_("please specify just one revision"))
3787 if not node:
3789 if not node:
3788 node = opts.get('rev')
3790 node = opts.get('rev')
3789
3791
3790 if node:
3792 if node:
3791 node = scmutil.revsingle(repo, node).node()
3793 node = scmutil.revsingle(repo, node).node()
3792
3794
3793 if not node and not abort:
3795 if not node and not abort:
3794 node = repo[destutil.destmerge(repo)].node()
3796 node = repo[destutil.destmerge(repo)].node()
3795
3797
3796 if opts.get('preview'):
3798 if opts.get('preview'):
3797 # find nodes that are ancestors of p2 but not of p1
3799 # find nodes that are ancestors of p2 but not of p1
3798 p1 = repo.lookup('.')
3800 p1 = repo.lookup('.')
3799 p2 = node
3801 p2 = node
3800 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3802 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3801
3803
3802 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3804 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3803 for node in nodes:
3805 for node in nodes:
3804 displayer.show(repo[node])
3806 displayer.show(repo[node])
3805 displayer.close()
3807 displayer.close()
3806 return 0
3808 return 0
3807
3809
3808 # ui.forcemerge is an internal variable, do not document
3810 # ui.forcemerge is an internal variable, do not document
3809 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3811 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3810 with ui.configoverride(overrides, 'merge'):
3812 with ui.configoverride(overrides, 'merge'):
3811 force = opts.get('force')
3813 force = opts.get('force')
3812 labels = ['working copy', 'merge rev']
3814 labels = ['working copy', 'merge rev']
3813 return hg.merge(repo, node, force=force, mergeforce=force,
3815 return hg.merge(repo, node, force=force, mergeforce=force,
3814 labels=labels, abort=abort)
3816 labels=labels, abort=abort)
3815
3817
3816 @command('outgoing|out',
3818 @command('outgoing|out',
3817 [('f', 'force', None, _('run even when the destination is unrelated')),
3819 [('f', 'force', None, _('run even when the destination is unrelated')),
3818 ('r', 'rev', [],
3820 ('r', 'rev', [],
3819 _('a changeset intended to be included in the destination'), _('REV')),
3821 _('a changeset intended to be included in the destination'), _('REV')),
3820 ('n', 'newest-first', None, _('show newest record first')),
3822 ('n', 'newest-first', None, _('show newest record first')),
3821 ('B', 'bookmarks', False, _('compare bookmarks')),
3823 ('B', 'bookmarks', False, _('compare bookmarks')),
3822 ('b', 'branch', [], _('a specific branch you would like to push'),
3824 ('b', 'branch', [], _('a specific branch you would like to push'),
3823 _('BRANCH')),
3825 _('BRANCH')),
3824 ] + logopts + remoteopts + subrepoopts,
3826 ] + logopts + remoteopts + subrepoopts,
3825 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3827 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3826 def outgoing(ui, repo, dest=None, **opts):
3828 def outgoing(ui, repo, dest=None, **opts):
3827 """show changesets not found in the destination
3829 """show changesets not found in the destination
3828
3830
3829 Show changesets not found in the specified destination repository
3831 Show changesets not found in the specified destination repository
3830 or the default push location. These are the changesets that would
3832 or the default push location. These are the changesets that would
3831 be pushed if a push was requested.
3833 be pushed if a push was requested.
3832
3834
3833 See pull for details of valid destination formats.
3835 See pull for details of valid destination formats.
3834
3836
3835 .. container:: verbose
3837 .. container:: verbose
3836
3838
3837 With -B/--bookmarks, the result of bookmark comparison between
3839 With -B/--bookmarks, the result of bookmark comparison between
3838 local and remote repositories is displayed. With -v/--verbose,
3840 local and remote repositories is displayed. With -v/--verbose,
3839 status is also displayed for each bookmark like below::
3841 status is also displayed for each bookmark like below::
3840
3842
3841 BM1 01234567890a added
3843 BM1 01234567890a added
3842 BM2 deleted
3844 BM2 deleted
3843 BM3 234567890abc advanced
3845 BM3 234567890abc advanced
3844 BM4 34567890abcd diverged
3846 BM4 34567890abcd diverged
3845 BM5 4567890abcde changed
3847 BM5 4567890abcde changed
3846
3848
3847 The action taken when pushing depends on the
3849 The action taken when pushing depends on the
3848 status of each bookmark:
3850 status of each bookmark:
3849
3851
3850 :``added``: push with ``-B`` will create it
3852 :``added``: push with ``-B`` will create it
3851 :``deleted``: push with ``-B`` will delete it
3853 :``deleted``: push with ``-B`` will delete it
3852 :``advanced``: push will update it
3854 :``advanced``: push will update it
3853 :``diverged``: push with ``-B`` will update it
3855 :``diverged``: push with ``-B`` will update it
3854 :``changed``: push with ``-B`` will update it
3856 :``changed``: push with ``-B`` will update it
3855
3857
3856 From the point of view of pushing behavior, bookmarks
3858 From the point of view of pushing behavior, bookmarks
3857 existing only in the remote repository are treated as
3859 existing only in the remote repository are treated as
3858 ``deleted``, even if it is in fact added remotely.
3860 ``deleted``, even if it is in fact added remotely.
3859
3861
3860 Returns 0 if there are outgoing changes, 1 otherwise.
3862 Returns 0 if there are outgoing changes, 1 otherwise.
3861 """
3863 """
3862 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3864 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3863 # style URLs, so don't overwrite dest.
3865 # style URLs, so don't overwrite dest.
3864 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3866 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3865 if not path:
3867 if not path:
3866 raise error.Abort(_('default repository not configured!'),
3868 raise error.Abort(_('default repository not configured!'),
3867 hint=_("see 'hg help config.paths'"))
3869 hint=_("see 'hg help config.paths'"))
3868
3870
3869 opts = pycompat.byteskwargs(opts)
3871 opts = pycompat.byteskwargs(opts)
3870 if opts.get('graph'):
3872 if opts.get('graph'):
3871 logcmdutil.checkunsupportedgraphflags([], opts)
3873 logcmdutil.checkunsupportedgraphflags([], opts)
3872 o, other = hg._outgoing(ui, repo, dest, opts)
3874 o, other = hg._outgoing(ui, repo, dest, opts)
3873 if not o:
3875 if not o:
3874 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3876 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3875 return
3877 return
3876
3878
3877 revdag = logcmdutil.graphrevs(repo, o, opts)
3879 revdag = logcmdutil.graphrevs(repo, o, opts)
3878 ui.pager('outgoing')
3880 ui.pager('outgoing')
3879 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3881 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3880 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3882 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3881 graphmod.asciiedges)
3883 graphmod.asciiedges)
3882 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3884 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3883 return 0
3885 return 0
3884
3886
3885 if opts.get('bookmarks'):
3887 if opts.get('bookmarks'):
3886 dest = path.pushloc or path.loc
3888 dest = path.pushloc or path.loc
3887 other = hg.peer(repo, opts, dest)
3889 other = hg.peer(repo, opts, dest)
3888 if 'bookmarks' not in other.listkeys('namespaces'):
3890 if 'bookmarks' not in other.listkeys('namespaces'):
3889 ui.warn(_("remote doesn't support bookmarks\n"))
3891 ui.warn(_("remote doesn't support bookmarks\n"))
3890 return 0
3892 return 0
3891 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3893 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3892 ui.pager('outgoing')
3894 ui.pager('outgoing')
3893 return bookmarks.outgoing(ui, repo, other)
3895 return bookmarks.outgoing(ui, repo, other)
3894
3896
3895 repo._subtoppath = path.pushloc or path.loc
3897 repo._subtoppath = path.pushloc or path.loc
3896 try:
3898 try:
3897 return hg.outgoing(ui, repo, dest, opts)
3899 return hg.outgoing(ui, repo, dest, opts)
3898 finally:
3900 finally:
3899 del repo._subtoppath
3901 del repo._subtoppath
3900
3902
3901 @command('parents',
3903 @command('parents',
3902 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3904 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3903 ] + templateopts,
3905 ] + templateopts,
3904 _('[-r REV] [FILE]'),
3906 _('[-r REV] [FILE]'),
3905 inferrepo=True)
3907 inferrepo=True)
3906 def parents(ui, repo, file_=None, **opts):
3908 def parents(ui, repo, file_=None, **opts):
3907 """show the parents of the working directory or revision (DEPRECATED)
3909 """show the parents of the working directory or revision (DEPRECATED)
3908
3910
3909 Print the working directory's parent revisions. If a revision is
3911 Print the working directory's parent revisions. If a revision is
3910 given via -r/--rev, the parent of that revision will be printed.
3912 given via -r/--rev, the parent of that revision will be printed.
3911 If a file argument is given, the revision in which the file was
3913 If a file argument is given, the revision in which the file was
3912 last changed (before the working directory revision or the
3914 last changed (before the working directory revision or the
3913 argument to --rev if given) is printed.
3915 argument to --rev if given) is printed.
3914
3916
3915 This command is equivalent to::
3917 This command is equivalent to::
3916
3918
3917 hg log -r "p1()+p2()" or
3919 hg log -r "p1()+p2()" or
3918 hg log -r "p1(REV)+p2(REV)" or
3920 hg log -r "p1(REV)+p2(REV)" or
3919 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3921 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3920 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3922 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3921
3923
3922 See :hg:`summary` and :hg:`help revsets` for related information.
3924 See :hg:`summary` and :hg:`help revsets` for related information.
3923
3925
3924 Returns 0 on success.
3926 Returns 0 on success.
3925 """
3927 """
3926
3928
3927 opts = pycompat.byteskwargs(opts)
3929 opts = pycompat.byteskwargs(opts)
3928 rev = opts.get('rev')
3930 rev = opts.get('rev')
3929 if rev:
3931 if rev:
3930 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3931 ctx = scmutil.revsingle(repo, rev, None)
3933 ctx = scmutil.revsingle(repo, rev, None)
3932
3934
3933 if file_:
3935 if file_:
3934 m = scmutil.match(ctx, (file_,), opts)
3936 m = scmutil.match(ctx, (file_,), opts)
3935 if m.anypats() or len(m.files()) != 1:
3937 if m.anypats() or len(m.files()) != 1:
3936 raise error.Abort(_('can only specify an explicit filename'))
3938 raise error.Abort(_('can only specify an explicit filename'))
3937 file_ = m.files()[0]
3939 file_ = m.files()[0]
3938 filenodes = []
3940 filenodes = []
3939 for cp in ctx.parents():
3941 for cp in ctx.parents():
3940 if not cp:
3942 if not cp:
3941 continue
3943 continue
3942 try:
3944 try:
3943 filenodes.append(cp.filenode(file_))
3945 filenodes.append(cp.filenode(file_))
3944 except error.LookupError:
3946 except error.LookupError:
3945 pass
3947 pass
3946 if not filenodes:
3948 if not filenodes:
3947 raise error.Abort(_("'%s' not found in manifest!") % file_)
3949 raise error.Abort(_("'%s' not found in manifest!") % file_)
3948 p = []
3950 p = []
3949 for fn in filenodes:
3951 for fn in filenodes:
3950 fctx = repo.filectx(file_, fileid=fn)
3952 fctx = repo.filectx(file_, fileid=fn)
3951 p.append(fctx.node())
3953 p.append(fctx.node())
3952 else:
3954 else:
3953 p = [cp.node() for cp in ctx.parents()]
3955 p = [cp.node() for cp in ctx.parents()]
3954
3956
3955 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3957 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3956 for n in p:
3958 for n in p:
3957 if n != nullid:
3959 if n != nullid:
3958 displayer.show(repo[n])
3960 displayer.show(repo[n])
3959 displayer.close()
3961 displayer.close()
3960
3962
3961 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3963 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3962 intents={INTENT_READONLY})
3964 intents={INTENT_READONLY})
3963 def paths(ui, repo, search=None, **opts):
3965 def paths(ui, repo, search=None, **opts):
3964 """show aliases for remote repositories
3966 """show aliases for remote repositories
3965
3967
3966 Show definition of symbolic path name NAME. If no name is given,
3968 Show definition of symbolic path name NAME. If no name is given,
3967 show definition of all available names.
3969 show definition of all available names.
3968
3970
3969 Option -q/--quiet suppresses all output when searching for NAME
3971 Option -q/--quiet suppresses all output when searching for NAME
3970 and shows only the path names when listing all definitions.
3972 and shows only the path names when listing all definitions.
3971
3973
3972 Path names are defined in the [paths] section of your
3974 Path names are defined in the [paths] section of your
3973 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3975 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3974 repository, ``.hg/hgrc`` is used, too.
3976 repository, ``.hg/hgrc`` is used, too.
3975
3977
3976 The path names ``default`` and ``default-push`` have a special
3978 The path names ``default`` and ``default-push`` have a special
3977 meaning. When performing a push or pull operation, they are used
3979 meaning. When performing a push or pull operation, they are used
3978 as fallbacks if no location is specified on the command-line.
3980 as fallbacks if no location is specified on the command-line.
3979 When ``default-push`` is set, it will be used for push and
3981 When ``default-push`` is set, it will be used for push and
3980 ``default`` will be used for pull; otherwise ``default`` is used
3982 ``default`` will be used for pull; otherwise ``default`` is used
3981 as the fallback for both. When cloning a repository, the clone
3983 as the fallback for both. When cloning a repository, the clone
3982 source is written as ``default`` in ``.hg/hgrc``.
3984 source is written as ``default`` in ``.hg/hgrc``.
3983
3985
3984 .. note::
3986 .. note::
3985
3987
3986 ``default`` and ``default-push`` apply to all inbound (e.g.
3988 ``default`` and ``default-push`` apply to all inbound (e.g.
3987 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3989 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3988 and :hg:`bundle`) operations.
3990 and :hg:`bundle`) operations.
3989
3991
3990 See :hg:`help urls` for more information.
3992 See :hg:`help urls` for more information.
3991
3993
3992 Returns 0 on success.
3994 Returns 0 on success.
3993 """
3995 """
3994
3996
3995 opts = pycompat.byteskwargs(opts)
3997 opts = pycompat.byteskwargs(opts)
3996 ui.pager('paths')
3998 ui.pager('paths')
3997 if search:
3999 if search:
3998 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4000 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3999 if name == search]
4001 if name == search]
4000 else:
4002 else:
4001 pathitems = sorted(ui.paths.iteritems())
4003 pathitems = sorted(ui.paths.iteritems())
4002
4004
4003 fm = ui.formatter('paths', opts)
4005 fm = ui.formatter('paths', opts)
4004 if fm.isplain():
4006 if fm.isplain():
4005 hidepassword = util.hidepassword
4007 hidepassword = util.hidepassword
4006 else:
4008 else:
4007 hidepassword = bytes
4009 hidepassword = bytes
4008 if ui.quiet:
4010 if ui.quiet:
4009 namefmt = '%s\n'
4011 namefmt = '%s\n'
4010 else:
4012 else:
4011 namefmt = '%s = '
4013 namefmt = '%s = '
4012 showsubopts = not search and not ui.quiet
4014 showsubopts = not search and not ui.quiet
4013
4015
4014 for name, path in pathitems:
4016 for name, path in pathitems:
4015 fm.startitem()
4017 fm.startitem()
4016 fm.condwrite(not search, 'name', namefmt, name)
4018 fm.condwrite(not search, 'name', namefmt, name)
4017 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4019 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4018 for subopt, value in sorted(path.suboptions.items()):
4020 for subopt, value in sorted(path.suboptions.items()):
4019 assert subopt not in ('name', 'url')
4021 assert subopt not in ('name', 'url')
4020 if showsubopts:
4022 if showsubopts:
4021 fm.plain('%s:%s = ' % (name, subopt))
4023 fm.plain('%s:%s = ' % (name, subopt))
4022 fm.condwrite(showsubopts, subopt, '%s\n', value)
4024 fm.condwrite(showsubopts, subopt, '%s\n', value)
4023
4025
4024 fm.end()
4026 fm.end()
4025
4027
4026 if search and not pathitems:
4028 if search and not pathitems:
4027 if not ui.quiet:
4029 if not ui.quiet:
4028 ui.warn(_("not found!\n"))
4030 ui.warn(_("not found!\n"))
4029 return 1
4031 return 1
4030 else:
4032 else:
4031 return 0
4033 return 0
4032
4034
4033 @command('phase',
4035 @command('phase',
4034 [('p', 'public', False, _('set changeset phase to public')),
4036 [('p', 'public', False, _('set changeset phase to public')),
4035 ('d', 'draft', False, _('set changeset phase to draft')),
4037 ('d', 'draft', False, _('set changeset phase to draft')),
4036 ('s', 'secret', False, _('set changeset phase to secret')),
4038 ('s', 'secret', False, _('set changeset phase to secret')),
4037 ('f', 'force', False, _('allow to move boundary backward')),
4039 ('f', 'force', False, _('allow to move boundary backward')),
4038 ('r', 'rev', [], _('target revision'), _('REV')),
4040 ('r', 'rev', [], _('target revision'), _('REV')),
4039 ],
4041 ],
4040 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4042 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4041 def phase(ui, repo, *revs, **opts):
4043 def phase(ui, repo, *revs, **opts):
4042 """set or show the current phase name
4044 """set or show the current phase name
4043
4045
4044 With no argument, show the phase name of the current revision(s).
4046 With no argument, show the phase name of the current revision(s).
4045
4047
4046 With one of -p/--public, -d/--draft or -s/--secret, change the
4048 With one of -p/--public, -d/--draft or -s/--secret, change the
4047 phase value of the specified revisions.
4049 phase value of the specified revisions.
4048
4050
4049 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4051 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4050 lower phase to a higher phase. Phases are ordered as follows::
4052 lower phase to a higher phase. Phases are ordered as follows::
4051
4053
4052 public < draft < secret
4054 public < draft < secret
4053
4055
4054 Returns 0 on success, 1 if some phases could not be changed.
4056 Returns 0 on success, 1 if some phases could not be changed.
4055
4057
4056 (For more information about the phases concept, see :hg:`help phases`.)
4058 (For more information about the phases concept, see :hg:`help phases`.)
4057 """
4059 """
4058 opts = pycompat.byteskwargs(opts)
4060 opts = pycompat.byteskwargs(opts)
4059 # search for a unique phase argument
4061 # search for a unique phase argument
4060 targetphase = None
4062 targetphase = None
4061 for idx, name in enumerate(phases.phasenames):
4063 for idx, name in enumerate(phases.phasenames):
4062 if opts.get(name, False):
4064 if opts.get(name, False):
4063 if targetphase is not None:
4065 if targetphase is not None:
4064 raise error.Abort(_('only one phase can be specified'))
4066 raise error.Abort(_('only one phase can be specified'))
4065 targetphase = idx
4067 targetphase = idx
4066
4068
4067 # look for specified revision
4069 # look for specified revision
4068 revs = list(revs)
4070 revs = list(revs)
4069 revs.extend(opts['rev'])
4071 revs.extend(opts['rev'])
4070 if not revs:
4072 if not revs:
4071 # display both parents as the second parent phase can influence
4073 # display both parents as the second parent phase can influence
4072 # the phase of a merge commit
4074 # the phase of a merge commit
4073 revs = [c.rev() for c in repo[None].parents()]
4075 revs = [c.rev() for c in repo[None].parents()]
4074
4076
4075 revs = scmutil.revrange(repo, revs)
4077 revs = scmutil.revrange(repo, revs)
4076
4078
4077 ret = 0
4079 ret = 0
4078 if targetphase is None:
4080 if targetphase is None:
4079 # display
4081 # display
4080 for r in revs:
4082 for r in revs:
4081 ctx = repo[r]
4083 ctx = repo[r]
4082 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4084 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4083 else:
4085 else:
4084 with repo.lock(), repo.transaction("phase") as tr:
4086 with repo.lock(), repo.transaction("phase") as tr:
4085 # set phase
4087 # set phase
4086 if not revs:
4088 if not revs:
4087 raise error.Abort(_('empty revision set'))
4089 raise error.Abort(_('empty revision set'))
4088 nodes = [repo[r].node() for r in revs]
4090 nodes = [repo[r].node() for r in revs]
4089 # moving revision from public to draft may hide them
4091 # moving revision from public to draft may hide them
4090 # We have to check result on an unfiltered repository
4092 # We have to check result on an unfiltered repository
4091 unfi = repo.unfiltered()
4093 unfi = repo.unfiltered()
4092 getphase = unfi._phasecache.phase
4094 getphase = unfi._phasecache.phase
4093 olddata = [getphase(unfi, r) for r in unfi]
4095 olddata = [getphase(unfi, r) for r in unfi]
4094 phases.advanceboundary(repo, tr, targetphase, nodes)
4096 phases.advanceboundary(repo, tr, targetphase, nodes)
4095 if opts['force']:
4097 if opts['force']:
4096 phases.retractboundary(repo, tr, targetphase, nodes)
4098 phases.retractboundary(repo, tr, targetphase, nodes)
4097 getphase = unfi._phasecache.phase
4099 getphase = unfi._phasecache.phase
4098 newdata = [getphase(unfi, r) for r in unfi]
4100 newdata = [getphase(unfi, r) for r in unfi]
4099 changes = sum(newdata[r] != olddata[r] for r in unfi)
4101 changes = sum(newdata[r] != olddata[r] for r in unfi)
4100 cl = unfi.changelog
4102 cl = unfi.changelog
4101 rejected = [n for n in nodes
4103 rejected = [n for n in nodes
4102 if newdata[cl.rev(n)] < targetphase]
4104 if newdata[cl.rev(n)] < targetphase]
4103 if rejected:
4105 if rejected:
4104 ui.warn(_('cannot move %i changesets to a higher '
4106 ui.warn(_('cannot move %i changesets to a higher '
4105 'phase, use --force\n') % len(rejected))
4107 'phase, use --force\n') % len(rejected))
4106 ret = 1
4108 ret = 1
4107 if changes:
4109 if changes:
4108 msg = _('phase changed for %i changesets\n') % changes
4110 msg = _('phase changed for %i changesets\n') % changes
4109 if ret:
4111 if ret:
4110 ui.status(msg)
4112 ui.status(msg)
4111 else:
4113 else:
4112 ui.note(msg)
4114 ui.note(msg)
4113 else:
4115 else:
4114 ui.warn(_('no phases changed\n'))
4116 ui.warn(_('no phases changed\n'))
4115 return ret
4117 return ret
4116
4118
4117 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4119 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4118 """Run after a changegroup has been added via pull/unbundle
4120 """Run after a changegroup has been added via pull/unbundle
4119
4121
4120 This takes arguments below:
4122 This takes arguments below:
4121
4123
4122 :modheads: change of heads by pull/unbundle
4124 :modheads: change of heads by pull/unbundle
4123 :optupdate: updating working directory is needed or not
4125 :optupdate: updating working directory is needed or not
4124 :checkout: update destination revision (or None to default destination)
4126 :checkout: update destination revision (or None to default destination)
4125 :brev: a name, which might be a bookmark to be activated after updating
4127 :brev: a name, which might be a bookmark to be activated after updating
4126 """
4128 """
4127 if modheads == 0:
4129 if modheads == 0:
4128 return
4130 return
4129 if optupdate:
4131 if optupdate:
4130 try:
4132 try:
4131 return hg.updatetotally(ui, repo, checkout, brev)
4133 return hg.updatetotally(ui, repo, checkout, brev)
4132 except error.UpdateAbort as inst:
4134 except error.UpdateAbort as inst:
4133 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4135 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4134 hint = inst.hint
4136 hint = inst.hint
4135 raise error.UpdateAbort(msg, hint=hint)
4137 raise error.UpdateAbort(msg, hint=hint)
4136 if modheads > 1:
4138 if modheads > 1:
4137 currentbranchheads = len(repo.branchheads())
4139 currentbranchheads = len(repo.branchheads())
4138 if currentbranchheads == modheads:
4140 if currentbranchheads == modheads:
4139 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4141 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4140 elif currentbranchheads > 1:
4142 elif currentbranchheads > 1:
4141 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4143 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4142 "merge)\n"))
4144 "merge)\n"))
4143 else:
4145 else:
4144 ui.status(_("(run 'hg heads' to see heads)\n"))
4146 ui.status(_("(run 'hg heads' to see heads)\n"))
4145 elif not ui.configbool('commands', 'update.requiredest'):
4147 elif not ui.configbool('commands', 'update.requiredest'):
4146 ui.status(_("(run 'hg update' to get a working copy)\n"))
4148 ui.status(_("(run 'hg update' to get a working copy)\n"))
4147
4149
4148 @command('^pull',
4150 @command('^pull',
4149 [('u', 'update', None,
4151 [('u', 'update', None,
4150 _('update to new branch head if new descendants were pulled')),
4152 _('update to new branch head if new descendants were pulled')),
4151 ('f', 'force', None, _('run even when remote repository is unrelated')),
4153 ('f', 'force', None, _('run even when remote repository is unrelated')),
4152 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4154 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4153 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4155 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4154 ('b', 'branch', [], _('a specific branch you would like to pull'),
4156 ('b', 'branch', [], _('a specific branch you would like to pull'),
4155 _('BRANCH')),
4157 _('BRANCH')),
4156 ] + remoteopts,
4158 ] + remoteopts,
4157 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4159 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4158 def pull(ui, repo, source="default", **opts):
4160 def pull(ui, repo, source="default", **opts):
4159 """pull changes from the specified source
4161 """pull changes from the specified source
4160
4162
4161 Pull changes from a remote repository to a local one.
4163 Pull changes from a remote repository to a local one.
4162
4164
4163 This finds all changes from the repository at the specified path
4165 This finds all changes from the repository at the specified path
4164 or URL and adds them to a local repository (the current one unless
4166 or URL and adds them to a local repository (the current one unless
4165 -R is specified). By default, this does not update the copy of the
4167 -R is specified). By default, this does not update the copy of the
4166 project in the working directory.
4168 project in the working directory.
4167
4169
4168 When cloning from servers that support it, Mercurial may fetch
4170 When cloning from servers that support it, Mercurial may fetch
4169 pre-generated data. When this is done, hooks operating on incoming
4171 pre-generated data. When this is done, hooks operating on incoming
4170 changesets and changegroups may fire more than once, once for each
4172 changesets and changegroups may fire more than once, once for each
4171 pre-generated bundle and as well as for any additional remaining
4173 pre-generated bundle and as well as for any additional remaining
4172 data. See :hg:`help -e clonebundles` for more.
4174 data. See :hg:`help -e clonebundles` for more.
4173
4175
4174 Use :hg:`incoming` if you want to see what would have been added
4176 Use :hg:`incoming` if you want to see what would have been added
4175 by a pull at the time you issued this command. If you then decide
4177 by a pull at the time you issued this command. If you then decide
4176 to add those changes to the repository, you should use :hg:`pull
4178 to add those changes to the repository, you should use :hg:`pull
4177 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4179 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4178
4180
4179 If SOURCE is omitted, the 'default' path will be used.
4181 If SOURCE is omitted, the 'default' path will be used.
4180 See :hg:`help urls` for more information.
4182 See :hg:`help urls` for more information.
4181
4183
4182 Specifying bookmark as ``.`` is equivalent to specifying the active
4184 Specifying bookmark as ``.`` is equivalent to specifying the active
4183 bookmark's name.
4185 bookmark's name.
4184
4186
4185 Returns 0 on success, 1 if an update had unresolved files.
4187 Returns 0 on success, 1 if an update had unresolved files.
4186 """
4188 """
4187
4189
4188 opts = pycompat.byteskwargs(opts)
4190 opts = pycompat.byteskwargs(opts)
4189 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4191 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4190 msg = _('update destination required by configuration')
4192 msg = _('update destination required by configuration')
4191 hint = _('use hg pull followed by hg update DEST')
4193 hint = _('use hg pull followed by hg update DEST')
4192 raise error.Abort(msg, hint=hint)
4194 raise error.Abort(msg, hint=hint)
4193
4195
4194 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4196 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4195 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4197 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4196 other = hg.peer(repo, opts, source)
4198 other = hg.peer(repo, opts, source)
4197 try:
4199 try:
4198 revs, checkout = hg.addbranchrevs(repo, other, branches,
4200 revs, checkout = hg.addbranchrevs(repo, other, branches,
4199 opts.get('rev'))
4201 opts.get('rev'))
4200
4202
4201
4203
4202 pullopargs = {}
4204 pullopargs = {}
4203 if opts.get('bookmark'):
4205 if opts.get('bookmark'):
4204 if not revs:
4206 if not revs:
4205 revs = []
4207 revs = []
4206 # The list of bookmark used here is not the one used to actually
4208 # The list of bookmark used here is not the one used to actually
4207 # update the bookmark name. This can result in the revision pulled
4209 # update the bookmark name. This can result in the revision pulled
4208 # not ending up with the name of the bookmark because of a race
4210 # not ending up with the name of the bookmark because of a race
4209 # condition on the server. (See issue 4689 for details)
4211 # condition on the server. (See issue 4689 for details)
4210 remotebookmarks = other.listkeys('bookmarks')
4212 remotebookmarks = other.listkeys('bookmarks')
4211 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4213 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4212 pullopargs['remotebookmarks'] = remotebookmarks
4214 pullopargs['remotebookmarks'] = remotebookmarks
4213 for b in opts['bookmark']:
4215 for b in opts['bookmark']:
4214 b = repo._bookmarks.expandname(b)
4216 b = repo._bookmarks.expandname(b)
4215 if b not in remotebookmarks:
4217 if b not in remotebookmarks:
4216 raise error.Abort(_('remote bookmark %s not found!') % b)
4218 raise error.Abort(_('remote bookmark %s not found!') % b)
4217 revs.append(hex(remotebookmarks[b]))
4219 revs.append(hex(remotebookmarks[b]))
4218
4220
4219 if revs:
4221 if revs:
4220 try:
4222 try:
4221 # When 'rev' is a bookmark name, we cannot guarantee that it
4223 # When 'rev' is a bookmark name, we cannot guarantee that it
4222 # will be updated with that name because of a race condition
4224 # will be updated with that name because of a race condition
4223 # server side. (See issue 4689 for details)
4225 # server side. (See issue 4689 for details)
4224 oldrevs = revs
4226 oldrevs = revs
4225 revs = [] # actually, nodes
4227 revs = [] # actually, nodes
4226 for r in oldrevs:
4228 for r in oldrevs:
4227 with other.commandexecutor() as e:
4229 with other.commandexecutor() as e:
4228 node = e.callcommand('lookup', {'key': r}).result()
4230 node = e.callcommand('lookup', {'key': r}).result()
4229
4231
4230 revs.append(node)
4232 revs.append(node)
4231 if r == checkout:
4233 if r == checkout:
4232 checkout = node
4234 checkout = node
4233 except error.CapabilityError:
4235 except error.CapabilityError:
4234 err = _("other repository doesn't support revision lookup, "
4236 err = _("other repository doesn't support revision lookup, "
4235 "so a rev cannot be specified.")
4237 "so a rev cannot be specified.")
4236 raise error.Abort(err)
4238 raise error.Abort(err)
4237
4239
4238 wlock = util.nullcontextmanager()
4240 wlock = util.nullcontextmanager()
4239 if opts.get('update'):
4241 if opts.get('update'):
4240 wlock = repo.wlock()
4242 wlock = repo.wlock()
4241 with wlock:
4243 with wlock:
4242 pullopargs.update(opts.get('opargs', {}))
4244 pullopargs.update(opts.get('opargs', {}))
4243 modheads = exchange.pull(repo, other, heads=revs,
4245 modheads = exchange.pull(repo, other, heads=revs,
4244 force=opts.get('force'),
4246 force=opts.get('force'),
4245 bookmarks=opts.get('bookmark', ()),
4247 bookmarks=opts.get('bookmark', ()),
4246 opargs=pullopargs).cgresult
4248 opargs=pullopargs).cgresult
4247
4249
4248 # brev is a name, which might be a bookmark to be activated at
4250 # brev is a name, which might be a bookmark to be activated at
4249 # the end of the update. In other words, it is an explicit
4251 # the end of the update. In other words, it is an explicit
4250 # destination of the update
4252 # destination of the update
4251 brev = None
4253 brev = None
4252
4254
4253 if checkout:
4255 if checkout:
4254 checkout = repo.changelog.rev(checkout)
4256 checkout = repo.changelog.rev(checkout)
4255
4257
4256 # order below depends on implementation of
4258 # order below depends on implementation of
4257 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4259 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4258 # because 'checkout' is determined without it.
4260 # because 'checkout' is determined without it.
4259 if opts.get('rev'):
4261 if opts.get('rev'):
4260 brev = opts['rev'][0]
4262 brev = opts['rev'][0]
4261 elif opts.get('branch'):
4263 elif opts.get('branch'):
4262 brev = opts['branch'][0]
4264 brev = opts['branch'][0]
4263 else:
4265 else:
4264 brev = branches[0]
4266 brev = branches[0]
4265 repo._subtoppath = source
4267 repo._subtoppath = source
4266 try:
4268 try:
4267 ret = postincoming(ui, repo, modheads, opts.get('update'),
4269 ret = postincoming(ui, repo, modheads, opts.get('update'),
4268 checkout, brev)
4270 checkout, brev)
4269
4271
4270 finally:
4272 finally:
4271 del repo._subtoppath
4273 del repo._subtoppath
4272
4274
4273 finally:
4275 finally:
4274 other.close()
4276 other.close()
4275 return ret
4277 return ret
4276
4278
4277 @command('^push',
4279 @command('^push',
4278 [('f', 'force', None, _('force push')),
4280 [('f', 'force', None, _('force push')),
4279 ('r', 'rev', [],
4281 ('r', 'rev', [],
4280 _('a changeset intended to be included in the destination'),
4282 _('a changeset intended to be included in the destination'),
4281 _('REV')),
4283 _('REV')),
4282 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4284 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4283 ('b', 'branch', [],
4285 ('b', 'branch', [],
4284 _('a specific branch you would like to push'), _('BRANCH')),
4286 _('a specific branch you would like to push'), _('BRANCH')),
4285 ('', 'new-branch', False, _('allow pushing a new branch')),
4287 ('', 'new-branch', False, _('allow pushing a new branch')),
4286 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4288 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4287 ] + remoteopts,
4289 ] + remoteopts,
4288 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4290 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4289 def push(ui, repo, dest=None, **opts):
4291 def push(ui, repo, dest=None, **opts):
4290 """push changes to the specified destination
4292 """push changes to the specified destination
4291
4293
4292 Push changesets from the local repository to the specified
4294 Push changesets from the local repository to the specified
4293 destination.
4295 destination.
4294
4296
4295 This operation is symmetrical to pull: it is identical to a pull
4297 This operation is symmetrical to pull: it is identical to a pull
4296 in the destination repository from the current one.
4298 in the destination repository from the current one.
4297
4299
4298 By default, push will not allow creation of new heads at the
4300 By default, push will not allow creation of new heads at the
4299 destination, since multiple heads would make it unclear which head
4301 destination, since multiple heads would make it unclear which head
4300 to use. In this situation, it is recommended to pull and merge
4302 to use. In this situation, it is recommended to pull and merge
4301 before pushing.
4303 before pushing.
4302
4304
4303 Use --new-branch if you want to allow push to create a new named
4305 Use --new-branch if you want to allow push to create a new named
4304 branch that is not present at the destination. This allows you to
4306 branch that is not present at the destination. This allows you to
4305 only create a new branch without forcing other changes.
4307 only create a new branch without forcing other changes.
4306
4308
4307 .. note::
4309 .. note::
4308
4310
4309 Extra care should be taken with the -f/--force option,
4311 Extra care should be taken with the -f/--force option,
4310 which will push all new heads on all branches, an action which will
4312 which will push all new heads on all branches, an action which will
4311 almost always cause confusion for collaborators.
4313 almost always cause confusion for collaborators.
4312
4314
4313 If -r/--rev is used, the specified revision and all its ancestors
4315 If -r/--rev is used, the specified revision and all its ancestors
4314 will be pushed to the remote repository.
4316 will be pushed to the remote repository.
4315
4317
4316 If -B/--bookmark is used, the specified bookmarked revision, its
4318 If -B/--bookmark is used, the specified bookmarked revision, its
4317 ancestors, and the bookmark will be pushed to the remote
4319 ancestors, and the bookmark will be pushed to the remote
4318 repository. Specifying ``.`` is equivalent to specifying the active
4320 repository. Specifying ``.`` is equivalent to specifying the active
4319 bookmark's name.
4321 bookmark's name.
4320
4322
4321 Please see :hg:`help urls` for important details about ``ssh://``
4323 Please see :hg:`help urls` for important details about ``ssh://``
4322 URLs. If DESTINATION is omitted, a default path will be used.
4324 URLs. If DESTINATION is omitted, a default path will be used.
4323
4325
4324 .. container:: verbose
4326 .. container:: verbose
4325
4327
4326 The --pushvars option sends strings to the server that become
4328 The --pushvars option sends strings to the server that become
4327 environment variables prepended with ``HG_USERVAR_``. For example,
4329 environment variables prepended with ``HG_USERVAR_``. For example,
4328 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4330 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4329 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4331 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4330
4332
4331 pushvars can provide for user-overridable hooks as well as set debug
4333 pushvars can provide for user-overridable hooks as well as set debug
4332 levels. One example is having a hook that blocks commits containing
4334 levels. One example is having a hook that blocks commits containing
4333 conflict markers, but enables the user to override the hook if the file
4335 conflict markers, but enables the user to override the hook if the file
4334 is using conflict markers for testing purposes or the file format has
4336 is using conflict markers for testing purposes or the file format has
4335 strings that look like conflict markers.
4337 strings that look like conflict markers.
4336
4338
4337 By default, servers will ignore `--pushvars`. To enable it add the
4339 By default, servers will ignore `--pushvars`. To enable it add the
4338 following to your configuration file::
4340 following to your configuration file::
4339
4341
4340 [push]
4342 [push]
4341 pushvars.server = true
4343 pushvars.server = true
4342
4344
4343 Returns 0 if push was successful, 1 if nothing to push.
4345 Returns 0 if push was successful, 1 if nothing to push.
4344 """
4346 """
4345
4347
4346 opts = pycompat.byteskwargs(opts)
4348 opts = pycompat.byteskwargs(opts)
4347 if opts.get('bookmark'):
4349 if opts.get('bookmark'):
4348 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4350 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4349 for b in opts['bookmark']:
4351 for b in opts['bookmark']:
4350 # translate -B options to -r so changesets get pushed
4352 # translate -B options to -r so changesets get pushed
4351 b = repo._bookmarks.expandname(b)
4353 b = repo._bookmarks.expandname(b)
4352 if b in repo._bookmarks:
4354 if b in repo._bookmarks:
4353 opts.setdefault('rev', []).append(b)
4355 opts.setdefault('rev', []).append(b)
4354 else:
4356 else:
4355 # if we try to push a deleted bookmark, translate it to null
4357 # if we try to push a deleted bookmark, translate it to null
4356 # this lets simultaneous -r, -b options continue working
4358 # this lets simultaneous -r, -b options continue working
4357 opts.setdefault('rev', []).append("null")
4359 opts.setdefault('rev', []).append("null")
4358
4360
4359 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4361 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4360 if not path:
4362 if not path:
4361 raise error.Abort(_('default repository not configured!'),
4363 raise error.Abort(_('default repository not configured!'),
4362 hint=_("see 'hg help config.paths'"))
4364 hint=_("see 'hg help config.paths'"))
4363 dest = path.pushloc or path.loc
4365 dest = path.pushloc or path.loc
4364 branches = (path.branch, opts.get('branch') or [])
4366 branches = (path.branch, opts.get('branch') or [])
4365 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4367 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4366 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4368 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4367 other = hg.peer(repo, opts, dest)
4369 other = hg.peer(repo, opts, dest)
4368
4370
4369 if revs:
4371 if revs:
4370 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4372 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4371 if not revs:
4373 if not revs:
4372 raise error.Abort(_("specified revisions evaluate to an empty set"),
4374 raise error.Abort(_("specified revisions evaluate to an empty set"),
4373 hint=_("use different revision arguments"))
4375 hint=_("use different revision arguments"))
4374 elif path.pushrev:
4376 elif path.pushrev:
4375 # It doesn't make any sense to specify ancestor revisions. So limit
4377 # It doesn't make any sense to specify ancestor revisions. So limit
4376 # to DAG heads to make discovery simpler.
4378 # to DAG heads to make discovery simpler.
4377 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4379 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4378 revs = scmutil.revrange(repo, [expr])
4380 revs = scmutil.revrange(repo, [expr])
4379 revs = [repo[rev].node() for rev in revs]
4381 revs = [repo[rev].node() for rev in revs]
4380 if not revs:
4382 if not revs:
4381 raise error.Abort(_('default push revset for path evaluates to an '
4383 raise error.Abort(_('default push revset for path evaluates to an '
4382 'empty set'))
4384 'empty set'))
4383
4385
4384 repo._subtoppath = dest
4386 repo._subtoppath = dest
4385 try:
4387 try:
4386 # push subrepos depth-first for coherent ordering
4388 # push subrepos depth-first for coherent ordering
4387 c = repo['.']
4389 c = repo['.']
4388 subs = c.substate # only repos that are committed
4390 subs = c.substate # only repos that are committed
4389 for s in sorted(subs):
4391 for s in sorted(subs):
4390 result = c.sub(s).push(opts)
4392 result = c.sub(s).push(opts)
4391 if result == 0:
4393 if result == 0:
4392 return not result
4394 return not result
4393 finally:
4395 finally:
4394 del repo._subtoppath
4396 del repo._subtoppath
4395
4397
4396 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4398 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4397 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4399 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4398
4400
4399 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4401 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4400 newbranch=opts.get('new_branch'),
4402 newbranch=opts.get('new_branch'),
4401 bookmarks=opts.get('bookmark', ()),
4403 bookmarks=opts.get('bookmark', ()),
4402 opargs=opargs)
4404 opargs=opargs)
4403
4405
4404 result = not pushop.cgresult
4406 result = not pushop.cgresult
4405
4407
4406 if pushop.bkresult is not None:
4408 if pushop.bkresult is not None:
4407 if pushop.bkresult == 2:
4409 if pushop.bkresult == 2:
4408 result = 2
4410 result = 2
4409 elif not result and pushop.bkresult:
4411 elif not result and pushop.bkresult:
4410 result = 2
4412 result = 2
4411
4413
4412 return result
4414 return result
4413
4415
4414 @command('recover', [])
4416 @command('recover', [])
4415 def recover(ui, repo):
4417 def recover(ui, repo):
4416 """roll back an interrupted transaction
4418 """roll back an interrupted transaction
4417
4419
4418 Recover from an interrupted commit or pull.
4420 Recover from an interrupted commit or pull.
4419
4421
4420 This command tries to fix the repository status after an
4422 This command tries to fix the repository status after an
4421 interrupted operation. It should only be necessary when Mercurial
4423 interrupted operation. It should only be necessary when Mercurial
4422 suggests it.
4424 suggests it.
4423
4425
4424 Returns 0 if successful, 1 if nothing to recover or verify fails.
4426 Returns 0 if successful, 1 if nothing to recover or verify fails.
4425 """
4427 """
4426 if repo.recover():
4428 if repo.recover():
4427 return hg.verify(repo)
4429 return hg.verify(repo)
4428 return 1
4430 return 1
4429
4431
4430 @command('^remove|rm',
4432 @command('^remove|rm',
4431 [('A', 'after', None, _('record delete for missing files')),
4433 [('A', 'after', None, _('record delete for missing files')),
4432 ('f', 'force', None,
4434 ('f', 'force', None,
4433 _('forget added files, delete modified files')),
4435 _('forget added files, delete modified files')),
4434 ] + subrepoopts + walkopts + dryrunopts,
4436 ] + subrepoopts + walkopts + dryrunopts,
4435 _('[OPTION]... FILE...'),
4437 _('[OPTION]... FILE...'),
4436 inferrepo=True)
4438 inferrepo=True)
4437 def remove(ui, repo, *pats, **opts):
4439 def remove(ui, repo, *pats, **opts):
4438 """remove the specified files on the next commit
4440 """remove the specified files on the next commit
4439
4441
4440 Schedule the indicated files for removal from the current branch.
4442 Schedule the indicated files for removal from the current branch.
4441
4443
4442 This command schedules the files to be removed at the next commit.
4444 This command schedules the files to be removed at the next commit.
4443 To undo a remove before that, see :hg:`revert`. To undo added
4445 To undo a remove before that, see :hg:`revert`. To undo added
4444 files, see :hg:`forget`.
4446 files, see :hg:`forget`.
4445
4447
4446 .. container:: verbose
4448 .. container:: verbose
4447
4449
4448 -A/--after can be used to remove only files that have already
4450 -A/--after can be used to remove only files that have already
4449 been deleted, -f/--force can be used to force deletion, and -Af
4451 been deleted, -f/--force can be used to force deletion, and -Af
4450 can be used to remove files from the next revision without
4452 can be used to remove files from the next revision without
4451 deleting them from the working directory.
4453 deleting them from the working directory.
4452
4454
4453 The following table details the behavior of remove for different
4455 The following table details the behavior of remove for different
4454 file states (columns) and option combinations (rows). The file
4456 file states (columns) and option combinations (rows). The file
4455 states are Added [A], Clean [C], Modified [M] and Missing [!]
4457 states are Added [A], Clean [C], Modified [M] and Missing [!]
4456 (as reported by :hg:`status`). The actions are Warn, Remove
4458 (as reported by :hg:`status`). The actions are Warn, Remove
4457 (from branch) and Delete (from disk):
4459 (from branch) and Delete (from disk):
4458
4460
4459 ========= == == == ==
4461 ========= == == == ==
4460 opt/state A C M !
4462 opt/state A C M !
4461 ========= == == == ==
4463 ========= == == == ==
4462 none W RD W R
4464 none W RD W R
4463 -f R RD RD R
4465 -f R RD RD R
4464 -A W W W R
4466 -A W W W R
4465 -Af R R R R
4467 -Af R R R R
4466 ========= == == == ==
4468 ========= == == == ==
4467
4469
4468 .. note::
4470 .. note::
4469
4471
4470 :hg:`remove` never deletes files in Added [A] state from the
4472 :hg:`remove` never deletes files in Added [A] state from the
4471 working directory, not even if ``--force`` is specified.
4473 working directory, not even if ``--force`` is specified.
4472
4474
4473 Returns 0 on success, 1 if any warnings encountered.
4475 Returns 0 on success, 1 if any warnings encountered.
4474 """
4476 """
4475
4477
4476 opts = pycompat.byteskwargs(opts)
4478 opts = pycompat.byteskwargs(opts)
4477 after, force = opts.get('after'), opts.get('force')
4479 after, force = opts.get('after'), opts.get('force')
4478 dryrun = opts.get('dry_run')
4480 dryrun = opts.get('dry_run')
4479 if not pats and not after:
4481 if not pats and not after:
4480 raise error.Abort(_('no files specified'))
4482 raise error.Abort(_('no files specified'))
4481
4483
4482 m = scmutil.match(repo[None], pats, opts)
4484 m = scmutil.match(repo[None], pats, opts)
4483 subrepos = opts.get('subrepos')
4485 subrepos = opts.get('subrepos')
4484 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4486 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4485 dryrun=dryrun)
4487 dryrun=dryrun)
4486
4488
4487 @command('rename|move|mv',
4489 @command('rename|move|mv',
4488 [('A', 'after', None, _('record a rename that has already occurred')),
4490 [('A', 'after', None, _('record a rename that has already occurred')),
4489 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4491 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4490 ] + walkopts + dryrunopts,
4492 ] + walkopts + dryrunopts,
4491 _('[OPTION]... SOURCE... DEST'))
4493 _('[OPTION]... SOURCE... DEST'))
4492 def rename(ui, repo, *pats, **opts):
4494 def rename(ui, repo, *pats, **opts):
4493 """rename files; equivalent of copy + remove
4495 """rename files; equivalent of copy + remove
4494
4496
4495 Mark dest as copies of sources; mark sources for deletion. If dest
4497 Mark dest as copies of sources; mark sources for deletion. If dest
4496 is a directory, copies are put in that directory. If dest is a
4498 is a directory, copies are put in that directory. If dest is a
4497 file, there can only be one source.
4499 file, there can only be one source.
4498
4500
4499 By default, this command copies the contents of files as they
4501 By default, this command copies the contents of files as they
4500 exist in the working directory. If invoked with -A/--after, the
4502 exist in the working directory. If invoked with -A/--after, the
4501 operation is recorded, but no copying is performed.
4503 operation is recorded, but no copying is performed.
4502
4504
4503 This command takes effect at the next commit. To undo a rename
4505 This command takes effect at the next commit. To undo a rename
4504 before that, see :hg:`revert`.
4506 before that, see :hg:`revert`.
4505
4507
4506 Returns 0 on success, 1 if errors are encountered.
4508 Returns 0 on success, 1 if errors are encountered.
4507 """
4509 """
4508 opts = pycompat.byteskwargs(opts)
4510 opts = pycompat.byteskwargs(opts)
4509 with repo.wlock(False):
4511 with repo.wlock(False):
4510 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4512 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4511
4513
4512 @command('resolve',
4514 @command('resolve',
4513 [('a', 'all', None, _('select all unresolved files')),
4515 [('a', 'all', None, _('select all unresolved files')),
4514 ('l', 'list', None, _('list state of files needing merge')),
4516 ('l', 'list', None, _('list state of files needing merge')),
4515 ('m', 'mark', None, _('mark files as resolved')),
4517 ('m', 'mark', None, _('mark files as resolved')),
4516 ('u', 'unmark', None, _('mark files as unresolved')),
4518 ('u', 'unmark', None, _('mark files as unresolved')),
4517 ('n', 'no-status', None, _('hide status prefix')),
4519 ('n', 'no-status', None, _('hide status prefix')),
4518 ('', 're-merge', None, _('re-merge files'))]
4520 ('', 're-merge', None, _('re-merge files'))]
4519 + mergetoolopts + walkopts + formatteropts,
4521 + mergetoolopts + walkopts + formatteropts,
4520 _('[OPTION]... [FILE]...'),
4522 _('[OPTION]... [FILE]...'),
4521 inferrepo=True)
4523 inferrepo=True)
4522 def resolve(ui, repo, *pats, **opts):
4524 def resolve(ui, repo, *pats, **opts):
4523 """redo merges or set/view the merge status of files
4525 """redo merges or set/view the merge status of files
4524
4526
4525 Merges with unresolved conflicts are often the result of
4527 Merges with unresolved conflicts are often the result of
4526 non-interactive merging using the ``internal:merge`` configuration
4528 non-interactive merging using the ``internal:merge`` configuration
4527 setting, or a command-line merge tool like ``diff3``. The resolve
4529 setting, or a command-line merge tool like ``diff3``. The resolve
4528 command is used to manage the files involved in a merge, after
4530 command is used to manage the files involved in a merge, after
4529 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4531 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4530 working directory must have two parents). See :hg:`help
4532 working directory must have two parents). See :hg:`help
4531 merge-tools` for information on configuring merge tools.
4533 merge-tools` for information on configuring merge tools.
4532
4534
4533 The resolve command can be used in the following ways:
4535 The resolve command can be used in the following ways:
4534
4536
4535 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4537 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4536 the specified files, discarding any previous merge attempts. Re-merging
4538 the specified files, discarding any previous merge attempts. Re-merging
4537 is not performed for files already marked as resolved. Use ``--all/-a``
4539 is not performed for files already marked as resolved. Use ``--all/-a``
4538 to select all unresolved files. ``--tool`` can be used to specify
4540 to select all unresolved files. ``--tool`` can be used to specify
4539 the merge tool used for the given files. It overrides the HGMERGE
4541 the merge tool used for the given files. It overrides the HGMERGE
4540 environment variable and your configuration files. Previous file
4542 environment variable and your configuration files. Previous file
4541 contents are saved with a ``.orig`` suffix.
4543 contents are saved with a ``.orig`` suffix.
4542
4544
4543 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4545 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4544 (e.g. after having manually fixed-up the files). The default is
4546 (e.g. after having manually fixed-up the files). The default is
4545 to mark all unresolved files.
4547 to mark all unresolved files.
4546
4548
4547 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4549 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4548 default is to mark all resolved files.
4550 default is to mark all resolved files.
4549
4551
4550 - :hg:`resolve -l`: list files which had or still have conflicts.
4552 - :hg:`resolve -l`: list files which had or still have conflicts.
4551 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4553 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4552 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4554 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4553 the list. See :hg:`help filesets` for details.
4555 the list. See :hg:`help filesets` for details.
4554
4556
4555 .. note::
4557 .. note::
4556
4558
4557 Mercurial will not let you commit files with unresolved merge
4559 Mercurial will not let you commit files with unresolved merge
4558 conflicts. You must use :hg:`resolve -m ...` before you can
4560 conflicts. You must use :hg:`resolve -m ...` before you can
4559 commit after a conflicting merge.
4561 commit after a conflicting merge.
4560
4562
4561 Returns 0 on success, 1 if any files fail a resolve attempt.
4563 Returns 0 on success, 1 if any files fail a resolve attempt.
4562 """
4564 """
4563
4565
4564 opts = pycompat.byteskwargs(opts)
4566 opts = pycompat.byteskwargs(opts)
4565 confirm = ui.configbool('commands', 'resolve.confirm')
4567 confirm = ui.configbool('commands', 'resolve.confirm')
4566 flaglist = 'all mark unmark list no_status re_merge'.split()
4568 flaglist = 'all mark unmark list no_status re_merge'.split()
4567 all, mark, unmark, show, nostatus, remerge = \
4569 all, mark, unmark, show, nostatus, remerge = \
4568 [opts.get(o) for o in flaglist]
4570 [opts.get(o) for o in flaglist]
4569
4571
4570 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4572 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4571 if actioncount > 1:
4573 if actioncount > 1:
4572 raise error.Abort(_("too many actions specified"))
4574 raise error.Abort(_("too many actions specified"))
4573 elif (actioncount == 0
4575 elif (actioncount == 0
4574 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4576 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4575 hint = _('use --mark, --unmark, --list or --re-merge')
4577 hint = _('use --mark, --unmark, --list or --re-merge')
4576 raise error.Abort(_('no action specified'), hint=hint)
4578 raise error.Abort(_('no action specified'), hint=hint)
4577 if pats and all:
4579 if pats and all:
4578 raise error.Abort(_("can't specify --all and patterns"))
4580 raise error.Abort(_("can't specify --all and patterns"))
4579 if not (all or pats or show or mark or unmark):
4581 if not (all or pats or show or mark or unmark):
4580 raise error.Abort(_('no files or directories specified'),
4582 raise error.Abort(_('no files or directories specified'),
4581 hint=('use --all to re-merge all unresolved files'))
4583 hint=('use --all to re-merge all unresolved files'))
4582
4584
4583 if confirm:
4585 if confirm:
4584 if all:
4586 if all:
4585 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4587 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4586 b'$$ &Yes $$ &No')):
4588 b'$$ &Yes $$ &No')):
4587 raise error.Abort(_('user quit'))
4589 raise error.Abort(_('user quit'))
4588 if mark and not pats:
4590 if mark and not pats:
4589 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4591 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4590 b'$$ &Yes $$ &No')):
4592 b'$$ &Yes $$ &No')):
4591 raise error.Abort(_('user quit'))
4593 raise error.Abort(_('user quit'))
4592 if unmark and not pats:
4594 if unmark and not pats:
4593 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4595 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4594 b'$$ &Yes $$ &No')):
4596 b'$$ &Yes $$ &No')):
4595 raise error.Abort(_('user quit'))
4597 raise error.Abort(_('user quit'))
4596
4598
4597 if show:
4599 if show:
4598 ui.pager('resolve')
4600 ui.pager('resolve')
4599 fm = ui.formatter('resolve', opts)
4601 fm = ui.formatter('resolve', opts)
4600 ms = mergemod.mergestate.read(repo)
4602 ms = mergemod.mergestate.read(repo)
4601 wctx = repo[None]
4603 wctx = repo[None]
4602 m = scmutil.match(wctx, pats, opts)
4604 m = scmutil.match(wctx, pats, opts)
4603
4605
4604 # Labels and keys based on merge state. Unresolved path conflicts show
4606 # Labels and keys based on merge state. Unresolved path conflicts show
4605 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4607 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4606 # resolved conflicts.
4608 # resolved conflicts.
4607 mergestateinfo = {
4609 mergestateinfo = {
4608 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4610 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4609 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4611 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4610 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4612 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4611 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4613 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4612 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4614 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4613 'D'),
4615 'D'),
4614 }
4616 }
4615
4617
4616 for f in ms:
4618 for f in ms:
4617 if not m(f):
4619 if not m(f):
4618 continue
4620 continue
4619
4621
4620 label, key = mergestateinfo[ms[f]]
4622 label, key = mergestateinfo[ms[f]]
4621 fm.startitem()
4623 fm.startitem()
4622 fm.context(ctx=wctx)
4624 fm.context(ctx=wctx)
4623 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4625 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4624 fm.write('path', '%s\n', f, label=label)
4626 fm.write('path', '%s\n', f, label=label)
4625 fm.end()
4627 fm.end()
4626 return 0
4628 return 0
4627
4629
4628 with repo.wlock():
4630 with repo.wlock():
4629 ms = mergemod.mergestate.read(repo)
4631 ms = mergemod.mergestate.read(repo)
4630
4632
4631 if not (ms.active() or repo.dirstate.p2() != nullid):
4633 if not (ms.active() or repo.dirstate.p2() != nullid):
4632 raise error.Abort(
4634 raise error.Abort(
4633 _('resolve command not applicable when not merging'))
4635 _('resolve command not applicable when not merging'))
4634
4636
4635 wctx = repo[None]
4637 wctx = repo[None]
4636
4638
4637 if (ms.mergedriver
4639 if (ms.mergedriver
4638 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4640 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4639 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4641 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4640 ms.commit()
4642 ms.commit()
4641 # allow mark and unmark to go through
4643 # allow mark and unmark to go through
4642 if not mark and not unmark and not proceed:
4644 if not mark and not unmark and not proceed:
4643 return 1
4645 return 1
4644
4646
4645 m = scmutil.match(wctx, pats, opts)
4647 m = scmutil.match(wctx, pats, opts)
4646 ret = 0
4648 ret = 0
4647 didwork = False
4649 didwork = False
4648 runconclude = False
4650 runconclude = False
4649
4651
4650 tocomplete = []
4652 tocomplete = []
4651 hasconflictmarkers = []
4653 hasconflictmarkers = []
4652 if mark:
4654 if mark:
4653 markcheck = ui.config('commands', 'resolve.mark-check')
4655 markcheck = ui.config('commands', 'resolve.mark-check')
4654 if markcheck not in ['warn', 'abort']:
4656 if markcheck not in ['warn', 'abort']:
4655 # Treat all invalid / unrecognized values as 'none'.
4657 # Treat all invalid / unrecognized values as 'none'.
4656 markcheck = False
4658 markcheck = False
4657 for f in ms:
4659 for f in ms:
4658 if not m(f):
4660 if not m(f):
4659 continue
4661 continue
4660
4662
4661 didwork = True
4663 didwork = True
4662
4664
4663 # don't let driver-resolved files be marked, and run the conclude
4665 # don't let driver-resolved files be marked, and run the conclude
4664 # step if asked to resolve
4666 # step if asked to resolve
4665 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4667 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4666 exact = m.exact(f)
4668 exact = m.exact(f)
4667 if mark:
4669 if mark:
4668 if exact:
4670 if exact:
4669 ui.warn(_('not marking %s as it is driver-resolved\n')
4671 ui.warn(_('not marking %s as it is driver-resolved\n')
4670 % f)
4672 % f)
4671 elif unmark:
4673 elif unmark:
4672 if exact:
4674 if exact:
4673 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4675 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4674 % f)
4676 % f)
4675 else:
4677 else:
4676 runconclude = True
4678 runconclude = True
4677 continue
4679 continue
4678
4680
4679 # path conflicts must be resolved manually
4681 # path conflicts must be resolved manually
4680 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4682 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4681 mergemod.MERGE_RECORD_RESOLVED_PATH):
4683 mergemod.MERGE_RECORD_RESOLVED_PATH):
4682 if mark:
4684 if mark:
4683 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4685 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4684 elif unmark:
4686 elif unmark:
4685 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4687 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4686 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4688 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4687 ui.warn(_('%s: path conflict must be resolved manually\n')
4689 ui.warn(_('%s: path conflict must be resolved manually\n')
4688 % f)
4690 % f)
4689 continue
4691 continue
4690
4692
4691 if mark:
4693 if mark:
4692 if markcheck:
4694 if markcheck:
4693 with repo.wvfs(f) as fobj:
4695 with repo.wvfs(f) as fobj:
4694 fdata = fobj.read()
4696 fdata = fobj.read()
4695 if filemerge.hasconflictmarkers(fdata) and \
4697 if filemerge.hasconflictmarkers(fdata) and \
4696 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4698 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4697 hasconflictmarkers.append(f)
4699 hasconflictmarkers.append(f)
4698 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4700 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4699 elif unmark:
4701 elif unmark:
4700 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4702 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4701 else:
4703 else:
4702 # backup pre-resolve (merge uses .orig for its own purposes)
4704 # backup pre-resolve (merge uses .orig for its own purposes)
4703 a = repo.wjoin(f)
4705 a = repo.wjoin(f)
4704 try:
4706 try:
4705 util.copyfile(a, a + ".resolve")
4707 util.copyfile(a, a + ".resolve")
4706 except (IOError, OSError) as inst:
4708 except (IOError, OSError) as inst:
4707 if inst.errno != errno.ENOENT:
4709 if inst.errno != errno.ENOENT:
4708 raise
4710 raise
4709
4711
4710 try:
4712 try:
4711 # preresolve file
4713 # preresolve file
4712 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4714 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4713 with ui.configoverride(overrides, 'resolve'):
4715 with ui.configoverride(overrides, 'resolve'):
4714 complete, r = ms.preresolve(f, wctx)
4716 complete, r = ms.preresolve(f, wctx)
4715 if not complete:
4717 if not complete:
4716 tocomplete.append(f)
4718 tocomplete.append(f)
4717 elif r:
4719 elif r:
4718 ret = 1
4720 ret = 1
4719 finally:
4721 finally:
4720 ms.commit()
4722 ms.commit()
4721
4723
4722 # replace filemerge's .orig file with our resolve file, but only
4724 # replace filemerge's .orig file with our resolve file, but only
4723 # for merges that are complete
4725 # for merges that are complete
4724 if complete:
4726 if complete:
4725 try:
4727 try:
4726 util.rename(a + ".resolve",
4728 util.rename(a + ".resolve",
4727 scmutil.origpath(ui, repo, a))
4729 scmutil.origpath(ui, repo, a))
4728 except OSError as inst:
4730 except OSError as inst:
4729 if inst.errno != errno.ENOENT:
4731 if inst.errno != errno.ENOENT:
4730 raise
4732 raise
4731
4733
4732 if hasconflictmarkers:
4734 if hasconflictmarkers:
4733 ui.warn(_('warning: the following files still have conflict '
4735 ui.warn(_('warning: the following files still have conflict '
4734 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4736 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4735 if markcheck == 'abort' and not all:
4737 if markcheck == 'abort' and not all:
4736 raise error.Abort(_('conflict markers detected'),
4738 raise error.Abort(_('conflict markers detected'),
4737 hint=_('use --all to mark anyway'))
4739 hint=_('use --all to mark anyway'))
4738
4740
4739 for f in tocomplete:
4741 for f in tocomplete:
4740 try:
4742 try:
4741 # resolve file
4743 # resolve file
4742 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4744 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4743 with ui.configoverride(overrides, 'resolve'):
4745 with ui.configoverride(overrides, 'resolve'):
4744 r = ms.resolve(f, wctx)
4746 r = ms.resolve(f, wctx)
4745 if r:
4747 if r:
4746 ret = 1
4748 ret = 1
4747 finally:
4749 finally:
4748 ms.commit()
4750 ms.commit()
4749
4751
4750 # replace filemerge's .orig file with our resolve file
4752 # replace filemerge's .orig file with our resolve file
4751 a = repo.wjoin(f)
4753 a = repo.wjoin(f)
4752 try:
4754 try:
4753 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4755 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4754 except OSError as inst:
4756 except OSError as inst:
4755 if inst.errno != errno.ENOENT:
4757 if inst.errno != errno.ENOENT:
4756 raise
4758 raise
4757
4759
4758 ms.commit()
4760 ms.commit()
4759 ms.recordactions()
4761 ms.recordactions()
4760
4762
4761 if not didwork and pats:
4763 if not didwork and pats:
4762 hint = None
4764 hint = None
4763 if not any([p for p in pats if p.find(':') >= 0]):
4765 if not any([p for p in pats if p.find(':') >= 0]):
4764 pats = ['path:%s' % p for p in pats]
4766 pats = ['path:%s' % p for p in pats]
4765 m = scmutil.match(wctx, pats, opts)
4767 m = scmutil.match(wctx, pats, opts)
4766 for f in ms:
4768 for f in ms:
4767 if not m(f):
4769 if not m(f):
4768 continue
4770 continue
4769 def flag(o):
4771 def flag(o):
4770 if o == 're_merge':
4772 if o == 're_merge':
4771 return '--re-merge '
4773 return '--re-merge '
4772 return '-%s ' % o[0:1]
4774 return '-%s ' % o[0:1]
4773 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4775 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4774 hint = _("(try: hg resolve %s%s)\n") % (
4776 hint = _("(try: hg resolve %s%s)\n") % (
4775 flags,
4777 flags,
4776 ' '.join(pats))
4778 ' '.join(pats))
4777 break
4779 break
4778 ui.warn(_("arguments do not match paths that need resolving\n"))
4780 ui.warn(_("arguments do not match paths that need resolving\n"))
4779 if hint:
4781 if hint:
4780 ui.warn(hint)
4782 ui.warn(hint)
4781 elif ms.mergedriver and ms.mdstate() != 's':
4783 elif ms.mergedriver and ms.mdstate() != 's':
4782 # run conclude step when either a driver-resolved file is requested
4784 # run conclude step when either a driver-resolved file is requested
4783 # or there are no driver-resolved files
4785 # or there are no driver-resolved files
4784 # we can't use 'ret' to determine whether any files are unresolved
4786 # we can't use 'ret' to determine whether any files are unresolved
4785 # because we might not have tried to resolve some
4787 # because we might not have tried to resolve some
4786 if ((runconclude or not list(ms.driverresolved()))
4788 if ((runconclude or not list(ms.driverresolved()))
4787 and not list(ms.unresolved())):
4789 and not list(ms.unresolved())):
4788 proceed = mergemod.driverconclude(repo, ms, wctx)
4790 proceed = mergemod.driverconclude(repo, ms, wctx)
4789 ms.commit()
4791 ms.commit()
4790 if not proceed:
4792 if not proceed:
4791 return 1
4793 return 1
4792
4794
4793 # Nudge users into finishing an unfinished operation
4795 # Nudge users into finishing an unfinished operation
4794 unresolvedf = list(ms.unresolved())
4796 unresolvedf = list(ms.unresolved())
4795 driverresolvedf = list(ms.driverresolved())
4797 driverresolvedf = list(ms.driverresolved())
4796 if not unresolvedf and not driverresolvedf:
4798 if not unresolvedf and not driverresolvedf:
4797 ui.status(_('(no more unresolved files)\n'))
4799 ui.status(_('(no more unresolved files)\n'))
4798 cmdutil.checkafterresolved(repo)
4800 cmdutil.checkafterresolved(repo)
4799 elif not unresolvedf:
4801 elif not unresolvedf:
4800 ui.status(_('(no more unresolved files -- '
4802 ui.status(_('(no more unresolved files -- '
4801 'run "hg resolve --all" to conclude)\n'))
4803 'run "hg resolve --all" to conclude)\n'))
4802
4804
4803 return ret
4805 return ret
4804
4806
4805 @command('revert',
4807 @command('revert',
4806 [('a', 'all', None, _('revert all changes when no arguments given')),
4808 [('a', 'all', None, _('revert all changes when no arguments given')),
4807 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4809 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4808 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4810 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4809 ('C', 'no-backup', None, _('do not save backup copies of files')),
4811 ('C', 'no-backup', None, _('do not save backup copies of files')),
4810 ('i', 'interactive', None, _('interactively select the changes')),
4812 ('i', 'interactive', None, _('interactively select the changes')),
4811 ] + walkopts + dryrunopts,
4813 ] + walkopts + dryrunopts,
4812 _('[OPTION]... [-r REV] [NAME]...'))
4814 _('[OPTION]... [-r REV] [NAME]...'))
4813 def revert(ui, repo, *pats, **opts):
4815 def revert(ui, repo, *pats, **opts):
4814 """restore files to their checkout state
4816 """restore files to their checkout state
4815
4817
4816 .. note::
4818 .. note::
4817
4819
4818 To check out earlier revisions, you should use :hg:`update REV`.
4820 To check out earlier revisions, you should use :hg:`update REV`.
4819 To cancel an uncommitted merge (and lose your changes),
4821 To cancel an uncommitted merge (and lose your changes),
4820 use :hg:`merge --abort`.
4822 use :hg:`merge --abort`.
4821
4823
4822 With no revision specified, revert the specified files or directories
4824 With no revision specified, revert the specified files or directories
4823 to the contents they had in the parent of the working directory.
4825 to the contents they had in the parent of the working directory.
4824 This restores the contents of files to an unmodified
4826 This restores the contents of files to an unmodified
4825 state and unschedules adds, removes, copies, and renames. If the
4827 state and unschedules adds, removes, copies, and renames. If the
4826 working directory has two parents, you must explicitly specify a
4828 working directory has two parents, you must explicitly specify a
4827 revision.
4829 revision.
4828
4830
4829 Using the -r/--rev or -d/--date options, revert the given files or
4831 Using the -r/--rev or -d/--date options, revert the given files or
4830 directories to their states as of a specific revision. Because
4832 directories to their states as of a specific revision. Because
4831 revert does not change the working directory parents, this will
4833 revert does not change the working directory parents, this will
4832 cause these files to appear modified. This can be helpful to "back
4834 cause these files to appear modified. This can be helpful to "back
4833 out" some or all of an earlier change. See :hg:`backout` for a
4835 out" some or all of an earlier change. See :hg:`backout` for a
4834 related method.
4836 related method.
4835
4837
4836 Modified files are saved with a .orig suffix before reverting.
4838 Modified files are saved with a .orig suffix before reverting.
4837 To disable these backups, use --no-backup. It is possible to store
4839 To disable these backups, use --no-backup. It is possible to store
4838 the backup files in a custom directory relative to the root of the
4840 the backup files in a custom directory relative to the root of the
4839 repository by setting the ``ui.origbackuppath`` configuration
4841 repository by setting the ``ui.origbackuppath`` configuration
4840 option.
4842 option.
4841
4843
4842 See :hg:`help dates` for a list of formats valid for -d/--date.
4844 See :hg:`help dates` for a list of formats valid for -d/--date.
4843
4845
4844 See :hg:`help backout` for a way to reverse the effect of an
4846 See :hg:`help backout` for a way to reverse the effect of an
4845 earlier changeset.
4847 earlier changeset.
4846
4848
4847 Returns 0 on success.
4849 Returns 0 on success.
4848 """
4850 """
4849
4851
4850 opts = pycompat.byteskwargs(opts)
4852 opts = pycompat.byteskwargs(opts)
4851 if opts.get("date"):
4853 if opts.get("date"):
4852 if opts.get("rev"):
4854 if opts.get("rev"):
4853 raise error.Abort(_("you can't specify a revision and a date"))
4855 raise error.Abort(_("you can't specify a revision and a date"))
4854 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4856 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4855
4857
4856 parent, p2 = repo.dirstate.parents()
4858 parent, p2 = repo.dirstate.parents()
4857 if not opts.get('rev') and p2 != nullid:
4859 if not opts.get('rev') and p2 != nullid:
4858 # revert after merge is a trap for new users (issue2915)
4860 # revert after merge is a trap for new users (issue2915)
4859 raise error.Abort(_('uncommitted merge with no revision specified'),
4861 raise error.Abort(_('uncommitted merge with no revision specified'),
4860 hint=_("use 'hg update' or see 'hg help revert'"))
4862 hint=_("use 'hg update' or see 'hg help revert'"))
4861
4863
4862 rev = opts.get('rev')
4864 rev = opts.get('rev')
4863 if rev:
4865 if rev:
4864 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4866 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4865 ctx = scmutil.revsingle(repo, rev)
4867 ctx = scmutil.revsingle(repo, rev)
4866
4868
4867 if (not (pats or opts.get('include') or opts.get('exclude') or
4869 if (not (pats or opts.get('include') or opts.get('exclude') or
4868 opts.get('all') or opts.get('interactive'))):
4870 opts.get('all') or opts.get('interactive'))):
4869 msg = _("no files or directories specified")
4871 msg = _("no files or directories specified")
4870 if p2 != nullid:
4872 if p2 != nullid:
4871 hint = _("uncommitted merge, use --all to discard all changes,"
4873 hint = _("uncommitted merge, use --all to discard all changes,"
4872 " or 'hg update -C .' to abort the merge")
4874 " or 'hg update -C .' to abort the merge")
4873 raise error.Abort(msg, hint=hint)
4875 raise error.Abort(msg, hint=hint)
4874 dirty = any(repo.status())
4876 dirty = any(repo.status())
4875 node = ctx.node()
4877 node = ctx.node()
4876 if node != parent:
4878 if node != parent:
4877 if dirty:
4879 if dirty:
4878 hint = _("uncommitted changes, use --all to discard all"
4880 hint = _("uncommitted changes, use --all to discard all"
4879 " changes, or 'hg update %s' to update") % ctx.rev()
4881 " changes, or 'hg update %s' to update") % ctx.rev()
4880 else:
4882 else:
4881 hint = _("use --all to revert all files,"
4883 hint = _("use --all to revert all files,"
4882 " or 'hg update %s' to update") % ctx.rev()
4884 " or 'hg update %s' to update") % ctx.rev()
4883 elif dirty:
4885 elif dirty:
4884 hint = _("uncommitted changes, use --all to discard all changes")
4886 hint = _("uncommitted changes, use --all to discard all changes")
4885 else:
4887 else:
4886 hint = _("use --all to revert all files")
4888 hint = _("use --all to revert all files")
4887 raise error.Abort(msg, hint=hint)
4889 raise error.Abort(msg, hint=hint)
4888
4890
4889 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4891 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4890 **pycompat.strkwargs(opts))
4892 **pycompat.strkwargs(opts))
4891
4893
4892 @command('rollback', dryrunopts +
4894 @command('rollback', dryrunopts +
4893 [('f', 'force', False, _('ignore safety measures'))])
4895 [('f', 'force', False, _('ignore safety measures'))])
4894 def rollback(ui, repo, **opts):
4896 def rollback(ui, repo, **opts):
4895 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4897 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4896
4898
4897 Please use :hg:`commit --amend` instead of rollback to correct
4899 Please use :hg:`commit --amend` instead of rollback to correct
4898 mistakes in the last commit.
4900 mistakes in the last commit.
4899
4901
4900 This command should be used with care. There is only one level of
4902 This command should be used with care. There is only one level of
4901 rollback, and there is no way to undo a rollback. It will also
4903 rollback, and there is no way to undo a rollback. It will also
4902 restore the dirstate at the time of the last transaction, losing
4904 restore the dirstate at the time of the last transaction, losing
4903 any dirstate changes since that time. This command does not alter
4905 any dirstate changes since that time. This command does not alter
4904 the working directory.
4906 the working directory.
4905
4907
4906 Transactions are used to encapsulate the effects of all commands
4908 Transactions are used to encapsulate the effects of all commands
4907 that create new changesets or propagate existing changesets into a
4909 that create new changesets or propagate existing changesets into a
4908 repository.
4910 repository.
4909
4911
4910 .. container:: verbose
4912 .. container:: verbose
4911
4913
4912 For example, the following commands are transactional, and their
4914 For example, the following commands are transactional, and their
4913 effects can be rolled back:
4915 effects can be rolled back:
4914
4916
4915 - commit
4917 - commit
4916 - import
4918 - import
4917 - pull
4919 - pull
4918 - push (with this repository as the destination)
4920 - push (with this repository as the destination)
4919 - unbundle
4921 - unbundle
4920
4922
4921 To avoid permanent data loss, rollback will refuse to rollback a
4923 To avoid permanent data loss, rollback will refuse to rollback a
4922 commit transaction if it isn't checked out. Use --force to
4924 commit transaction if it isn't checked out. Use --force to
4923 override this protection.
4925 override this protection.
4924
4926
4925 The rollback command can be entirely disabled by setting the
4927 The rollback command can be entirely disabled by setting the
4926 ``ui.rollback`` configuration setting to false. If you're here
4928 ``ui.rollback`` configuration setting to false. If you're here
4927 because you want to use rollback and it's disabled, you can
4929 because you want to use rollback and it's disabled, you can
4928 re-enable the command by setting ``ui.rollback`` to true.
4930 re-enable the command by setting ``ui.rollback`` to true.
4929
4931
4930 This command is not intended for use on public repositories. Once
4932 This command is not intended for use on public repositories. Once
4931 changes are visible for pull by other users, rolling a transaction
4933 changes are visible for pull by other users, rolling a transaction
4932 back locally is ineffective (someone else may already have pulled
4934 back locally is ineffective (someone else may already have pulled
4933 the changes). Furthermore, a race is possible with readers of the
4935 the changes). Furthermore, a race is possible with readers of the
4934 repository; for example an in-progress pull from the repository
4936 repository; for example an in-progress pull from the repository
4935 may fail if a rollback is performed.
4937 may fail if a rollback is performed.
4936
4938
4937 Returns 0 on success, 1 if no rollback data is available.
4939 Returns 0 on success, 1 if no rollback data is available.
4938 """
4940 """
4939 if not ui.configbool('ui', 'rollback'):
4941 if not ui.configbool('ui', 'rollback'):
4940 raise error.Abort(_('rollback is disabled because it is unsafe'),
4942 raise error.Abort(_('rollback is disabled because it is unsafe'),
4941 hint=('see `hg help -v rollback` for information'))
4943 hint=('see `hg help -v rollback` for information'))
4942 return repo.rollback(dryrun=opts.get(r'dry_run'),
4944 return repo.rollback(dryrun=opts.get(r'dry_run'),
4943 force=opts.get(r'force'))
4945 force=opts.get(r'force'))
4944
4946
4945 @command('root', [], intents={INTENT_READONLY})
4947 @command('root', [], intents={INTENT_READONLY})
4946 def root(ui, repo):
4948 def root(ui, repo):
4947 """print the root (top) of the current working directory
4949 """print the root (top) of the current working directory
4948
4950
4949 Print the root directory of the current repository.
4951 Print the root directory of the current repository.
4950
4952
4951 Returns 0 on success.
4953 Returns 0 on success.
4952 """
4954 """
4953 ui.write(repo.root + "\n")
4955 ui.write(repo.root + "\n")
4954
4956
4955 @command('^serve',
4957 @command('^serve',
4956 [('A', 'accesslog', '', _('name of access log file to write to'),
4958 [('A', 'accesslog', '', _('name of access log file to write to'),
4957 _('FILE')),
4959 _('FILE')),
4958 ('d', 'daemon', None, _('run server in background')),
4960 ('d', 'daemon', None, _('run server in background')),
4959 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4961 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4960 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4962 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4961 # use string type, then we can check if something was passed
4963 # use string type, then we can check if something was passed
4962 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4964 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4963 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4965 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4964 _('ADDR')),
4966 _('ADDR')),
4965 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4967 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4966 _('PREFIX')),
4968 _('PREFIX')),
4967 ('n', 'name', '',
4969 ('n', 'name', '',
4968 _('name to show in web pages (default: working directory)'), _('NAME')),
4970 _('name to show in web pages (default: working directory)'), _('NAME')),
4969 ('', 'web-conf', '',
4971 ('', 'web-conf', '',
4970 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4972 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4971 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4973 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4972 _('FILE')),
4974 _('FILE')),
4973 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4975 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4974 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4976 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4975 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4977 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4976 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4978 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4977 ('', 'style', '', _('template style to use'), _('STYLE')),
4979 ('', 'style', '', _('template style to use'), _('STYLE')),
4978 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4980 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4979 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4981 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4980 ('', 'print-url', None, _('start and print only the URL'))]
4982 ('', 'print-url', None, _('start and print only the URL'))]
4981 + subrepoopts,
4983 + subrepoopts,
4982 _('[OPTION]...'),
4984 _('[OPTION]...'),
4983 optionalrepo=True)
4985 optionalrepo=True)
4984 def serve(ui, repo, **opts):
4986 def serve(ui, repo, **opts):
4985 """start stand-alone webserver
4987 """start stand-alone webserver
4986
4988
4987 Start a local HTTP repository browser and pull server. You can use
4989 Start a local HTTP repository browser and pull server. You can use
4988 this for ad-hoc sharing and browsing of repositories. It is
4990 this for ad-hoc sharing and browsing of repositories. It is
4989 recommended to use a real web server to serve a repository for
4991 recommended to use a real web server to serve a repository for
4990 longer periods of time.
4992 longer periods of time.
4991
4993
4992 Please note that the server does not implement access control.
4994 Please note that the server does not implement access control.
4993 This means that, by default, anybody can read from the server and
4995 This means that, by default, anybody can read from the server and
4994 nobody can write to it by default. Set the ``web.allow-push``
4996 nobody can write to it by default. Set the ``web.allow-push``
4995 option to ``*`` to allow everybody to push to the server. You
4997 option to ``*`` to allow everybody to push to the server. You
4996 should use a real web server if you need to authenticate users.
4998 should use a real web server if you need to authenticate users.
4997
4999
4998 By default, the server logs accesses to stdout and errors to
5000 By default, the server logs accesses to stdout and errors to
4999 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5001 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5000 files.
5002 files.
5001
5003
5002 To have the server choose a free port number to listen on, specify
5004 To have the server choose a free port number to listen on, specify
5003 a port number of 0; in this case, the server will print the port
5005 a port number of 0; in this case, the server will print the port
5004 number it uses.
5006 number it uses.
5005
5007
5006 Returns 0 on success.
5008 Returns 0 on success.
5007 """
5009 """
5008
5010
5009 opts = pycompat.byteskwargs(opts)
5011 opts = pycompat.byteskwargs(opts)
5010 if opts["stdio"] and opts["cmdserver"]:
5012 if opts["stdio"] and opts["cmdserver"]:
5011 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5013 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5012 if opts["print_url"] and ui.verbose:
5014 if opts["print_url"] and ui.verbose:
5013 raise error.Abort(_("cannot use --print-url with --verbose"))
5015 raise error.Abort(_("cannot use --print-url with --verbose"))
5014
5016
5015 if opts["stdio"]:
5017 if opts["stdio"]:
5016 if repo is None:
5018 if repo is None:
5017 raise error.RepoError(_("there is no Mercurial repository here"
5019 raise error.RepoError(_("there is no Mercurial repository here"
5018 " (.hg not found)"))
5020 " (.hg not found)"))
5019 s = wireprotoserver.sshserver(ui, repo)
5021 s = wireprotoserver.sshserver(ui, repo)
5020 s.serve_forever()
5022 s.serve_forever()
5021
5023
5022 service = server.createservice(ui, repo, opts)
5024 service = server.createservice(ui, repo, opts)
5023 return server.runservice(opts, initfn=service.init, runfn=service.run)
5025 return server.runservice(opts, initfn=service.init, runfn=service.run)
5024
5026
5025 _NOTTERSE = 'nothing'
5027 _NOTTERSE = 'nothing'
5026
5028
5027 @command('^status|st',
5029 @command('^status|st',
5028 [('A', 'all', None, _('show status of all files')),
5030 [('A', 'all', None, _('show status of all files')),
5029 ('m', 'modified', None, _('show only modified files')),
5031 ('m', 'modified', None, _('show only modified files')),
5030 ('a', 'added', None, _('show only added files')),
5032 ('a', 'added', None, _('show only added files')),
5031 ('r', 'removed', None, _('show only removed files')),
5033 ('r', 'removed', None, _('show only removed files')),
5032 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5034 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5033 ('c', 'clean', None, _('show only files without changes')),
5035 ('c', 'clean', None, _('show only files without changes')),
5034 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5036 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5035 ('i', 'ignored', None, _('show only ignored files')),
5037 ('i', 'ignored', None, _('show only ignored files')),
5036 ('n', 'no-status', None, _('hide status prefix')),
5038 ('n', 'no-status', None, _('hide status prefix')),
5037 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5039 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5038 ('C', 'copies', None, _('show source of copied files')),
5040 ('C', 'copies', None, _('show source of copied files')),
5039 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5040 ('', 'rev', [], _('show difference from revision'), _('REV')),
5042 ('', 'rev', [], _('show difference from revision'), _('REV')),
5041 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5043 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5042 ] + walkopts + subrepoopts + formatteropts,
5044 ] + walkopts + subrepoopts + formatteropts,
5043 _('[OPTION]... [FILE]...'),
5045 _('[OPTION]... [FILE]...'),
5044 inferrepo=True,
5046 inferrepo=True,
5045 intents={INTENT_READONLY})
5047 intents={INTENT_READONLY})
5046 def status(ui, repo, *pats, **opts):
5048 def status(ui, repo, *pats, **opts):
5047 """show changed files in the working directory
5049 """show changed files in the working directory
5048
5050
5049 Show status of files in the repository. If names are given, only
5051 Show status of files in the repository. If names are given, only
5050 files that match are shown. Files that are clean or ignored or
5052 files that match are shown. Files that are clean or ignored or
5051 the source of a copy/move operation, are not listed unless
5053 the source of a copy/move operation, are not listed unless
5052 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5054 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5053 Unless options described with "show only ..." are given, the
5055 Unless options described with "show only ..." are given, the
5054 options -mardu are used.
5056 options -mardu are used.
5055
5057
5056 Option -q/--quiet hides untracked (unknown and ignored) files
5058 Option -q/--quiet hides untracked (unknown and ignored) files
5057 unless explicitly requested with -u/--unknown or -i/--ignored.
5059 unless explicitly requested with -u/--unknown or -i/--ignored.
5058
5060
5059 .. note::
5061 .. note::
5060
5062
5061 :hg:`status` may appear to disagree with diff if permissions have
5063 :hg:`status` may appear to disagree with diff if permissions have
5062 changed or a merge has occurred. The standard diff format does
5064 changed or a merge has occurred. The standard diff format does
5063 not report permission changes and diff only reports changes
5065 not report permission changes and diff only reports changes
5064 relative to one merge parent.
5066 relative to one merge parent.
5065
5067
5066 If one revision is given, it is used as the base revision.
5068 If one revision is given, it is used as the base revision.
5067 If two revisions are given, the differences between them are
5069 If two revisions are given, the differences between them are
5068 shown. The --change option can also be used as a shortcut to list
5070 shown. The --change option can also be used as a shortcut to list
5069 the changed files of a revision from its first parent.
5071 the changed files of a revision from its first parent.
5070
5072
5071 The codes used to show the status of files are::
5073 The codes used to show the status of files are::
5072
5074
5073 M = modified
5075 M = modified
5074 A = added
5076 A = added
5075 R = removed
5077 R = removed
5076 C = clean
5078 C = clean
5077 ! = missing (deleted by non-hg command, but still tracked)
5079 ! = missing (deleted by non-hg command, but still tracked)
5078 ? = not tracked
5080 ? = not tracked
5079 I = ignored
5081 I = ignored
5080 = origin of the previous file (with --copies)
5082 = origin of the previous file (with --copies)
5081
5083
5082 .. container:: verbose
5084 .. container:: verbose
5083
5085
5084 The -t/--terse option abbreviates the output by showing only the directory
5086 The -t/--terse option abbreviates the output by showing only the directory
5085 name if all the files in it share the same status. The option takes an
5087 name if all the files in it share the same status. The option takes an
5086 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5088 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5087 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5089 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5088 for 'ignored' and 'c' for clean.
5090 for 'ignored' and 'c' for clean.
5089
5091
5090 It abbreviates only those statuses which are passed. Note that clean and
5092 It abbreviates only those statuses which are passed. Note that clean and
5091 ignored files are not displayed with '--terse ic' unless the -c/--clean
5093 ignored files are not displayed with '--terse ic' unless the -c/--clean
5092 and -i/--ignored options are also used.
5094 and -i/--ignored options are also used.
5093
5095
5094 The -v/--verbose option shows information when the repository is in an
5096 The -v/--verbose option shows information when the repository is in an
5095 unfinished merge, shelve, rebase state etc. You can have this behavior
5097 unfinished merge, shelve, rebase state etc. You can have this behavior
5096 turned on by default by enabling the ``commands.status.verbose`` option.
5098 turned on by default by enabling the ``commands.status.verbose`` option.
5097
5099
5098 You can skip displaying some of these states by setting
5100 You can skip displaying some of these states by setting
5099 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5101 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5100 'histedit', 'merge', 'rebase', or 'unshelve'.
5102 'histedit', 'merge', 'rebase', or 'unshelve'.
5101
5103
5102 Examples:
5104 Examples:
5103
5105
5104 - show changes in the working directory relative to a
5106 - show changes in the working directory relative to a
5105 changeset::
5107 changeset::
5106
5108
5107 hg status --rev 9353
5109 hg status --rev 9353
5108
5110
5109 - show changes in the working directory relative to the
5111 - show changes in the working directory relative to the
5110 current directory (see :hg:`help patterns` for more information)::
5112 current directory (see :hg:`help patterns` for more information)::
5111
5113
5112 hg status re:
5114 hg status re:
5113
5115
5114 - show all changes including copies in an existing changeset::
5116 - show all changes including copies in an existing changeset::
5115
5117
5116 hg status --copies --change 9353
5118 hg status --copies --change 9353
5117
5119
5118 - get a NUL separated list of added files, suitable for xargs::
5120 - get a NUL separated list of added files, suitable for xargs::
5119
5121
5120 hg status -an0
5122 hg status -an0
5121
5123
5122 - show more information about the repository status, abbreviating
5124 - show more information about the repository status, abbreviating
5123 added, removed, modified, deleted, and untracked paths::
5125 added, removed, modified, deleted, and untracked paths::
5124
5126
5125 hg status -v -t mardu
5127 hg status -v -t mardu
5126
5128
5127 Returns 0 on success.
5129 Returns 0 on success.
5128
5130
5129 """
5131 """
5130
5132
5131 opts = pycompat.byteskwargs(opts)
5133 opts = pycompat.byteskwargs(opts)
5132 revs = opts.get('rev')
5134 revs = opts.get('rev')
5133 change = opts.get('change')
5135 change = opts.get('change')
5134 terse = opts.get('terse')
5136 terse = opts.get('terse')
5135 if terse is _NOTTERSE:
5137 if terse is _NOTTERSE:
5136 if revs:
5138 if revs:
5137 terse = ''
5139 terse = ''
5138 else:
5140 else:
5139 terse = ui.config('commands', 'status.terse')
5141 terse = ui.config('commands', 'status.terse')
5140
5142
5141 if revs and change:
5143 if revs and change:
5142 msg = _('cannot specify --rev and --change at the same time')
5144 msg = _('cannot specify --rev and --change at the same time')
5143 raise error.Abort(msg)
5145 raise error.Abort(msg)
5144 elif revs and terse:
5146 elif revs and terse:
5145 msg = _('cannot use --terse with --rev')
5147 msg = _('cannot use --terse with --rev')
5146 raise error.Abort(msg)
5148 raise error.Abort(msg)
5147 elif change:
5149 elif change:
5148 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5150 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5149 ctx2 = scmutil.revsingle(repo, change, None)
5151 ctx2 = scmutil.revsingle(repo, change, None)
5150 ctx1 = ctx2.p1()
5152 ctx1 = ctx2.p1()
5151 else:
5153 else:
5152 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5154 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5153 ctx1, ctx2 = scmutil.revpair(repo, revs)
5155 ctx1, ctx2 = scmutil.revpair(repo, revs)
5154
5156
5155 if pats or ui.configbool('commands', 'status.relative'):
5157 if pats or ui.configbool('commands', 'status.relative'):
5156 cwd = repo.getcwd()
5158 cwd = repo.getcwd()
5157 else:
5159 else:
5158 cwd = ''
5160 cwd = ''
5159
5161
5160 if opts.get('print0'):
5162 if opts.get('print0'):
5161 end = '\0'
5163 end = '\0'
5162 else:
5164 else:
5163 end = '\n'
5165 end = '\n'
5164 copy = {}
5166 copy = {}
5165 states = 'modified added removed deleted unknown ignored clean'.split()
5167 states = 'modified added removed deleted unknown ignored clean'.split()
5166 show = [k for k in states if opts.get(k)]
5168 show = [k for k in states if opts.get(k)]
5167 if opts.get('all'):
5169 if opts.get('all'):
5168 show += ui.quiet and (states[:4] + ['clean']) or states
5170 show += ui.quiet and (states[:4] + ['clean']) or states
5169
5171
5170 if not show:
5172 if not show:
5171 if ui.quiet:
5173 if ui.quiet:
5172 show = states[:4]
5174 show = states[:4]
5173 else:
5175 else:
5174 show = states[:5]
5176 show = states[:5]
5175
5177
5176 m = scmutil.match(ctx2, pats, opts)
5178 m = scmutil.match(ctx2, pats, opts)
5177 if terse:
5179 if terse:
5178 # we need to compute clean and unknown to terse
5180 # we need to compute clean and unknown to terse
5179 stat = repo.status(ctx1.node(), ctx2.node(), m,
5181 stat = repo.status(ctx1.node(), ctx2.node(), m,
5180 'ignored' in show or 'i' in terse,
5182 'ignored' in show or 'i' in terse,
5181 clean=True, unknown=True,
5183 clean=True, unknown=True,
5182 listsubrepos=opts.get('subrepos'))
5184 listsubrepos=opts.get('subrepos'))
5183
5185
5184 stat = cmdutil.tersedir(stat, terse)
5186 stat = cmdutil.tersedir(stat, terse)
5185 else:
5187 else:
5186 stat = repo.status(ctx1.node(), ctx2.node(), m,
5188 stat = repo.status(ctx1.node(), ctx2.node(), m,
5187 'ignored' in show, 'clean' in show,
5189 'ignored' in show, 'clean' in show,
5188 'unknown' in show, opts.get('subrepos'))
5190 'unknown' in show, opts.get('subrepos'))
5189
5191
5190 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5192 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5191
5193
5192 if (opts.get('all') or opts.get('copies')
5194 if (opts.get('all') or opts.get('copies')
5193 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5195 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5194 copy = copies.pathcopies(ctx1, ctx2, m)
5196 copy = copies.pathcopies(ctx1, ctx2, m)
5195
5197
5196 ui.pager('status')
5198 ui.pager('status')
5197 fm = ui.formatter('status', opts)
5199 fm = ui.formatter('status', opts)
5198 fmt = '%s' + end
5200 fmt = '%s' + end
5199 showchar = not opts.get('no_status')
5201 showchar = not opts.get('no_status')
5200
5202
5201 for state, char, files in changestates:
5203 for state, char, files in changestates:
5202 if state in show:
5204 if state in show:
5203 label = 'status.' + state
5205 label = 'status.' + state
5204 for f in files:
5206 for f in files:
5205 fm.startitem()
5207 fm.startitem()
5206 fm.context(ctx=ctx2)
5208 fm.context(ctx=ctx2)
5207 fm.data(path=f)
5209 fm.data(path=f)
5208 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5210 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5209 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5211 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5210 if f in copy:
5212 if f in copy:
5211 fm.data(source=copy[f])
5213 fm.data(source=copy[f])
5212 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5214 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5213 label='status.copied')
5215 label='status.copied')
5214
5216
5215 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5217 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5216 and not ui.plain()):
5218 and not ui.plain()):
5217 cmdutil.morestatus(repo, fm)
5219 cmdutil.morestatus(repo, fm)
5218 fm.end()
5220 fm.end()
5219
5221
5220 @command('^summary|sum',
5222 @command('^summary|sum',
5221 [('', 'remote', None, _('check for push and pull'))],
5223 [('', 'remote', None, _('check for push and pull'))],
5222 '[--remote]',
5224 '[--remote]',
5223 intents={INTENT_READONLY})
5225 intents={INTENT_READONLY})
5224 def summary(ui, repo, **opts):
5226 def summary(ui, repo, **opts):
5225 """summarize working directory state
5227 """summarize working directory state
5226
5228
5227 This generates a brief summary of the working directory state,
5229 This generates a brief summary of the working directory state,
5228 including parents, branch, commit status, phase and available updates.
5230 including parents, branch, commit status, phase and available updates.
5229
5231
5230 With the --remote option, this will check the default paths for
5232 With the --remote option, this will check the default paths for
5231 incoming and outgoing changes. This can be time-consuming.
5233 incoming and outgoing changes. This can be time-consuming.
5232
5234
5233 Returns 0 on success.
5235 Returns 0 on success.
5234 """
5236 """
5235
5237
5236 opts = pycompat.byteskwargs(opts)
5238 opts = pycompat.byteskwargs(opts)
5237 ui.pager('summary')
5239 ui.pager('summary')
5238 ctx = repo[None]
5240 ctx = repo[None]
5239 parents = ctx.parents()
5241 parents = ctx.parents()
5240 pnode = parents[0].node()
5242 pnode = parents[0].node()
5241 marks = []
5243 marks = []
5242
5244
5243 ms = None
5245 ms = None
5244 try:
5246 try:
5245 ms = mergemod.mergestate.read(repo)
5247 ms = mergemod.mergestate.read(repo)
5246 except error.UnsupportedMergeRecords as e:
5248 except error.UnsupportedMergeRecords as e:
5247 s = ' '.join(e.recordtypes)
5249 s = ' '.join(e.recordtypes)
5248 ui.warn(
5250 ui.warn(
5249 _('warning: merge state has unsupported record types: %s\n') % s)
5251 _('warning: merge state has unsupported record types: %s\n') % s)
5250 unresolved = []
5252 unresolved = []
5251 else:
5253 else:
5252 unresolved = list(ms.unresolved())
5254 unresolved = list(ms.unresolved())
5253
5255
5254 for p in parents:
5256 for p in parents:
5255 # label with log.changeset (instead of log.parent) since this
5257 # label with log.changeset (instead of log.parent) since this
5256 # shows a working directory parent *changeset*:
5258 # shows a working directory parent *changeset*:
5257 # i18n: column positioning for "hg summary"
5259 # i18n: column positioning for "hg summary"
5258 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5260 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5259 label=logcmdutil.changesetlabels(p))
5261 label=logcmdutil.changesetlabels(p))
5260 ui.write(' '.join(p.tags()), label='log.tag')
5262 ui.write(' '.join(p.tags()), label='log.tag')
5261 if p.bookmarks():
5263 if p.bookmarks():
5262 marks.extend(p.bookmarks())
5264 marks.extend(p.bookmarks())
5263 if p.rev() == -1:
5265 if p.rev() == -1:
5264 if not len(repo):
5266 if not len(repo):
5265 ui.write(_(' (empty repository)'))
5267 ui.write(_(' (empty repository)'))
5266 else:
5268 else:
5267 ui.write(_(' (no revision checked out)'))
5269 ui.write(_(' (no revision checked out)'))
5268 if p.obsolete():
5270 if p.obsolete():
5269 ui.write(_(' (obsolete)'))
5271 ui.write(_(' (obsolete)'))
5270 if p.isunstable():
5272 if p.isunstable():
5271 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5273 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5272 for instability in p.instabilities())
5274 for instability in p.instabilities())
5273 ui.write(' ('
5275 ui.write(' ('
5274 + ', '.join(instabilities)
5276 + ', '.join(instabilities)
5275 + ')')
5277 + ')')
5276 ui.write('\n')
5278 ui.write('\n')
5277 if p.description():
5279 if p.description():
5278 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5280 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5279 label='log.summary')
5281 label='log.summary')
5280
5282
5281 branch = ctx.branch()
5283 branch = ctx.branch()
5282 bheads = repo.branchheads(branch)
5284 bheads = repo.branchheads(branch)
5283 # i18n: column positioning for "hg summary"
5285 # i18n: column positioning for "hg summary"
5284 m = _('branch: %s\n') % branch
5286 m = _('branch: %s\n') % branch
5285 if branch != 'default':
5287 if branch != 'default':
5286 ui.write(m, label='log.branch')
5288 ui.write(m, label='log.branch')
5287 else:
5289 else:
5288 ui.status(m, label='log.branch')
5290 ui.status(m, label='log.branch')
5289
5291
5290 if marks:
5292 if marks:
5291 active = repo._activebookmark
5293 active = repo._activebookmark
5292 # i18n: column positioning for "hg summary"
5294 # i18n: column positioning for "hg summary"
5293 ui.write(_('bookmarks:'), label='log.bookmark')
5295 ui.write(_('bookmarks:'), label='log.bookmark')
5294 if active is not None:
5296 if active is not None:
5295 if active in marks:
5297 if active in marks:
5296 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5298 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5297 marks.remove(active)
5299 marks.remove(active)
5298 else:
5300 else:
5299 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5301 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5300 for m in marks:
5302 for m in marks:
5301 ui.write(' ' + m, label='log.bookmark')
5303 ui.write(' ' + m, label='log.bookmark')
5302 ui.write('\n', label='log.bookmark')
5304 ui.write('\n', label='log.bookmark')
5303
5305
5304 status = repo.status(unknown=True)
5306 status = repo.status(unknown=True)
5305
5307
5306 c = repo.dirstate.copies()
5308 c = repo.dirstate.copies()
5307 copied, renamed = [], []
5309 copied, renamed = [], []
5308 for d, s in c.iteritems():
5310 for d, s in c.iteritems():
5309 if s in status.removed:
5311 if s in status.removed:
5310 status.removed.remove(s)
5312 status.removed.remove(s)
5311 renamed.append(d)
5313 renamed.append(d)
5312 else:
5314 else:
5313 copied.append(d)
5315 copied.append(d)
5314 if d in status.added:
5316 if d in status.added:
5315 status.added.remove(d)
5317 status.added.remove(d)
5316
5318
5317 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5319 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5318
5320
5319 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5321 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5320 (ui.label(_('%d added'), 'status.added'), status.added),
5322 (ui.label(_('%d added'), 'status.added'), status.added),
5321 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5323 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5322 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5324 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5323 (ui.label(_('%d copied'), 'status.copied'), copied),
5325 (ui.label(_('%d copied'), 'status.copied'), copied),
5324 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5326 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5325 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5327 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5326 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5328 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5327 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5329 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5328 t = []
5330 t = []
5329 for l, s in labels:
5331 for l, s in labels:
5330 if s:
5332 if s:
5331 t.append(l % len(s))
5333 t.append(l % len(s))
5332
5334
5333 t = ', '.join(t)
5335 t = ', '.join(t)
5334 cleanworkdir = False
5336 cleanworkdir = False
5335
5337
5336 if repo.vfs.exists('graftstate'):
5338 if repo.vfs.exists('graftstate'):
5337 t += _(' (graft in progress)')
5339 t += _(' (graft in progress)')
5338 if repo.vfs.exists('updatestate'):
5340 if repo.vfs.exists('updatestate'):
5339 t += _(' (interrupted update)')
5341 t += _(' (interrupted update)')
5340 elif len(parents) > 1:
5342 elif len(parents) > 1:
5341 t += _(' (merge)')
5343 t += _(' (merge)')
5342 elif branch != parents[0].branch():
5344 elif branch != parents[0].branch():
5343 t += _(' (new branch)')
5345 t += _(' (new branch)')
5344 elif (parents[0].closesbranch() and
5346 elif (parents[0].closesbranch() and
5345 pnode in repo.branchheads(branch, closed=True)):
5347 pnode in repo.branchheads(branch, closed=True)):
5346 t += _(' (head closed)')
5348 t += _(' (head closed)')
5347 elif not (status.modified or status.added or status.removed or renamed or
5349 elif not (status.modified or status.added or status.removed or renamed or
5348 copied or subs):
5350 copied or subs):
5349 t += _(' (clean)')
5351 t += _(' (clean)')
5350 cleanworkdir = True
5352 cleanworkdir = True
5351 elif pnode not in bheads:
5353 elif pnode not in bheads:
5352 t += _(' (new branch head)')
5354 t += _(' (new branch head)')
5353
5355
5354 if parents:
5356 if parents:
5355 pendingphase = max(p.phase() for p in parents)
5357 pendingphase = max(p.phase() for p in parents)
5356 else:
5358 else:
5357 pendingphase = phases.public
5359 pendingphase = phases.public
5358
5360
5359 if pendingphase > phases.newcommitphase(ui):
5361 if pendingphase > phases.newcommitphase(ui):
5360 t += ' (%s)' % phases.phasenames[pendingphase]
5362 t += ' (%s)' % phases.phasenames[pendingphase]
5361
5363
5362 if cleanworkdir:
5364 if cleanworkdir:
5363 # i18n: column positioning for "hg summary"
5365 # i18n: column positioning for "hg summary"
5364 ui.status(_('commit: %s\n') % t.strip())
5366 ui.status(_('commit: %s\n') % t.strip())
5365 else:
5367 else:
5366 # i18n: column positioning for "hg summary"
5368 # i18n: column positioning for "hg summary"
5367 ui.write(_('commit: %s\n') % t.strip())
5369 ui.write(_('commit: %s\n') % t.strip())
5368
5370
5369 # all ancestors of branch heads - all ancestors of parent = new csets
5371 # all ancestors of branch heads - all ancestors of parent = new csets
5370 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5372 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5371 bheads))
5373 bheads))
5372
5374
5373 if new == 0:
5375 if new == 0:
5374 # i18n: column positioning for "hg summary"
5376 # i18n: column positioning for "hg summary"
5375 ui.status(_('update: (current)\n'))
5377 ui.status(_('update: (current)\n'))
5376 elif pnode not in bheads:
5378 elif pnode not in bheads:
5377 # i18n: column positioning for "hg summary"
5379 # i18n: column positioning for "hg summary"
5378 ui.write(_('update: %d new changesets (update)\n') % new)
5380 ui.write(_('update: %d new changesets (update)\n') % new)
5379 else:
5381 else:
5380 # i18n: column positioning for "hg summary"
5382 # i18n: column positioning for "hg summary"
5381 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5383 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5382 (new, len(bheads)))
5384 (new, len(bheads)))
5383
5385
5384 t = []
5386 t = []
5385 draft = len(repo.revs('draft()'))
5387 draft = len(repo.revs('draft()'))
5386 if draft:
5388 if draft:
5387 t.append(_('%d draft') % draft)
5389 t.append(_('%d draft') % draft)
5388 secret = len(repo.revs('secret()'))
5390 secret = len(repo.revs('secret()'))
5389 if secret:
5391 if secret:
5390 t.append(_('%d secret') % secret)
5392 t.append(_('%d secret') % secret)
5391
5393
5392 if draft or secret:
5394 if draft or secret:
5393 ui.status(_('phases: %s\n') % ', '.join(t))
5395 ui.status(_('phases: %s\n') % ', '.join(t))
5394
5396
5395 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5397 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5396 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5398 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5397 numtrouble = len(repo.revs(trouble + "()"))
5399 numtrouble = len(repo.revs(trouble + "()"))
5398 # We write all the possibilities to ease translation
5400 # We write all the possibilities to ease translation
5399 troublemsg = {
5401 troublemsg = {
5400 "orphan": _("orphan: %d changesets"),
5402 "orphan": _("orphan: %d changesets"),
5401 "contentdivergent": _("content-divergent: %d changesets"),
5403 "contentdivergent": _("content-divergent: %d changesets"),
5402 "phasedivergent": _("phase-divergent: %d changesets"),
5404 "phasedivergent": _("phase-divergent: %d changesets"),
5403 }
5405 }
5404 if numtrouble > 0:
5406 if numtrouble > 0:
5405 ui.status(troublemsg[trouble] % numtrouble + "\n")
5407 ui.status(troublemsg[trouble] % numtrouble + "\n")
5406
5408
5407 cmdutil.summaryhooks(ui, repo)
5409 cmdutil.summaryhooks(ui, repo)
5408
5410
5409 if opts.get('remote'):
5411 if opts.get('remote'):
5410 needsincoming, needsoutgoing = True, True
5412 needsincoming, needsoutgoing = True, True
5411 else:
5413 else:
5412 needsincoming, needsoutgoing = False, False
5414 needsincoming, needsoutgoing = False, False
5413 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5415 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5414 if i:
5416 if i:
5415 needsincoming = True
5417 needsincoming = True
5416 if o:
5418 if o:
5417 needsoutgoing = True
5419 needsoutgoing = True
5418 if not needsincoming and not needsoutgoing:
5420 if not needsincoming and not needsoutgoing:
5419 return
5421 return
5420
5422
5421 def getincoming():
5423 def getincoming():
5422 source, branches = hg.parseurl(ui.expandpath('default'))
5424 source, branches = hg.parseurl(ui.expandpath('default'))
5423 sbranch = branches[0]
5425 sbranch = branches[0]
5424 try:
5426 try:
5425 other = hg.peer(repo, {}, source)
5427 other = hg.peer(repo, {}, source)
5426 except error.RepoError:
5428 except error.RepoError:
5427 if opts.get('remote'):
5429 if opts.get('remote'):
5428 raise
5430 raise
5429 return source, sbranch, None, None, None
5431 return source, sbranch, None, None, None
5430 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5432 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5431 if revs:
5433 if revs:
5432 revs = [other.lookup(rev) for rev in revs]
5434 revs = [other.lookup(rev) for rev in revs]
5433 ui.debug('comparing with %s\n' % util.hidepassword(source))
5435 ui.debug('comparing with %s\n' % util.hidepassword(source))
5434 repo.ui.pushbuffer()
5436 repo.ui.pushbuffer()
5435 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5437 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5436 repo.ui.popbuffer()
5438 repo.ui.popbuffer()
5437 return source, sbranch, other, commoninc, commoninc[1]
5439 return source, sbranch, other, commoninc, commoninc[1]
5438
5440
5439 if needsincoming:
5441 if needsincoming:
5440 source, sbranch, sother, commoninc, incoming = getincoming()
5442 source, sbranch, sother, commoninc, incoming = getincoming()
5441 else:
5443 else:
5442 source = sbranch = sother = commoninc = incoming = None
5444 source = sbranch = sother = commoninc = incoming = None
5443
5445
5444 def getoutgoing():
5446 def getoutgoing():
5445 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5447 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5446 dbranch = branches[0]
5448 dbranch = branches[0]
5447 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5449 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5448 if source != dest:
5450 if source != dest:
5449 try:
5451 try:
5450 dother = hg.peer(repo, {}, dest)
5452 dother = hg.peer(repo, {}, dest)
5451 except error.RepoError:
5453 except error.RepoError:
5452 if opts.get('remote'):
5454 if opts.get('remote'):
5453 raise
5455 raise
5454 return dest, dbranch, None, None
5456 return dest, dbranch, None, None
5455 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5457 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5456 elif sother is None:
5458 elif sother is None:
5457 # there is no explicit destination peer, but source one is invalid
5459 # there is no explicit destination peer, but source one is invalid
5458 return dest, dbranch, None, None
5460 return dest, dbranch, None, None
5459 else:
5461 else:
5460 dother = sother
5462 dother = sother
5461 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5463 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5462 common = None
5464 common = None
5463 else:
5465 else:
5464 common = commoninc
5466 common = commoninc
5465 if revs:
5467 if revs:
5466 revs = [repo.lookup(rev) for rev in revs]
5468 revs = [repo.lookup(rev) for rev in revs]
5467 repo.ui.pushbuffer()
5469 repo.ui.pushbuffer()
5468 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5470 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5469 commoninc=common)
5471 commoninc=common)
5470 repo.ui.popbuffer()
5472 repo.ui.popbuffer()
5471 return dest, dbranch, dother, outgoing
5473 return dest, dbranch, dother, outgoing
5472
5474
5473 if needsoutgoing:
5475 if needsoutgoing:
5474 dest, dbranch, dother, outgoing = getoutgoing()
5476 dest, dbranch, dother, outgoing = getoutgoing()
5475 else:
5477 else:
5476 dest = dbranch = dother = outgoing = None
5478 dest = dbranch = dother = outgoing = None
5477
5479
5478 if opts.get('remote'):
5480 if opts.get('remote'):
5479 t = []
5481 t = []
5480 if incoming:
5482 if incoming:
5481 t.append(_('1 or more incoming'))
5483 t.append(_('1 or more incoming'))
5482 o = outgoing.missing
5484 o = outgoing.missing
5483 if o:
5485 if o:
5484 t.append(_('%d outgoing') % len(o))
5486 t.append(_('%d outgoing') % len(o))
5485 other = dother or sother
5487 other = dother or sother
5486 if 'bookmarks' in other.listkeys('namespaces'):
5488 if 'bookmarks' in other.listkeys('namespaces'):
5487 counts = bookmarks.summary(repo, other)
5489 counts = bookmarks.summary(repo, other)
5488 if counts[0] > 0:
5490 if counts[0] > 0:
5489 t.append(_('%d incoming bookmarks') % counts[0])
5491 t.append(_('%d incoming bookmarks') % counts[0])
5490 if counts[1] > 0:
5492 if counts[1] > 0:
5491 t.append(_('%d outgoing bookmarks') % counts[1])
5493 t.append(_('%d outgoing bookmarks') % counts[1])
5492
5494
5493 if t:
5495 if t:
5494 # i18n: column positioning for "hg summary"
5496 # i18n: column positioning for "hg summary"
5495 ui.write(_('remote: %s\n') % (', '.join(t)))
5497 ui.write(_('remote: %s\n') % (', '.join(t)))
5496 else:
5498 else:
5497 # i18n: column positioning for "hg summary"
5499 # i18n: column positioning for "hg summary"
5498 ui.status(_('remote: (synced)\n'))
5500 ui.status(_('remote: (synced)\n'))
5499
5501
5500 cmdutil.summaryremotehooks(ui, repo, opts,
5502 cmdutil.summaryremotehooks(ui, repo, opts,
5501 ((source, sbranch, sother, commoninc),
5503 ((source, sbranch, sother, commoninc),
5502 (dest, dbranch, dother, outgoing)))
5504 (dest, dbranch, dother, outgoing)))
5503
5505
5504 @command('tag',
5506 @command('tag',
5505 [('f', 'force', None, _('force tag')),
5507 [('f', 'force', None, _('force tag')),
5506 ('l', 'local', None, _('make the tag local')),
5508 ('l', 'local', None, _('make the tag local')),
5507 ('r', 'rev', '', _('revision to tag'), _('REV')),
5509 ('r', 'rev', '', _('revision to tag'), _('REV')),
5508 ('', 'remove', None, _('remove a tag')),
5510 ('', 'remove', None, _('remove a tag')),
5509 # -l/--local is already there, commitopts cannot be used
5511 # -l/--local is already there, commitopts cannot be used
5510 ('e', 'edit', None, _('invoke editor on commit messages')),
5512 ('e', 'edit', None, _('invoke editor on commit messages')),
5511 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5513 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5512 ] + commitopts2,
5514 ] + commitopts2,
5513 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5515 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5514 def tag(ui, repo, name1, *names, **opts):
5516 def tag(ui, repo, name1, *names, **opts):
5515 """add one or more tags for the current or given revision
5517 """add one or more tags for the current or given revision
5516
5518
5517 Name a particular revision using <name>.
5519 Name a particular revision using <name>.
5518
5520
5519 Tags are used to name particular revisions of the repository and are
5521 Tags are used to name particular revisions of the repository and are
5520 very useful to compare different revisions, to go back to significant
5522 very useful to compare different revisions, to go back to significant
5521 earlier versions or to mark branch points as releases, etc. Changing
5523 earlier versions or to mark branch points as releases, etc. Changing
5522 an existing tag is normally disallowed; use -f/--force to override.
5524 an existing tag is normally disallowed; use -f/--force to override.
5523
5525
5524 If no revision is given, the parent of the working directory is
5526 If no revision is given, the parent of the working directory is
5525 used.
5527 used.
5526
5528
5527 To facilitate version control, distribution, and merging of tags,
5529 To facilitate version control, distribution, and merging of tags,
5528 they are stored as a file named ".hgtags" which is managed similarly
5530 they are stored as a file named ".hgtags" which is managed similarly
5529 to other project files and can be hand-edited if necessary. This
5531 to other project files and can be hand-edited if necessary. This
5530 also means that tagging creates a new commit. The file
5532 also means that tagging creates a new commit. The file
5531 ".hg/localtags" is used for local tags (not shared among
5533 ".hg/localtags" is used for local tags (not shared among
5532 repositories).
5534 repositories).
5533
5535
5534 Tag commits are usually made at the head of a branch. If the parent
5536 Tag commits are usually made at the head of a branch. If the parent
5535 of the working directory is not a branch head, :hg:`tag` aborts; use
5537 of the working directory is not a branch head, :hg:`tag` aborts; use
5536 -f/--force to force the tag commit to be based on a non-head
5538 -f/--force to force the tag commit to be based on a non-head
5537 changeset.
5539 changeset.
5538
5540
5539 See :hg:`help dates` for a list of formats valid for -d/--date.
5541 See :hg:`help dates` for a list of formats valid for -d/--date.
5540
5542
5541 Since tag names have priority over branch names during revision
5543 Since tag names have priority over branch names during revision
5542 lookup, using an existing branch name as a tag name is discouraged.
5544 lookup, using an existing branch name as a tag name is discouraged.
5543
5545
5544 Returns 0 on success.
5546 Returns 0 on success.
5545 """
5547 """
5546 opts = pycompat.byteskwargs(opts)
5548 opts = pycompat.byteskwargs(opts)
5547 with repo.wlock(), repo.lock():
5549 with repo.wlock(), repo.lock():
5548 rev_ = "."
5550 rev_ = "."
5549 names = [t.strip() for t in (name1,) + names]
5551 names = [t.strip() for t in (name1,) + names]
5550 if len(names) != len(set(names)):
5552 if len(names) != len(set(names)):
5551 raise error.Abort(_('tag names must be unique'))
5553 raise error.Abort(_('tag names must be unique'))
5552 for n in names:
5554 for n in names:
5553 scmutil.checknewlabel(repo, n, 'tag')
5555 scmutil.checknewlabel(repo, n, 'tag')
5554 if not n:
5556 if not n:
5555 raise error.Abort(_('tag names cannot consist entirely of '
5557 raise error.Abort(_('tag names cannot consist entirely of '
5556 'whitespace'))
5558 'whitespace'))
5557 if opts.get('rev') and opts.get('remove'):
5559 if opts.get('rev') and opts.get('remove'):
5558 raise error.Abort(_("--rev and --remove are incompatible"))
5560 raise error.Abort(_("--rev and --remove are incompatible"))
5559 if opts.get('rev'):
5561 if opts.get('rev'):
5560 rev_ = opts['rev']
5562 rev_ = opts['rev']
5561 message = opts.get('message')
5563 message = opts.get('message')
5562 if opts.get('remove'):
5564 if opts.get('remove'):
5563 if opts.get('local'):
5565 if opts.get('local'):
5564 expectedtype = 'local'
5566 expectedtype = 'local'
5565 else:
5567 else:
5566 expectedtype = 'global'
5568 expectedtype = 'global'
5567
5569
5568 for n in names:
5570 for n in names:
5569 if not repo.tagtype(n):
5571 if not repo.tagtype(n):
5570 raise error.Abort(_("tag '%s' does not exist") % n)
5572 raise error.Abort(_("tag '%s' does not exist") % n)
5571 if repo.tagtype(n) != expectedtype:
5573 if repo.tagtype(n) != expectedtype:
5572 if expectedtype == 'global':
5574 if expectedtype == 'global':
5573 raise error.Abort(_("tag '%s' is not a global tag") % n)
5575 raise error.Abort(_("tag '%s' is not a global tag") % n)
5574 else:
5576 else:
5575 raise error.Abort(_("tag '%s' is not a local tag") % n)
5577 raise error.Abort(_("tag '%s' is not a local tag") % n)
5576 rev_ = 'null'
5578 rev_ = 'null'
5577 if not message:
5579 if not message:
5578 # we don't translate commit messages
5580 # we don't translate commit messages
5579 message = 'Removed tag %s' % ', '.join(names)
5581 message = 'Removed tag %s' % ', '.join(names)
5580 elif not opts.get('force'):
5582 elif not opts.get('force'):
5581 for n in names:
5583 for n in names:
5582 if n in repo.tags():
5584 if n in repo.tags():
5583 raise error.Abort(_("tag '%s' already exists "
5585 raise error.Abort(_("tag '%s' already exists "
5584 "(use -f to force)") % n)
5586 "(use -f to force)") % n)
5585 if not opts.get('local'):
5587 if not opts.get('local'):
5586 p1, p2 = repo.dirstate.parents()
5588 p1, p2 = repo.dirstate.parents()
5587 if p2 != nullid:
5589 if p2 != nullid:
5588 raise error.Abort(_('uncommitted merge'))
5590 raise error.Abort(_('uncommitted merge'))
5589 bheads = repo.branchheads()
5591 bheads = repo.branchheads()
5590 if not opts.get('force') and bheads and p1 not in bheads:
5592 if not opts.get('force') and bheads and p1 not in bheads:
5591 raise error.Abort(_('working directory is not at a branch head '
5593 raise error.Abort(_('working directory is not at a branch head '
5592 '(use -f to force)'))
5594 '(use -f to force)'))
5593 node = scmutil.revsingle(repo, rev_).node()
5595 node = scmutil.revsingle(repo, rev_).node()
5594
5596
5595 if not message:
5597 if not message:
5596 # we don't translate commit messages
5598 # we don't translate commit messages
5597 message = ('Added tag %s for changeset %s' %
5599 message = ('Added tag %s for changeset %s' %
5598 (', '.join(names), short(node)))
5600 (', '.join(names), short(node)))
5599
5601
5600 date = opts.get('date')
5602 date = opts.get('date')
5601 if date:
5603 if date:
5602 date = dateutil.parsedate(date)
5604 date = dateutil.parsedate(date)
5603
5605
5604 if opts.get('remove'):
5606 if opts.get('remove'):
5605 editform = 'tag.remove'
5607 editform = 'tag.remove'
5606 else:
5608 else:
5607 editform = 'tag.add'
5609 editform = 'tag.add'
5608 editor = cmdutil.getcommiteditor(editform=editform,
5610 editor = cmdutil.getcommiteditor(editform=editform,
5609 **pycompat.strkwargs(opts))
5611 **pycompat.strkwargs(opts))
5610
5612
5611 # don't allow tagging the null rev
5613 # don't allow tagging the null rev
5612 if (not opts.get('remove') and
5614 if (not opts.get('remove') and
5613 scmutil.revsingle(repo, rev_).rev() == nullrev):
5615 scmutil.revsingle(repo, rev_).rev() == nullrev):
5614 raise error.Abort(_("cannot tag null revision"))
5616 raise error.Abort(_("cannot tag null revision"))
5615
5617
5616 tagsmod.tag(repo, names, node, message, opts.get('local'),
5618 tagsmod.tag(repo, names, node, message, opts.get('local'),
5617 opts.get('user'), date, editor=editor)
5619 opts.get('user'), date, editor=editor)
5618
5620
5619 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5621 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5620 def tags(ui, repo, **opts):
5622 def tags(ui, repo, **opts):
5621 """list repository tags
5623 """list repository tags
5622
5624
5623 This lists both regular and local tags. When the -v/--verbose
5625 This lists both regular and local tags. When the -v/--verbose
5624 switch is used, a third column "local" is printed for local tags.
5626 switch is used, a third column "local" is printed for local tags.
5625 When the -q/--quiet switch is used, only the tag name is printed.
5627 When the -q/--quiet switch is used, only the tag name is printed.
5626
5628
5627 Returns 0 on success.
5629 Returns 0 on success.
5628 """
5630 """
5629
5631
5630 opts = pycompat.byteskwargs(opts)
5632 opts = pycompat.byteskwargs(opts)
5631 ui.pager('tags')
5633 ui.pager('tags')
5632 fm = ui.formatter('tags', opts)
5634 fm = ui.formatter('tags', opts)
5633 hexfunc = fm.hexfunc
5635 hexfunc = fm.hexfunc
5634 tagtype = ""
5636 tagtype = ""
5635
5637
5636 for t, n in reversed(repo.tagslist()):
5638 for t, n in reversed(repo.tagslist()):
5637 hn = hexfunc(n)
5639 hn = hexfunc(n)
5638 label = 'tags.normal'
5640 label = 'tags.normal'
5639 tagtype = ''
5641 tagtype = ''
5640 if repo.tagtype(t) == 'local':
5642 if repo.tagtype(t) == 'local':
5641 label = 'tags.local'
5643 label = 'tags.local'
5642 tagtype = 'local'
5644 tagtype = 'local'
5643
5645
5644 fm.startitem()
5646 fm.startitem()
5645 fm.context(repo=repo)
5647 fm.context(repo=repo)
5646 fm.write('tag', '%s', t, label=label)
5648 fm.write('tag', '%s', t, label=label)
5647 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5649 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5648 fm.condwrite(not ui.quiet, 'rev node', fmt,
5650 fm.condwrite(not ui.quiet, 'rev node', fmt,
5649 repo.changelog.rev(n), hn, label=label)
5651 repo.changelog.rev(n), hn, label=label)
5650 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5652 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5651 tagtype, label=label)
5653 tagtype, label=label)
5652 fm.plain('\n')
5654 fm.plain('\n')
5653 fm.end()
5655 fm.end()
5654
5656
5655 @command('tip',
5657 @command('tip',
5656 [('p', 'patch', None, _('show patch')),
5658 [('p', 'patch', None, _('show patch')),
5657 ('g', 'git', None, _('use git extended diff format')),
5659 ('g', 'git', None, _('use git extended diff format')),
5658 ] + templateopts,
5660 ] + templateopts,
5659 _('[-p] [-g]'))
5661 _('[-p] [-g]'))
5660 def tip(ui, repo, **opts):
5662 def tip(ui, repo, **opts):
5661 """show the tip revision (DEPRECATED)
5663 """show the tip revision (DEPRECATED)
5662
5664
5663 The tip revision (usually just called the tip) is the changeset
5665 The tip revision (usually just called the tip) is the changeset
5664 most recently added to the repository (and therefore the most
5666 most recently added to the repository (and therefore the most
5665 recently changed head).
5667 recently changed head).
5666
5668
5667 If you have just made a commit, that commit will be the tip. If
5669 If you have just made a commit, that commit will be the tip. If
5668 you have just pulled changes from another repository, the tip of
5670 you have just pulled changes from another repository, the tip of
5669 that repository becomes the current tip. The "tip" tag is special
5671 that repository becomes the current tip. The "tip" tag is special
5670 and cannot be renamed or assigned to a different changeset.
5672 and cannot be renamed or assigned to a different changeset.
5671
5673
5672 This command is deprecated, please use :hg:`heads` instead.
5674 This command is deprecated, please use :hg:`heads` instead.
5673
5675
5674 Returns 0 on success.
5676 Returns 0 on success.
5675 """
5677 """
5676 opts = pycompat.byteskwargs(opts)
5678 opts = pycompat.byteskwargs(opts)
5677 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5678 displayer.show(repo['tip'])
5680 displayer.show(repo['tip'])
5679 displayer.close()
5681 displayer.close()
5680
5682
5681 @command('unbundle',
5683 @command('unbundle',
5682 [('u', 'update', None,
5684 [('u', 'update', None,
5683 _('update to new branch head if changesets were unbundled'))],
5685 _('update to new branch head if changesets were unbundled'))],
5684 _('[-u] FILE...'))
5686 _('[-u] FILE...'))
5685 def unbundle(ui, repo, fname1, *fnames, **opts):
5687 def unbundle(ui, repo, fname1, *fnames, **opts):
5686 """apply one or more bundle files
5688 """apply one or more bundle files
5687
5689
5688 Apply one or more bundle files generated by :hg:`bundle`.
5690 Apply one or more bundle files generated by :hg:`bundle`.
5689
5691
5690 Returns 0 on success, 1 if an update has unresolved files.
5692 Returns 0 on success, 1 if an update has unresolved files.
5691 """
5693 """
5692 fnames = (fname1,) + fnames
5694 fnames = (fname1,) + fnames
5693
5695
5694 with repo.lock():
5696 with repo.lock():
5695 for fname in fnames:
5697 for fname in fnames:
5696 f = hg.openpath(ui, fname)
5698 f = hg.openpath(ui, fname)
5697 gen = exchange.readbundle(ui, f, fname)
5699 gen = exchange.readbundle(ui, f, fname)
5698 if isinstance(gen, streamclone.streamcloneapplier):
5700 if isinstance(gen, streamclone.streamcloneapplier):
5699 raise error.Abort(
5701 raise error.Abort(
5700 _('packed bundles cannot be applied with '
5702 _('packed bundles cannot be applied with '
5701 '"hg unbundle"'),
5703 '"hg unbundle"'),
5702 hint=_('use "hg debugapplystreamclonebundle"'))
5704 hint=_('use "hg debugapplystreamclonebundle"'))
5703 url = 'bundle:' + fname
5705 url = 'bundle:' + fname
5704 try:
5706 try:
5705 txnname = 'unbundle'
5707 txnname = 'unbundle'
5706 if not isinstance(gen, bundle2.unbundle20):
5708 if not isinstance(gen, bundle2.unbundle20):
5707 txnname = 'unbundle\n%s' % util.hidepassword(url)
5709 txnname = 'unbundle\n%s' % util.hidepassword(url)
5708 with repo.transaction(txnname) as tr:
5710 with repo.transaction(txnname) as tr:
5709 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5711 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5710 url=url)
5712 url=url)
5711 except error.BundleUnknownFeatureError as exc:
5713 except error.BundleUnknownFeatureError as exc:
5712 raise error.Abort(
5714 raise error.Abort(
5713 _('%s: unknown bundle feature, %s') % (fname, exc),
5715 _('%s: unknown bundle feature, %s') % (fname, exc),
5714 hint=_("see https://mercurial-scm.org/"
5716 hint=_("see https://mercurial-scm.org/"
5715 "wiki/BundleFeature for more "
5717 "wiki/BundleFeature for more "
5716 "information"))
5718 "information"))
5717 modheads = bundle2.combinechangegroupresults(op)
5719 modheads = bundle2.combinechangegroupresults(op)
5718
5720
5719 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5721 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5720
5722
5721 @command('^update|up|checkout|co',
5723 @command('^update|up|checkout|co',
5722 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5724 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5723 ('c', 'check', None, _('require clean working directory')),
5725 ('c', 'check', None, _('require clean working directory')),
5724 ('m', 'merge', None, _('merge uncommitted changes')),
5726 ('m', 'merge', None, _('merge uncommitted changes')),
5725 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5727 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5726 ('r', 'rev', '', _('revision'), _('REV'))
5728 ('r', 'rev', '', _('revision'), _('REV'))
5727 ] + mergetoolopts,
5729 ] + mergetoolopts,
5728 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5730 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5729 def update(ui, repo, node=None, **opts):
5731 def update(ui, repo, node=None, **opts):
5730 """update working directory (or switch revisions)
5732 """update working directory (or switch revisions)
5731
5733
5732 Update the repository's working directory to the specified
5734 Update the repository's working directory to the specified
5733 changeset. If no changeset is specified, update to the tip of the
5735 changeset. If no changeset is specified, update to the tip of the
5734 current named branch and move the active bookmark (see :hg:`help
5736 current named branch and move the active bookmark (see :hg:`help
5735 bookmarks`).
5737 bookmarks`).
5736
5738
5737 Update sets the working directory's parent revision to the specified
5739 Update sets the working directory's parent revision to the specified
5738 changeset (see :hg:`help parents`).
5740 changeset (see :hg:`help parents`).
5739
5741
5740 If the changeset is not a descendant or ancestor of the working
5742 If the changeset is not a descendant or ancestor of the working
5741 directory's parent and there are uncommitted changes, the update is
5743 directory's parent and there are uncommitted changes, the update is
5742 aborted. With the -c/--check option, the working directory is checked
5744 aborted. With the -c/--check option, the working directory is checked
5743 for uncommitted changes; if none are found, the working directory is
5745 for uncommitted changes; if none are found, the working directory is
5744 updated to the specified changeset.
5746 updated to the specified changeset.
5745
5747
5746 .. container:: verbose
5748 .. container:: verbose
5747
5749
5748 The -C/--clean, -c/--check, and -m/--merge options control what
5750 The -C/--clean, -c/--check, and -m/--merge options control what
5749 happens if the working directory contains uncommitted changes.
5751 happens if the working directory contains uncommitted changes.
5750 At most of one of them can be specified.
5752 At most of one of them can be specified.
5751
5753
5752 1. If no option is specified, and if
5754 1. If no option is specified, and if
5753 the requested changeset is an ancestor or descendant of
5755 the requested changeset is an ancestor or descendant of
5754 the working directory's parent, the uncommitted changes
5756 the working directory's parent, the uncommitted changes
5755 are merged into the requested changeset and the merged
5757 are merged into the requested changeset and the merged
5756 result is left uncommitted. If the requested changeset is
5758 result is left uncommitted. If the requested changeset is
5757 not an ancestor or descendant (that is, it is on another
5759 not an ancestor or descendant (that is, it is on another
5758 branch), the update is aborted and the uncommitted changes
5760 branch), the update is aborted and the uncommitted changes
5759 are preserved.
5761 are preserved.
5760
5762
5761 2. With the -m/--merge option, the update is allowed even if the
5763 2. With the -m/--merge option, the update is allowed even if the
5762 requested changeset is not an ancestor or descendant of
5764 requested changeset is not an ancestor or descendant of
5763 the working directory's parent.
5765 the working directory's parent.
5764
5766
5765 3. With the -c/--check option, the update is aborted and the
5767 3. With the -c/--check option, the update is aborted and the
5766 uncommitted changes are preserved.
5768 uncommitted changes are preserved.
5767
5769
5768 4. With the -C/--clean option, uncommitted changes are discarded and
5770 4. With the -C/--clean option, uncommitted changes are discarded and
5769 the working directory is updated to the requested changeset.
5771 the working directory is updated to the requested changeset.
5770
5772
5771 To cancel an uncommitted merge (and lose your changes), use
5773 To cancel an uncommitted merge (and lose your changes), use
5772 :hg:`merge --abort`.
5774 :hg:`merge --abort`.
5773
5775
5774 Use null as the changeset to remove the working directory (like
5776 Use null as the changeset to remove the working directory (like
5775 :hg:`clone -U`).
5777 :hg:`clone -U`).
5776
5778
5777 If you want to revert just one file to an older revision, use
5779 If you want to revert just one file to an older revision, use
5778 :hg:`revert [-r REV] NAME`.
5780 :hg:`revert [-r REV] NAME`.
5779
5781
5780 See :hg:`help dates` for a list of formats valid for -d/--date.
5782 See :hg:`help dates` for a list of formats valid for -d/--date.
5781
5783
5782 Returns 0 on success, 1 if there are unresolved files.
5784 Returns 0 on success, 1 if there are unresolved files.
5783 """
5785 """
5784 rev = opts.get(r'rev')
5786 rev = opts.get(r'rev')
5785 date = opts.get(r'date')
5787 date = opts.get(r'date')
5786 clean = opts.get(r'clean')
5788 clean = opts.get(r'clean')
5787 check = opts.get(r'check')
5789 check = opts.get(r'check')
5788 merge = opts.get(r'merge')
5790 merge = opts.get(r'merge')
5789 if rev and node:
5791 if rev and node:
5790 raise error.Abort(_("please specify just one revision"))
5792 raise error.Abort(_("please specify just one revision"))
5791
5793
5792 if ui.configbool('commands', 'update.requiredest'):
5794 if ui.configbool('commands', 'update.requiredest'):
5793 if not node and not rev and not date:
5795 if not node and not rev and not date:
5794 raise error.Abort(_('you must specify a destination'),
5796 raise error.Abort(_('you must specify a destination'),
5795 hint=_('for example: hg update ".::"'))
5797 hint=_('for example: hg update ".::"'))
5796
5798
5797 if rev is None or rev == '':
5799 if rev is None or rev == '':
5798 rev = node
5800 rev = node
5799
5801
5800 if date and rev is not None:
5802 if date and rev is not None:
5801 raise error.Abort(_("you can't specify a revision and a date"))
5803 raise error.Abort(_("you can't specify a revision and a date"))
5802
5804
5803 if len([x for x in (clean, check, merge) if x]) > 1:
5805 if len([x for x in (clean, check, merge) if x]) > 1:
5804 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5806 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5805 "or -m/--merge"))
5807 "or -m/--merge"))
5806
5808
5807 updatecheck = None
5809 updatecheck = None
5808 if check:
5810 if check:
5809 updatecheck = 'abort'
5811 updatecheck = 'abort'
5810 elif merge:
5812 elif merge:
5811 updatecheck = 'none'
5813 updatecheck = 'none'
5812
5814
5813 with repo.wlock():
5815 with repo.wlock():
5814 cmdutil.clearunfinished(repo)
5816 cmdutil.clearunfinished(repo)
5815
5817
5816 if date:
5818 if date:
5817 rev = cmdutil.finddate(ui, repo, date)
5819 rev = cmdutil.finddate(ui, repo, date)
5818
5820
5819 # if we defined a bookmark, we have to remember the original name
5821 # if we defined a bookmark, we have to remember the original name
5820 brev = rev
5822 brev = rev
5821 if rev:
5823 if rev:
5822 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5824 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5823 ctx = scmutil.revsingle(repo, rev, rev)
5825 ctx = scmutil.revsingle(repo, rev, rev)
5824 rev = ctx.rev()
5826 rev = ctx.rev()
5825 hidden = ctx.hidden()
5827 hidden = ctx.hidden()
5826 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5828 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5827 with ui.configoverride(overrides, 'update'):
5829 with ui.configoverride(overrides, 'update'):
5828 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5830 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5829 updatecheck=updatecheck)
5831 updatecheck=updatecheck)
5830 if hidden:
5832 if hidden:
5831 ctxstr = ctx.hex()[:12]
5833 ctxstr = ctx.hex()[:12]
5832 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5834 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5833
5835
5834 if ctx.obsolete():
5836 if ctx.obsolete():
5835 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5837 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5836 ui.warn("(%s)\n" % obsfatemsg)
5838 ui.warn("(%s)\n" % obsfatemsg)
5837 return ret
5839 return ret
5838
5840
5839 @command('verify', [])
5841 @command('verify', [])
5840 def verify(ui, repo):
5842 def verify(ui, repo):
5841 """verify the integrity of the repository
5843 """verify the integrity of the repository
5842
5844
5843 Verify the integrity of the current repository.
5845 Verify the integrity of the current repository.
5844
5846
5845 This will perform an extensive check of the repository's
5847 This will perform an extensive check of the repository's
5846 integrity, validating the hashes and checksums of each entry in
5848 integrity, validating the hashes and checksums of each entry in
5847 the changelog, manifest, and tracked files, as well as the
5849 the changelog, manifest, and tracked files, as well as the
5848 integrity of their crosslinks and indices.
5850 integrity of their crosslinks and indices.
5849
5851
5850 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5852 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5851 for more information about recovery from corruption of the
5853 for more information about recovery from corruption of the
5852 repository.
5854 repository.
5853
5855
5854 Returns 0 on success, 1 if errors are encountered.
5856 Returns 0 on success, 1 if errors are encountered.
5855 """
5857 """
5856 return hg.verify(repo)
5858 return hg.verify(repo)
5857
5859
5858 @command('version', [] + formatteropts, norepo=True,
5860 @command('version', [] + formatteropts, norepo=True,
5859 intents={INTENT_READONLY})
5861 intents={INTENT_READONLY})
5860 def version_(ui, **opts):
5862 def version_(ui, **opts):
5861 """output version and copyright information"""
5863 """output version and copyright information"""
5862 opts = pycompat.byteskwargs(opts)
5864 opts = pycompat.byteskwargs(opts)
5863 if ui.verbose:
5865 if ui.verbose:
5864 ui.pager('version')
5866 ui.pager('version')
5865 fm = ui.formatter("version", opts)
5867 fm = ui.formatter("version", opts)
5866 fm.startitem()
5868 fm.startitem()
5867 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5869 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5868 util.version())
5870 util.version())
5869 license = _(
5871 license = _(
5870 "(see https://mercurial-scm.org for more information)\n"
5872 "(see https://mercurial-scm.org for more information)\n"
5871 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5873 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5872 "This is free software; see the source for copying conditions. "
5874 "This is free software; see the source for copying conditions. "
5873 "There is NO\nwarranty; "
5875 "There is NO\nwarranty; "
5874 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5876 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5875 )
5877 )
5876 if not ui.quiet:
5878 if not ui.quiet:
5877 fm.plain(license)
5879 fm.plain(license)
5878
5880
5879 if ui.verbose:
5881 if ui.verbose:
5880 fm.plain(_("\nEnabled extensions:\n\n"))
5882 fm.plain(_("\nEnabled extensions:\n\n"))
5881 # format names and versions into columns
5883 # format names and versions into columns
5882 names = []
5884 names = []
5883 vers = []
5885 vers = []
5884 isinternals = []
5886 isinternals = []
5885 for name, module in extensions.extensions():
5887 for name, module in extensions.extensions():
5886 names.append(name)
5888 names.append(name)
5887 vers.append(extensions.moduleversion(module) or None)
5889 vers.append(extensions.moduleversion(module) or None)
5888 isinternals.append(extensions.ismoduleinternal(module))
5890 isinternals.append(extensions.ismoduleinternal(module))
5889 fn = fm.nested("extensions", tmpl='{name}\n')
5891 fn = fm.nested("extensions", tmpl='{name}\n')
5890 if names:
5892 if names:
5891 namefmt = " %%-%ds " % max(len(n) for n in names)
5893 namefmt = " %%-%ds " % max(len(n) for n in names)
5892 places = [_("external"), _("internal")]
5894 places = [_("external"), _("internal")]
5893 for n, v, p in zip(names, vers, isinternals):
5895 for n, v, p in zip(names, vers, isinternals):
5894 fn.startitem()
5896 fn.startitem()
5895 fn.condwrite(ui.verbose, "name", namefmt, n)
5897 fn.condwrite(ui.verbose, "name", namefmt, n)
5896 if ui.verbose:
5898 if ui.verbose:
5897 fn.plain("%s " % places[p])
5899 fn.plain("%s " % places[p])
5898 fn.data(bundled=p)
5900 fn.data(bundled=p)
5899 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5901 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5900 if ui.verbose:
5902 if ui.verbose:
5901 fn.plain("\n")
5903 fn.plain("\n")
5902 fn.end()
5904 fn.end()
5903 fm.end()
5905 fm.end()
5904
5906
5905 def loadcmdtable(ui, name, cmdtable):
5907 def loadcmdtable(ui, name, cmdtable):
5906 """Load command functions from specified cmdtable
5908 """Load command functions from specified cmdtable
5907 """
5909 """
5908 overrides = [cmd for cmd in cmdtable if cmd in table]
5910 overrides = [cmd for cmd in cmdtable if cmd in table]
5909 if overrides:
5911 if overrides:
5910 ui.warn(_("extension '%s' overrides commands: %s\n")
5912 ui.warn(_("extension '%s' overrides commands: %s\n")
5911 % (name, " ".join(overrides)))
5913 % (name, " ".join(overrides)))
5912 table.update(cmdtable)
5914 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now