##// END OF EJS Templates
identify: only query remote bookmarks if needed...
Valentin Gatien-Baron -
r40025:c9026e92 default
parent child Browse files
Show More
@@ -1,5924 +1,5925
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 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 copies,
31 copies,
32 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 discovery,
35 discovery,
36 encoding,
36 encoding,
37 error,
37 error,
38 exchange,
38 exchange,
39 extensions,
39 extensions,
40 filemerge,
40 filemerge,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 match as matchmod,
47 match as matchmod,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 repair,
57 repair,
58 revsetlang,
58 revsetlang,
59 rewriteutil,
59 rewriteutil,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 templatekw,
65 templatekw,
66 ui as uimod,
66 ui as uimod,
67 util,
67 util,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 ('R', 'repository', '',
84 ('R', 'repository', '',
85 _('repository root directory or name of overlay bundle file'),
85 _('repository root directory or name of overlay bundle file'),
86 _('REPO')),
86 _('REPO')),
87 ('', 'cwd', '',
87 ('', 'cwd', '',
88 _('change working directory'), _('DIR')),
88 _('change working directory'), _('DIR')),
89 ('y', 'noninteractive', None,
89 ('y', 'noninteractive', None,
90 _('do not prompt, automatically pick the first choice for all prompts')),
90 _('do not prompt, automatically pick the first choice for all prompts')),
91 ('q', 'quiet', None, _('suppress output')),
91 ('q', 'quiet', None, _('suppress output')),
92 ('v', 'verbose', None, _('enable additional output')),
92 ('v', 'verbose', None, _('enable additional output')),
93 ('', 'color', '',
93 ('', 'color', '',
94 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
95 # and should not be translated
95 # and should not be translated
96 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _("when to colorize (boolean, always, auto, never, or debug)"),
97 _('TYPE')),
97 _('TYPE')),
98 ('', 'config', [],
98 ('', 'config', [],
99 _('set/override config option (use \'section.name=value\')'),
99 _('set/override config option (use \'section.name=value\')'),
100 _('CONFIG')),
100 _('CONFIG')),
101 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debug', None, _('enable debugging output')),
102 ('', 'debugger', None, _('start debugger')),
102 ('', 'debugger', None, _('start debugger')),
103 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
104 _('ENCODE')),
104 _('ENCODE')),
105 ('', 'encodingmode', encoding.encodingmode,
105 ('', 'encodingmode', encoding.encodingmode,
106 _('set the charset encoding mode'), _('MODE')),
106 _('set the charset encoding mode'), _('MODE')),
107 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'traceback', None, _('always print a traceback on exception')),
108 ('', 'time', None, _('time how long the command takes')),
108 ('', 'time', None, _('time how long the command takes')),
109 ('', 'profile', None, _('print command execution profile')),
109 ('', 'profile', None, _('print command execution profile')),
110 ('', 'version', None, _('output version information and exit')),
110 ('', 'version', None, _('output version information and exit')),
111 ('h', 'help', None, _('display help and exit')),
111 ('h', 'help', None, _('display help and exit')),
112 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'hidden', False, _('consider hidden changesets')),
113 ('', 'pager', 'auto',
113 ('', 'pager', 'auto',
114 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
115 ]
115 ]
116
116
117 dryrunopts = cmdutil.dryrunopts
117 dryrunopts = cmdutil.dryrunopts
118 remoteopts = cmdutil.remoteopts
118 remoteopts = cmdutil.remoteopts
119 walkopts = cmdutil.walkopts
119 walkopts = cmdutil.walkopts
120 commitopts = cmdutil.commitopts
120 commitopts = cmdutil.commitopts
121 commitopts2 = cmdutil.commitopts2
121 commitopts2 = cmdutil.commitopts2
122 formatteropts = cmdutil.formatteropts
122 formatteropts = cmdutil.formatteropts
123 templateopts = cmdutil.templateopts
123 templateopts = cmdutil.templateopts
124 logopts = cmdutil.logopts
124 logopts = cmdutil.logopts
125 diffopts = cmdutil.diffopts
125 diffopts = cmdutil.diffopts
126 diffwsopts = cmdutil.diffwsopts
126 diffwsopts = cmdutil.diffwsopts
127 diffopts2 = cmdutil.diffopts2
127 diffopts2 = cmdutil.diffopts2
128 mergetoolopts = cmdutil.mergetoolopts
128 mergetoolopts = cmdutil.mergetoolopts
129 similarityopts = cmdutil.similarityopts
129 similarityopts = cmdutil.similarityopts
130 subrepoopts = cmdutil.subrepoopts
130 subrepoopts = cmdutil.subrepoopts
131 debugrevlogopts = cmdutil.debugrevlogopts
131 debugrevlogopts = cmdutil.debugrevlogopts
132
132
133 # Commands start here, listed alphabetically
133 # Commands start here, listed alphabetically
134
134
135 @command('^add',
135 @command('^add',
136 walkopts + subrepoopts + dryrunopts,
136 walkopts + subrepoopts + dryrunopts,
137 _('[OPTION]... [FILE]...'),
137 _('[OPTION]... [FILE]...'),
138 inferrepo=True)
138 inferrepo=True)
139 def add(ui, repo, *pats, **opts):
139 def add(ui, repo, *pats, **opts):
140 """add the specified files on the next commit
140 """add the specified files on the next commit
141
141
142 Schedule files to be version controlled and added to the
142 Schedule files to be version controlled and added to the
143 repository.
143 repository.
144
144
145 The files will be added to the repository at the next commit. To
145 The files will be added to the repository at the next commit. To
146 undo an add before that, see :hg:`forget`.
146 undo an add before that, see :hg:`forget`.
147
147
148 If no names are given, add all files to the repository (except
148 If no names are given, add all files to the repository (except
149 files matching ``.hgignore``).
149 files matching ``.hgignore``).
150
150
151 .. container:: verbose
151 .. container:: verbose
152
152
153 Examples:
153 Examples:
154
154
155 - New (unknown) files are added
155 - New (unknown) files are added
156 automatically by :hg:`add`::
156 automatically by :hg:`add`::
157
157
158 $ ls
158 $ ls
159 foo.c
159 foo.c
160 $ hg status
160 $ hg status
161 ? foo.c
161 ? foo.c
162 $ hg add
162 $ hg add
163 adding foo.c
163 adding foo.c
164 $ hg status
164 $ hg status
165 A foo.c
165 A foo.c
166
166
167 - Specific files to be added can be specified::
167 - Specific files to be added can be specified::
168
168
169 $ ls
169 $ ls
170 bar.c foo.c
170 bar.c foo.c
171 $ hg status
171 $ hg status
172 ? bar.c
172 ? bar.c
173 ? foo.c
173 ? foo.c
174 $ hg add bar.c
174 $ hg add bar.c
175 $ hg status
175 $ hg status
176 A bar.c
176 A bar.c
177 ? foo.c
177 ? foo.c
178
178
179 Returns 0 if all files are successfully added.
179 Returns 0 if all files are successfully added.
180 """
180 """
181
181
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
184 return rejected and 1 or 0
184 return rejected and 1 or 0
185
185
186 @command('addremove',
186 @command('addremove',
187 similarityopts + subrepoopts + walkopts + dryrunopts,
187 similarityopts + subrepoopts + walkopts + dryrunopts,
188 _('[OPTION]... [FILE]...'),
188 _('[OPTION]... [FILE]...'),
189 inferrepo=True)
189 inferrepo=True)
190 def addremove(ui, repo, *pats, **opts):
190 def addremove(ui, repo, *pats, **opts):
191 """add all new files, delete all missing files
191 """add all new files, delete all missing files
192
192
193 Add all new files and remove all missing files from the
193 Add all new files and remove all missing files from the
194 repository.
194 repository.
195
195
196 Unless names are given, new files are ignored if they match any of
196 Unless names are given, new files are ignored if they match any of
197 the patterns in ``.hgignore``. As with add, these changes take
197 the patterns in ``.hgignore``. As with add, these changes take
198 effect at the next commit.
198 effect at the next commit.
199
199
200 Use the -s/--similarity option to detect renamed files. This
200 Use the -s/--similarity option to detect renamed files. This
201 option takes a percentage between 0 (disabled) and 100 (files must
201 option takes a percentage between 0 (disabled) and 100 (files must
202 be identical) as its parameter. With a parameter greater than 0,
202 be identical) as its parameter. With a parameter greater than 0,
203 this compares every removed file with every added file and records
203 this compares every removed file with every added file and records
204 those similar enough as renames. Detecting renamed files this way
204 those similar enough as renames. Detecting renamed files this way
205 can be expensive. After using this option, :hg:`status -C` can be
205 can be expensive. After using this option, :hg:`status -C` can be
206 used to check which files were identified as moved or renamed. If
206 used to check which files were identified as moved or renamed. If
207 not specified, -s/--similarity defaults to 100 and only renames of
207 not specified, -s/--similarity defaults to 100 and only renames of
208 identical files are detected.
208 identical files are detected.
209
209
210 .. container:: verbose
210 .. container:: verbose
211
211
212 Examples:
212 Examples:
213
213
214 - A number of files (bar.c and foo.c) are new,
214 - A number of files (bar.c and foo.c) are new,
215 while foobar.c has been removed (without using :hg:`remove`)
215 while foobar.c has been removed (without using :hg:`remove`)
216 from the repository::
216 from the repository::
217
217
218 $ ls
218 $ ls
219 bar.c foo.c
219 bar.c foo.c
220 $ hg status
220 $ hg status
221 ! foobar.c
221 ! foobar.c
222 ? bar.c
222 ? bar.c
223 ? foo.c
223 ? foo.c
224 $ hg addremove
224 $ hg addremove
225 adding bar.c
225 adding bar.c
226 adding foo.c
226 adding foo.c
227 removing foobar.c
227 removing foobar.c
228 $ hg status
228 $ hg status
229 A bar.c
229 A bar.c
230 A foo.c
230 A foo.c
231 R foobar.c
231 R foobar.c
232
232
233 - A file foobar.c was moved to foo.c without using :hg:`rename`.
233 - A file foobar.c was moved to foo.c without using :hg:`rename`.
234 Afterwards, it was edited slightly::
234 Afterwards, it was edited slightly::
235
235
236 $ ls
236 $ ls
237 foo.c
237 foo.c
238 $ hg status
238 $ hg status
239 ! foobar.c
239 ! foobar.c
240 ? foo.c
240 ? foo.c
241 $ hg addremove --similarity 90
241 $ hg addremove --similarity 90
242 removing foobar.c
242 removing foobar.c
243 adding foo.c
243 adding foo.c
244 recording removal of foobar.c as rename to foo.c (94% similar)
244 recording removal of foobar.c as rename to foo.c (94% similar)
245 $ hg status -C
245 $ hg status -C
246 A foo.c
246 A foo.c
247 foobar.c
247 foobar.c
248 R foobar.c
248 R foobar.c
249
249
250 Returns 0 if all files are successfully added.
250 Returns 0 if all files are successfully added.
251 """
251 """
252 opts = pycompat.byteskwargs(opts)
252 opts = pycompat.byteskwargs(opts)
253 if not opts.get('similarity'):
253 if not opts.get('similarity'):
254 opts['similarity'] = '100'
254 opts['similarity'] = '100'
255 matcher = scmutil.match(repo[None], pats, opts)
255 matcher = scmutil.match(repo[None], pats, opts)
256 return scmutil.addremove(repo, matcher, "", opts)
256 return scmutil.addremove(repo, matcher, "", opts)
257
257
258 @command('^annotate|blame',
258 @command('^annotate|blame',
259 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
259 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
260 ('', 'follow', None,
260 ('', 'follow', None,
261 _('follow copies/renames and list the filename (DEPRECATED)')),
261 _('follow copies/renames and list the filename (DEPRECATED)')),
262 ('', 'no-follow', None, _("don't follow copies and renames")),
262 ('', 'no-follow', None, _("don't follow copies and renames")),
263 ('a', 'text', None, _('treat all files as text')),
263 ('a', 'text', None, _('treat all files as text')),
264 ('u', 'user', None, _('list the author (long with -v)')),
264 ('u', 'user', None, _('list the author (long with -v)')),
265 ('f', 'file', None, _('list the filename')),
265 ('f', 'file', None, _('list the filename')),
266 ('d', 'date', None, _('list the date (short with -q)')),
266 ('d', 'date', None, _('list the date (short with -q)')),
267 ('n', 'number', None, _('list the revision number (default)')),
267 ('n', 'number', None, _('list the revision number (default)')),
268 ('c', 'changeset', None, _('list the changeset')),
268 ('c', 'changeset', None, _('list the changeset')),
269 ('l', 'line-number', None, _('show line number at the first appearance')),
269 ('l', 'line-number', None, _('show line number at the first appearance')),
270 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
270 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
271 ] + diffwsopts + walkopts + formatteropts,
271 ] + diffwsopts + walkopts + formatteropts,
272 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
272 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
273 inferrepo=True)
273 inferrepo=True)
274 def annotate(ui, repo, *pats, **opts):
274 def annotate(ui, repo, *pats, **opts):
275 """show changeset information by line for each file
275 """show changeset information by line for each file
276
276
277 List changes in files, showing the revision id responsible for
277 List changes in files, showing the revision id responsible for
278 each line.
278 each line.
279
279
280 This command is useful for discovering when a change was made and
280 This command is useful for discovering when a change was made and
281 by whom.
281 by whom.
282
282
283 If you include --file, --user, or --date, the revision number is
283 If you include --file, --user, or --date, the revision number is
284 suppressed unless you also include --number.
284 suppressed unless you also include --number.
285
285
286 Without the -a/--text option, annotate will avoid processing files
286 Without the -a/--text option, annotate will avoid processing files
287 it detects as binary. With -a, annotate will annotate the file
287 it detects as binary. With -a, annotate will annotate the file
288 anyway, although the results will probably be neither useful
288 anyway, although the results will probably be neither useful
289 nor desirable.
289 nor desirable.
290
290
291 Returns 0 on success.
291 Returns 0 on success.
292 """
292 """
293 opts = pycompat.byteskwargs(opts)
293 opts = pycompat.byteskwargs(opts)
294 if not pats:
294 if not pats:
295 raise error.Abort(_('at least one filename or pattern is required'))
295 raise error.Abort(_('at least one filename or pattern is required'))
296
296
297 if opts.get('follow'):
297 if opts.get('follow'):
298 # --follow is deprecated and now just an alias for -f/--file
298 # --follow is deprecated and now just an alias for -f/--file
299 # to mimic the behavior of Mercurial before version 1.5
299 # to mimic the behavior of Mercurial before version 1.5
300 opts['file'] = True
300 opts['file'] = True
301
301
302 rev = opts.get('rev')
302 rev = opts.get('rev')
303 if rev:
303 if rev:
304 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
304 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
305 ctx = scmutil.revsingle(repo, rev)
305 ctx = scmutil.revsingle(repo, rev)
306
306
307 rootfm = ui.formatter('annotate', opts)
307 rootfm = ui.formatter('annotate', opts)
308 if ui.debugflag:
308 if ui.debugflag:
309 shorthex = pycompat.identity
309 shorthex = pycompat.identity
310 else:
310 else:
311 def shorthex(h):
311 def shorthex(h):
312 return h[:12]
312 return h[:12]
313 if ui.quiet:
313 if ui.quiet:
314 datefunc = dateutil.shortdate
314 datefunc = dateutil.shortdate
315 else:
315 else:
316 datefunc = dateutil.datestr
316 datefunc = dateutil.datestr
317 if ctx.rev() is None:
317 if ctx.rev() is None:
318 if opts.get('changeset'):
318 if opts.get('changeset'):
319 # omit "+" suffix which is appended to node hex
319 # omit "+" suffix which is appended to node hex
320 def formatrev(rev):
320 def formatrev(rev):
321 if rev == wdirrev:
321 if rev == wdirrev:
322 return '%d' % ctx.p1().rev()
322 return '%d' % ctx.p1().rev()
323 else:
323 else:
324 return '%d' % rev
324 return '%d' % rev
325 else:
325 else:
326 def formatrev(rev):
326 def formatrev(rev):
327 if rev == wdirrev:
327 if rev == wdirrev:
328 return '%d+' % ctx.p1().rev()
328 return '%d+' % ctx.p1().rev()
329 else:
329 else:
330 return '%d ' % rev
330 return '%d ' % rev
331 def formathex(h):
331 def formathex(h):
332 if h == wdirhex:
332 if h == wdirhex:
333 return '%s+' % shorthex(hex(ctx.p1().node()))
333 return '%s+' % shorthex(hex(ctx.p1().node()))
334 else:
334 else:
335 return '%s ' % shorthex(h)
335 return '%s ' % shorthex(h)
336 else:
336 else:
337 formatrev = b'%d'.__mod__
337 formatrev = b'%d'.__mod__
338 formathex = shorthex
338 formathex = shorthex
339
339
340 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
340 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
341 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
341 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
342 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
342 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
343 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
343 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
344 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
344 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
345 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
345 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
346 ]
346 ]
347 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
347 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
348 'lineno': 'line_number'}
348 'lineno': 'line_number'}
349
349
350 if (not opts.get('user') and not opts.get('changeset')
350 if (not opts.get('user') and not opts.get('changeset')
351 and not opts.get('date') and not opts.get('file')):
351 and not opts.get('date') and not opts.get('file')):
352 opts['number'] = True
352 opts['number'] = True
353
353
354 linenumber = opts.get('line_number') is not None
354 linenumber = opts.get('line_number') is not None
355 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
355 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
356 raise error.Abort(_('at least one of -n/-c is required for -l'))
356 raise error.Abort(_('at least one of -n/-c is required for -l'))
357
357
358 ui.pager('annotate')
358 ui.pager('annotate')
359
359
360 if rootfm.isplain():
360 if rootfm.isplain():
361 def makefunc(get, fmt):
361 def makefunc(get, fmt):
362 return lambda x: fmt(get(x))
362 return lambda x: fmt(get(x))
363 else:
363 else:
364 def makefunc(get, fmt):
364 def makefunc(get, fmt):
365 return get
365 return get
366 datahint = rootfm.datahint()
366 datahint = rootfm.datahint()
367 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
367 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
368 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
368 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
369 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
369 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
370 fields = ' '.join(fn for fn, sep, get, fmt in opmap
370 fields = ' '.join(fn for fn, sep, get, fmt in opmap
371 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
371 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
372
372
373 def bad(x, y):
373 def bad(x, y):
374 raise error.Abort("%s: %s" % (x, y))
374 raise error.Abort("%s: %s" % (x, y))
375
375
376 m = scmutil.match(ctx, pats, opts, badfn=bad)
376 m = scmutil.match(ctx, pats, opts, badfn=bad)
377
377
378 follow = not opts.get('no_follow')
378 follow = not opts.get('no_follow')
379 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
379 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
380 whitespace=True)
380 whitespace=True)
381 skiprevs = opts.get('skip')
381 skiprevs = opts.get('skip')
382 if skiprevs:
382 if skiprevs:
383 skiprevs = scmutil.revrange(repo, skiprevs)
383 skiprevs = scmutil.revrange(repo, skiprevs)
384
384
385 for abs in ctx.walk(m):
385 for abs in ctx.walk(m):
386 fctx = ctx[abs]
386 fctx = ctx[abs]
387 rootfm.startitem()
387 rootfm.startitem()
388 rootfm.data(path=abs)
388 rootfm.data(path=abs)
389 if not opts.get('text') and fctx.isbinary():
389 if not opts.get('text') and fctx.isbinary():
390 rootfm.plain(_("%s: binary file\n")
390 rootfm.plain(_("%s: binary file\n")
391 % ((pats and m.rel(abs)) or abs))
391 % ((pats and m.rel(abs)) or abs))
392 continue
392 continue
393
393
394 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
394 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
395 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
395 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
396 diffopts=diffopts)
396 diffopts=diffopts)
397 if not lines:
397 if not lines:
398 fm.end()
398 fm.end()
399 continue
399 continue
400 formats = []
400 formats = []
401 pieces = []
401 pieces = []
402
402
403 for f, sep in funcmap:
403 for f, sep in funcmap:
404 l = [f(n) for n in lines]
404 l = [f(n) for n in lines]
405 if fm.isplain():
405 if fm.isplain():
406 sizes = [encoding.colwidth(x) for x in l]
406 sizes = [encoding.colwidth(x) for x in l]
407 ml = max(sizes)
407 ml = max(sizes)
408 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
408 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
409 else:
409 else:
410 formats.append(['%s' for x in l])
410 formats.append(['%s' for x in l])
411 pieces.append(l)
411 pieces.append(l)
412
412
413 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
413 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
414 fm.startitem()
414 fm.startitem()
415 fm.context(fctx=n.fctx)
415 fm.context(fctx=n.fctx)
416 fm.write(fields, "".join(f), *p)
416 fm.write(fields, "".join(f), *p)
417 if n.skip:
417 if n.skip:
418 fmt = "* %s"
418 fmt = "* %s"
419 else:
419 else:
420 fmt = ": %s"
420 fmt = ": %s"
421 fm.write('line', fmt, n.text)
421 fm.write('line', fmt, n.text)
422
422
423 if not lines[-1].text.endswith('\n'):
423 if not lines[-1].text.endswith('\n'):
424 fm.plain('\n')
424 fm.plain('\n')
425 fm.end()
425 fm.end()
426
426
427 rootfm.end()
427 rootfm.end()
428
428
429 @command('archive',
429 @command('archive',
430 [('', 'no-decode', None, _('do not pass files through decoders')),
430 [('', 'no-decode', None, _('do not pass files through decoders')),
431 ('p', 'prefix', '', _('directory prefix for files in archive'),
431 ('p', 'prefix', '', _('directory prefix for files in archive'),
432 _('PREFIX')),
432 _('PREFIX')),
433 ('r', 'rev', '', _('revision to distribute'), _('REV')),
433 ('r', 'rev', '', _('revision to distribute'), _('REV')),
434 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
434 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
435 ] + subrepoopts + walkopts,
435 ] + subrepoopts + walkopts,
436 _('[OPTION]... DEST'))
436 _('[OPTION]... DEST'))
437 def archive(ui, repo, dest, **opts):
437 def archive(ui, repo, dest, **opts):
438 '''create an unversioned archive of a repository revision
438 '''create an unversioned archive of a repository revision
439
439
440 By default, the revision used is the parent of the working
440 By default, the revision used is the parent of the working
441 directory; use -r/--rev to specify a different revision.
441 directory; use -r/--rev to specify a different revision.
442
442
443 The archive type is automatically detected based on file
443 The archive type is automatically detected based on file
444 extension (to override, use -t/--type).
444 extension (to override, use -t/--type).
445
445
446 .. container:: verbose
446 .. container:: verbose
447
447
448 Examples:
448 Examples:
449
449
450 - create a zip file containing the 1.0 release::
450 - create a zip file containing the 1.0 release::
451
451
452 hg archive -r 1.0 project-1.0.zip
452 hg archive -r 1.0 project-1.0.zip
453
453
454 - create a tarball excluding .hg files::
454 - create a tarball excluding .hg files::
455
455
456 hg archive project.tar.gz -X ".hg*"
456 hg archive project.tar.gz -X ".hg*"
457
457
458 Valid types are:
458 Valid types are:
459
459
460 :``files``: a directory full of files (default)
460 :``files``: a directory full of files (default)
461 :``tar``: tar archive, uncompressed
461 :``tar``: tar archive, uncompressed
462 :``tbz2``: tar archive, compressed using bzip2
462 :``tbz2``: tar archive, compressed using bzip2
463 :``tgz``: tar archive, compressed using gzip
463 :``tgz``: tar archive, compressed using gzip
464 :``uzip``: zip archive, uncompressed
464 :``uzip``: zip archive, uncompressed
465 :``zip``: zip archive, compressed using deflate
465 :``zip``: zip archive, compressed using deflate
466
466
467 The exact name of the destination archive or directory is given
467 The exact name of the destination archive or directory is given
468 using a format string; see :hg:`help export` for details.
468 using a format string; see :hg:`help export` for details.
469
469
470 Each member added to an archive file has a directory prefix
470 Each member added to an archive file has a directory prefix
471 prepended. Use -p/--prefix to specify a format string for the
471 prepended. Use -p/--prefix to specify a format string for the
472 prefix. The default is the basename of the archive, with suffixes
472 prefix. The default is the basename of the archive, with suffixes
473 removed.
473 removed.
474
474
475 Returns 0 on success.
475 Returns 0 on success.
476 '''
476 '''
477
477
478 opts = pycompat.byteskwargs(opts)
478 opts = pycompat.byteskwargs(opts)
479 rev = opts.get('rev')
479 rev = opts.get('rev')
480 if rev:
480 if rev:
481 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
481 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
482 ctx = scmutil.revsingle(repo, rev)
482 ctx = scmutil.revsingle(repo, rev)
483 if not ctx:
483 if not ctx:
484 raise error.Abort(_('no working directory: please specify a revision'))
484 raise error.Abort(_('no working directory: please specify a revision'))
485 node = ctx.node()
485 node = ctx.node()
486 dest = cmdutil.makefilename(ctx, dest)
486 dest = cmdutil.makefilename(ctx, dest)
487 if os.path.realpath(dest) == repo.root:
487 if os.path.realpath(dest) == repo.root:
488 raise error.Abort(_('repository root cannot be destination'))
488 raise error.Abort(_('repository root cannot be destination'))
489
489
490 kind = opts.get('type') or archival.guesskind(dest) or 'files'
490 kind = opts.get('type') or archival.guesskind(dest) or 'files'
491 prefix = opts.get('prefix')
491 prefix = opts.get('prefix')
492
492
493 if dest == '-':
493 if dest == '-':
494 if kind == 'files':
494 if kind == 'files':
495 raise error.Abort(_('cannot archive plain files to stdout'))
495 raise error.Abort(_('cannot archive plain files to stdout'))
496 dest = cmdutil.makefileobj(ctx, dest)
496 dest = cmdutil.makefileobj(ctx, dest)
497 if not prefix:
497 if not prefix:
498 prefix = os.path.basename(repo.root) + '-%h'
498 prefix = os.path.basename(repo.root) + '-%h'
499
499
500 prefix = cmdutil.makefilename(ctx, prefix)
500 prefix = cmdutil.makefilename(ctx, prefix)
501 match = scmutil.match(ctx, [], opts)
501 match = scmutil.match(ctx, [], opts)
502 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
502 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
503 match, prefix, subrepos=opts.get('subrepos'))
503 match, prefix, subrepos=opts.get('subrepos'))
504
504
505 @command('backout',
505 @command('backout',
506 [('', 'merge', None, _('merge with old dirstate parent after backout')),
506 [('', 'merge', None, _('merge with old dirstate parent after backout')),
507 ('', 'commit', None,
507 ('', 'commit', None,
508 _('commit if no conflicts were encountered (DEPRECATED)')),
508 _('commit if no conflicts were encountered (DEPRECATED)')),
509 ('', 'no-commit', None, _('do not commit')),
509 ('', 'no-commit', None, _('do not commit')),
510 ('', 'parent', '',
510 ('', 'parent', '',
511 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
511 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
512 ('r', 'rev', '', _('revision to backout'), _('REV')),
512 ('r', 'rev', '', _('revision to backout'), _('REV')),
513 ('e', 'edit', False, _('invoke editor on commit messages')),
513 ('e', 'edit', False, _('invoke editor on commit messages')),
514 ] + mergetoolopts + walkopts + commitopts + commitopts2,
514 ] + mergetoolopts + walkopts + commitopts + commitopts2,
515 _('[OPTION]... [-r] REV'))
515 _('[OPTION]... [-r] REV'))
516 def backout(ui, repo, node=None, rev=None, **opts):
516 def backout(ui, repo, node=None, rev=None, **opts):
517 '''reverse effect of earlier changeset
517 '''reverse effect of earlier changeset
518
518
519 Prepare a new changeset with the effect of REV undone in the
519 Prepare a new changeset with the effect of REV undone in the
520 current working directory. If no conflicts were encountered,
520 current working directory. If no conflicts were encountered,
521 it will be committed immediately.
521 it will be committed immediately.
522
522
523 If REV is the parent of the working directory, then this new changeset
523 If REV is the parent of the working directory, then this new changeset
524 is committed automatically (unless --no-commit is specified).
524 is committed automatically (unless --no-commit is specified).
525
525
526 .. note::
526 .. note::
527
527
528 :hg:`backout` cannot be used to fix either an unwanted or
528 :hg:`backout` cannot be used to fix either an unwanted or
529 incorrect merge.
529 incorrect merge.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Examples:
533 Examples:
534
534
535 - Reverse the effect of the parent of the working directory.
535 - Reverse the effect of the parent of the working directory.
536 This backout will be committed immediately::
536 This backout will be committed immediately::
537
537
538 hg backout -r .
538 hg backout -r .
539
539
540 - Reverse the effect of previous bad revision 23::
540 - Reverse the effect of previous bad revision 23::
541
541
542 hg backout -r 23
542 hg backout -r 23
543
543
544 - Reverse the effect of previous bad revision 23 and
544 - Reverse the effect of previous bad revision 23 and
545 leave changes uncommitted::
545 leave changes uncommitted::
546
546
547 hg backout -r 23 --no-commit
547 hg backout -r 23 --no-commit
548 hg commit -m "Backout revision 23"
548 hg commit -m "Backout revision 23"
549
549
550 By default, the pending changeset will have one parent,
550 By default, the pending changeset will have one parent,
551 maintaining a linear history. With --merge, the pending
551 maintaining a linear history. With --merge, the pending
552 changeset will instead have two parents: the old parent of the
552 changeset will instead have two parents: the old parent of the
553 working directory and a new child of REV that simply undoes REV.
553 working directory and a new child of REV that simply undoes REV.
554
554
555 Before version 1.7, the behavior without --merge was equivalent
555 Before version 1.7, the behavior without --merge was equivalent
556 to specifying --merge followed by :hg:`update --clean .` to
556 to specifying --merge followed by :hg:`update --clean .` to
557 cancel the merge and leave the child of REV as a head to be
557 cancel the merge and leave the child of REV as a head to be
558 merged separately.
558 merged separately.
559
559
560 See :hg:`help dates` for a list of formats valid for -d/--date.
560 See :hg:`help dates` for a list of formats valid for -d/--date.
561
561
562 See :hg:`help revert` for a way to restore files to the state
562 See :hg:`help revert` for a way to restore files to the state
563 of another revision.
563 of another revision.
564
564
565 Returns 0 on success, 1 if nothing to backout or there are unresolved
565 Returns 0 on success, 1 if nothing to backout or there are unresolved
566 files.
566 files.
567 '''
567 '''
568 with repo.wlock(), repo.lock():
568 with repo.wlock(), repo.lock():
569 return _dobackout(ui, repo, node, rev, **opts)
569 return _dobackout(ui, repo, node, rev, **opts)
570
570
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
571 def _dobackout(ui, repo, node=None, rev=None, **opts):
572 opts = pycompat.byteskwargs(opts)
572 opts = pycompat.byteskwargs(opts)
573 if opts.get('commit') and opts.get('no_commit'):
573 if opts.get('commit') and opts.get('no_commit'):
574 raise error.Abort(_("cannot use --commit with --no-commit"))
574 raise error.Abort(_("cannot use --commit with --no-commit"))
575 if opts.get('merge') and opts.get('no_commit'):
575 if opts.get('merge') and opts.get('no_commit'):
576 raise error.Abort(_("cannot use --merge with --no-commit"))
576 raise error.Abort(_("cannot use --merge with --no-commit"))
577
577
578 if rev and node:
578 if rev and node:
579 raise error.Abort(_("please specify just one revision"))
579 raise error.Abort(_("please specify just one revision"))
580
580
581 if not rev:
581 if not rev:
582 rev = node
582 rev = node
583
583
584 if not rev:
584 if not rev:
585 raise error.Abort(_("please specify a revision to backout"))
585 raise error.Abort(_("please specify a revision to backout"))
586
586
587 date = opts.get('date')
587 date = opts.get('date')
588 if date:
588 if date:
589 opts['date'] = dateutil.parsedate(date)
589 opts['date'] = dateutil.parsedate(date)
590
590
591 cmdutil.checkunfinished(repo)
591 cmdutil.checkunfinished(repo)
592 cmdutil.bailifchanged(repo)
592 cmdutil.bailifchanged(repo)
593 node = scmutil.revsingle(repo, rev).node()
593 node = scmutil.revsingle(repo, rev).node()
594
594
595 op1, op2 = repo.dirstate.parents()
595 op1, op2 = repo.dirstate.parents()
596 if not repo.changelog.isancestor(node, op1):
596 if not repo.changelog.isancestor(node, op1):
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
597 raise error.Abort(_('cannot backout change that is not an ancestor'))
598
598
599 p1, p2 = repo.changelog.parents(node)
599 p1, p2 = repo.changelog.parents(node)
600 if p1 == nullid:
600 if p1 == nullid:
601 raise error.Abort(_('cannot backout a change with no parents'))
601 raise error.Abort(_('cannot backout a change with no parents'))
602 if p2 != nullid:
602 if p2 != nullid:
603 if not opts.get('parent'):
603 if not opts.get('parent'):
604 raise error.Abort(_('cannot backout a merge changeset'))
604 raise error.Abort(_('cannot backout a merge changeset'))
605 p = repo.lookup(opts['parent'])
605 p = repo.lookup(opts['parent'])
606 if p not in (p1, p2):
606 if p not in (p1, p2):
607 raise error.Abort(_('%s is not a parent of %s') %
607 raise error.Abort(_('%s is not a parent of %s') %
608 (short(p), short(node)))
608 (short(p), short(node)))
609 parent = p
609 parent = p
610 else:
610 else:
611 if opts.get('parent'):
611 if opts.get('parent'):
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
612 raise error.Abort(_('cannot use --parent on non-merge changeset'))
613 parent = p1
613 parent = p1
614
614
615 # the backout should appear on the same branch
615 # the backout should appear on the same branch
616 branch = repo.dirstate.branch()
616 branch = repo.dirstate.branch()
617 bheads = repo.branchheads(branch)
617 bheads = repo.branchheads(branch)
618 rctx = scmutil.revsingle(repo, hex(parent))
618 rctx = scmutil.revsingle(repo, hex(parent))
619 if not opts.get('merge') and op1 != node:
619 if not opts.get('merge') and op1 != node:
620 with dirstateguard.dirstateguard(repo, 'backout'):
620 with dirstateguard.dirstateguard(repo, 'backout'):
621 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
621 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
622 with ui.configoverride(overrides, 'backout'):
622 with ui.configoverride(overrides, 'backout'):
623 stats = mergemod.update(repo, parent, True, True, node, False)
623 stats = mergemod.update(repo, parent, True, True, node, False)
624 repo.setparents(op1, op2)
624 repo.setparents(op1, op2)
625 hg._showstats(repo, stats)
625 hg._showstats(repo, stats)
626 if stats.unresolvedcount:
626 if stats.unresolvedcount:
627 repo.ui.status(_("use 'hg resolve' to retry unresolved "
627 repo.ui.status(_("use 'hg resolve' to retry unresolved "
628 "file merges\n"))
628 "file merges\n"))
629 return 1
629 return 1
630 else:
630 else:
631 hg.clean(repo, node, show_stats=False)
631 hg.clean(repo, node, show_stats=False)
632 repo.dirstate.setbranch(branch)
632 repo.dirstate.setbranch(branch)
633 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
633 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
634
634
635 if opts.get('no_commit'):
635 if opts.get('no_commit'):
636 msg = _("changeset %s backed out, "
636 msg = _("changeset %s backed out, "
637 "don't forget to commit.\n")
637 "don't forget to commit.\n")
638 ui.status(msg % short(node))
638 ui.status(msg % short(node))
639 return 0
639 return 0
640
640
641 def commitfunc(ui, repo, message, match, opts):
641 def commitfunc(ui, repo, message, match, opts):
642 editform = 'backout'
642 editform = 'backout'
643 e = cmdutil.getcommiteditor(editform=editform,
643 e = cmdutil.getcommiteditor(editform=editform,
644 **pycompat.strkwargs(opts))
644 **pycompat.strkwargs(opts))
645 if not message:
645 if not message:
646 # we don't translate commit messages
646 # we don't translate commit messages
647 message = "Backed out changeset %s" % short(node)
647 message = "Backed out changeset %s" % short(node)
648 e = cmdutil.getcommiteditor(edit=True, editform=editform)
648 e = cmdutil.getcommiteditor(edit=True, editform=editform)
649 return repo.commit(message, opts.get('user'), opts.get('date'),
649 return repo.commit(message, opts.get('user'), opts.get('date'),
650 match, editor=e)
650 match, editor=e)
651 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
651 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
652 if not newnode:
652 if not newnode:
653 ui.status(_("nothing changed\n"))
653 ui.status(_("nothing changed\n"))
654 return 1
654 return 1
655 cmdutil.commitstatus(repo, newnode, branch, bheads)
655 cmdutil.commitstatus(repo, newnode, branch, bheads)
656
656
657 def nice(node):
657 def nice(node):
658 return '%d:%s' % (repo.changelog.rev(node), short(node))
658 return '%d:%s' % (repo.changelog.rev(node), short(node))
659 ui.status(_('changeset %s backs out changeset %s\n') %
659 ui.status(_('changeset %s backs out changeset %s\n') %
660 (nice(repo.changelog.tip()), nice(node)))
660 (nice(repo.changelog.tip()), nice(node)))
661 if opts.get('merge') and op1 != node:
661 if opts.get('merge') and op1 != node:
662 hg.clean(repo, op1, show_stats=False)
662 hg.clean(repo, op1, show_stats=False)
663 ui.status(_('merging with changeset %s\n')
663 ui.status(_('merging with changeset %s\n')
664 % nice(repo.changelog.tip()))
664 % nice(repo.changelog.tip()))
665 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
665 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
666 with ui.configoverride(overrides, 'backout'):
666 with ui.configoverride(overrides, 'backout'):
667 return hg.merge(repo, hex(repo.changelog.tip()))
667 return hg.merge(repo, hex(repo.changelog.tip()))
668 return 0
668 return 0
669
669
670 @command('bisect',
670 @command('bisect',
671 [('r', 'reset', False, _('reset bisect state')),
671 [('r', 'reset', False, _('reset bisect state')),
672 ('g', 'good', False, _('mark changeset good')),
672 ('g', 'good', False, _('mark changeset good')),
673 ('b', 'bad', False, _('mark changeset bad')),
673 ('b', 'bad', False, _('mark changeset bad')),
674 ('s', 'skip', False, _('skip testing changeset')),
674 ('s', 'skip', False, _('skip testing changeset')),
675 ('e', 'extend', False, _('extend the bisect range')),
675 ('e', 'extend', False, _('extend the bisect range')),
676 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
676 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
677 ('U', 'noupdate', False, _('do not update to target'))],
677 ('U', 'noupdate', False, _('do not update to target'))],
678 _("[-gbsr] [-U] [-c CMD] [REV]"))
678 _("[-gbsr] [-U] [-c CMD] [REV]"))
679 def bisect(ui, repo, rev=None, extra=None, command=None,
679 def bisect(ui, repo, rev=None, extra=None, command=None,
680 reset=None, good=None, bad=None, skip=None, extend=None,
680 reset=None, good=None, bad=None, skip=None, extend=None,
681 noupdate=None):
681 noupdate=None):
682 """subdivision search of changesets
682 """subdivision search of changesets
683
683
684 This command helps to find changesets which introduce problems. To
684 This command helps to find changesets which introduce problems. To
685 use, mark the earliest changeset you know exhibits the problem as
685 use, mark the earliest changeset you know exhibits the problem as
686 bad, then mark the latest changeset which is free from the problem
686 bad, then mark the latest changeset which is free from the problem
687 as good. Bisect will update your working directory to a revision
687 as good. Bisect will update your working directory to a revision
688 for testing (unless the -U/--noupdate option is specified). Once
688 for testing (unless the -U/--noupdate option is specified). Once
689 you have performed tests, mark the working directory as good or
689 you have performed tests, mark the working directory as good or
690 bad, and bisect will either update to another candidate changeset
690 bad, and bisect will either update to another candidate changeset
691 or announce that it has found the bad revision.
691 or announce that it has found the bad revision.
692
692
693 As a shortcut, you can also use the revision argument to mark a
693 As a shortcut, you can also use the revision argument to mark a
694 revision as good or bad without checking it out first.
694 revision as good or bad without checking it out first.
695
695
696 If you supply a command, it will be used for automatic bisection.
696 If you supply a command, it will be used for automatic bisection.
697 The environment variable HG_NODE will contain the ID of the
697 The environment variable HG_NODE will contain the ID of the
698 changeset being tested. The exit status of the command will be
698 changeset being tested. The exit status of the command will be
699 used to mark revisions as good or bad: status 0 means good, 125
699 used to mark revisions as good or bad: status 0 means good, 125
700 means to skip the revision, 127 (command not found) will abort the
700 means to skip the revision, 127 (command not found) will abort the
701 bisection, and any other non-zero exit status means the revision
701 bisection, and any other non-zero exit status means the revision
702 is bad.
702 is bad.
703
703
704 .. container:: verbose
704 .. container:: verbose
705
705
706 Some examples:
706 Some examples:
707
707
708 - start a bisection with known bad revision 34, and good revision 12::
708 - start a bisection with known bad revision 34, and good revision 12::
709
709
710 hg bisect --bad 34
710 hg bisect --bad 34
711 hg bisect --good 12
711 hg bisect --good 12
712
712
713 - advance the current bisection by marking current revision as good or
713 - advance the current bisection by marking current revision as good or
714 bad::
714 bad::
715
715
716 hg bisect --good
716 hg bisect --good
717 hg bisect --bad
717 hg bisect --bad
718
718
719 - mark the current revision, or a known revision, to be skipped (e.g. if
719 - mark the current revision, or a known revision, to be skipped (e.g. if
720 that revision is not usable because of another issue)::
720 that revision is not usable because of another issue)::
721
721
722 hg bisect --skip
722 hg bisect --skip
723 hg bisect --skip 23
723 hg bisect --skip 23
724
724
725 - skip all revisions that do not touch directories ``foo`` or ``bar``::
725 - skip all revisions that do not touch directories ``foo`` or ``bar``::
726
726
727 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
727 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
728
728
729 - forget the current bisection::
729 - forget the current bisection::
730
730
731 hg bisect --reset
731 hg bisect --reset
732
732
733 - use 'make && make tests' to automatically find the first broken
733 - use 'make && make tests' to automatically find the first broken
734 revision::
734 revision::
735
735
736 hg bisect --reset
736 hg bisect --reset
737 hg bisect --bad 34
737 hg bisect --bad 34
738 hg bisect --good 12
738 hg bisect --good 12
739 hg bisect --command "make && make tests"
739 hg bisect --command "make && make tests"
740
740
741 - see all changesets whose states are already known in the current
741 - see all changesets whose states are already known in the current
742 bisection::
742 bisection::
743
743
744 hg log -r "bisect(pruned)"
744 hg log -r "bisect(pruned)"
745
745
746 - see the changeset currently being bisected (especially useful
746 - see the changeset currently being bisected (especially useful
747 if running with -U/--noupdate)::
747 if running with -U/--noupdate)::
748
748
749 hg log -r "bisect(current)"
749 hg log -r "bisect(current)"
750
750
751 - see all changesets that took part in the current bisection::
751 - see all changesets that took part in the current bisection::
752
752
753 hg log -r "bisect(range)"
753 hg log -r "bisect(range)"
754
754
755 - you can even get a nice graph::
755 - you can even get a nice graph::
756
756
757 hg log --graph -r "bisect(range)"
757 hg log --graph -r "bisect(range)"
758
758
759 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
759 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
760
760
761 Returns 0 on success.
761 Returns 0 on success.
762 """
762 """
763 # backward compatibility
763 # backward compatibility
764 if rev in "good bad reset init".split():
764 if rev in "good bad reset init".split():
765 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
765 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
766 cmd, rev, extra = rev, extra, None
766 cmd, rev, extra = rev, extra, None
767 if cmd == "good":
767 if cmd == "good":
768 good = True
768 good = True
769 elif cmd == "bad":
769 elif cmd == "bad":
770 bad = True
770 bad = True
771 else:
771 else:
772 reset = True
772 reset = True
773 elif extra:
773 elif extra:
774 raise error.Abort(_('incompatible arguments'))
774 raise error.Abort(_('incompatible arguments'))
775
775
776 incompatibles = {
776 incompatibles = {
777 '--bad': bad,
777 '--bad': bad,
778 '--command': bool(command),
778 '--command': bool(command),
779 '--extend': extend,
779 '--extend': extend,
780 '--good': good,
780 '--good': good,
781 '--reset': reset,
781 '--reset': reset,
782 '--skip': skip,
782 '--skip': skip,
783 }
783 }
784
784
785 enabled = [x for x in incompatibles if incompatibles[x]]
785 enabled = [x for x in incompatibles if incompatibles[x]]
786
786
787 if len(enabled) > 1:
787 if len(enabled) > 1:
788 raise error.Abort(_('%s and %s are incompatible') %
788 raise error.Abort(_('%s and %s are incompatible') %
789 tuple(sorted(enabled)[0:2]))
789 tuple(sorted(enabled)[0:2]))
790
790
791 if reset:
791 if reset:
792 hbisect.resetstate(repo)
792 hbisect.resetstate(repo)
793 return
793 return
794
794
795 state = hbisect.load_state(repo)
795 state = hbisect.load_state(repo)
796
796
797 # update state
797 # update state
798 if good or bad or skip:
798 if good or bad or skip:
799 if rev:
799 if rev:
800 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
800 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
801 else:
801 else:
802 nodes = [repo.lookup('.')]
802 nodes = [repo.lookup('.')]
803 if good:
803 if good:
804 state['good'] += nodes
804 state['good'] += nodes
805 elif bad:
805 elif bad:
806 state['bad'] += nodes
806 state['bad'] += nodes
807 elif skip:
807 elif skip:
808 state['skip'] += nodes
808 state['skip'] += nodes
809 hbisect.save_state(repo, state)
809 hbisect.save_state(repo, state)
810 if not (state['good'] and state['bad']):
810 if not (state['good'] and state['bad']):
811 return
811 return
812
812
813 def mayupdate(repo, node, show_stats=True):
813 def mayupdate(repo, node, show_stats=True):
814 """common used update sequence"""
814 """common used update sequence"""
815 if noupdate:
815 if noupdate:
816 return
816 return
817 cmdutil.checkunfinished(repo)
817 cmdutil.checkunfinished(repo)
818 cmdutil.bailifchanged(repo)
818 cmdutil.bailifchanged(repo)
819 return hg.clean(repo, node, show_stats=show_stats)
819 return hg.clean(repo, node, show_stats=show_stats)
820
820
821 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
821 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
822
822
823 if command:
823 if command:
824 changesets = 1
824 changesets = 1
825 if noupdate:
825 if noupdate:
826 try:
826 try:
827 node = state['current'][0]
827 node = state['current'][0]
828 except LookupError:
828 except LookupError:
829 raise error.Abort(_('current bisect revision is unknown - '
829 raise error.Abort(_('current bisect revision is unknown - '
830 'start a new bisect to fix'))
830 'start a new bisect to fix'))
831 else:
831 else:
832 node, p2 = repo.dirstate.parents()
832 node, p2 = repo.dirstate.parents()
833 if p2 != nullid:
833 if p2 != nullid:
834 raise error.Abort(_('current bisect revision is a merge'))
834 raise error.Abort(_('current bisect revision is a merge'))
835 if rev:
835 if rev:
836 node = repo[scmutil.revsingle(repo, rev, node)].node()
836 node = repo[scmutil.revsingle(repo, rev, node)].node()
837 try:
837 try:
838 while changesets:
838 while changesets:
839 # update state
839 # update state
840 state['current'] = [node]
840 state['current'] = [node]
841 hbisect.save_state(repo, state)
841 hbisect.save_state(repo, state)
842 status = ui.system(command, environ={'HG_NODE': hex(node)},
842 status = ui.system(command, environ={'HG_NODE': hex(node)},
843 blockedtag='bisect_check')
843 blockedtag='bisect_check')
844 if status == 125:
844 if status == 125:
845 transition = "skip"
845 transition = "skip"
846 elif status == 0:
846 elif status == 0:
847 transition = "good"
847 transition = "good"
848 # status < 0 means process was killed
848 # status < 0 means process was killed
849 elif status == 127:
849 elif status == 127:
850 raise error.Abort(_("failed to execute %s") % command)
850 raise error.Abort(_("failed to execute %s") % command)
851 elif status < 0:
851 elif status < 0:
852 raise error.Abort(_("%s killed") % command)
852 raise error.Abort(_("%s killed") % command)
853 else:
853 else:
854 transition = "bad"
854 transition = "bad"
855 state[transition].append(node)
855 state[transition].append(node)
856 ctx = repo[node]
856 ctx = repo[node]
857 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
857 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
858 transition))
858 transition))
859 hbisect.checkstate(state)
859 hbisect.checkstate(state)
860 # bisect
860 # bisect
861 nodes, changesets, bgood = hbisect.bisect(repo, state)
861 nodes, changesets, bgood = hbisect.bisect(repo, state)
862 # update to next check
862 # update to next check
863 node = nodes[0]
863 node = nodes[0]
864 mayupdate(repo, node, show_stats=False)
864 mayupdate(repo, node, show_stats=False)
865 finally:
865 finally:
866 state['current'] = [node]
866 state['current'] = [node]
867 hbisect.save_state(repo, state)
867 hbisect.save_state(repo, state)
868 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
868 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
869 return
869 return
870
870
871 hbisect.checkstate(state)
871 hbisect.checkstate(state)
872
872
873 # actually bisect
873 # actually bisect
874 nodes, changesets, good = hbisect.bisect(repo, state)
874 nodes, changesets, good = hbisect.bisect(repo, state)
875 if extend:
875 if extend:
876 if not changesets:
876 if not changesets:
877 extendnode = hbisect.extendrange(repo, state, nodes, good)
877 extendnode = hbisect.extendrange(repo, state, nodes, good)
878 if extendnode is not None:
878 if extendnode is not None:
879 ui.write(_("Extending search to changeset %d:%s\n")
879 ui.write(_("Extending search to changeset %d:%s\n")
880 % (extendnode.rev(), extendnode))
880 % (extendnode.rev(), extendnode))
881 state['current'] = [extendnode.node()]
881 state['current'] = [extendnode.node()]
882 hbisect.save_state(repo, state)
882 hbisect.save_state(repo, state)
883 return mayupdate(repo, extendnode.node())
883 return mayupdate(repo, extendnode.node())
884 raise error.Abort(_("nothing to extend"))
884 raise error.Abort(_("nothing to extend"))
885
885
886 if changesets == 0:
886 if changesets == 0:
887 hbisect.printresult(ui, repo, state, displayer, nodes, good)
887 hbisect.printresult(ui, repo, state, displayer, nodes, good)
888 else:
888 else:
889 assert len(nodes) == 1 # only a single node can be tested next
889 assert len(nodes) == 1 # only a single node can be tested next
890 node = nodes[0]
890 node = nodes[0]
891 # compute the approximate number of remaining tests
891 # compute the approximate number of remaining tests
892 tests, size = 0, 2
892 tests, size = 0, 2
893 while size <= changesets:
893 while size <= changesets:
894 tests, size = tests + 1, size * 2
894 tests, size = tests + 1, size * 2
895 rev = repo.changelog.rev(node)
895 rev = repo.changelog.rev(node)
896 ui.write(_("Testing changeset %d:%s "
896 ui.write(_("Testing changeset %d:%s "
897 "(%d changesets remaining, ~%d tests)\n")
897 "(%d changesets remaining, ~%d tests)\n")
898 % (rev, short(node), changesets, tests))
898 % (rev, short(node), changesets, tests))
899 state['current'] = [node]
899 state['current'] = [node]
900 hbisect.save_state(repo, state)
900 hbisect.save_state(repo, state)
901 return mayupdate(repo, node)
901 return mayupdate(repo, node)
902
902
903 @command('bookmarks|bookmark',
903 @command('bookmarks|bookmark',
904 [('f', 'force', False, _('force')),
904 [('f', 'force', False, _('force')),
905 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
905 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
906 ('d', 'delete', False, _('delete a given bookmark')),
906 ('d', 'delete', False, _('delete a given bookmark')),
907 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
907 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
908 ('i', 'inactive', False, _('mark a bookmark inactive')),
908 ('i', 'inactive', False, _('mark a bookmark inactive')),
909 ('l', 'list', False, _('list existing bookmarks')),
909 ('l', 'list', False, _('list existing bookmarks')),
910 ] + formatteropts,
910 ] + formatteropts,
911 _('hg bookmarks [OPTIONS]... [NAME]...'))
911 _('hg bookmarks [OPTIONS]... [NAME]...'))
912 def bookmark(ui, repo, *names, **opts):
912 def bookmark(ui, repo, *names, **opts):
913 '''create a new bookmark or list existing bookmarks
913 '''create a new bookmark or list existing bookmarks
914
914
915 Bookmarks are labels on changesets to help track lines of development.
915 Bookmarks are labels on changesets to help track lines of development.
916 Bookmarks are unversioned and can be moved, renamed and deleted.
916 Bookmarks are unversioned and can be moved, renamed and deleted.
917 Deleting or moving a bookmark has no effect on the associated changesets.
917 Deleting or moving a bookmark has no effect on the associated changesets.
918
918
919 Creating or updating to a bookmark causes it to be marked as 'active'.
919 Creating or updating to a bookmark causes it to be marked as 'active'.
920 The active bookmark is indicated with a '*'.
920 The active bookmark is indicated with a '*'.
921 When a commit is made, the active bookmark will advance to the new commit.
921 When a commit is made, the active bookmark will advance to the new commit.
922 A plain :hg:`update` will also advance an active bookmark, if possible.
922 A plain :hg:`update` will also advance an active bookmark, if possible.
923 Updating away from a bookmark will cause it to be deactivated.
923 Updating away from a bookmark will cause it to be deactivated.
924
924
925 Bookmarks can be pushed and pulled between repositories (see
925 Bookmarks can be pushed and pulled between repositories (see
926 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
926 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
927 diverged, a new 'divergent bookmark' of the form 'name@path' will
927 diverged, a new 'divergent bookmark' of the form 'name@path' will
928 be created. Using :hg:`merge` will resolve the divergence.
928 be created. Using :hg:`merge` will resolve the divergence.
929
929
930 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
930 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
931 the active bookmark's name.
931 the active bookmark's name.
932
932
933 A bookmark named '@' has the special property that :hg:`clone` will
933 A bookmark named '@' has the special property that :hg:`clone` will
934 check it out by default if it exists.
934 check it out by default if it exists.
935
935
936 .. container:: verbose
936 .. container:: verbose
937
937
938 Examples:
938 Examples:
939
939
940 - create an active bookmark for a new line of development::
940 - create an active bookmark for a new line of development::
941
941
942 hg book new-feature
942 hg book new-feature
943
943
944 - create an inactive bookmark as a place marker::
944 - create an inactive bookmark as a place marker::
945
945
946 hg book -i reviewed
946 hg book -i reviewed
947
947
948 - create an inactive bookmark on another changeset::
948 - create an inactive bookmark on another changeset::
949
949
950 hg book -r .^ tested
950 hg book -r .^ tested
951
951
952 - rename bookmark turkey to dinner::
952 - rename bookmark turkey to dinner::
953
953
954 hg book -m turkey dinner
954 hg book -m turkey dinner
955
955
956 - move the '@' bookmark from another branch::
956 - move the '@' bookmark from another branch::
957
957
958 hg book -f @
958 hg book -f @
959
959
960 - print only the active bookmark name::
960 - print only the active bookmark name::
961
961
962 hg book -ql .
962 hg book -ql .
963 '''
963 '''
964 opts = pycompat.byteskwargs(opts)
964 opts = pycompat.byteskwargs(opts)
965 force = opts.get('force')
965 force = opts.get('force')
966 rev = opts.get('rev')
966 rev = opts.get('rev')
967 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
967 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
968
968
969 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
969 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
970 if len(selactions) > 1:
970 if len(selactions) > 1:
971 raise error.Abort(_('--%s and --%s are incompatible')
971 raise error.Abort(_('--%s and --%s are incompatible')
972 % tuple(selactions[:2]))
972 % tuple(selactions[:2]))
973 if selactions:
973 if selactions:
974 action = selactions[0]
974 action = selactions[0]
975 elif names or rev:
975 elif names or rev:
976 action = 'add'
976 action = 'add'
977 elif inactive:
977 elif inactive:
978 action = 'inactive' # meaning deactivate
978 action = 'inactive' # meaning deactivate
979 else:
979 else:
980 action = 'list'
980 action = 'list'
981
981
982 if rev and action in {'delete', 'rename', 'list'}:
982 if rev and action in {'delete', 'rename', 'list'}:
983 raise error.Abort(_("--rev is incompatible with --%s") % action)
983 raise error.Abort(_("--rev is incompatible with --%s") % action)
984 if inactive and action in {'delete', 'list'}:
984 if inactive and action in {'delete', 'list'}:
985 raise error.Abort(_("--inactive is incompatible with --%s") % action)
985 raise error.Abort(_("--inactive is incompatible with --%s") % action)
986 if not names and action in {'add', 'delete'}:
986 if not names and action in {'add', 'delete'}:
987 raise error.Abort(_("bookmark name required"))
987 raise error.Abort(_("bookmark name required"))
988
988
989 if action in {'add', 'delete', 'rename', 'inactive'}:
989 if action in {'add', 'delete', 'rename', 'inactive'}:
990 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
990 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
991 if action == 'delete':
991 if action == 'delete':
992 names = pycompat.maplist(repo._bookmarks.expandname, names)
992 names = pycompat.maplist(repo._bookmarks.expandname, names)
993 bookmarks.delete(repo, tr, names)
993 bookmarks.delete(repo, tr, names)
994 elif action == 'rename':
994 elif action == 'rename':
995 if not names:
995 if not names:
996 raise error.Abort(_("new bookmark name required"))
996 raise error.Abort(_("new bookmark name required"))
997 elif len(names) > 1:
997 elif len(names) > 1:
998 raise error.Abort(_("only one new bookmark name allowed"))
998 raise error.Abort(_("only one new bookmark name allowed"))
999 oldname = repo._bookmarks.expandname(opts['rename'])
999 oldname = repo._bookmarks.expandname(opts['rename'])
1000 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1000 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1001 elif action == 'add':
1001 elif action == 'add':
1002 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1002 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1003 elif action == 'inactive':
1003 elif action == 'inactive':
1004 if len(repo._bookmarks) == 0:
1004 if len(repo._bookmarks) == 0:
1005 ui.status(_("no bookmarks set\n"))
1005 ui.status(_("no bookmarks set\n"))
1006 elif not repo._activebookmark:
1006 elif not repo._activebookmark:
1007 ui.status(_("no active bookmark\n"))
1007 ui.status(_("no active bookmark\n"))
1008 else:
1008 else:
1009 bookmarks.deactivate(repo)
1009 bookmarks.deactivate(repo)
1010 elif action == 'list':
1010 elif action == 'list':
1011 names = pycompat.maplist(repo._bookmarks.expandname, names)
1011 names = pycompat.maplist(repo._bookmarks.expandname, names)
1012 with ui.formatter('bookmarks', opts) as fm:
1012 with ui.formatter('bookmarks', opts) as fm:
1013 bookmarks.printbookmarks(ui, repo, fm, names)
1013 bookmarks.printbookmarks(ui, repo, fm, names)
1014 else:
1014 else:
1015 raise error.ProgrammingError('invalid action: %s' % action)
1015 raise error.ProgrammingError('invalid action: %s' % action)
1016
1016
1017 @command('branch',
1017 @command('branch',
1018 [('f', 'force', None,
1018 [('f', 'force', None,
1019 _('set branch name even if it shadows an existing branch')),
1019 _('set branch name even if it shadows an existing branch')),
1020 ('C', 'clean', None, _('reset branch name to parent branch name')),
1020 ('C', 'clean', None, _('reset branch name to parent branch name')),
1021 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1021 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1022 ],
1022 ],
1023 _('[-fC] [NAME]'))
1023 _('[-fC] [NAME]'))
1024 def branch(ui, repo, label=None, **opts):
1024 def branch(ui, repo, label=None, **opts):
1025 """set or show the current branch name
1025 """set or show the current branch name
1026
1026
1027 .. note::
1027 .. note::
1028
1028
1029 Branch names are permanent and global. Use :hg:`bookmark` to create a
1029 Branch names are permanent and global. Use :hg:`bookmark` to create a
1030 light-weight bookmark instead. See :hg:`help glossary` for more
1030 light-weight bookmark instead. See :hg:`help glossary` for more
1031 information about named branches and bookmarks.
1031 information about named branches and bookmarks.
1032
1032
1033 With no argument, show the current branch name. With one argument,
1033 With no argument, show the current branch name. With one argument,
1034 set the working directory branch name (the branch will not exist
1034 set the working directory branch name (the branch will not exist
1035 in the repository until the next commit). Standard practice
1035 in the repository until the next commit). Standard practice
1036 recommends that primary development take place on the 'default'
1036 recommends that primary development take place on the 'default'
1037 branch.
1037 branch.
1038
1038
1039 Unless -f/--force is specified, branch will not let you set a
1039 Unless -f/--force is specified, branch will not let you set a
1040 branch name that already exists.
1040 branch name that already exists.
1041
1041
1042 Use -C/--clean to reset the working directory branch to that of
1042 Use -C/--clean to reset the working directory branch to that of
1043 the parent of the working directory, negating a previous branch
1043 the parent of the working directory, negating a previous branch
1044 change.
1044 change.
1045
1045
1046 Use the command :hg:`update` to switch to an existing branch. Use
1046 Use the command :hg:`update` to switch to an existing branch. Use
1047 :hg:`commit --close-branch` to mark this branch head as closed.
1047 :hg:`commit --close-branch` to mark this branch head as closed.
1048 When all heads of a branch are closed, the branch will be
1048 When all heads of a branch are closed, the branch will be
1049 considered closed.
1049 considered closed.
1050
1050
1051 Returns 0 on success.
1051 Returns 0 on success.
1052 """
1052 """
1053 opts = pycompat.byteskwargs(opts)
1053 opts = pycompat.byteskwargs(opts)
1054 revs = opts.get('rev')
1054 revs = opts.get('rev')
1055 if label:
1055 if label:
1056 label = label.strip()
1056 label = label.strip()
1057
1057
1058 if not opts.get('clean') and not label:
1058 if not opts.get('clean') and not label:
1059 if revs:
1059 if revs:
1060 raise error.Abort(_("no branch name specified for the revisions"))
1060 raise error.Abort(_("no branch name specified for the revisions"))
1061 ui.write("%s\n" % repo.dirstate.branch())
1061 ui.write("%s\n" % repo.dirstate.branch())
1062 return
1062 return
1063
1063
1064 with repo.wlock():
1064 with repo.wlock():
1065 if opts.get('clean'):
1065 if opts.get('clean'):
1066 label = repo[None].p1().branch()
1066 label = repo[None].p1().branch()
1067 repo.dirstate.setbranch(label)
1067 repo.dirstate.setbranch(label)
1068 ui.status(_('reset working directory to branch %s\n') % label)
1068 ui.status(_('reset working directory to branch %s\n') % label)
1069 elif label:
1069 elif label:
1070
1070
1071 scmutil.checknewlabel(repo, label, 'branch')
1071 scmutil.checknewlabel(repo, label, 'branch')
1072 if revs:
1072 if revs:
1073 return cmdutil.changebranch(ui, repo, revs, label)
1073 return cmdutil.changebranch(ui, repo, revs, label)
1074
1074
1075 if not opts.get('force') and label in repo.branchmap():
1075 if not opts.get('force') and label in repo.branchmap():
1076 if label not in [p.branch() for p in repo[None].parents()]:
1076 if label not in [p.branch() for p in repo[None].parents()]:
1077 raise error.Abort(_('a branch of the same name already'
1077 raise error.Abort(_('a branch of the same name already'
1078 ' exists'),
1078 ' exists'),
1079 # i18n: "it" refers to an existing branch
1079 # i18n: "it" refers to an existing branch
1080 hint=_("use 'hg update' to switch to it"))
1080 hint=_("use 'hg update' to switch to it"))
1081
1081
1082 repo.dirstate.setbranch(label)
1082 repo.dirstate.setbranch(label)
1083 ui.status(_('marked working directory as branch %s\n') % label)
1083 ui.status(_('marked working directory as branch %s\n') % label)
1084
1084
1085 # find any open named branches aside from default
1085 # find any open named branches aside from default
1086 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1086 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1087 if n != "default" and not c]
1087 if n != "default" and not c]
1088 if not others:
1088 if not others:
1089 ui.status(_('(branches are permanent and global, '
1089 ui.status(_('(branches are permanent and global, '
1090 'did you want a bookmark?)\n'))
1090 'did you want a bookmark?)\n'))
1091
1091
1092 @command('branches',
1092 @command('branches',
1093 [('a', 'active', False,
1093 [('a', 'active', False,
1094 _('show only branches that have unmerged heads (DEPRECATED)')),
1094 _('show only branches that have unmerged heads (DEPRECATED)')),
1095 ('c', 'closed', False, _('show normal and closed branches')),
1095 ('c', 'closed', False, _('show normal and closed branches')),
1096 ] + formatteropts,
1096 ] + formatteropts,
1097 _('[-c]'),
1097 _('[-c]'),
1098 intents={INTENT_READONLY})
1098 intents={INTENT_READONLY})
1099 def branches(ui, repo, active=False, closed=False, **opts):
1099 def branches(ui, repo, active=False, closed=False, **opts):
1100 """list repository named branches
1100 """list repository named branches
1101
1101
1102 List the repository's named branches, indicating which ones are
1102 List the repository's named branches, indicating which ones are
1103 inactive. If -c/--closed is specified, also list branches which have
1103 inactive. If -c/--closed is specified, also list branches which have
1104 been marked closed (see :hg:`commit --close-branch`).
1104 been marked closed (see :hg:`commit --close-branch`).
1105
1105
1106 Use the command :hg:`update` to switch to an existing branch.
1106 Use the command :hg:`update` to switch to an existing branch.
1107
1107
1108 Returns 0.
1108 Returns 0.
1109 """
1109 """
1110
1110
1111 opts = pycompat.byteskwargs(opts)
1111 opts = pycompat.byteskwargs(opts)
1112 ui.pager('branches')
1112 ui.pager('branches')
1113 fm = ui.formatter('branches', opts)
1113 fm = ui.formatter('branches', opts)
1114 hexfunc = fm.hexfunc
1114 hexfunc = fm.hexfunc
1115
1115
1116 allheads = set(repo.heads())
1116 allheads = set(repo.heads())
1117 branches = []
1117 branches = []
1118 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1118 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1119 isactive = False
1119 isactive = False
1120 if not isclosed:
1120 if not isclosed:
1121 openheads = set(repo.branchmap().iteropen(heads))
1121 openheads = set(repo.branchmap().iteropen(heads))
1122 isactive = bool(openheads & allheads)
1122 isactive = bool(openheads & allheads)
1123 branches.append((tag, repo[tip], isactive, not isclosed))
1123 branches.append((tag, repo[tip], isactive, not isclosed))
1124 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1124 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1125 reverse=True)
1125 reverse=True)
1126
1126
1127 for tag, ctx, isactive, isopen in branches:
1127 for tag, ctx, isactive, isopen in branches:
1128 if active and not isactive:
1128 if active and not isactive:
1129 continue
1129 continue
1130 if isactive:
1130 if isactive:
1131 label = 'branches.active'
1131 label = 'branches.active'
1132 notice = ''
1132 notice = ''
1133 elif not isopen:
1133 elif not isopen:
1134 if not closed:
1134 if not closed:
1135 continue
1135 continue
1136 label = 'branches.closed'
1136 label = 'branches.closed'
1137 notice = _(' (closed)')
1137 notice = _(' (closed)')
1138 else:
1138 else:
1139 label = 'branches.inactive'
1139 label = 'branches.inactive'
1140 notice = _(' (inactive)')
1140 notice = _(' (inactive)')
1141 current = (tag == repo.dirstate.branch())
1141 current = (tag == repo.dirstate.branch())
1142 if current:
1142 if current:
1143 label = 'branches.current'
1143 label = 'branches.current'
1144
1144
1145 fm.startitem()
1145 fm.startitem()
1146 fm.write('branch', '%s', tag, label=label)
1146 fm.write('branch', '%s', tag, label=label)
1147 rev = ctx.rev()
1147 rev = ctx.rev()
1148 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1148 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1149 fmt = ' ' * padsize + ' %d:%s'
1149 fmt = ' ' * padsize + ' %d:%s'
1150 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1150 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1151 label='log.changeset changeset.%s' % ctx.phasestr())
1151 label='log.changeset changeset.%s' % ctx.phasestr())
1152 fm.context(ctx=ctx)
1152 fm.context(ctx=ctx)
1153 fm.data(active=isactive, closed=not isopen, current=current)
1153 fm.data(active=isactive, closed=not isopen, current=current)
1154 if not ui.quiet:
1154 if not ui.quiet:
1155 fm.plain(notice)
1155 fm.plain(notice)
1156 fm.plain('\n')
1156 fm.plain('\n')
1157 fm.end()
1157 fm.end()
1158
1158
1159 @command('bundle',
1159 @command('bundle',
1160 [('f', 'force', None, _('run even when the destination is unrelated')),
1160 [('f', 'force', None, _('run even when the destination is unrelated')),
1161 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1161 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1162 _('REV')),
1162 _('REV')),
1163 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1163 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1164 _('BRANCH')),
1164 _('BRANCH')),
1165 ('', 'base', [],
1165 ('', 'base', [],
1166 _('a base changeset assumed to be available at the destination'),
1166 _('a base changeset assumed to be available at the destination'),
1167 _('REV')),
1167 _('REV')),
1168 ('a', 'all', None, _('bundle all changesets in the repository')),
1168 ('a', 'all', None, _('bundle all changesets in the repository')),
1169 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1169 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1170 ] + remoteopts,
1170 ] + remoteopts,
1171 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1171 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1172 def bundle(ui, repo, fname, dest=None, **opts):
1172 def bundle(ui, repo, fname, dest=None, **opts):
1173 """create a bundle file
1173 """create a bundle file
1174
1174
1175 Generate a bundle file containing data to be transferred to another
1175 Generate a bundle file containing data to be transferred to another
1176 repository.
1176 repository.
1177
1177
1178 To create a bundle containing all changesets, use -a/--all
1178 To create a bundle containing all changesets, use -a/--all
1179 (or --base null). Otherwise, hg assumes the destination will have
1179 (or --base null). Otherwise, hg assumes the destination will have
1180 all the nodes you specify with --base parameters. Otherwise, hg
1180 all the nodes you specify with --base parameters. Otherwise, hg
1181 will assume the repository has all the nodes in destination, or
1181 will assume the repository has all the nodes in destination, or
1182 default-push/default if no destination is specified, where destination
1182 default-push/default if no destination is specified, where destination
1183 is the repository you provide through DEST option.
1183 is the repository you provide through DEST option.
1184
1184
1185 You can change bundle format with the -t/--type option. See
1185 You can change bundle format with the -t/--type option. See
1186 :hg:`help bundlespec` for documentation on this format. By default,
1186 :hg:`help bundlespec` for documentation on this format. By default,
1187 the most appropriate format is used and compression defaults to
1187 the most appropriate format is used and compression defaults to
1188 bzip2.
1188 bzip2.
1189
1189
1190 The bundle file can then be transferred using conventional means
1190 The bundle file can then be transferred using conventional means
1191 and applied to another repository with the unbundle or pull
1191 and applied to another repository with the unbundle or pull
1192 command. This is useful when direct push and pull are not
1192 command. This is useful when direct push and pull are not
1193 available or when exporting an entire repository is undesirable.
1193 available or when exporting an entire repository is undesirable.
1194
1194
1195 Applying bundles preserves all changeset contents including
1195 Applying bundles preserves all changeset contents including
1196 permissions, copy/rename information, and revision history.
1196 permissions, copy/rename information, and revision history.
1197
1197
1198 Returns 0 on success, 1 if no changes found.
1198 Returns 0 on success, 1 if no changes found.
1199 """
1199 """
1200 opts = pycompat.byteskwargs(opts)
1200 opts = pycompat.byteskwargs(opts)
1201 revs = None
1201 revs = None
1202 if 'rev' in opts:
1202 if 'rev' in opts:
1203 revstrings = opts['rev']
1203 revstrings = opts['rev']
1204 revs = scmutil.revrange(repo, revstrings)
1204 revs = scmutil.revrange(repo, revstrings)
1205 if revstrings and not revs:
1205 if revstrings and not revs:
1206 raise error.Abort(_('no commits to bundle'))
1206 raise error.Abort(_('no commits to bundle'))
1207
1207
1208 bundletype = opts.get('type', 'bzip2').lower()
1208 bundletype = opts.get('type', 'bzip2').lower()
1209 try:
1209 try:
1210 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1210 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1211 except error.UnsupportedBundleSpecification as e:
1211 except error.UnsupportedBundleSpecification as e:
1212 raise error.Abort(pycompat.bytestr(e),
1212 raise error.Abort(pycompat.bytestr(e),
1213 hint=_("see 'hg help bundlespec' for supported "
1213 hint=_("see 'hg help bundlespec' for supported "
1214 "values for --type"))
1214 "values for --type"))
1215 cgversion = bundlespec.contentopts["cg.version"]
1215 cgversion = bundlespec.contentopts["cg.version"]
1216
1216
1217 # Packed bundles are a pseudo bundle format for now.
1217 # Packed bundles are a pseudo bundle format for now.
1218 if cgversion == 's1':
1218 if cgversion == 's1':
1219 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1219 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1220 hint=_("use 'hg debugcreatestreamclonebundle'"))
1220 hint=_("use 'hg debugcreatestreamclonebundle'"))
1221
1221
1222 if opts.get('all'):
1222 if opts.get('all'):
1223 if dest:
1223 if dest:
1224 raise error.Abort(_("--all is incompatible with specifying "
1224 raise error.Abort(_("--all is incompatible with specifying "
1225 "a destination"))
1225 "a destination"))
1226 if opts.get('base'):
1226 if opts.get('base'):
1227 ui.warn(_("ignoring --base because --all was specified\n"))
1227 ui.warn(_("ignoring --base because --all was specified\n"))
1228 base = [nullrev]
1228 base = [nullrev]
1229 else:
1229 else:
1230 base = scmutil.revrange(repo, opts.get('base'))
1230 base = scmutil.revrange(repo, opts.get('base'))
1231 if cgversion not in changegroup.supportedoutgoingversions(repo):
1231 if cgversion not in changegroup.supportedoutgoingversions(repo):
1232 raise error.Abort(_("repository does not support bundle version %s") %
1232 raise error.Abort(_("repository does not support bundle version %s") %
1233 cgversion)
1233 cgversion)
1234
1234
1235 if base:
1235 if base:
1236 if dest:
1236 if dest:
1237 raise error.Abort(_("--base is incompatible with specifying "
1237 raise error.Abort(_("--base is incompatible with specifying "
1238 "a destination"))
1238 "a destination"))
1239 common = [repo[rev].node() for rev in base]
1239 common = [repo[rev].node() for rev in base]
1240 heads = [repo[r].node() for r in revs] if revs else None
1240 heads = [repo[r].node() for r in revs] if revs else None
1241 outgoing = discovery.outgoing(repo, common, heads)
1241 outgoing = discovery.outgoing(repo, common, heads)
1242 else:
1242 else:
1243 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1243 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1244 dest, branches = hg.parseurl(dest, opts.get('branch'))
1244 dest, branches = hg.parseurl(dest, opts.get('branch'))
1245 other = hg.peer(repo, opts, dest)
1245 other = hg.peer(repo, opts, dest)
1246 revs = [repo[r].hex() for r in revs]
1246 revs = [repo[r].hex() for r in revs]
1247 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1247 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1248 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1248 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1249 outgoing = discovery.findcommonoutgoing(repo, other,
1249 outgoing = discovery.findcommonoutgoing(repo, other,
1250 onlyheads=heads,
1250 onlyheads=heads,
1251 force=opts.get('force'),
1251 force=opts.get('force'),
1252 portable=True)
1252 portable=True)
1253
1253
1254 if not outgoing.missing:
1254 if not outgoing.missing:
1255 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1255 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1256 return 1
1256 return 1
1257
1257
1258 if cgversion == '01': #bundle1
1258 if cgversion == '01': #bundle1
1259 bversion = 'HG10' + bundlespec.wirecompression
1259 bversion = 'HG10' + bundlespec.wirecompression
1260 bcompression = None
1260 bcompression = None
1261 elif cgversion in ('02', '03'):
1261 elif cgversion in ('02', '03'):
1262 bversion = 'HG20'
1262 bversion = 'HG20'
1263 bcompression = bundlespec.wirecompression
1263 bcompression = bundlespec.wirecompression
1264 else:
1264 else:
1265 raise error.ProgrammingError(
1265 raise error.ProgrammingError(
1266 'bundle: unexpected changegroup version %s' % cgversion)
1266 'bundle: unexpected changegroup version %s' % cgversion)
1267
1267
1268 # TODO compression options should be derived from bundlespec parsing.
1268 # TODO compression options should be derived from bundlespec parsing.
1269 # This is a temporary hack to allow adjusting bundle compression
1269 # This is a temporary hack to allow adjusting bundle compression
1270 # level without a) formalizing the bundlespec changes to declare it
1270 # level without a) formalizing the bundlespec changes to declare it
1271 # b) introducing a command flag.
1271 # b) introducing a command flag.
1272 compopts = {}
1272 compopts = {}
1273 complevel = ui.configint('experimental',
1273 complevel = ui.configint('experimental',
1274 'bundlecomplevel.' + bundlespec.compression)
1274 'bundlecomplevel.' + bundlespec.compression)
1275 if complevel is None:
1275 if complevel is None:
1276 complevel = ui.configint('experimental', 'bundlecomplevel')
1276 complevel = ui.configint('experimental', 'bundlecomplevel')
1277 if complevel is not None:
1277 if complevel is not None:
1278 compopts['level'] = complevel
1278 compopts['level'] = complevel
1279
1279
1280 # Allow overriding the bundling of obsmarker in phases through
1280 # Allow overriding the bundling of obsmarker in phases through
1281 # configuration while we don't have a bundle version that include them
1281 # configuration while we don't have a bundle version that include them
1282 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1282 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1283 bundlespec.contentopts['obsolescence'] = True
1283 bundlespec.contentopts['obsolescence'] = True
1284 if repo.ui.configbool('experimental', 'bundle-phases'):
1284 if repo.ui.configbool('experimental', 'bundle-phases'):
1285 bundlespec.contentopts['phases'] = True
1285 bundlespec.contentopts['phases'] = True
1286
1286
1287 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1287 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1288 bundlespec.contentopts, compression=bcompression,
1288 bundlespec.contentopts, compression=bcompression,
1289 compopts=compopts)
1289 compopts=compopts)
1290
1290
1291 @command('cat',
1291 @command('cat',
1292 [('o', 'output', '',
1292 [('o', 'output', '',
1293 _('print output to file with formatted name'), _('FORMAT')),
1293 _('print output to file with formatted name'), _('FORMAT')),
1294 ('r', 'rev', '', _('print the given revision'), _('REV')),
1294 ('r', 'rev', '', _('print the given revision'), _('REV')),
1295 ('', 'decode', None, _('apply any matching decode filter')),
1295 ('', 'decode', None, _('apply any matching decode filter')),
1296 ] + walkopts + formatteropts,
1296 ] + walkopts + formatteropts,
1297 _('[OPTION]... FILE...'),
1297 _('[OPTION]... FILE...'),
1298 inferrepo=True,
1298 inferrepo=True,
1299 intents={INTENT_READONLY})
1299 intents={INTENT_READONLY})
1300 def cat(ui, repo, file1, *pats, **opts):
1300 def cat(ui, repo, file1, *pats, **opts):
1301 """output the current or given revision of files
1301 """output the current or given revision of files
1302
1302
1303 Print the specified files as they were at the given revision. If
1303 Print the specified files as they were at the given revision. If
1304 no revision is given, the parent of the working directory is used.
1304 no revision is given, the parent of the working directory is used.
1305
1305
1306 Output may be to a file, in which case the name of the file is
1306 Output may be to a file, in which case the name of the file is
1307 given using a template string. See :hg:`help templates`. In addition
1307 given using a template string. See :hg:`help templates`. In addition
1308 to the common template keywords, the following formatting rules are
1308 to the common template keywords, the following formatting rules are
1309 supported:
1309 supported:
1310
1310
1311 :``%%``: literal "%" character
1311 :``%%``: literal "%" character
1312 :``%s``: basename of file being printed
1312 :``%s``: basename of file being printed
1313 :``%d``: dirname of file being printed, or '.' if in repository root
1313 :``%d``: dirname of file being printed, or '.' if in repository root
1314 :``%p``: root-relative path name of file being printed
1314 :``%p``: root-relative path name of file being printed
1315 :``%H``: changeset hash (40 hexadecimal digits)
1315 :``%H``: changeset hash (40 hexadecimal digits)
1316 :``%R``: changeset revision number
1316 :``%R``: changeset revision number
1317 :``%h``: short-form changeset hash (12 hexadecimal digits)
1317 :``%h``: short-form changeset hash (12 hexadecimal digits)
1318 :``%r``: zero-padded changeset revision number
1318 :``%r``: zero-padded changeset revision number
1319 :``%b``: basename of the exporting repository
1319 :``%b``: basename of the exporting repository
1320 :``\\``: literal "\\" character
1320 :``\\``: literal "\\" character
1321
1321
1322 Returns 0 on success.
1322 Returns 0 on success.
1323 """
1323 """
1324 opts = pycompat.byteskwargs(opts)
1324 opts = pycompat.byteskwargs(opts)
1325 rev = opts.get('rev')
1325 rev = opts.get('rev')
1326 if rev:
1326 if rev:
1327 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1327 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1328 ctx = scmutil.revsingle(repo, rev)
1328 ctx = scmutil.revsingle(repo, rev)
1329 m = scmutil.match(ctx, (file1,) + pats, opts)
1329 m = scmutil.match(ctx, (file1,) + pats, opts)
1330 fntemplate = opts.pop('output', '')
1330 fntemplate = opts.pop('output', '')
1331 if cmdutil.isstdiofilename(fntemplate):
1331 if cmdutil.isstdiofilename(fntemplate):
1332 fntemplate = ''
1332 fntemplate = ''
1333
1333
1334 if fntemplate:
1334 if fntemplate:
1335 fm = formatter.nullformatter(ui, 'cat', opts)
1335 fm = formatter.nullformatter(ui, 'cat', opts)
1336 else:
1336 else:
1337 ui.pager('cat')
1337 ui.pager('cat')
1338 fm = ui.formatter('cat', opts)
1338 fm = ui.formatter('cat', opts)
1339 with fm:
1339 with fm:
1340 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1340 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1341 **pycompat.strkwargs(opts))
1341 **pycompat.strkwargs(opts))
1342
1342
1343 @command('^clone',
1343 @command('^clone',
1344 [('U', 'noupdate', None, _('the clone will include an empty working '
1344 [('U', 'noupdate', None, _('the clone will include an empty working '
1345 'directory (only a repository)')),
1345 'directory (only a repository)')),
1346 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1346 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1347 _('REV')),
1347 _('REV')),
1348 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1348 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1349 ' and its ancestors'), _('REV')),
1349 ' and its ancestors'), _('REV')),
1350 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1350 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1351 ' changesets and their ancestors'), _('BRANCH')),
1351 ' changesets and their ancestors'), _('BRANCH')),
1352 ('', 'pull', None, _('use pull protocol to copy metadata')),
1352 ('', 'pull', None, _('use pull protocol to copy metadata')),
1353 ('', 'uncompressed', None,
1353 ('', 'uncompressed', None,
1354 _('an alias to --stream (DEPRECATED)')),
1354 _('an alias to --stream (DEPRECATED)')),
1355 ('', 'stream', None,
1355 ('', 'stream', None,
1356 _('clone with minimal data processing')),
1356 _('clone with minimal data processing')),
1357 ] + remoteopts,
1357 ] + remoteopts,
1358 _('[OPTION]... SOURCE [DEST]'),
1358 _('[OPTION]... SOURCE [DEST]'),
1359 norepo=True)
1359 norepo=True)
1360 def clone(ui, source, dest=None, **opts):
1360 def clone(ui, source, dest=None, **opts):
1361 """make a copy of an existing repository
1361 """make a copy of an existing repository
1362
1362
1363 Create a copy of an existing repository in a new directory.
1363 Create a copy of an existing repository in a new directory.
1364
1364
1365 If no destination directory name is specified, it defaults to the
1365 If no destination directory name is specified, it defaults to the
1366 basename of the source.
1366 basename of the source.
1367
1367
1368 The location of the source is added to the new repository's
1368 The location of the source is added to the new repository's
1369 ``.hg/hgrc`` file, as the default to be used for future pulls.
1369 ``.hg/hgrc`` file, as the default to be used for future pulls.
1370
1370
1371 Only local paths and ``ssh://`` URLs are supported as
1371 Only local paths and ``ssh://`` URLs are supported as
1372 destinations. For ``ssh://`` destinations, no working directory or
1372 destinations. For ``ssh://`` destinations, no working directory or
1373 ``.hg/hgrc`` will be created on the remote side.
1373 ``.hg/hgrc`` will be created on the remote side.
1374
1374
1375 If the source repository has a bookmark called '@' set, that
1375 If the source repository has a bookmark called '@' set, that
1376 revision will be checked out in the new repository by default.
1376 revision will be checked out in the new repository by default.
1377
1377
1378 To check out a particular version, use -u/--update, or
1378 To check out a particular version, use -u/--update, or
1379 -U/--noupdate to create a clone with no working directory.
1379 -U/--noupdate to create a clone with no working directory.
1380
1380
1381 To pull only a subset of changesets, specify one or more revisions
1381 To pull only a subset of changesets, specify one or more revisions
1382 identifiers with -r/--rev or branches with -b/--branch. The
1382 identifiers with -r/--rev or branches with -b/--branch. The
1383 resulting clone will contain only the specified changesets and
1383 resulting clone will contain only the specified changesets and
1384 their ancestors. These options (or 'clone src#rev dest') imply
1384 their ancestors. These options (or 'clone src#rev dest') imply
1385 --pull, even for local source repositories.
1385 --pull, even for local source repositories.
1386
1386
1387 In normal clone mode, the remote normalizes repository data into a common
1387 In normal clone mode, the remote normalizes repository data into a common
1388 exchange format and the receiving end translates this data into its local
1388 exchange format and the receiving end translates this data into its local
1389 storage format. --stream activates a different clone mode that essentially
1389 storage format. --stream activates a different clone mode that essentially
1390 copies repository files from the remote with minimal data processing. This
1390 copies repository files from the remote with minimal data processing. This
1391 significantly reduces the CPU cost of a clone both remotely and locally.
1391 significantly reduces the CPU cost of a clone both remotely and locally.
1392 However, it often increases the transferred data size by 30-40%. This can
1392 However, it often increases the transferred data size by 30-40%. This can
1393 result in substantially faster clones where I/O throughput is plentiful,
1393 result in substantially faster clones where I/O throughput is plentiful,
1394 especially for larger repositories. A side-effect of --stream clones is
1394 especially for larger repositories. A side-effect of --stream clones is
1395 that storage settings and requirements on the remote are applied locally:
1395 that storage settings and requirements on the remote are applied locally:
1396 a modern client may inherit legacy or inefficient storage used by the
1396 a modern client may inherit legacy or inefficient storage used by the
1397 remote or a legacy Mercurial client may not be able to clone from a
1397 remote or a legacy Mercurial client may not be able to clone from a
1398 modern Mercurial remote.
1398 modern Mercurial remote.
1399
1399
1400 .. note::
1400 .. note::
1401
1401
1402 Specifying a tag will include the tagged changeset but not the
1402 Specifying a tag will include the tagged changeset but not the
1403 changeset containing the tag.
1403 changeset containing the tag.
1404
1404
1405 .. container:: verbose
1405 .. container:: verbose
1406
1406
1407 For efficiency, hardlinks are used for cloning whenever the
1407 For efficiency, hardlinks are used for cloning whenever the
1408 source and destination are on the same filesystem (note this
1408 source and destination are on the same filesystem (note this
1409 applies only to the repository data, not to the working
1409 applies only to the repository data, not to the working
1410 directory). Some filesystems, such as AFS, implement hardlinking
1410 directory). Some filesystems, such as AFS, implement hardlinking
1411 incorrectly, but do not report errors. In these cases, use the
1411 incorrectly, but do not report errors. In these cases, use the
1412 --pull option to avoid hardlinking.
1412 --pull option to avoid hardlinking.
1413
1413
1414 Mercurial will update the working directory to the first applicable
1414 Mercurial will update the working directory to the first applicable
1415 revision from this list:
1415 revision from this list:
1416
1416
1417 a) null if -U or the source repository has no changesets
1417 a) null if -U or the source repository has no changesets
1418 b) if -u . and the source repository is local, the first parent of
1418 b) if -u . and the source repository is local, the first parent of
1419 the source repository's working directory
1419 the source repository's working directory
1420 c) the changeset specified with -u (if a branch name, this means the
1420 c) the changeset specified with -u (if a branch name, this means the
1421 latest head of that branch)
1421 latest head of that branch)
1422 d) the changeset specified with -r
1422 d) the changeset specified with -r
1423 e) the tipmost head specified with -b
1423 e) the tipmost head specified with -b
1424 f) the tipmost head specified with the url#branch source syntax
1424 f) the tipmost head specified with the url#branch source syntax
1425 g) the revision marked with the '@' bookmark, if present
1425 g) the revision marked with the '@' bookmark, if present
1426 h) the tipmost head of the default branch
1426 h) the tipmost head of the default branch
1427 i) tip
1427 i) tip
1428
1428
1429 When cloning from servers that support it, Mercurial may fetch
1429 When cloning from servers that support it, Mercurial may fetch
1430 pre-generated data from a server-advertised URL or inline from the
1430 pre-generated data from a server-advertised URL or inline from the
1431 same stream. When this is done, hooks operating on incoming changesets
1431 same stream. When this is done, hooks operating on incoming changesets
1432 and changegroups may fire more than once, once for each pre-generated
1432 and changegroups may fire more than once, once for each pre-generated
1433 bundle and as well as for any additional remaining data. In addition,
1433 bundle and as well as for any additional remaining data. In addition,
1434 if an error occurs, the repository may be rolled back to a partial
1434 if an error occurs, the repository may be rolled back to a partial
1435 clone. This behavior may change in future releases.
1435 clone. This behavior may change in future releases.
1436 See :hg:`help -e clonebundles` for more.
1436 See :hg:`help -e clonebundles` for more.
1437
1437
1438 Examples:
1438 Examples:
1439
1439
1440 - clone a remote repository to a new directory named hg/::
1440 - clone a remote repository to a new directory named hg/::
1441
1441
1442 hg clone https://www.mercurial-scm.org/repo/hg/
1442 hg clone https://www.mercurial-scm.org/repo/hg/
1443
1443
1444 - create a lightweight local clone::
1444 - create a lightweight local clone::
1445
1445
1446 hg clone project/ project-feature/
1446 hg clone project/ project-feature/
1447
1447
1448 - clone from an absolute path on an ssh server (note double-slash)::
1448 - clone from an absolute path on an ssh server (note double-slash)::
1449
1449
1450 hg clone ssh://user@server//home/projects/alpha/
1450 hg clone ssh://user@server//home/projects/alpha/
1451
1451
1452 - do a streaming clone while checking out a specified version::
1452 - do a streaming clone while checking out a specified version::
1453
1453
1454 hg clone --stream http://server/repo -u 1.5
1454 hg clone --stream http://server/repo -u 1.5
1455
1455
1456 - create a repository without changesets after a particular revision::
1456 - create a repository without changesets after a particular revision::
1457
1457
1458 hg clone -r 04e544 experimental/ good/
1458 hg clone -r 04e544 experimental/ good/
1459
1459
1460 - clone (and track) a particular named branch::
1460 - clone (and track) a particular named branch::
1461
1461
1462 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1462 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1463
1463
1464 See :hg:`help urls` for details on specifying URLs.
1464 See :hg:`help urls` for details on specifying URLs.
1465
1465
1466 Returns 0 on success.
1466 Returns 0 on success.
1467 """
1467 """
1468 opts = pycompat.byteskwargs(opts)
1468 opts = pycompat.byteskwargs(opts)
1469 if opts.get('noupdate') and opts.get('updaterev'):
1469 if opts.get('noupdate') and opts.get('updaterev'):
1470 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1470 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1471
1471
1472 # --include/--exclude can come from narrow or sparse.
1472 # --include/--exclude can come from narrow or sparse.
1473 includepats, excludepats = None, None
1473 includepats, excludepats = None, None
1474
1474
1475 # hg.clone() differentiates between None and an empty set. So make sure
1475 # hg.clone() differentiates between None and an empty set. So make sure
1476 # patterns are sets if narrow is requested without patterns.
1476 # patterns are sets if narrow is requested without patterns.
1477 if opts.get('narrow'):
1477 if opts.get('narrow'):
1478 includepats = set()
1478 includepats = set()
1479 excludepats = set()
1479 excludepats = set()
1480
1480
1481 if opts.get('include'):
1481 if opts.get('include'):
1482 includepats = narrowspec.parsepatterns(opts.get('include'))
1482 includepats = narrowspec.parsepatterns(opts.get('include'))
1483 if opts.get('exclude'):
1483 if opts.get('exclude'):
1484 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1484 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1485
1485
1486 r = hg.clone(ui, opts, source, dest,
1486 r = hg.clone(ui, opts, source, dest,
1487 pull=opts.get('pull'),
1487 pull=opts.get('pull'),
1488 stream=opts.get('stream') or opts.get('uncompressed'),
1488 stream=opts.get('stream') or opts.get('uncompressed'),
1489 revs=opts.get('rev'),
1489 revs=opts.get('rev'),
1490 update=opts.get('updaterev') or not opts.get('noupdate'),
1490 update=opts.get('updaterev') or not opts.get('noupdate'),
1491 branch=opts.get('branch'),
1491 branch=opts.get('branch'),
1492 shareopts=opts.get('shareopts'),
1492 shareopts=opts.get('shareopts'),
1493 storeincludepats=includepats,
1493 storeincludepats=includepats,
1494 storeexcludepats=excludepats)
1494 storeexcludepats=excludepats)
1495
1495
1496 return r is None
1496 return r is None
1497
1497
1498 @command('^commit|ci',
1498 @command('^commit|ci',
1499 [('A', 'addremove', None,
1499 [('A', 'addremove', None,
1500 _('mark new/missing files as added/removed before committing')),
1500 _('mark new/missing files as added/removed before committing')),
1501 ('', 'close-branch', None,
1501 ('', 'close-branch', None,
1502 _('mark a branch head as closed')),
1502 _('mark a branch head as closed')),
1503 ('', 'amend', None, _('amend the parent of the working directory')),
1503 ('', 'amend', None, _('amend the parent of the working directory')),
1504 ('s', 'secret', None, _('use the secret phase for committing')),
1504 ('s', 'secret', None, _('use the secret phase for committing')),
1505 ('e', 'edit', None, _('invoke editor on commit messages')),
1505 ('e', 'edit', None, _('invoke editor on commit messages')),
1506 ('i', 'interactive', None, _('use interactive mode')),
1506 ('i', 'interactive', None, _('use interactive mode')),
1507 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1507 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1508 _('[OPTION]... [FILE]...'),
1508 _('[OPTION]... [FILE]...'),
1509 inferrepo=True)
1509 inferrepo=True)
1510 def commit(ui, repo, *pats, **opts):
1510 def commit(ui, repo, *pats, **opts):
1511 """commit the specified files or all outstanding changes
1511 """commit the specified files or all outstanding changes
1512
1512
1513 Commit changes to the given files into the repository. Unlike a
1513 Commit changes to the given files into the repository. Unlike a
1514 centralized SCM, this operation is a local operation. See
1514 centralized SCM, this operation is a local operation. See
1515 :hg:`push` for a way to actively distribute your changes.
1515 :hg:`push` for a way to actively distribute your changes.
1516
1516
1517 If a list of files is omitted, all changes reported by :hg:`status`
1517 If a list of files is omitted, all changes reported by :hg:`status`
1518 will be committed.
1518 will be committed.
1519
1519
1520 If you are committing the result of a merge, do not provide any
1520 If you are committing the result of a merge, do not provide any
1521 filenames or -I/-X filters.
1521 filenames or -I/-X filters.
1522
1522
1523 If no commit message is specified, Mercurial starts your
1523 If no commit message is specified, Mercurial starts your
1524 configured editor where you can enter a message. In case your
1524 configured editor where you can enter a message. In case your
1525 commit fails, you will find a backup of your message in
1525 commit fails, you will find a backup of your message in
1526 ``.hg/last-message.txt``.
1526 ``.hg/last-message.txt``.
1527
1527
1528 The --close-branch flag can be used to mark the current branch
1528 The --close-branch flag can be used to mark the current branch
1529 head closed. When all heads of a branch are closed, the branch
1529 head closed. When all heads of a branch are closed, the branch
1530 will be considered closed and no longer listed.
1530 will be considered closed and no longer listed.
1531
1531
1532 The --amend flag can be used to amend the parent of the
1532 The --amend flag can be used to amend the parent of the
1533 working directory with a new commit that contains the changes
1533 working directory with a new commit that contains the changes
1534 in the parent in addition to those currently reported by :hg:`status`,
1534 in the parent in addition to those currently reported by :hg:`status`,
1535 if there are any. The old commit is stored in a backup bundle in
1535 if there are any. The old commit is stored in a backup bundle in
1536 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1536 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1537 on how to restore it).
1537 on how to restore it).
1538
1538
1539 Message, user and date are taken from the amended commit unless
1539 Message, user and date are taken from the amended commit unless
1540 specified. When a message isn't specified on the command line,
1540 specified. When a message isn't specified on the command line,
1541 the editor will open with the message of the amended commit.
1541 the editor will open with the message of the amended commit.
1542
1542
1543 It is not possible to amend public changesets (see :hg:`help phases`)
1543 It is not possible to amend public changesets (see :hg:`help phases`)
1544 or changesets that have children.
1544 or changesets that have children.
1545
1545
1546 See :hg:`help dates` for a list of formats valid for -d/--date.
1546 See :hg:`help dates` for a list of formats valid for -d/--date.
1547
1547
1548 Returns 0 on success, 1 if nothing changed.
1548 Returns 0 on success, 1 if nothing changed.
1549
1549
1550 .. container:: verbose
1550 .. container:: verbose
1551
1551
1552 Examples:
1552 Examples:
1553
1553
1554 - commit all files ending in .py::
1554 - commit all files ending in .py::
1555
1555
1556 hg commit --include "set:**.py"
1556 hg commit --include "set:**.py"
1557
1557
1558 - commit all non-binary files::
1558 - commit all non-binary files::
1559
1559
1560 hg commit --exclude "set:binary()"
1560 hg commit --exclude "set:binary()"
1561
1561
1562 - amend the current commit and set the date to now::
1562 - amend the current commit and set the date to now::
1563
1563
1564 hg commit --amend --date now
1564 hg commit --amend --date now
1565 """
1565 """
1566 with repo.wlock(), repo.lock():
1566 with repo.wlock(), repo.lock():
1567 return _docommit(ui, repo, *pats, **opts)
1567 return _docommit(ui, repo, *pats, **opts)
1568
1568
1569 def _docommit(ui, repo, *pats, **opts):
1569 def _docommit(ui, repo, *pats, **opts):
1570 if opts.get(r'interactive'):
1570 if opts.get(r'interactive'):
1571 opts.pop(r'interactive')
1571 opts.pop(r'interactive')
1572 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1572 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1573 cmdutil.recordfilter, *pats,
1573 cmdutil.recordfilter, *pats,
1574 **opts)
1574 **opts)
1575 # ret can be 0 (no changes to record) or the value returned by
1575 # ret can be 0 (no changes to record) or the value returned by
1576 # commit(), 1 if nothing changed or None on success.
1576 # commit(), 1 if nothing changed or None on success.
1577 return 1 if ret == 0 else ret
1577 return 1 if ret == 0 else ret
1578
1578
1579 opts = pycompat.byteskwargs(opts)
1579 opts = pycompat.byteskwargs(opts)
1580 if opts.get('subrepos'):
1580 if opts.get('subrepos'):
1581 if opts.get('amend'):
1581 if opts.get('amend'):
1582 raise error.Abort(_('cannot amend with --subrepos'))
1582 raise error.Abort(_('cannot amend with --subrepos'))
1583 # Let --subrepos on the command line override config setting.
1583 # Let --subrepos on the command line override config setting.
1584 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1584 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1585
1585
1586 cmdutil.checkunfinished(repo, commit=True)
1586 cmdutil.checkunfinished(repo, commit=True)
1587
1587
1588 branch = repo[None].branch()
1588 branch = repo[None].branch()
1589 bheads = repo.branchheads(branch)
1589 bheads = repo.branchheads(branch)
1590
1590
1591 extra = {}
1591 extra = {}
1592 if opts.get('close_branch'):
1592 if opts.get('close_branch'):
1593 extra['close'] = '1'
1593 extra['close'] = '1'
1594
1594
1595 if not bheads:
1595 if not bheads:
1596 raise error.Abort(_('can only close branch heads'))
1596 raise error.Abort(_('can only close branch heads'))
1597 elif opts.get('amend'):
1597 elif opts.get('amend'):
1598 if repo[None].parents()[0].p1().branch() != branch and \
1598 if repo[None].parents()[0].p1().branch() != branch and \
1599 repo[None].parents()[0].p2().branch() != branch:
1599 repo[None].parents()[0].p2().branch() != branch:
1600 raise error.Abort(_('can only close branch heads'))
1600 raise error.Abort(_('can only close branch heads'))
1601
1601
1602 if opts.get('amend'):
1602 if opts.get('amend'):
1603 if ui.configbool('ui', 'commitsubrepos'):
1603 if ui.configbool('ui', 'commitsubrepos'):
1604 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1604 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1605
1605
1606 old = repo['.']
1606 old = repo['.']
1607 rewriteutil.precheck(repo, [old.rev()], 'amend')
1607 rewriteutil.precheck(repo, [old.rev()], 'amend')
1608
1608
1609 # Currently histedit gets confused if an amend happens while histedit
1609 # Currently histedit gets confused if an amend happens while histedit
1610 # is in progress. Since we have a checkunfinished command, we are
1610 # is in progress. Since we have a checkunfinished command, we are
1611 # temporarily honoring it.
1611 # temporarily honoring it.
1612 #
1612 #
1613 # Note: eventually this guard will be removed. Please do not expect
1613 # Note: eventually this guard will be removed. Please do not expect
1614 # this behavior to remain.
1614 # this behavior to remain.
1615 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1615 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1616 cmdutil.checkunfinished(repo)
1616 cmdutil.checkunfinished(repo)
1617
1617
1618 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1618 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1619 if node == old.node():
1619 if node == old.node():
1620 ui.status(_("nothing changed\n"))
1620 ui.status(_("nothing changed\n"))
1621 return 1
1621 return 1
1622 else:
1622 else:
1623 def commitfunc(ui, repo, message, match, opts):
1623 def commitfunc(ui, repo, message, match, opts):
1624 overrides = {}
1624 overrides = {}
1625 if opts.get('secret'):
1625 if opts.get('secret'):
1626 overrides[('phases', 'new-commit')] = 'secret'
1626 overrides[('phases', 'new-commit')] = 'secret'
1627
1627
1628 baseui = repo.baseui
1628 baseui = repo.baseui
1629 with baseui.configoverride(overrides, 'commit'):
1629 with baseui.configoverride(overrides, 'commit'):
1630 with ui.configoverride(overrides, 'commit'):
1630 with ui.configoverride(overrides, 'commit'):
1631 editform = cmdutil.mergeeditform(repo[None],
1631 editform = cmdutil.mergeeditform(repo[None],
1632 'commit.normal')
1632 'commit.normal')
1633 editor = cmdutil.getcommiteditor(
1633 editor = cmdutil.getcommiteditor(
1634 editform=editform, **pycompat.strkwargs(opts))
1634 editform=editform, **pycompat.strkwargs(opts))
1635 return repo.commit(message,
1635 return repo.commit(message,
1636 opts.get('user'),
1636 opts.get('user'),
1637 opts.get('date'),
1637 opts.get('date'),
1638 match,
1638 match,
1639 editor=editor,
1639 editor=editor,
1640 extra=extra)
1640 extra=extra)
1641
1641
1642 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1642 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1643
1643
1644 if not node:
1644 if not node:
1645 stat = cmdutil.postcommitstatus(repo, pats, opts)
1645 stat = cmdutil.postcommitstatus(repo, pats, opts)
1646 if stat[3]:
1646 if stat[3]:
1647 ui.status(_("nothing changed (%d missing files, see "
1647 ui.status(_("nothing changed (%d missing files, see "
1648 "'hg status')\n") % len(stat[3]))
1648 "'hg status')\n") % len(stat[3]))
1649 else:
1649 else:
1650 ui.status(_("nothing changed\n"))
1650 ui.status(_("nothing changed\n"))
1651 return 1
1651 return 1
1652
1652
1653 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1653 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1654
1654
1655 @command('config|showconfig|debugconfig',
1655 @command('config|showconfig|debugconfig',
1656 [('u', 'untrusted', None, _('show untrusted configuration options')),
1656 [('u', 'untrusted', None, _('show untrusted configuration options')),
1657 ('e', 'edit', None, _('edit user config')),
1657 ('e', 'edit', None, _('edit user config')),
1658 ('l', 'local', None, _('edit repository config')),
1658 ('l', 'local', None, _('edit repository config')),
1659 ('g', 'global', None, _('edit global config'))] + formatteropts,
1659 ('g', 'global', None, _('edit global config'))] + formatteropts,
1660 _('[-u] [NAME]...'),
1660 _('[-u] [NAME]...'),
1661 optionalrepo=True,
1661 optionalrepo=True,
1662 intents={INTENT_READONLY})
1662 intents={INTENT_READONLY})
1663 def config(ui, repo, *values, **opts):
1663 def config(ui, repo, *values, **opts):
1664 """show combined config settings from all hgrc files
1664 """show combined config settings from all hgrc files
1665
1665
1666 With no arguments, print names and values of all config items.
1666 With no arguments, print names and values of all config items.
1667
1667
1668 With one argument of the form section.name, print just the value
1668 With one argument of the form section.name, print just the value
1669 of that config item.
1669 of that config item.
1670
1670
1671 With multiple arguments, print names and values of all config
1671 With multiple arguments, print names and values of all config
1672 items with matching section names or section.names.
1672 items with matching section names or section.names.
1673
1673
1674 With --edit, start an editor on the user-level config file. With
1674 With --edit, start an editor on the user-level config file. With
1675 --global, edit the system-wide config file. With --local, edit the
1675 --global, edit the system-wide config file. With --local, edit the
1676 repository-level config file.
1676 repository-level config file.
1677
1677
1678 With --debug, the source (filename and line number) is printed
1678 With --debug, the source (filename and line number) is printed
1679 for each config item.
1679 for each config item.
1680
1680
1681 See :hg:`help config` for more information about config files.
1681 See :hg:`help config` for more information about config files.
1682
1682
1683 Returns 0 on success, 1 if NAME does not exist.
1683 Returns 0 on success, 1 if NAME does not exist.
1684
1684
1685 """
1685 """
1686
1686
1687 opts = pycompat.byteskwargs(opts)
1687 opts = pycompat.byteskwargs(opts)
1688 if opts.get('edit') or opts.get('local') or opts.get('global'):
1688 if opts.get('edit') or opts.get('local') or opts.get('global'):
1689 if opts.get('local') and opts.get('global'):
1689 if opts.get('local') and opts.get('global'):
1690 raise error.Abort(_("can't use --local and --global together"))
1690 raise error.Abort(_("can't use --local and --global together"))
1691
1691
1692 if opts.get('local'):
1692 if opts.get('local'):
1693 if not repo:
1693 if not repo:
1694 raise error.Abort(_("can't use --local outside a repository"))
1694 raise error.Abort(_("can't use --local outside a repository"))
1695 paths = [repo.vfs.join('hgrc')]
1695 paths = [repo.vfs.join('hgrc')]
1696 elif opts.get('global'):
1696 elif opts.get('global'):
1697 paths = rcutil.systemrcpath()
1697 paths = rcutil.systemrcpath()
1698 else:
1698 else:
1699 paths = rcutil.userrcpath()
1699 paths = rcutil.userrcpath()
1700
1700
1701 for f in paths:
1701 for f in paths:
1702 if os.path.exists(f):
1702 if os.path.exists(f):
1703 break
1703 break
1704 else:
1704 else:
1705 if opts.get('global'):
1705 if opts.get('global'):
1706 samplehgrc = uimod.samplehgrcs['global']
1706 samplehgrc = uimod.samplehgrcs['global']
1707 elif opts.get('local'):
1707 elif opts.get('local'):
1708 samplehgrc = uimod.samplehgrcs['local']
1708 samplehgrc = uimod.samplehgrcs['local']
1709 else:
1709 else:
1710 samplehgrc = uimod.samplehgrcs['user']
1710 samplehgrc = uimod.samplehgrcs['user']
1711
1711
1712 f = paths[0]
1712 f = paths[0]
1713 fp = open(f, "wb")
1713 fp = open(f, "wb")
1714 fp.write(util.tonativeeol(samplehgrc))
1714 fp.write(util.tonativeeol(samplehgrc))
1715 fp.close()
1715 fp.close()
1716
1716
1717 editor = ui.geteditor()
1717 editor = ui.geteditor()
1718 ui.system("%s \"%s\"" % (editor, f),
1718 ui.system("%s \"%s\"" % (editor, f),
1719 onerr=error.Abort, errprefix=_("edit failed"),
1719 onerr=error.Abort, errprefix=_("edit failed"),
1720 blockedtag='config_edit')
1720 blockedtag='config_edit')
1721 return
1721 return
1722 ui.pager('config')
1722 ui.pager('config')
1723 fm = ui.formatter('config', opts)
1723 fm = ui.formatter('config', opts)
1724 for t, f in rcutil.rccomponents():
1724 for t, f in rcutil.rccomponents():
1725 if t == 'path':
1725 if t == 'path':
1726 ui.debug('read config from: %s\n' % f)
1726 ui.debug('read config from: %s\n' % f)
1727 elif t == 'items':
1727 elif t == 'items':
1728 for section, name, value, source in f:
1728 for section, name, value, source in f:
1729 ui.debug('set config by: %s\n' % source)
1729 ui.debug('set config by: %s\n' % source)
1730 else:
1730 else:
1731 raise error.ProgrammingError('unknown rctype: %s' % t)
1731 raise error.ProgrammingError('unknown rctype: %s' % t)
1732 untrusted = bool(opts.get('untrusted'))
1732 untrusted = bool(opts.get('untrusted'))
1733
1733
1734 selsections = selentries = []
1734 selsections = selentries = []
1735 if values:
1735 if values:
1736 selsections = [v for v in values if '.' not in v]
1736 selsections = [v for v in values if '.' not in v]
1737 selentries = [v for v in values if '.' in v]
1737 selentries = [v for v in values if '.' in v]
1738 uniquesel = (len(selentries) == 1 and not selsections)
1738 uniquesel = (len(selentries) == 1 and not selsections)
1739 selsections = set(selsections)
1739 selsections = set(selsections)
1740 selentries = set(selentries)
1740 selentries = set(selentries)
1741
1741
1742 matched = False
1742 matched = False
1743 for section, name, value in ui.walkconfig(untrusted=untrusted):
1743 for section, name, value in ui.walkconfig(untrusted=untrusted):
1744 source = ui.configsource(section, name, untrusted)
1744 source = ui.configsource(section, name, untrusted)
1745 value = pycompat.bytestr(value)
1745 value = pycompat.bytestr(value)
1746 if fm.isplain():
1746 if fm.isplain():
1747 source = source or 'none'
1747 source = source or 'none'
1748 value = value.replace('\n', '\\n')
1748 value = value.replace('\n', '\\n')
1749 entryname = section + '.' + name
1749 entryname = section + '.' + name
1750 if values and not (section in selsections or entryname in selentries):
1750 if values and not (section in selsections or entryname in selentries):
1751 continue
1751 continue
1752 fm.startitem()
1752 fm.startitem()
1753 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1753 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1754 if uniquesel:
1754 if uniquesel:
1755 fm.data(name=entryname)
1755 fm.data(name=entryname)
1756 fm.write('value', '%s\n', value)
1756 fm.write('value', '%s\n', value)
1757 else:
1757 else:
1758 fm.write('name value', '%s=%s\n', entryname, value)
1758 fm.write('name value', '%s=%s\n', entryname, value)
1759 matched = True
1759 matched = True
1760 fm.end()
1760 fm.end()
1761 if matched:
1761 if matched:
1762 return 0
1762 return 0
1763 return 1
1763 return 1
1764
1764
1765 @command('copy|cp',
1765 @command('copy|cp',
1766 [('A', 'after', None, _('record a copy that has already occurred')),
1766 [('A', 'after', None, _('record a copy that has already occurred')),
1767 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1767 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1768 ] + walkopts + dryrunopts,
1768 ] + walkopts + dryrunopts,
1769 _('[OPTION]... [SOURCE]... DEST'))
1769 _('[OPTION]... [SOURCE]... DEST'))
1770 def copy(ui, repo, *pats, **opts):
1770 def copy(ui, repo, *pats, **opts):
1771 """mark files as copied for the next commit
1771 """mark files as copied for the next commit
1772
1772
1773 Mark dest as having copies of source files. If dest is a
1773 Mark dest as having copies of source files. If dest is a
1774 directory, copies are put in that directory. If dest is a file,
1774 directory, copies are put in that directory. If dest is a file,
1775 the source must be a single file.
1775 the source must be a single file.
1776
1776
1777 By default, this command copies the contents of files as they
1777 By default, this command copies the contents of files as they
1778 exist in the working directory. If invoked with -A/--after, the
1778 exist in the working directory. If invoked with -A/--after, the
1779 operation is recorded, but no copying is performed.
1779 operation is recorded, but no copying is performed.
1780
1780
1781 This command takes effect with the next commit. To undo a copy
1781 This command takes effect with the next commit. To undo a copy
1782 before that, see :hg:`revert`.
1782 before that, see :hg:`revert`.
1783
1783
1784 Returns 0 on success, 1 if errors are encountered.
1784 Returns 0 on success, 1 if errors are encountered.
1785 """
1785 """
1786 opts = pycompat.byteskwargs(opts)
1786 opts = pycompat.byteskwargs(opts)
1787 with repo.wlock(False):
1787 with repo.wlock(False):
1788 return cmdutil.copy(ui, repo, pats, opts)
1788 return cmdutil.copy(ui, repo, pats, opts)
1789
1789
1790 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1790 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1791 def debugcommands(ui, cmd='', *args):
1791 def debugcommands(ui, cmd='', *args):
1792 """list all available commands and options"""
1792 """list all available commands and options"""
1793 for cmd, vals in sorted(table.iteritems()):
1793 for cmd, vals in sorted(table.iteritems()):
1794 cmd = cmd.split('|')[0].strip('^')
1794 cmd = cmd.split('|')[0].strip('^')
1795 opts = ', '.join([i[1] for i in vals[1]])
1795 opts = ', '.join([i[1] for i in vals[1]])
1796 ui.write('%s: %s\n' % (cmd, opts))
1796 ui.write('%s: %s\n' % (cmd, opts))
1797
1797
1798 @command('debugcomplete',
1798 @command('debugcomplete',
1799 [('o', 'options', None, _('show the command options'))],
1799 [('o', 'options', None, _('show the command options'))],
1800 _('[-o] CMD'),
1800 _('[-o] CMD'),
1801 norepo=True)
1801 norepo=True)
1802 def debugcomplete(ui, cmd='', **opts):
1802 def debugcomplete(ui, cmd='', **opts):
1803 """returns the completion list associated with the given command"""
1803 """returns the completion list associated with the given command"""
1804
1804
1805 if opts.get(r'options'):
1805 if opts.get(r'options'):
1806 options = []
1806 options = []
1807 otables = [globalopts]
1807 otables = [globalopts]
1808 if cmd:
1808 if cmd:
1809 aliases, entry = cmdutil.findcmd(cmd, table, False)
1809 aliases, entry = cmdutil.findcmd(cmd, table, False)
1810 otables.append(entry[1])
1810 otables.append(entry[1])
1811 for t in otables:
1811 for t in otables:
1812 for o in t:
1812 for o in t:
1813 if "(DEPRECATED)" in o[3]:
1813 if "(DEPRECATED)" in o[3]:
1814 continue
1814 continue
1815 if o[0]:
1815 if o[0]:
1816 options.append('-%s' % o[0])
1816 options.append('-%s' % o[0])
1817 options.append('--%s' % o[1])
1817 options.append('--%s' % o[1])
1818 ui.write("%s\n" % "\n".join(options))
1818 ui.write("%s\n" % "\n".join(options))
1819 return
1819 return
1820
1820
1821 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1821 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1822 if ui.verbose:
1822 if ui.verbose:
1823 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1823 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1824 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1824 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1825
1825
1826 @command('^diff',
1826 @command('^diff',
1827 [('r', 'rev', [], _('revision'), _('REV')),
1827 [('r', 'rev', [], _('revision'), _('REV')),
1828 ('c', 'change', '', _('change made by revision'), _('REV'))
1828 ('c', 'change', '', _('change made by revision'), _('REV'))
1829 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1829 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1830 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1830 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1831 inferrepo=True,
1831 inferrepo=True,
1832 intents={INTENT_READONLY})
1832 intents={INTENT_READONLY})
1833 def diff(ui, repo, *pats, **opts):
1833 def diff(ui, repo, *pats, **opts):
1834 """diff repository (or selected files)
1834 """diff repository (or selected files)
1835
1835
1836 Show differences between revisions for the specified files.
1836 Show differences between revisions for the specified files.
1837
1837
1838 Differences between files are shown using the unified diff format.
1838 Differences between files are shown using the unified diff format.
1839
1839
1840 .. note::
1840 .. note::
1841
1841
1842 :hg:`diff` may generate unexpected results for merges, as it will
1842 :hg:`diff` may generate unexpected results for merges, as it will
1843 default to comparing against the working directory's first
1843 default to comparing against the working directory's first
1844 parent changeset if no revisions are specified.
1844 parent changeset if no revisions are specified.
1845
1845
1846 When two revision arguments are given, then changes are shown
1846 When two revision arguments are given, then changes are shown
1847 between those revisions. If only one revision is specified then
1847 between those revisions. If only one revision is specified then
1848 that revision is compared to the working directory, and, when no
1848 that revision is compared to the working directory, and, when no
1849 revisions are specified, the working directory files are compared
1849 revisions are specified, the working directory files are compared
1850 to its first parent.
1850 to its first parent.
1851
1851
1852 Alternatively you can specify -c/--change with a revision to see
1852 Alternatively you can specify -c/--change with a revision to see
1853 the changes in that changeset relative to its first parent.
1853 the changes in that changeset relative to its first parent.
1854
1854
1855 Without the -a/--text option, diff will avoid generating diffs of
1855 Without the -a/--text option, diff will avoid generating diffs of
1856 files it detects as binary. With -a, diff will generate a diff
1856 files it detects as binary. With -a, diff will generate a diff
1857 anyway, probably with undesirable results.
1857 anyway, probably with undesirable results.
1858
1858
1859 Use the -g/--git option to generate diffs in the git extended diff
1859 Use the -g/--git option to generate diffs in the git extended diff
1860 format. For more information, read :hg:`help diffs`.
1860 format. For more information, read :hg:`help diffs`.
1861
1861
1862 .. container:: verbose
1862 .. container:: verbose
1863
1863
1864 Examples:
1864 Examples:
1865
1865
1866 - compare a file in the current working directory to its parent::
1866 - compare a file in the current working directory to its parent::
1867
1867
1868 hg diff foo.c
1868 hg diff foo.c
1869
1869
1870 - compare two historical versions of a directory, with rename info::
1870 - compare two historical versions of a directory, with rename info::
1871
1871
1872 hg diff --git -r 1.0:1.2 lib/
1872 hg diff --git -r 1.0:1.2 lib/
1873
1873
1874 - get change stats relative to the last change on some date::
1874 - get change stats relative to the last change on some date::
1875
1875
1876 hg diff --stat -r "date('may 2')"
1876 hg diff --stat -r "date('may 2')"
1877
1877
1878 - diff all newly-added files that contain a keyword::
1878 - diff all newly-added files that contain a keyword::
1879
1879
1880 hg diff "set:added() and grep(GNU)"
1880 hg diff "set:added() and grep(GNU)"
1881
1881
1882 - compare a revision and its parents::
1882 - compare a revision and its parents::
1883
1883
1884 hg diff -c 9353 # compare against first parent
1884 hg diff -c 9353 # compare against first parent
1885 hg diff -r 9353^:9353 # same using revset syntax
1885 hg diff -r 9353^:9353 # same using revset syntax
1886 hg diff -r 9353^2:9353 # compare against the second parent
1886 hg diff -r 9353^2:9353 # compare against the second parent
1887
1887
1888 Returns 0 on success.
1888 Returns 0 on success.
1889 """
1889 """
1890
1890
1891 opts = pycompat.byteskwargs(opts)
1891 opts = pycompat.byteskwargs(opts)
1892 revs = opts.get('rev')
1892 revs = opts.get('rev')
1893 change = opts.get('change')
1893 change = opts.get('change')
1894 stat = opts.get('stat')
1894 stat = opts.get('stat')
1895 reverse = opts.get('reverse')
1895 reverse = opts.get('reverse')
1896
1896
1897 if revs and change:
1897 if revs and change:
1898 msg = _('cannot specify --rev and --change at the same time')
1898 msg = _('cannot specify --rev and --change at the same time')
1899 raise error.Abort(msg)
1899 raise error.Abort(msg)
1900 elif change:
1900 elif change:
1901 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1901 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1902 ctx2 = scmutil.revsingle(repo, change, None)
1902 ctx2 = scmutil.revsingle(repo, change, None)
1903 ctx1 = ctx2.p1()
1903 ctx1 = ctx2.p1()
1904 else:
1904 else:
1905 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1905 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1906 ctx1, ctx2 = scmutil.revpair(repo, revs)
1906 ctx1, ctx2 = scmutil.revpair(repo, revs)
1907 node1, node2 = ctx1.node(), ctx2.node()
1907 node1, node2 = ctx1.node(), ctx2.node()
1908
1908
1909 if reverse:
1909 if reverse:
1910 node1, node2 = node2, node1
1910 node1, node2 = node2, node1
1911
1911
1912 diffopts = patch.diffallopts(ui, opts)
1912 diffopts = patch.diffallopts(ui, opts)
1913 m = scmutil.match(ctx2, pats, opts)
1913 m = scmutil.match(ctx2, pats, opts)
1914 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1914 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1915 ui.pager('diff')
1915 ui.pager('diff')
1916 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1916 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1917 listsubrepos=opts.get('subrepos'),
1917 listsubrepos=opts.get('subrepos'),
1918 root=opts.get('root'))
1918 root=opts.get('root'))
1919
1919
1920 @command('^export',
1920 @command('^export',
1921 [('B', 'bookmark', '',
1921 [('B', 'bookmark', '',
1922 _('export changes only reachable by given bookmark')),
1922 _('export changes only reachable by given bookmark')),
1923 ('o', 'output', '',
1923 ('o', 'output', '',
1924 _('print output to file with formatted name'), _('FORMAT')),
1924 _('print output to file with formatted name'), _('FORMAT')),
1925 ('', 'switch-parent', None, _('diff against the second parent')),
1925 ('', 'switch-parent', None, _('diff against the second parent')),
1926 ('r', 'rev', [], _('revisions to export'), _('REV')),
1926 ('r', 'rev', [], _('revisions to export'), _('REV')),
1927 ] + diffopts + formatteropts,
1927 ] + diffopts + formatteropts,
1928 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1928 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1929 intents={INTENT_READONLY})
1929 intents={INTENT_READONLY})
1930 def export(ui, repo, *changesets, **opts):
1930 def export(ui, repo, *changesets, **opts):
1931 """dump the header and diffs for one or more changesets
1931 """dump the header and diffs for one or more changesets
1932
1932
1933 Print the changeset header and diffs for one or more revisions.
1933 Print the changeset header and diffs for one or more revisions.
1934 If no revision is given, the parent of the working directory is used.
1934 If no revision is given, the parent of the working directory is used.
1935
1935
1936 The information shown in the changeset header is: author, date,
1936 The information shown in the changeset header is: author, date,
1937 branch name (if non-default), changeset hash, parent(s) and commit
1937 branch name (if non-default), changeset hash, parent(s) and commit
1938 comment.
1938 comment.
1939
1939
1940 .. note::
1940 .. note::
1941
1941
1942 :hg:`export` may generate unexpected diff output for merge
1942 :hg:`export` may generate unexpected diff output for merge
1943 changesets, as it will compare the merge changeset against its
1943 changesets, as it will compare the merge changeset against its
1944 first parent only.
1944 first parent only.
1945
1945
1946 Output may be to a file, in which case the name of the file is
1946 Output may be to a file, in which case the name of the file is
1947 given using a template string. See :hg:`help templates`. In addition
1947 given using a template string. See :hg:`help templates`. In addition
1948 to the common template keywords, the following formatting rules are
1948 to the common template keywords, the following formatting rules are
1949 supported:
1949 supported:
1950
1950
1951 :``%%``: literal "%" character
1951 :``%%``: literal "%" character
1952 :``%H``: changeset hash (40 hexadecimal digits)
1952 :``%H``: changeset hash (40 hexadecimal digits)
1953 :``%N``: number of patches being generated
1953 :``%N``: number of patches being generated
1954 :``%R``: changeset revision number
1954 :``%R``: changeset revision number
1955 :``%b``: basename of the exporting repository
1955 :``%b``: basename of the exporting repository
1956 :``%h``: short-form changeset hash (12 hexadecimal digits)
1956 :``%h``: short-form changeset hash (12 hexadecimal digits)
1957 :``%m``: first line of the commit message (only alphanumeric characters)
1957 :``%m``: first line of the commit message (only alphanumeric characters)
1958 :``%n``: zero-padded sequence number, starting at 1
1958 :``%n``: zero-padded sequence number, starting at 1
1959 :``%r``: zero-padded changeset revision number
1959 :``%r``: zero-padded changeset revision number
1960 :``\\``: literal "\\" character
1960 :``\\``: literal "\\" character
1961
1961
1962 Without the -a/--text option, export will avoid generating diffs
1962 Without the -a/--text option, export will avoid generating diffs
1963 of files it detects as binary. With -a, export will generate a
1963 of files it detects as binary. With -a, export will generate a
1964 diff anyway, probably with undesirable results.
1964 diff anyway, probably with undesirable results.
1965
1965
1966 With -B/--bookmark changesets reachable by the given bookmark are
1966 With -B/--bookmark changesets reachable by the given bookmark are
1967 selected.
1967 selected.
1968
1968
1969 Use the -g/--git option to generate diffs in the git extended diff
1969 Use the -g/--git option to generate diffs in the git extended diff
1970 format. See :hg:`help diffs` for more information.
1970 format. See :hg:`help diffs` for more information.
1971
1971
1972 With the --switch-parent option, the diff will be against the
1972 With the --switch-parent option, the diff will be against the
1973 second parent. It can be useful to review a merge.
1973 second parent. It can be useful to review a merge.
1974
1974
1975 .. container:: verbose
1975 .. container:: verbose
1976
1976
1977 Examples:
1977 Examples:
1978
1978
1979 - use export and import to transplant a bugfix to the current
1979 - use export and import to transplant a bugfix to the current
1980 branch::
1980 branch::
1981
1981
1982 hg export -r 9353 | hg import -
1982 hg export -r 9353 | hg import -
1983
1983
1984 - export all the changesets between two revisions to a file with
1984 - export all the changesets between two revisions to a file with
1985 rename information::
1985 rename information::
1986
1986
1987 hg export --git -r 123:150 > changes.txt
1987 hg export --git -r 123:150 > changes.txt
1988
1988
1989 - split outgoing changes into a series of patches with
1989 - split outgoing changes into a series of patches with
1990 descriptive names::
1990 descriptive names::
1991
1991
1992 hg export -r "outgoing()" -o "%n-%m.patch"
1992 hg export -r "outgoing()" -o "%n-%m.patch"
1993
1993
1994 Returns 0 on success.
1994 Returns 0 on success.
1995 """
1995 """
1996 opts = pycompat.byteskwargs(opts)
1996 opts = pycompat.byteskwargs(opts)
1997 bookmark = opts.get('bookmark')
1997 bookmark = opts.get('bookmark')
1998 changesets += tuple(opts.get('rev', []))
1998 changesets += tuple(opts.get('rev', []))
1999
1999
2000 if bookmark and changesets:
2000 if bookmark and changesets:
2001 raise error.Abort(_("-r and -B are mutually exclusive"))
2001 raise error.Abort(_("-r and -B are mutually exclusive"))
2002
2002
2003 if bookmark:
2003 if bookmark:
2004 if bookmark not in repo._bookmarks:
2004 if bookmark not in repo._bookmarks:
2005 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2005 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2006
2006
2007 revs = scmutil.bookmarkrevs(repo, bookmark)
2007 revs = scmutil.bookmarkrevs(repo, bookmark)
2008 else:
2008 else:
2009 if not changesets:
2009 if not changesets:
2010 changesets = ['.']
2010 changesets = ['.']
2011
2011
2012 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2012 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2013 revs = scmutil.revrange(repo, changesets)
2013 revs = scmutil.revrange(repo, changesets)
2014
2014
2015 if not revs:
2015 if not revs:
2016 raise error.Abort(_("export requires at least one changeset"))
2016 raise error.Abort(_("export requires at least one changeset"))
2017 if len(revs) > 1:
2017 if len(revs) > 1:
2018 ui.note(_('exporting patches:\n'))
2018 ui.note(_('exporting patches:\n'))
2019 else:
2019 else:
2020 ui.note(_('exporting patch:\n'))
2020 ui.note(_('exporting patch:\n'))
2021
2021
2022 fntemplate = opts.get('output')
2022 fntemplate = opts.get('output')
2023 if cmdutil.isstdiofilename(fntemplate):
2023 if cmdutil.isstdiofilename(fntemplate):
2024 fntemplate = ''
2024 fntemplate = ''
2025
2025
2026 if fntemplate:
2026 if fntemplate:
2027 fm = formatter.nullformatter(ui, 'export', opts)
2027 fm = formatter.nullformatter(ui, 'export', opts)
2028 else:
2028 else:
2029 ui.pager('export')
2029 ui.pager('export')
2030 fm = ui.formatter('export', opts)
2030 fm = ui.formatter('export', opts)
2031 with fm:
2031 with fm:
2032 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2032 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2033 switch_parent=opts.get('switch_parent'),
2033 switch_parent=opts.get('switch_parent'),
2034 opts=patch.diffallopts(ui, opts))
2034 opts=patch.diffallopts(ui, opts))
2035
2035
2036 @command('files',
2036 @command('files',
2037 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2037 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2038 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2038 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2039 ] + walkopts + formatteropts + subrepoopts,
2039 ] + walkopts + formatteropts + subrepoopts,
2040 _('[OPTION]... [FILE]...'),
2040 _('[OPTION]... [FILE]...'),
2041 intents={INTENT_READONLY})
2041 intents={INTENT_READONLY})
2042 def files(ui, repo, *pats, **opts):
2042 def files(ui, repo, *pats, **opts):
2043 """list tracked files
2043 """list tracked files
2044
2044
2045 Print files under Mercurial control in the working directory or
2045 Print files under Mercurial control in the working directory or
2046 specified revision for given files (excluding removed files).
2046 specified revision for given files (excluding removed files).
2047 Files can be specified as filenames or filesets.
2047 Files can be specified as filenames or filesets.
2048
2048
2049 If no files are given to match, this command prints the names
2049 If no files are given to match, this command prints the names
2050 of all files under Mercurial control.
2050 of all files under Mercurial control.
2051
2051
2052 .. container:: verbose
2052 .. container:: verbose
2053
2053
2054 Template:
2054 Template:
2055
2055
2056 The following keywords are supported in addition to the common template
2056 The following keywords are supported in addition to the common template
2057 keywords and functions. See also :hg:`help templates`.
2057 keywords and functions. See also :hg:`help templates`.
2058
2058
2059 :flags: String. Character denoting file's symlink and executable bits.
2059 :flags: String. Character denoting file's symlink and executable bits.
2060 :path: String. Repository-absolute path of the file.
2060 :path: String. Repository-absolute path of the file.
2061 :size: Integer. Size of the file in bytes.
2061 :size: Integer. Size of the file in bytes.
2062
2062
2063 Examples:
2063 Examples:
2064
2064
2065 - list all files under the current directory::
2065 - list all files under the current directory::
2066
2066
2067 hg files .
2067 hg files .
2068
2068
2069 - shows sizes and flags for current revision::
2069 - shows sizes and flags for current revision::
2070
2070
2071 hg files -vr .
2071 hg files -vr .
2072
2072
2073 - list all files named README::
2073 - list all files named README::
2074
2074
2075 hg files -I "**/README"
2075 hg files -I "**/README"
2076
2076
2077 - list all binary files::
2077 - list all binary files::
2078
2078
2079 hg files "set:binary()"
2079 hg files "set:binary()"
2080
2080
2081 - find files containing a regular expression::
2081 - find files containing a regular expression::
2082
2082
2083 hg files "set:grep('bob')"
2083 hg files "set:grep('bob')"
2084
2084
2085 - search tracked file contents with xargs and grep::
2085 - search tracked file contents with xargs and grep::
2086
2086
2087 hg files -0 | xargs -0 grep foo
2087 hg files -0 | xargs -0 grep foo
2088
2088
2089 See :hg:`help patterns` and :hg:`help filesets` for more information
2089 See :hg:`help patterns` and :hg:`help filesets` for more information
2090 on specifying file patterns.
2090 on specifying file patterns.
2091
2091
2092 Returns 0 if a match is found, 1 otherwise.
2092 Returns 0 if a match is found, 1 otherwise.
2093
2093
2094 """
2094 """
2095
2095
2096 opts = pycompat.byteskwargs(opts)
2096 opts = pycompat.byteskwargs(opts)
2097 rev = opts.get('rev')
2097 rev = opts.get('rev')
2098 if rev:
2098 if rev:
2099 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2099 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2100 ctx = scmutil.revsingle(repo, rev, None)
2100 ctx = scmutil.revsingle(repo, rev, None)
2101
2101
2102 end = '\n'
2102 end = '\n'
2103 if opts.get('print0'):
2103 if opts.get('print0'):
2104 end = '\0'
2104 end = '\0'
2105 fmt = '%s' + end
2105 fmt = '%s' + end
2106
2106
2107 m = scmutil.match(ctx, pats, opts)
2107 m = scmutil.match(ctx, pats, opts)
2108 ui.pager('files')
2108 ui.pager('files')
2109 with ui.formatter('files', opts) as fm:
2109 with ui.formatter('files', opts) as fm:
2110 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2110 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2111
2111
2112 @command(
2112 @command(
2113 '^forget',
2113 '^forget',
2114 [('i', 'interactive', None, _('use interactive mode')),
2114 [('i', 'interactive', None, _('use interactive mode')),
2115 ] + walkopts + dryrunopts,
2115 ] + walkopts + dryrunopts,
2116 _('[OPTION]... FILE...'), inferrepo=True)
2116 _('[OPTION]... FILE...'), inferrepo=True)
2117 def forget(ui, repo, *pats, **opts):
2117 def forget(ui, repo, *pats, **opts):
2118 """forget the specified files on the next commit
2118 """forget the specified files on the next commit
2119
2119
2120 Mark the specified files so they will no longer be tracked
2120 Mark the specified files so they will no longer be tracked
2121 after the next commit.
2121 after the next commit.
2122
2122
2123 This only removes files from the current branch, not from the
2123 This only removes files from the current branch, not from the
2124 entire project history, and it does not delete them from the
2124 entire project history, and it does not delete them from the
2125 working directory.
2125 working directory.
2126
2126
2127 To delete the file from the working directory, see :hg:`remove`.
2127 To delete the file from the working directory, see :hg:`remove`.
2128
2128
2129 To undo a forget before the next commit, see :hg:`add`.
2129 To undo a forget before the next commit, see :hg:`add`.
2130
2130
2131 .. container:: verbose
2131 .. container:: verbose
2132
2132
2133 Examples:
2133 Examples:
2134
2134
2135 - forget newly-added binary files::
2135 - forget newly-added binary files::
2136
2136
2137 hg forget "set:added() and binary()"
2137 hg forget "set:added() and binary()"
2138
2138
2139 - forget files that would be excluded by .hgignore::
2139 - forget files that would be excluded by .hgignore::
2140
2140
2141 hg forget "set:hgignore()"
2141 hg forget "set:hgignore()"
2142
2142
2143 Returns 0 on success.
2143 Returns 0 on success.
2144 """
2144 """
2145
2145
2146 opts = pycompat.byteskwargs(opts)
2146 opts = pycompat.byteskwargs(opts)
2147 if not pats:
2147 if not pats:
2148 raise error.Abort(_('no files specified'))
2148 raise error.Abort(_('no files specified'))
2149
2149
2150 m = scmutil.match(repo[None], pats, opts)
2150 m = scmutil.match(repo[None], pats, opts)
2151 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2151 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2152 rejected = cmdutil.forget(ui, repo, m, prefix="",
2152 rejected = cmdutil.forget(ui, repo, m, prefix="",
2153 explicitonly=False, dryrun=dryrun,
2153 explicitonly=False, dryrun=dryrun,
2154 interactive=interactive)[0]
2154 interactive=interactive)[0]
2155 return rejected and 1 or 0
2155 return rejected and 1 or 0
2156
2156
2157 @command(
2157 @command(
2158 'graft',
2158 'graft',
2159 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2159 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2160 ('c', 'continue', False, _('resume interrupted graft')),
2160 ('c', 'continue', False, _('resume interrupted graft')),
2161 ('', 'stop', False, _('stop interrupted graft')),
2161 ('', 'stop', False, _('stop interrupted graft')),
2162 ('', 'abort', False, _('abort interrupted graft')),
2162 ('', 'abort', False, _('abort interrupted graft')),
2163 ('e', 'edit', False, _('invoke editor on commit messages')),
2163 ('e', 'edit', False, _('invoke editor on commit messages')),
2164 ('', 'log', None, _('append graft info to log message')),
2164 ('', 'log', None, _('append graft info to log message')),
2165 ('', 'no-commit', None,
2165 ('', 'no-commit', None,
2166 _("don't commit, just apply the changes in working directory")),
2166 _("don't commit, just apply the changes in working directory")),
2167 ('f', 'force', False, _('force graft')),
2167 ('f', 'force', False, _('force graft')),
2168 ('D', 'currentdate', False,
2168 ('D', 'currentdate', False,
2169 _('record the current date as commit date')),
2169 _('record the current date as commit date')),
2170 ('U', 'currentuser', False,
2170 ('U', 'currentuser', False,
2171 _('record the current user as committer'), _('DATE'))]
2171 _('record the current user as committer'), _('DATE'))]
2172 + commitopts2 + mergetoolopts + dryrunopts,
2172 + commitopts2 + mergetoolopts + dryrunopts,
2173 _('[OPTION]... [-r REV]... REV...'))
2173 _('[OPTION]... [-r REV]... REV...'))
2174 def graft(ui, repo, *revs, **opts):
2174 def graft(ui, repo, *revs, **opts):
2175 '''copy changes from other branches onto the current branch
2175 '''copy changes from other branches onto the current branch
2176
2176
2177 This command uses Mercurial's merge logic to copy individual
2177 This command uses Mercurial's merge logic to copy individual
2178 changes from other branches without merging branches in the
2178 changes from other branches without merging branches in the
2179 history graph. This is sometimes known as 'backporting' or
2179 history graph. This is sometimes known as 'backporting' or
2180 'cherry-picking'. By default, graft will copy user, date, and
2180 'cherry-picking'. By default, graft will copy user, date, and
2181 description from the source changesets.
2181 description from the source changesets.
2182
2182
2183 Changesets that are ancestors of the current revision, that have
2183 Changesets that are ancestors of the current revision, that have
2184 already been grafted, or that are merges will be skipped.
2184 already been grafted, or that are merges will be skipped.
2185
2185
2186 If --log is specified, log messages will have a comment appended
2186 If --log is specified, log messages will have a comment appended
2187 of the form::
2187 of the form::
2188
2188
2189 (grafted from CHANGESETHASH)
2189 (grafted from CHANGESETHASH)
2190
2190
2191 If --force is specified, revisions will be grafted even if they
2191 If --force is specified, revisions will be grafted even if they
2192 are already ancestors of, or have been grafted to, the destination.
2192 are already ancestors of, or have been grafted to, the destination.
2193 This is useful when the revisions have since been backed out.
2193 This is useful when the revisions have since been backed out.
2194
2194
2195 If a graft merge results in conflicts, the graft process is
2195 If a graft merge results in conflicts, the graft process is
2196 interrupted so that the current merge can be manually resolved.
2196 interrupted so that the current merge can be manually resolved.
2197 Once all conflicts are addressed, the graft process can be
2197 Once all conflicts are addressed, the graft process can be
2198 continued with the -c/--continue option.
2198 continued with the -c/--continue option.
2199
2199
2200 The -c/--continue option reapplies all the earlier options.
2200 The -c/--continue option reapplies all the earlier options.
2201
2201
2202 .. container:: verbose
2202 .. container:: verbose
2203
2203
2204 Examples:
2204 Examples:
2205
2205
2206 - copy a single change to the stable branch and edit its description::
2206 - copy a single change to the stable branch and edit its description::
2207
2207
2208 hg update stable
2208 hg update stable
2209 hg graft --edit 9393
2209 hg graft --edit 9393
2210
2210
2211 - graft a range of changesets with one exception, updating dates::
2211 - graft a range of changesets with one exception, updating dates::
2212
2212
2213 hg graft -D "2085::2093 and not 2091"
2213 hg graft -D "2085::2093 and not 2091"
2214
2214
2215 - continue a graft after resolving conflicts::
2215 - continue a graft after resolving conflicts::
2216
2216
2217 hg graft -c
2217 hg graft -c
2218
2218
2219 - show the source of a grafted changeset::
2219 - show the source of a grafted changeset::
2220
2220
2221 hg log --debug -r .
2221 hg log --debug -r .
2222
2222
2223 - show revisions sorted by date::
2223 - show revisions sorted by date::
2224
2224
2225 hg log -r "sort(all(), date)"
2225 hg log -r "sort(all(), date)"
2226
2226
2227 See :hg:`help revisions` for more about specifying revisions.
2227 See :hg:`help revisions` for more about specifying revisions.
2228
2228
2229 Returns 0 on successful completion.
2229 Returns 0 on successful completion.
2230 '''
2230 '''
2231 with repo.wlock():
2231 with repo.wlock():
2232 return _dograft(ui, repo, *revs, **opts)
2232 return _dograft(ui, repo, *revs, **opts)
2233
2233
2234 def _dograft(ui, repo, *revs, **opts):
2234 def _dograft(ui, repo, *revs, **opts):
2235 opts = pycompat.byteskwargs(opts)
2235 opts = pycompat.byteskwargs(opts)
2236 if revs and opts.get('rev'):
2236 if revs and opts.get('rev'):
2237 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2237 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2238 'revision ordering!\n'))
2238 'revision ordering!\n'))
2239
2239
2240 revs = list(revs)
2240 revs = list(revs)
2241 revs.extend(opts.get('rev'))
2241 revs.extend(opts.get('rev'))
2242 # a dict of data to be stored in state file
2242 # a dict of data to be stored in state file
2243 statedata = {}
2243 statedata = {}
2244 # list of new nodes created by ongoing graft
2244 # list of new nodes created by ongoing graft
2245 statedata['newnodes'] = []
2245 statedata['newnodes'] = []
2246
2246
2247 if not opts.get('user') and opts.get('currentuser'):
2247 if not opts.get('user') and opts.get('currentuser'):
2248 opts['user'] = ui.username()
2248 opts['user'] = ui.username()
2249 if not opts.get('date') and opts.get('currentdate'):
2249 if not opts.get('date') and opts.get('currentdate'):
2250 opts['date'] = "%d %d" % dateutil.makedate()
2250 opts['date'] = "%d %d" % dateutil.makedate()
2251
2251
2252 editor = cmdutil.getcommiteditor(editform='graft',
2252 editor = cmdutil.getcommiteditor(editform='graft',
2253 **pycompat.strkwargs(opts))
2253 **pycompat.strkwargs(opts))
2254
2254
2255 cont = False
2255 cont = False
2256 if opts.get('no_commit'):
2256 if opts.get('no_commit'):
2257 if opts.get('edit'):
2257 if opts.get('edit'):
2258 raise error.Abort(_("cannot specify --no-commit and "
2258 raise error.Abort(_("cannot specify --no-commit and "
2259 "--edit together"))
2259 "--edit together"))
2260 if opts.get('currentuser'):
2260 if opts.get('currentuser'):
2261 raise error.Abort(_("cannot specify --no-commit and "
2261 raise error.Abort(_("cannot specify --no-commit and "
2262 "--currentuser together"))
2262 "--currentuser together"))
2263 if opts.get('currentdate'):
2263 if opts.get('currentdate'):
2264 raise error.Abort(_("cannot specify --no-commit and "
2264 raise error.Abort(_("cannot specify --no-commit and "
2265 "--currentdate together"))
2265 "--currentdate together"))
2266 if opts.get('log'):
2266 if opts.get('log'):
2267 raise error.Abort(_("cannot specify --no-commit and "
2267 raise error.Abort(_("cannot specify --no-commit and "
2268 "--log together"))
2268 "--log together"))
2269
2269
2270 graftstate = statemod.cmdstate(repo, 'graftstate')
2270 graftstate = statemod.cmdstate(repo, 'graftstate')
2271
2271
2272 if opts.get('stop'):
2272 if opts.get('stop'):
2273 if opts.get('continue'):
2273 if opts.get('continue'):
2274 raise error.Abort(_("cannot use '--continue' and "
2274 raise error.Abort(_("cannot use '--continue' and "
2275 "'--stop' together"))
2275 "'--stop' together"))
2276 if opts.get('abort'):
2276 if opts.get('abort'):
2277 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2277 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2278
2278
2279 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2279 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2280 opts.get('date'), opts.get('currentdate'),
2280 opts.get('date'), opts.get('currentdate'),
2281 opts.get('currentuser'), opts.get('rev'))):
2281 opts.get('currentuser'), opts.get('rev'))):
2282 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2282 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2283 return _stopgraft(ui, repo, graftstate)
2283 return _stopgraft(ui, repo, graftstate)
2284 elif opts.get('abort'):
2284 elif opts.get('abort'):
2285 if opts.get('continue'):
2285 if opts.get('continue'):
2286 raise error.Abort(_("cannot use '--continue' and "
2286 raise error.Abort(_("cannot use '--continue' and "
2287 "'--abort' together"))
2287 "'--abort' together"))
2288 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2288 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2289 opts.get('date'), opts.get('currentdate'),
2289 opts.get('date'), opts.get('currentdate'),
2290 opts.get('currentuser'), opts.get('rev'))):
2290 opts.get('currentuser'), opts.get('rev'))):
2291 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2291 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2292
2292
2293 return _abortgraft(ui, repo, graftstate)
2293 return _abortgraft(ui, repo, graftstate)
2294 elif opts.get('continue'):
2294 elif opts.get('continue'):
2295 cont = True
2295 cont = True
2296 if revs:
2296 if revs:
2297 raise error.Abort(_("can't specify --continue and revisions"))
2297 raise error.Abort(_("can't specify --continue and revisions"))
2298 # read in unfinished revisions
2298 # read in unfinished revisions
2299 if graftstate.exists():
2299 if graftstate.exists():
2300 statedata = _readgraftstate(repo, graftstate)
2300 statedata = _readgraftstate(repo, graftstate)
2301 if statedata.get('date'):
2301 if statedata.get('date'):
2302 opts['date'] = statedata['date']
2302 opts['date'] = statedata['date']
2303 if statedata.get('user'):
2303 if statedata.get('user'):
2304 opts['user'] = statedata['user']
2304 opts['user'] = statedata['user']
2305 if statedata.get('log'):
2305 if statedata.get('log'):
2306 opts['log'] = True
2306 opts['log'] = True
2307 if statedata.get('no_commit'):
2307 if statedata.get('no_commit'):
2308 opts['no_commit'] = statedata.get('no_commit')
2308 opts['no_commit'] = statedata.get('no_commit')
2309 nodes = statedata['nodes']
2309 nodes = statedata['nodes']
2310 revs = [repo[node].rev() for node in nodes]
2310 revs = [repo[node].rev() for node in nodes]
2311 else:
2311 else:
2312 cmdutil.wrongtooltocontinue(repo, _('graft'))
2312 cmdutil.wrongtooltocontinue(repo, _('graft'))
2313 else:
2313 else:
2314 if not revs:
2314 if not revs:
2315 raise error.Abort(_('no revisions specified'))
2315 raise error.Abort(_('no revisions specified'))
2316 cmdutil.checkunfinished(repo)
2316 cmdutil.checkunfinished(repo)
2317 cmdutil.bailifchanged(repo)
2317 cmdutil.bailifchanged(repo)
2318 revs = scmutil.revrange(repo, revs)
2318 revs = scmutil.revrange(repo, revs)
2319
2319
2320 skipped = set()
2320 skipped = set()
2321 # check for merges
2321 # check for merges
2322 for rev in repo.revs('%ld and merge()', revs):
2322 for rev in repo.revs('%ld and merge()', revs):
2323 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2323 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2324 skipped.add(rev)
2324 skipped.add(rev)
2325 revs = [r for r in revs if r not in skipped]
2325 revs = [r for r in revs if r not in skipped]
2326 if not revs:
2326 if not revs:
2327 return -1
2327 return -1
2328
2328
2329 # Don't check in the --continue case, in effect retaining --force across
2329 # Don't check in the --continue case, in effect retaining --force across
2330 # --continues. That's because without --force, any revisions we decided to
2330 # --continues. That's because without --force, any revisions we decided to
2331 # skip would have been filtered out here, so they wouldn't have made their
2331 # skip would have been filtered out here, so they wouldn't have made their
2332 # way to the graftstate. With --force, any revisions we would have otherwise
2332 # way to the graftstate. With --force, any revisions we would have otherwise
2333 # skipped would not have been filtered out, and if they hadn't been applied
2333 # skipped would not have been filtered out, and if they hadn't been applied
2334 # already, they'd have been in the graftstate.
2334 # already, they'd have been in the graftstate.
2335 if not (cont or opts.get('force')):
2335 if not (cont or opts.get('force')):
2336 # check for ancestors of dest branch
2336 # check for ancestors of dest branch
2337 crev = repo['.'].rev()
2337 crev = repo['.'].rev()
2338 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2338 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2339 # XXX make this lazy in the future
2339 # XXX make this lazy in the future
2340 # don't mutate while iterating, create a copy
2340 # don't mutate while iterating, create a copy
2341 for rev in list(revs):
2341 for rev in list(revs):
2342 if rev in ancestors:
2342 if rev in ancestors:
2343 ui.warn(_('skipping ancestor revision %d:%s\n') %
2343 ui.warn(_('skipping ancestor revision %d:%s\n') %
2344 (rev, repo[rev]))
2344 (rev, repo[rev]))
2345 # XXX remove on list is slow
2345 # XXX remove on list is slow
2346 revs.remove(rev)
2346 revs.remove(rev)
2347 if not revs:
2347 if not revs:
2348 return -1
2348 return -1
2349
2349
2350 # analyze revs for earlier grafts
2350 # analyze revs for earlier grafts
2351 ids = {}
2351 ids = {}
2352 for ctx in repo.set("%ld", revs):
2352 for ctx in repo.set("%ld", revs):
2353 ids[ctx.hex()] = ctx.rev()
2353 ids[ctx.hex()] = ctx.rev()
2354 n = ctx.extra().get('source')
2354 n = ctx.extra().get('source')
2355 if n:
2355 if n:
2356 ids[n] = ctx.rev()
2356 ids[n] = ctx.rev()
2357
2357
2358 # check ancestors for earlier grafts
2358 # check ancestors for earlier grafts
2359 ui.debug('scanning for duplicate grafts\n')
2359 ui.debug('scanning for duplicate grafts\n')
2360
2360
2361 # The only changesets we can be sure doesn't contain grafts of any
2361 # The only changesets we can be sure doesn't contain grafts of any
2362 # revs, are the ones that are common ancestors of *all* revs:
2362 # revs, are the ones that are common ancestors of *all* revs:
2363 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2363 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2364 ctx = repo[rev]
2364 ctx = repo[rev]
2365 n = ctx.extra().get('source')
2365 n = ctx.extra().get('source')
2366 if n in ids:
2366 if n in ids:
2367 try:
2367 try:
2368 r = repo[n].rev()
2368 r = repo[n].rev()
2369 except error.RepoLookupError:
2369 except error.RepoLookupError:
2370 r = None
2370 r = None
2371 if r in revs:
2371 if r in revs:
2372 ui.warn(_('skipping revision %d:%s '
2372 ui.warn(_('skipping revision %d:%s '
2373 '(already grafted to %d:%s)\n')
2373 '(already grafted to %d:%s)\n')
2374 % (r, repo[r], rev, ctx))
2374 % (r, repo[r], rev, ctx))
2375 revs.remove(r)
2375 revs.remove(r)
2376 elif ids[n] in revs:
2376 elif ids[n] in revs:
2377 if r is None:
2377 if r is None:
2378 ui.warn(_('skipping already grafted revision %d:%s '
2378 ui.warn(_('skipping already grafted revision %d:%s '
2379 '(%d:%s also has unknown origin %s)\n')
2379 '(%d:%s also has unknown origin %s)\n')
2380 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2380 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2381 else:
2381 else:
2382 ui.warn(_('skipping already grafted revision %d:%s '
2382 ui.warn(_('skipping already grafted revision %d:%s '
2383 '(%d:%s also has origin %d:%s)\n')
2383 '(%d:%s also has origin %d:%s)\n')
2384 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2384 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2385 revs.remove(ids[n])
2385 revs.remove(ids[n])
2386 elif ctx.hex() in ids:
2386 elif ctx.hex() in ids:
2387 r = ids[ctx.hex()]
2387 r = ids[ctx.hex()]
2388 ui.warn(_('skipping already grafted revision %d:%s '
2388 ui.warn(_('skipping already grafted revision %d:%s '
2389 '(was grafted from %d:%s)\n') %
2389 '(was grafted from %d:%s)\n') %
2390 (r, repo[r], rev, ctx))
2390 (r, repo[r], rev, ctx))
2391 revs.remove(r)
2391 revs.remove(r)
2392 if not revs:
2392 if not revs:
2393 return -1
2393 return -1
2394
2394
2395 if opts.get('no_commit'):
2395 if opts.get('no_commit'):
2396 statedata['no_commit'] = True
2396 statedata['no_commit'] = True
2397 for pos, ctx in enumerate(repo.set("%ld", revs)):
2397 for pos, ctx in enumerate(repo.set("%ld", revs)):
2398 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2398 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2399 ctx.description().split('\n', 1)[0])
2399 ctx.description().split('\n', 1)[0])
2400 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2400 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2401 if names:
2401 if names:
2402 desc += ' (%s)' % ' '.join(names)
2402 desc += ' (%s)' % ' '.join(names)
2403 ui.status(_('grafting %s\n') % desc)
2403 ui.status(_('grafting %s\n') % desc)
2404 if opts.get('dry_run'):
2404 if opts.get('dry_run'):
2405 continue
2405 continue
2406
2406
2407 source = ctx.extra().get('source')
2407 source = ctx.extra().get('source')
2408 extra = {}
2408 extra = {}
2409 if source:
2409 if source:
2410 extra['source'] = source
2410 extra['source'] = source
2411 extra['intermediate-source'] = ctx.hex()
2411 extra['intermediate-source'] = ctx.hex()
2412 else:
2412 else:
2413 extra['source'] = ctx.hex()
2413 extra['source'] = ctx.hex()
2414 user = ctx.user()
2414 user = ctx.user()
2415 if opts.get('user'):
2415 if opts.get('user'):
2416 user = opts['user']
2416 user = opts['user']
2417 statedata['user'] = user
2417 statedata['user'] = user
2418 date = ctx.date()
2418 date = ctx.date()
2419 if opts.get('date'):
2419 if opts.get('date'):
2420 date = opts['date']
2420 date = opts['date']
2421 statedata['date'] = date
2421 statedata['date'] = date
2422 message = ctx.description()
2422 message = ctx.description()
2423 if opts.get('log'):
2423 if opts.get('log'):
2424 message += '\n(grafted from %s)' % ctx.hex()
2424 message += '\n(grafted from %s)' % ctx.hex()
2425 statedata['log'] = True
2425 statedata['log'] = True
2426
2426
2427 # we don't merge the first commit when continuing
2427 # we don't merge the first commit when continuing
2428 if not cont:
2428 if not cont:
2429 # perform the graft merge with p1(rev) as 'ancestor'
2429 # perform the graft merge with p1(rev) as 'ancestor'
2430 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2430 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2431 with ui.configoverride(overrides, 'graft'):
2431 with ui.configoverride(overrides, 'graft'):
2432 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2432 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2433 # report any conflicts
2433 # report any conflicts
2434 if stats.unresolvedcount > 0:
2434 if stats.unresolvedcount > 0:
2435 # write out state for --continue
2435 # write out state for --continue
2436 nodes = [repo[rev].hex() for rev in revs[pos:]]
2436 nodes = [repo[rev].hex() for rev in revs[pos:]]
2437 statedata['nodes'] = nodes
2437 statedata['nodes'] = nodes
2438 stateversion = 1
2438 stateversion = 1
2439 graftstate.save(stateversion, statedata)
2439 graftstate.save(stateversion, statedata)
2440 hint = _("use 'hg resolve' and 'hg graft --continue'")
2440 hint = _("use 'hg resolve' and 'hg graft --continue'")
2441 raise error.Abort(
2441 raise error.Abort(
2442 _("unresolved conflicts, can't continue"),
2442 _("unresolved conflicts, can't continue"),
2443 hint=hint)
2443 hint=hint)
2444 else:
2444 else:
2445 cont = False
2445 cont = False
2446
2446
2447 # commit if --no-commit is false
2447 # commit if --no-commit is false
2448 if not opts.get('no_commit'):
2448 if not opts.get('no_commit'):
2449 node = repo.commit(text=message, user=user, date=date, extra=extra,
2449 node = repo.commit(text=message, user=user, date=date, extra=extra,
2450 editor=editor)
2450 editor=editor)
2451 if node is None:
2451 if node is None:
2452 ui.warn(
2452 ui.warn(
2453 _('note: graft of %d:%s created no changes to commit\n') %
2453 _('note: graft of %d:%s created no changes to commit\n') %
2454 (ctx.rev(), ctx))
2454 (ctx.rev(), ctx))
2455 # checking that newnodes exist because old state files won't have it
2455 # checking that newnodes exist because old state files won't have it
2456 elif statedata.get('newnodes') is not None:
2456 elif statedata.get('newnodes') is not None:
2457 statedata['newnodes'].append(node)
2457 statedata['newnodes'].append(node)
2458
2458
2459 # remove state when we complete successfully
2459 # remove state when we complete successfully
2460 if not opts.get('dry_run'):
2460 if not opts.get('dry_run'):
2461 graftstate.delete()
2461 graftstate.delete()
2462
2462
2463 return 0
2463 return 0
2464
2464
2465 def _abortgraft(ui, repo, graftstate):
2465 def _abortgraft(ui, repo, graftstate):
2466 """abort the interrupted graft and rollbacks to the state before interrupted
2466 """abort the interrupted graft and rollbacks to the state before interrupted
2467 graft"""
2467 graft"""
2468 if not graftstate.exists():
2468 if not graftstate.exists():
2469 raise error.Abort(_("no interrupted graft to abort"))
2469 raise error.Abort(_("no interrupted graft to abort"))
2470 statedata = _readgraftstate(repo, graftstate)
2470 statedata = _readgraftstate(repo, graftstate)
2471 newnodes = statedata.get('newnodes')
2471 newnodes = statedata.get('newnodes')
2472 if newnodes is None:
2472 if newnodes is None:
2473 # and old graft state which does not have all the data required to abort
2473 # and old graft state which does not have all the data required to abort
2474 # the graft
2474 # the graft
2475 raise error.Abort(_("cannot abort using an old graftstate"))
2475 raise error.Abort(_("cannot abort using an old graftstate"))
2476
2476
2477 # changeset from which graft operation was started
2477 # changeset from which graft operation was started
2478 startctx = None
2478 startctx = None
2479 if len(newnodes) > 0:
2479 if len(newnodes) > 0:
2480 startctx = repo[newnodes[0]].p1()
2480 startctx = repo[newnodes[0]].p1()
2481 else:
2481 else:
2482 startctx = repo['.']
2482 startctx = repo['.']
2483 # whether to strip or not
2483 # whether to strip or not
2484 cleanup = False
2484 cleanup = False
2485 if newnodes:
2485 if newnodes:
2486 newnodes = [repo[r].rev() for r in newnodes]
2486 newnodes = [repo[r].rev() for r in newnodes]
2487 cleanup = True
2487 cleanup = True
2488 # checking that none of the newnodes turned public or is public
2488 # checking that none of the newnodes turned public or is public
2489 immutable = [c for c in newnodes if not repo[c].mutable()]
2489 immutable = [c for c in newnodes if not repo[c].mutable()]
2490 if immutable:
2490 if immutable:
2491 repo.ui.warn(_("cannot clean up public changesets %s\n")
2491 repo.ui.warn(_("cannot clean up public changesets %s\n")
2492 % ', '.join(bytes(repo[r]) for r in immutable),
2492 % ', '.join(bytes(repo[r]) for r in immutable),
2493 hint=_("see 'hg help phases' for details"))
2493 hint=_("see 'hg help phases' for details"))
2494 cleanup = False
2494 cleanup = False
2495
2495
2496 # checking that no new nodes are created on top of grafted revs
2496 # checking that no new nodes are created on top of grafted revs
2497 desc = set(repo.changelog.descendants(newnodes))
2497 desc = set(repo.changelog.descendants(newnodes))
2498 if desc - set(newnodes):
2498 if desc - set(newnodes):
2499 repo.ui.warn(_("new changesets detected on destination "
2499 repo.ui.warn(_("new changesets detected on destination "
2500 "branch, can't strip\n"))
2500 "branch, can't strip\n"))
2501 cleanup = False
2501 cleanup = False
2502
2502
2503 if cleanup:
2503 if cleanup:
2504 with repo.wlock(), repo.lock():
2504 with repo.wlock(), repo.lock():
2505 hg.updaterepo(repo, startctx.node(), overwrite=True)
2505 hg.updaterepo(repo, startctx.node(), overwrite=True)
2506 # stripping the new nodes created
2506 # stripping the new nodes created
2507 strippoints = [c.node() for c in repo.set("roots(%ld)",
2507 strippoints = [c.node() for c in repo.set("roots(%ld)",
2508 newnodes)]
2508 newnodes)]
2509 repair.strip(repo.ui, repo, strippoints, backup=False)
2509 repair.strip(repo.ui, repo, strippoints, backup=False)
2510
2510
2511 if not cleanup:
2511 if not cleanup:
2512 # we don't update to the startnode if we can't strip
2512 # we don't update to the startnode if we can't strip
2513 startctx = repo['.']
2513 startctx = repo['.']
2514 hg.updaterepo(repo, startctx.node(), overwrite=True)
2514 hg.updaterepo(repo, startctx.node(), overwrite=True)
2515
2515
2516 ui.status(_("graft aborted\n"))
2516 ui.status(_("graft aborted\n"))
2517 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2517 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2518 graftstate.delete()
2518 graftstate.delete()
2519 return 0
2519 return 0
2520
2520
2521 def _readgraftstate(repo, graftstate):
2521 def _readgraftstate(repo, graftstate):
2522 """read the graft state file and return a dict of the data stored in it"""
2522 """read the graft state file and return a dict of the data stored in it"""
2523 try:
2523 try:
2524 return graftstate.read()
2524 return graftstate.read()
2525 except error.CorruptedState:
2525 except error.CorruptedState:
2526 nodes = repo.vfs.read('graftstate').splitlines()
2526 nodes = repo.vfs.read('graftstate').splitlines()
2527 return {'nodes': nodes}
2527 return {'nodes': nodes}
2528
2528
2529 def _stopgraft(ui, repo, graftstate):
2529 def _stopgraft(ui, repo, graftstate):
2530 """stop the interrupted graft"""
2530 """stop the interrupted graft"""
2531 if not graftstate.exists():
2531 if not graftstate.exists():
2532 raise error.Abort(_("no interrupted graft found"))
2532 raise error.Abort(_("no interrupted graft found"))
2533 pctx = repo['.']
2533 pctx = repo['.']
2534 hg.updaterepo(repo, pctx.node(), overwrite=True)
2534 hg.updaterepo(repo, pctx.node(), overwrite=True)
2535 graftstate.delete()
2535 graftstate.delete()
2536 ui.status(_("stopped the interrupted graft\n"))
2536 ui.status(_("stopped the interrupted graft\n"))
2537 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2537 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2538 return 0
2538 return 0
2539
2539
2540 @command('grep',
2540 @command('grep',
2541 [('0', 'print0', None, _('end fields with NUL')),
2541 [('0', 'print0', None, _('end fields with NUL')),
2542 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2542 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2543 ('', 'diff', None, _('print all revisions when the term was introduced '
2543 ('', 'diff', None, _('print all revisions when the term was introduced '
2544 'or removed')),
2544 'or removed')),
2545 ('a', 'text', None, _('treat all files as text')),
2545 ('a', 'text', None, _('treat all files as text')),
2546 ('f', 'follow', None,
2546 ('f', 'follow', None,
2547 _('follow changeset history,'
2547 _('follow changeset history,'
2548 ' or file history across copies and renames')),
2548 ' or file history across copies and renames')),
2549 ('i', 'ignore-case', None, _('ignore case when matching')),
2549 ('i', 'ignore-case', None, _('ignore case when matching')),
2550 ('l', 'files-with-matches', None,
2550 ('l', 'files-with-matches', None,
2551 _('print only filenames and revisions that match')),
2551 _('print only filenames and revisions that match')),
2552 ('n', 'line-number', None, _('print matching line numbers')),
2552 ('n', 'line-number', None, _('print matching line numbers')),
2553 ('r', 'rev', [],
2553 ('r', 'rev', [],
2554 _('only search files changed within revision range'), _('REV')),
2554 _('only search files changed within revision range'), _('REV')),
2555 ('', 'all-files', None,
2555 ('', 'all-files', None,
2556 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2556 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2557 ('u', 'user', None, _('list the author (long with -v)')),
2557 ('u', 'user', None, _('list the author (long with -v)')),
2558 ('d', 'date', None, _('list the date (short with -q)')),
2558 ('d', 'date', None, _('list the date (short with -q)')),
2559 ] + formatteropts + walkopts,
2559 ] + formatteropts + walkopts,
2560 _('[OPTION]... PATTERN [FILE]...'),
2560 _('[OPTION]... PATTERN [FILE]...'),
2561 inferrepo=True,
2561 inferrepo=True,
2562 intents={INTENT_READONLY})
2562 intents={INTENT_READONLY})
2563 def grep(ui, repo, pattern, *pats, **opts):
2563 def grep(ui, repo, pattern, *pats, **opts):
2564 """search revision history for a pattern in specified files
2564 """search revision history for a pattern in specified files
2565
2565
2566 Search revision history for a regular expression in the specified
2566 Search revision history for a regular expression in the specified
2567 files or the entire project.
2567 files or the entire project.
2568
2568
2569 By default, grep prints the most recent revision number for each
2569 By default, grep prints the most recent revision number for each
2570 file in which it finds a match. To get it to print every revision
2570 file in which it finds a match. To get it to print every revision
2571 that contains a change in match status ("-" for a match that becomes
2571 that contains a change in match status ("-" for a match that becomes
2572 a non-match, or "+" for a non-match that becomes a match), use the
2572 a non-match, or "+" for a non-match that becomes a match), use the
2573 --diff flag.
2573 --diff flag.
2574
2574
2575 PATTERN can be any Python (roughly Perl-compatible) regular
2575 PATTERN can be any Python (roughly Perl-compatible) regular
2576 expression.
2576 expression.
2577
2577
2578 If no FILEs are specified (and -f/--follow isn't set), all files in
2578 If no FILEs are specified (and -f/--follow isn't set), all files in
2579 the repository are searched, including those that don't exist in the
2579 the repository are searched, including those that don't exist in the
2580 current branch or have been deleted in a prior changeset.
2580 current branch or have been deleted in a prior changeset.
2581
2581
2582 Returns 0 if a match is found, 1 otherwise.
2582 Returns 0 if a match is found, 1 otherwise.
2583 """
2583 """
2584 opts = pycompat.byteskwargs(opts)
2584 opts = pycompat.byteskwargs(opts)
2585 diff = opts.get('all') or opts.get('diff')
2585 diff = opts.get('all') or opts.get('diff')
2586 all_files = opts.get('all_files')
2586 all_files = opts.get('all_files')
2587 if diff and opts.get('all_files'):
2587 if diff and opts.get('all_files'):
2588 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2588 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2589 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2589 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2590 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2590 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2591 # experimental config: commands.grep.all-files
2591 # experimental config: commands.grep.all-files
2592 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2592 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2593 plaingrep = opts.get('all_files') and not opts.get('rev')
2593 plaingrep = opts.get('all_files') and not opts.get('rev')
2594 if plaingrep:
2594 if plaingrep:
2595 opts['rev'] = ['wdir()']
2595 opts['rev'] = ['wdir()']
2596
2596
2597 reflags = re.M
2597 reflags = re.M
2598 if opts.get('ignore_case'):
2598 if opts.get('ignore_case'):
2599 reflags |= re.I
2599 reflags |= re.I
2600 try:
2600 try:
2601 regexp = util.re.compile(pattern, reflags)
2601 regexp = util.re.compile(pattern, reflags)
2602 except re.error as inst:
2602 except re.error as inst:
2603 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2603 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2604 return 1
2604 return 1
2605 sep, eol = ':', '\n'
2605 sep, eol = ':', '\n'
2606 if opts.get('print0'):
2606 if opts.get('print0'):
2607 sep = eol = '\0'
2607 sep = eol = '\0'
2608
2608
2609 getfile = util.lrucachefunc(repo.file)
2609 getfile = util.lrucachefunc(repo.file)
2610
2610
2611 def matchlines(body):
2611 def matchlines(body):
2612 begin = 0
2612 begin = 0
2613 linenum = 0
2613 linenum = 0
2614 while begin < len(body):
2614 while begin < len(body):
2615 match = regexp.search(body, begin)
2615 match = regexp.search(body, begin)
2616 if not match:
2616 if not match:
2617 break
2617 break
2618 mstart, mend = match.span()
2618 mstart, mend = match.span()
2619 linenum += body.count('\n', begin, mstart) + 1
2619 linenum += body.count('\n', begin, mstart) + 1
2620 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2620 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2621 begin = body.find('\n', mend) + 1 or len(body) + 1
2621 begin = body.find('\n', mend) + 1 or len(body) + 1
2622 lend = begin - 1
2622 lend = begin - 1
2623 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2623 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2624
2624
2625 class linestate(object):
2625 class linestate(object):
2626 def __init__(self, line, linenum, colstart, colend):
2626 def __init__(self, line, linenum, colstart, colend):
2627 self.line = line
2627 self.line = line
2628 self.linenum = linenum
2628 self.linenum = linenum
2629 self.colstart = colstart
2629 self.colstart = colstart
2630 self.colend = colend
2630 self.colend = colend
2631
2631
2632 def __hash__(self):
2632 def __hash__(self):
2633 return hash((self.linenum, self.line))
2633 return hash((self.linenum, self.line))
2634
2634
2635 def __eq__(self, other):
2635 def __eq__(self, other):
2636 return self.line == other.line
2636 return self.line == other.line
2637
2637
2638 def findpos(self):
2638 def findpos(self):
2639 """Iterate all (start, end) indices of matches"""
2639 """Iterate all (start, end) indices of matches"""
2640 yield self.colstart, self.colend
2640 yield self.colstart, self.colend
2641 p = self.colend
2641 p = self.colend
2642 while p < len(self.line):
2642 while p < len(self.line):
2643 m = regexp.search(self.line, p)
2643 m = regexp.search(self.line, p)
2644 if not m:
2644 if not m:
2645 break
2645 break
2646 yield m.span()
2646 yield m.span()
2647 p = m.end()
2647 p = m.end()
2648
2648
2649 matches = {}
2649 matches = {}
2650 copies = {}
2650 copies = {}
2651 def grepbody(fn, rev, body):
2651 def grepbody(fn, rev, body):
2652 matches[rev].setdefault(fn, [])
2652 matches[rev].setdefault(fn, [])
2653 m = matches[rev][fn]
2653 m = matches[rev][fn]
2654 for lnum, cstart, cend, line in matchlines(body):
2654 for lnum, cstart, cend, line in matchlines(body):
2655 s = linestate(line, lnum, cstart, cend)
2655 s = linestate(line, lnum, cstart, cend)
2656 m.append(s)
2656 m.append(s)
2657
2657
2658 def difflinestates(a, b):
2658 def difflinestates(a, b):
2659 sm = difflib.SequenceMatcher(None, a, b)
2659 sm = difflib.SequenceMatcher(None, a, b)
2660 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2660 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2661 if tag == r'insert':
2661 if tag == r'insert':
2662 for i in pycompat.xrange(blo, bhi):
2662 for i in pycompat.xrange(blo, bhi):
2663 yield ('+', b[i])
2663 yield ('+', b[i])
2664 elif tag == r'delete':
2664 elif tag == r'delete':
2665 for i in pycompat.xrange(alo, ahi):
2665 for i in pycompat.xrange(alo, ahi):
2666 yield ('-', a[i])
2666 yield ('-', a[i])
2667 elif tag == r'replace':
2667 elif tag == r'replace':
2668 for i in pycompat.xrange(alo, ahi):
2668 for i in pycompat.xrange(alo, ahi):
2669 yield ('-', a[i])
2669 yield ('-', a[i])
2670 for i in pycompat.xrange(blo, bhi):
2670 for i in pycompat.xrange(blo, bhi):
2671 yield ('+', b[i])
2671 yield ('+', b[i])
2672
2672
2673 def display(fm, fn, ctx, pstates, states):
2673 def display(fm, fn, ctx, pstates, states):
2674 rev = scmutil.intrev(ctx)
2674 rev = scmutil.intrev(ctx)
2675 if fm.isplain():
2675 if fm.isplain():
2676 formatuser = ui.shortuser
2676 formatuser = ui.shortuser
2677 else:
2677 else:
2678 formatuser = pycompat.bytestr
2678 formatuser = pycompat.bytestr
2679 if ui.quiet:
2679 if ui.quiet:
2680 datefmt = '%Y-%m-%d'
2680 datefmt = '%Y-%m-%d'
2681 else:
2681 else:
2682 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2682 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2683 found = False
2683 found = False
2684 @util.cachefunc
2684 @util.cachefunc
2685 def binary():
2685 def binary():
2686 flog = getfile(fn)
2686 flog = getfile(fn)
2687 try:
2687 try:
2688 return stringutil.binary(flog.read(ctx.filenode(fn)))
2688 return stringutil.binary(flog.read(ctx.filenode(fn)))
2689 except error.WdirUnsupported:
2689 except error.WdirUnsupported:
2690 return ctx[fn].isbinary()
2690 return ctx[fn].isbinary()
2691
2691
2692 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2692 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2693 if diff:
2693 if diff:
2694 iter = difflinestates(pstates, states)
2694 iter = difflinestates(pstates, states)
2695 else:
2695 else:
2696 iter = [('', l) for l in states]
2696 iter = [('', l) for l in states]
2697 for change, l in iter:
2697 for change, l in iter:
2698 fm.startitem()
2698 fm.startitem()
2699 fm.context(ctx=ctx)
2699 fm.context(ctx=ctx)
2700 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2700 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2701
2701
2702 cols = [
2702 cols = [
2703 ('filename', '%s', fn, True),
2703 ('filename', '%s', fn, True),
2704 ('rev', '%d', rev, not plaingrep),
2704 ('rev', '%d', rev, not plaingrep),
2705 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2705 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2706 ]
2706 ]
2707 if diff:
2707 if diff:
2708 cols.append(('change', '%s', change, True))
2708 cols.append(('change', '%s', change, True))
2709 cols.extend([
2709 cols.extend([
2710 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2710 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2711 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2711 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2712 opts.get('date')),
2712 opts.get('date')),
2713 ])
2713 ])
2714 lastcol = next(
2714 lastcol = next(
2715 name for name, fmt, data, cond in reversed(cols) if cond)
2715 name for name, fmt, data, cond in reversed(cols) if cond)
2716 for name, fmt, data, cond in cols:
2716 for name, fmt, data, cond in cols:
2717 field = fieldnamemap.get(name, name)
2717 field = fieldnamemap.get(name, name)
2718 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2718 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2719 if cond and name != lastcol:
2719 if cond and name != lastcol:
2720 fm.plain(sep, label='grep.sep')
2720 fm.plain(sep, label='grep.sep')
2721 if not opts.get('files_with_matches'):
2721 if not opts.get('files_with_matches'):
2722 fm.plain(sep, label='grep.sep')
2722 fm.plain(sep, label='grep.sep')
2723 if not opts.get('text') and binary():
2723 if not opts.get('text') and binary():
2724 fm.plain(_(" Binary file matches"))
2724 fm.plain(_(" Binary file matches"))
2725 else:
2725 else:
2726 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2726 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2727 fm.plain(eol)
2727 fm.plain(eol)
2728 found = True
2728 found = True
2729 if opts.get('files_with_matches'):
2729 if opts.get('files_with_matches'):
2730 break
2730 break
2731 return found
2731 return found
2732
2732
2733 def displaymatches(fm, l):
2733 def displaymatches(fm, l):
2734 p = 0
2734 p = 0
2735 for s, e in l.findpos():
2735 for s, e in l.findpos():
2736 if p < s:
2736 if p < s:
2737 fm.startitem()
2737 fm.startitem()
2738 fm.write('text', '%s', l.line[p:s])
2738 fm.write('text', '%s', l.line[p:s])
2739 fm.data(matched=False)
2739 fm.data(matched=False)
2740 fm.startitem()
2740 fm.startitem()
2741 fm.write('text', '%s', l.line[s:e], label='grep.match')
2741 fm.write('text', '%s', l.line[s:e], label='grep.match')
2742 fm.data(matched=True)
2742 fm.data(matched=True)
2743 p = e
2743 p = e
2744 if p < len(l.line):
2744 if p < len(l.line):
2745 fm.startitem()
2745 fm.startitem()
2746 fm.write('text', '%s', l.line[p:])
2746 fm.write('text', '%s', l.line[p:])
2747 fm.data(matched=False)
2747 fm.data(matched=False)
2748 fm.end()
2748 fm.end()
2749
2749
2750 skip = {}
2750 skip = {}
2751 revfiles = {}
2751 revfiles = {}
2752 match = scmutil.match(repo[None], pats, opts)
2752 match = scmutil.match(repo[None], pats, opts)
2753 found = False
2753 found = False
2754 follow = opts.get('follow')
2754 follow = opts.get('follow')
2755
2755
2756 def prep(ctx, fns):
2756 def prep(ctx, fns):
2757 rev = ctx.rev()
2757 rev = ctx.rev()
2758 pctx = ctx.p1()
2758 pctx = ctx.p1()
2759 parent = pctx.rev()
2759 parent = pctx.rev()
2760 matches.setdefault(rev, {})
2760 matches.setdefault(rev, {})
2761 matches.setdefault(parent, {})
2761 matches.setdefault(parent, {})
2762 files = revfiles.setdefault(rev, [])
2762 files = revfiles.setdefault(rev, [])
2763 for fn in fns:
2763 for fn in fns:
2764 flog = getfile(fn)
2764 flog = getfile(fn)
2765 try:
2765 try:
2766 fnode = ctx.filenode(fn)
2766 fnode = ctx.filenode(fn)
2767 except error.LookupError:
2767 except error.LookupError:
2768 continue
2768 continue
2769 try:
2769 try:
2770 copied = flog.renamed(fnode)
2770 copied = flog.renamed(fnode)
2771 except error.WdirUnsupported:
2771 except error.WdirUnsupported:
2772 copied = ctx[fn].renamed()
2772 copied = ctx[fn].renamed()
2773 copy = follow and copied and copied[0]
2773 copy = follow and copied and copied[0]
2774 if copy:
2774 if copy:
2775 copies.setdefault(rev, {})[fn] = copy
2775 copies.setdefault(rev, {})[fn] = copy
2776 if fn in skip:
2776 if fn in skip:
2777 if copy:
2777 if copy:
2778 skip[copy] = True
2778 skip[copy] = True
2779 continue
2779 continue
2780 files.append(fn)
2780 files.append(fn)
2781
2781
2782 if fn not in matches[rev]:
2782 if fn not in matches[rev]:
2783 try:
2783 try:
2784 content = flog.read(fnode)
2784 content = flog.read(fnode)
2785 except error.WdirUnsupported:
2785 except error.WdirUnsupported:
2786 content = ctx[fn].data()
2786 content = ctx[fn].data()
2787 grepbody(fn, rev, content)
2787 grepbody(fn, rev, content)
2788
2788
2789 pfn = copy or fn
2789 pfn = copy or fn
2790 if pfn not in matches[parent]:
2790 if pfn not in matches[parent]:
2791 try:
2791 try:
2792 fnode = pctx.filenode(pfn)
2792 fnode = pctx.filenode(pfn)
2793 grepbody(pfn, parent, flog.read(fnode))
2793 grepbody(pfn, parent, flog.read(fnode))
2794 except error.LookupError:
2794 except error.LookupError:
2795 pass
2795 pass
2796
2796
2797 ui.pager('grep')
2797 ui.pager('grep')
2798 fm = ui.formatter('grep', opts)
2798 fm = ui.formatter('grep', opts)
2799 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2799 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2800 rev = ctx.rev()
2800 rev = ctx.rev()
2801 parent = ctx.p1().rev()
2801 parent = ctx.p1().rev()
2802 for fn in sorted(revfiles.get(rev, [])):
2802 for fn in sorted(revfiles.get(rev, [])):
2803 states = matches[rev][fn]
2803 states = matches[rev][fn]
2804 copy = copies.get(rev, {}).get(fn)
2804 copy = copies.get(rev, {}).get(fn)
2805 if fn in skip:
2805 if fn in skip:
2806 if copy:
2806 if copy:
2807 skip[copy] = True
2807 skip[copy] = True
2808 continue
2808 continue
2809 pstates = matches.get(parent, {}).get(copy or fn, [])
2809 pstates = matches.get(parent, {}).get(copy or fn, [])
2810 if pstates or states:
2810 if pstates or states:
2811 r = display(fm, fn, ctx, pstates, states)
2811 r = display(fm, fn, ctx, pstates, states)
2812 found = found or r
2812 found = found or r
2813 if r and not diff and not all_files:
2813 if r and not diff and not all_files:
2814 skip[fn] = True
2814 skip[fn] = True
2815 if copy:
2815 if copy:
2816 skip[copy] = True
2816 skip[copy] = True
2817 del revfiles[rev]
2817 del revfiles[rev]
2818 # We will keep the matches dict for the duration of the window
2818 # We will keep the matches dict for the duration of the window
2819 # clear the matches dict once the window is over
2819 # clear the matches dict once the window is over
2820 if not revfiles:
2820 if not revfiles:
2821 matches.clear()
2821 matches.clear()
2822 fm.end()
2822 fm.end()
2823
2823
2824 return not found
2824 return not found
2825
2825
2826 @command('heads',
2826 @command('heads',
2827 [('r', 'rev', '',
2827 [('r', 'rev', '',
2828 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2828 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2829 ('t', 'topo', False, _('show topological heads only')),
2829 ('t', 'topo', False, _('show topological heads only')),
2830 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2830 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2831 ('c', 'closed', False, _('show normal and closed branch heads')),
2831 ('c', 'closed', False, _('show normal and closed branch heads')),
2832 ] + templateopts,
2832 ] + templateopts,
2833 _('[-ct] [-r STARTREV] [REV]...'),
2833 _('[-ct] [-r STARTREV] [REV]...'),
2834 intents={INTENT_READONLY})
2834 intents={INTENT_READONLY})
2835 def heads(ui, repo, *branchrevs, **opts):
2835 def heads(ui, repo, *branchrevs, **opts):
2836 """show branch heads
2836 """show branch heads
2837
2837
2838 With no arguments, show all open branch heads in the repository.
2838 With no arguments, show all open branch heads in the repository.
2839 Branch heads are changesets that have no descendants on the
2839 Branch heads are changesets that have no descendants on the
2840 same branch. They are where development generally takes place and
2840 same branch. They are where development generally takes place and
2841 are the usual targets for update and merge operations.
2841 are the usual targets for update and merge operations.
2842
2842
2843 If one or more REVs are given, only open branch heads on the
2843 If one or more REVs are given, only open branch heads on the
2844 branches associated with the specified changesets are shown. This
2844 branches associated with the specified changesets are shown. This
2845 means that you can use :hg:`heads .` to see the heads on the
2845 means that you can use :hg:`heads .` to see the heads on the
2846 currently checked-out branch.
2846 currently checked-out branch.
2847
2847
2848 If -c/--closed is specified, also show branch heads marked closed
2848 If -c/--closed is specified, also show branch heads marked closed
2849 (see :hg:`commit --close-branch`).
2849 (see :hg:`commit --close-branch`).
2850
2850
2851 If STARTREV is specified, only those heads that are descendants of
2851 If STARTREV is specified, only those heads that are descendants of
2852 STARTREV will be displayed.
2852 STARTREV will be displayed.
2853
2853
2854 If -t/--topo is specified, named branch mechanics will be ignored and only
2854 If -t/--topo is specified, named branch mechanics will be ignored and only
2855 topological heads (changesets with no children) will be shown.
2855 topological heads (changesets with no children) will be shown.
2856
2856
2857 Returns 0 if matching heads are found, 1 if not.
2857 Returns 0 if matching heads are found, 1 if not.
2858 """
2858 """
2859
2859
2860 opts = pycompat.byteskwargs(opts)
2860 opts = pycompat.byteskwargs(opts)
2861 start = None
2861 start = None
2862 rev = opts.get('rev')
2862 rev = opts.get('rev')
2863 if rev:
2863 if rev:
2864 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2864 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2865 start = scmutil.revsingle(repo, rev, None).node()
2865 start = scmutil.revsingle(repo, rev, None).node()
2866
2866
2867 if opts.get('topo'):
2867 if opts.get('topo'):
2868 heads = [repo[h] for h in repo.heads(start)]
2868 heads = [repo[h] for h in repo.heads(start)]
2869 else:
2869 else:
2870 heads = []
2870 heads = []
2871 for branch in repo.branchmap():
2871 for branch in repo.branchmap():
2872 heads += repo.branchheads(branch, start, opts.get('closed'))
2872 heads += repo.branchheads(branch, start, opts.get('closed'))
2873 heads = [repo[h] for h in heads]
2873 heads = [repo[h] for h in heads]
2874
2874
2875 if branchrevs:
2875 if branchrevs:
2876 branches = set(repo[r].branch()
2876 branches = set(repo[r].branch()
2877 for r in scmutil.revrange(repo, branchrevs))
2877 for r in scmutil.revrange(repo, branchrevs))
2878 heads = [h for h in heads if h.branch() in branches]
2878 heads = [h for h in heads if h.branch() in branches]
2879
2879
2880 if opts.get('active') and branchrevs:
2880 if opts.get('active') and branchrevs:
2881 dagheads = repo.heads(start)
2881 dagheads = repo.heads(start)
2882 heads = [h for h in heads if h.node() in dagheads]
2882 heads = [h for h in heads if h.node() in dagheads]
2883
2883
2884 if branchrevs:
2884 if branchrevs:
2885 haveheads = set(h.branch() for h in heads)
2885 haveheads = set(h.branch() for h in heads)
2886 if branches - haveheads:
2886 if branches - haveheads:
2887 headless = ', '.join(b for b in branches - haveheads)
2887 headless = ', '.join(b for b in branches - haveheads)
2888 msg = _('no open branch heads found on branches %s')
2888 msg = _('no open branch heads found on branches %s')
2889 if opts.get('rev'):
2889 if opts.get('rev'):
2890 msg += _(' (started at %s)') % opts['rev']
2890 msg += _(' (started at %s)') % opts['rev']
2891 ui.warn((msg + '\n') % headless)
2891 ui.warn((msg + '\n') % headless)
2892
2892
2893 if not heads:
2893 if not heads:
2894 return 1
2894 return 1
2895
2895
2896 ui.pager('heads')
2896 ui.pager('heads')
2897 heads = sorted(heads, key=lambda x: -x.rev())
2897 heads = sorted(heads, key=lambda x: -x.rev())
2898 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2898 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2899 for ctx in heads:
2899 for ctx in heads:
2900 displayer.show(ctx)
2900 displayer.show(ctx)
2901 displayer.close()
2901 displayer.close()
2902
2902
2903 @command('help',
2903 @command('help',
2904 [('e', 'extension', None, _('show only help for extensions')),
2904 [('e', 'extension', None, _('show only help for extensions')),
2905 ('c', 'command', None, _('show only help for commands')),
2905 ('c', 'command', None, _('show only help for commands')),
2906 ('k', 'keyword', None, _('show topics matching keyword')),
2906 ('k', 'keyword', None, _('show topics matching keyword')),
2907 ('s', 'system', [], _('show help for specific platform(s)')),
2907 ('s', 'system', [], _('show help for specific platform(s)')),
2908 ],
2908 ],
2909 _('[-ecks] [TOPIC]'),
2909 _('[-ecks] [TOPIC]'),
2910 norepo=True,
2910 norepo=True,
2911 intents={INTENT_READONLY})
2911 intents={INTENT_READONLY})
2912 def help_(ui, name=None, **opts):
2912 def help_(ui, name=None, **opts):
2913 """show help for a given topic or a help overview
2913 """show help for a given topic or a help overview
2914
2914
2915 With no arguments, print a list of commands with short help messages.
2915 With no arguments, print a list of commands with short help messages.
2916
2916
2917 Given a topic, extension, or command name, print help for that
2917 Given a topic, extension, or command name, print help for that
2918 topic.
2918 topic.
2919
2919
2920 Returns 0 if successful.
2920 Returns 0 if successful.
2921 """
2921 """
2922
2922
2923 keep = opts.get(r'system') or []
2923 keep = opts.get(r'system') or []
2924 if len(keep) == 0:
2924 if len(keep) == 0:
2925 if pycompat.sysplatform.startswith('win'):
2925 if pycompat.sysplatform.startswith('win'):
2926 keep.append('windows')
2926 keep.append('windows')
2927 elif pycompat.sysplatform == 'OpenVMS':
2927 elif pycompat.sysplatform == 'OpenVMS':
2928 keep.append('vms')
2928 keep.append('vms')
2929 elif pycompat.sysplatform == 'plan9':
2929 elif pycompat.sysplatform == 'plan9':
2930 keep.append('plan9')
2930 keep.append('plan9')
2931 else:
2931 else:
2932 keep.append('unix')
2932 keep.append('unix')
2933 keep.append(pycompat.sysplatform.lower())
2933 keep.append(pycompat.sysplatform.lower())
2934 if ui.verbose:
2934 if ui.verbose:
2935 keep.append('verbose')
2935 keep.append('verbose')
2936
2936
2937 commands = sys.modules[__name__]
2937 commands = sys.modules[__name__]
2938 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2938 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2939 ui.pager('help')
2939 ui.pager('help')
2940 ui.write(formatted)
2940 ui.write(formatted)
2941
2941
2942
2942
2943 @command('identify|id',
2943 @command('identify|id',
2944 [('r', 'rev', '',
2944 [('r', 'rev', '',
2945 _('identify the specified revision'), _('REV')),
2945 _('identify the specified revision'), _('REV')),
2946 ('n', 'num', None, _('show local revision number')),
2946 ('n', 'num', None, _('show local revision number')),
2947 ('i', 'id', None, _('show global revision id')),
2947 ('i', 'id', None, _('show global revision id')),
2948 ('b', 'branch', None, _('show branch')),
2948 ('b', 'branch', None, _('show branch')),
2949 ('t', 'tags', None, _('show tags')),
2949 ('t', 'tags', None, _('show tags')),
2950 ('B', 'bookmarks', None, _('show bookmarks')),
2950 ('B', 'bookmarks', None, _('show bookmarks')),
2951 ] + remoteopts + formatteropts,
2951 ] + remoteopts + formatteropts,
2952 _('[-nibtB] [-r REV] [SOURCE]'),
2952 _('[-nibtB] [-r REV] [SOURCE]'),
2953 optionalrepo=True,
2953 optionalrepo=True,
2954 intents={INTENT_READONLY})
2954 intents={INTENT_READONLY})
2955 def identify(ui, repo, source=None, rev=None,
2955 def identify(ui, repo, source=None, rev=None,
2956 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2956 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2957 """identify the working directory or specified revision
2957 """identify the working directory or specified revision
2958
2958
2959 Print a summary identifying the repository state at REV using one or
2959 Print a summary identifying the repository state at REV using one or
2960 two parent hash identifiers, followed by a "+" if the working
2960 two parent hash identifiers, followed by a "+" if the working
2961 directory has uncommitted changes, the branch name (if not default),
2961 directory has uncommitted changes, the branch name (if not default),
2962 a list of tags, and a list of bookmarks.
2962 a list of tags, and a list of bookmarks.
2963
2963
2964 When REV is not given, print a summary of the current state of the
2964 When REV is not given, print a summary of the current state of the
2965 repository including the working directory. Specify -r. to get information
2965 repository including the working directory. Specify -r. to get information
2966 of the working directory parent without scanning uncommitted changes.
2966 of the working directory parent without scanning uncommitted changes.
2967
2967
2968 Specifying a path to a repository root or Mercurial bundle will
2968 Specifying a path to a repository root or Mercurial bundle will
2969 cause lookup to operate on that repository/bundle.
2969 cause lookup to operate on that repository/bundle.
2970
2970
2971 .. container:: verbose
2971 .. container:: verbose
2972
2972
2973 Examples:
2973 Examples:
2974
2974
2975 - generate a build identifier for the working directory::
2975 - generate a build identifier for the working directory::
2976
2976
2977 hg id --id > build-id.dat
2977 hg id --id > build-id.dat
2978
2978
2979 - find the revision corresponding to a tag::
2979 - find the revision corresponding to a tag::
2980
2980
2981 hg id -n -r 1.3
2981 hg id -n -r 1.3
2982
2982
2983 - check the most recent revision of a remote repository::
2983 - check the most recent revision of a remote repository::
2984
2984
2985 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2985 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2986
2986
2987 See :hg:`log` for generating more information about specific revisions,
2987 See :hg:`log` for generating more information about specific revisions,
2988 including full hash identifiers.
2988 including full hash identifiers.
2989
2989
2990 Returns 0 if successful.
2990 Returns 0 if successful.
2991 """
2991 """
2992
2992
2993 opts = pycompat.byteskwargs(opts)
2993 opts = pycompat.byteskwargs(opts)
2994 if not repo and not source:
2994 if not repo and not source:
2995 raise error.Abort(_("there is no Mercurial repository here "
2995 raise error.Abort(_("there is no Mercurial repository here "
2996 "(.hg not found)"))
2996 "(.hg not found)"))
2997
2997
2998 default = not (num or id or branch or tags or bookmarks)
2998 default = not (num or id or branch or tags or bookmarks)
2999 output = []
2999 output = []
3000 revs = []
3000 revs = []
3001
3001
3002 if source:
3002 if source:
3003 source, branches = hg.parseurl(ui.expandpath(source))
3003 source, branches = hg.parseurl(ui.expandpath(source))
3004 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3004 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3005 repo = peer.local()
3005 repo = peer.local()
3006 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3006 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3007
3007
3008 fm = ui.formatter('identify', opts)
3008 fm = ui.formatter('identify', opts)
3009 fm.startitem()
3009 fm.startitem()
3010
3010
3011 if not repo:
3011 if not repo:
3012 if num or branch or tags:
3012 if num or branch or tags:
3013 raise error.Abort(
3013 raise error.Abort(
3014 _("can't query remote revision number, branch, or tags"))
3014 _("can't query remote revision number, branch, or tags"))
3015 if not rev and revs:
3015 if not rev and revs:
3016 rev = revs[0]
3016 rev = revs[0]
3017 if not rev:
3017 if not rev:
3018 rev = "tip"
3018 rev = "tip"
3019
3019
3020 remoterev = peer.lookup(rev)
3020 remoterev = peer.lookup(rev)
3021 hexrev = fm.hexfunc(remoterev)
3021 hexrev = fm.hexfunc(remoterev)
3022 if default or id:
3022 if default or id:
3023 output = [hexrev]
3023 output = [hexrev]
3024 fm.data(id=hexrev)
3024 fm.data(id=hexrev)
3025
3025
3026 @util.cachefunc
3026 def getbms():
3027 def getbms():
3027 bms = []
3028 bms = []
3028
3029
3029 if 'bookmarks' in peer.listkeys('namespaces'):
3030 if 'bookmarks' in peer.listkeys('namespaces'):
3030 hexremoterev = hex(remoterev)
3031 hexremoterev = hex(remoterev)
3031 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3032 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3032 if bmr == hexremoterev]
3033 if bmr == hexremoterev]
3033
3034
3034 return sorted(bms)
3035 return sorted(bms)
3035
3036
3036 bms = getbms()
3037 if bookmarks:
3037 if bookmarks:
3038 output.extend(bms)
3038 output.extend(getbms())
3039 elif default and not ui.quiet:
3039 elif default and not ui.quiet:
3040 # multiple bookmarks for a single parent separated by '/'
3040 # multiple bookmarks for a single parent separated by '/'
3041 bm = '/'.join(bms)
3041 bm = '/'.join(getbms())
3042 if bm:
3042 if bm:
3043 output.append(bm)
3043 output.append(bm)
3044
3044
3045 fm.data(node=hex(remoterev))
3045 fm.data(node=hex(remoterev))
3046 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3046 if 'bookmarks' in fm.datahint():
3047 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3047 else:
3048 else:
3048 if rev:
3049 if rev:
3049 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3050 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3050 ctx = scmutil.revsingle(repo, rev, None)
3051 ctx = scmutil.revsingle(repo, rev, None)
3051
3052
3052 if ctx.rev() is None:
3053 if ctx.rev() is None:
3053 ctx = repo[None]
3054 ctx = repo[None]
3054 parents = ctx.parents()
3055 parents = ctx.parents()
3055 taglist = []
3056 taglist = []
3056 for p in parents:
3057 for p in parents:
3057 taglist.extend(p.tags())
3058 taglist.extend(p.tags())
3058
3059
3059 dirty = ""
3060 dirty = ""
3060 if ctx.dirty(missing=True, merge=False, branch=False):
3061 if ctx.dirty(missing=True, merge=False, branch=False):
3061 dirty = '+'
3062 dirty = '+'
3062 fm.data(dirty=dirty)
3063 fm.data(dirty=dirty)
3063
3064
3064 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3065 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3065 if default or id:
3066 if default or id:
3066 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3067 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3067 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3068 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3068
3069
3069 if num:
3070 if num:
3070 numoutput = ["%d" % p.rev() for p in parents]
3071 numoutput = ["%d" % p.rev() for p in parents]
3071 output.append("%s%s" % ('+'.join(numoutput), dirty))
3072 output.append("%s%s" % ('+'.join(numoutput), dirty))
3072
3073
3073 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3074 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3074 for p in parents], name='node'))
3075 for p in parents], name='node'))
3075 else:
3076 else:
3076 hexoutput = fm.hexfunc(ctx.node())
3077 hexoutput = fm.hexfunc(ctx.node())
3077 if default or id:
3078 if default or id:
3078 output = [hexoutput]
3079 output = [hexoutput]
3079 fm.data(id=hexoutput)
3080 fm.data(id=hexoutput)
3080
3081
3081 if num:
3082 if num:
3082 output.append(pycompat.bytestr(ctx.rev()))
3083 output.append(pycompat.bytestr(ctx.rev()))
3083 taglist = ctx.tags()
3084 taglist = ctx.tags()
3084
3085
3085 if default and not ui.quiet:
3086 if default and not ui.quiet:
3086 b = ctx.branch()
3087 b = ctx.branch()
3087 if b != 'default':
3088 if b != 'default':
3088 output.append("(%s)" % b)
3089 output.append("(%s)" % b)
3089
3090
3090 # multiple tags for a single parent separated by '/'
3091 # multiple tags for a single parent separated by '/'
3091 t = '/'.join(taglist)
3092 t = '/'.join(taglist)
3092 if t:
3093 if t:
3093 output.append(t)
3094 output.append(t)
3094
3095
3095 # multiple bookmarks for a single parent separated by '/'
3096 # multiple bookmarks for a single parent separated by '/'
3096 bm = '/'.join(ctx.bookmarks())
3097 bm = '/'.join(ctx.bookmarks())
3097 if bm:
3098 if bm:
3098 output.append(bm)
3099 output.append(bm)
3099 else:
3100 else:
3100 if branch:
3101 if branch:
3101 output.append(ctx.branch())
3102 output.append(ctx.branch())
3102
3103
3103 if tags:
3104 if tags:
3104 output.extend(taglist)
3105 output.extend(taglist)
3105
3106
3106 if bookmarks:
3107 if bookmarks:
3107 output.extend(ctx.bookmarks())
3108 output.extend(ctx.bookmarks())
3108
3109
3109 fm.data(node=ctx.hex())
3110 fm.data(node=ctx.hex())
3110 fm.data(branch=ctx.branch())
3111 fm.data(branch=ctx.branch())
3111 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3112 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3112 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3113 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3113 fm.context(ctx=ctx)
3114 fm.context(ctx=ctx)
3114
3115
3115 fm.plain("%s\n" % ' '.join(output))
3116 fm.plain("%s\n" % ' '.join(output))
3116 fm.end()
3117 fm.end()
3117
3118
3118 @command('import|patch',
3119 @command('import|patch',
3119 [('p', 'strip', 1,
3120 [('p', 'strip', 1,
3120 _('directory strip option for patch. This has the same '
3121 _('directory strip option for patch. This has the same '
3121 'meaning as the corresponding patch option'), _('NUM')),
3122 'meaning as the corresponding patch option'), _('NUM')),
3122 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3123 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3123 ('e', 'edit', False, _('invoke editor on commit messages')),
3124 ('e', 'edit', False, _('invoke editor on commit messages')),
3124 ('f', 'force', None,
3125 ('f', 'force', None,
3125 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3126 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3126 ('', 'no-commit', None,
3127 ('', 'no-commit', None,
3127 _("don't commit, just update the working directory")),
3128 _("don't commit, just update the working directory")),
3128 ('', 'bypass', None,
3129 ('', 'bypass', None,
3129 _("apply patch without touching the working directory")),
3130 _("apply patch without touching the working directory")),
3130 ('', 'partial', None,
3131 ('', 'partial', None,
3131 _('commit even if some hunks fail')),
3132 _('commit even if some hunks fail')),
3132 ('', 'exact', None,
3133 ('', 'exact', None,
3133 _('abort if patch would apply lossily')),
3134 _('abort if patch would apply lossily')),
3134 ('', 'prefix', '',
3135 ('', 'prefix', '',
3135 _('apply patch to subdirectory'), _('DIR')),
3136 _('apply patch to subdirectory'), _('DIR')),
3136 ('', 'import-branch', None,
3137 ('', 'import-branch', None,
3137 _('use any branch information in patch (implied by --exact)'))] +
3138 _('use any branch information in patch (implied by --exact)'))] +
3138 commitopts + commitopts2 + similarityopts,
3139 commitopts + commitopts2 + similarityopts,
3139 _('[OPTION]... PATCH...'))
3140 _('[OPTION]... PATCH...'))
3140 def import_(ui, repo, patch1=None, *patches, **opts):
3141 def import_(ui, repo, patch1=None, *patches, **opts):
3141 """import an ordered set of patches
3142 """import an ordered set of patches
3142
3143
3143 Import a list of patches and commit them individually (unless
3144 Import a list of patches and commit them individually (unless
3144 --no-commit is specified).
3145 --no-commit is specified).
3145
3146
3146 To read a patch from standard input (stdin), use "-" as the patch
3147 To read a patch from standard input (stdin), use "-" as the patch
3147 name. If a URL is specified, the patch will be downloaded from
3148 name. If a URL is specified, the patch will be downloaded from
3148 there.
3149 there.
3149
3150
3150 Import first applies changes to the working directory (unless
3151 Import first applies changes to the working directory (unless
3151 --bypass is specified), import will abort if there are outstanding
3152 --bypass is specified), import will abort if there are outstanding
3152 changes.
3153 changes.
3153
3154
3154 Use --bypass to apply and commit patches directly to the
3155 Use --bypass to apply and commit patches directly to the
3155 repository, without affecting the working directory. Without
3156 repository, without affecting the working directory. Without
3156 --exact, patches will be applied on top of the working directory
3157 --exact, patches will be applied on top of the working directory
3157 parent revision.
3158 parent revision.
3158
3159
3159 You can import a patch straight from a mail message. Even patches
3160 You can import a patch straight from a mail message. Even patches
3160 as attachments work (to use the body part, it must have type
3161 as attachments work (to use the body part, it must have type
3161 text/plain or text/x-patch). From and Subject headers of email
3162 text/plain or text/x-patch). From and Subject headers of email
3162 message are used as default committer and commit message. All
3163 message are used as default committer and commit message. All
3163 text/plain body parts before first diff are added to the commit
3164 text/plain body parts before first diff are added to the commit
3164 message.
3165 message.
3165
3166
3166 If the imported patch was generated by :hg:`export`, user and
3167 If the imported patch was generated by :hg:`export`, user and
3167 description from patch override values from message headers and
3168 description from patch override values from message headers and
3168 body. Values given on command line with -m/--message and -u/--user
3169 body. Values given on command line with -m/--message and -u/--user
3169 override these.
3170 override these.
3170
3171
3171 If --exact is specified, import will set the working directory to
3172 If --exact is specified, import will set the working directory to
3172 the parent of each patch before applying it, and will abort if the
3173 the parent of each patch before applying it, and will abort if the
3173 resulting changeset has a different ID than the one recorded in
3174 resulting changeset has a different ID than the one recorded in
3174 the patch. This will guard against various ways that portable
3175 the patch. This will guard against various ways that portable
3175 patch formats and mail systems might fail to transfer Mercurial
3176 patch formats and mail systems might fail to transfer Mercurial
3176 data or metadata. See :hg:`bundle` for lossless transmission.
3177 data or metadata. See :hg:`bundle` for lossless transmission.
3177
3178
3178 Use --partial to ensure a changeset will be created from the patch
3179 Use --partial to ensure a changeset will be created from the patch
3179 even if some hunks fail to apply. Hunks that fail to apply will be
3180 even if some hunks fail to apply. Hunks that fail to apply will be
3180 written to a <target-file>.rej file. Conflicts can then be resolved
3181 written to a <target-file>.rej file. Conflicts can then be resolved
3181 by hand before :hg:`commit --amend` is run to update the created
3182 by hand before :hg:`commit --amend` is run to update the created
3182 changeset. This flag exists to let people import patches that
3183 changeset. This flag exists to let people import patches that
3183 partially apply without losing the associated metadata (author,
3184 partially apply without losing the associated metadata (author,
3184 date, description, ...).
3185 date, description, ...).
3185
3186
3186 .. note::
3187 .. note::
3187
3188
3188 When no hunks apply cleanly, :hg:`import --partial` will create
3189 When no hunks apply cleanly, :hg:`import --partial` will create
3189 an empty changeset, importing only the patch metadata.
3190 an empty changeset, importing only the patch metadata.
3190
3191
3191 With -s/--similarity, hg will attempt to discover renames and
3192 With -s/--similarity, hg will attempt to discover renames and
3192 copies in the patch in the same way as :hg:`addremove`.
3193 copies in the patch in the same way as :hg:`addremove`.
3193
3194
3194 It is possible to use external patch programs to perform the patch
3195 It is possible to use external patch programs to perform the patch
3195 by setting the ``ui.patch`` configuration option. For the default
3196 by setting the ``ui.patch`` configuration option. For the default
3196 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3197 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3197 See :hg:`help config` for more information about configuration
3198 See :hg:`help config` for more information about configuration
3198 files and how to use these options.
3199 files and how to use these options.
3199
3200
3200 See :hg:`help dates` for a list of formats valid for -d/--date.
3201 See :hg:`help dates` for a list of formats valid for -d/--date.
3201
3202
3202 .. container:: verbose
3203 .. container:: verbose
3203
3204
3204 Examples:
3205 Examples:
3205
3206
3206 - import a traditional patch from a website and detect renames::
3207 - import a traditional patch from a website and detect renames::
3207
3208
3208 hg import -s 80 http://example.com/bugfix.patch
3209 hg import -s 80 http://example.com/bugfix.patch
3209
3210
3210 - import a changeset from an hgweb server::
3211 - import a changeset from an hgweb server::
3211
3212
3212 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3213 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3213
3214
3214 - import all the patches in an Unix-style mbox::
3215 - import all the patches in an Unix-style mbox::
3215
3216
3216 hg import incoming-patches.mbox
3217 hg import incoming-patches.mbox
3217
3218
3218 - import patches from stdin::
3219 - import patches from stdin::
3219
3220
3220 hg import -
3221 hg import -
3221
3222
3222 - attempt to exactly restore an exported changeset (not always
3223 - attempt to exactly restore an exported changeset (not always
3223 possible)::
3224 possible)::
3224
3225
3225 hg import --exact proposed-fix.patch
3226 hg import --exact proposed-fix.patch
3226
3227
3227 - use an external tool to apply a patch which is too fuzzy for
3228 - use an external tool to apply a patch which is too fuzzy for
3228 the default internal tool.
3229 the default internal tool.
3229
3230
3230 hg import --config ui.patch="patch --merge" fuzzy.patch
3231 hg import --config ui.patch="patch --merge" fuzzy.patch
3231
3232
3232 - change the default fuzzing from 2 to a less strict 7
3233 - change the default fuzzing from 2 to a less strict 7
3233
3234
3234 hg import --config ui.fuzz=7 fuzz.patch
3235 hg import --config ui.fuzz=7 fuzz.patch
3235
3236
3236 Returns 0 on success, 1 on partial success (see --partial).
3237 Returns 0 on success, 1 on partial success (see --partial).
3237 """
3238 """
3238
3239
3239 opts = pycompat.byteskwargs(opts)
3240 opts = pycompat.byteskwargs(opts)
3240 if not patch1:
3241 if not patch1:
3241 raise error.Abort(_('need at least one patch to import'))
3242 raise error.Abort(_('need at least one patch to import'))
3242
3243
3243 patches = (patch1,) + patches
3244 patches = (patch1,) + patches
3244
3245
3245 date = opts.get('date')
3246 date = opts.get('date')
3246 if date:
3247 if date:
3247 opts['date'] = dateutil.parsedate(date)
3248 opts['date'] = dateutil.parsedate(date)
3248
3249
3249 exact = opts.get('exact')
3250 exact = opts.get('exact')
3250 update = not opts.get('bypass')
3251 update = not opts.get('bypass')
3251 if not update and opts.get('no_commit'):
3252 if not update and opts.get('no_commit'):
3252 raise error.Abort(_('cannot use --no-commit with --bypass'))
3253 raise error.Abort(_('cannot use --no-commit with --bypass'))
3253 try:
3254 try:
3254 sim = float(opts.get('similarity') or 0)
3255 sim = float(opts.get('similarity') or 0)
3255 except ValueError:
3256 except ValueError:
3256 raise error.Abort(_('similarity must be a number'))
3257 raise error.Abort(_('similarity must be a number'))
3257 if sim < 0 or sim > 100:
3258 if sim < 0 or sim > 100:
3258 raise error.Abort(_('similarity must be between 0 and 100'))
3259 raise error.Abort(_('similarity must be between 0 and 100'))
3259 if sim and not update:
3260 if sim and not update:
3260 raise error.Abort(_('cannot use --similarity with --bypass'))
3261 raise error.Abort(_('cannot use --similarity with --bypass'))
3261 if exact:
3262 if exact:
3262 if opts.get('edit'):
3263 if opts.get('edit'):
3263 raise error.Abort(_('cannot use --exact with --edit'))
3264 raise error.Abort(_('cannot use --exact with --edit'))
3264 if opts.get('prefix'):
3265 if opts.get('prefix'):
3265 raise error.Abort(_('cannot use --exact with --prefix'))
3266 raise error.Abort(_('cannot use --exact with --prefix'))
3266
3267
3267 base = opts["base"]
3268 base = opts["base"]
3268 msgs = []
3269 msgs = []
3269 ret = 0
3270 ret = 0
3270
3271
3271 with repo.wlock():
3272 with repo.wlock():
3272 if update:
3273 if update:
3273 cmdutil.checkunfinished(repo)
3274 cmdutil.checkunfinished(repo)
3274 if (exact or not opts.get('force')):
3275 if (exact or not opts.get('force')):
3275 cmdutil.bailifchanged(repo)
3276 cmdutil.bailifchanged(repo)
3276
3277
3277 if not opts.get('no_commit'):
3278 if not opts.get('no_commit'):
3278 lock = repo.lock
3279 lock = repo.lock
3279 tr = lambda: repo.transaction('import')
3280 tr = lambda: repo.transaction('import')
3280 dsguard = util.nullcontextmanager
3281 dsguard = util.nullcontextmanager
3281 else:
3282 else:
3282 lock = util.nullcontextmanager
3283 lock = util.nullcontextmanager
3283 tr = util.nullcontextmanager
3284 tr = util.nullcontextmanager
3284 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3285 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3285 with lock(), tr(), dsguard():
3286 with lock(), tr(), dsguard():
3286 parents = repo[None].parents()
3287 parents = repo[None].parents()
3287 for patchurl in patches:
3288 for patchurl in patches:
3288 if patchurl == '-':
3289 if patchurl == '-':
3289 ui.status(_('applying patch from stdin\n'))
3290 ui.status(_('applying patch from stdin\n'))
3290 patchfile = ui.fin
3291 patchfile = ui.fin
3291 patchurl = 'stdin' # for error message
3292 patchurl = 'stdin' # for error message
3292 else:
3293 else:
3293 patchurl = os.path.join(base, patchurl)
3294 patchurl = os.path.join(base, patchurl)
3294 ui.status(_('applying %s\n') % patchurl)
3295 ui.status(_('applying %s\n') % patchurl)
3295 patchfile = hg.openpath(ui, patchurl)
3296 patchfile = hg.openpath(ui, patchurl)
3296
3297
3297 haspatch = False
3298 haspatch = False
3298 for hunk in patch.split(patchfile):
3299 for hunk in patch.split(patchfile):
3299 with patch.extract(ui, hunk) as patchdata:
3300 with patch.extract(ui, hunk) as patchdata:
3300 msg, node, rej = cmdutil.tryimportone(ui, repo,
3301 msg, node, rej = cmdutil.tryimportone(ui, repo,
3301 patchdata,
3302 patchdata,
3302 parents, opts,
3303 parents, opts,
3303 msgs, hg.clean)
3304 msgs, hg.clean)
3304 if msg:
3305 if msg:
3305 haspatch = True
3306 haspatch = True
3306 ui.note(msg + '\n')
3307 ui.note(msg + '\n')
3307 if update or exact:
3308 if update or exact:
3308 parents = repo[None].parents()
3309 parents = repo[None].parents()
3309 else:
3310 else:
3310 parents = [repo[node]]
3311 parents = [repo[node]]
3311 if rej:
3312 if rej:
3312 ui.write_err(_("patch applied partially\n"))
3313 ui.write_err(_("patch applied partially\n"))
3313 ui.write_err(_("(fix the .rej files and run "
3314 ui.write_err(_("(fix the .rej files and run "
3314 "`hg commit --amend`)\n"))
3315 "`hg commit --amend`)\n"))
3315 ret = 1
3316 ret = 1
3316 break
3317 break
3317
3318
3318 if not haspatch:
3319 if not haspatch:
3319 raise error.Abort(_('%s: no diffs found') % patchurl)
3320 raise error.Abort(_('%s: no diffs found') % patchurl)
3320
3321
3321 if msgs:
3322 if msgs:
3322 repo.savecommitmessage('\n* * *\n'.join(msgs))
3323 repo.savecommitmessage('\n* * *\n'.join(msgs))
3323 return ret
3324 return ret
3324
3325
3325 @command('incoming|in',
3326 @command('incoming|in',
3326 [('f', 'force', None,
3327 [('f', 'force', None,
3327 _('run even if remote repository is unrelated')),
3328 _('run even if remote repository is unrelated')),
3328 ('n', 'newest-first', None, _('show newest record first')),
3329 ('n', 'newest-first', None, _('show newest record first')),
3329 ('', 'bundle', '',
3330 ('', 'bundle', '',
3330 _('file to store the bundles into'), _('FILE')),
3331 _('file to store the bundles into'), _('FILE')),
3331 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3332 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3332 ('B', 'bookmarks', False, _("compare bookmarks")),
3333 ('B', 'bookmarks', False, _("compare bookmarks")),
3333 ('b', 'branch', [],
3334 ('b', 'branch', [],
3334 _('a specific branch you would like to pull'), _('BRANCH')),
3335 _('a specific branch you would like to pull'), _('BRANCH')),
3335 ] + logopts + remoteopts + subrepoopts,
3336 ] + logopts + remoteopts + subrepoopts,
3336 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3337 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3337 def incoming(ui, repo, source="default", **opts):
3338 def incoming(ui, repo, source="default", **opts):
3338 """show new changesets found in source
3339 """show new changesets found in source
3339
3340
3340 Show new changesets found in the specified path/URL or the default
3341 Show new changesets found in the specified path/URL or the default
3341 pull location. These are the changesets that would have been pulled
3342 pull location. These are the changesets that would have been pulled
3342 by :hg:`pull` at the time you issued this command.
3343 by :hg:`pull` at the time you issued this command.
3343
3344
3344 See pull for valid source format details.
3345 See pull for valid source format details.
3345
3346
3346 .. container:: verbose
3347 .. container:: verbose
3347
3348
3348 With -B/--bookmarks, the result of bookmark comparison between
3349 With -B/--bookmarks, the result of bookmark comparison between
3349 local and remote repositories is displayed. With -v/--verbose,
3350 local and remote repositories is displayed. With -v/--verbose,
3350 status is also displayed for each bookmark like below::
3351 status is also displayed for each bookmark like below::
3351
3352
3352 BM1 01234567890a added
3353 BM1 01234567890a added
3353 BM2 1234567890ab advanced
3354 BM2 1234567890ab advanced
3354 BM3 234567890abc diverged
3355 BM3 234567890abc diverged
3355 BM4 34567890abcd changed
3356 BM4 34567890abcd changed
3356
3357
3357 The action taken locally when pulling depends on the
3358 The action taken locally when pulling depends on the
3358 status of each bookmark:
3359 status of each bookmark:
3359
3360
3360 :``added``: pull will create it
3361 :``added``: pull will create it
3361 :``advanced``: pull will update it
3362 :``advanced``: pull will update it
3362 :``diverged``: pull will create a divergent bookmark
3363 :``diverged``: pull will create a divergent bookmark
3363 :``changed``: result depends on remote changesets
3364 :``changed``: result depends on remote changesets
3364
3365
3365 From the point of view of pulling behavior, bookmark
3366 From the point of view of pulling behavior, bookmark
3366 existing only in the remote repository are treated as ``added``,
3367 existing only in the remote repository are treated as ``added``,
3367 even if it is in fact locally deleted.
3368 even if it is in fact locally deleted.
3368
3369
3369 .. container:: verbose
3370 .. container:: verbose
3370
3371
3371 For remote repository, using --bundle avoids downloading the
3372 For remote repository, using --bundle avoids downloading the
3372 changesets twice if the incoming is followed by a pull.
3373 changesets twice if the incoming is followed by a pull.
3373
3374
3374 Examples:
3375 Examples:
3375
3376
3376 - show incoming changes with patches and full description::
3377 - show incoming changes with patches and full description::
3377
3378
3378 hg incoming -vp
3379 hg incoming -vp
3379
3380
3380 - show incoming changes excluding merges, store a bundle::
3381 - show incoming changes excluding merges, store a bundle::
3381
3382
3382 hg in -vpM --bundle incoming.hg
3383 hg in -vpM --bundle incoming.hg
3383 hg pull incoming.hg
3384 hg pull incoming.hg
3384
3385
3385 - briefly list changes inside a bundle::
3386 - briefly list changes inside a bundle::
3386
3387
3387 hg in changes.hg -T "{desc|firstline}\\n"
3388 hg in changes.hg -T "{desc|firstline}\\n"
3388
3389
3389 Returns 0 if there are incoming changes, 1 otherwise.
3390 Returns 0 if there are incoming changes, 1 otherwise.
3390 """
3391 """
3391 opts = pycompat.byteskwargs(opts)
3392 opts = pycompat.byteskwargs(opts)
3392 if opts.get('graph'):
3393 if opts.get('graph'):
3393 logcmdutil.checkunsupportedgraphflags([], opts)
3394 logcmdutil.checkunsupportedgraphflags([], opts)
3394 def display(other, chlist, displayer):
3395 def display(other, chlist, displayer):
3395 revdag = logcmdutil.graphrevs(other, chlist, opts)
3396 revdag = logcmdutil.graphrevs(other, chlist, opts)
3396 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3397 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3397 graphmod.asciiedges)
3398 graphmod.asciiedges)
3398
3399
3399 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3400 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3400 return 0
3401 return 0
3401
3402
3402 if opts.get('bundle') and opts.get('subrepos'):
3403 if opts.get('bundle') and opts.get('subrepos'):
3403 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3404 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3404
3405
3405 if opts.get('bookmarks'):
3406 if opts.get('bookmarks'):
3406 source, branches = hg.parseurl(ui.expandpath(source),
3407 source, branches = hg.parseurl(ui.expandpath(source),
3407 opts.get('branch'))
3408 opts.get('branch'))
3408 other = hg.peer(repo, opts, source)
3409 other = hg.peer(repo, opts, source)
3409 if 'bookmarks' not in other.listkeys('namespaces'):
3410 if 'bookmarks' not in other.listkeys('namespaces'):
3410 ui.warn(_("remote doesn't support bookmarks\n"))
3411 ui.warn(_("remote doesn't support bookmarks\n"))
3411 return 0
3412 return 0
3412 ui.pager('incoming')
3413 ui.pager('incoming')
3413 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3414 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3414 return bookmarks.incoming(ui, repo, other)
3415 return bookmarks.incoming(ui, repo, other)
3415
3416
3416 repo._subtoppath = ui.expandpath(source)
3417 repo._subtoppath = ui.expandpath(source)
3417 try:
3418 try:
3418 return hg.incoming(ui, repo, source, opts)
3419 return hg.incoming(ui, repo, source, opts)
3419 finally:
3420 finally:
3420 del repo._subtoppath
3421 del repo._subtoppath
3421
3422
3422
3423
3423 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3424 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3424 norepo=True)
3425 norepo=True)
3425 def init(ui, dest=".", **opts):
3426 def init(ui, dest=".", **opts):
3426 """create a new repository in the given directory
3427 """create a new repository in the given directory
3427
3428
3428 Initialize a new repository in the given directory. If the given
3429 Initialize a new repository in the given directory. If the given
3429 directory does not exist, it will be created.
3430 directory does not exist, it will be created.
3430
3431
3431 If no directory is given, the current directory is used.
3432 If no directory is given, the current directory is used.
3432
3433
3433 It is possible to specify an ``ssh://`` URL as the destination.
3434 It is possible to specify an ``ssh://`` URL as the destination.
3434 See :hg:`help urls` for more information.
3435 See :hg:`help urls` for more information.
3435
3436
3436 Returns 0 on success.
3437 Returns 0 on success.
3437 """
3438 """
3438 opts = pycompat.byteskwargs(opts)
3439 opts = pycompat.byteskwargs(opts)
3439 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3440 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3440
3441
3441 @command('locate',
3442 @command('locate',
3442 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3443 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3443 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3444 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3444 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3445 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3445 ] + walkopts,
3446 ] + walkopts,
3446 _('[OPTION]... [PATTERN]...'))
3447 _('[OPTION]... [PATTERN]...'))
3447 def locate(ui, repo, *pats, **opts):
3448 def locate(ui, repo, *pats, **opts):
3448 """locate files matching specific patterns (DEPRECATED)
3449 """locate files matching specific patterns (DEPRECATED)
3449
3450
3450 Print files under Mercurial control in the working directory whose
3451 Print files under Mercurial control in the working directory whose
3451 names match the given patterns.
3452 names match the given patterns.
3452
3453
3453 By default, this command searches all directories in the working
3454 By default, this command searches all directories in the working
3454 directory. To search just the current directory and its
3455 directory. To search just the current directory and its
3455 subdirectories, use "--include .".
3456 subdirectories, use "--include .".
3456
3457
3457 If no patterns are given to match, this command prints the names
3458 If no patterns are given to match, this command prints the names
3458 of all files under Mercurial control in the working directory.
3459 of all files under Mercurial control in the working directory.
3459
3460
3460 If you want to feed the output of this command into the "xargs"
3461 If you want to feed the output of this command into the "xargs"
3461 command, use the -0 option to both this command and "xargs". This
3462 command, use the -0 option to both this command and "xargs". This
3462 will avoid the problem of "xargs" treating single filenames that
3463 will avoid the problem of "xargs" treating single filenames that
3463 contain whitespace as multiple filenames.
3464 contain whitespace as multiple filenames.
3464
3465
3465 See :hg:`help files` for a more versatile command.
3466 See :hg:`help files` for a more versatile command.
3466
3467
3467 Returns 0 if a match is found, 1 otherwise.
3468 Returns 0 if a match is found, 1 otherwise.
3468 """
3469 """
3469 opts = pycompat.byteskwargs(opts)
3470 opts = pycompat.byteskwargs(opts)
3470 if opts.get('print0'):
3471 if opts.get('print0'):
3471 end = '\0'
3472 end = '\0'
3472 else:
3473 else:
3473 end = '\n'
3474 end = '\n'
3474 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3475 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3475
3476
3476 ret = 1
3477 ret = 1
3477 m = scmutil.match(ctx, pats, opts, default='relglob',
3478 m = scmutil.match(ctx, pats, opts, default='relglob',
3478 badfn=lambda x, y: False)
3479 badfn=lambda x, y: False)
3479
3480
3480 ui.pager('locate')
3481 ui.pager('locate')
3481 if ctx.rev() is None:
3482 if ctx.rev() is None:
3482 # When run on the working copy, "locate" includes removed files, so
3483 # When run on the working copy, "locate" includes removed files, so
3483 # we get the list of files from the dirstate.
3484 # we get the list of files from the dirstate.
3484 filesgen = sorted(repo.dirstate.matches(m))
3485 filesgen = sorted(repo.dirstate.matches(m))
3485 else:
3486 else:
3486 filesgen = ctx.matches(m)
3487 filesgen = ctx.matches(m)
3487 for abs in filesgen:
3488 for abs in filesgen:
3488 if opts.get('fullpath'):
3489 if opts.get('fullpath'):
3489 ui.write(repo.wjoin(abs), end)
3490 ui.write(repo.wjoin(abs), end)
3490 else:
3491 else:
3491 ui.write(((pats and m.rel(abs)) or abs), end)
3492 ui.write(((pats and m.rel(abs)) or abs), end)
3492 ret = 0
3493 ret = 0
3493
3494
3494 return ret
3495 return ret
3495
3496
3496 @command('^log|history',
3497 @command('^log|history',
3497 [('f', 'follow', None,
3498 [('f', 'follow', None,
3498 _('follow changeset history, or file history across copies and renames')),
3499 _('follow changeset history, or file history across copies and renames')),
3499 ('', 'follow-first', None,
3500 ('', 'follow-first', None,
3500 _('only follow the first parent of merge changesets (DEPRECATED)')),
3501 _('only follow the first parent of merge changesets (DEPRECATED)')),
3501 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3502 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3502 ('C', 'copies', None, _('show copied files')),
3503 ('C', 'copies', None, _('show copied files')),
3503 ('k', 'keyword', [],
3504 ('k', 'keyword', [],
3504 _('do case-insensitive search for a given text'), _('TEXT')),
3505 _('do case-insensitive search for a given text'), _('TEXT')),
3505 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3506 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3506 ('L', 'line-range', [],
3507 ('L', 'line-range', [],
3507 _('follow line range of specified file (EXPERIMENTAL)'),
3508 _('follow line range of specified file (EXPERIMENTAL)'),
3508 _('FILE,RANGE')),
3509 _('FILE,RANGE')),
3509 ('', 'removed', None, _('include revisions where files were removed')),
3510 ('', 'removed', None, _('include revisions where files were removed')),
3510 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3511 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3511 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3512 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3512 ('', 'only-branch', [],
3513 ('', 'only-branch', [],
3513 _('show only changesets within the given named branch (DEPRECATED)'),
3514 _('show only changesets within the given named branch (DEPRECATED)'),
3514 _('BRANCH')),
3515 _('BRANCH')),
3515 ('b', 'branch', [],
3516 ('b', 'branch', [],
3516 _('show changesets within the given named branch'), _('BRANCH')),
3517 _('show changesets within the given named branch'), _('BRANCH')),
3517 ('P', 'prune', [],
3518 ('P', 'prune', [],
3518 _('do not display revision or any of its ancestors'), _('REV')),
3519 _('do not display revision or any of its ancestors'), _('REV')),
3519 ] + logopts + walkopts,
3520 ] + logopts + walkopts,
3520 _('[OPTION]... [FILE]'),
3521 _('[OPTION]... [FILE]'),
3521 inferrepo=True,
3522 inferrepo=True,
3522 intents={INTENT_READONLY})
3523 intents={INTENT_READONLY})
3523 def log(ui, repo, *pats, **opts):
3524 def log(ui, repo, *pats, **opts):
3524 """show revision history of entire repository or files
3525 """show revision history of entire repository or files
3525
3526
3526 Print the revision history of the specified files or the entire
3527 Print the revision history of the specified files or the entire
3527 project.
3528 project.
3528
3529
3529 If no revision range is specified, the default is ``tip:0`` unless
3530 If no revision range is specified, the default is ``tip:0`` unless
3530 --follow is set, in which case the working directory parent is
3531 --follow is set, in which case the working directory parent is
3531 used as the starting revision.
3532 used as the starting revision.
3532
3533
3533 File history is shown without following rename or copy history of
3534 File history is shown without following rename or copy history of
3534 files. Use -f/--follow with a filename to follow history across
3535 files. Use -f/--follow with a filename to follow history across
3535 renames and copies. --follow without a filename will only show
3536 renames and copies. --follow without a filename will only show
3536 ancestors of the starting revision.
3537 ancestors of the starting revision.
3537
3538
3538 By default this command prints revision number and changeset id,
3539 By default this command prints revision number and changeset id,
3539 tags, non-trivial parents, user, date and time, and a summary for
3540 tags, non-trivial parents, user, date and time, and a summary for
3540 each commit. When the -v/--verbose switch is used, the list of
3541 each commit. When the -v/--verbose switch is used, the list of
3541 changed files and full commit message are shown.
3542 changed files and full commit message are shown.
3542
3543
3543 With --graph the revisions are shown as an ASCII art DAG with the most
3544 With --graph the revisions are shown as an ASCII art DAG with the most
3544 recent changeset at the top.
3545 recent changeset at the top.
3545 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3546 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3546 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3547 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3547 changeset from the lines below is a parent of the 'o' merge on the same
3548 changeset from the lines below is a parent of the 'o' merge on the same
3548 line.
3549 line.
3549 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3550 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3550 of a '|' indicates one or more revisions in a path are omitted.
3551 of a '|' indicates one or more revisions in a path are omitted.
3551
3552
3552 .. container:: verbose
3553 .. container:: verbose
3553
3554
3554 Use -L/--line-range FILE,M:N options to follow the history of lines
3555 Use -L/--line-range FILE,M:N options to follow the history of lines
3555 from M to N in FILE. With -p/--patch only diff hunks affecting
3556 from M to N in FILE. With -p/--patch only diff hunks affecting
3556 specified line range will be shown. This option requires --follow;
3557 specified line range will be shown. This option requires --follow;
3557 it can be specified multiple times. Currently, this option is not
3558 it can be specified multiple times. Currently, this option is not
3558 compatible with --graph. This option is experimental.
3559 compatible with --graph. This option is experimental.
3559
3560
3560 .. note::
3561 .. note::
3561
3562
3562 :hg:`log --patch` may generate unexpected diff output for merge
3563 :hg:`log --patch` may generate unexpected diff output for merge
3563 changesets, as it will only compare the merge changeset against
3564 changesets, as it will only compare the merge changeset against
3564 its first parent. Also, only files different from BOTH parents
3565 its first parent. Also, only files different from BOTH parents
3565 will appear in files:.
3566 will appear in files:.
3566
3567
3567 .. note::
3568 .. note::
3568
3569
3569 For performance reasons, :hg:`log FILE` may omit duplicate changes
3570 For performance reasons, :hg:`log FILE` may omit duplicate changes
3570 made on branches and will not show removals or mode changes. To
3571 made on branches and will not show removals or mode changes. To
3571 see all such changes, use the --removed switch.
3572 see all such changes, use the --removed switch.
3572
3573
3573 .. container:: verbose
3574 .. container:: verbose
3574
3575
3575 .. note::
3576 .. note::
3576
3577
3577 The history resulting from -L/--line-range options depends on diff
3578 The history resulting from -L/--line-range options depends on diff
3578 options; for instance if white-spaces are ignored, respective changes
3579 options; for instance if white-spaces are ignored, respective changes
3579 with only white-spaces in specified line range will not be listed.
3580 with only white-spaces in specified line range will not be listed.
3580
3581
3581 .. container:: verbose
3582 .. container:: verbose
3582
3583
3583 Some examples:
3584 Some examples:
3584
3585
3585 - changesets with full descriptions and file lists::
3586 - changesets with full descriptions and file lists::
3586
3587
3587 hg log -v
3588 hg log -v
3588
3589
3589 - changesets ancestral to the working directory::
3590 - changesets ancestral to the working directory::
3590
3591
3591 hg log -f
3592 hg log -f
3592
3593
3593 - last 10 commits on the current branch::
3594 - last 10 commits on the current branch::
3594
3595
3595 hg log -l 10 -b .
3596 hg log -l 10 -b .
3596
3597
3597 - changesets showing all modifications of a file, including removals::
3598 - changesets showing all modifications of a file, including removals::
3598
3599
3599 hg log --removed file.c
3600 hg log --removed file.c
3600
3601
3601 - all changesets that touch a directory, with diffs, excluding merges::
3602 - all changesets that touch a directory, with diffs, excluding merges::
3602
3603
3603 hg log -Mp lib/
3604 hg log -Mp lib/
3604
3605
3605 - all revision numbers that match a keyword::
3606 - all revision numbers that match a keyword::
3606
3607
3607 hg log -k bug --template "{rev}\\n"
3608 hg log -k bug --template "{rev}\\n"
3608
3609
3609 - the full hash identifier of the working directory parent::
3610 - the full hash identifier of the working directory parent::
3610
3611
3611 hg log -r . --template "{node}\\n"
3612 hg log -r . --template "{node}\\n"
3612
3613
3613 - list available log templates::
3614 - list available log templates::
3614
3615
3615 hg log -T list
3616 hg log -T list
3616
3617
3617 - check if a given changeset is included in a tagged release::
3618 - check if a given changeset is included in a tagged release::
3618
3619
3619 hg log -r "a21ccf and ancestor(1.9)"
3620 hg log -r "a21ccf and ancestor(1.9)"
3620
3621
3621 - find all changesets by some user in a date range::
3622 - find all changesets by some user in a date range::
3622
3623
3623 hg log -k alice -d "may 2008 to jul 2008"
3624 hg log -k alice -d "may 2008 to jul 2008"
3624
3625
3625 - summary of all changesets after the last tag::
3626 - summary of all changesets after the last tag::
3626
3627
3627 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3628 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3628
3629
3629 - changesets touching lines 13 to 23 for file.c::
3630 - changesets touching lines 13 to 23 for file.c::
3630
3631
3631 hg log -L file.c,13:23
3632 hg log -L file.c,13:23
3632
3633
3633 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3634 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3634 main.c with patch::
3635 main.c with patch::
3635
3636
3636 hg log -L file.c,13:23 -L main.c,2:6 -p
3637 hg log -L file.c,13:23 -L main.c,2:6 -p
3637
3638
3638 See :hg:`help dates` for a list of formats valid for -d/--date.
3639 See :hg:`help dates` for a list of formats valid for -d/--date.
3639
3640
3640 See :hg:`help revisions` for more about specifying and ordering
3641 See :hg:`help revisions` for more about specifying and ordering
3641 revisions.
3642 revisions.
3642
3643
3643 See :hg:`help templates` for more about pre-packaged styles and
3644 See :hg:`help templates` for more about pre-packaged styles and
3644 specifying custom templates. The default template used by the log
3645 specifying custom templates. The default template used by the log
3645 command can be customized via the ``ui.logtemplate`` configuration
3646 command can be customized via the ``ui.logtemplate`` configuration
3646 setting.
3647 setting.
3647
3648
3648 Returns 0 on success.
3649 Returns 0 on success.
3649
3650
3650 """
3651 """
3651 opts = pycompat.byteskwargs(opts)
3652 opts = pycompat.byteskwargs(opts)
3652 linerange = opts.get('line_range')
3653 linerange = opts.get('line_range')
3653
3654
3654 if linerange and not opts.get('follow'):
3655 if linerange and not opts.get('follow'):
3655 raise error.Abort(_('--line-range requires --follow'))
3656 raise error.Abort(_('--line-range requires --follow'))
3656
3657
3657 if linerange and pats:
3658 if linerange and pats:
3658 # TODO: take pats as patterns with no line-range filter
3659 # TODO: take pats as patterns with no line-range filter
3659 raise error.Abort(
3660 raise error.Abort(
3660 _('FILE arguments are not compatible with --line-range option')
3661 _('FILE arguments are not compatible with --line-range option')
3661 )
3662 )
3662
3663
3663 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3664 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3664 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3665 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3665 if linerange:
3666 if linerange:
3666 # TODO: should follow file history from logcmdutil._initialrevs(),
3667 # TODO: should follow file history from logcmdutil._initialrevs(),
3667 # then filter the result by logcmdutil._makerevset() and --limit
3668 # then filter the result by logcmdutil._makerevset() and --limit
3668 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3669 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3669
3670
3670 getrenamed = None
3671 getrenamed = None
3671 if opts.get('copies'):
3672 if opts.get('copies'):
3672 endrev = None
3673 endrev = None
3673 if revs:
3674 if revs:
3674 endrev = revs.max() + 1
3675 endrev = revs.max() + 1
3675 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3676 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3676
3677
3677 ui.pager('log')
3678 ui.pager('log')
3678 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3679 buffered=True)
3680 buffered=True)
3680 if opts.get('graph'):
3681 if opts.get('graph'):
3681 displayfn = logcmdutil.displaygraphrevs
3682 displayfn = logcmdutil.displaygraphrevs
3682 else:
3683 else:
3683 displayfn = logcmdutil.displayrevs
3684 displayfn = logcmdutil.displayrevs
3684 displayfn(ui, repo, revs, displayer, getrenamed)
3685 displayfn(ui, repo, revs, displayer, getrenamed)
3685
3686
3686 @command('manifest',
3687 @command('manifest',
3687 [('r', 'rev', '', _('revision to display'), _('REV')),
3688 [('r', 'rev', '', _('revision to display'), _('REV')),
3688 ('', 'all', False, _("list files from all revisions"))]
3689 ('', 'all', False, _("list files from all revisions"))]
3689 + formatteropts,
3690 + formatteropts,
3690 _('[-r REV]'),
3691 _('[-r REV]'),
3691 intents={INTENT_READONLY})
3692 intents={INTENT_READONLY})
3692 def manifest(ui, repo, node=None, rev=None, **opts):
3693 def manifest(ui, repo, node=None, rev=None, **opts):
3693 """output the current or given revision of the project manifest
3694 """output the current or given revision of the project manifest
3694
3695
3695 Print a list of version controlled files for the given revision.
3696 Print a list of version controlled files for the given revision.
3696 If no revision is given, the first parent of the working directory
3697 If no revision is given, the first parent of the working directory
3697 is used, or the null revision if no revision is checked out.
3698 is used, or the null revision if no revision is checked out.
3698
3699
3699 With -v, print file permissions, symlink and executable bits.
3700 With -v, print file permissions, symlink and executable bits.
3700 With --debug, print file revision hashes.
3701 With --debug, print file revision hashes.
3701
3702
3702 If option --all is specified, the list of all files from all revisions
3703 If option --all is specified, the list of all files from all revisions
3703 is printed. This includes deleted and renamed files.
3704 is printed. This includes deleted and renamed files.
3704
3705
3705 Returns 0 on success.
3706 Returns 0 on success.
3706 """
3707 """
3707 opts = pycompat.byteskwargs(opts)
3708 opts = pycompat.byteskwargs(opts)
3708 fm = ui.formatter('manifest', opts)
3709 fm = ui.formatter('manifest', opts)
3709
3710
3710 if opts.get('all'):
3711 if opts.get('all'):
3711 if rev or node:
3712 if rev or node:
3712 raise error.Abort(_("can't specify a revision with --all"))
3713 raise error.Abort(_("can't specify a revision with --all"))
3713
3714
3714 res = set()
3715 res = set()
3715 for rev in repo:
3716 for rev in repo:
3716 ctx = repo[rev]
3717 ctx = repo[rev]
3717 res |= set(ctx.files())
3718 res |= set(ctx.files())
3718
3719
3719 ui.pager('manifest')
3720 ui.pager('manifest')
3720 for f in sorted(res):
3721 for f in sorted(res):
3721 fm.startitem()
3722 fm.startitem()
3722 fm.write("path", '%s\n', f)
3723 fm.write("path", '%s\n', f)
3723 fm.end()
3724 fm.end()
3724 return
3725 return
3725
3726
3726 if rev and node:
3727 if rev and node:
3727 raise error.Abort(_("please specify just one revision"))
3728 raise error.Abort(_("please specify just one revision"))
3728
3729
3729 if not node:
3730 if not node:
3730 node = rev
3731 node = rev
3731
3732
3732 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3733 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3733 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3734 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3734 if node:
3735 if node:
3735 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3736 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3736 ctx = scmutil.revsingle(repo, node)
3737 ctx = scmutil.revsingle(repo, node)
3737 mf = ctx.manifest()
3738 mf = ctx.manifest()
3738 ui.pager('manifest')
3739 ui.pager('manifest')
3739 for f in ctx:
3740 for f in ctx:
3740 fm.startitem()
3741 fm.startitem()
3741 fm.context(ctx=ctx)
3742 fm.context(ctx=ctx)
3742 fl = ctx[f].flags()
3743 fl = ctx[f].flags()
3743 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3744 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3744 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3745 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3745 fm.write('path', '%s\n', f)
3746 fm.write('path', '%s\n', f)
3746 fm.end()
3747 fm.end()
3747
3748
3748 @command('^merge',
3749 @command('^merge',
3749 [('f', 'force', None,
3750 [('f', 'force', None,
3750 _('force a merge including outstanding changes (DEPRECATED)')),
3751 _('force a merge including outstanding changes (DEPRECATED)')),
3751 ('r', 'rev', '', _('revision to merge'), _('REV')),
3752 ('r', 'rev', '', _('revision to merge'), _('REV')),
3752 ('P', 'preview', None,
3753 ('P', 'preview', None,
3753 _('review revisions to merge (no merge is performed)')),
3754 _('review revisions to merge (no merge is performed)')),
3754 ('', 'abort', None, _('abort the ongoing merge')),
3755 ('', 'abort', None, _('abort the ongoing merge')),
3755 ] + mergetoolopts,
3756 ] + mergetoolopts,
3756 _('[-P] [[-r] REV]'))
3757 _('[-P] [[-r] REV]'))
3757 def merge(ui, repo, node=None, **opts):
3758 def merge(ui, repo, node=None, **opts):
3758 """merge another revision into working directory
3759 """merge another revision into working directory
3759
3760
3760 The current working directory is updated with all changes made in
3761 The current working directory is updated with all changes made in
3761 the requested revision since the last common predecessor revision.
3762 the requested revision since the last common predecessor revision.
3762
3763
3763 Files that changed between either parent are marked as changed for
3764 Files that changed between either parent are marked as changed for
3764 the next commit and a commit must be performed before any further
3765 the next commit and a commit must be performed before any further
3765 updates to the repository are allowed. The next commit will have
3766 updates to the repository are allowed. The next commit will have
3766 two parents.
3767 two parents.
3767
3768
3768 ``--tool`` can be used to specify the merge tool used for file
3769 ``--tool`` can be used to specify the merge tool used for file
3769 merges. It overrides the HGMERGE environment variable and your
3770 merges. It overrides the HGMERGE environment variable and your
3770 configuration files. See :hg:`help merge-tools` for options.
3771 configuration files. See :hg:`help merge-tools` for options.
3771
3772
3772 If no revision is specified, the working directory's parent is a
3773 If no revision is specified, the working directory's parent is a
3773 head revision, and the current branch contains exactly one other
3774 head revision, and the current branch contains exactly one other
3774 head, the other head is merged with by default. Otherwise, an
3775 head, the other head is merged with by default. Otherwise, an
3775 explicit revision with which to merge with must be provided.
3776 explicit revision with which to merge with must be provided.
3776
3777
3777 See :hg:`help resolve` for information on handling file conflicts.
3778 See :hg:`help resolve` for information on handling file conflicts.
3778
3779
3779 To undo an uncommitted merge, use :hg:`merge --abort` which
3780 To undo an uncommitted merge, use :hg:`merge --abort` which
3780 will check out a clean copy of the original merge parent, losing
3781 will check out a clean copy of the original merge parent, losing
3781 all changes.
3782 all changes.
3782
3783
3783 Returns 0 on success, 1 if there are unresolved files.
3784 Returns 0 on success, 1 if there are unresolved files.
3784 """
3785 """
3785
3786
3786 opts = pycompat.byteskwargs(opts)
3787 opts = pycompat.byteskwargs(opts)
3787 abort = opts.get('abort')
3788 abort = opts.get('abort')
3788 if abort and repo.dirstate.p2() == nullid:
3789 if abort and repo.dirstate.p2() == nullid:
3789 cmdutil.wrongtooltocontinue(repo, _('merge'))
3790 cmdutil.wrongtooltocontinue(repo, _('merge'))
3790 if abort:
3791 if abort:
3791 if node:
3792 if node:
3792 raise error.Abort(_("cannot specify a node with --abort"))
3793 raise error.Abort(_("cannot specify a node with --abort"))
3793 if opts.get('rev'):
3794 if opts.get('rev'):
3794 raise error.Abort(_("cannot specify both --rev and --abort"))
3795 raise error.Abort(_("cannot specify both --rev and --abort"))
3795 if opts.get('preview'):
3796 if opts.get('preview'):
3796 raise error.Abort(_("cannot specify --preview with --abort"))
3797 raise error.Abort(_("cannot specify --preview with --abort"))
3797 if opts.get('rev') and node:
3798 if opts.get('rev') and node:
3798 raise error.Abort(_("please specify just one revision"))
3799 raise error.Abort(_("please specify just one revision"))
3799 if not node:
3800 if not node:
3800 node = opts.get('rev')
3801 node = opts.get('rev')
3801
3802
3802 if node:
3803 if node:
3803 node = scmutil.revsingle(repo, node).node()
3804 node = scmutil.revsingle(repo, node).node()
3804
3805
3805 if not node and not abort:
3806 if not node and not abort:
3806 node = repo[destutil.destmerge(repo)].node()
3807 node = repo[destutil.destmerge(repo)].node()
3807
3808
3808 if opts.get('preview'):
3809 if opts.get('preview'):
3809 # find nodes that are ancestors of p2 but not of p1
3810 # find nodes that are ancestors of p2 but not of p1
3810 p1 = repo.lookup('.')
3811 p1 = repo.lookup('.')
3811 p2 = node
3812 p2 = node
3812 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3813 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3813
3814
3814 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3815 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3815 for node in nodes:
3816 for node in nodes:
3816 displayer.show(repo[node])
3817 displayer.show(repo[node])
3817 displayer.close()
3818 displayer.close()
3818 return 0
3819 return 0
3819
3820
3820 # ui.forcemerge is an internal variable, do not document
3821 # ui.forcemerge is an internal variable, do not document
3821 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3822 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3822 with ui.configoverride(overrides, 'merge'):
3823 with ui.configoverride(overrides, 'merge'):
3823 force = opts.get('force')
3824 force = opts.get('force')
3824 labels = ['working copy', 'merge rev']
3825 labels = ['working copy', 'merge rev']
3825 return hg.merge(repo, node, force=force, mergeforce=force,
3826 return hg.merge(repo, node, force=force, mergeforce=force,
3826 labels=labels, abort=abort)
3827 labels=labels, abort=abort)
3827
3828
3828 @command('outgoing|out',
3829 @command('outgoing|out',
3829 [('f', 'force', None, _('run even when the destination is unrelated')),
3830 [('f', 'force', None, _('run even when the destination is unrelated')),
3830 ('r', 'rev', [],
3831 ('r', 'rev', [],
3831 _('a changeset intended to be included in the destination'), _('REV')),
3832 _('a changeset intended to be included in the destination'), _('REV')),
3832 ('n', 'newest-first', None, _('show newest record first')),
3833 ('n', 'newest-first', None, _('show newest record first')),
3833 ('B', 'bookmarks', False, _('compare bookmarks')),
3834 ('B', 'bookmarks', False, _('compare bookmarks')),
3834 ('b', 'branch', [], _('a specific branch you would like to push'),
3835 ('b', 'branch', [], _('a specific branch you would like to push'),
3835 _('BRANCH')),
3836 _('BRANCH')),
3836 ] + logopts + remoteopts + subrepoopts,
3837 ] + logopts + remoteopts + subrepoopts,
3837 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3838 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3838 def outgoing(ui, repo, dest=None, **opts):
3839 def outgoing(ui, repo, dest=None, **opts):
3839 """show changesets not found in the destination
3840 """show changesets not found in the destination
3840
3841
3841 Show changesets not found in the specified destination repository
3842 Show changesets not found in the specified destination repository
3842 or the default push location. These are the changesets that would
3843 or the default push location. These are the changesets that would
3843 be pushed if a push was requested.
3844 be pushed if a push was requested.
3844
3845
3845 See pull for details of valid destination formats.
3846 See pull for details of valid destination formats.
3846
3847
3847 .. container:: verbose
3848 .. container:: verbose
3848
3849
3849 With -B/--bookmarks, the result of bookmark comparison between
3850 With -B/--bookmarks, the result of bookmark comparison between
3850 local and remote repositories is displayed. With -v/--verbose,
3851 local and remote repositories is displayed. With -v/--verbose,
3851 status is also displayed for each bookmark like below::
3852 status is also displayed for each bookmark like below::
3852
3853
3853 BM1 01234567890a added
3854 BM1 01234567890a added
3854 BM2 deleted
3855 BM2 deleted
3855 BM3 234567890abc advanced
3856 BM3 234567890abc advanced
3856 BM4 34567890abcd diverged
3857 BM4 34567890abcd diverged
3857 BM5 4567890abcde changed
3858 BM5 4567890abcde changed
3858
3859
3859 The action taken when pushing depends on the
3860 The action taken when pushing depends on the
3860 status of each bookmark:
3861 status of each bookmark:
3861
3862
3862 :``added``: push with ``-B`` will create it
3863 :``added``: push with ``-B`` will create it
3863 :``deleted``: push with ``-B`` will delete it
3864 :``deleted``: push with ``-B`` will delete it
3864 :``advanced``: push will update it
3865 :``advanced``: push will update it
3865 :``diverged``: push with ``-B`` will update it
3866 :``diverged``: push with ``-B`` will update it
3866 :``changed``: push with ``-B`` will update it
3867 :``changed``: push with ``-B`` will update it
3867
3868
3868 From the point of view of pushing behavior, bookmarks
3869 From the point of view of pushing behavior, bookmarks
3869 existing only in the remote repository are treated as
3870 existing only in the remote repository are treated as
3870 ``deleted``, even if it is in fact added remotely.
3871 ``deleted``, even if it is in fact added remotely.
3871
3872
3872 Returns 0 if there are outgoing changes, 1 otherwise.
3873 Returns 0 if there are outgoing changes, 1 otherwise.
3873 """
3874 """
3874 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3875 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3875 # style URLs, so don't overwrite dest.
3876 # style URLs, so don't overwrite dest.
3876 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3877 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3877 if not path:
3878 if not path:
3878 raise error.Abort(_('default repository not configured!'),
3879 raise error.Abort(_('default repository not configured!'),
3879 hint=_("see 'hg help config.paths'"))
3880 hint=_("see 'hg help config.paths'"))
3880
3881
3881 opts = pycompat.byteskwargs(opts)
3882 opts = pycompat.byteskwargs(opts)
3882 if opts.get('graph'):
3883 if opts.get('graph'):
3883 logcmdutil.checkunsupportedgraphflags([], opts)
3884 logcmdutil.checkunsupportedgraphflags([], opts)
3884 o, other = hg._outgoing(ui, repo, dest, opts)
3885 o, other = hg._outgoing(ui, repo, dest, opts)
3885 if not o:
3886 if not o:
3886 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3887 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3887 return
3888 return
3888
3889
3889 revdag = logcmdutil.graphrevs(repo, o, opts)
3890 revdag = logcmdutil.graphrevs(repo, o, opts)
3890 ui.pager('outgoing')
3891 ui.pager('outgoing')
3891 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3892 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3892 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3893 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3893 graphmod.asciiedges)
3894 graphmod.asciiedges)
3894 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3895 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3895 return 0
3896 return 0
3896
3897
3897 if opts.get('bookmarks'):
3898 if opts.get('bookmarks'):
3898 dest = path.pushloc or path.loc
3899 dest = path.pushloc or path.loc
3899 other = hg.peer(repo, opts, dest)
3900 other = hg.peer(repo, opts, dest)
3900 if 'bookmarks' not in other.listkeys('namespaces'):
3901 if 'bookmarks' not in other.listkeys('namespaces'):
3901 ui.warn(_("remote doesn't support bookmarks\n"))
3902 ui.warn(_("remote doesn't support bookmarks\n"))
3902 return 0
3903 return 0
3903 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3904 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3904 ui.pager('outgoing')
3905 ui.pager('outgoing')
3905 return bookmarks.outgoing(ui, repo, other)
3906 return bookmarks.outgoing(ui, repo, other)
3906
3907
3907 repo._subtoppath = path.pushloc or path.loc
3908 repo._subtoppath = path.pushloc or path.loc
3908 try:
3909 try:
3909 return hg.outgoing(ui, repo, dest, opts)
3910 return hg.outgoing(ui, repo, dest, opts)
3910 finally:
3911 finally:
3911 del repo._subtoppath
3912 del repo._subtoppath
3912
3913
3913 @command('parents',
3914 @command('parents',
3914 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3915 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3915 ] + templateopts,
3916 ] + templateopts,
3916 _('[-r REV] [FILE]'),
3917 _('[-r REV] [FILE]'),
3917 inferrepo=True)
3918 inferrepo=True)
3918 def parents(ui, repo, file_=None, **opts):
3919 def parents(ui, repo, file_=None, **opts):
3919 """show the parents of the working directory or revision (DEPRECATED)
3920 """show the parents of the working directory or revision (DEPRECATED)
3920
3921
3921 Print the working directory's parent revisions. If a revision is
3922 Print the working directory's parent revisions. If a revision is
3922 given via -r/--rev, the parent of that revision will be printed.
3923 given via -r/--rev, the parent of that revision will be printed.
3923 If a file argument is given, the revision in which the file was
3924 If a file argument is given, the revision in which the file was
3924 last changed (before the working directory revision or the
3925 last changed (before the working directory revision or the
3925 argument to --rev if given) is printed.
3926 argument to --rev if given) is printed.
3926
3927
3927 This command is equivalent to::
3928 This command is equivalent to::
3928
3929
3929 hg log -r "p1()+p2()" or
3930 hg log -r "p1()+p2()" or
3930 hg log -r "p1(REV)+p2(REV)" or
3931 hg log -r "p1(REV)+p2(REV)" or
3931 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3932 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3932 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3933 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3933
3934
3934 See :hg:`summary` and :hg:`help revsets` for related information.
3935 See :hg:`summary` and :hg:`help revsets` for related information.
3935
3936
3936 Returns 0 on success.
3937 Returns 0 on success.
3937 """
3938 """
3938
3939
3939 opts = pycompat.byteskwargs(opts)
3940 opts = pycompat.byteskwargs(opts)
3940 rev = opts.get('rev')
3941 rev = opts.get('rev')
3941 if rev:
3942 if rev:
3942 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3943 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3943 ctx = scmutil.revsingle(repo, rev, None)
3944 ctx = scmutil.revsingle(repo, rev, None)
3944
3945
3945 if file_:
3946 if file_:
3946 m = scmutil.match(ctx, (file_,), opts)
3947 m = scmutil.match(ctx, (file_,), opts)
3947 if m.anypats() or len(m.files()) != 1:
3948 if m.anypats() or len(m.files()) != 1:
3948 raise error.Abort(_('can only specify an explicit filename'))
3949 raise error.Abort(_('can only specify an explicit filename'))
3949 file_ = m.files()[0]
3950 file_ = m.files()[0]
3950 filenodes = []
3951 filenodes = []
3951 for cp in ctx.parents():
3952 for cp in ctx.parents():
3952 if not cp:
3953 if not cp:
3953 continue
3954 continue
3954 try:
3955 try:
3955 filenodes.append(cp.filenode(file_))
3956 filenodes.append(cp.filenode(file_))
3956 except error.LookupError:
3957 except error.LookupError:
3957 pass
3958 pass
3958 if not filenodes:
3959 if not filenodes:
3959 raise error.Abort(_("'%s' not found in manifest!") % file_)
3960 raise error.Abort(_("'%s' not found in manifest!") % file_)
3960 p = []
3961 p = []
3961 for fn in filenodes:
3962 for fn in filenodes:
3962 fctx = repo.filectx(file_, fileid=fn)
3963 fctx = repo.filectx(file_, fileid=fn)
3963 p.append(fctx.node())
3964 p.append(fctx.node())
3964 else:
3965 else:
3965 p = [cp.node() for cp in ctx.parents()]
3966 p = [cp.node() for cp in ctx.parents()]
3966
3967
3967 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3968 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3968 for n in p:
3969 for n in p:
3969 if n != nullid:
3970 if n != nullid:
3970 displayer.show(repo[n])
3971 displayer.show(repo[n])
3971 displayer.close()
3972 displayer.close()
3972
3973
3973 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3974 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3974 intents={INTENT_READONLY})
3975 intents={INTENT_READONLY})
3975 def paths(ui, repo, search=None, **opts):
3976 def paths(ui, repo, search=None, **opts):
3976 """show aliases for remote repositories
3977 """show aliases for remote repositories
3977
3978
3978 Show definition of symbolic path name NAME. If no name is given,
3979 Show definition of symbolic path name NAME. If no name is given,
3979 show definition of all available names.
3980 show definition of all available names.
3980
3981
3981 Option -q/--quiet suppresses all output when searching for NAME
3982 Option -q/--quiet suppresses all output when searching for NAME
3982 and shows only the path names when listing all definitions.
3983 and shows only the path names when listing all definitions.
3983
3984
3984 Path names are defined in the [paths] section of your
3985 Path names are defined in the [paths] section of your
3985 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3986 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3986 repository, ``.hg/hgrc`` is used, too.
3987 repository, ``.hg/hgrc`` is used, too.
3987
3988
3988 The path names ``default`` and ``default-push`` have a special
3989 The path names ``default`` and ``default-push`` have a special
3989 meaning. When performing a push or pull operation, they are used
3990 meaning. When performing a push or pull operation, they are used
3990 as fallbacks if no location is specified on the command-line.
3991 as fallbacks if no location is specified on the command-line.
3991 When ``default-push`` is set, it will be used for push and
3992 When ``default-push`` is set, it will be used for push and
3992 ``default`` will be used for pull; otherwise ``default`` is used
3993 ``default`` will be used for pull; otherwise ``default`` is used
3993 as the fallback for both. When cloning a repository, the clone
3994 as the fallback for both. When cloning a repository, the clone
3994 source is written as ``default`` in ``.hg/hgrc``.
3995 source is written as ``default`` in ``.hg/hgrc``.
3995
3996
3996 .. note::
3997 .. note::
3997
3998
3998 ``default`` and ``default-push`` apply to all inbound (e.g.
3999 ``default`` and ``default-push`` apply to all inbound (e.g.
3999 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4000 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4000 and :hg:`bundle`) operations.
4001 and :hg:`bundle`) operations.
4001
4002
4002 See :hg:`help urls` for more information.
4003 See :hg:`help urls` for more information.
4003
4004
4004 Returns 0 on success.
4005 Returns 0 on success.
4005 """
4006 """
4006
4007
4007 opts = pycompat.byteskwargs(opts)
4008 opts = pycompat.byteskwargs(opts)
4008 ui.pager('paths')
4009 ui.pager('paths')
4009 if search:
4010 if search:
4010 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4011 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4011 if name == search]
4012 if name == search]
4012 else:
4013 else:
4013 pathitems = sorted(ui.paths.iteritems())
4014 pathitems = sorted(ui.paths.iteritems())
4014
4015
4015 fm = ui.formatter('paths', opts)
4016 fm = ui.formatter('paths', opts)
4016 if fm.isplain():
4017 if fm.isplain():
4017 hidepassword = util.hidepassword
4018 hidepassword = util.hidepassword
4018 else:
4019 else:
4019 hidepassword = bytes
4020 hidepassword = bytes
4020 if ui.quiet:
4021 if ui.quiet:
4021 namefmt = '%s\n'
4022 namefmt = '%s\n'
4022 else:
4023 else:
4023 namefmt = '%s = '
4024 namefmt = '%s = '
4024 showsubopts = not search and not ui.quiet
4025 showsubopts = not search and not ui.quiet
4025
4026
4026 for name, path in pathitems:
4027 for name, path in pathitems:
4027 fm.startitem()
4028 fm.startitem()
4028 fm.condwrite(not search, 'name', namefmt, name)
4029 fm.condwrite(not search, 'name', namefmt, name)
4029 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4030 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4030 for subopt, value in sorted(path.suboptions.items()):
4031 for subopt, value in sorted(path.suboptions.items()):
4031 assert subopt not in ('name', 'url')
4032 assert subopt not in ('name', 'url')
4032 if showsubopts:
4033 if showsubopts:
4033 fm.plain('%s:%s = ' % (name, subopt))
4034 fm.plain('%s:%s = ' % (name, subopt))
4034 fm.condwrite(showsubopts, subopt, '%s\n', value)
4035 fm.condwrite(showsubopts, subopt, '%s\n', value)
4035
4036
4036 fm.end()
4037 fm.end()
4037
4038
4038 if search and not pathitems:
4039 if search and not pathitems:
4039 if not ui.quiet:
4040 if not ui.quiet:
4040 ui.warn(_("not found!\n"))
4041 ui.warn(_("not found!\n"))
4041 return 1
4042 return 1
4042 else:
4043 else:
4043 return 0
4044 return 0
4044
4045
4045 @command('phase',
4046 @command('phase',
4046 [('p', 'public', False, _('set changeset phase to public')),
4047 [('p', 'public', False, _('set changeset phase to public')),
4047 ('d', 'draft', False, _('set changeset phase to draft')),
4048 ('d', 'draft', False, _('set changeset phase to draft')),
4048 ('s', 'secret', False, _('set changeset phase to secret')),
4049 ('s', 'secret', False, _('set changeset phase to secret')),
4049 ('f', 'force', False, _('allow to move boundary backward')),
4050 ('f', 'force', False, _('allow to move boundary backward')),
4050 ('r', 'rev', [], _('target revision'), _('REV')),
4051 ('r', 'rev', [], _('target revision'), _('REV')),
4051 ],
4052 ],
4052 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4053 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4053 def phase(ui, repo, *revs, **opts):
4054 def phase(ui, repo, *revs, **opts):
4054 """set or show the current phase name
4055 """set or show the current phase name
4055
4056
4056 With no argument, show the phase name of the current revision(s).
4057 With no argument, show the phase name of the current revision(s).
4057
4058
4058 With one of -p/--public, -d/--draft or -s/--secret, change the
4059 With one of -p/--public, -d/--draft or -s/--secret, change the
4059 phase value of the specified revisions.
4060 phase value of the specified revisions.
4060
4061
4061 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4062 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4062 lower phase to a higher phase. Phases are ordered as follows::
4063 lower phase to a higher phase. Phases are ordered as follows::
4063
4064
4064 public < draft < secret
4065 public < draft < secret
4065
4066
4066 Returns 0 on success, 1 if some phases could not be changed.
4067 Returns 0 on success, 1 if some phases could not be changed.
4067
4068
4068 (For more information about the phases concept, see :hg:`help phases`.)
4069 (For more information about the phases concept, see :hg:`help phases`.)
4069 """
4070 """
4070 opts = pycompat.byteskwargs(opts)
4071 opts = pycompat.byteskwargs(opts)
4071 # search for a unique phase argument
4072 # search for a unique phase argument
4072 targetphase = None
4073 targetphase = None
4073 for idx, name in enumerate(phases.phasenames):
4074 for idx, name in enumerate(phases.phasenames):
4074 if opts.get(name, False):
4075 if opts.get(name, False):
4075 if targetphase is not None:
4076 if targetphase is not None:
4076 raise error.Abort(_('only one phase can be specified'))
4077 raise error.Abort(_('only one phase can be specified'))
4077 targetphase = idx
4078 targetphase = idx
4078
4079
4079 # look for specified revision
4080 # look for specified revision
4080 revs = list(revs)
4081 revs = list(revs)
4081 revs.extend(opts['rev'])
4082 revs.extend(opts['rev'])
4082 if not revs:
4083 if not revs:
4083 # display both parents as the second parent phase can influence
4084 # display both parents as the second parent phase can influence
4084 # the phase of a merge commit
4085 # the phase of a merge commit
4085 revs = [c.rev() for c in repo[None].parents()]
4086 revs = [c.rev() for c in repo[None].parents()]
4086
4087
4087 revs = scmutil.revrange(repo, revs)
4088 revs = scmutil.revrange(repo, revs)
4088
4089
4089 ret = 0
4090 ret = 0
4090 if targetphase is None:
4091 if targetphase is None:
4091 # display
4092 # display
4092 for r in revs:
4093 for r in revs:
4093 ctx = repo[r]
4094 ctx = repo[r]
4094 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4095 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4095 else:
4096 else:
4096 with repo.lock(), repo.transaction("phase") as tr:
4097 with repo.lock(), repo.transaction("phase") as tr:
4097 # set phase
4098 # set phase
4098 if not revs:
4099 if not revs:
4099 raise error.Abort(_('empty revision set'))
4100 raise error.Abort(_('empty revision set'))
4100 nodes = [repo[r].node() for r in revs]
4101 nodes = [repo[r].node() for r in revs]
4101 # moving revision from public to draft may hide them
4102 # moving revision from public to draft may hide them
4102 # We have to check result on an unfiltered repository
4103 # We have to check result on an unfiltered repository
4103 unfi = repo.unfiltered()
4104 unfi = repo.unfiltered()
4104 getphase = unfi._phasecache.phase
4105 getphase = unfi._phasecache.phase
4105 olddata = [getphase(unfi, r) for r in unfi]
4106 olddata = [getphase(unfi, r) for r in unfi]
4106 phases.advanceboundary(repo, tr, targetphase, nodes)
4107 phases.advanceboundary(repo, tr, targetphase, nodes)
4107 if opts['force']:
4108 if opts['force']:
4108 phases.retractboundary(repo, tr, targetphase, nodes)
4109 phases.retractboundary(repo, tr, targetphase, nodes)
4109 getphase = unfi._phasecache.phase
4110 getphase = unfi._phasecache.phase
4110 newdata = [getphase(unfi, r) for r in unfi]
4111 newdata = [getphase(unfi, r) for r in unfi]
4111 changes = sum(newdata[r] != olddata[r] for r in unfi)
4112 changes = sum(newdata[r] != olddata[r] for r in unfi)
4112 cl = unfi.changelog
4113 cl = unfi.changelog
4113 rejected = [n for n in nodes
4114 rejected = [n for n in nodes
4114 if newdata[cl.rev(n)] < targetphase]
4115 if newdata[cl.rev(n)] < targetphase]
4115 if rejected:
4116 if rejected:
4116 ui.warn(_('cannot move %i changesets to a higher '
4117 ui.warn(_('cannot move %i changesets to a higher '
4117 'phase, use --force\n') % len(rejected))
4118 'phase, use --force\n') % len(rejected))
4118 ret = 1
4119 ret = 1
4119 if changes:
4120 if changes:
4120 msg = _('phase changed for %i changesets\n') % changes
4121 msg = _('phase changed for %i changesets\n') % changes
4121 if ret:
4122 if ret:
4122 ui.status(msg)
4123 ui.status(msg)
4123 else:
4124 else:
4124 ui.note(msg)
4125 ui.note(msg)
4125 else:
4126 else:
4126 ui.warn(_('no phases changed\n'))
4127 ui.warn(_('no phases changed\n'))
4127 return ret
4128 return ret
4128
4129
4129 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4130 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4130 """Run after a changegroup has been added via pull/unbundle
4131 """Run after a changegroup has been added via pull/unbundle
4131
4132
4132 This takes arguments below:
4133 This takes arguments below:
4133
4134
4134 :modheads: change of heads by pull/unbundle
4135 :modheads: change of heads by pull/unbundle
4135 :optupdate: updating working directory is needed or not
4136 :optupdate: updating working directory is needed or not
4136 :checkout: update destination revision (or None to default destination)
4137 :checkout: update destination revision (or None to default destination)
4137 :brev: a name, which might be a bookmark to be activated after updating
4138 :brev: a name, which might be a bookmark to be activated after updating
4138 """
4139 """
4139 if modheads == 0:
4140 if modheads == 0:
4140 return
4141 return
4141 if optupdate:
4142 if optupdate:
4142 try:
4143 try:
4143 return hg.updatetotally(ui, repo, checkout, brev)
4144 return hg.updatetotally(ui, repo, checkout, brev)
4144 except error.UpdateAbort as inst:
4145 except error.UpdateAbort as inst:
4145 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4146 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4146 hint = inst.hint
4147 hint = inst.hint
4147 raise error.UpdateAbort(msg, hint=hint)
4148 raise error.UpdateAbort(msg, hint=hint)
4148 if modheads > 1:
4149 if modheads > 1:
4149 currentbranchheads = len(repo.branchheads())
4150 currentbranchheads = len(repo.branchheads())
4150 if currentbranchheads == modheads:
4151 if currentbranchheads == modheads:
4151 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4152 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4152 elif currentbranchheads > 1:
4153 elif currentbranchheads > 1:
4153 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4154 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4154 "merge)\n"))
4155 "merge)\n"))
4155 else:
4156 else:
4156 ui.status(_("(run 'hg heads' to see heads)\n"))
4157 ui.status(_("(run 'hg heads' to see heads)\n"))
4157 elif not ui.configbool('commands', 'update.requiredest'):
4158 elif not ui.configbool('commands', 'update.requiredest'):
4158 ui.status(_("(run 'hg update' to get a working copy)\n"))
4159 ui.status(_("(run 'hg update' to get a working copy)\n"))
4159
4160
4160 @command('^pull',
4161 @command('^pull',
4161 [('u', 'update', None,
4162 [('u', 'update', None,
4162 _('update to new branch head if new descendants were pulled')),
4163 _('update to new branch head if new descendants were pulled')),
4163 ('f', 'force', None, _('run even when remote repository is unrelated')),
4164 ('f', 'force', None, _('run even when remote repository is unrelated')),
4164 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4165 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4165 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4166 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4166 ('b', 'branch', [], _('a specific branch you would like to pull'),
4167 ('b', 'branch', [], _('a specific branch you would like to pull'),
4167 _('BRANCH')),
4168 _('BRANCH')),
4168 ] + remoteopts,
4169 ] + remoteopts,
4169 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4170 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4170 def pull(ui, repo, source="default", **opts):
4171 def pull(ui, repo, source="default", **opts):
4171 """pull changes from the specified source
4172 """pull changes from the specified source
4172
4173
4173 Pull changes from a remote repository to a local one.
4174 Pull changes from a remote repository to a local one.
4174
4175
4175 This finds all changes from the repository at the specified path
4176 This finds all changes from the repository at the specified path
4176 or URL and adds them to a local repository (the current one unless
4177 or URL and adds them to a local repository (the current one unless
4177 -R is specified). By default, this does not update the copy of the
4178 -R is specified). By default, this does not update the copy of the
4178 project in the working directory.
4179 project in the working directory.
4179
4180
4180 When cloning from servers that support it, Mercurial may fetch
4181 When cloning from servers that support it, Mercurial may fetch
4181 pre-generated data. When this is done, hooks operating on incoming
4182 pre-generated data. When this is done, hooks operating on incoming
4182 changesets and changegroups may fire more than once, once for each
4183 changesets and changegroups may fire more than once, once for each
4183 pre-generated bundle and as well as for any additional remaining
4184 pre-generated bundle and as well as for any additional remaining
4184 data. See :hg:`help -e clonebundles` for more.
4185 data. See :hg:`help -e clonebundles` for more.
4185
4186
4186 Use :hg:`incoming` if you want to see what would have been added
4187 Use :hg:`incoming` if you want to see what would have been added
4187 by a pull at the time you issued this command. If you then decide
4188 by a pull at the time you issued this command. If you then decide
4188 to add those changes to the repository, you should use :hg:`pull
4189 to add those changes to the repository, you should use :hg:`pull
4189 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4190 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4190
4191
4191 If SOURCE is omitted, the 'default' path will be used.
4192 If SOURCE is omitted, the 'default' path will be used.
4192 See :hg:`help urls` for more information.
4193 See :hg:`help urls` for more information.
4193
4194
4194 Specifying bookmark as ``.`` is equivalent to specifying the active
4195 Specifying bookmark as ``.`` is equivalent to specifying the active
4195 bookmark's name.
4196 bookmark's name.
4196
4197
4197 Returns 0 on success, 1 if an update had unresolved files.
4198 Returns 0 on success, 1 if an update had unresolved files.
4198 """
4199 """
4199
4200
4200 opts = pycompat.byteskwargs(opts)
4201 opts = pycompat.byteskwargs(opts)
4201 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4202 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4202 msg = _('update destination required by configuration')
4203 msg = _('update destination required by configuration')
4203 hint = _('use hg pull followed by hg update DEST')
4204 hint = _('use hg pull followed by hg update DEST')
4204 raise error.Abort(msg, hint=hint)
4205 raise error.Abort(msg, hint=hint)
4205
4206
4206 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4207 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4207 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4208 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4208 other = hg.peer(repo, opts, source)
4209 other = hg.peer(repo, opts, source)
4209 try:
4210 try:
4210 revs, checkout = hg.addbranchrevs(repo, other, branches,
4211 revs, checkout = hg.addbranchrevs(repo, other, branches,
4211 opts.get('rev'))
4212 opts.get('rev'))
4212
4213
4213
4214
4214 pullopargs = {}
4215 pullopargs = {}
4215 if opts.get('bookmark'):
4216 if opts.get('bookmark'):
4216 if not revs:
4217 if not revs:
4217 revs = []
4218 revs = []
4218 # The list of bookmark used here is not the one used to actually
4219 # The list of bookmark used here is not the one used to actually
4219 # update the bookmark name. This can result in the revision pulled
4220 # update the bookmark name. This can result in the revision pulled
4220 # not ending up with the name of the bookmark because of a race
4221 # not ending up with the name of the bookmark because of a race
4221 # condition on the server. (See issue 4689 for details)
4222 # condition on the server. (See issue 4689 for details)
4222 remotebookmarks = other.listkeys('bookmarks')
4223 remotebookmarks = other.listkeys('bookmarks')
4223 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4224 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4224 pullopargs['remotebookmarks'] = remotebookmarks
4225 pullopargs['remotebookmarks'] = remotebookmarks
4225 for b in opts['bookmark']:
4226 for b in opts['bookmark']:
4226 b = repo._bookmarks.expandname(b)
4227 b = repo._bookmarks.expandname(b)
4227 if b not in remotebookmarks:
4228 if b not in remotebookmarks:
4228 raise error.Abort(_('remote bookmark %s not found!') % b)
4229 raise error.Abort(_('remote bookmark %s not found!') % b)
4229 revs.append(hex(remotebookmarks[b]))
4230 revs.append(hex(remotebookmarks[b]))
4230
4231
4231 if revs:
4232 if revs:
4232 try:
4233 try:
4233 # When 'rev' is a bookmark name, we cannot guarantee that it
4234 # When 'rev' is a bookmark name, we cannot guarantee that it
4234 # will be updated with that name because of a race condition
4235 # will be updated with that name because of a race condition
4235 # server side. (See issue 4689 for details)
4236 # server side. (See issue 4689 for details)
4236 oldrevs = revs
4237 oldrevs = revs
4237 revs = [] # actually, nodes
4238 revs = [] # actually, nodes
4238 for r in oldrevs:
4239 for r in oldrevs:
4239 with other.commandexecutor() as e:
4240 with other.commandexecutor() as e:
4240 node = e.callcommand('lookup', {'key': r}).result()
4241 node = e.callcommand('lookup', {'key': r}).result()
4241
4242
4242 revs.append(node)
4243 revs.append(node)
4243 if r == checkout:
4244 if r == checkout:
4244 checkout = node
4245 checkout = node
4245 except error.CapabilityError:
4246 except error.CapabilityError:
4246 err = _("other repository doesn't support revision lookup, "
4247 err = _("other repository doesn't support revision lookup, "
4247 "so a rev cannot be specified.")
4248 "so a rev cannot be specified.")
4248 raise error.Abort(err)
4249 raise error.Abort(err)
4249
4250
4250 wlock = util.nullcontextmanager()
4251 wlock = util.nullcontextmanager()
4251 if opts.get('update'):
4252 if opts.get('update'):
4252 wlock = repo.wlock()
4253 wlock = repo.wlock()
4253 with wlock:
4254 with wlock:
4254 pullopargs.update(opts.get('opargs', {}))
4255 pullopargs.update(opts.get('opargs', {}))
4255 modheads = exchange.pull(repo, other, heads=revs,
4256 modheads = exchange.pull(repo, other, heads=revs,
4256 force=opts.get('force'),
4257 force=opts.get('force'),
4257 bookmarks=opts.get('bookmark', ()),
4258 bookmarks=opts.get('bookmark', ()),
4258 opargs=pullopargs).cgresult
4259 opargs=pullopargs).cgresult
4259
4260
4260 # brev is a name, which might be a bookmark to be activated at
4261 # brev is a name, which might be a bookmark to be activated at
4261 # the end of the update. In other words, it is an explicit
4262 # the end of the update. In other words, it is an explicit
4262 # destination of the update
4263 # destination of the update
4263 brev = None
4264 brev = None
4264
4265
4265 if checkout:
4266 if checkout:
4266 checkout = repo.changelog.rev(checkout)
4267 checkout = repo.changelog.rev(checkout)
4267
4268
4268 # order below depends on implementation of
4269 # order below depends on implementation of
4269 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4270 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4270 # because 'checkout' is determined without it.
4271 # because 'checkout' is determined without it.
4271 if opts.get('rev'):
4272 if opts.get('rev'):
4272 brev = opts['rev'][0]
4273 brev = opts['rev'][0]
4273 elif opts.get('branch'):
4274 elif opts.get('branch'):
4274 brev = opts['branch'][0]
4275 brev = opts['branch'][0]
4275 else:
4276 else:
4276 brev = branches[0]
4277 brev = branches[0]
4277 repo._subtoppath = source
4278 repo._subtoppath = source
4278 try:
4279 try:
4279 ret = postincoming(ui, repo, modheads, opts.get('update'),
4280 ret = postincoming(ui, repo, modheads, opts.get('update'),
4280 checkout, brev)
4281 checkout, brev)
4281
4282
4282 finally:
4283 finally:
4283 del repo._subtoppath
4284 del repo._subtoppath
4284
4285
4285 finally:
4286 finally:
4286 other.close()
4287 other.close()
4287 return ret
4288 return ret
4288
4289
4289 @command('^push',
4290 @command('^push',
4290 [('f', 'force', None, _('force push')),
4291 [('f', 'force', None, _('force push')),
4291 ('r', 'rev', [],
4292 ('r', 'rev', [],
4292 _('a changeset intended to be included in the destination'),
4293 _('a changeset intended to be included in the destination'),
4293 _('REV')),
4294 _('REV')),
4294 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4295 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4295 ('b', 'branch', [],
4296 ('b', 'branch', [],
4296 _('a specific branch you would like to push'), _('BRANCH')),
4297 _('a specific branch you would like to push'), _('BRANCH')),
4297 ('', 'new-branch', False, _('allow pushing a new branch')),
4298 ('', 'new-branch', False, _('allow pushing a new branch')),
4298 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4299 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4299 ] + remoteopts,
4300 ] + remoteopts,
4300 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4301 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4301 def push(ui, repo, dest=None, **opts):
4302 def push(ui, repo, dest=None, **opts):
4302 """push changes to the specified destination
4303 """push changes to the specified destination
4303
4304
4304 Push changesets from the local repository to the specified
4305 Push changesets from the local repository to the specified
4305 destination.
4306 destination.
4306
4307
4307 This operation is symmetrical to pull: it is identical to a pull
4308 This operation is symmetrical to pull: it is identical to a pull
4308 in the destination repository from the current one.
4309 in the destination repository from the current one.
4309
4310
4310 By default, push will not allow creation of new heads at the
4311 By default, push will not allow creation of new heads at the
4311 destination, since multiple heads would make it unclear which head
4312 destination, since multiple heads would make it unclear which head
4312 to use. In this situation, it is recommended to pull and merge
4313 to use. In this situation, it is recommended to pull and merge
4313 before pushing.
4314 before pushing.
4314
4315
4315 Use --new-branch if you want to allow push to create a new named
4316 Use --new-branch if you want to allow push to create a new named
4316 branch that is not present at the destination. This allows you to
4317 branch that is not present at the destination. This allows you to
4317 only create a new branch without forcing other changes.
4318 only create a new branch without forcing other changes.
4318
4319
4319 .. note::
4320 .. note::
4320
4321
4321 Extra care should be taken with the -f/--force option,
4322 Extra care should be taken with the -f/--force option,
4322 which will push all new heads on all branches, an action which will
4323 which will push all new heads on all branches, an action which will
4323 almost always cause confusion for collaborators.
4324 almost always cause confusion for collaborators.
4324
4325
4325 If -r/--rev is used, the specified revision and all its ancestors
4326 If -r/--rev is used, the specified revision and all its ancestors
4326 will be pushed to the remote repository.
4327 will be pushed to the remote repository.
4327
4328
4328 If -B/--bookmark is used, the specified bookmarked revision, its
4329 If -B/--bookmark is used, the specified bookmarked revision, its
4329 ancestors, and the bookmark will be pushed to the remote
4330 ancestors, and the bookmark will be pushed to the remote
4330 repository. Specifying ``.`` is equivalent to specifying the active
4331 repository. Specifying ``.`` is equivalent to specifying the active
4331 bookmark's name.
4332 bookmark's name.
4332
4333
4333 Please see :hg:`help urls` for important details about ``ssh://``
4334 Please see :hg:`help urls` for important details about ``ssh://``
4334 URLs. If DESTINATION is omitted, a default path will be used.
4335 URLs. If DESTINATION is omitted, a default path will be used.
4335
4336
4336 .. container:: verbose
4337 .. container:: verbose
4337
4338
4338 The --pushvars option sends strings to the server that become
4339 The --pushvars option sends strings to the server that become
4339 environment variables prepended with ``HG_USERVAR_``. For example,
4340 environment variables prepended with ``HG_USERVAR_``. For example,
4340 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4341 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4341 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4342 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4342
4343
4343 pushvars can provide for user-overridable hooks as well as set debug
4344 pushvars can provide for user-overridable hooks as well as set debug
4344 levels. One example is having a hook that blocks commits containing
4345 levels. One example is having a hook that blocks commits containing
4345 conflict markers, but enables the user to override the hook if the file
4346 conflict markers, but enables the user to override the hook if the file
4346 is using conflict markers for testing purposes or the file format has
4347 is using conflict markers for testing purposes or the file format has
4347 strings that look like conflict markers.
4348 strings that look like conflict markers.
4348
4349
4349 By default, servers will ignore `--pushvars`. To enable it add the
4350 By default, servers will ignore `--pushvars`. To enable it add the
4350 following to your configuration file::
4351 following to your configuration file::
4351
4352
4352 [push]
4353 [push]
4353 pushvars.server = true
4354 pushvars.server = true
4354
4355
4355 Returns 0 if push was successful, 1 if nothing to push.
4356 Returns 0 if push was successful, 1 if nothing to push.
4356 """
4357 """
4357
4358
4358 opts = pycompat.byteskwargs(opts)
4359 opts = pycompat.byteskwargs(opts)
4359 if opts.get('bookmark'):
4360 if opts.get('bookmark'):
4360 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4361 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4361 for b in opts['bookmark']:
4362 for b in opts['bookmark']:
4362 # translate -B options to -r so changesets get pushed
4363 # translate -B options to -r so changesets get pushed
4363 b = repo._bookmarks.expandname(b)
4364 b = repo._bookmarks.expandname(b)
4364 if b in repo._bookmarks:
4365 if b in repo._bookmarks:
4365 opts.setdefault('rev', []).append(b)
4366 opts.setdefault('rev', []).append(b)
4366 else:
4367 else:
4367 # if we try to push a deleted bookmark, translate it to null
4368 # if we try to push a deleted bookmark, translate it to null
4368 # this lets simultaneous -r, -b options continue working
4369 # this lets simultaneous -r, -b options continue working
4369 opts.setdefault('rev', []).append("null")
4370 opts.setdefault('rev', []).append("null")
4370
4371
4371 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4372 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4372 if not path:
4373 if not path:
4373 raise error.Abort(_('default repository not configured!'),
4374 raise error.Abort(_('default repository not configured!'),
4374 hint=_("see 'hg help config.paths'"))
4375 hint=_("see 'hg help config.paths'"))
4375 dest = path.pushloc or path.loc
4376 dest = path.pushloc or path.loc
4376 branches = (path.branch, opts.get('branch') or [])
4377 branches = (path.branch, opts.get('branch') or [])
4377 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4378 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4378 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4379 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4379 other = hg.peer(repo, opts, dest)
4380 other = hg.peer(repo, opts, dest)
4380
4381
4381 if revs:
4382 if revs:
4382 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4383 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4383 if not revs:
4384 if not revs:
4384 raise error.Abort(_("specified revisions evaluate to an empty set"),
4385 raise error.Abort(_("specified revisions evaluate to an empty set"),
4385 hint=_("use different revision arguments"))
4386 hint=_("use different revision arguments"))
4386 elif path.pushrev:
4387 elif path.pushrev:
4387 # It doesn't make any sense to specify ancestor revisions. So limit
4388 # It doesn't make any sense to specify ancestor revisions. So limit
4388 # to DAG heads to make discovery simpler.
4389 # to DAG heads to make discovery simpler.
4389 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4390 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4390 revs = scmutil.revrange(repo, [expr])
4391 revs = scmutil.revrange(repo, [expr])
4391 revs = [repo[rev].node() for rev in revs]
4392 revs = [repo[rev].node() for rev in revs]
4392 if not revs:
4393 if not revs:
4393 raise error.Abort(_('default push revset for path evaluates to an '
4394 raise error.Abort(_('default push revset for path evaluates to an '
4394 'empty set'))
4395 'empty set'))
4395
4396
4396 repo._subtoppath = dest
4397 repo._subtoppath = dest
4397 try:
4398 try:
4398 # push subrepos depth-first for coherent ordering
4399 # push subrepos depth-first for coherent ordering
4399 c = repo['.']
4400 c = repo['.']
4400 subs = c.substate # only repos that are committed
4401 subs = c.substate # only repos that are committed
4401 for s in sorted(subs):
4402 for s in sorted(subs):
4402 result = c.sub(s).push(opts)
4403 result = c.sub(s).push(opts)
4403 if result == 0:
4404 if result == 0:
4404 return not result
4405 return not result
4405 finally:
4406 finally:
4406 del repo._subtoppath
4407 del repo._subtoppath
4407
4408
4408 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4409 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4409 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4410 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4410
4411
4411 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4412 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4412 newbranch=opts.get('new_branch'),
4413 newbranch=opts.get('new_branch'),
4413 bookmarks=opts.get('bookmark', ()),
4414 bookmarks=opts.get('bookmark', ()),
4414 opargs=opargs)
4415 opargs=opargs)
4415
4416
4416 result = not pushop.cgresult
4417 result = not pushop.cgresult
4417
4418
4418 if pushop.bkresult is not None:
4419 if pushop.bkresult is not None:
4419 if pushop.bkresult == 2:
4420 if pushop.bkresult == 2:
4420 result = 2
4421 result = 2
4421 elif not result and pushop.bkresult:
4422 elif not result and pushop.bkresult:
4422 result = 2
4423 result = 2
4423
4424
4424 return result
4425 return result
4425
4426
4426 @command('recover', [])
4427 @command('recover', [])
4427 def recover(ui, repo):
4428 def recover(ui, repo):
4428 """roll back an interrupted transaction
4429 """roll back an interrupted transaction
4429
4430
4430 Recover from an interrupted commit or pull.
4431 Recover from an interrupted commit or pull.
4431
4432
4432 This command tries to fix the repository status after an
4433 This command tries to fix the repository status after an
4433 interrupted operation. It should only be necessary when Mercurial
4434 interrupted operation. It should only be necessary when Mercurial
4434 suggests it.
4435 suggests it.
4435
4436
4436 Returns 0 if successful, 1 if nothing to recover or verify fails.
4437 Returns 0 if successful, 1 if nothing to recover or verify fails.
4437 """
4438 """
4438 if repo.recover():
4439 if repo.recover():
4439 return hg.verify(repo)
4440 return hg.verify(repo)
4440 return 1
4441 return 1
4441
4442
4442 @command('^remove|rm',
4443 @command('^remove|rm',
4443 [('A', 'after', None, _('record delete for missing files')),
4444 [('A', 'after', None, _('record delete for missing files')),
4444 ('f', 'force', None,
4445 ('f', 'force', None,
4445 _('forget added files, delete modified files')),
4446 _('forget added files, delete modified files')),
4446 ] + subrepoopts + walkopts + dryrunopts,
4447 ] + subrepoopts + walkopts + dryrunopts,
4447 _('[OPTION]... FILE...'),
4448 _('[OPTION]... FILE...'),
4448 inferrepo=True)
4449 inferrepo=True)
4449 def remove(ui, repo, *pats, **opts):
4450 def remove(ui, repo, *pats, **opts):
4450 """remove the specified files on the next commit
4451 """remove the specified files on the next commit
4451
4452
4452 Schedule the indicated files for removal from the current branch.
4453 Schedule the indicated files for removal from the current branch.
4453
4454
4454 This command schedules the files to be removed at the next commit.
4455 This command schedules the files to be removed at the next commit.
4455 To undo a remove before that, see :hg:`revert`. To undo added
4456 To undo a remove before that, see :hg:`revert`. To undo added
4456 files, see :hg:`forget`.
4457 files, see :hg:`forget`.
4457
4458
4458 .. container:: verbose
4459 .. container:: verbose
4459
4460
4460 -A/--after can be used to remove only files that have already
4461 -A/--after can be used to remove only files that have already
4461 been deleted, -f/--force can be used to force deletion, and -Af
4462 been deleted, -f/--force can be used to force deletion, and -Af
4462 can be used to remove files from the next revision without
4463 can be used to remove files from the next revision without
4463 deleting them from the working directory.
4464 deleting them from the working directory.
4464
4465
4465 The following table details the behavior of remove for different
4466 The following table details the behavior of remove for different
4466 file states (columns) and option combinations (rows). The file
4467 file states (columns) and option combinations (rows). The file
4467 states are Added [A], Clean [C], Modified [M] and Missing [!]
4468 states are Added [A], Clean [C], Modified [M] and Missing [!]
4468 (as reported by :hg:`status`). The actions are Warn, Remove
4469 (as reported by :hg:`status`). The actions are Warn, Remove
4469 (from branch) and Delete (from disk):
4470 (from branch) and Delete (from disk):
4470
4471
4471 ========= == == == ==
4472 ========= == == == ==
4472 opt/state A C M !
4473 opt/state A C M !
4473 ========= == == == ==
4474 ========= == == == ==
4474 none W RD W R
4475 none W RD W R
4475 -f R RD RD R
4476 -f R RD RD R
4476 -A W W W R
4477 -A W W W R
4477 -Af R R R R
4478 -Af R R R R
4478 ========= == == == ==
4479 ========= == == == ==
4479
4480
4480 .. note::
4481 .. note::
4481
4482
4482 :hg:`remove` never deletes files in Added [A] state from the
4483 :hg:`remove` never deletes files in Added [A] state from the
4483 working directory, not even if ``--force`` is specified.
4484 working directory, not even if ``--force`` is specified.
4484
4485
4485 Returns 0 on success, 1 if any warnings encountered.
4486 Returns 0 on success, 1 if any warnings encountered.
4486 """
4487 """
4487
4488
4488 opts = pycompat.byteskwargs(opts)
4489 opts = pycompat.byteskwargs(opts)
4489 after, force = opts.get('after'), opts.get('force')
4490 after, force = opts.get('after'), opts.get('force')
4490 dryrun = opts.get('dry_run')
4491 dryrun = opts.get('dry_run')
4491 if not pats and not after:
4492 if not pats and not after:
4492 raise error.Abort(_('no files specified'))
4493 raise error.Abort(_('no files specified'))
4493
4494
4494 m = scmutil.match(repo[None], pats, opts)
4495 m = scmutil.match(repo[None], pats, opts)
4495 subrepos = opts.get('subrepos')
4496 subrepos = opts.get('subrepos')
4496 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4497 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4497 dryrun=dryrun)
4498 dryrun=dryrun)
4498
4499
4499 @command('rename|move|mv',
4500 @command('rename|move|mv',
4500 [('A', 'after', None, _('record a rename that has already occurred')),
4501 [('A', 'after', None, _('record a rename that has already occurred')),
4501 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4502 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4502 ] + walkopts + dryrunopts,
4503 ] + walkopts + dryrunopts,
4503 _('[OPTION]... SOURCE... DEST'))
4504 _('[OPTION]... SOURCE... DEST'))
4504 def rename(ui, repo, *pats, **opts):
4505 def rename(ui, repo, *pats, **opts):
4505 """rename files; equivalent of copy + remove
4506 """rename files; equivalent of copy + remove
4506
4507
4507 Mark dest as copies of sources; mark sources for deletion. If dest
4508 Mark dest as copies of sources; mark sources for deletion. If dest
4508 is a directory, copies are put in that directory. If dest is a
4509 is a directory, copies are put in that directory. If dest is a
4509 file, there can only be one source.
4510 file, there can only be one source.
4510
4511
4511 By default, this command copies the contents of files as they
4512 By default, this command copies the contents of files as they
4512 exist in the working directory. If invoked with -A/--after, the
4513 exist in the working directory. If invoked with -A/--after, the
4513 operation is recorded, but no copying is performed.
4514 operation is recorded, but no copying is performed.
4514
4515
4515 This command takes effect at the next commit. To undo a rename
4516 This command takes effect at the next commit. To undo a rename
4516 before that, see :hg:`revert`.
4517 before that, see :hg:`revert`.
4517
4518
4518 Returns 0 on success, 1 if errors are encountered.
4519 Returns 0 on success, 1 if errors are encountered.
4519 """
4520 """
4520 opts = pycompat.byteskwargs(opts)
4521 opts = pycompat.byteskwargs(opts)
4521 with repo.wlock(False):
4522 with repo.wlock(False):
4522 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4523 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4523
4524
4524 @command('resolve',
4525 @command('resolve',
4525 [('a', 'all', None, _('select all unresolved files')),
4526 [('a', 'all', None, _('select all unresolved files')),
4526 ('l', 'list', None, _('list state of files needing merge')),
4527 ('l', 'list', None, _('list state of files needing merge')),
4527 ('m', 'mark', None, _('mark files as resolved')),
4528 ('m', 'mark', None, _('mark files as resolved')),
4528 ('u', 'unmark', None, _('mark files as unresolved')),
4529 ('u', 'unmark', None, _('mark files as unresolved')),
4529 ('n', 'no-status', None, _('hide status prefix')),
4530 ('n', 'no-status', None, _('hide status prefix')),
4530 ('', 're-merge', None, _('re-merge files'))]
4531 ('', 're-merge', None, _('re-merge files'))]
4531 + mergetoolopts + walkopts + formatteropts,
4532 + mergetoolopts + walkopts + formatteropts,
4532 _('[OPTION]... [FILE]...'),
4533 _('[OPTION]... [FILE]...'),
4533 inferrepo=True)
4534 inferrepo=True)
4534 def resolve(ui, repo, *pats, **opts):
4535 def resolve(ui, repo, *pats, **opts):
4535 """redo merges or set/view the merge status of files
4536 """redo merges or set/view the merge status of files
4536
4537
4537 Merges with unresolved conflicts are often the result of
4538 Merges with unresolved conflicts are often the result of
4538 non-interactive merging using the ``internal:merge`` configuration
4539 non-interactive merging using the ``internal:merge`` configuration
4539 setting, or a command-line merge tool like ``diff3``. The resolve
4540 setting, or a command-line merge tool like ``diff3``. The resolve
4540 command is used to manage the files involved in a merge, after
4541 command is used to manage the files involved in a merge, after
4541 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4542 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4542 working directory must have two parents). See :hg:`help
4543 working directory must have two parents). See :hg:`help
4543 merge-tools` for information on configuring merge tools.
4544 merge-tools` for information on configuring merge tools.
4544
4545
4545 The resolve command can be used in the following ways:
4546 The resolve command can be used in the following ways:
4546
4547
4547 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4548 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4548 the specified files, discarding any previous merge attempts. Re-merging
4549 the specified files, discarding any previous merge attempts. Re-merging
4549 is not performed for files already marked as resolved. Use ``--all/-a``
4550 is not performed for files already marked as resolved. Use ``--all/-a``
4550 to select all unresolved files. ``--tool`` can be used to specify
4551 to select all unresolved files. ``--tool`` can be used to specify
4551 the merge tool used for the given files. It overrides the HGMERGE
4552 the merge tool used for the given files. It overrides the HGMERGE
4552 environment variable and your configuration files. Previous file
4553 environment variable and your configuration files. Previous file
4553 contents are saved with a ``.orig`` suffix.
4554 contents are saved with a ``.orig`` suffix.
4554
4555
4555 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4556 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4556 (e.g. after having manually fixed-up the files). The default is
4557 (e.g. after having manually fixed-up the files). The default is
4557 to mark all unresolved files.
4558 to mark all unresolved files.
4558
4559
4559 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4560 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4560 default is to mark all resolved files.
4561 default is to mark all resolved files.
4561
4562
4562 - :hg:`resolve -l`: list files which had or still have conflicts.
4563 - :hg:`resolve -l`: list files which had or still have conflicts.
4563 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4564 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4564 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4565 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4565 the list. See :hg:`help filesets` for details.
4566 the list. See :hg:`help filesets` for details.
4566
4567
4567 .. note::
4568 .. note::
4568
4569
4569 Mercurial will not let you commit files with unresolved merge
4570 Mercurial will not let you commit files with unresolved merge
4570 conflicts. You must use :hg:`resolve -m ...` before you can
4571 conflicts. You must use :hg:`resolve -m ...` before you can
4571 commit after a conflicting merge.
4572 commit after a conflicting merge.
4572
4573
4573 Returns 0 on success, 1 if any files fail a resolve attempt.
4574 Returns 0 on success, 1 if any files fail a resolve attempt.
4574 """
4575 """
4575
4576
4576 opts = pycompat.byteskwargs(opts)
4577 opts = pycompat.byteskwargs(opts)
4577 confirm = ui.configbool('commands', 'resolve.confirm')
4578 confirm = ui.configbool('commands', 'resolve.confirm')
4578 flaglist = 'all mark unmark list no_status re_merge'.split()
4579 flaglist = 'all mark unmark list no_status re_merge'.split()
4579 all, mark, unmark, show, nostatus, remerge = \
4580 all, mark, unmark, show, nostatus, remerge = \
4580 [opts.get(o) for o in flaglist]
4581 [opts.get(o) for o in flaglist]
4581
4582
4582 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4583 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4583 if actioncount > 1:
4584 if actioncount > 1:
4584 raise error.Abort(_("too many actions specified"))
4585 raise error.Abort(_("too many actions specified"))
4585 elif (actioncount == 0
4586 elif (actioncount == 0
4586 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4587 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4587 hint = _('use --mark, --unmark, --list or --re-merge')
4588 hint = _('use --mark, --unmark, --list or --re-merge')
4588 raise error.Abort(_('no action specified'), hint=hint)
4589 raise error.Abort(_('no action specified'), hint=hint)
4589 if pats and all:
4590 if pats and all:
4590 raise error.Abort(_("can't specify --all and patterns"))
4591 raise error.Abort(_("can't specify --all and patterns"))
4591 if not (all or pats or show or mark or unmark):
4592 if not (all or pats or show or mark or unmark):
4592 raise error.Abort(_('no files or directories specified'),
4593 raise error.Abort(_('no files or directories specified'),
4593 hint=('use --all to re-merge all unresolved files'))
4594 hint=('use --all to re-merge all unresolved files'))
4594
4595
4595 if confirm:
4596 if confirm:
4596 if all:
4597 if all:
4597 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4598 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4598 b'$$ &Yes $$ &No')):
4599 b'$$ &Yes $$ &No')):
4599 raise error.Abort(_('user quit'))
4600 raise error.Abort(_('user quit'))
4600 if mark and not pats:
4601 if mark and not pats:
4601 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4602 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4602 b'$$ &Yes $$ &No')):
4603 b'$$ &Yes $$ &No')):
4603 raise error.Abort(_('user quit'))
4604 raise error.Abort(_('user quit'))
4604 if unmark and not pats:
4605 if unmark and not pats:
4605 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4606 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4606 b'$$ &Yes $$ &No')):
4607 b'$$ &Yes $$ &No')):
4607 raise error.Abort(_('user quit'))
4608 raise error.Abort(_('user quit'))
4608
4609
4609 if show:
4610 if show:
4610 ui.pager('resolve')
4611 ui.pager('resolve')
4611 fm = ui.formatter('resolve', opts)
4612 fm = ui.formatter('resolve', opts)
4612 ms = mergemod.mergestate.read(repo)
4613 ms = mergemod.mergestate.read(repo)
4613 wctx = repo[None]
4614 wctx = repo[None]
4614 m = scmutil.match(wctx, pats, opts)
4615 m = scmutil.match(wctx, pats, opts)
4615
4616
4616 # Labels and keys based on merge state. Unresolved path conflicts show
4617 # Labels and keys based on merge state. Unresolved path conflicts show
4617 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4618 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4618 # resolved conflicts.
4619 # resolved conflicts.
4619 mergestateinfo = {
4620 mergestateinfo = {
4620 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4621 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4621 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4622 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4622 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4623 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4623 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4624 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4624 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4625 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4625 'D'),
4626 'D'),
4626 }
4627 }
4627
4628
4628 for f in ms:
4629 for f in ms:
4629 if not m(f):
4630 if not m(f):
4630 continue
4631 continue
4631
4632
4632 label, key = mergestateinfo[ms[f]]
4633 label, key = mergestateinfo[ms[f]]
4633 fm.startitem()
4634 fm.startitem()
4634 fm.context(ctx=wctx)
4635 fm.context(ctx=wctx)
4635 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4636 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4636 fm.write('path', '%s\n', f, label=label)
4637 fm.write('path', '%s\n', f, label=label)
4637 fm.end()
4638 fm.end()
4638 return 0
4639 return 0
4639
4640
4640 with repo.wlock():
4641 with repo.wlock():
4641 ms = mergemod.mergestate.read(repo)
4642 ms = mergemod.mergestate.read(repo)
4642
4643
4643 if not (ms.active() or repo.dirstate.p2() != nullid):
4644 if not (ms.active() or repo.dirstate.p2() != nullid):
4644 raise error.Abort(
4645 raise error.Abort(
4645 _('resolve command not applicable when not merging'))
4646 _('resolve command not applicable when not merging'))
4646
4647
4647 wctx = repo[None]
4648 wctx = repo[None]
4648
4649
4649 if (ms.mergedriver
4650 if (ms.mergedriver
4650 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4651 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4651 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4652 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4652 ms.commit()
4653 ms.commit()
4653 # allow mark and unmark to go through
4654 # allow mark and unmark to go through
4654 if not mark and not unmark and not proceed:
4655 if not mark and not unmark and not proceed:
4655 return 1
4656 return 1
4656
4657
4657 m = scmutil.match(wctx, pats, opts)
4658 m = scmutil.match(wctx, pats, opts)
4658 ret = 0
4659 ret = 0
4659 didwork = False
4660 didwork = False
4660 runconclude = False
4661 runconclude = False
4661
4662
4662 tocomplete = []
4663 tocomplete = []
4663 hasconflictmarkers = []
4664 hasconflictmarkers = []
4664 if mark:
4665 if mark:
4665 markcheck = ui.config('commands', 'resolve.mark-check')
4666 markcheck = ui.config('commands', 'resolve.mark-check')
4666 if markcheck not in ['warn', 'abort']:
4667 if markcheck not in ['warn', 'abort']:
4667 # Treat all invalid / unrecognized values as 'none'.
4668 # Treat all invalid / unrecognized values as 'none'.
4668 markcheck = False
4669 markcheck = False
4669 for f in ms:
4670 for f in ms:
4670 if not m(f):
4671 if not m(f):
4671 continue
4672 continue
4672
4673
4673 didwork = True
4674 didwork = True
4674
4675
4675 # don't let driver-resolved files be marked, and run the conclude
4676 # don't let driver-resolved files be marked, and run the conclude
4676 # step if asked to resolve
4677 # step if asked to resolve
4677 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4678 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4678 exact = m.exact(f)
4679 exact = m.exact(f)
4679 if mark:
4680 if mark:
4680 if exact:
4681 if exact:
4681 ui.warn(_('not marking %s as it is driver-resolved\n')
4682 ui.warn(_('not marking %s as it is driver-resolved\n')
4682 % f)
4683 % f)
4683 elif unmark:
4684 elif unmark:
4684 if exact:
4685 if exact:
4685 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4686 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4686 % f)
4687 % f)
4687 else:
4688 else:
4688 runconclude = True
4689 runconclude = True
4689 continue
4690 continue
4690
4691
4691 # path conflicts must be resolved manually
4692 # path conflicts must be resolved manually
4692 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4693 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4693 mergemod.MERGE_RECORD_RESOLVED_PATH):
4694 mergemod.MERGE_RECORD_RESOLVED_PATH):
4694 if mark:
4695 if mark:
4695 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4696 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4696 elif unmark:
4697 elif unmark:
4697 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4698 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4698 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4699 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4699 ui.warn(_('%s: path conflict must be resolved manually\n')
4700 ui.warn(_('%s: path conflict must be resolved manually\n')
4700 % f)
4701 % f)
4701 continue
4702 continue
4702
4703
4703 if mark:
4704 if mark:
4704 if markcheck:
4705 if markcheck:
4705 with repo.wvfs(f) as fobj:
4706 with repo.wvfs(f) as fobj:
4706 fdata = fobj.read()
4707 fdata = fobj.read()
4707 if filemerge.hasconflictmarkers(fdata) and \
4708 if filemerge.hasconflictmarkers(fdata) and \
4708 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4709 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4709 hasconflictmarkers.append(f)
4710 hasconflictmarkers.append(f)
4710 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4711 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4711 elif unmark:
4712 elif unmark:
4712 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4713 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4713 else:
4714 else:
4714 # backup pre-resolve (merge uses .orig for its own purposes)
4715 # backup pre-resolve (merge uses .orig for its own purposes)
4715 a = repo.wjoin(f)
4716 a = repo.wjoin(f)
4716 try:
4717 try:
4717 util.copyfile(a, a + ".resolve")
4718 util.copyfile(a, a + ".resolve")
4718 except (IOError, OSError) as inst:
4719 except (IOError, OSError) as inst:
4719 if inst.errno != errno.ENOENT:
4720 if inst.errno != errno.ENOENT:
4720 raise
4721 raise
4721
4722
4722 try:
4723 try:
4723 # preresolve file
4724 # preresolve file
4724 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4725 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4725 with ui.configoverride(overrides, 'resolve'):
4726 with ui.configoverride(overrides, 'resolve'):
4726 complete, r = ms.preresolve(f, wctx)
4727 complete, r = ms.preresolve(f, wctx)
4727 if not complete:
4728 if not complete:
4728 tocomplete.append(f)
4729 tocomplete.append(f)
4729 elif r:
4730 elif r:
4730 ret = 1
4731 ret = 1
4731 finally:
4732 finally:
4732 ms.commit()
4733 ms.commit()
4733
4734
4734 # replace filemerge's .orig file with our resolve file, but only
4735 # replace filemerge's .orig file with our resolve file, but only
4735 # for merges that are complete
4736 # for merges that are complete
4736 if complete:
4737 if complete:
4737 try:
4738 try:
4738 util.rename(a + ".resolve",
4739 util.rename(a + ".resolve",
4739 scmutil.origpath(ui, repo, a))
4740 scmutil.origpath(ui, repo, a))
4740 except OSError as inst:
4741 except OSError as inst:
4741 if inst.errno != errno.ENOENT:
4742 if inst.errno != errno.ENOENT:
4742 raise
4743 raise
4743
4744
4744 if hasconflictmarkers:
4745 if hasconflictmarkers:
4745 ui.warn(_('warning: the following files still have conflict '
4746 ui.warn(_('warning: the following files still have conflict '
4746 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4747 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4747 if markcheck == 'abort' and not all:
4748 if markcheck == 'abort' and not all:
4748 raise error.Abort(_('conflict markers detected'),
4749 raise error.Abort(_('conflict markers detected'),
4749 hint=_('use --all to mark anyway'))
4750 hint=_('use --all to mark anyway'))
4750
4751
4751 for f in tocomplete:
4752 for f in tocomplete:
4752 try:
4753 try:
4753 # resolve file
4754 # resolve file
4754 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4755 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4755 with ui.configoverride(overrides, 'resolve'):
4756 with ui.configoverride(overrides, 'resolve'):
4756 r = ms.resolve(f, wctx)
4757 r = ms.resolve(f, wctx)
4757 if r:
4758 if r:
4758 ret = 1
4759 ret = 1
4759 finally:
4760 finally:
4760 ms.commit()
4761 ms.commit()
4761
4762
4762 # replace filemerge's .orig file with our resolve file
4763 # replace filemerge's .orig file with our resolve file
4763 a = repo.wjoin(f)
4764 a = repo.wjoin(f)
4764 try:
4765 try:
4765 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4766 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4766 except OSError as inst:
4767 except OSError as inst:
4767 if inst.errno != errno.ENOENT:
4768 if inst.errno != errno.ENOENT:
4768 raise
4769 raise
4769
4770
4770 ms.commit()
4771 ms.commit()
4771 ms.recordactions()
4772 ms.recordactions()
4772
4773
4773 if not didwork and pats:
4774 if not didwork and pats:
4774 hint = None
4775 hint = None
4775 if not any([p for p in pats if p.find(':') >= 0]):
4776 if not any([p for p in pats if p.find(':') >= 0]):
4776 pats = ['path:%s' % p for p in pats]
4777 pats = ['path:%s' % p for p in pats]
4777 m = scmutil.match(wctx, pats, opts)
4778 m = scmutil.match(wctx, pats, opts)
4778 for f in ms:
4779 for f in ms:
4779 if not m(f):
4780 if not m(f):
4780 continue
4781 continue
4781 def flag(o):
4782 def flag(o):
4782 if o == 're_merge':
4783 if o == 're_merge':
4783 return '--re-merge '
4784 return '--re-merge '
4784 return '-%s ' % o[0:1]
4785 return '-%s ' % o[0:1]
4785 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4786 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4786 hint = _("(try: hg resolve %s%s)\n") % (
4787 hint = _("(try: hg resolve %s%s)\n") % (
4787 flags,
4788 flags,
4788 ' '.join(pats))
4789 ' '.join(pats))
4789 break
4790 break
4790 ui.warn(_("arguments do not match paths that need resolving\n"))
4791 ui.warn(_("arguments do not match paths that need resolving\n"))
4791 if hint:
4792 if hint:
4792 ui.warn(hint)
4793 ui.warn(hint)
4793 elif ms.mergedriver and ms.mdstate() != 's':
4794 elif ms.mergedriver and ms.mdstate() != 's':
4794 # run conclude step when either a driver-resolved file is requested
4795 # run conclude step when either a driver-resolved file is requested
4795 # or there are no driver-resolved files
4796 # or there are no driver-resolved files
4796 # we can't use 'ret' to determine whether any files are unresolved
4797 # we can't use 'ret' to determine whether any files are unresolved
4797 # because we might not have tried to resolve some
4798 # because we might not have tried to resolve some
4798 if ((runconclude or not list(ms.driverresolved()))
4799 if ((runconclude or not list(ms.driverresolved()))
4799 and not list(ms.unresolved())):
4800 and not list(ms.unresolved())):
4800 proceed = mergemod.driverconclude(repo, ms, wctx)
4801 proceed = mergemod.driverconclude(repo, ms, wctx)
4801 ms.commit()
4802 ms.commit()
4802 if not proceed:
4803 if not proceed:
4803 return 1
4804 return 1
4804
4805
4805 # Nudge users into finishing an unfinished operation
4806 # Nudge users into finishing an unfinished operation
4806 unresolvedf = list(ms.unresolved())
4807 unresolvedf = list(ms.unresolved())
4807 driverresolvedf = list(ms.driverresolved())
4808 driverresolvedf = list(ms.driverresolved())
4808 if not unresolvedf and not driverresolvedf:
4809 if not unresolvedf and not driverresolvedf:
4809 ui.status(_('(no more unresolved files)\n'))
4810 ui.status(_('(no more unresolved files)\n'))
4810 cmdutil.checkafterresolved(repo)
4811 cmdutil.checkafterresolved(repo)
4811 elif not unresolvedf:
4812 elif not unresolvedf:
4812 ui.status(_('(no more unresolved files -- '
4813 ui.status(_('(no more unresolved files -- '
4813 'run "hg resolve --all" to conclude)\n'))
4814 'run "hg resolve --all" to conclude)\n'))
4814
4815
4815 return ret
4816 return ret
4816
4817
4817 @command('revert',
4818 @command('revert',
4818 [('a', 'all', None, _('revert all changes when no arguments given')),
4819 [('a', 'all', None, _('revert all changes when no arguments given')),
4819 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4820 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4820 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4821 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4821 ('C', 'no-backup', None, _('do not save backup copies of files')),
4822 ('C', 'no-backup', None, _('do not save backup copies of files')),
4822 ('i', 'interactive', None, _('interactively select the changes')),
4823 ('i', 'interactive', None, _('interactively select the changes')),
4823 ] + walkopts + dryrunopts,
4824 ] + walkopts + dryrunopts,
4824 _('[OPTION]... [-r REV] [NAME]...'))
4825 _('[OPTION]... [-r REV] [NAME]...'))
4825 def revert(ui, repo, *pats, **opts):
4826 def revert(ui, repo, *pats, **opts):
4826 """restore files to their checkout state
4827 """restore files to their checkout state
4827
4828
4828 .. note::
4829 .. note::
4829
4830
4830 To check out earlier revisions, you should use :hg:`update REV`.
4831 To check out earlier revisions, you should use :hg:`update REV`.
4831 To cancel an uncommitted merge (and lose your changes),
4832 To cancel an uncommitted merge (and lose your changes),
4832 use :hg:`merge --abort`.
4833 use :hg:`merge --abort`.
4833
4834
4834 With no revision specified, revert the specified files or directories
4835 With no revision specified, revert the specified files or directories
4835 to the contents they had in the parent of the working directory.
4836 to the contents they had in the parent of the working directory.
4836 This restores the contents of files to an unmodified
4837 This restores the contents of files to an unmodified
4837 state and unschedules adds, removes, copies, and renames. If the
4838 state and unschedules adds, removes, copies, and renames. If the
4838 working directory has two parents, you must explicitly specify a
4839 working directory has two parents, you must explicitly specify a
4839 revision.
4840 revision.
4840
4841
4841 Using the -r/--rev or -d/--date options, revert the given files or
4842 Using the -r/--rev or -d/--date options, revert the given files or
4842 directories to their states as of a specific revision. Because
4843 directories to their states as of a specific revision. Because
4843 revert does not change the working directory parents, this will
4844 revert does not change the working directory parents, this will
4844 cause these files to appear modified. This can be helpful to "back
4845 cause these files to appear modified. This can be helpful to "back
4845 out" some or all of an earlier change. See :hg:`backout` for a
4846 out" some or all of an earlier change. See :hg:`backout` for a
4846 related method.
4847 related method.
4847
4848
4848 Modified files are saved with a .orig suffix before reverting.
4849 Modified files are saved with a .orig suffix before reverting.
4849 To disable these backups, use --no-backup. It is possible to store
4850 To disable these backups, use --no-backup. It is possible to store
4850 the backup files in a custom directory relative to the root of the
4851 the backup files in a custom directory relative to the root of the
4851 repository by setting the ``ui.origbackuppath`` configuration
4852 repository by setting the ``ui.origbackuppath`` configuration
4852 option.
4853 option.
4853
4854
4854 See :hg:`help dates` for a list of formats valid for -d/--date.
4855 See :hg:`help dates` for a list of formats valid for -d/--date.
4855
4856
4856 See :hg:`help backout` for a way to reverse the effect of an
4857 See :hg:`help backout` for a way to reverse the effect of an
4857 earlier changeset.
4858 earlier changeset.
4858
4859
4859 Returns 0 on success.
4860 Returns 0 on success.
4860 """
4861 """
4861
4862
4862 opts = pycompat.byteskwargs(opts)
4863 opts = pycompat.byteskwargs(opts)
4863 if opts.get("date"):
4864 if opts.get("date"):
4864 if opts.get("rev"):
4865 if opts.get("rev"):
4865 raise error.Abort(_("you can't specify a revision and a date"))
4866 raise error.Abort(_("you can't specify a revision and a date"))
4866 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4867 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4867
4868
4868 parent, p2 = repo.dirstate.parents()
4869 parent, p2 = repo.dirstate.parents()
4869 if not opts.get('rev') and p2 != nullid:
4870 if not opts.get('rev') and p2 != nullid:
4870 # revert after merge is a trap for new users (issue2915)
4871 # revert after merge is a trap for new users (issue2915)
4871 raise error.Abort(_('uncommitted merge with no revision specified'),
4872 raise error.Abort(_('uncommitted merge with no revision specified'),
4872 hint=_("use 'hg update' or see 'hg help revert'"))
4873 hint=_("use 'hg update' or see 'hg help revert'"))
4873
4874
4874 rev = opts.get('rev')
4875 rev = opts.get('rev')
4875 if rev:
4876 if rev:
4876 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4877 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4877 ctx = scmutil.revsingle(repo, rev)
4878 ctx = scmutil.revsingle(repo, rev)
4878
4879
4879 if (not (pats or opts.get('include') or opts.get('exclude') or
4880 if (not (pats or opts.get('include') or opts.get('exclude') or
4880 opts.get('all') or opts.get('interactive'))):
4881 opts.get('all') or opts.get('interactive'))):
4881 msg = _("no files or directories specified")
4882 msg = _("no files or directories specified")
4882 if p2 != nullid:
4883 if p2 != nullid:
4883 hint = _("uncommitted merge, use --all to discard all changes,"
4884 hint = _("uncommitted merge, use --all to discard all changes,"
4884 " or 'hg update -C .' to abort the merge")
4885 " or 'hg update -C .' to abort the merge")
4885 raise error.Abort(msg, hint=hint)
4886 raise error.Abort(msg, hint=hint)
4886 dirty = any(repo.status())
4887 dirty = any(repo.status())
4887 node = ctx.node()
4888 node = ctx.node()
4888 if node != parent:
4889 if node != parent:
4889 if dirty:
4890 if dirty:
4890 hint = _("uncommitted changes, use --all to discard all"
4891 hint = _("uncommitted changes, use --all to discard all"
4891 " changes, or 'hg update %d' to update") % ctx.rev()
4892 " changes, or 'hg update %d' to update") % ctx.rev()
4892 else:
4893 else:
4893 hint = _("use --all to revert all files,"
4894 hint = _("use --all to revert all files,"
4894 " or 'hg update %d' to update") % ctx.rev()
4895 " or 'hg update %d' to update") % ctx.rev()
4895 elif dirty:
4896 elif dirty:
4896 hint = _("uncommitted changes, use --all to discard all changes")
4897 hint = _("uncommitted changes, use --all to discard all changes")
4897 else:
4898 else:
4898 hint = _("use --all to revert all files")
4899 hint = _("use --all to revert all files")
4899 raise error.Abort(msg, hint=hint)
4900 raise error.Abort(msg, hint=hint)
4900
4901
4901 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4902 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4902 **pycompat.strkwargs(opts))
4903 **pycompat.strkwargs(opts))
4903
4904
4904 @command('rollback', dryrunopts +
4905 @command('rollback', dryrunopts +
4905 [('f', 'force', False, _('ignore safety measures'))])
4906 [('f', 'force', False, _('ignore safety measures'))])
4906 def rollback(ui, repo, **opts):
4907 def rollback(ui, repo, **opts):
4907 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4908 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4908
4909
4909 Please use :hg:`commit --amend` instead of rollback to correct
4910 Please use :hg:`commit --amend` instead of rollback to correct
4910 mistakes in the last commit.
4911 mistakes in the last commit.
4911
4912
4912 This command should be used with care. There is only one level of
4913 This command should be used with care. There is only one level of
4913 rollback, and there is no way to undo a rollback. It will also
4914 rollback, and there is no way to undo a rollback. It will also
4914 restore the dirstate at the time of the last transaction, losing
4915 restore the dirstate at the time of the last transaction, losing
4915 any dirstate changes since that time. This command does not alter
4916 any dirstate changes since that time. This command does not alter
4916 the working directory.
4917 the working directory.
4917
4918
4918 Transactions are used to encapsulate the effects of all commands
4919 Transactions are used to encapsulate the effects of all commands
4919 that create new changesets or propagate existing changesets into a
4920 that create new changesets or propagate existing changesets into a
4920 repository.
4921 repository.
4921
4922
4922 .. container:: verbose
4923 .. container:: verbose
4923
4924
4924 For example, the following commands are transactional, and their
4925 For example, the following commands are transactional, and their
4925 effects can be rolled back:
4926 effects can be rolled back:
4926
4927
4927 - commit
4928 - commit
4928 - import
4929 - import
4929 - pull
4930 - pull
4930 - push (with this repository as the destination)
4931 - push (with this repository as the destination)
4931 - unbundle
4932 - unbundle
4932
4933
4933 To avoid permanent data loss, rollback will refuse to rollback a
4934 To avoid permanent data loss, rollback will refuse to rollback a
4934 commit transaction if it isn't checked out. Use --force to
4935 commit transaction if it isn't checked out. Use --force to
4935 override this protection.
4936 override this protection.
4936
4937
4937 The rollback command can be entirely disabled by setting the
4938 The rollback command can be entirely disabled by setting the
4938 ``ui.rollback`` configuration setting to false. If you're here
4939 ``ui.rollback`` configuration setting to false. If you're here
4939 because you want to use rollback and it's disabled, you can
4940 because you want to use rollback and it's disabled, you can
4940 re-enable the command by setting ``ui.rollback`` to true.
4941 re-enable the command by setting ``ui.rollback`` to true.
4941
4942
4942 This command is not intended for use on public repositories. Once
4943 This command is not intended for use on public repositories. Once
4943 changes are visible for pull by other users, rolling a transaction
4944 changes are visible for pull by other users, rolling a transaction
4944 back locally is ineffective (someone else may already have pulled
4945 back locally is ineffective (someone else may already have pulled
4945 the changes). Furthermore, a race is possible with readers of the
4946 the changes). Furthermore, a race is possible with readers of the
4946 repository; for example an in-progress pull from the repository
4947 repository; for example an in-progress pull from the repository
4947 may fail if a rollback is performed.
4948 may fail if a rollback is performed.
4948
4949
4949 Returns 0 on success, 1 if no rollback data is available.
4950 Returns 0 on success, 1 if no rollback data is available.
4950 """
4951 """
4951 if not ui.configbool('ui', 'rollback'):
4952 if not ui.configbool('ui', 'rollback'):
4952 raise error.Abort(_('rollback is disabled because it is unsafe'),
4953 raise error.Abort(_('rollback is disabled because it is unsafe'),
4953 hint=('see `hg help -v rollback` for information'))
4954 hint=('see `hg help -v rollback` for information'))
4954 return repo.rollback(dryrun=opts.get(r'dry_run'),
4955 return repo.rollback(dryrun=opts.get(r'dry_run'),
4955 force=opts.get(r'force'))
4956 force=opts.get(r'force'))
4956
4957
4957 @command('root', [], intents={INTENT_READONLY})
4958 @command('root', [], intents={INTENT_READONLY})
4958 def root(ui, repo):
4959 def root(ui, repo):
4959 """print the root (top) of the current working directory
4960 """print the root (top) of the current working directory
4960
4961
4961 Print the root directory of the current repository.
4962 Print the root directory of the current repository.
4962
4963
4963 Returns 0 on success.
4964 Returns 0 on success.
4964 """
4965 """
4965 ui.write(repo.root + "\n")
4966 ui.write(repo.root + "\n")
4966
4967
4967 @command('^serve',
4968 @command('^serve',
4968 [('A', 'accesslog', '', _('name of access log file to write to'),
4969 [('A', 'accesslog', '', _('name of access log file to write to'),
4969 _('FILE')),
4970 _('FILE')),
4970 ('d', 'daemon', None, _('run server in background')),
4971 ('d', 'daemon', None, _('run server in background')),
4971 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4972 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4972 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4973 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4973 # use string type, then we can check if something was passed
4974 # use string type, then we can check if something was passed
4974 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4975 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4975 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4976 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4976 _('ADDR')),
4977 _('ADDR')),
4977 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4978 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4978 _('PREFIX')),
4979 _('PREFIX')),
4979 ('n', 'name', '',
4980 ('n', 'name', '',
4980 _('name to show in web pages (default: working directory)'), _('NAME')),
4981 _('name to show in web pages (default: working directory)'), _('NAME')),
4981 ('', 'web-conf', '',
4982 ('', 'web-conf', '',
4982 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4983 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4983 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4984 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4984 _('FILE')),
4985 _('FILE')),
4985 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4986 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4986 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4987 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4987 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4988 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4988 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4989 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4989 ('', 'style', '', _('template style to use'), _('STYLE')),
4990 ('', 'style', '', _('template style to use'), _('STYLE')),
4990 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4991 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4991 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4992 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4992 ('', 'print-url', None, _('start and print only the URL'))]
4993 ('', 'print-url', None, _('start and print only the URL'))]
4993 + subrepoopts,
4994 + subrepoopts,
4994 _('[OPTION]...'),
4995 _('[OPTION]...'),
4995 optionalrepo=True)
4996 optionalrepo=True)
4996 def serve(ui, repo, **opts):
4997 def serve(ui, repo, **opts):
4997 """start stand-alone webserver
4998 """start stand-alone webserver
4998
4999
4999 Start a local HTTP repository browser and pull server. You can use
5000 Start a local HTTP repository browser and pull server. You can use
5000 this for ad-hoc sharing and browsing of repositories. It is
5001 this for ad-hoc sharing and browsing of repositories. It is
5001 recommended to use a real web server to serve a repository for
5002 recommended to use a real web server to serve a repository for
5002 longer periods of time.
5003 longer periods of time.
5003
5004
5004 Please note that the server does not implement access control.
5005 Please note that the server does not implement access control.
5005 This means that, by default, anybody can read from the server and
5006 This means that, by default, anybody can read from the server and
5006 nobody can write to it by default. Set the ``web.allow-push``
5007 nobody can write to it by default. Set the ``web.allow-push``
5007 option to ``*`` to allow everybody to push to the server. You
5008 option to ``*`` to allow everybody to push to the server. You
5008 should use a real web server if you need to authenticate users.
5009 should use a real web server if you need to authenticate users.
5009
5010
5010 By default, the server logs accesses to stdout and errors to
5011 By default, the server logs accesses to stdout and errors to
5011 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5012 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5012 files.
5013 files.
5013
5014
5014 To have the server choose a free port number to listen on, specify
5015 To have the server choose a free port number to listen on, specify
5015 a port number of 0; in this case, the server will print the port
5016 a port number of 0; in this case, the server will print the port
5016 number it uses.
5017 number it uses.
5017
5018
5018 Returns 0 on success.
5019 Returns 0 on success.
5019 """
5020 """
5020
5021
5021 opts = pycompat.byteskwargs(opts)
5022 opts = pycompat.byteskwargs(opts)
5022 if opts["stdio"] and opts["cmdserver"]:
5023 if opts["stdio"] and opts["cmdserver"]:
5023 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5024 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5024 if opts["print_url"] and ui.verbose:
5025 if opts["print_url"] and ui.verbose:
5025 raise error.Abort(_("cannot use --print-url with --verbose"))
5026 raise error.Abort(_("cannot use --print-url with --verbose"))
5026
5027
5027 if opts["stdio"]:
5028 if opts["stdio"]:
5028 if repo is None:
5029 if repo is None:
5029 raise error.RepoError(_("there is no Mercurial repository here"
5030 raise error.RepoError(_("there is no Mercurial repository here"
5030 " (.hg not found)"))
5031 " (.hg not found)"))
5031 s = wireprotoserver.sshserver(ui, repo)
5032 s = wireprotoserver.sshserver(ui, repo)
5032 s.serve_forever()
5033 s.serve_forever()
5033
5034
5034 service = server.createservice(ui, repo, opts)
5035 service = server.createservice(ui, repo, opts)
5035 return server.runservice(opts, initfn=service.init, runfn=service.run)
5036 return server.runservice(opts, initfn=service.init, runfn=service.run)
5036
5037
5037 _NOTTERSE = 'nothing'
5038 _NOTTERSE = 'nothing'
5038
5039
5039 @command('^status|st',
5040 @command('^status|st',
5040 [('A', 'all', None, _('show status of all files')),
5041 [('A', 'all', None, _('show status of all files')),
5041 ('m', 'modified', None, _('show only modified files')),
5042 ('m', 'modified', None, _('show only modified files')),
5042 ('a', 'added', None, _('show only added files')),
5043 ('a', 'added', None, _('show only added files')),
5043 ('r', 'removed', None, _('show only removed files')),
5044 ('r', 'removed', None, _('show only removed files')),
5044 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5045 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5045 ('c', 'clean', None, _('show only files without changes')),
5046 ('c', 'clean', None, _('show only files without changes')),
5046 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5047 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5047 ('i', 'ignored', None, _('show only ignored files')),
5048 ('i', 'ignored', None, _('show only ignored files')),
5048 ('n', 'no-status', None, _('hide status prefix')),
5049 ('n', 'no-status', None, _('hide status prefix')),
5049 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5050 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5050 ('C', 'copies', None, _('show source of copied files')),
5051 ('C', 'copies', None, _('show source of copied files')),
5051 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5052 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5052 ('', 'rev', [], _('show difference from revision'), _('REV')),
5053 ('', 'rev', [], _('show difference from revision'), _('REV')),
5053 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5054 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5054 ] + walkopts + subrepoopts + formatteropts,
5055 ] + walkopts + subrepoopts + formatteropts,
5055 _('[OPTION]... [FILE]...'),
5056 _('[OPTION]... [FILE]...'),
5056 inferrepo=True,
5057 inferrepo=True,
5057 intents={INTENT_READONLY})
5058 intents={INTENT_READONLY})
5058 def status(ui, repo, *pats, **opts):
5059 def status(ui, repo, *pats, **opts):
5059 """show changed files in the working directory
5060 """show changed files in the working directory
5060
5061
5061 Show status of files in the repository. If names are given, only
5062 Show status of files in the repository. If names are given, only
5062 files that match are shown. Files that are clean or ignored or
5063 files that match are shown. Files that are clean or ignored or
5063 the source of a copy/move operation, are not listed unless
5064 the source of a copy/move operation, are not listed unless
5064 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5065 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5065 Unless options described with "show only ..." are given, the
5066 Unless options described with "show only ..." are given, the
5066 options -mardu are used.
5067 options -mardu are used.
5067
5068
5068 Option -q/--quiet hides untracked (unknown and ignored) files
5069 Option -q/--quiet hides untracked (unknown and ignored) files
5069 unless explicitly requested with -u/--unknown or -i/--ignored.
5070 unless explicitly requested with -u/--unknown or -i/--ignored.
5070
5071
5071 .. note::
5072 .. note::
5072
5073
5073 :hg:`status` may appear to disagree with diff if permissions have
5074 :hg:`status` may appear to disagree with diff if permissions have
5074 changed or a merge has occurred. The standard diff format does
5075 changed or a merge has occurred. The standard diff format does
5075 not report permission changes and diff only reports changes
5076 not report permission changes and diff only reports changes
5076 relative to one merge parent.
5077 relative to one merge parent.
5077
5078
5078 If one revision is given, it is used as the base revision.
5079 If one revision is given, it is used as the base revision.
5079 If two revisions are given, the differences between them are
5080 If two revisions are given, the differences between them are
5080 shown. The --change option can also be used as a shortcut to list
5081 shown. The --change option can also be used as a shortcut to list
5081 the changed files of a revision from its first parent.
5082 the changed files of a revision from its first parent.
5082
5083
5083 The codes used to show the status of files are::
5084 The codes used to show the status of files are::
5084
5085
5085 M = modified
5086 M = modified
5086 A = added
5087 A = added
5087 R = removed
5088 R = removed
5088 C = clean
5089 C = clean
5089 ! = missing (deleted by non-hg command, but still tracked)
5090 ! = missing (deleted by non-hg command, but still tracked)
5090 ? = not tracked
5091 ? = not tracked
5091 I = ignored
5092 I = ignored
5092 = origin of the previous file (with --copies)
5093 = origin of the previous file (with --copies)
5093
5094
5094 .. container:: verbose
5095 .. container:: verbose
5095
5096
5096 The -t/--terse option abbreviates the output by showing only the directory
5097 The -t/--terse option abbreviates the output by showing only the directory
5097 name if all the files in it share the same status. The option takes an
5098 name if all the files in it share the same status. The option takes an
5098 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5099 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5099 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5100 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5100 for 'ignored' and 'c' for clean.
5101 for 'ignored' and 'c' for clean.
5101
5102
5102 It abbreviates only those statuses which are passed. Note that clean and
5103 It abbreviates only those statuses which are passed. Note that clean and
5103 ignored files are not displayed with '--terse ic' unless the -c/--clean
5104 ignored files are not displayed with '--terse ic' unless the -c/--clean
5104 and -i/--ignored options are also used.
5105 and -i/--ignored options are also used.
5105
5106
5106 The -v/--verbose option shows information when the repository is in an
5107 The -v/--verbose option shows information when the repository is in an
5107 unfinished merge, shelve, rebase state etc. You can have this behavior
5108 unfinished merge, shelve, rebase state etc. You can have this behavior
5108 turned on by default by enabling the ``commands.status.verbose`` option.
5109 turned on by default by enabling the ``commands.status.verbose`` option.
5109
5110
5110 You can skip displaying some of these states by setting
5111 You can skip displaying some of these states by setting
5111 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5112 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5112 'histedit', 'merge', 'rebase', or 'unshelve'.
5113 'histedit', 'merge', 'rebase', or 'unshelve'.
5113
5114
5114 Examples:
5115 Examples:
5115
5116
5116 - show changes in the working directory relative to a
5117 - show changes in the working directory relative to a
5117 changeset::
5118 changeset::
5118
5119
5119 hg status --rev 9353
5120 hg status --rev 9353
5120
5121
5121 - show changes in the working directory relative to the
5122 - show changes in the working directory relative to the
5122 current directory (see :hg:`help patterns` for more information)::
5123 current directory (see :hg:`help patterns` for more information)::
5123
5124
5124 hg status re:
5125 hg status re:
5125
5126
5126 - show all changes including copies in an existing changeset::
5127 - show all changes including copies in an existing changeset::
5127
5128
5128 hg status --copies --change 9353
5129 hg status --copies --change 9353
5129
5130
5130 - get a NUL separated list of added files, suitable for xargs::
5131 - get a NUL separated list of added files, suitable for xargs::
5131
5132
5132 hg status -an0
5133 hg status -an0
5133
5134
5134 - show more information about the repository status, abbreviating
5135 - show more information about the repository status, abbreviating
5135 added, removed, modified, deleted, and untracked paths::
5136 added, removed, modified, deleted, and untracked paths::
5136
5137
5137 hg status -v -t mardu
5138 hg status -v -t mardu
5138
5139
5139 Returns 0 on success.
5140 Returns 0 on success.
5140
5141
5141 """
5142 """
5142
5143
5143 opts = pycompat.byteskwargs(opts)
5144 opts = pycompat.byteskwargs(opts)
5144 revs = opts.get('rev')
5145 revs = opts.get('rev')
5145 change = opts.get('change')
5146 change = opts.get('change')
5146 terse = opts.get('terse')
5147 terse = opts.get('terse')
5147 if terse is _NOTTERSE:
5148 if terse is _NOTTERSE:
5148 if revs:
5149 if revs:
5149 terse = ''
5150 terse = ''
5150 else:
5151 else:
5151 terse = ui.config('commands', 'status.terse')
5152 terse = ui.config('commands', 'status.terse')
5152
5153
5153 if revs and change:
5154 if revs and change:
5154 msg = _('cannot specify --rev and --change at the same time')
5155 msg = _('cannot specify --rev and --change at the same time')
5155 raise error.Abort(msg)
5156 raise error.Abort(msg)
5156 elif revs and terse:
5157 elif revs and terse:
5157 msg = _('cannot use --terse with --rev')
5158 msg = _('cannot use --terse with --rev')
5158 raise error.Abort(msg)
5159 raise error.Abort(msg)
5159 elif change:
5160 elif change:
5160 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5161 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5161 ctx2 = scmutil.revsingle(repo, change, None)
5162 ctx2 = scmutil.revsingle(repo, change, None)
5162 ctx1 = ctx2.p1()
5163 ctx1 = ctx2.p1()
5163 else:
5164 else:
5164 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5165 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5165 ctx1, ctx2 = scmutil.revpair(repo, revs)
5166 ctx1, ctx2 = scmutil.revpair(repo, revs)
5166
5167
5167 if pats or ui.configbool('commands', 'status.relative'):
5168 if pats or ui.configbool('commands', 'status.relative'):
5168 cwd = repo.getcwd()
5169 cwd = repo.getcwd()
5169 else:
5170 else:
5170 cwd = ''
5171 cwd = ''
5171
5172
5172 if opts.get('print0'):
5173 if opts.get('print0'):
5173 end = '\0'
5174 end = '\0'
5174 else:
5175 else:
5175 end = '\n'
5176 end = '\n'
5176 copy = {}
5177 copy = {}
5177 states = 'modified added removed deleted unknown ignored clean'.split()
5178 states = 'modified added removed deleted unknown ignored clean'.split()
5178 show = [k for k in states if opts.get(k)]
5179 show = [k for k in states if opts.get(k)]
5179 if opts.get('all'):
5180 if opts.get('all'):
5180 show += ui.quiet and (states[:4] + ['clean']) or states
5181 show += ui.quiet and (states[:4] + ['clean']) or states
5181
5182
5182 if not show:
5183 if not show:
5183 if ui.quiet:
5184 if ui.quiet:
5184 show = states[:4]
5185 show = states[:4]
5185 else:
5186 else:
5186 show = states[:5]
5187 show = states[:5]
5187
5188
5188 m = scmutil.match(ctx2, pats, opts)
5189 m = scmutil.match(ctx2, pats, opts)
5189 if terse:
5190 if terse:
5190 # we need to compute clean and unknown to terse
5191 # we need to compute clean and unknown to terse
5191 stat = repo.status(ctx1.node(), ctx2.node(), m,
5192 stat = repo.status(ctx1.node(), ctx2.node(), m,
5192 'ignored' in show or 'i' in terse,
5193 'ignored' in show or 'i' in terse,
5193 clean=True, unknown=True,
5194 clean=True, unknown=True,
5194 listsubrepos=opts.get('subrepos'))
5195 listsubrepos=opts.get('subrepos'))
5195
5196
5196 stat = cmdutil.tersedir(stat, terse)
5197 stat = cmdutil.tersedir(stat, terse)
5197 else:
5198 else:
5198 stat = repo.status(ctx1.node(), ctx2.node(), m,
5199 stat = repo.status(ctx1.node(), ctx2.node(), m,
5199 'ignored' in show, 'clean' in show,
5200 'ignored' in show, 'clean' in show,
5200 'unknown' in show, opts.get('subrepos'))
5201 'unknown' in show, opts.get('subrepos'))
5201
5202
5202 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5203 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5203
5204
5204 if (opts.get('all') or opts.get('copies')
5205 if (opts.get('all') or opts.get('copies')
5205 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5206 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5206 copy = copies.pathcopies(ctx1, ctx2, m)
5207 copy = copies.pathcopies(ctx1, ctx2, m)
5207
5208
5208 ui.pager('status')
5209 ui.pager('status')
5209 fm = ui.formatter('status', opts)
5210 fm = ui.formatter('status', opts)
5210 fmt = '%s' + end
5211 fmt = '%s' + end
5211 showchar = not opts.get('no_status')
5212 showchar = not opts.get('no_status')
5212
5213
5213 for state, char, files in changestates:
5214 for state, char, files in changestates:
5214 if state in show:
5215 if state in show:
5215 label = 'status.' + state
5216 label = 'status.' + state
5216 for f in files:
5217 for f in files:
5217 fm.startitem()
5218 fm.startitem()
5218 fm.context(ctx=ctx2)
5219 fm.context(ctx=ctx2)
5219 fm.data(path=f)
5220 fm.data(path=f)
5220 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5221 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5221 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5222 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5222 if f in copy:
5223 if f in copy:
5223 fm.data(source=copy[f])
5224 fm.data(source=copy[f])
5224 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5225 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5225 label='status.copied')
5226 label='status.copied')
5226
5227
5227 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5228 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5228 and not ui.plain()):
5229 and not ui.plain()):
5229 cmdutil.morestatus(repo, fm)
5230 cmdutil.morestatus(repo, fm)
5230 fm.end()
5231 fm.end()
5231
5232
5232 @command('^summary|sum',
5233 @command('^summary|sum',
5233 [('', 'remote', None, _('check for push and pull'))],
5234 [('', 'remote', None, _('check for push and pull'))],
5234 '[--remote]',
5235 '[--remote]',
5235 intents={INTENT_READONLY})
5236 intents={INTENT_READONLY})
5236 def summary(ui, repo, **opts):
5237 def summary(ui, repo, **opts):
5237 """summarize working directory state
5238 """summarize working directory state
5238
5239
5239 This generates a brief summary of the working directory state,
5240 This generates a brief summary of the working directory state,
5240 including parents, branch, commit status, phase and available updates.
5241 including parents, branch, commit status, phase and available updates.
5241
5242
5242 With the --remote option, this will check the default paths for
5243 With the --remote option, this will check the default paths for
5243 incoming and outgoing changes. This can be time-consuming.
5244 incoming and outgoing changes. This can be time-consuming.
5244
5245
5245 Returns 0 on success.
5246 Returns 0 on success.
5246 """
5247 """
5247
5248
5248 opts = pycompat.byteskwargs(opts)
5249 opts = pycompat.byteskwargs(opts)
5249 ui.pager('summary')
5250 ui.pager('summary')
5250 ctx = repo[None]
5251 ctx = repo[None]
5251 parents = ctx.parents()
5252 parents = ctx.parents()
5252 pnode = parents[0].node()
5253 pnode = parents[0].node()
5253 marks = []
5254 marks = []
5254
5255
5255 ms = None
5256 ms = None
5256 try:
5257 try:
5257 ms = mergemod.mergestate.read(repo)
5258 ms = mergemod.mergestate.read(repo)
5258 except error.UnsupportedMergeRecords as e:
5259 except error.UnsupportedMergeRecords as e:
5259 s = ' '.join(e.recordtypes)
5260 s = ' '.join(e.recordtypes)
5260 ui.warn(
5261 ui.warn(
5261 _('warning: merge state has unsupported record types: %s\n') % s)
5262 _('warning: merge state has unsupported record types: %s\n') % s)
5262 unresolved = []
5263 unresolved = []
5263 else:
5264 else:
5264 unresolved = list(ms.unresolved())
5265 unresolved = list(ms.unresolved())
5265
5266
5266 for p in parents:
5267 for p in parents:
5267 # label with log.changeset (instead of log.parent) since this
5268 # label with log.changeset (instead of log.parent) since this
5268 # shows a working directory parent *changeset*:
5269 # shows a working directory parent *changeset*:
5269 # i18n: column positioning for "hg summary"
5270 # i18n: column positioning for "hg summary"
5270 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5271 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5271 label=logcmdutil.changesetlabels(p))
5272 label=logcmdutil.changesetlabels(p))
5272 ui.write(' '.join(p.tags()), label='log.tag')
5273 ui.write(' '.join(p.tags()), label='log.tag')
5273 if p.bookmarks():
5274 if p.bookmarks():
5274 marks.extend(p.bookmarks())
5275 marks.extend(p.bookmarks())
5275 if p.rev() == -1:
5276 if p.rev() == -1:
5276 if not len(repo):
5277 if not len(repo):
5277 ui.write(_(' (empty repository)'))
5278 ui.write(_(' (empty repository)'))
5278 else:
5279 else:
5279 ui.write(_(' (no revision checked out)'))
5280 ui.write(_(' (no revision checked out)'))
5280 if p.obsolete():
5281 if p.obsolete():
5281 ui.write(_(' (obsolete)'))
5282 ui.write(_(' (obsolete)'))
5282 if p.isunstable():
5283 if p.isunstable():
5283 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5284 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5284 for instability in p.instabilities())
5285 for instability in p.instabilities())
5285 ui.write(' ('
5286 ui.write(' ('
5286 + ', '.join(instabilities)
5287 + ', '.join(instabilities)
5287 + ')')
5288 + ')')
5288 ui.write('\n')
5289 ui.write('\n')
5289 if p.description():
5290 if p.description():
5290 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5291 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5291 label='log.summary')
5292 label='log.summary')
5292
5293
5293 branch = ctx.branch()
5294 branch = ctx.branch()
5294 bheads = repo.branchheads(branch)
5295 bheads = repo.branchheads(branch)
5295 # i18n: column positioning for "hg summary"
5296 # i18n: column positioning for "hg summary"
5296 m = _('branch: %s\n') % branch
5297 m = _('branch: %s\n') % branch
5297 if branch != 'default':
5298 if branch != 'default':
5298 ui.write(m, label='log.branch')
5299 ui.write(m, label='log.branch')
5299 else:
5300 else:
5300 ui.status(m, label='log.branch')
5301 ui.status(m, label='log.branch')
5301
5302
5302 if marks:
5303 if marks:
5303 active = repo._activebookmark
5304 active = repo._activebookmark
5304 # i18n: column positioning for "hg summary"
5305 # i18n: column positioning for "hg summary"
5305 ui.write(_('bookmarks:'), label='log.bookmark')
5306 ui.write(_('bookmarks:'), label='log.bookmark')
5306 if active is not None:
5307 if active is not None:
5307 if active in marks:
5308 if active in marks:
5308 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5309 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5309 marks.remove(active)
5310 marks.remove(active)
5310 else:
5311 else:
5311 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5312 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5312 for m in marks:
5313 for m in marks:
5313 ui.write(' ' + m, label='log.bookmark')
5314 ui.write(' ' + m, label='log.bookmark')
5314 ui.write('\n', label='log.bookmark')
5315 ui.write('\n', label='log.bookmark')
5315
5316
5316 status = repo.status(unknown=True)
5317 status = repo.status(unknown=True)
5317
5318
5318 c = repo.dirstate.copies()
5319 c = repo.dirstate.copies()
5319 copied, renamed = [], []
5320 copied, renamed = [], []
5320 for d, s in c.iteritems():
5321 for d, s in c.iteritems():
5321 if s in status.removed:
5322 if s in status.removed:
5322 status.removed.remove(s)
5323 status.removed.remove(s)
5323 renamed.append(d)
5324 renamed.append(d)
5324 else:
5325 else:
5325 copied.append(d)
5326 copied.append(d)
5326 if d in status.added:
5327 if d in status.added:
5327 status.added.remove(d)
5328 status.added.remove(d)
5328
5329
5329 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5330 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5330
5331
5331 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5332 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5332 (ui.label(_('%d added'), 'status.added'), status.added),
5333 (ui.label(_('%d added'), 'status.added'), status.added),
5333 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5334 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5334 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5335 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5335 (ui.label(_('%d copied'), 'status.copied'), copied),
5336 (ui.label(_('%d copied'), 'status.copied'), copied),
5336 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5337 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5337 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5338 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5338 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5339 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5339 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5340 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5340 t = []
5341 t = []
5341 for l, s in labels:
5342 for l, s in labels:
5342 if s:
5343 if s:
5343 t.append(l % len(s))
5344 t.append(l % len(s))
5344
5345
5345 t = ', '.join(t)
5346 t = ', '.join(t)
5346 cleanworkdir = False
5347 cleanworkdir = False
5347
5348
5348 if repo.vfs.exists('graftstate'):
5349 if repo.vfs.exists('graftstate'):
5349 t += _(' (graft in progress)')
5350 t += _(' (graft in progress)')
5350 if repo.vfs.exists('updatestate'):
5351 if repo.vfs.exists('updatestate'):
5351 t += _(' (interrupted update)')
5352 t += _(' (interrupted update)')
5352 elif len(parents) > 1:
5353 elif len(parents) > 1:
5353 t += _(' (merge)')
5354 t += _(' (merge)')
5354 elif branch != parents[0].branch():
5355 elif branch != parents[0].branch():
5355 t += _(' (new branch)')
5356 t += _(' (new branch)')
5356 elif (parents[0].closesbranch() and
5357 elif (parents[0].closesbranch() and
5357 pnode in repo.branchheads(branch, closed=True)):
5358 pnode in repo.branchheads(branch, closed=True)):
5358 t += _(' (head closed)')
5359 t += _(' (head closed)')
5359 elif not (status.modified or status.added or status.removed or renamed or
5360 elif not (status.modified or status.added or status.removed or renamed or
5360 copied or subs):
5361 copied or subs):
5361 t += _(' (clean)')
5362 t += _(' (clean)')
5362 cleanworkdir = True
5363 cleanworkdir = True
5363 elif pnode not in bheads:
5364 elif pnode not in bheads:
5364 t += _(' (new branch head)')
5365 t += _(' (new branch head)')
5365
5366
5366 if parents:
5367 if parents:
5367 pendingphase = max(p.phase() for p in parents)
5368 pendingphase = max(p.phase() for p in parents)
5368 else:
5369 else:
5369 pendingphase = phases.public
5370 pendingphase = phases.public
5370
5371
5371 if pendingphase > phases.newcommitphase(ui):
5372 if pendingphase > phases.newcommitphase(ui):
5372 t += ' (%s)' % phases.phasenames[pendingphase]
5373 t += ' (%s)' % phases.phasenames[pendingphase]
5373
5374
5374 if cleanworkdir:
5375 if cleanworkdir:
5375 # i18n: column positioning for "hg summary"
5376 # i18n: column positioning for "hg summary"
5376 ui.status(_('commit: %s\n') % t.strip())
5377 ui.status(_('commit: %s\n') % t.strip())
5377 else:
5378 else:
5378 # i18n: column positioning for "hg summary"
5379 # i18n: column positioning for "hg summary"
5379 ui.write(_('commit: %s\n') % t.strip())
5380 ui.write(_('commit: %s\n') % t.strip())
5380
5381
5381 # all ancestors of branch heads - all ancestors of parent = new csets
5382 # all ancestors of branch heads - all ancestors of parent = new csets
5382 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5383 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5383 bheads))
5384 bheads))
5384
5385
5385 if new == 0:
5386 if new == 0:
5386 # i18n: column positioning for "hg summary"
5387 # i18n: column positioning for "hg summary"
5387 ui.status(_('update: (current)\n'))
5388 ui.status(_('update: (current)\n'))
5388 elif pnode not in bheads:
5389 elif pnode not in bheads:
5389 # i18n: column positioning for "hg summary"
5390 # i18n: column positioning for "hg summary"
5390 ui.write(_('update: %d new changesets (update)\n') % new)
5391 ui.write(_('update: %d new changesets (update)\n') % new)
5391 else:
5392 else:
5392 # i18n: column positioning for "hg summary"
5393 # i18n: column positioning for "hg summary"
5393 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5394 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5394 (new, len(bheads)))
5395 (new, len(bheads)))
5395
5396
5396 t = []
5397 t = []
5397 draft = len(repo.revs('draft()'))
5398 draft = len(repo.revs('draft()'))
5398 if draft:
5399 if draft:
5399 t.append(_('%d draft') % draft)
5400 t.append(_('%d draft') % draft)
5400 secret = len(repo.revs('secret()'))
5401 secret = len(repo.revs('secret()'))
5401 if secret:
5402 if secret:
5402 t.append(_('%d secret') % secret)
5403 t.append(_('%d secret') % secret)
5403
5404
5404 if draft or secret:
5405 if draft or secret:
5405 ui.status(_('phases: %s\n') % ', '.join(t))
5406 ui.status(_('phases: %s\n') % ', '.join(t))
5406
5407
5407 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5408 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5408 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5409 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5409 numtrouble = len(repo.revs(trouble + "()"))
5410 numtrouble = len(repo.revs(trouble + "()"))
5410 # We write all the possibilities to ease translation
5411 # We write all the possibilities to ease translation
5411 troublemsg = {
5412 troublemsg = {
5412 "orphan": _("orphan: %d changesets"),
5413 "orphan": _("orphan: %d changesets"),
5413 "contentdivergent": _("content-divergent: %d changesets"),
5414 "contentdivergent": _("content-divergent: %d changesets"),
5414 "phasedivergent": _("phase-divergent: %d changesets"),
5415 "phasedivergent": _("phase-divergent: %d changesets"),
5415 }
5416 }
5416 if numtrouble > 0:
5417 if numtrouble > 0:
5417 ui.status(troublemsg[trouble] % numtrouble + "\n")
5418 ui.status(troublemsg[trouble] % numtrouble + "\n")
5418
5419
5419 cmdutil.summaryhooks(ui, repo)
5420 cmdutil.summaryhooks(ui, repo)
5420
5421
5421 if opts.get('remote'):
5422 if opts.get('remote'):
5422 needsincoming, needsoutgoing = True, True
5423 needsincoming, needsoutgoing = True, True
5423 else:
5424 else:
5424 needsincoming, needsoutgoing = False, False
5425 needsincoming, needsoutgoing = False, False
5425 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5426 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5426 if i:
5427 if i:
5427 needsincoming = True
5428 needsincoming = True
5428 if o:
5429 if o:
5429 needsoutgoing = True
5430 needsoutgoing = True
5430 if not needsincoming and not needsoutgoing:
5431 if not needsincoming and not needsoutgoing:
5431 return
5432 return
5432
5433
5433 def getincoming():
5434 def getincoming():
5434 source, branches = hg.parseurl(ui.expandpath('default'))
5435 source, branches = hg.parseurl(ui.expandpath('default'))
5435 sbranch = branches[0]
5436 sbranch = branches[0]
5436 try:
5437 try:
5437 other = hg.peer(repo, {}, source)
5438 other = hg.peer(repo, {}, source)
5438 except error.RepoError:
5439 except error.RepoError:
5439 if opts.get('remote'):
5440 if opts.get('remote'):
5440 raise
5441 raise
5441 return source, sbranch, None, None, None
5442 return source, sbranch, None, None, None
5442 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5443 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5443 if revs:
5444 if revs:
5444 revs = [other.lookup(rev) for rev in revs]
5445 revs = [other.lookup(rev) for rev in revs]
5445 ui.debug('comparing with %s\n' % util.hidepassword(source))
5446 ui.debug('comparing with %s\n' % util.hidepassword(source))
5446 repo.ui.pushbuffer()
5447 repo.ui.pushbuffer()
5447 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5448 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5448 repo.ui.popbuffer()
5449 repo.ui.popbuffer()
5449 return source, sbranch, other, commoninc, commoninc[1]
5450 return source, sbranch, other, commoninc, commoninc[1]
5450
5451
5451 if needsincoming:
5452 if needsincoming:
5452 source, sbranch, sother, commoninc, incoming = getincoming()
5453 source, sbranch, sother, commoninc, incoming = getincoming()
5453 else:
5454 else:
5454 source = sbranch = sother = commoninc = incoming = None
5455 source = sbranch = sother = commoninc = incoming = None
5455
5456
5456 def getoutgoing():
5457 def getoutgoing():
5457 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5458 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5458 dbranch = branches[0]
5459 dbranch = branches[0]
5459 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5460 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5460 if source != dest:
5461 if source != dest:
5461 try:
5462 try:
5462 dother = hg.peer(repo, {}, dest)
5463 dother = hg.peer(repo, {}, dest)
5463 except error.RepoError:
5464 except error.RepoError:
5464 if opts.get('remote'):
5465 if opts.get('remote'):
5465 raise
5466 raise
5466 return dest, dbranch, None, None
5467 return dest, dbranch, None, None
5467 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5468 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5468 elif sother is None:
5469 elif sother is None:
5469 # there is no explicit destination peer, but source one is invalid
5470 # there is no explicit destination peer, but source one is invalid
5470 return dest, dbranch, None, None
5471 return dest, dbranch, None, None
5471 else:
5472 else:
5472 dother = sother
5473 dother = sother
5473 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5474 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5474 common = None
5475 common = None
5475 else:
5476 else:
5476 common = commoninc
5477 common = commoninc
5477 if revs:
5478 if revs:
5478 revs = [repo.lookup(rev) for rev in revs]
5479 revs = [repo.lookup(rev) for rev in revs]
5479 repo.ui.pushbuffer()
5480 repo.ui.pushbuffer()
5480 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5481 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5481 commoninc=common)
5482 commoninc=common)
5482 repo.ui.popbuffer()
5483 repo.ui.popbuffer()
5483 return dest, dbranch, dother, outgoing
5484 return dest, dbranch, dother, outgoing
5484
5485
5485 if needsoutgoing:
5486 if needsoutgoing:
5486 dest, dbranch, dother, outgoing = getoutgoing()
5487 dest, dbranch, dother, outgoing = getoutgoing()
5487 else:
5488 else:
5488 dest = dbranch = dother = outgoing = None
5489 dest = dbranch = dother = outgoing = None
5489
5490
5490 if opts.get('remote'):
5491 if opts.get('remote'):
5491 t = []
5492 t = []
5492 if incoming:
5493 if incoming:
5493 t.append(_('1 or more incoming'))
5494 t.append(_('1 or more incoming'))
5494 o = outgoing.missing
5495 o = outgoing.missing
5495 if o:
5496 if o:
5496 t.append(_('%d outgoing') % len(o))
5497 t.append(_('%d outgoing') % len(o))
5497 other = dother or sother
5498 other = dother or sother
5498 if 'bookmarks' in other.listkeys('namespaces'):
5499 if 'bookmarks' in other.listkeys('namespaces'):
5499 counts = bookmarks.summary(repo, other)
5500 counts = bookmarks.summary(repo, other)
5500 if counts[0] > 0:
5501 if counts[0] > 0:
5501 t.append(_('%d incoming bookmarks') % counts[0])
5502 t.append(_('%d incoming bookmarks') % counts[0])
5502 if counts[1] > 0:
5503 if counts[1] > 0:
5503 t.append(_('%d outgoing bookmarks') % counts[1])
5504 t.append(_('%d outgoing bookmarks') % counts[1])
5504
5505
5505 if t:
5506 if t:
5506 # i18n: column positioning for "hg summary"
5507 # i18n: column positioning for "hg summary"
5507 ui.write(_('remote: %s\n') % (', '.join(t)))
5508 ui.write(_('remote: %s\n') % (', '.join(t)))
5508 else:
5509 else:
5509 # i18n: column positioning for "hg summary"
5510 # i18n: column positioning for "hg summary"
5510 ui.status(_('remote: (synced)\n'))
5511 ui.status(_('remote: (synced)\n'))
5511
5512
5512 cmdutil.summaryremotehooks(ui, repo, opts,
5513 cmdutil.summaryremotehooks(ui, repo, opts,
5513 ((source, sbranch, sother, commoninc),
5514 ((source, sbranch, sother, commoninc),
5514 (dest, dbranch, dother, outgoing)))
5515 (dest, dbranch, dother, outgoing)))
5515
5516
5516 @command('tag',
5517 @command('tag',
5517 [('f', 'force', None, _('force tag')),
5518 [('f', 'force', None, _('force tag')),
5518 ('l', 'local', None, _('make the tag local')),
5519 ('l', 'local', None, _('make the tag local')),
5519 ('r', 'rev', '', _('revision to tag'), _('REV')),
5520 ('r', 'rev', '', _('revision to tag'), _('REV')),
5520 ('', 'remove', None, _('remove a tag')),
5521 ('', 'remove', None, _('remove a tag')),
5521 # -l/--local is already there, commitopts cannot be used
5522 # -l/--local is already there, commitopts cannot be used
5522 ('e', 'edit', None, _('invoke editor on commit messages')),
5523 ('e', 'edit', None, _('invoke editor on commit messages')),
5523 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5524 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5524 ] + commitopts2,
5525 ] + commitopts2,
5525 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5526 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5526 def tag(ui, repo, name1, *names, **opts):
5527 def tag(ui, repo, name1, *names, **opts):
5527 """add one or more tags for the current or given revision
5528 """add one or more tags for the current or given revision
5528
5529
5529 Name a particular revision using <name>.
5530 Name a particular revision using <name>.
5530
5531
5531 Tags are used to name particular revisions of the repository and are
5532 Tags are used to name particular revisions of the repository and are
5532 very useful to compare different revisions, to go back to significant
5533 very useful to compare different revisions, to go back to significant
5533 earlier versions or to mark branch points as releases, etc. Changing
5534 earlier versions or to mark branch points as releases, etc. Changing
5534 an existing tag is normally disallowed; use -f/--force to override.
5535 an existing tag is normally disallowed; use -f/--force to override.
5535
5536
5536 If no revision is given, the parent of the working directory is
5537 If no revision is given, the parent of the working directory is
5537 used.
5538 used.
5538
5539
5539 To facilitate version control, distribution, and merging of tags,
5540 To facilitate version control, distribution, and merging of tags,
5540 they are stored as a file named ".hgtags" which is managed similarly
5541 they are stored as a file named ".hgtags" which is managed similarly
5541 to other project files and can be hand-edited if necessary. This
5542 to other project files and can be hand-edited if necessary. This
5542 also means that tagging creates a new commit. The file
5543 also means that tagging creates a new commit. The file
5543 ".hg/localtags" is used for local tags (not shared among
5544 ".hg/localtags" is used for local tags (not shared among
5544 repositories).
5545 repositories).
5545
5546
5546 Tag commits are usually made at the head of a branch. If the parent
5547 Tag commits are usually made at the head of a branch. If the parent
5547 of the working directory is not a branch head, :hg:`tag` aborts; use
5548 of the working directory is not a branch head, :hg:`tag` aborts; use
5548 -f/--force to force the tag commit to be based on a non-head
5549 -f/--force to force the tag commit to be based on a non-head
5549 changeset.
5550 changeset.
5550
5551
5551 See :hg:`help dates` for a list of formats valid for -d/--date.
5552 See :hg:`help dates` for a list of formats valid for -d/--date.
5552
5553
5553 Since tag names have priority over branch names during revision
5554 Since tag names have priority over branch names during revision
5554 lookup, using an existing branch name as a tag name is discouraged.
5555 lookup, using an existing branch name as a tag name is discouraged.
5555
5556
5556 Returns 0 on success.
5557 Returns 0 on success.
5557 """
5558 """
5558 opts = pycompat.byteskwargs(opts)
5559 opts = pycompat.byteskwargs(opts)
5559 with repo.wlock(), repo.lock():
5560 with repo.wlock(), repo.lock():
5560 rev_ = "."
5561 rev_ = "."
5561 names = [t.strip() for t in (name1,) + names]
5562 names = [t.strip() for t in (name1,) + names]
5562 if len(names) != len(set(names)):
5563 if len(names) != len(set(names)):
5563 raise error.Abort(_('tag names must be unique'))
5564 raise error.Abort(_('tag names must be unique'))
5564 for n in names:
5565 for n in names:
5565 scmutil.checknewlabel(repo, n, 'tag')
5566 scmutil.checknewlabel(repo, n, 'tag')
5566 if not n:
5567 if not n:
5567 raise error.Abort(_('tag names cannot consist entirely of '
5568 raise error.Abort(_('tag names cannot consist entirely of '
5568 'whitespace'))
5569 'whitespace'))
5569 if opts.get('rev') and opts.get('remove'):
5570 if opts.get('rev') and opts.get('remove'):
5570 raise error.Abort(_("--rev and --remove are incompatible"))
5571 raise error.Abort(_("--rev and --remove are incompatible"))
5571 if opts.get('rev'):
5572 if opts.get('rev'):
5572 rev_ = opts['rev']
5573 rev_ = opts['rev']
5573 message = opts.get('message')
5574 message = opts.get('message')
5574 if opts.get('remove'):
5575 if opts.get('remove'):
5575 if opts.get('local'):
5576 if opts.get('local'):
5576 expectedtype = 'local'
5577 expectedtype = 'local'
5577 else:
5578 else:
5578 expectedtype = 'global'
5579 expectedtype = 'global'
5579
5580
5580 for n in names:
5581 for n in names:
5581 if not repo.tagtype(n):
5582 if not repo.tagtype(n):
5582 raise error.Abort(_("tag '%s' does not exist") % n)
5583 raise error.Abort(_("tag '%s' does not exist") % n)
5583 if repo.tagtype(n) != expectedtype:
5584 if repo.tagtype(n) != expectedtype:
5584 if expectedtype == 'global':
5585 if expectedtype == 'global':
5585 raise error.Abort(_("tag '%s' is not a global tag") % n)
5586 raise error.Abort(_("tag '%s' is not a global tag") % n)
5586 else:
5587 else:
5587 raise error.Abort(_("tag '%s' is not a local tag") % n)
5588 raise error.Abort(_("tag '%s' is not a local tag") % n)
5588 rev_ = 'null'
5589 rev_ = 'null'
5589 if not message:
5590 if not message:
5590 # we don't translate commit messages
5591 # we don't translate commit messages
5591 message = 'Removed tag %s' % ', '.join(names)
5592 message = 'Removed tag %s' % ', '.join(names)
5592 elif not opts.get('force'):
5593 elif not opts.get('force'):
5593 for n in names:
5594 for n in names:
5594 if n in repo.tags():
5595 if n in repo.tags():
5595 raise error.Abort(_("tag '%s' already exists "
5596 raise error.Abort(_("tag '%s' already exists "
5596 "(use -f to force)") % n)
5597 "(use -f to force)") % n)
5597 if not opts.get('local'):
5598 if not opts.get('local'):
5598 p1, p2 = repo.dirstate.parents()
5599 p1, p2 = repo.dirstate.parents()
5599 if p2 != nullid:
5600 if p2 != nullid:
5600 raise error.Abort(_('uncommitted merge'))
5601 raise error.Abort(_('uncommitted merge'))
5601 bheads = repo.branchheads()
5602 bheads = repo.branchheads()
5602 if not opts.get('force') and bheads and p1 not in bheads:
5603 if not opts.get('force') and bheads and p1 not in bheads:
5603 raise error.Abort(_('working directory is not at a branch head '
5604 raise error.Abort(_('working directory is not at a branch head '
5604 '(use -f to force)'))
5605 '(use -f to force)'))
5605 node = scmutil.revsingle(repo, rev_).node()
5606 node = scmutil.revsingle(repo, rev_).node()
5606
5607
5607 if not message:
5608 if not message:
5608 # we don't translate commit messages
5609 # we don't translate commit messages
5609 message = ('Added tag %s for changeset %s' %
5610 message = ('Added tag %s for changeset %s' %
5610 (', '.join(names), short(node)))
5611 (', '.join(names), short(node)))
5611
5612
5612 date = opts.get('date')
5613 date = opts.get('date')
5613 if date:
5614 if date:
5614 date = dateutil.parsedate(date)
5615 date = dateutil.parsedate(date)
5615
5616
5616 if opts.get('remove'):
5617 if opts.get('remove'):
5617 editform = 'tag.remove'
5618 editform = 'tag.remove'
5618 else:
5619 else:
5619 editform = 'tag.add'
5620 editform = 'tag.add'
5620 editor = cmdutil.getcommiteditor(editform=editform,
5621 editor = cmdutil.getcommiteditor(editform=editform,
5621 **pycompat.strkwargs(opts))
5622 **pycompat.strkwargs(opts))
5622
5623
5623 # don't allow tagging the null rev
5624 # don't allow tagging the null rev
5624 if (not opts.get('remove') and
5625 if (not opts.get('remove') and
5625 scmutil.revsingle(repo, rev_).rev() == nullrev):
5626 scmutil.revsingle(repo, rev_).rev() == nullrev):
5626 raise error.Abort(_("cannot tag null revision"))
5627 raise error.Abort(_("cannot tag null revision"))
5627
5628
5628 tagsmod.tag(repo, names, node, message, opts.get('local'),
5629 tagsmod.tag(repo, names, node, message, opts.get('local'),
5629 opts.get('user'), date, editor=editor)
5630 opts.get('user'), date, editor=editor)
5630
5631
5631 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5632 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5632 def tags(ui, repo, **opts):
5633 def tags(ui, repo, **opts):
5633 """list repository tags
5634 """list repository tags
5634
5635
5635 This lists both regular and local tags. When the -v/--verbose
5636 This lists both regular and local tags. When the -v/--verbose
5636 switch is used, a third column "local" is printed for local tags.
5637 switch is used, a third column "local" is printed for local tags.
5637 When the -q/--quiet switch is used, only the tag name is printed.
5638 When the -q/--quiet switch is used, only the tag name is printed.
5638
5639
5639 Returns 0 on success.
5640 Returns 0 on success.
5640 """
5641 """
5641
5642
5642 opts = pycompat.byteskwargs(opts)
5643 opts = pycompat.byteskwargs(opts)
5643 ui.pager('tags')
5644 ui.pager('tags')
5644 fm = ui.formatter('tags', opts)
5645 fm = ui.formatter('tags', opts)
5645 hexfunc = fm.hexfunc
5646 hexfunc = fm.hexfunc
5646 tagtype = ""
5647 tagtype = ""
5647
5648
5648 for t, n in reversed(repo.tagslist()):
5649 for t, n in reversed(repo.tagslist()):
5649 hn = hexfunc(n)
5650 hn = hexfunc(n)
5650 label = 'tags.normal'
5651 label = 'tags.normal'
5651 tagtype = ''
5652 tagtype = ''
5652 if repo.tagtype(t) == 'local':
5653 if repo.tagtype(t) == 'local':
5653 label = 'tags.local'
5654 label = 'tags.local'
5654 tagtype = 'local'
5655 tagtype = 'local'
5655
5656
5656 fm.startitem()
5657 fm.startitem()
5657 fm.context(repo=repo)
5658 fm.context(repo=repo)
5658 fm.write('tag', '%s', t, label=label)
5659 fm.write('tag', '%s', t, label=label)
5659 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5660 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5660 fm.condwrite(not ui.quiet, 'rev node', fmt,
5661 fm.condwrite(not ui.quiet, 'rev node', fmt,
5661 repo.changelog.rev(n), hn, label=label)
5662 repo.changelog.rev(n), hn, label=label)
5662 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5663 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5663 tagtype, label=label)
5664 tagtype, label=label)
5664 fm.plain('\n')
5665 fm.plain('\n')
5665 fm.end()
5666 fm.end()
5666
5667
5667 @command('tip',
5668 @command('tip',
5668 [('p', 'patch', None, _('show patch')),
5669 [('p', 'patch', None, _('show patch')),
5669 ('g', 'git', None, _('use git extended diff format')),
5670 ('g', 'git', None, _('use git extended diff format')),
5670 ] + templateopts,
5671 ] + templateopts,
5671 _('[-p] [-g]'))
5672 _('[-p] [-g]'))
5672 def tip(ui, repo, **opts):
5673 def tip(ui, repo, **opts):
5673 """show the tip revision (DEPRECATED)
5674 """show the tip revision (DEPRECATED)
5674
5675
5675 The tip revision (usually just called the tip) is the changeset
5676 The tip revision (usually just called the tip) is the changeset
5676 most recently added to the repository (and therefore the most
5677 most recently added to the repository (and therefore the most
5677 recently changed head).
5678 recently changed head).
5678
5679
5679 If you have just made a commit, that commit will be the tip. If
5680 If you have just made a commit, that commit will be the tip. If
5680 you have just pulled changes from another repository, the tip of
5681 you have just pulled changes from another repository, the tip of
5681 that repository becomes the current tip. The "tip" tag is special
5682 that repository becomes the current tip. The "tip" tag is special
5682 and cannot be renamed or assigned to a different changeset.
5683 and cannot be renamed or assigned to a different changeset.
5683
5684
5684 This command is deprecated, please use :hg:`heads` instead.
5685 This command is deprecated, please use :hg:`heads` instead.
5685
5686
5686 Returns 0 on success.
5687 Returns 0 on success.
5687 """
5688 """
5688 opts = pycompat.byteskwargs(opts)
5689 opts = pycompat.byteskwargs(opts)
5689 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5690 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5690 displayer.show(repo['tip'])
5691 displayer.show(repo['tip'])
5691 displayer.close()
5692 displayer.close()
5692
5693
5693 @command('unbundle',
5694 @command('unbundle',
5694 [('u', 'update', None,
5695 [('u', 'update', None,
5695 _('update to new branch head if changesets were unbundled'))],
5696 _('update to new branch head if changesets were unbundled'))],
5696 _('[-u] FILE...'))
5697 _('[-u] FILE...'))
5697 def unbundle(ui, repo, fname1, *fnames, **opts):
5698 def unbundle(ui, repo, fname1, *fnames, **opts):
5698 """apply one or more bundle files
5699 """apply one or more bundle files
5699
5700
5700 Apply one or more bundle files generated by :hg:`bundle`.
5701 Apply one or more bundle files generated by :hg:`bundle`.
5701
5702
5702 Returns 0 on success, 1 if an update has unresolved files.
5703 Returns 0 on success, 1 if an update has unresolved files.
5703 """
5704 """
5704 fnames = (fname1,) + fnames
5705 fnames = (fname1,) + fnames
5705
5706
5706 with repo.lock():
5707 with repo.lock():
5707 for fname in fnames:
5708 for fname in fnames:
5708 f = hg.openpath(ui, fname)
5709 f = hg.openpath(ui, fname)
5709 gen = exchange.readbundle(ui, f, fname)
5710 gen = exchange.readbundle(ui, f, fname)
5710 if isinstance(gen, streamclone.streamcloneapplier):
5711 if isinstance(gen, streamclone.streamcloneapplier):
5711 raise error.Abort(
5712 raise error.Abort(
5712 _('packed bundles cannot be applied with '
5713 _('packed bundles cannot be applied with '
5713 '"hg unbundle"'),
5714 '"hg unbundle"'),
5714 hint=_('use "hg debugapplystreamclonebundle"'))
5715 hint=_('use "hg debugapplystreamclonebundle"'))
5715 url = 'bundle:' + fname
5716 url = 'bundle:' + fname
5716 try:
5717 try:
5717 txnname = 'unbundle'
5718 txnname = 'unbundle'
5718 if not isinstance(gen, bundle2.unbundle20):
5719 if not isinstance(gen, bundle2.unbundle20):
5719 txnname = 'unbundle\n%s' % util.hidepassword(url)
5720 txnname = 'unbundle\n%s' % util.hidepassword(url)
5720 with repo.transaction(txnname) as tr:
5721 with repo.transaction(txnname) as tr:
5721 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5722 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5722 url=url)
5723 url=url)
5723 except error.BundleUnknownFeatureError as exc:
5724 except error.BundleUnknownFeatureError as exc:
5724 raise error.Abort(
5725 raise error.Abort(
5725 _('%s: unknown bundle feature, %s') % (fname, exc),
5726 _('%s: unknown bundle feature, %s') % (fname, exc),
5726 hint=_("see https://mercurial-scm.org/"
5727 hint=_("see https://mercurial-scm.org/"
5727 "wiki/BundleFeature for more "
5728 "wiki/BundleFeature for more "
5728 "information"))
5729 "information"))
5729 modheads = bundle2.combinechangegroupresults(op)
5730 modheads = bundle2.combinechangegroupresults(op)
5730
5731
5731 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5732 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5732
5733
5733 @command('^update|up|checkout|co',
5734 @command('^update|up|checkout|co',
5734 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5735 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5735 ('c', 'check', None, _('require clean working directory')),
5736 ('c', 'check', None, _('require clean working directory')),
5736 ('m', 'merge', None, _('merge uncommitted changes')),
5737 ('m', 'merge', None, _('merge uncommitted changes')),
5737 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5738 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5738 ('r', 'rev', '', _('revision'), _('REV'))
5739 ('r', 'rev', '', _('revision'), _('REV'))
5739 ] + mergetoolopts,
5740 ] + mergetoolopts,
5740 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5741 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5741 def update(ui, repo, node=None, **opts):
5742 def update(ui, repo, node=None, **opts):
5742 """update working directory (or switch revisions)
5743 """update working directory (or switch revisions)
5743
5744
5744 Update the repository's working directory to the specified
5745 Update the repository's working directory to the specified
5745 changeset. If no changeset is specified, update to the tip of the
5746 changeset. If no changeset is specified, update to the tip of the
5746 current named branch and move the active bookmark (see :hg:`help
5747 current named branch and move the active bookmark (see :hg:`help
5747 bookmarks`).
5748 bookmarks`).
5748
5749
5749 Update sets the working directory's parent revision to the specified
5750 Update sets the working directory's parent revision to the specified
5750 changeset (see :hg:`help parents`).
5751 changeset (see :hg:`help parents`).
5751
5752
5752 If the changeset is not a descendant or ancestor of the working
5753 If the changeset is not a descendant or ancestor of the working
5753 directory's parent and there are uncommitted changes, the update is
5754 directory's parent and there are uncommitted changes, the update is
5754 aborted. With the -c/--check option, the working directory is checked
5755 aborted. With the -c/--check option, the working directory is checked
5755 for uncommitted changes; if none are found, the working directory is
5756 for uncommitted changes; if none are found, the working directory is
5756 updated to the specified changeset.
5757 updated to the specified changeset.
5757
5758
5758 .. container:: verbose
5759 .. container:: verbose
5759
5760
5760 The -C/--clean, -c/--check, and -m/--merge options control what
5761 The -C/--clean, -c/--check, and -m/--merge options control what
5761 happens if the working directory contains uncommitted changes.
5762 happens if the working directory contains uncommitted changes.
5762 At most of one of them can be specified.
5763 At most of one of them can be specified.
5763
5764
5764 1. If no option is specified, and if
5765 1. If no option is specified, and if
5765 the requested changeset is an ancestor or descendant of
5766 the requested changeset is an ancestor or descendant of
5766 the working directory's parent, the uncommitted changes
5767 the working directory's parent, the uncommitted changes
5767 are merged into the requested changeset and the merged
5768 are merged into the requested changeset and the merged
5768 result is left uncommitted. If the requested changeset is
5769 result is left uncommitted. If the requested changeset is
5769 not an ancestor or descendant (that is, it is on another
5770 not an ancestor or descendant (that is, it is on another
5770 branch), the update is aborted and the uncommitted changes
5771 branch), the update is aborted and the uncommitted changes
5771 are preserved.
5772 are preserved.
5772
5773
5773 2. With the -m/--merge option, the update is allowed even if the
5774 2. With the -m/--merge option, the update is allowed even if the
5774 requested changeset is not an ancestor or descendant of
5775 requested changeset is not an ancestor or descendant of
5775 the working directory's parent.
5776 the working directory's parent.
5776
5777
5777 3. With the -c/--check option, the update is aborted and the
5778 3. With the -c/--check option, the update is aborted and the
5778 uncommitted changes are preserved.
5779 uncommitted changes are preserved.
5779
5780
5780 4. With the -C/--clean option, uncommitted changes are discarded and
5781 4. With the -C/--clean option, uncommitted changes are discarded and
5781 the working directory is updated to the requested changeset.
5782 the working directory is updated to the requested changeset.
5782
5783
5783 To cancel an uncommitted merge (and lose your changes), use
5784 To cancel an uncommitted merge (and lose your changes), use
5784 :hg:`merge --abort`.
5785 :hg:`merge --abort`.
5785
5786
5786 Use null as the changeset to remove the working directory (like
5787 Use null as the changeset to remove the working directory (like
5787 :hg:`clone -U`).
5788 :hg:`clone -U`).
5788
5789
5789 If you want to revert just one file to an older revision, use
5790 If you want to revert just one file to an older revision, use
5790 :hg:`revert [-r REV] NAME`.
5791 :hg:`revert [-r REV] NAME`.
5791
5792
5792 See :hg:`help dates` for a list of formats valid for -d/--date.
5793 See :hg:`help dates` for a list of formats valid for -d/--date.
5793
5794
5794 Returns 0 on success, 1 if there are unresolved files.
5795 Returns 0 on success, 1 if there are unresolved files.
5795 """
5796 """
5796 rev = opts.get(r'rev')
5797 rev = opts.get(r'rev')
5797 date = opts.get(r'date')
5798 date = opts.get(r'date')
5798 clean = opts.get(r'clean')
5799 clean = opts.get(r'clean')
5799 check = opts.get(r'check')
5800 check = opts.get(r'check')
5800 merge = opts.get(r'merge')
5801 merge = opts.get(r'merge')
5801 if rev and node:
5802 if rev and node:
5802 raise error.Abort(_("please specify just one revision"))
5803 raise error.Abort(_("please specify just one revision"))
5803
5804
5804 if ui.configbool('commands', 'update.requiredest'):
5805 if ui.configbool('commands', 'update.requiredest'):
5805 if not node and not rev and not date:
5806 if not node and not rev and not date:
5806 raise error.Abort(_('you must specify a destination'),
5807 raise error.Abort(_('you must specify a destination'),
5807 hint=_('for example: hg update ".::"'))
5808 hint=_('for example: hg update ".::"'))
5808
5809
5809 if rev is None or rev == '':
5810 if rev is None or rev == '':
5810 rev = node
5811 rev = node
5811
5812
5812 if date and rev is not None:
5813 if date and rev is not None:
5813 raise error.Abort(_("you can't specify a revision and a date"))
5814 raise error.Abort(_("you can't specify a revision and a date"))
5814
5815
5815 if len([x for x in (clean, check, merge) if x]) > 1:
5816 if len([x for x in (clean, check, merge) if x]) > 1:
5816 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5817 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5817 "or -m/--merge"))
5818 "or -m/--merge"))
5818
5819
5819 updatecheck = None
5820 updatecheck = None
5820 if check:
5821 if check:
5821 updatecheck = 'abort'
5822 updatecheck = 'abort'
5822 elif merge:
5823 elif merge:
5823 updatecheck = 'none'
5824 updatecheck = 'none'
5824
5825
5825 with repo.wlock():
5826 with repo.wlock():
5826 cmdutil.clearunfinished(repo)
5827 cmdutil.clearunfinished(repo)
5827
5828
5828 if date:
5829 if date:
5829 rev = cmdutil.finddate(ui, repo, date)
5830 rev = cmdutil.finddate(ui, repo, date)
5830
5831
5831 # if we defined a bookmark, we have to remember the original name
5832 # if we defined a bookmark, we have to remember the original name
5832 brev = rev
5833 brev = rev
5833 if rev:
5834 if rev:
5834 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5835 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5835 ctx = scmutil.revsingle(repo, rev, rev)
5836 ctx = scmutil.revsingle(repo, rev, rev)
5836 rev = ctx.rev()
5837 rev = ctx.rev()
5837 hidden = ctx.hidden()
5838 hidden = ctx.hidden()
5838 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5839 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5839 with ui.configoverride(overrides, 'update'):
5840 with ui.configoverride(overrides, 'update'):
5840 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5841 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5841 updatecheck=updatecheck)
5842 updatecheck=updatecheck)
5842 if hidden:
5843 if hidden:
5843 ctxstr = ctx.hex()[:12]
5844 ctxstr = ctx.hex()[:12]
5844 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5845 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5845
5846
5846 if ctx.obsolete():
5847 if ctx.obsolete():
5847 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5848 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5848 ui.warn("(%s)\n" % obsfatemsg)
5849 ui.warn("(%s)\n" % obsfatemsg)
5849 return ret
5850 return ret
5850
5851
5851 @command('verify', [])
5852 @command('verify', [])
5852 def verify(ui, repo):
5853 def verify(ui, repo):
5853 """verify the integrity of the repository
5854 """verify the integrity of the repository
5854
5855
5855 Verify the integrity of the current repository.
5856 Verify the integrity of the current repository.
5856
5857
5857 This will perform an extensive check of the repository's
5858 This will perform an extensive check of the repository's
5858 integrity, validating the hashes and checksums of each entry in
5859 integrity, validating the hashes and checksums of each entry in
5859 the changelog, manifest, and tracked files, as well as the
5860 the changelog, manifest, and tracked files, as well as the
5860 integrity of their crosslinks and indices.
5861 integrity of their crosslinks and indices.
5861
5862
5862 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5863 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5863 for more information about recovery from corruption of the
5864 for more information about recovery from corruption of the
5864 repository.
5865 repository.
5865
5866
5866 Returns 0 on success, 1 if errors are encountered.
5867 Returns 0 on success, 1 if errors are encountered.
5867 """
5868 """
5868 return hg.verify(repo)
5869 return hg.verify(repo)
5869
5870
5870 @command('version', [] + formatteropts, norepo=True,
5871 @command('version', [] + formatteropts, norepo=True,
5871 intents={INTENT_READONLY})
5872 intents={INTENT_READONLY})
5872 def version_(ui, **opts):
5873 def version_(ui, **opts):
5873 """output version and copyright information"""
5874 """output version and copyright information"""
5874 opts = pycompat.byteskwargs(opts)
5875 opts = pycompat.byteskwargs(opts)
5875 if ui.verbose:
5876 if ui.verbose:
5876 ui.pager('version')
5877 ui.pager('version')
5877 fm = ui.formatter("version", opts)
5878 fm = ui.formatter("version", opts)
5878 fm.startitem()
5879 fm.startitem()
5879 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5880 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5880 util.version())
5881 util.version())
5881 license = _(
5882 license = _(
5882 "(see https://mercurial-scm.org for more information)\n"
5883 "(see https://mercurial-scm.org for more information)\n"
5883 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5884 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5884 "This is free software; see the source for copying conditions. "
5885 "This is free software; see the source for copying conditions. "
5885 "There is NO\nwarranty; "
5886 "There is NO\nwarranty; "
5886 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5887 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5887 )
5888 )
5888 if not ui.quiet:
5889 if not ui.quiet:
5889 fm.plain(license)
5890 fm.plain(license)
5890
5891
5891 if ui.verbose:
5892 if ui.verbose:
5892 fm.plain(_("\nEnabled extensions:\n\n"))
5893 fm.plain(_("\nEnabled extensions:\n\n"))
5893 # format names and versions into columns
5894 # format names and versions into columns
5894 names = []
5895 names = []
5895 vers = []
5896 vers = []
5896 isinternals = []
5897 isinternals = []
5897 for name, module in extensions.extensions():
5898 for name, module in extensions.extensions():
5898 names.append(name)
5899 names.append(name)
5899 vers.append(extensions.moduleversion(module) or None)
5900 vers.append(extensions.moduleversion(module) or None)
5900 isinternals.append(extensions.ismoduleinternal(module))
5901 isinternals.append(extensions.ismoduleinternal(module))
5901 fn = fm.nested("extensions", tmpl='{name}\n')
5902 fn = fm.nested("extensions", tmpl='{name}\n')
5902 if names:
5903 if names:
5903 namefmt = " %%-%ds " % max(len(n) for n in names)
5904 namefmt = " %%-%ds " % max(len(n) for n in names)
5904 places = [_("external"), _("internal")]
5905 places = [_("external"), _("internal")]
5905 for n, v, p in zip(names, vers, isinternals):
5906 for n, v, p in zip(names, vers, isinternals):
5906 fn.startitem()
5907 fn.startitem()
5907 fn.condwrite(ui.verbose, "name", namefmt, n)
5908 fn.condwrite(ui.verbose, "name", namefmt, n)
5908 if ui.verbose:
5909 if ui.verbose:
5909 fn.plain("%s " % places[p])
5910 fn.plain("%s " % places[p])
5910 fn.data(bundled=p)
5911 fn.data(bundled=p)
5911 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5912 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5912 if ui.verbose:
5913 if ui.verbose:
5913 fn.plain("\n")
5914 fn.plain("\n")
5914 fn.end()
5915 fn.end()
5915 fm.end()
5916 fm.end()
5916
5917
5917 def loadcmdtable(ui, name, cmdtable):
5918 def loadcmdtable(ui, name, cmdtable):
5918 """Load command functions from specified cmdtable
5919 """Load command functions from specified cmdtable
5919 """
5920 """
5920 overrides = [cmd for cmd in cmdtable if cmd in table]
5921 overrides = [cmd for cmd in cmdtable if cmd in table]
5921 if overrides:
5922 if overrides:
5922 ui.warn(_("extension '%s' overrides commands: %s\n")
5923 ui.warn(_("extension '%s' overrides commands: %s\n")
5923 % (name, " ".join(overrides)))
5924 % (name, " ".join(overrides)))
5924 table.update(cmdtable)
5925 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now