##// END OF EJS Templates
help: document about "export" template keywords
Yuya Nishihara -
r40052:1f12a3ad default
parent child Browse files
Show More
@@ -1,5985 +1,5993 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 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 .. container:: verbose
291 .. container:: verbose
292
292
293 Template:
293 Template:
294
294
295 The following keywords are supported in addition to the common template
295 The following keywords are supported in addition to the common template
296 keywords and functions. See also :hg:`help templates`.
296 keywords and functions. See also :hg:`help templates`.
297
297
298 :lines: List of lines with annotation data.
298 :lines: List of lines with annotation data.
299 :path: String. Repository-absolute path of the specified file.
299 :path: String. Repository-absolute path of the specified file.
300
300
301 And each entry of ``{lines}`` provides the following sub-keywords in
301 And each entry of ``{lines}`` provides the following sub-keywords in
302 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
302 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
303
303
304 :line: String. Line content.
304 :line: String. Line content.
305 :lineno: Integer. Line number at that revision.
305 :lineno: Integer. Line number at that revision.
306 :path: String. Repository-absolute path of the file at that revision.
306 :path: String. Repository-absolute path of the file at that revision.
307
307
308 See :hg:`help templates.operators` for the list expansion syntax.
308 See :hg:`help templates.operators` for the list expansion syntax.
309
309
310 Returns 0 on success.
310 Returns 0 on success.
311 """
311 """
312 opts = pycompat.byteskwargs(opts)
312 opts = pycompat.byteskwargs(opts)
313 if not pats:
313 if not pats:
314 raise error.Abort(_('at least one filename or pattern is required'))
314 raise error.Abort(_('at least one filename or pattern is required'))
315
315
316 if opts.get('follow'):
316 if opts.get('follow'):
317 # --follow is deprecated and now just an alias for -f/--file
317 # --follow is deprecated and now just an alias for -f/--file
318 # to mimic the behavior of Mercurial before version 1.5
318 # to mimic the behavior of Mercurial before version 1.5
319 opts['file'] = True
319 opts['file'] = True
320
320
321 rev = opts.get('rev')
321 rev = opts.get('rev')
322 if rev:
322 if rev:
323 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
323 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
324 ctx = scmutil.revsingle(repo, rev)
324 ctx = scmutil.revsingle(repo, rev)
325
325
326 rootfm = ui.formatter('annotate', opts)
326 rootfm = ui.formatter('annotate', opts)
327 if ui.debugflag:
327 if ui.debugflag:
328 shorthex = pycompat.identity
328 shorthex = pycompat.identity
329 else:
329 else:
330 def shorthex(h):
330 def shorthex(h):
331 return h[:12]
331 return h[:12]
332 if ui.quiet:
332 if ui.quiet:
333 datefunc = dateutil.shortdate
333 datefunc = dateutil.shortdate
334 else:
334 else:
335 datefunc = dateutil.datestr
335 datefunc = dateutil.datestr
336 if ctx.rev() is None:
336 if ctx.rev() is None:
337 if opts.get('changeset'):
337 if opts.get('changeset'):
338 # omit "+" suffix which is appended to node hex
338 # omit "+" suffix which is appended to node hex
339 def formatrev(rev):
339 def formatrev(rev):
340 if rev == wdirrev:
340 if rev == wdirrev:
341 return '%d' % ctx.p1().rev()
341 return '%d' % ctx.p1().rev()
342 else:
342 else:
343 return '%d' % rev
343 return '%d' % rev
344 else:
344 else:
345 def formatrev(rev):
345 def formatrev(rev):
346 if rev == wdirrev:
346 if rev == wdirrev:
347 return '%d+' % ctx.p1().rev()
347 return '%d+' % ctx.p1().rev()
348 else:
348 else:
349 return '%d ' % rev
349 return '%d ' % rev
350 def formathex(h):
350 def formathex(h):
351 if h == wdirhex:
351 if h == wdirhex:
352 return '%s+' % shorthex(hex(ctx.p1().node()))
352 return '%s+' % shorthex(hex(ctx.p1().node()))
353 else:
353 else:
354 return '%s ' % shorthex(h)
354 return '%s ' % shorthex(h)
355 else:
355 else:
356 formatrev = b'%d'.__mod__
356 formatrev = b'%d'.__mod__
357 formathex = shorthex
357 formathex = shorthex
358
358
359 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
359 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
360 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
360 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
361 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
361 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
362 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
362 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
363 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
363 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
364 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
364 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
365 ]
365 ]
366 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
366 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
367 'lineno': 'line_number'}
367 'lineno': 'line_number'}
368
368
369 if (not opts.get('user') and not opts.get('changeset')
369 if (not opts.get('user') and not opts.get('changeset')
370 and not opts.get('date') and not opts.get('file')):
370 and not opts.get('date') and not opts.get('file')):
371 opts['number'] = True
371 opts['number'] = True
372
372
373 linenumber = opts.get('line_number') is not None
373 linenumber = opts.get('line_number') is not None
374 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
374 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
375 raise error.Abort(_('at least one of -n/-c is required for -l'))
375 raise error.Abort(_('at least one of -n/-c is required for -l'))
376
376
377 ui.pager('annotate')
377 ui.pager('annotate')
378
378
379 if rootfm.isplain():
379 if rootfm.isplain():
380 def makefunc(get, fmt):
380 def makefunc(get, fmt):
381 return lambda x: fmt(get(x))
381 return lambda x: fmt(get(x))
382 else:
382 else:
383 def makefunc(get, fmt):
383 def makefunc(get, fmt):
384 return get
384 return get
385 datahint = rootfm.datahint()
385 datahint = rootfm.datahint()
386 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
386 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
387 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
387 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
388 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
388 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
389 fields = ' '.join(fn for fn, sep, get, fmt in opmap
389 fields = ' '.join(fn for fn, sep, get, fmt in opmap
390 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
390 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
391
391
392 def bad(x, y):
392 def bad(x, y):
393 raise error.Abort("%s: %s" % (x, y))
393 raise error.Abort("%s: %s" % (x, y))
394
394
395 m = scmutil.match(ctx, pats, opts, badfn=bad)
395 m = scmutil.match(ctx, pats, opts, badfn=bad)
396
396
397 follow = not opts.get('no_follow')
397 follow = not opts.get('no_follow')
398 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
398 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
399 whitespace=True)
399 whitespace=True)
400 skiprevs = opts.get('skip')
400 skiprevs = opts.get('skip')
401 if skiprevs:
401 if skiprevs:
402 skiprevs = scmutil.revrange(repo, skiprevs)
402 skiprevs = scmutil.revrange(repo, skiprevs)
403
403
404 for abs in ctx.walk(m):
404 for abs in ctx.walk(m):
405 fctx = ctx[abs]
405 fctx = ctx[abs]
406 rootfm.startitem()
406 rootfm.startitem()
407 rootfm.data(path=abs)
407 rootfm.data(path=abs)
408 if not opts.get('text') and fctx.isbinary():
408 if not opts.get('text') and fctx.isbinary():
409 rootfm.plain(_("%s: binary file\n")
409 rootfm.plain(_("%s: binary file\n")
410 % ((pats and m.rel(abs)) or abs))
410 % ((pats and m.rel(abs)) or abs))
411 continue
411 continue
412
412
413 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
413 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
414 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
414 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
415 diffopts=diffopts)
415 diffopts=diffopts)
416 if not lines:
416 if not lines:
417 fm.end()
417 fm.end()
418 continue
418 continue
419 formats = []
419 formats = []
420 pieces = []
420 pieces = []
421
421
422 for f, sep in funcmap:
422 for f, sep in funcmap:
423 l = [f(n) for n in lines]
423 l = [f(n) for n in lines]
424 if fm.isplain():
424 if fm.isplain():
425 sizes = [encoding.colwidth(x) for x in l]
425 sizes = [encoding.colwidth(x) for x in l]
426 ml = max(sizes)
426 ml = max(sizes)
427 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
427 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
428 else:
428 else:
429 formats.append(['%s' for x in l])
429 formats.append(['%s' for x in l])
430 pieces.append(l)
430 pieces.append(l)
431
431
432 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
432 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
433 fm.startitem()
433 fm.startitem()
434 fm.context(fctx=n.fctx)
434 fm.context(fctx=n.fctx)
435 fm.write(fields, "".join(f), *p)
435 fm.write(fields, "".join(f), *p)
436 if n.skip:
436 if n.skip:
437 fmt = "* %s"
437 fmt = "* %s"
438 else:
438 else:
439 fmt = ": %s"
439 fmt = ": %s"
440 fm.write('line', fmt, n.text)
440 fm.write('line', fmt, n.text)
441
441
442 if not lines[-1].text.endswith('\n'):
442 if not lines[-1].text.endswith('\n'):
443 fm.plain('\n')
443 fm.plain('\n')
444 fm.end()
444 fm.end()
445
445
446 rootfm.end()
446 rootfm.end()
447
447
448 @command('archive',
448 @command('archive',
449 [('', 'no-decode', None, _('do not pass files through decoders')),
449 [('', 'no-decode', None, _('do not pass files through decoders')),
450 ('p', 'prefix', '', _('directory prefix for files in archive'),
450 ('p', 'prefix', '', _('directory prefix for files in archive'),
451 _('PREFIX')),
451 _('PREFIX')),
452 ('r', 'rev', '', _('revision to distribute'), _('REV')),
452 ('r', 'rev', '', _('revision to distribute'), _('REV')),
453 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
453 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
454 ] + subrepoopts + walkopts,
454 ] + subrepoopts + walkopts,
455 _('[OPTION]... DEST'))
455 _('[OPTION]... DEST'))
456 def archive(ui, repo, dest, **opts):
456 def archive(ui, repo, dest, **opts):
457 '''create an unversioned archive of a repository revision
457 '''create an unversioned archive of a repository revision
458
458
459 By default, the revision used is the parent of the working
459 By default, the revision used is the parent of the working
460 directory; use -r/--rev to specify a different revision.
460 directory; use -r/--rev to specify a different revision.
461
461
462 The archive type is automatically detected based on file
462 The archive type is automatically detected based on file
463 extension (to override, use -t/--type).
463 extension (to override, use -t/--type).
464
464
465 .. container:: verbose
465 .. container:: verbose
466
466
467 Examples:
467 Examples:
468
468
469 - create a zip file containing the 1.0 release::
469 - create a zip file containing the 1.0 release::
470
470
471 hg archive -r 1.0 project-1.0.zip
471 hg archive -r 1.0 project-1.0.zip
472
472
473 - create a tarball excluding .hg files::
473 - create a tarball excluding .hg files::
474
474
475 hg archive project.tar.gz -X ".hg*"
475 hg archive project.tar.gz -X ".hg*"
476
476
477 Valid types are:
477 Valid types are:
478
478
479 :``files``: a directory full of files (default)
479 :``files``: a directory full of files (default)
480 :``tar``: tar archive, uncompressed
480 :``tar``: tar archive, uncompressed
481 :``tbz2``: tar archive, compressed using bzip2
481 :``tbz2``: tar archive, compressed using bzip2
482 :``tgz``: tar archive, compressed using gzip
482 :``tgz``: tar archive, compressed using gzip
483 :``uzip``: zip archive, uncompressed
483 :``uzip``: zip archive, uncompressed
484 :``zip``: zip archive, compressed using deflate
484 :``zip``: zip archive, compressed using deflate
485
485
486 The exact name of the destination archive or directory is given
486 The exact name of the destination archive or directory is given
487 using a format string; see :hg:`help export` for details.
487 using a format string; see :hg:`help export` for details.
488
488
489 Each member added to an archive file has a directory prefix
489 Each member added to an archive file has a directory prefix
490 prepended. Use -p/--prefix to specify a format string for the
490 prepended. Use -p/--prefix to specify a format string for the
491 prefix. The default is the basename of the archive, with suffixes
491 prefix. The default is the basename of the archive, with suffixes
492 removed.
492 removed.
493
493
494 Returns 0 on success.
494 Returns 0 on success.
495 '''
495 '''
496
496
497 opts = pycompat.byteskwargs(opts)
497 opts = pycompat.byteskwargs(opts)
498 rev = opts.get('rev')
498 rev = opts.get('rev')
499 if rev:
499 if rev:
500 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
500 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
501 ctx = scmutil.revsingle(repo, rev)
501 ctx = scmutil.revsingle(repo, rev)
502 if not ctx:
502 if not ctx:
503 raise error.Abort(_('no working directory: please specify a revision'))
503 raise error.Abort(_('no working directory: please specify a revision'))
504 node = ctx.node()
504 node = ctx.node()
505 dest = cmdutil.makefilename(ctx, dest)
505 dest = cmdutil.makefilename(ctx, dest)
506 if os.path.realpath(dest) == repo.root:
506 if os.path.realpath(dest) == repo.root:
507 raise error.Abort(_('repository root cannot be destination'))
507 raise error.Abort(_('repository root cannot be destination'))
508
508
509 kind = opts.get('type') or archival.guesskind(dest) or 'files'
509 kind = opts.get('type') or archival.guesskind(dest) or 'files'
510 prefix = opts.get('prefix')
510 prefix = opts.get('prefix')
511
511
512 if dest == '-':
512 if dest == '-':
513 if kind == 'files':
513 if kind == 'files':
514 raise error.Abort(_('cannot archive plain files to stdout'))
514 raise error.Abort(_('cannot archive plain files to stdout'))
515 dest = cmdutil.makefileobj(ctx, dest)
515 dest = cmdutil.makefileobj(ctx, dest)
516 if not prefix:
516 if not prefix:
517 prefix = os.path.basename(repo.root) + '-%h'
517 prefix = os.path.basename(repo.root) + '-%h'
518
518
519 prefix = cmdutil.makefilename(ctx, prefix)
519 prefix = cmdutil.makefilename(ctx, prefix)
520 match = scmutil.match(ctx, [], opts)
520 match = scmutil.match(ctx, [], opts)
521 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
521 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
522 match, prefix, subrepos=opts.get('subrepos'))
522 match, prefix, subrepos=opts.get('subrepos'))
523
523
524 @command('backout',
524 @command('backout',
525 [('', 'merge', None, _('merge with old dirstate parent after backout')),
525 [('', 'merge', None, _('merge with old dirstate parent after backout')),
526 ('', 'commit', None,
526 ('', 'commit', None,
527 _('commit if no conflicts were encountered (DEPRECATED)')),
527 _('commit if no conflicts were encountered (DEPRECATED)')),
528 ('', 'no-commit', None, _('do not commit')),
528 ('', 'no-commit', None, _('do not commit')),
529 ('', 'parent', '',
529 ('', 'parent', '',
530 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
530 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
531 ('r', 'rev', '', _('revision to backout'), _('REV')),
531 ('r', 'rev', '', _('revision to backout'), _('REV')),
532 ('e', 'edit', False, _('invoke editor on commit messages')),
532 ('e', 'edit', False, _('invoke editor on commit messages')),
533 ] + mergetoolopts + walkopts + commitopts + commitopts2,
533 ] + mergetoolopts + walkopts + commitopts + commitopts2,
534 _('[OPTION]... [-r] REV'))
534 _('[OPTION]... [-r] REV'))
535 def backout(ui, repo, node=None, rev=None, **opts):
535 def backout(ui, repo, node=None, rev=None, **opts):
536 '''reverse effect of earlier changeset
536 '''reverse effect of earlier changeset
537
537
538 Prepare a new changeset with the effect of REV undone in the
538 Prepare a new changeset with the effect of REV undone in the
539 current working directory. If no conflicts were encountered,
539 current working directory. If no conflicts were encountered,
540 it will be committed immediately.
540 it will be committed immediately.
541
541
542 If REV is the parent of the working directory, then this new changeset
542 If REV is the parent of the working directory, then this new changeset
543 is committed automatically (unless --no-commit is specified).
543 is committed automatically (unless --no-commit is specified).
544
544
545 .. note::
545 .. note::
546
546
547 :hg:`backout` cannot be used to fix either an unwanted or
547 :hg:`backout` cannot be used to fix either an unwanted or
548 incorrect merge.
548 incorrect merge.
549
549
550 .. container:: verbose
550 .. container:: verbose
551
551
552 Examples:
552 Examples:
553
553
554 - Reverse the effect of the parent of the working directory.
554 - Reverse the effect of the parent of the working directory.
555 This backout will be committed immediately::
555 This backout will be committed immediately::
556
556
557 hg backout -r .
557 hg backout -r .
558
558
559 - Reverse the effect of previous bad revision 23::
559 - Reverse the effect of previous bad revision 23::
560
560
561 hg backout -r 23
561 hg backout -r 23
562
562
563 - Reverse the effect of previous bad revision 23 and
563 - Reverse the effect of previous bad revision 23 and
564 leave changes uncommitted::
564 leave changes uncommitted::
565
565
566 hg backout -r 23 --no-commit
566 hg backout -r 23 --no-commit
567 hg commit -m "Backout revision 23"
567 hg commit -m "Backout revision 23"
568
568
569 By default, the pending changeset will have one parent,
569 By default, the pending changeset will have one parent,
570 maintaining a linear history. With --merge, the pending
570 maintaining a linear history. With --merge, the pending
571 changeset will instead have two parents: the old parent of the
571 changeset will instead have two parents: the old parent of the
572 working directory and a new child of REV that simply undoes REV.
572 working directory and a new child of REV that simply undoes REV.
573
573
574 Before version 1.7, the behavior without --merge was equivalent
574 Before version 1.7, the behavior without --merge was equivalent
575 to specifying --merge followed by :hg:`update --clean .` to
575 to specifying --merge followed by :hg:`update --clean .` to
576 cancel the merge and leave the child of REV as a head to be
576 cancel the merge and leave the child of REV as a head to be
577 merged separately.
577 merged separately.
578
578
579 See :hg:`help dates` for a list of formats valid for -d/--date.
579 See :hg:`help dates` for a list of formats valid for -d/--date.
580
580
581 See :hg:`help revert` for a way to restore files to the state
581 See :hg:`help revert` for a way to restore files to the state
582 of another revision.
582 of another revision.
583
583
584 Returns 0 on success, 1 if nothing to backout or there are unresolved
584 Returns 0 on success, 1 if nothing to backout or there are unresolved
585 files.
585 files.
586 '''
586 '''
587 with repo.wlock(), repo.lock():
587 with repo.wlock(), repo.lock():
588 return _dobackout(ui, repo, node, rev, **opts)
588 return _dobackout(ui, repo, node, rev, **opts)
589
589
590 def _dobackout(ui, repo, node=None, rev=None, **opts):
590 def _dobackout(ui, repo, node=None, rev=None, **opts):
591 opts = pycompat.byteskwargs(opts)
591 opts = pycompat.byteskwargs(opts)
592 if opts.get('commit') and opts.get('no_commit'):
592 if opts.get('commit') and opts.get('no_commit'):
593 raise error.Abort(_("cannot use --commit with --no-commit"))
593 raise error.Abort(_("cannot use --commit with --no-commit"))
594 if opts.get('merge') and opts.get('no_commit'):
594 if opts.get('merge') and opts.get('no_commit'):
595 raise error.Abort(_("cannot use --merge with --no-commit"))
595 raise error.Abort(_("cannot use --merge with --no-commit"))
596
596
597 if rev and node:
597 if rev and node:
598 raise error.Abort(_("please specify just one revision"))
598 raise error.Abort(_("please specify just one revision"))
599
599
600 if not rev:
600 if not rev:
601 rev = node
601 rev = node
602
602
603 if not rev:
603 if not rev:
604 raise error.Abort(_("please specify a revision to backout"))
604 raise error.Abort(_("please specify a revision to backout"))
605
605
606 date = opts.get('date')
606 date = opts.get('date')
607 if date:
607 if date:
608 opts['date'] = dateutil.parsedate(date)
608 opts['date'] = dateutil.parsedate(date)
609
609
610 cmdutil.checkunfinished(repo)
610 cmdutil.checkunfinished(repo)
611 cmdutil.bailifchanged(repo)
611 cmdutil.bailifchanged(repo)
612 node = scmutil.revsingle(repo, rev).node()
612 node = scmutil.revsingle(repo, rev).node()
613
613
614 op1, op2 = repo.dirstate.parents()
614 op1, op2 = repo.dirstate.parents()
615 if not repo.changelog.isancestor(node, op1):
615 if not repo.changelog.isancestor(node, op1):
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
617
617
618 p1, p2 = repo.changelog.parents(node)
618 p1, p2 = repo.changelog.parents(node)
619 if p1 == nullid:
619 if p1 == nullid:
620 raise error.Abort(_('cannot backout a change with no parents'))
620 raise error.Abort(_('cannot backout a change with no parents'))
621 if p2 != nullid:
621 if p2 != nullid:
622 if not opts.get('parent'):
622 if not opts.get('parent'):
623 raise error.Abort(_('cannot backout a merge changeset'))
623 raise error.Abort(_('cannot backout a merge changeset'))
624 p = repo.lookup(opts['parent'])
624 p = repo.lookup(opts['parent'])
625 if p not in (p1, p2):
625 if p not in (p1, p2):
626 raise error.Abort(_('%s is not a parent of %s') %
626 raise error.Abort(_('%s is not a parent of %s') %
627 (short(p), short(node)))
627 (short(p), short(node)))
628 parent = p
628 parent = p
629 else:
629 else:
630 if opts.get('parent'):
630 if opts.get('parent'):
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
632 parent = p1
632 parent = p1
633
633
634 # the backout should appear on the same branch
634 # the backout should appear on the same branch
635 branch = repo.dirstate.branch()
635 branch = repo.dirstate.branch()
636 bheads = repo.branchheads(branch)
636 bheads = repo.branchheads(branch)
637 rctx = scmutil.revsingle(repo, hex(parent))
637 rctx = scmutil.revsingle(repo, hex(parent))
638 if not opts.get('merge') and op1 != node:
638 if not opts.get('merge') and op1 != node:
639 with dirstateguard.dirstateguard(repo, 'backout'):
639 with dirstateguard.dirstateguard(repo, 'backout'):
640 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
640 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
641 with ui.configoverride(overrides, 'backout'):
641 with ui.configoverride(overrides, 'backout'):
642 stats = mergemod.update(repo, parent, True, True, node, False)
642 stats = mergemod.update(repo, parent, True, True, node, False)
643 repo.setparents(op1, op2)
643 repo.setparents(op1, op2)
644 hg._showstats(repo, stats)
644 hg._showstats(repo, stats)
645 if stats.unresolvedcount:
645 if stats.unresolvedcount:
646 repo.ui.status(_("use 'hg resolve' to retry unresolved "
646 repo.ui.status(_("use 'hg resolve' to retry unresolved "
647 "file merges\n"))
647 "file merges\n"))
648 return 1
648 return 1
649 else:
649 else:
650 hg.clean(repo, node, show_stats=False)
650 hg.clean(repo, node, show_stats=False)
651 repo.dirstate.setbranch(branch)
651 repo.dirstate.setbranch(branch)
652 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
652 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
653
653
654 if opts.get('no_commit'):
654 if opts.get('no_commit'):
655 msg = _("changeset %s backed out, "
655 msg = _("changeset %s backed out, "
656 "don't forget to commit.\n")
656 "don't forget to commit.\n")
657 ui.status(msg % short(node))
657 ui.status(msg % short(node))
658 return 0
658 return 0
659
659
660 def commitfunc(ui, repo, message, match, opts):
660 def commitfunc(ui, repo, message, match, opts):
661 editform = 'backout'
661 editform = 'backout'
662 e = cmdutil.getcommiteditor(editform=editform,
662 e = cmdutil.getcommiteditor(editform=editform,
663 **pycompat.strkwargs(opts))
663 **pycompat.strkwargs(opts))
664 if not message:
664 if not message:
665 # we don't translate commit messages
665 # we don't translate commit messages
666 message = "Backed out changeset %s" % short(node)
666 message = "Backed out changeset %s" % short(node)
667 e = cmdutil.getcommiteditor(edit=True, editform=editform)
667 e = cmdutil.getcommiteditor(edit=True, editform=editform)
668 return repo.commit(message, opts.get('user'), opts.get('date'),
668 return repo.commit(message, opts.get('user'), opts.get('date'),
669 match, editor=e)
669 match, editor=e)
670 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
670 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
671 if not newnode:
671 if not newnode:
672 ui.status(_("nothing changed\n"))
672 ui.status(_("nothing changed\n"))
673 return 1
673 return 1
674 cmdutil.commitstatus(repo, newnode, branch, bheads)
674 cmdutil.commitstatus(repo, newnode, branch, bheads)
675
675
676 def nice(node):
676 def nice(node):
677 return '%d:%s' % (repo.changelog.rev(node), short(node))
677 return '%d:%s' % (repo.changelog.rev(node), short(node))
678 ui.status(_('changeset %s backs out changeset %s\n') %
678 ui.status(_('changeset %s backs out changeset %s\n') %
679 (nice(repo.changelog.tip()), nice(node)))
679 (nice(repo.changelog.tip()), nice(node)))
680 if opts.get('merge') and op1 != node:
680 if opts.get('merge') and op1 != node:
681 hg.clean(repo, op1, show_stats=False)
681 hg.clean(repo, op1, show_stats=False)
682 ui.status(_('merging with changeset %s\n')
682 ui.status(_('merging with changeset %s\n')
683 % nice(repo.changelog.tip()))
683 % nice(repo.changelog.tip()))
684 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
684 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
685 with ui.configoverride(overrides, 'backout'):
685 with ui.configoverride(overrides, 'backout'):
686 return hg.merge(repo, hex(repo.changelog.tip()))
686 return hg.merge(repo, hex(repo.changelog.tip()))
687 return 0
687 return 0
688
688
689 @command('bisect',
689 @command('bisect',
690 [('r', 'reset', False, _('reset bisect state')),
690 [('r', 'reset', False, _('reset bisect state')),
691 ('g', 'good', False, _('mark changeset good')),
691 ('g', 'good', False, _('mark changeset good')),
692 ('b', 'bad', False, _('mark changeset bad')),
692 ('b', 'bad', False, _('mark changeset bad')),
693 ('s', 'skip', False, _('skip testing changeset')),
693 ('s', 'skip', False, _('skip testing changeset')),
694 ('e', 'extend', False, _('extend the bisect range')),
694 ('e', 'extend', False, _('extend the bisect range')),
695 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
695 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
696 ('U', 'noupdate', False, _('do not update to target'))],
696 ('U', 'noupdate', False, _('do not update to target'))],
697 _("[-gbsr] [-U] [-c CMD] [REV]"))
697 _("[-gbsr] [-U] [-c CMD] [REV]"))
698 def bisect(ui, repo, rev=None, extra=None, command=None,
698 def bisect(ui, repo, rev=None, extra=None, command=None,
699 reset=None, good=None, bad=None, skip=None, extend=None,
699 reset=None, good=None, bad=None, skip=None, extend=None,
700 noupdate=None):
700 noupdate=None):
701 """subdivision search of changesets
701 """subdivision search of changesets
702
702
703 This command helps to find changesets which introduce problems. To
703 This command helps to find changesets which introduce problems. To
704 use, mark the earliest changeset you know exhibits the problem as
704 use, mark the earliest changeset you know exhibits the problem as
705 bad, then mark the latest changeset which is free from the problem
705 bad, then mark the latest changeset which is free from the problem
706 as good. Bisect will update your working directory to a revision
706 as good. Bisect will update your working directory to a revision
707 for testing (unless the -U/--noupdate option is specified). Once
707 for testing (unless the -U/--noupdate option is specified). Once
708 you have performed tests, mark the working directory as good or
708 you have performed tests, mark the working directory as good or
709 bad, and bisect will either update to another candidate changeset
709 bad, and bisect will either update to another candidate changeset
710 or announce that it has found the bad revision.
710 or announce that it has found the bad revision.
711
711
712 As a shortcut, you can also use the revision argument to mark a
712 As a shortcut, you can also use the revision argument to mark a
713 revision as good or bad without checking it out first.
713 revision as good or bad without checking it out first.
714
714
715 If you supply a command, it will be used for automatic bisection.
715 If you supply a command, it will be used for automatic bisection.
716 The environment variable HG_NODE will contain the ID of the
716 The environment variable HG_NODE will contain the ID of the
717 changeset being tested. The exit status of the command will be
717 changeset being tested. The exit status of the command will be
718 used to mark revisions as good or bad: status 0 means good, 125
718 used to mark revisions as good or bad: status 0 means good, 125
719 means to skip the revision, 127 (command not found) will abort the
719 means to skip the revision, 127 (command not found) will abort the
720 bisection, and any other non-zero exit status means the revision
720 bisection, and any other non-zero exit status means the revision
721 is bad.
721 is bad.
722
722
723 .. container:: verbose
723 .. container:: verbose
724
724
725 Some examples:
725 Some examples:
726
726
727 - start a bisection with known bad revision 34, and good revision 12::
727 - start a bisection with known bad revision 34, and good revision 12::
728
728
729 hg bisect --bad 34
729 hg bisect --bad 34
730 hg bisect --good 12
730 hg bisect --good 12
731
731
732 - advance the current bisection by marking current revision as good or
732 - advance the current bisection by marking current revision as good or
733 bad::
733 bad::
734
734
735 hg bisect --good
735 hg bisect --good
736 hg bisect --bad
736 hg bisect --bad
737
737
738 - mark the current revision, or a known revision, to be skipped (e.g. if
738 - mark the current revision, or a known revision, to be skipped (e.g. if
739 that revision is not usable because of another issue)::
739 that revision is not usable because of another issue)::
740
740
741 hg bisect --skip
741 hg bisect --skip
742 hg bisect --skip 23
742 hg bisect --skip 23
743
743
744 - skip all revisions that do not touch directories ``foo`` or ``bar``::
744 - skip all revisions that do not touch directories ``foo`` or ``bar``::
745
745
746 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
746 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
747
747
748 - forget the current bisection::
748 - forget the current bisection::
749
749
750 hg bisect --reset
750 hg bisect --reset
751
751
752 - use 'make && make tests' to automatically find the first broken
752 - use 'make && make tests' to automatically find the first broken
753 revision::
753 revision::
754
754
755 hg bisect --reset
755 hg bisect --reset
756 hg bisect --bad 34
756 hg bisect --bad 34
757 hg bisect --good 12
757 hg bisect --good 12
758 hg bisect --command "make && make tests"
758 hg bisect --command "make && make tests"
759
759
760 - see all changesets whose states are already known in the current
760 - see all changesets whose states are already known in the current
761 bisection::
761 bisection::
762
762
763 hg log -r "bisect(pruned)"
763 hg log -r "bisect(pruned)"
764
764
765 - see the changeset currently being bisected (especially useful
765 - see the changeset currently being bisected (especially useful
766 if running with -U/--noupdate)::
766 if running with -U/--noupdate)::
767
767
768 hg log -r "bisect(current)"
768 hg log -r "bisect(current)"
769
769
770 - see all changesets that took part in the current bisection::
770 - see all changesets that took part in the current bisection::
771
771
772 hg log -r "bisect(range)"
772 hg log -r "bisect(range)"
773
773
774 - you can even get a nice graph::
774 - you can even get a nice graph::
775
775
776 hg log --graph -r "bisect(range)"
776 hg log --graph -r "bisect(range)"
777
777
778 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
778 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
779
779
780 Returns 0 on success.
780 Returns 0 on success.
781 """
781 """
782 # backward compatibility
782 # backward compatibility
783 if rev in "good bad reset init".split():
783 if rev in "good bad reset init".split():
784 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
784 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
785 cmd, rev, extra = rev, extra, None
785 cmd, rev, extra = rev, extra, None
786 if cmd == "good":
786 if cmd == "good":
787 good = True
787 good = True
788 elif cmd == "bad":
788 elif cmd == "bad":
789 bad = True
789 bad = True
790 else:
790 else:
791 reset = True
791 reset = True
792 elif extra:
792 elif extra:
793 raise error.Abort(_('incompatible arguments'))
793 raise error.Abort(_('incompatible arguments'))
794
794
795 incompatibles = {
795 incompatibles = {
796 '--bad': bad,
796 '--bad': bad,
797 '--command': bool(command),
797 '--command': bool(command),
798 '--extend': extend,
798 '--extend': extend,
799 '--good': good,
799 '--good': good,
800 '--reset': reset,
800 '--reset': reset,
801 '--skip': skip,
801 '--skip': skip,
802 }
802 }
803
803
804 enabled = [x for x in incompatibles if incompatibles[x]]
804 enabled = [x for x in incompatibles if incompatibles[x]]
805
805
806 if len(enabled) > 1:
806 if len(enabled) > 1:
807 raise error.Abort(_('%s and %s are incompatible') %
807 raise error.Abort(_('%s and %s are incompatible') %
808 tuple(sorted(enabled)[0:2]))
808 tuple(sorted(enabled)[0:2]))
809
809
810 if reset:
810 if reset:
811 hbisect.resetstate(repo)
811 hbisect.resetstate(repo)
812 return
812 return
813
813
814 state = hbisect.load_state(repo)
814 state = hbisect.load_state(repo)
815
815
816 # update state
816 # update state
817 if good or bad or skip:
817 if good or bad or skip:
818 if rev:
818 if rev:
819 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
819 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
820 else:
820 else:
821 nodes = [repo.lookup('.')]
821 nodes = [repo.lookup('.')]
822 if good:
822 if good:
823 state['good'] += nodes
823 state['good'] += nodes
824 elif bad:
824 elif bad:
825 state['bad'] += nodes
825 state['bad'] += nodes
826 elif skip:
826 elif skip:
827 state['skip'] += nodes
827 state['skip'] += nodes
828 hbisect.save_state(repo, state)
828 hbisect.save_state(repo, state)
829 if not (state['good'] and state['bad']):
829 if not (state['good'] and state['bad']):
830 return
830 return
831
831
832 def mayupdate(repo, node, show_stats=True):
832 def mayupdate(repo, node, show_stats=True):
833 """common used update sequence"""
833 """common used update sequence"""
834 if noupdate:
834 if noupdate:
835 return
835 return
836 cmdutil.checkunfinished(repo)
836 cmdutil.checkunfinished(repo)
837 cmdutil.bailifchanged(repo)
837 cmdutil.bailifchanged(repo)
838 return hg.clean(repo, node, show_stats=show_stats)
838 return hg.clean(repo, node, show_stats=show_stats)
839
839
840 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
840 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
841
841
842 if command:
842 if command:
843 changesets = 1
843 changesets = 1
844 if noupdate:
844 if noupdate:
845 try:
845 try:
846 node = state['current'][0]
846 node = state['current'][0]
847 except LookupError:
847 except LookupError:
848 raise error.Abort(_('current bisect revision is unknown - '
848 raise error.Abort(_('current bisect revision is unknown - '
849 'start a new bisect to fix'))
849 'start a new bisect to fix'))
850 else:
850 else:
851 node, p2 = repo.dirstate.parents()
851 node, p2 = repo.dirstate.parents()
852 if p2 != nullid:
852 if p2 != nullid:
853 raise error.Abort(_('current bisect revision is a merge'))
853 raise error.Abort(_('current bisect revision is a merge'))
854 if rev:
854 if rev:
855 node = repo[scmutil.revsingle(repo, rev, node)].node()
855 node = repo[scmutil.revsingle(repo, rev, node)].node()
856 try:
856 try:
857 while changesets:
857 while changesets:
858 # update state
858 # update state
859 state['current'] = [node]
859 state['current'] = [node]
860 hbisect.save_state(repo, state)
860 hbisect.save_state(repo, state)
861 status = ui.system(command, environ={'HG_NODE': hex(node)},
861 status = ui.system(command, environ={'HG_NODE': hex(node)},
862 blockedtag='bisect_check')
862 blockedtag='bisect_check')
863 if status == 125:
863 if status == 125:
864 transition = "skip"
864 transition = "skip"
865 elif status == 0:
865 elif status == 0:
866 transition = "good"
866 transition = "good"
867 # status < 0 means process was killed
867 # status < 0 means process was killed
868 elif status == 127:
868 elif status == 127:
869 raise error.Abort(_("failed to execute %s") % command)
869 raise error.Abort(_("failed to execute %s") % command)
870 elif status < 0:
870 elif status < 0:
871 raise error.Abort(_("%s killed") % command)
871 raise error.Abort(_("%s killed") % command)
872 else:
872 else:
873 transition = "bad"
873 transition = "bad"
874 state[transition].append(node)
874 state[transition].append(node)
875 ctx = repo[node]
875 ctx = repo[node]
876 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
876 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
877 transition))
877 transition))
878 hbisect.checkstate(state)
878 hbisect.checkstate(state)
879 # bisect
879 # bisect
880 nodes, changesets, bgood = hbisect.bisect(repo, state)
880 nodes, changesets, bgood = hbisect.bisect(repo, state)
881 # update to next check
881 # update to next check
882 node = nodes[0]
882 node = nodes[0]
883 mayupdate(repo, node, show_stats=False)
883 mayupdate(repo, node, show_stats=False)
884 finally:
884 finally:
885 state['current'] = [node]
885 state['current'] = [node]
886 hbisect.save_state(repo, state)
886 hbisect.save_state(repo, state)
887 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
887 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
888 return
888 return
889
889
890 hbisect.checkstate(state)
890 hbisect.checkstate(state)
891
891
892 # actually bisect
892 # actually bisect
893 nodes, changesets, good = hbisect.bisect(repo, state)
893 nodes, changesets, good = hbisect.bisect(repo, state)
894 if extend:
894 if extend:
895 if not changesets:
895 if not changesets:
896 extendnode = hbisect.extendrange(repo, state, nodes, good)
896 extendnode = hbisect.extendrange(repo, state, nodes, good)
897 if extendnode is not None:
897 if extendnode is not None:
898 ui.write(_("Extending search to changeset %d:%s\n")
898 ui.write(_("Extending search to changeset %d:%s\n")
899 % (extendnode.rev(), extendnode))
899 % (extendnode.rev(), extendnode))
900 state['current'] = [extendnode.node()]
900 state['current'] = [extendnode.node()]
901 hbisect.save_state(repo, state)
901 hbisect.save_state(repo, state)
902 return mayupdate(repo, extendnode.node())
902 return mayupdate(repo, extendnode.node())
903 raise error.Abort(_("nothing to extend"))
903 raise error.Abort(_("nothing to extend"))
904
904
905 if changesets == 0:
905 if changesets == 0:
906 hbisect.printresult(ui, repo, state, displayer, nodes, good)
906 hbisect.printresult(ui, repo, state, displayer, nodes, good)
907 else:
907 else:
908 assert len(nodes) == 1 # only a single node can be tested next
908 assert len(nodes) == 1 # only a single node can be tested next
909 node = nodes[0]
909 node = nodes[0]
910 # compute the approximate number of remaining tests
910 # compute the approximate number of remaining tests
911 tests, size = 0, 2
911 tests, size = 0, 2
912 while size <= changesets:
912 while size <= changesets:
913 tests, size = tests + 1, size * 2
913 tests, size = tests + 1, size * 2
914 rev = repo.changelog.rev(node)
914 rev = repo.changelog.rev(node)
915 ui.write(_("Testing changeset %d:%s "
915 ui.write(_("Testing changeset %d:%s "
916 "(%d changesets remaining, ~%d tests)\n")
916 "(%d changesets remaining, ~%d tests)\n")
917 % (rev, short(node), changesets, tests))
917 % (rev, short(node), changesets, tests))
918 state['current'] = [node]
918 state['current'] = [node]
919 hbisect.save_state(repo, state)
919 hbisect.save_state(repo, state)
920 return mayupdate(repo, node)
920 return mayupdate(repo, node)
921
921
922 @command('bookmarks|bookmark',
922 @command('bookmarks|bookmark',
923 [('f', 'force', False, _('force')),
923 [('f', 'force', False, _('force')),
924 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
924 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
925 ('d', 'delete', False, _('delete a given bookmark')),
925 ('d', 'delete', False, _('delete a given bookmark')),
926 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
926 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
927 ('i', 'inactive', False, _('mark a bookmark inactive')),
927 ('i', 'inactive', False, _('mark a bookmark inactive')),
928 ('l', 'list', False, _('list existing bookmarks')),
928 ('l', 'list', False, _('list existing bookmarks')),
929 ] + formatteropts,
929 ] + formatteropts,
930 _('hg bookmarks [OPTIONS]... [NAME]...'))
930 _('hg bookmarks [OPTIONS]... [NAME]...'))
931 def bookmark(ui, repo, *names, **opts):
931 def bookmark(ui, repo, *names, **opts):
932 '''create a new bookmark or list existing bookmarks
932 '''create a new bookmark or list existing bookmarks
933
933
934 Bookmarks are labels on changesets to help track lines of development.
934 Bookmarks are labels on changesets to help track lines of development.
935 Bookmarks are unversioned and can be moved, renamed and deleted.
935 Bookmarks are unversioned and can be moved, renamed and deleted.
936 Deleting or moving a bookmark has no effect on the associated changesets.
936 Deleting or moving a bookmark has no effect on the associated changesets.
937
937
938 Creating or updating to a bookmark causes it to be marked as 'active'.
938 Creating or updating to a bookmark causes it to be marked as 'active'.
939 The active bookmark is indicated with a '*'.
939 The active bookmark is indicated with a '*'.
940 When a commit is made, the active bookmark will advance to the new commit.
940 When a commit is made, the active bookmark will advance to the new commit.
941 A plain :hg:`update` will also advance an active bookmark, if possible.
941 A plain :hg:`update` will also advance an active bookmark, if possible.
942 Updating away from a bookmark will cause it to be deactivated.
942 Updating away from a bookmark will cause it to be deactivated.
943
943
944 Bookmarks can be pushed and pulled between repositories (see
944 Bookmarks can be pushed and pulled between repositories (see
945 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
945 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
946 diverged, a new 'divergent bookmark' of the form 'name@path' will
946 diverged, a new 'divergent bookmark' of the form 'name@path' will
947 be created. Using :hg:`merge` will resolve the divergence.
947 be created. Using :hg:`merge` will resolve the divergence.
948
948
949 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
949 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
950 the active bookmark's name.
950 the active bookmark's name.
951
951
952 A bookmark named '@' has the special property that :hg:`clone` will
952 A bookmark named '@' has the special property that :hg:`clone` will
953 check it out by default if it exists.
953 check it out by default if it exists.
954
954
955 .. container:: verbose
955 .. container:: verbose
956
956
957 Template:
957 Template:
958
958
959 The following keywords are supported in addition to the common template
959 The following keywords are supported in addition to the common template
960 keywords and functions such as ``{bookmark}``. See also
960 keywords and functions such as ``{bookmark}``. See also
961 :hg:`help templates`.
961 :hg:`help templates`.
962
962
963 :active: Boolean. True if the bookmark is active.
963 :active: Boolean. True if the bookmark is active.
964
964
965 Examples:
965 Examples:
966
966
967 - create an active bookmark for a new line of development::
967 - create an active bookmark for a new line of development::
968
968
969 hg book new-feature
969 hg book new-feature
970
970
971 - create an inactive bookmark as a place marker::
971 - create an inactive bookmark as a place marker::
972
972
973 hg book -i reviewed
973 hg book -i reviewed
974
974
975 - create an inactive bookmark on another changeset::
975 - create an inactive bookmark on another changeset::
976
976
977 hg book -r .^ tested
977 hg book -r .^ tested
978
978
979 - rename bookmark turkey to dinner::
979 - rename bookmark turkey to dinner::
980
980
981 hg book -m turkey dinner
981 hg book -m turkey dinner
982
982
983 - move the '@' bookmark from another branch::
983 - move the '@' bookmark from another branch::
984
984
985 hg book -f @
985 hg book -f @
986
986
987 - print only the active bookmark name::
987 - print only the active bookmark name::
988
988
989 hg book -ql .
989 hg book -ql .
990 '''
990 '''
991 opts = pycompat.byteskwargs(opts)
991 opts = pycompat.byteskwargs(opts)
992 force = opts.get('force')
992 force = opts.get('force')
993 rev = opts.get('rev')
993 rev = opts.get('rev')
994 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
994 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
995
995
996 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
996 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
997 if len(selactions) > 1:
997 if len(selactions) > 1:
998 raise error.Abort(_('--%s and --%s are incompatible')
998 raise error.Abort(_('--%s and --%s are incompatible')
999 % tuple(selactions[:2]))
999 % tuple(selactions[:2]))
1000 if selactions:
1000 if selactions:
1001 action = selactions[0]
1001 action = selactions[0]
1002 elif names or rev:
1002 elif names or rev:
1003 action = 'add'
1003 action = 'add'
1004 elif inactive:
1004 elif inactive:
1005 action = 'inactive' # meaning deactivate
1005 action = 'inactive' # meaning deactivate
1006 else:
1006 else:
1007 action = 'list'
1007 action = 'list'
1008
1008
1009 if rev and action in {'delete', 'rename', 'list'}:
1009 if rev and action in {'delete', 'rename', 'list'}:
1010 raise error.Abort(_("--rev is incompatible with --%s") % action)
1010 raise error.Abort(_("--rev is incompatible with --%s") % action)
1011 if inactive and action in {'delete', 'list'}:
1011 if inactive and action in {'delete', 'list'}:
1012 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1012 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1013 if not names and action in {'add', 'delete'}:
1013 if not names and action in {'add', 'delete'}:
1014 raise error.Abort(_("bookmark name required"))
1014 raise error.Abort(_("bookmark name required"))
1015
1015
1016 if action in {'add', 'delete', 'rename', 'inactive'}:
1016 if action in {'add', 'delete', 'rename', 'inactive'}:
1017 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1017 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1018 if action == 'delete':
1018 if action == 'delete':
1019 names = pycompat.maplist(repo._bookmarks.expandname, names)
1019 names = pycompat.maplist(repo._bookmarks.expandname, names)
1020 bookmarks.delete(repo, tr, names)
1020 bookmarks.delete(repo, tr, names)
1021 elif action == 'rename':
1021 elif action == 'rename':
1022 if not names:
1022 if not names:
1023 raise error.Abort(_("new bookmark name required"))
1023 raise error.Abort(_("new bookmark name required"))
1024 elif len(names) > 1:
1024 elif len(names) > 1:
1025 raise error.Abort(_("only one new bookmark name allowed"))
1025 raise error.Abort(_("only one new bookmark name allowed"))
1026 oldname = repo._bookmarks.expandname(opts['rename'])
1026 oldname = repo._bookmarks.expandname(opts['rename'])
1027 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1027 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1028 elif action == 'add':
1028 elif action == 'add':
1029 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1029 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1030 elif action == 'inactive':
1030 elif action == 'inactive':
1031 if len(repo._bookmarks) == 0:
1031 if len(repo._bookmarks) == 0:
1032 ui.status(_("no bookmarks set\n"))
1032 ui.status(_("no bookmarks set\n"))
1033 elif not repo._activebookmark:
1033 elif not repo._activebookmark:
1034 ui.status(_("no active bookmark\n"))
1034 ui.status(_("no active bookmark\n"))
1035 else:
1035 else:
1036 bookmarks.deactivate(repo)
1036 bookmarks.deactivate(repo)
1037 elif action == 'list':
1037 elif action == 'list':
1038 names = pycompat.maplist(repo._bookmarks.expandname, names)
1038 names = pycompat.maplist(repo._bookmarks.expandname, names)
1039 with ui.formatter('bookmarks', opts) as fm:
1039 with ui.formatter('bookmarks', opts) as fm:
1040 bookmarks.printbookmarks(ui, repo, fm, names)
1040 bookmarks.printbookmarks(ui, repo, fm, names)
1041 else:
1041 else:
1042 raise error.ProgrammingError('invalid action: %s' % action)
1042 raise error.ProgrammingError('invalid action: %s' % action)
1043
1043
1044 @command('branch',
1044 @command('branch',
1045 [('f', 'force', None,
1045 [('f', 'force', None,
1046 _('set branch name even if it shadows an existing branch')),
1046 _('set branch name even if it shadows an existing branch')),
1047 ('C', 'clean', None, _('reset branch name to parent branch name')),
1047 ('C', 'clean', None, _('reset branch name to parent branch name')),
1048 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1048 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1049 ],
1049 ],
1050 _('[-fC] [NAME]'))
1050 _('[-fC] [NAME]'))
1051 def branch(ui, repo, label=None, **opts):
1051 def branch(ui, repo, label=None, **opts):
1052 """set or show the current branch name
1052 """set or show the current branch name
1053
1053
1054 .. note::
1054 .. note::
1055
1055
1056 Branch names are permanent and global. Use :hg:`bookmark` to create a
1056 Branch names are permanent and global. Use :hg:`bookmark` to create a
1057 light-weight bookmark instead. See :hg:`help glossary` for more
1057 light-weight bookmark instead. See :hg:`help glossary` for more
1058 information about named branches and bookmarks.
1058 information about named branches and bookmarks.
1059
1059
1060 With no argument, show the current branch name. With one argument,
1060 With no argument, show the current branch name. With one argument,
1061 set the working directory branch name (the branch will not exist
1061 set the working directory branch name (the branch will not exist
1062 in the repository until the next commit). Standard practice
1062 in the repository until the next commit). Standard practice
1063 recommends that primary development take place on the 'default'
1063 recommends that primary development take place on the 'default'
1064 branch.
1064 branch.
1065
1065
1066 Unless -f/--force is specified, branch will not let you set a
1066 Unless -f/--force is specified, branch will not let you set a
1067 branch name that already exists.
1067 branch name that already exists.
1068
1068
1069 Use -C/--clean to reset the working directory branch to that of
1069 Use -C/--clean to reset the working directory branch to that of
1070 the parent of the working directory, negating a previous branch
1070 the parent of the working directory, negating a previous branch
1071 change.
1071 change.
1072
1072
1073 Use the command :hg:`update` to switch to an existing branch. Use
1073 Use the command :hg:`update` to switch to an existing branch. Use
1074 :hg:`commit --close-branch` to mark this branch head as closed.
1074 :hg:`commit --close-branch` to mark this branch head as closed.
1075 When all heads of a branch are closed, the branch will be
1075 When all heads of a branch are closed, the branch will be
1076 considered closed.
1076 considered closed.
1077
1077
1078 Returns 0 on success.
1078 Returns 0 on success.
1079 """
1079 """
1080 opts = pycompat.byteskwargs(opts)
1080 opts = pycompat.byteskwargs(opts)
1081 revs = opts.get('rev')
1081 revs = opts.get('rev')
1082 if label:
1082 if label:
1083 label = label.strip()
1083 label = label.strip()
1084
1084
1085 if not opts.get('clean') and not label:
1085 if not opts.get('clean') and not label:
1086 if revs:
1086 if revs:
1087 raise error.Abort(_("no branch name specified for the revisions"))
1087 raise error.Abort(_("no branch name specified for the revisions"))
1088 ui.write("%s\n" % repo.dirstate.branch())
1088 ui.write("%s\n" % repo.dirstate.branch())
1089 return
1089 return
1090
1090
1091 with repo.wlock():
1091 with repo.wlock():
1092 if opts.get('clean'):
1092 if opts.get('clean'):
1093 label = repo[None].p1().branch()
1093 label = repo[None].p1().branch()
1094 repo.dirstate.setbranch(label)
1094 repo.dirstate.setbranch(label)
1095 ui.status(_('reset working directory to branch %s\n') % label)
1095 ui.status(_('reset working directory to branch %s\n') % label)
1096 elif label:
1096 elif label:
1097
1097
1098 scmutil.checknewlabel(repo, label, 'branch')
1098 scmutil.checknewlabel(repo, label, 'branch')
1099 if revs:
1099 if revs:
1100 return cmdutil.changebranch(ui, repo, revs, label)
1100 return cmdutil.changebranch(ui, repo, revs, label)
1101
1101
1102 if not opts.get('force') and label in repo.branchmap():
1102 if not opts.get('force') and label in repo.branchmap():
1103 if label not in [p.branch() for p in repo[None].parents()]:
1103 if label not in [p.branch() for p in repo[None].parents()]:
1104 raise error.Abort(_('a branch of the same name already'
1104 raise error.Abort(_('a branch of the same name already'
1105 ' exists'),
1105 ' exists'),
1106 # i18n: "it" refers to an existing branch
1106 # i18n: "it" refers to an existing branch
1107 hint=_("use 'hg update' to switch to it"))
1107 hint=_("use 'hg update' to switch to it"))
1108
1108
1109 repo.dirstate.setbranch(label)
1109 repo.dirstate.setbranch(label)
1110 ui.status(_('marked working directory as branch %s\n') % label)
1110 ui.status(_('marked working directory as branch %s\n') % label)
1111
1111
1112 # find any open named branches aside from default
1112 # find any open named branches aside from default
1113 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1113 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1114 if n != "default" and not c]
1114 if n != "default" and not c]
1115 if not others:
1115 if not others:
1116 ui.status(_('(branches are permanent and global, '
1116 ui.status(_('(branches are permanent and global, '
1117 'did you want a bookmark?)\n'))
1117 'did you want a bookmark?)\n'))
1118
1118
1119 @command('branches',
1119 @command('branches',
1120 [('a', 'active', False,
1120 [('a', 'active', False,
1121 _('show only branches that have unmerged heads (DEPRECATED)')),
1121 _('show only branches that have unmerged heads (DEPRECATED)')),
1122 ('c', 'closed', False, _('show normal and closed branches')),
1122 ('c', 'closed', False, _('show normal and closed branches')),
1123 ] + formatteropts,
1123 ] + formatteropts,
1124 _('[-c]'),
1124 _('[-c]'),
1125 intents={INTENT_READONLY})
1125 intents={INTENT_READONLY})
1126 def branches(ui, repo, active=False, closed=False, **opts):
1126 def branches(ui, repo, active=False, closed=False, **opts):
1127 """list repository named branches
1127 """list repository named branches
1128
1128
1129 List the repository's named branches, indicating which ones are
1129 List the repository's named branches, indicating which ones are
1130 inactive. If -c/--closed is specified, also list branches which have
1130 inactive. If -c/--closed is specified, also list branches which have
1131 been marked closed (see :hg:`commit --close-branch`).
1131 been marked closed (see :hg:`commit --close-branch`).
1132
1132
1133 Use the command :hg:`update` to switch to an existing branch.
1133 Use the command :hg:`update` to switch to an existing branch.
1134
1134
1135 .. container:: verbose
1135 .. container:: verbose
1136
1136
1137 Template:
1137 Template:
1138
1138
1139 The following keywords are supported in addition to the common template
1139 The following keywords are supported in addition to the common template
1140 keywords and functions such as ``{branch}``. See also
1140 keywords and functions such as ``{branch}``. See also
1141 :hg:`help templates`.
1141 :hg:`help templates`.
1142
1142
1143 :active: Boolean. True if the branch is active.
1143 :active: Boolean. True if the branch is active.
1144 :closed: Boolean. True if the branch is closed.
1144 :closed: Boolean. True if the branch is closed.
1145 :current: Boolean. True if it is the current branch.
1145 :current: Boolean. True if it is the current branch.
1146
1146
1147 Returns 0.
1147 Returns 0.
1148 """
1148 """
1149
1149
1150 opts = pycompat.byteskwargs(opts)
1150 opts = pycompat.byteskwargs(opts)
1151 ui.pager('branches')
1151 ui.pager('branches')
1152 fm = ui.formatter('branches', opts)
1152 fm = ui.formatter('branches', opts)
1153 hexfunc = fm.hexfunc
1153 hexfunc = fm.hexfunc
1154
1154
1155 allheads = set(repo.heads())
1155 allheads = set(repo.heads())
1156 branches = []
1156 branches = []
1157 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1157 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1158 isactive = False
1158 isactive = False
1159 if not isclosed:
1159 if not isclosed:
1160 openheads = set(repo.branchmap().iteropen(heads))
1160 openheads = set(repo.branchmap().iteropen(heads))
1161 isactive = bool(openheads & allheads)
1161 isactive = bool(openheads & allheads)
1162 branches.append((tag, repo[tip], isactive, not isclosed))
1162 branches.append((tag, repo[tip], isactive, not isclosed))
1163 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1163 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1164 reverse=True)
1164 reverse=True)
1165
1165
1166 for tag, ctx, isactive, isopen in branches:
1166 for tag, ctx, isactive, isopen in branches:
1167 if active and not isactive:
1167 if active and not isactive:
1168 continue
1168 continue
1169 if isactive:
1169 if isactive:
1170 label = 'branches.active'
1170 label = 'branches.active'
1171 notice = ''
1171 notice = ''
1172 elif not isopen:
1172 elif not isopen:
1173 if not closed:
1173 if not closed:
1174 continue
1174 continue
1175 label = 'branches.closed'
1175 label = 'branches.closed'
1176 notice = _(' (closed)')
1176 notice = _(' (closed)')
1177 else:
1177 else:
1178 label = 'branches.inactive'
1178 label = 'branches.inactive'
1179 notice = _(' (inactive)')
1179 notice = _(' (inactive)')
1180 current = (tag == repo.dirstate.branch())
1180 current = (tag == repo.dirstate.branch())
1181 if current:
1181 if current:
1182 label = 'branches.current'
1182 label = 'branches.current'
1183
1183
1184 fm.startitem()
1184 fm.startitem()
1185 fm.write('branch', '%s', tag, label=label)
1185 fm.write('branch', '%s', tag, label=label)
1186 rev = ctx.rev()
1186 rev = ctx.rev()
1187 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1187 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1188 fmt = ' ' * padsize + ' %d:%s'
1188 fmt = ' ' * padsize + ' %d:%s'
1189 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1189 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1190 label='log.changeset changeset.%s' % ctx.phasestr())
1190 label='log.changeset changeset.%s' % ctx.phasestr())
1191 fm.context(ctx=ctx)
1191 fm.context(ctx=ctx)
1192 fm.data(active=isactive, closed=not isopen, current=current)
1192 fm.data(active=isactive, closed=not isopen, current=current)
1193 if not ui.quiet:
1193 if not ui.quiet:
1194 fm.plain(notice)
1194 fm.plain(notice)
1195 fm.plain('\n')
1195 fm.plain('\n')
1196 fm.end()
1196 fm.end()
1197
1197
1198 @command('bundle',
1198 @command('bundle',
1199 [('f', 'force', None, _('run even when the destination is unrelated')),
1199 [('f', 'force', None, _('run even when the destination is unrelated')),
1200 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1200 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1201 _('REV')),
1201 _('REV')),
1202 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1202 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1203 _('BRANCH')),
1203 _('BRANCH')),
1204 ('', 'base', [],
1204 ('', 'base', [],
1205 _('a base changeset assumed to be available at the destination'),
1205 _('a base changeset assumed to be available at the destination'),
1206 _('REV')),
1206 _('REV')),
1207 ('a', 'all', None, _('bundle all changesets in the repository')),
1207 ('a', 'all', None, _('bundle all changesets in the repository')),
1208 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1208 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1209 ] + remoteopts,
1209 ] + remoteopts,
1210 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1210 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1211 def bundle(ui, repo, fname, dest=None, **opts):
1211 def bundle(ui, repo, fname, dest=None, **opts):
1212 """create a bundle file
1212 """create a bundle file
1213
1213
1214 Generate a bundle file containing data to be transferred to another
1214 Generate a bundle file containing data to be transferred to another
1215 repository.
1215 repository.
1216
1216
1217 To create a bundle containing all changesets, use -a/--all
1217 To create a bundle containing all changesets, use -a/--all
1218 (or --base null). Otherwise, hg assumes the destination will have
1218 (or --base null). Otherwise, hg assumes the destination will have
1219 all the nodes you specify with --base parameters. Otherwise, hg
1219 all the nodes you specify with --base parameters. Otherwise, hg
1220 will assume the repository has all the nodes in destination, or
1220 will assume the repository has all the nodes in destination, or
1221 default-push/default if no destination is specified, where destination
1221 default-push/default if no destination is specified, where destination
1222 is the repository you provide through DEST option.
1222 is the repository you provide through DEST option.
1223
1223
1224 You can change bundle format with the -t/--type option. See
1224 You can change bundle format with the -t/--type option. See
1225 :hg:`help bundlespec` for documentation on this format. By default,
1225 :hg:`help bundlespec` for documentation on this format. By default,
1226 the most appropriate format is used and compression defaults to
1226 the most appropriate format is used and compression defaults to
1227 bzip2.
1227 bzip2.
1228
1228
1229 The bundle file can then be transferred using conventional means
1229 The bundle file can then be transferred using conventional means
1230 and applied to another repository with the unbundle or pull
1230 and applied to another repository with the unbundle or pull
1231 command. This is useful when direct push and pull are not
1231 command. This is useful when direct push and pull are not
1232 available or when exporting an entire repository is undesirable.
1232 available or when exporting an entire repository is undesirable.
1233
1233
1234 Applying bundles preserves all changeset contents including
1234 Applying bundles preserves all changeset contents including
1235 permissions, copy/rename information, and revision history.
1235 permissions, copy/rename information, and revision history.
1236
1236
1237 Returns 0 on success, 1 if no changes found.
1237 Returns 0 on success, 1 if no changes found.
1238 """
1238 """
1239 opts = pycompat.byteskwargs(opts)
1239 opts = pycompat.byteskwargs(opts)
1240 revs = None
1240 revs = None
1241 if 'rev' in opts:
1241 if 'rev' in opts:
1242 revstrings = opts['rev']
1242 revstrings = opts['rev']
1243 revs = scmutil.revrange(repo, revstrings)
1243 revs = scmutil.revrange(repo, revstrings)
1244 if revstrings and not revs:
1244 if revstrings and not revs:
1245 raise error.Abort(_('no commits to bundle'))
1245 raise error.Abort(_('no commits to bundle'))
1246
1246
1247 bundletype = opts.get('type', 'bzip2').lower()
1247 bundletype = opts.get('type', 'bzip2').lower()
1248 try:
1248 try:
1249 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1249 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1250 except error.UnsupportedBundleSpecification as e:
1250 except error.UnsupportedBundleSpecification as e:
1251 raise error.Abort(pycompat.bytestr(e),
1251 raise error.Abort(pycompat.bytestr(e),
1252 hint=_("see 'hg help bundlespec' for supported "
1252 hint=_("see 'hg help bundlespec' for supported "
1253 "values for --type"))
1253 "values for --type"))
1254 cgversion = bundlespec.contentopts["cg.version"]
1254 cgversion = bundlespec.contentopts["cg.version"]
1255
1255
1256 # Packed bundles are a pseudo bundle format for now.
1256 # Packed bundles are a pseudo bundle format for now.
1257 if cgversion == 's1':
1257 if cgversion == 's1':
1258 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1258 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1259 hint=_("use 'hg debugcreatestreamclonebundle'"))
1259 hint=_("use 'hg debugcreatestreamclonebundle'"))
1260
1260
1261 if opts.get('all'):
1261 if opts.get('all'):
1262 if dest:
1262 if dest:
1263 raise error.Abort(_("--all is incompatible with specifying "
1263 raise error.Abort(_("--all is incompatible with specifying "
1264 "a destination"))
1264 "a destination"))
1265 if opts.get('base'):
1265 if opts.get('base'):
1266 ui.warn(_("ignoring --base because --all was specified\n"))
1266 ui.warn(_("ignoring --base because --all was specified\n"))
1267 base = [nullrev]
1267 base = [nullrev]
1268 else:
1268 else:
1269 base = scmutil.revrange(repo, opts.get('base'))
1269 base = scmutil.revrange(repo, opts.get('base'))
1270 if cgversion not in changegroup.supportedoutgoingversions(repo):
1270 if cgversion not in changegroup.supportedoutgoingversions(repo):
1271 raise error.Abort(_("repository does not support bundle version %s") %
1271 raise error.Abort(_("repository does not support bundle version %s") %
1272 cgversion)
1272 cgversion)
1273
1273
1274 if base:
1274 if base:
1275 if dest:
1275 if dest:
1276 raise error.Abort(_("--base is incompatible with specifying "
1276 raise error.Abort(_("--base is incompatible with specifying "
1277 "a destination"))
1277 "a destination"))
1278 common = [repo[rev].node() for rev in base]
1278 common = [repo[rev].node() for rev in base]
1279 heads = [repo[r].node() for r in revs] if revs else None
1279 heads = [repo[r].node() for r in revs] if revs else None
1280 outgoing = discovery.outgoing(repo, common, heads)
1280 outgoing = discovery.outgoing(repo, common, heads)
1281 else:
1281 else:
1282 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1282 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1283 dest, branches = hg.parseurl(dest, opts.get('branch'))
1283 dest, branches = hg.parseurl(dest, opts.get('branch'))
1284 other = hg.peer(repo, opts, dest)
1284 other = hg.peer(repo, opts, dest)
1285 revs = [repo[r].hex() for r in revs]
1285 revs = [repo[r].hex() for r in revs]
1286 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1286 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1287 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1287 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1288 outgoing = discovery.findcommonoutgoing(repo, other,
1288 outgoing = discovery.findcommonoutgoing(repo, other,
1289 onlyheads=heads,
1289 onlyheads=heads,
1290 force=opts.get('force'),
1290 force=opts.get('force'),
1291 portable=True)
1291 portable=True)
1292
1292
1293 if not outgoing.missing:
1293 if not outgoing.missing:
1294 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1294 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1295 return 1
1295 return 1
1296
1296
1297 if cgversion == '01': #bundle1
1297 if cgversion == '01': #bundle1
1298 bversion = 'HG10' + bundlespec.wirecompression
1298 bversion = 'HG10' + bundlespec.wirecompression
1299 bcompression = None
1299 bcompression = None
1300 elif cgversion in ('02', '03'):
1300 elif cgversion in ('02', '03'):
1301 bversion = 'HG20'
1301 bversion = 'HG20'
1302 bcompression = bundlespec.wirecompression
1302 bcompression = bundlespec.wirecompression
1303 else:
1303 else:
1304 raise error.ProgrammingError(
1304 raise error.ProgrammingError(
1305 'bundle: unexpected changegroup version %s' % cgversion)
1305 'bundle: unexpected changegroup version %s' % cgversion)
1306
1306
1307 # TODO compression options should be derived from bundlespec parsing.
1307 # TODO compression options should be derived from bundlespec parsing.
1308 # This is a temporary hack to allow adjusting bundle compression
1308 # This is a temporary hack to allow adjusting bundle compression
1309 # level without a) formalizing the bundlespec changes to declare it
1309 # level without a) formalizing the bundlespec changes to declare it
1310 # b) introducing a command flag.
1310 # b) introducing a command flag.
1311 compopts = {}
1311 compopts = {}
1312 complevel = ui.configint('experimental',
1312 complevel = ui.configint('experimental',
1313 'bundlecomplevel.' + bundlespec.compression)
1313 'bundlecomplevel.' + bundlespec.compression)
1314 if complevel is None:
1314 if complevel is None:
1315 complevel = ui.configint('experimental', 'bundlecomplevel')
1315 complevel = ui.configint('experimental', 'bundlecomplevel')
1316 if complevel is not None:
1316 if complevel is not None:
1317 compopts['level'] = complevel
1317 compopts['level'] = complevel
1318
1318
1319 # Allow overriding the bundling of obsmarker in phases through
1319 # Allow overriding the bundling of obsmarker in phases through
1320 # configuration while we don't have a bundle version that include them
1320 # configuration while we don't have a bundle version that include them
1321 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1321 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1322 bundlespec.contentopts['obsolescence'] = True
1322 bundlespec.contentopts['obsolescence'] = True
1323 if repo.ui.configbool('experimental', 'bundle-phases'):
1323 if repo.ui.configbool('experimental', 'bundle-phases'):
1324 bundlespec.contentopts['phases'] = True
1324 bundlespec.contentopts['phases'] = True
1325
1325
1326 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1326 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1327 bundlespec.contentopts, compression=bcompression,
1327 bundlespec.contentopts, compression=bcompression,
1328 compopts=compopts)
1328 compopts=compopts)
1329
1329
1330 @command('cat',
1330 @command('cat',
1331 [('o', 'output', '',
1331 [('o', 'output', '',
1332 _('print output to file with formatted name'), _('FORMAT')),
1332 _('print output to file with formatted name'), _('FORMAT')),
1333 ('r', 'rev', '', _('print the given revision'), _('REV')),
1333 ('r', 'rev', '', _('print the given revision'), _('REV')),
1334 ('', 'decode', None, _('apply any matching decode filter')),
1334 ('', 'decode', None, _('apply any matching decode filter')),
1335 ] + walkopts + formatteropts,
1335 ] + walkopts + formatteropts,
1336 _('[OPTION]... FILE...'),
1336 _('[OPTION]... FILE...'),
1337 inferrepo=True,
1337 inferrepo=True,
1338 intents={INTENT_READONLY})
1338 intents={INTENT_READONLY})
1339 def cat(ui, repo, file1, *pats, **opts):
1339 def cat(ui, repo, file1, *pats, **opts):
1340 """output the current or given revision of files
1340 """output the current or given revision of files
1341
1341
1342 Print the specified files as they were at the given revision. If
1342 Print the specified files as they were at the given revision. If
1343 no revision is given, the parent of the working directory is used.
1343 no revision is given, the parent of the working directory is used.
1344
1344
1345 Output may be to a file, in which case the name of the file is
1345 Output may be to a file, in which case the name of the file is
1346 given using a template string. See :hg:`help templates`. In addition
1346 given using a template string. See :hg:`help templates`. In addition
1347 to the common template keywords, the following formatting rules are
1347 to the common template keywords, the following formatting rules are
1348 supported:
1348 supported:
1349
1349
1350 :``%%``: literal "%" character
1350 :``%%``: literal "%" character
1351 :``%s``: basename of file being printed
1351 :``%s``: basename of file being printed
1352 :``%d``: dirname of file being printed, or '.' if in repository root
1352 :``%d``: dirname of file being printed, or '.' if in repository root
1353 :``%p``: root-relative path name of file being printed
1353 :``%p``: root-relative path name of file being printed
1354 :``%H``: changeset hash (40 hexadecimal digits)
1354 :``%H``: changeset hash (40 hexadecimal digits)
1355 :``%R``: changeset revision number
1355 :``%R``: changeset revision number
1356 :``%h``: short-form changeset hash (12 hexadecimal digits)
1356 :``%h``: short-form changeset hash (12 hexadecimal digits)
1357 :``%r``: zero-padded changeset revision number
1357 :``%r``: zero-padded changeset revision number
1358 :``%b``: basename of the exporting repository
1358 :``%b``: basename of the exporting repository
1359 :``\\``: literal "\\" character
1359 :``\\``: literal "\\" character
1360
1360
1361 .. container:: verbose
1361 .. container:: verbose
1362
1362
1363 Template:
1363 Template:
1364
1364
1365 The following keywords are supported in addition to the common template
1365 The following keywords are supported in addition to the common template
1366 keywords and functions. See also :hg:`help templates`.
1366 keywords and functions. See also :hg:`help templates`.
1367
1367
1368 :data: String. File content.
1368 :data: String. File content.
1369 :path: String. Repository-absolute path of the file.
1369 :path: String. Repository-absolute path of the file.
1370
1370
1371 Returns 0 on success.
1371 Returns 0 on success.
1372 """
1372 """
1373 opts = pycompat.byteskwargs(opts)
1373 opts = pycompat.byteskwargs(opts)
1374 rev = opts.get('rev')
1374 rev = opts.get('rev')
1375 if rev:
1375 if rev:
1376 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1376 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1377 ctx = scmutil.revsingle(repo, rev)
1377 ctx = scmutil.revsingle(repo, rev)
1378 m = scmutil.match(ctx, (file1,) + pats, opts)
1378 m = scmutil.match(ctx, (file1,) + pats, opts)
1379 fntemplate = opts.pop('output', '')
1379 fntemplate = opts.pop('output', '')
1380 if cmdutil.isstdiofilename(fntemplate):
1380 if cmdutil.isstdiofilename(fntemplate):
1381 fntemplate = ''
1381 fntemplate = ''
1382
1382
1383 if fntemplate:
1383 if fntemplate:
1384 fm = formatter.nullformatter(ui, 'cat', opts)
1384 fm = formatter.nullformatter(ui, 'cat', opts)
1385 else:
1385 else:
1386 ui.pager('cat')
1386 ui.pager('cat')
1387 fm = ui.formatter('cat', opts)
1387 fm = ui.formatter('cat', opts)
1388 with fm:
1388 with fm:
1389 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1389 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1390 **pycompat.strkwargs(opts))
1390 **pycompat.strkwargs(opts))
1391
1391
1392 @command('^clone',
1392 @command('^clone',
1393 [('U', 'noupdate', None, _('the clone will include an empty working '
1393 [('U', 'noupdate', None, _('the clone will include an empty working '
1394 'directory (only a repository)')),
1394 'directory (only a repository)')),
1395 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1395 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1396 _('REV')),
1396 _('REV')),
1397 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1397 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1398 ' and its ancestors'), _('REV')),
1398 ' and its ancestors'), _('REV')),
1399 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1399 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1400 ' changesets and their ancestors'), _('BRANCH')),
1400 ' changesets and their ancestors'), _('BRANCH')),
1401 ('', 'pull', None, _('use pull protocol to copy metadata')),
1401 ('', 'pull', None, _('use pull protocol to copy metadata')),
1402 ('', 'uncompressed', None,
1402 ('', 'uncompressed', None,
1403 _('an alias to --stream (DEPRECATED)')),
1403 _('an alias to --stream (DEPRECATED)')),
1404 ('', 'stream', None,
1404 ('', 'stream', None,
1405 _('clone with minimal data processing')),
1405 _('clone with minimal data processing')),
1406 ] + remoteopts,
1406 ] + remoteopts,
1407 _('[OPTION]... SOURCE [DEST]'),
1407 _('[OPTION]... SOURCE [DEST]'),
1408 norepo=True)
1408 norepo=True)
1409 def clone(ui, source, dest=None, **opts):
1409 def clone(ui, source, dest=None, **opts):
1410 """make a copy of an existing repository
1410 """make a copy of an existing repository
1411
1411
1412 Create a copy of an existing repository in a new directory.
1412 Create a copy of an existing repository in a new directory.
1413
1413
1414 If no destination directory name is specified, it defaults to the
1414 If no destination directory name is specified, it defaults to the
1415 basename of the source.
1415 basename of the source.
1416
1416
1417 The location of the source is added to the new repository's
1417 The location of the source is added to the new repository's
1418 ``.hg/hgrc`` file, as the default to be used for future pulls.
1418 ``.hg/hgrc`` file, as the default to be used for future pulls.
1419
1419
1420 Only local paths and ``ssh://`` URLs are supported as
1420 Only local paths and ``ssh://`` URLs are supported as
1421 destinations. For ``ssh://`` destinations, no working directory or
1421 destinations. For ``ssh://`` destinations, no working directory or
1422 ``.hg/hgrc`` will be created on the remote side.
1422 ``.hg/hgrc`` will be created on the remote side.
1423
1423
1424 If the source repository has a bookmark called '@' set, that
1424 If the source repository has a bookmark called '@' set, that
1425 revision will be checked out in the new repository by default.
1425 revision will be checked out in the new repository by default.
1426
1426
1427 To check out a particular version, use -u/--update, or
1427 To check out a particular version, use -u/--update, or
1428 -U/--noupdate to create a clone with no working directory.
1428 -U/--noupdate to create a clone with no working directory.
1429
1429
1430 To pull only a subset of changesets, specify one or more revisions
1430 To pull only a subset of changesets, specify one or more revisions
1431 identifiers with -r/--rev or branches with -b/--branch. The
1431 identifiers with -r/--rev or branches with -b/--branch. The
1432 resulting clone will contain only the specified changesets and
1432 resulting clone will contain only the specified changesets and
1433 their ancestors. These options (or 'clone src#rev dest') imply
1433 their ancestors. These options (or 'clone src#rev dest') imply
1434 --pull, even for local source repositories.
1434 --pull, even for local source repositories.
1435
1435
1436 In normal clone mode, the remote normalizes repository data into a common
1436 In normal clone mode, the remote normalizes repository data into a common
1437 exchange format and the receiving end translates this data into its local
1437 exchange format and the receiving end translates this data into its local
1438 storage format. --stream activates a different clone mode that essentially
1438 storage format. --stream activates a different clone mode that essentially
1439 copies repository files from the remote with minimal data processing. This
1439 copies repository files from the remote with minimal data processing. This
1440 significantly reduces the CPU cost of a clone both remotely and locally.
1440 significantly reduces the CPU cost of a clone both remotely and locally.
1441 However, it often increases the transferred data size by 30-40%. This can
1441 However, it often increases the transferred data size by 30-40%. This can
1442 result in substantially faster clones where I/O throughput is plentiful,
1442 result in substantially faster clones where I/O throughput is plentiful,
1443 especially for larger repositories. A side-effect of --stream clones is
1443 especially for larger repositories. A side-effect of --stream clones is
1444 that storage settings and requirements on the remote are applied locally:
1444 that storage settings and requirements on the remote are applied locally:
1445 a modern client may inherit legacy or inefficient storage used by the
1445 a modern client may inherit legacy or inefficient storage used by the
1446 remote or a legacy Mercurial client may not be able to clone from a
1446 remote or a legacy Mercurial client may not be able to clone from a
1447 modern Mercurial remote.
1447 modern Mercurial remote.
1448
1448
1449 .. note::
1449 .. note::
1450
1450
1451 Specifying a tag will include the tagged changeset but not the
1451 Specifying a tag will include the tagged changeset but not the
1452 changeset containing the tag.
1452 changeset containing the tag.
1453
1453
1454 .. container:: verbose
1454 .. container:: verbose
1455
1455
1456 For efficiency, hardlinks are used for cloning whenever the
1456 For efficiency, hardlinks are used for cloning whenever the
1457 source and destination are on the same filesystem (note this
1457 source and destination are on the same filesystem (note this
1458 applies only to the repository data, not to the working
1458 applies only to the repository data, not to the working
1459 directory). Some filesystems, such as AFS, implement hardlinking
1459 directory). Some filesystems, such as AFS, implement hardlinking
1460 incorrectly, but do not report errors. In these cases, use the
1460 incorrectly, but do not report errors. In these cases, use the
1461 --pull option to avoid hardlinking.
1461 --pull option to avoid hardlinking.
1462
1462
1463 Mercurial will update the working directory to the first applicable
1463 Mercurial will update the working directory to the first applicable
1464 revision from this list:
1464 revision from this list:
1465
1465
1466 a) null if -U or the source repository has no changesets
1466 a) null if -U or the source repository has no changesets
1467 b) if -u . and the source repository is local, the first parent of
1467 b) if -u . and the source repository is local, the first parent of
1468 the source repository's working directory
1468 the source repository's working directory
1469 c) the changeset specified with -u (if a branch name, this means the
1469 c) the changeset specified with -u (if a branch name, this means the
1470 latest head of that branch)
1470 latest head of that branch)
1471 d) the changeset specified with -r
1471 d) the changeset specified with -r
1472 e) the tipmost head specified with -b
1472 e) the tipmost head specified with -b
1473 f) the tipmost head specified with the url#branch source syntax
1473 f) the tipmost head specified with the url#branch source syntax
1474 g) the revision marked with the '@' bookmark, if present
1474 g) the revision marked with the '@' bookmark, if present
1475 h) the tipmost head of the default branch
1475 h) the tipmost head of the default branch
1476 i) tip
1476 i) tip
1477
1477
1478 When cloning from servers that support it, Mercurial may fetch
1478 When cloning from servers that support it, Mercurial may fetch
1479 pre-generated data from a server-advertised URL or inline from the
1479 pre-generated data from a server-advertised URL or inline from the
1480 same stream. When this is done, hooks operating on incoming changesets
1480 same stream. When this is done, hooks operating on incoming changesets
1481 and changegroups may fire more than once, once for each pre-generated
1481 and changegroups may fire more than once, once for each pre-generated
1482 bundle and as well as for any additional remaining data. In addition,
1482 bundle and as well as for any additional remaining data. In addition,
1483 if an error occurs, the repository may be rolled back to a partial
1483 if an error occurs, the repository may be rolled back to a partial
1484 clone. This behavior may change in future releases.
1484 clone. This behavior may change in future releases.
1485 See :hg:`help -e clonebundles` for more.
1485 See :hg:`help -e clonebundles` for more.
1486
1486
1487 Examples:
1487 Examples:
1488
1488
1489 - clone a remote repository to a new directory named hg/::
1489 - clone a remote repository to a new directory named hg/::
1490
1490
1491 hg clone https://www.mercurial-scm.org/repo/hg/
1491 hg clone https://www.mercurial-scm.org/repo/hg/
1492
1492
1493 - create a lightweight local clone::
1493 - create a lightweight local clone::
1494
1494
1495 hg clone project/ project-feature/
1495 hg clone project/ project-feature/
1496
1496
1497 - clone from an absolute path on an ssh server (note double-slash)::
1497 - clone from an absolute path on an ssh server (note double-slash)::
1498
1498
1499 hg clone ssh://user@server//home/projects/alpha/
1499 hg clone ssh://user@server//home/projects/alpha/
1500
1500
1501 - do a streaming clone while checking out a specified version::
1501 - do a streaming clone while checking out a specified version::
1502
1502
1503 hg clone --stream http://server/repo -u 1.5
1503 hg clone --stream http://server/repo -u 1.5
1504
1504
1505 - create a repository without changesets after a particular revision::
1505 - create a repository without changesets after a particular revision::
1506
1506
1507 hg clone -r 04e544 experimental/ good/
1507 hg clone -r 04e544 experimental/ good/
1508
1508
1509 - clone (and track) a particular named branch::
1509 - clone (and track) a particular named branch::
1510
1510
1511 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1511 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1512
1512
1513 See :hg:`help urls` for details on specifying URLs.
1513 See :hg:`help urls` for details on specifying URLs.
1514
1514
1515 Returns 0 on success.
1515 Returns 0 on success.
1516 """
1516 """
1517 opts = pycompat.byteskwargs(opts)
1517 opts = pycompat.byteskwargs(opts)
1518 if opts.get('noupdate') and opts.get('updaterev'):
1518 if opts.get('noupdate') and opts.get('updaterev'):
1519 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1519 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1520
1520
1521 # --include/--exclude can come from narrow or sparse.
1521 # --include/--exclude can come from narrow or sparse.
1522 includepats, excludepats = None, None
1522 includepats, excludepats = None, None
1523
1523
1524 # hg.clone() differentiates between None and an empty set. So make sure
1524 # hg.clone() differentiates between None and an empty set. So make sure
1525 # patterns are sets if narrow is requested without patterns.
1525 # patterns are sets if narrow is requested without patterns.
1526 if opts.get('narrow'):
1526 if opts.get('narrow'):
1527 includepats = set()
1527 includepats = set()
1528 excludepats = set()
1528 excludepats = set()
1529
1529
1530 if opts.get('include'):
1530 if opts.get('include'):
1531 includepats = narrowspec.parsepatterns(opts.get('include'))
1531 includepats = narrowspec.parsepatterns(opts.get('include'))
1532 if opts.get('exclude'):
1532 if opts.get('exclude'):
1533 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1533 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1534
1534
1535 r = hg.clone(ui, opts, source, dest,
1535 r = hg.clone(ui, opts, source, dest,
1536 pull=opts.get('pull'),
1536 pull=opts.get('pull'),
1537 stream=opts.get('stream') or opts.get('uncompressed'),
1537 stream=opts.get('stream') or opts.get('uncompressed'),
1538 revs=opts.get('rev'),
1538 revs=opts.get('rev'),
1539 update=opts.get('updaterev') or not opts.get('noupdate'),
1539 update=opts.get('updaterev') or not opts.get('noupdate'),
1540 branch=opts.get('branch'),
1540 branch=opts.get('branch'),
1541 shareopts=opts.get('shareopts'),
1541 shareopts=opts.get('shareopts'),
1542 storeincludepats=includepats,
1542 storeincludepats=includepats,
1543 storeexcludepats=excludepats)
1543 storeexcludepats=excludepats)
1544
1544
1545 return r is None
1545 return r is None
1546
1546
1547 @command('^commit|ci',
1547 @command('^commit|ci',
1548 [('A', 'addremove', None,
1548 [('A', 'addremove', None,
1549 _('mark new/missing files as added/removed before committing')),
1549 _('mark new/missing files as added/removed before committing')),
1550 ('', 'close-branch', None,
1550 ('', 'close-branch', None,
1551 _('mark a branch head as closed')),
1551 _('mark a branch head as closed')),
1552 ('', 'amend', None, _('amend the parent of the working directory')),
1552 ('', 'amend', None, _('amend the parent of the working directory')),
1553 ('s', 'secret', None, _('use the secret phase for committing')),
1553 ('s', 'secret', None, _('use the secret phase for committing')),
1554 ('e', 'edit', None, _('invoke editor on commit messages')),
1554 ('e', 'edit', None, _('invoke editor on commit messages')),
1555 ('i', 'interactive', None, _('use interactive mode')),
1555 ('i', 'interactive', None, _('use interactive mode')),
1556 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1556 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1557 _('[OPTION]... [FILE]...'),
1557 _('[OPTION]... [FILE]...'),
1558 inferrepo=True)
1558 inferrepo=True)
1559 def commit(ui, repo, *pats, **opts):
1559 def commit(ui, repo, *pats, **opts):
1560 """commit the specified files or all outstanding changes
1560 """commit the specified files or all outstanding changes
1561
1561
1562 Commit changes to the given files into the repository. Unlike a
1562 Commit changes to the given files into the repository. Unlike a
1563 centralized SCM, this operation is a local operation. See
1563 centralized SCM, this operation is a local operation. See
1564 :hg:`push` for a way to actively distribute your changes.
1564 :hg:`push` for a way to actively distribute your changes.
1565
1565
1566 If a list of files is omitted, all changes reported by :hg:`status`
1566 If a list of files is omitted, all changes reported by :hg:`status`
1567 will be committed.
1567 will be committed.
1568
1568
1569 If you are committing the result of a merge, do not provide any
1569 If you are committing the result of a merge, do not provide any
1570 filenames or -I/-X filters.
1570 filenames or -I/-X filters.
1571
1571
1572 If no commit message is specified, Mercurial starts your
1572 If no commit message is specified, Mercurial starts your
1573 configured editor where you can enter a message. In case your
1573 configured editor where you can enter a message. In case your
1574 commit fails, you will find a backup of your message in
1574 commit fails, you will find a backup of your message in
1575 ``.hg/last-message.txt``.
1575 ``.hg/last-message.txt``.
1576
1576
1577 The --close-branch flag can be used to mark the current branch
1577 The --close-branch flag can be used to mark the current branch
1578 head closed. When all heads of a branch are closed, the branch
1578 head closed. When all heads of a branch are closed, the branch
1579 will be considered closed and no longer listed.
1579 will be considered closed and no longer listed.
1580
1580
1581 The --amend flag can be used to amend the parent of the
1581 The --amend flag can be used to amend the parent of the
1582 working directory with a new commit that contains the changes
1582 working directory with a new commit that contains the changes
1583 in the parent in addition to those currently reported by :hg:`status`,
1583 in the parent in addition to those currently reported by :hg:`status`,
1584 if there are any. The old commit is stored in a backup bundle in
1584 if there are any. The old commit is stored in a backup bundle in
1585 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1585 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1586 on how to restore it).
1586 on how to restore it).
1587
1587
1588 Message, user and date are taken from the amended commit unless
1588 Message, user and date are taken from the amended commit unless
1589 specified. When a message isn't specified on the command line,
1589 specified. When a message isn't specified on the command line,
1590 the editor will open with the message of the amended commit.
1590 the editor will open with the message of the amended commit.
1591
1591
1592 It is not possible to amend public changesets (see :hg:`help phases`)
1592 It is not possible to amend public changesets (see :hg:`help phases`)
1593 or changesets that have children.
1593 or changesets that have children.
1594
1594
1595 See :hg:`help dates` for a list of formats valid for -d/--date.
1595 See :hg:`help dates` for a list of formats valid for -d/--date.
1596
1596
1597 Returns 0 on success, 1 if nothing changed.
1597 Returns 0 on success, 1 if nothing changed.
1598
1598
1599 .. container:: verbose
1599 .. container:: verbose
1600
1600
1601 Examples:
1601 Examples:
1602
1602
1603 - commit all files ending in .py::
1603 - commit all files ending in .py::
1604
1604
1605 hg commit --include "set:**.py"
1605 hg commit --include "set:**.py"
1606
1606
1607 - commit all non-binary files::
1607 - commit all non-binary files::
1608
1608
1609 hg commit --exclude "set:binary()"
1609 hg commit --exclude "set:binary()"
1610
1610
1611 - amend the current commit and set the date to now::
1611 - amend the current commit and set the date to now::
1612
1612
1613 hg commit --amend --date now
1613 hg commit --amend --date now
1614 """
1614 """
1615 with repo.wlock(), repo.lock():
1615 with repo.wlock(), repo.lock():
1616 return _docommit(ui, repo, *pats, **opts)
1616 return _docommit(ui, repo, *pats, **opts)
1617
1617
1618 def _docommit(ui, repo, *pats, **opts):
1618 def _docommit(ui, repo, *pats, **opts):
1619 if opts.get(r'interactive'):
1619 if opts.get(r'interactive'):
1620 opts.pop(r'interactive')
1620 opts.pop(r'interactive')
1621 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1621 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1622 cmdutil.recordfilter, *pats,
1622 cmdutil.recordfilter, *pats,
1623 **opts)
1623 **opts)
1624 # ret can be 0 (no changes to record) or the value returned by
1624 # ret can be 0 (no changes to record) or the value returned by
1625 # commit(), 1 if nothing changed or None on success.
1625 # commit(), 1 if nothing changed or None on success.
1626 return 1 if ret == 0 else ret
1626 return 1 if ret == 0 else ret
1627
1627
1628 opts = pycompat.byteskwargs(opts)
1628 opts = pycompat.byteskwargs(opts)
1629 if opts.get('subrepos'):
1629 if opts.get('subrepos'):
1630 if opts.get('amend'):
1630 if opts.get('amend'):
1631 raise error.Abort(_('cannot amend with --subrepos'))
1631 raise error.Abort(_('cannot amend with --subrepos'))
1632 # Let --subrepos on the command line override config setting.
1632 # Let --subrepos on the command line override config setting.
1633 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1633 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1634
1634
1635 cmdutil.checkunfinished(repo, commit=True)
1635 cmdutil.checkunfinished(repo, commit=True)
1636
1636
1637 branch = repo[None].branch()
1637 branch = repo[None].branch()
1638 bheads = repo.branchheads(branch)
1638 bheads = repo.branchheads(branch)
1639
1639
1640 extra = {}
1640 extra = {}
1641 if opts.get('close_branch'):
1641 if opts.get('close_branch'):
1642 extra['close'] = '1'
1642 extra['close'] = '1'
1643
1643
1644 if not bheads:
1644 if not bheads:
1645 raise error.Abort(_('can only close branch heads'))
1645 raise error.Abort(_('can only close branch heads'))
1646 elif opts.get('amend'):
1646 elif opts.get('amend'):
1647 if repo[None].parents()[0].p1().branch() != branch and \
1647 if repo[None].parents()[0].p1().branch() != branch and \
1648 repo[None].parents()[0].p2().branch() != branch:
1648 repo[None].parents()[0].p2().branch() != branch:
1649 raise error.Abort(_('can only close branch heads'))
1649 raise error.Abort(_('can only close branch heads'))
1650
1650
1651 if opts.get('amend'):
1651 if opts.get('amend'):
1652 if ui.configbool('ui', 'commitsubrepos'):
1652 if ui.configbool('ui', 'commitsubrepos'):
1653 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1653 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1654
1654
1655 old = repo['.']
1655 old = repo['.']
1656 rewriteutil.precheck(repo, [old.rev()], 'amend')
1656 rewriteutil.precheck(repo, [old.rev()], 'amend')
1657
1657
1658 # Currently histedit gets confused if an amend happens while histedit
1658 # Currently histedit gets confused if an amend happens while histedit
1659 # is in progress. Since we have a checkunfinished command, we are
1659 # is in progress. Since we have a checkunfinished command, we are
1660 # temporarily honoring it.
1660 # temporarily honoring it.
1661 #
1661 #
1662 # Note: eventually this guard will be removed. Please do not expect
1662 # Note: eventually this guard will be removed. Please do not expect
1663 # this behavior to remain.
1663 # this behavior to remain.
1664 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1664 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1665 cmdutil.checkunfinished(repo)
1665 cmdutil.checkunfinished(repo)
1666
1666
1667 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1667 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1668 if node == old.node():
1668 if node == old.node():
1669 ui.status(_("nothing changed\n"))
1669 ui.status(_("nothing changed\n"))
1670 return 1
1670 return 1
1671 else:
1671 else:
1672 def commitfunc(ui, repo, message, match, opts):
1672 def commitfunc(ui, repo, message, match, opts):
1673 overrides = {}
1673 overrides = {}
1674 if opts.get('secret'):
1674 if opts.get('secret'):
1675 overrides[('phases', 'new-commit')] = 'secret'
1675 overrides[('phases', 'new-commit')] = 'secret'
1676
1676
1677 baseui = repo.baseui
1677 baseui = repo.baseui
1678 with baseui.configoverride(overrides, 'commit'):
1678 with baseui.configoverride(overrides, 'commit'):
1679 with ui.configoverride(overrides, 'commit'):
1679 with ui.configoverride(overrides, 'commit'):
1680 editform = cmdutil.mergeeditform(repo[None],
1680 editform = cmdutil.mergeeditform(repo[None],
1681 'commit.normal')
1681 'commit.normal')
1682 editor = cmdutil.getcommiteditor(
1682 editor = cmdutil.getcommiteditor(
1683 editform=editform, **pycompat.strkwargs(opts))
1683 editform=editform, **pycompat.strkwargs(opts))
1684 return repo.commit(message,
1684 return repo.commit(message,
1685 opts.get('user'),
1685 opts.get('user'),
1686 opts.get('date'),
1686 opts.get('date'),
1687 match,
1687 match,
1688 editor=editor,
1688 editor=editor,
1689 extra=extra)
1689 extra=extra)
1690
1690
1691 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1691 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1692
1692
1693 if not node:
1693 if not node:
1694 stat = cmdutil.postcommitstatus(repo, pats, opts)
1694 stat = cmdutil.postcommitstatus(repo, pats, opts)
1695 if stat[3]:
1695 if stat[3]:
1696 ui.status(_("nothing changed (%d missing files, see "
1696 ui.status(_("nothing changed (%d missing files, see "
1697 "'hg status')\n") % len(stat[3]))
1697 "'hg status')\n") % len(stat[3]))
1698 else:
1698 else:
1699 ui.status(_("nothing changed\n"))
1699 ui.status(_("nothing changed\n"))
1700 return 1
1700 return 1
1701
1701
1702 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1702 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1703
1703
1704 @command('config|showconfig|debugconfig',
1704 @command('config|showconfig|debugconfig',
1705 [('u', 'untrusted', None, _('show untrusted configuration options')),
1705 [('u', 'untrusted', None, _('show untrusted configuration options')),
1706 ('e', 'edit', None, _('edit user config')),
1706 ('e', 'edit', None, _('edit user config')),
1707 ('l', 'local', None, _('edit repository config')),
1707 ('l', 'local', None, _('edit repository config')),
1708 ('g', 'global', None, _('edit global config'))] + formatteropts,
1708 ('g', 'global', None, _('edit global config'))] + formatteropts,
1709 _('[-u] [NAME]...'),
1709 _('[-u] [NAME]...'),
1710 optionalrepo=True,
1710 optionalrepo=True,
1711 intents={INTENT_READONLY})
1711 intents={INTENT_READONLY})
1712 def config(ui, repo, *values, **opts):
1712 def config(ui, repo, *values, **opts):
1713 """show combined config settings from all hgrc files
1713 """show combined config settings from all hgrc files
1714
1714
1715 With no arguments, print names and values of all config items.
1715 With no arguments, print names and values of all config items.
1716
1716
1717 With one argument of the form section.name, print just the value
1717 With one argument of the form section.name, print just the value
1718 of that config item.
1718 of that config item.
1719
1719
1720 With multiple arguments, print names and values of all config
1720 With multiple arguments, print names and values of all config
1721 items with matching section names or section.names.
1721 items with matching section names or section.names.
1722
1722
1723 With --edit, start an editor on the user-level config file. With
1723 With --edit, start an editor on the user-level config file. With
1724 --global, edit the system-wide config file. With --local, edit the
1724 --global, edit the system-wide config file. With --local, edit the
1725 repository-level config file.
1725 repository-level config file.
1726
1726
1727 With --debug, the source (filename and line number) is printed
1727 With --debug, the source (filename and line number) is printed
1728 for each config item.
1728 for each config item.
1729
1729
1730 See :hg:`help config` for more information about config files.
1730 See :hg:`help config` for more information about config files.
1731
1731
1732 .. container:: verbose
1732 .. container:: verbose
1733
1733
1734 Template:
1734 Template:
1735
1735
1736 The following keywords are supported. See also :hg:`help templates`.
1736 The following keywords are supported. See also :hg:`help templates`.
1737
1737
1738 :name: String. Config name.
1738 :name: String. Config name.
1739 :source: String. Filename and line number where the item is defined.
1739 :source: String. Filename and line number where the item is defined.
1740 :value: String. Config value.
1740 :value: String. Config value.
1741
1741
1742 Returns 0 on success, 1 if NAME does not exist.
1742 Returns 0 on success, 1 if NAME does not exist.
1743
1743
1744 """
1744 """
1745
1745
1746 opts = pycompat.byteskwargs(opts)
1746 opts = pycompat.byteskwargs(opts)
1747 if opts.get('edit') or opts.get('local') or opts.get('global'):
1747 if opts.get('edit') or opts.get('local') or opts.get('global'):
1748 if opts.get('local') and opts.get('global'):
1748 if opts.get('local') and opts.get('global'):
1749 raise error.Abort(_("can't use --local and --global together"))
1749 raise error.Abort(_("can't use --local and --global together"))
1750
1750
1751 if opts.get('local'):
1751 if opts.get('local'):
1752 if not repo:
1752 if not repo:
1753 raise error.Abort(_("can't use --local outside a repository"))
1753 raise error.Abort(_("can't use --local outside a repository"))
1754 paths = [repo.vfs.join('hgrc')]
1754 paths = [repo.vfs.join('hgrc')]
1755 elif opts.get('global'):
1755 elif opts.get('global'):
1756 paths = rcutil.systemrcpath()
1756 paths = rcutil.systemrcpath()
1757 else:
1757 else:
1758 paths = rcutil.userrcpath()
1758 paths = rcutil.userrcpath()
1759
1759
1760 for f in paths:
1760 for f in paths:
1761 if os.path.exists(f):
1761 if os.path.exists(f):
1762 break
1762 break
1763 else:
1763 else:
1764 if opts.get('global'):
1764 if opts.get('global'):
1765 samplehgrc = uimod.samplehgrcs['global']
1765 samplehgrc = uimod.samplehgrcs['global']
1766 elif opts.get('local'):
1766 elif opts.get('local'):
1767 samplehgrc = uimod.samplehgrcs['local']
1767 samplehgrc = uimod.samplehgrcs['local']
1768 else:
1768 else:
1769 samplehgrc = uimod.samplehgrcs['user']
1769 samplehgrc = uimod.samplehgrcs['user']
1770
1770
1771 f = paths[0]
1771 f = paths[0]
1772 fp = open(f, "wb")
1772 fp = open(f, "wb")
1773 fp.write(util.tonativeeol(samplehgrc))
1773 fp.write(util.tonativeeol(samplehgrc))
1774 fp.close()
1774 fp.close()
1775
1775
1776 editor = ui.geteditor()
1776 editor = ui.geteditor()
1777 ui.system("%s \"%s\"" % (editor, f),
1777 ui.system("%s \"%s\"" % (editor, f),
1778 onerr=error.Abort, errprefix=_("edit failed"),
1778 onerr=error.Abort, errprefix=_("edit failed"),
1779 blockedtag='config_edit')
1779 blockedtag='config_edit')
1780 return
1780 return
1781 ui.pager('config')
1781 ui.pager('config')
1782 fm = ui.formatter('config', opts)
1782 fm = ui.formatter('config', opts)
1783 for t, f in rcutil.rccomponents():
1783 for t, f in rcutil.rccomponents():
1784 if t == 'path':
1784 if t == 'path':
1785 ui.debug('read config from: %s\n' % f)
1785 ui.debug('read config from: %s\n' % f)
1786 elif t == 'items':
1786 elif t == 'items':
1787 for section, name, value, source in f:
1787 for section, name, value, source in f:
1788 ui.debug('set config by: %s\n' % source)
1788 ui.debug('set config by: %s\n' % source)
1789 else:
1789 else:
1790 raise error.ProgrammingError('unknown rctype: %s' % t)
1790 raise error.ProgrammingError('unknown rctype: %s' % t)
1791 untrusted = bool(opts.get('untrusted'))
1791 untrusted = bool(opts.get('untrusted'))
1792
1792
1793 selsections = selentries = []
1793 selsections = selentries = []
1794 if values:
1794 if values:
1795 selsections = [v for v in values if '.' not in v]
1795 selsections = [v for v in values if '.' not in v]
1796 selentries = [v for v in values if '.' in v]
1796 selentries = [v for v in values if '.' in v]
1797 uniquesel = (len(selentries) == 1 and not selsections)
1797 uniquesel = (len(selentries) == 1 and not selsections)
1798 selsections = set(selsections)
1798 selsections = set(selsections)
1799 selentries = set(selentries)
1799 selentries = set(selentries)
1800
1800
1801 matched = False
1801 matched = False
1802 for section, name, value in ui.walkconfig(untrusted=untrusted):
1802 for section, name, value in ui.walkconfig(untrusted=untrusted):
1803 source = ui.configsource(section, name, untrusted)
1803 source = ui.configsource(section, name, untrusted)
1804 value = pycompat.bytestr(value)
1804 value = pycompat.bytestr(value)
1805 if fm.isplain():
1805 if fm.isplain():
1806 source = source or 'none'
1806 source = source or 'none'
1807 value = value.replace('\n', '\\n')
1807 value = value.replace('\n', '\\n')
1808 entryname = section + '.' + name
1808 entryname = section + '.' + name
1809 if values and not (section in selsections or entryname in selentries):
1809 if values and not (section in selsections or entryname in selentries):
1810 continue
1810 continue
1811 fm.startitem()
1811 fm.startitem()
1812 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1812 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1813 if uniquesel:
1813 if uniquesel:
1814 fm.data(name=entryname)
1814 fm.data(name=entryname)
1815 fm.write('value', '%s\n', value)
1815 fm.write('value', '%s\n', value)
1816 else:
1816 else:
1817 fm.write('name value', '%s=%s\n', entryname, value)
1817 fm.write('name value', '%s=%s\n', entryname, value)
1818 matched = True
1818 matched = True
1819 fm.end()
1819 fm.end()
1820 if matched:
1820 if matched:
1821 return 0
1821 return 0
1822 return 1
1822 return 1
1823
1823
1824 @command('copy|cp',
1824 @command('copy|cp',
1825 [('A', 'after', None, _('record a copy that has already occurred')),
1825 [('A', 'after', None, _('record a copy that has already occurred')),
1826 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1826 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1827 ] + walkopts + dryrunopts,
1827 ] + walkopts + dryrunopts,
1828 _('[OPTION]... [SOURCE]... DEST'))
1828 _('[OPTION]... [SOURCE]... DEST'))
1829 def copy(ui, repo, *pats, **opts):
1829 def copy(ui, repo, *pats, **opts):
1830 """mark files as copied for the next commit
1830 """mark files as copied for the next commit
1831
1831
1832 Mark dest as having copies of source files. If dest is a
1832 Mark dest as having copies of source files. If dest is a
1833 directory, copies are put in that directory. If dest is a file,
1833 directory, copies are put in that directory. If dest is a file,
1834 the source must be a single file.
1834 the source must be a single file.
1835
1835
1836 By default, this command copies the contents of files as they
1836 By default, this command copies the contents of files as they
1837 exist in the working directory. If invoked with -A/--after, the
1837 exist in the working directory. If invoked with -A/--after, the
1838 operation is recorded, but no copying is performed.
1838 operation is recorded, but no copying is performed.
1839
1839
1840 This command takes effect with the next commit. To undo a copy
1840 This command takes effect with the next commit. To undo a copy
1841 before that, see :hg:`revert`.
1841 before that, see :hg:`revert`.
1842
1842
1843 Returns 0 on success, 1 if errors are encountered.
1843 Returns 0 on success, 1 if errors are encountered.
1844 """
1844 """
1845 opts = pycompat.byteskwargs(opts)
1845 opts = pycompat.byteskwargs(opts)
1846 with repo.wlock(False):
1846 with repo.wlock(False):
1847 return cmdutil.copy(ui, repo, pats, opts)
1847 return cmdutil.copy(ui, repo, pats, opts)
1848
1848
1849 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1849 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1850 def debugcommands(ui, cmd='', *args):
1850 def debugcommands(ui, cmd='', *args):
1851 """list all available commands and options"""
1851 """list all available commands and options"""
1852 for cmd, vals in sorted(table.iteritems()):
1852 for cmd, vals in sorted(table.iteritems()):
1853 cmd = cmd.split('|')[0].strip('^')
1853 cmd = cmd.split('|')[0].strip('^')
1854 opts = ', '.join([i[1] for i in vals[1]])
1854 opts = ', '.join([i[1] for i in vals[1]])
1855 ui.write('%s: %s\n' % (cmd, opts))
1855 ui.write('%s: %s\n' % (cmd, opts))
1856
1856
1857 @command('debugcomplete',
1857 @command('debugcomplete',
1858 [('o', 'options', None, _('show the command options'))],
1858 [('o', 'options', None, _('show the command options'))],
1859 _('[-o] CMD'),
1859 _('[-o] CMD'),
1860 norepo=True)
1860 norepo=True)
1861 def debugcomplete(ui, cmd='', **opts):
1861 def debugcomplete(ui, cmd='', **opts):
1862 """returns the completion list associated with the given command"""
1862 """returns the completion list associated with the given command"""
1863
1863
1864 if opts.get(r'options'):
1864 if opts.get(r'options'):
1865 options = []
1865 options = []
1866 otables = [globalopts]
1866 otables = [globalopts]
1867 if cmd:
1867 if cmd:
1868 aliases, entry = cmdutil.findcmd(cmd, table, False)
1868 aliases, entry = cmdutil.findcmd(cmd, table, False)
1869 otables.append(entry[1])
1869 otables.append(entry[1])
1870 for t in otables:
1870 for t in otables:
1871 for o in t:
1871 for o in t:
1872 if "(DEPRECATED)" in o[3]:
1872 if "(DEPRECATED)" in o[3]:
1873 continue
1873 continue
1874 if o[0]:
1874 if o[0]:
1875 options.append('-%s' % o[0])
1875 options.append('-%s' % o[0])
1876 options.append('--%s' % o[1])
1876 options.append('--%s' % o[1])
1877 ui.write("%s\n" % "\n".join(options))
1877 ui.write("%s\n" % "\n".join(options))
1878 return
1878 return
1879
1879
1880 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1880 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1881 if ui.verbose:
1881 if ui.verbose:
1882 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1882 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1883 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1883 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1884
1884
1885 @command('^diff',
1885 @command('^diff',
1886 [('r', 'rev', [], _('revision'), _('REV')),
1886 [('r', 'rev', [], _('revision'), _('REV')),
1887 ('c', 'change', '', _('change made by revision'), _('REV'))
1887 ('c', 'change', '', _('change made by revision'), _('REV'))
1888 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1888 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1889 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1889 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1890 inferrepo=True,
1890 inferrepo=True,
1891 intents={INTENT_READONLY})
1891 intents={INTENT_READONLY})
1892 def diff(ui, repo, *pats, **opts):
1892 def diff(ui, repo, *pats, **opts):
1893 """diff repository (or selected files)
1893 """diff repository (or selected files)
1894
1894
1895 Show differences between revisions for the specified files.
1895 Show differences between revisions for the specified files.
1896
1896
1897 Differences between files are shown using the unified diff format.
1897 Differences between files are shown using the unified diff format.
1898
1898
1899 .. note::
1899 .. note::
1900
1900
1901 :hg:`diff` may generate unexpected results for merges, as it will
1901 :hg:`diff` may generate unexpected results for merges, as it will
1902 default to comparing against the working directory's first
1902 default to comparing against the working directory's first
1903 parent changeset if no revisions are specified.
1903 parent changeset if no revisions are specified.
1904
1904
1905 When two revision arguments are given, then changes are shown
1905 When two revision arguments are given, then changes are shown
1906 between those revisions. If only one revision is specified then
1906 between those revisions. If only one revision is specified then
1907 that revision is compared to the working directory, and, when no
1907 that revision is compared to the working directory, and, when no
1908 revisions are specified, the working directory files are compared
1908 revisions are specified, the working directory files are compared
1909 to its first parent.
1909 to its first parent.
1910
1910
1911 Alternatively you can specify -c/--change with a revision to see
1911 Alternatively you can specify -c/--change with a revision to see
1912 the changes in that changeset relative to its first parent.
1912 the changes in that changeset relative to its first parent.
1913
1913
1914 Without the -a/--text option, diff will avoid generating diffs of
1914 Without the -a/--text option, diff will avoid generating diffs of
1915 files it detects as binary. With -a, diff will generate a diff
1915 files it detects as binary. With -a, diff will generate a diff
1916 anyway, probably with undesirable results.
1916 anyway, probably with undesirable results.
1917
1917
1918 Use the -g/--git option to generate diffs in the git extended diff
1918 Use the -g/--git option to generate diffs in the git extended diff
1919 format. For more information, read :hg:`help diffs`.
1919 format. For more information, read :hg:`help diffs`.
1920
1920
1921 .. container:: verbose
1921 .. container:: verbose
1922
1922
1923 Examples:
1923 Examples:
1924
1924
1925 - compare a file in the current working directory to its parent::
1925 - compare a file in the current working directory to its parent::
1926
1926
1927 hg diff foo.c
1927 hg diff foo.c
1928
1928
1929 - compare two historical versions of a directory, with rename info::
1929 - compare two historical versions of a directory, with rename info::
1930
1930
1931 hg diff --git -r 1.0:1.2 lib/
1931 hg diff --git -r 1.0:1.2 lib/
1932
1932
1933 - get change stats relative to the last change on some date::
1933 - get change stats relative to the last change on some date::
1934
1934
1935 hg diff --stat -r "date('may 2')"
1935 hg diff --stat -r "date('may 2')"
1936
1936
1937 - diff all newly-added files that contain a keyword::
1937 - diff all newly-added files that contain a keyword::
1938
1938
1939 hg diff "set:added() and grep(GNU)"
1939 hg diff "set:added() and grep(GNU)"
1940
1940
1941 - compare a revision and its parents::
1941 - compare a revision and its parents::
1942
1942
1943 hg diff -c 9353 # compare against first parent
1943 hg diff -c 9353 # compare against first parent
1944 hg diff -r 9353^:9353 # same using revset syntax
1944 hg diff -r 9353^:9353 # same using revset syntax
1945 hg diff -r 9353^2:9353 # compare against the second parent
1945 hg diff -r 9353^2:9353 # compare against the second parent
1946
1946
1947 Returns 0 on success.
1947 Returns 0 on success.
1948 """
1948 """
1949
1949
1950 opts = pycompat.byteskwargs(opts)
1950 opts = pycompat.byteskwargs(opts)
1951 revs = opts.get('rev')
1951 revs = opts.get('rev')
1952 change = opts.get('change')
1952 change = opts.get('change')
1953 stat = opts.get('stat')
1953 stat = opts.get('stat')
1954 reverse = opts.get('reverse')
1954 reverse = opts.get('reverse')
1955
1955
1956 if revs and change:
1956 if revs and change:
1957 msg = _('cannot specify --rev and --change at the same time')
1957 msg = _('cannot specify --rev and --change at the same time')
1958 raise error.Abort(msg)
1958 raise error.Abort(msg)
1959 elif change:
1959 elif change:
1960 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1960 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1961 ctx2 = scmutil.revsingle(repo, change, None)
1961 ctx2 = scmutil.revsingle(repo, change, None)
1962 ctx1 = ctx2.p1()
1962 ctx1 = ctx2.p1()
1963 else:
1963 else:
1964 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1964 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1965 ctx1, ctx2 = scmutil.revpair(repo, revs)
1965 ctx1, ctx2 = scmutil.revpair(repo, revs)
1966 node1, node2 = ctx1.node(), ctx2.node()
1966 node1, node2 = ctx1.node(), ctx2.node()
1967
1967
1968 if reverse:
1968 if reverse:
1969 node1, node2 = node2, node1
1969 node1, node2 = node2, node1
1970
1970
1971 diffopts = patch.diffallopts(ui, opts)
1971 diffopts = patch.diffallopts(ui, opts)
1972 m = scmutil.match(ctx2, pats, opts)
1972 m = scmutil.match(ctx2, pats, opts)
1973 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1973 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1974 ui.pager('diff')
1974 ui.pager('diff')
1975 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1975 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1976 listsubrepos=opts.get('subrepos'),
1976 listsubrepos=opts.get('subrepos'),
1977 root=opts.get('root'))
1977 root=opts.get('root'))
1978
1978
1979 @command('^export',
1979 @command('^export',
1980 [('B', 'bookmark', '',
1980 [('B', 'bookmark', '',
1981 _('export changes only reachable by given bookmark')),
1981 _('export changes only reachable by given bookmark')),
1982 ('o', 'output', '',
1982 ('o', 'output', '',
1983 _('print output to file with formatted name'), _('FORMAT')),
1983 _('print output to file with formatted name'), _('FORMAT')),
1984 ('', 'switch-parent', None, _('diff against the second parent')),
1984 ('', 'switch-parent', None, _('diff against the second parent')),
1985 ('r', 'rev', [], _('revisions to export'), _('REV')),
1985 ('r', 'rev', [], _('revisions to export'), _('REV')),
1986 ] + diffopts + formatteropts,
1986 ] + diffopts + formatteropts,
1987 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1987 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1988 intents={INTENT_READONLY})
1988 intents={INTENT_READONLY})
1989 def export(ui, repo, *changesets, **opts):
1989 def export(ui, repo, *changesets, **opts):
1990 """dump the header and diffs for one or more changesets
1990 """dump the header and diffs for one or more changesets
1991
1991
1992 Print the changeset header and diffs for one or more revisions.
1992 Print the changeset header and diffs for one or more revisions.
1993 If no revision is given, the parent of the working directory is used.
1993 If no revision is given, the parent of the working directory is used.
1994
1994
1995 The information shown in the changeset header is: author, date,
1995 The information shown in the changeset header is: author, date,
1996 branch name (if non-default), changeset hash, parent(s) and commit
1996 branch name (if non-default), changeset hash, parent(s) and commit
1997 comment.
1997 comment.
1998
1998
1999 .. note::
1999 .. note::
2000
2000
2001 :hg:`export` may generate unexpected diff output for merge
2001 :hg:`export` may generate unexpected diff output for merge
2002 changesets, as it will compare the merge changeset against its
2002 changesets, as it will compare the merge changeset against its
2003 first parent only.
2003 first parent only.
2004
2004
2005 Output may be to a file, in which case the name of the file is
2005 Output may be to a file, in which case the name of the file is
2006 given using a template string. See :hg:`help templates`. In addition
2006 given using a template string. See :hg:`help templates`. In addition
2007 to the common template keywords, the following formatting rules are
2007 to the common template keywords, the following formatting rules are
2008 supported:
2008 supported:
2009
2009
2010 :``%%``: literal "%" character
2010 :``%%``: literal "%" character
2011 :``%H``: changeset hash (40 hexadecimal digits)
2011 :``%H``: changeset hash (40 hexadecimal digits)
2012 :``%N``: number of patches being generated
2012 :``%N``: number of patches being generated
2013 :``%R``: changeset revision number
2013 :``%R``: changeset revision number
2014 :``%b``: basename of the exporting repository
2014 :``%b``: basename of the exporting repository
2015 :``%h``: short-form changeset hash (12 hexadecimal digits)
2015 :``%h``: short-form changeset hash (12 hexadecimal digits)
2016 :``%m``: first line of the commit message (only alphanumeric characters)
2016 :``%m``: first line of the commit message (only alphanumeric characters)
2017 :``%n``: zero-padded sequence number, starting at 1
2017 :``%n``: zero-padded sequence number, starting at 1
2018 :``%r``: zero-padded changeset revision number
2018 :``%r``: zero-padded changeset revision number
2019 :``\\``: literal "\\" character
2019 :``\\``: literal "\\" character
2020
2020
2021 Without the -a/--text option, export will avoid generating diffs
2021 Without the -a/--text option, export will avoid generating diffs
2022 of files it detects as binary. With -a, export will generate a
2022 of files it detects as binary. With -a, export will generate a
2023 diff anyway, probably with undesirable results.
2023 diff anyway, probably with undesirable results.
2024
2024
2025 With -B/--bookmark changesets reachable by the given bookmark are
2025 With -B/--bookmark changesets reachable by the given bookmark are
2026 selected.
2026 selected.
2027
2027
2028 Use the -g/--git option to generate diffs in the git extended diff
2028 Use the -g/--git option to generate diffs in the git extended diff
2029 format. See :hg:`help diffs` for more information.
2029 format. See :hg:`help diffs` for more information.
2030
2030
2031 With the --switch-parent option, the diff will be against the
2031 With the --switch-parent option, the diff will be against the
2032 second parent. It can be useful to review a merge.
2032 second parent. It can be useful to review a merge.
2033
2033
2034 .. container:: verbose
2034 .. container:: verbose
2035
2035
2036 Template:
2037
2038 The following keywords are supported in addition to the common template
2039 keywords and functions. See also :hg:`help templates`.
2040
2041 :diff: String. Diff content.
2042 :parents: List of strings. Parent nodes of the changeset.
2043
2036 Examples:
2044 Examples:
2037
2045
2038 - use export and import to transplant a bugfix to the current
2046 - use export and import to transplant a bugfix to the current
2039 branch::
2047 branch::
2040
2048
2041 hg export -r 9353 | hg import -
2049 hg export -r 9353 | hg import -
2042
2050
2043 - export all the changesets between two revisions to a file with
2051 - export all the changesets between two revisions to a file with
2044 rename information::
2052 rename information::
2045
2053
2046 hg export --git -r 123:150 > changes.txt
2054 hg export --git -r 123:150 > changes.txt
2047
2055
2048 - split outgoing changes into a series of patches with
2056 - split outgoing changes into a series of patches with
2049 descriptive names::
2057 descriptive names::
2050
2058
2051 hg export -r "outgoing()" -o "%n-%m.patch"
2059 hg export -r "outgoing()" -o "%n-%m.patch"
2052
2060
2053 Returns 0 on success.
2061 Returns 0 on success.
2054 """
2062 """
2055 opts = pycompat.byteskwargs(opts)
2063 opts = pycompat.byteskwargs(opts)
2056 bookmark = opts.get('bookmark')
2064 bookmark = opts.get('bookmark')
2057 changesets += tuple(opts.get('rev', []))
2065 changesets += tuple(opts.get('rev', []))
2058
2066
2059 if bookmark and changesets:
2067 if bookmark and changesets:
2060 raise error.Abort(_("-r and -B are mutually exclusive"))
2068 raise error.Abort(_("-r and -B are mutually exclusive"))
2061
2069
2062 if bookmark:
2070 if bookmark:
2063 if bookmark not in repo._bookmarks:
2071 if bookmark not in repo._bookmarks:
2064 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2072 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2065
2073
2066 revs = scmutil.bookmarkrevs(repo, bookmark)
2074 revs = scmutil.bookmarkrevs(repo, bookmark)
2067 else:
2075 else:
2068 if not changesets:
2076 if not changesets:
2069 changesets = ['.']
2077 changesets = ['.']
2070
2078
2071 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2079 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2072 revs = scmutil.revrange(repo, changesets)
2080 revs = scmutil.revrange(repo, changesets)
2073
2081
2074 if not revs:
2082 if not revs:
2075 raise error.Abort(_("export requires at least one changeset"))
2083 raise error.Abort(_("export requires at least one changeset"))
2076 if len(revs) > 1:
2084 if len(revs) > 1:
2077 ui.note(_('exporting patches:\n'))
2085 ui.note(_('exporting patches:\n'))
2078 else:
2086 else:
2079 ui.note(_('exporting patch:\n'))
2087 ui.note(_('exporting patch:\n'))
2080
2088
2081 fntemplate = opts.get('output')
2089 fntemplate = opts.get('output')
2082 if cmdutil.isstdiofilename(fntemplate):
2090 if cmdutil.isstdiofilename(fntemplate):
2083 fntemplate = ''
2091 fntemplate = ''
2084
2092
2085 if fntemplate:
2093 if fntemplate:
2086 fm = formatter.nullformatter(ui, 'export', opts)
2094 fm = formatter.nullformatter(ui, 'export', opts)
2087 else:
2095 else:
2088 ui.pager('export')
2096 ui.pager('export')
2089 fm = ui.formatter('export', opts)
2097 fm = ui.formatter('export', opts)
2090 with fm:
2098 with fm:
2091 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2099 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2092 switch_parent=opts.get('switch_parent'),
2100 switch_parent=opts.get('switch_parent'),
2093 opts=patch.diffallopts(ui, opts))
2101 opts=patch.diffallopts(ui, opts))
2094
2102
2095 @command('files',
2103 @command('files',
2096 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2104 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2097 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2105 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2098 ] + walkopts + formatteropts + subrepoopts,
2106 ] + walkopts + formatteropts + subrepoopts,
2099 _('[OPTION]... [FILE]...'),
2107 _('[OPTION]... [FILE]...'),
2100 intents={INTENT_READONLY})
2108 intents={INTENT_READONLY})
2101 def files(ui, repo, *pats, **opts):
2109 def files(ui, repo, *pats, **opts):
2102 """list tracked files
2110 """list tracked files
2103
2111
2104 Print files under Mercurial control in the working directory or
2112 Print files under Mercurial control in the working directory or
2105 specified revision for given files (excluding removed files).
2113 specified revision for given files (excluding removed files).
2106 Files can be specified as filenames or filesets.
2114 Files can be specified as filenames or filesets.
2107
2115
2108 If no files are given to match, this command prints the names
2116 If no files are given to match, this command prints the names
2109 of all files under Mercurial control.
2117 of all files under Mercurial control.
2110
2118
2111 .. container:: verbose
2119 .. container:: verbose
2112
2120
2113 Template:
2121 Template:
2114
2122
2115 The following keywords are supported in addition to the common template
2123 The following keywords are supported in addition to the common template
2116 keywords and functions. See also :hg:`help templates`.
2124 keywords and functions. See also :hg:`help templates`.
2117
2125
2118 :flags: String. Character denoting file's symlink and executable bits.
2126 :flags: String. Character denoting file's symlink and executable bits.
2119 :path: String. Repository-absolute path of the file.
2127 :path: String. Repository-absolute path of the file.
2120 :size: Integer. Size of the file in bytes.
2128 :size: Integer. Size of the file in bytes.
2121
2129
2122 Examples:
2130 Examples:
2123
2131
2124 - list all files under the current directory::
2132 - list all files under the current directory::
2125
2133
2126 hg files .
2134 hg files .
2127
2135
2128 - shows sizes and flags for current revision::
2136 - shows sizes and flags for current revision::
2129
2137
2130 hg files -vr .
2138 hg files -vr .
2131
2139
2132 - list all files named README::
2140 - list all files named README::
2133
2141
2134 hg files -I "**/README"
2142 hg files -I "**/README"
2135
2143
2136 - list all binary files::
2144 - list all binary files::
2137
2145
2138 hg files "set:binary()"
2146 hg files "set:binary()"
2139
2147
2140 - find files containing a regular expression::
2148 - find files containing a regular expression::
2141
2149
2142 hg files "set:grep('bob')"
2150 hg files "set:grep('bob')"
2143
2151
2144 - search tracked file contents with xargs and grep::
2152 - search tracked file contents with xargs and grep::
2145
2153
2146 hg files -0 | xargs -0 grep foo
2154 hg files -0 | xargs -0 grep foo
2147
2155
2148 See :hg:`help patterns` and :hg:`help filesets` for more information
2156 See :hg:`help patterns` and :hg:`help filesets` for more information
2149 on specifying file patterns.
2157 on specifying file patterns.
2150
2158
2151 Returns 0 if a match is found, 1 otherwise.
2159 Returns 0 if a match is found, 1 otherwise.
2152
2160
2153 """
2161 """
2154
2162
2155 opts = pycompat.byteskwargs(opts)
2163 opts = pycompat.byteskwargs(opts)
2156 rev = opts.get('rev')
2164 rev = opts.get('rev')
2157 if rev:
2165 if rev:
2158 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2166 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2159 ctx = scmutil.revsingle(repo, rev, None)
2167 ctx = scmutil.revsingle(repo, rev, None)
2160
2168
2161 end = '\n'
2169 end = '\n'
2162 if opts.get('print0'):
2170 if opts.get('print0'):
2163 end = '\0'
2171 end = '\0'
2164 fmt = '%s' + end
2172 fmt = '%s' + end
2165
2173
2166 m = scmutil.match(ctx, pats, opts)
2174 m = scmutil.match(ctx, pats, opts)
2167 ui.pager('files')
2175 ui.pager('files')
2168 with ui.formatter('files', opts) as fm:
2176 with ui.formatter('files', opts) as fm:
2169 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2177 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2170
2178
2171 @command(
2179 @command(
2172 '^forget',
2180 '^forget',
2173 [('i', 'interactive', None, _('use interactive mode')),
2181 [('i', 'interactive', None, _('use interactive mode')),
2174 ] + walkopts + dryrunopts,
2182 ] + walkopts + dryrunopts,
2175 _('[OPTION]... FILE...'), inferrepo=True)
2183 _('[OPTION]... FILE...'), inferrepo=True)
2176 def forget(ui, repo, *pats, **opts):
2184 def forget(ui, repo, *pats, **opts):
2177 """forget the specified files on the next commit
2185 """forget the specified files on the next commit
2178
2186
2179 Mark the specified files so they will no longer be tracked
2187 Mark the specified files so they will no longer be tracked
2180 after the next commit.
2188 after the next commit.
2181
2189
2182 This only removes files from the current branch, not from the
2190 This only removes files from the current branch, not from the
2183 entire project history, and it does not delete them from the
2191 entire project history, and it does not delete them from the
2184 working directory.
2192 working directory.
2185
2193
2186 To delete the file from the working directory, see :hg:`remove`.
2194 To delete the file from the working directory, see :hg:`remove`.
2187
2195
2188 To undo a forget before the next commit, see :hg:`add`.
2196 To undo a forget before the next commit, see :hg:`add`.
2189
2197
2190 .. container:: verbose
2198 .. container:: verbose
2191
2199
2192 Examples:
2200 Examples:
2193
2201
2194 - forget newly-added binary files::
2202 - forget newly-added binary files::
2195
2203
2196 hg forget "set:added() and binary()"
2204 hg forget "set:added() and binary()"
2197
2205
2198 - forget files that would be excluded by .hgignore::
2206 - forget files that would be excluded by .hgignore::
2199
2207
2200 hg forget "set:hgignore()"
2208 hg forget "set:hgignore()"
2201
2209
2202 Returns 0 on success.
2210 Returns 0 on success.
2203 """
2211 """
2204
2212
2205 opts = pycompat.byteskwargs(opts)
2213 opts = pycompat.byteskwargs(opts)
2206 if not pats:
2214 if not pats:
2207 raise error.Abort(_('no files specified'))
2215 raise error.Abort(_('no files specified'))
2208
2216
2209 m = scmutil.match(repo[None], pats, opts)
2217 m = scmutil.match(repo[None], pats, opts)
2210 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2218 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2211 rejected = cmdutil.forget(ui, repo, m, prefix="",
2219 rejected = cmdutil.forget(ui, repo, m, prefix="",
2212 explicitonly=False, dryrun=dryrun,
2220 explicitonly=False, dryrun=dryrun,
2213 interactive=interactive)[0]
2221 interactive=interactive)[0]
2214 return rejected and 1 or 0
2222 return rejected and 1 or 0
2215
2223
2216 @command(
2224 @command(
2217 'graft',
2225 'graft',
2218 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2226 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2219 ('c', 'continue', False, _('resume interrupted graft')),
2227 ('c', 'continue', False, _('resume interrupted graft')),
2220 ('', 'stop', False, _('stop interrupted graft')),
2228 ('', 'stop', False, _('stop interrupted graft')),
2221 ('', 'abort', False, _('abort interrupted graft')),
2229 ('', 'abort', False, _('abort interrupted graft')),
2222 ('e', 'edit', False, _('invoke editor on commit messages')),
2230 ('e', 'edit', False, _('invoke editor on commit messages')),
2223 ('', 'log', None, _('append graft info to log message')),
2231 ('', 'log', None, _('append graft info to log message')),
2224 ('', 'no-commit', None,
2232 ('', 'no-commit', None,
2225 _("don't commit, just apply the changes in working directory")),
2233 _("don't commit, just apply the changes in working directory")),
2226 ('f', 'force', False, _('force graft')),
2234 ('f', 'force', False, _('force graft')),
2227 ('D', 'currentdate', False,
2235 ('D', 'currentdate', False,
2228 _('record the current date as commit date')),
2236 _('record the current date as commit date')),
2229 ('U', 'currentuser', False,
2237 ('U', 'currentuser', False,
2230 _('record the current user as committer'), _('DATE'))]
2238 _('record the current user as committer'), _('DATE'))]
2231 + commitopts2 + mergetoolopts + dryrunopts,
2239 + commitopts2 + mergetoolopts + dryrunopts,
2232 _('[OPTION]... [-r REV]... REV...'))
2240 _('[OPTION]... [-r REV]... REV...'))
2233 def graft(ui, repo, *revs, **opts):
2241 def graft(ui, repo, *revs, **opts):
2234 '''copy changes from other branches onto the current branch
2242 '''copy changes from other branches onto the current branch
2235
2243
2236 This command uses Mercurial's merge logic to copy individual
2244 This command uses Mercurial's merge logic to copy individual
2237 changes from other branches without merging branches in the
2245 changes from other branches without merging branches in the
2238 history graph. This is sometimes known as 'backporting' or
2246 history graph. This is sometimes known as 'backporting' or
2239 'cherry-picking'. By default, graft will copy user, date, and
2247 'cherry-picking'. By default, graft will copy user, date, and
2240 description from the source changesets.
2248 description from the source changesets.
2241
2249
2242 Changesets that are ancestors of the current revision, that have
2250 Changesets that are ancestors of the current revision, that have
2243 already been grafted, or that are merges will be skipped.
2251 already been grafted, or that are merges will be skipped.
2244
2252
2245 If --log is specified, log messages will have a comment appended
2253 If --log is specified, log messages will have a comment appended
2246 of the form::
2254 of the form::
2247
2255
2248 (grafted from CHANGESETHASH)
2256 (grafted from CHANGESETHASH)
2249
2257
2250 If --force is specified, revisions will be grafted even if they
2258 If --force is specified, revisions will be grafted even if they
2251 are already ancestors of, or have been grafted to, the destination.
2259 are already ancestors of, or have been grafted to, the destination.
2252 This is useful when the revisions have since been backed out.
2260 This is useful when the revisions have since been backed out.
2253
2261
2254 If a graft merge results in conflicts, the graft process is
2262 If a graft merge results in conflicts, the graft process is
2255 interrupted so that the current merge can be manually resolved.
2263 interrupted so that the current merge can be manually resolved.
2256 Once all conflicts are addressed, the graft process can be
2264 Once all conflicts are addressed, the graft process can be
2257 continued with the -c/--continue option.
2265 continued with the -c/--continue option.
2258
2266
2259 The -c/--continue option reapplies all the earlier options.
2267 The -c/--continue option reapplies all the earlier options.
2260
2268
2261 .. container:: verbose
2269 .. container:: verbose
2262
2270
2263 Examples:
2271 Examples:
2264
2272
2265 - copy a single change to the stable branch and edit its description::
2273 - copy a single change to the stable branch and edit its description::
2266
2274
2267 hg update stable
2275 hg update stable
2268 hg graft --edit 9393
2276 hg graft --edit 9393
2269
2277
2270 - graft a range of changesets with one exception, updating dates::
2278 - graft a range of changesets with one exception, updating dates::
2271
2279
2272 hg graft -D "2085::2093 and not 2091"
2280 hg graft -D "2085::2093 and not 2091"
2273
2281
2274 - continue a graft after resolving conflicts::
2282 - continue a graft after resolving conflicts::
2275
2283
2276 hg graft -c
2284 hg graft -c
2277
2285
2278 - show the source of a grafted changeset::
2286 - show the source of a grafted changeset::
2279
2287
2280 hg log --debug -r .
2288 hg log --debug -r .
2281
2289
2282 - show revisions sorted by date::
2290 - show revisions sorted by date::
2283
2291
2284 hg log -r "sort(all(), date)"
2292 hg log -r "sort(all(), date)"
2285
2293
2286 See :hg:`help revisions` for more about specifying revisions.
2294 See :hg:`help revisions` for more about specifying revisions.
2287
2295
2288 Returns 0 on successful completion.
2296 Returns 0 on successful completion.
2289 '''
2297 '''
2290 with repo.wlock():
2298 with repo.wlock():
2291 return _dograft(ui, repo, *revs, **opts)
2299 return _dograft(ui, repo, *revs, **opts)
2292
2300
2293 def _dograft(ui, repo, *revs, **opts):
2301 def _dograft(ui, repo, *revs, **opts):
2294 opts = pycompat.byteskwargs(opts)
2302 opts = pycompat.byteskwargs(opts)
2295 if revs and opts.get('rev'):
2303 if revs and opts.get('rev'):
2296 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2304 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2297 'revision ordering!\n'))
2305 'revision ordering!\n'))
2298
2306
2299 revs = list(revs)
2307 revs = list(revs)
2300 revs.extend(opts.get('rev'))
2308 revs.extend(opts.get('rev'))
2301 # a dict of data to be stored in state file
2309 # a dict of data to be stored in state file
2302 statedata = {}
2310 statedata = {}
2303 # list of new nodes created by ongoing graft
2311 # list of new nodes created by ongoing graft
2304 statedata['newnodes'] = []
2312 statedata['newnodes'] = []
2305
2313
2306 if not opts.get('user') and opts.get('currentuser'):
2314 if not opts.get('user') and opts.get('currentuser'):
2307 opts['user'] = ui.username()
2315 opts['user'] = ui.username()
2308 if not opts.get('date') and opts.get('currentdate'):
2316 if not opts.get('date') and opts.get('currentdate'):
2309 opts['date'] = "%d %d" % dateutil.makedate()
2317 opts['date'] = "%d %d" % dateutil.makedate()
2310
2318
2311 editor = cmdutil.getcommiteditor(editform='graft',
2319 editor = cmdutil.getcommiteditor(editform='graft',
2312 **pycompat.strkwargs(opts))
2320 **pycompat.strkwargs(opts))
2313
2321
2314 cont = False
2322 cont = False
2315 if opts.get('no_commit'):
2323 if opts.get('no_commit'):
2316 if opts.get('edit'):
2324 if opts.get('edit'):
2317 raise error.Abort(_("cannot specify --no-commit and "
2325 raise error.Abort(_("cannot specify --no-commit and "
2318 "--edit together"))
2326 "--edit together"))
2319 if opts.get('currentuser'):
2327 if opts.get('currentuser'):
2320 raise error.Abort(_("cannot specify --no-commit and "
2328 raise error.Abort(_("cannot specify --no-commit and "
2321 "--currentuser together"))
2329 "--currentuser together"))
2322 if opts.get('currentdate'):
2330 if opts.get('currentdate'):
2323 raise error.Abort(_("cannot specify --no-commit and "
2331 raise error.Abort(_("cannot specify --no-commit and "
2324 "--currentdate together"))
2332 "--currentdate together"))
2325 if opts.get('log'):
2333 if opts.get('log'):
2326 raise error.Abort(_("cannot specify --no-commit and "
2334 raise error.Abort(_("cannot specify --no-commit and "
2327 "--log together"))
2335 "--log together"))
2328
2336
2329 graftstate = statemod.cmdstate(repo, 'graftstate')
2337 graftstate = statemod.cmdstate(repo, 'graftstate')
2330
2338
2331 if opts.get('stop'):
2339 if opts.get('stop'):
2332 if opts.get('continue'):
2340 if opts.get('continue'):
2333 raise error.Abort(_("cannot use '--continue' and "
2341 raise error.Abort(_("cannot use '--continue' and "
2334 "'--stop' together"))
2342 "'--stop' together"))
2335 if opts.get('abort'):
2343 if opts.get('abort'):
2336 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2344 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2337
2345
2338 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2346 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2339 opts.get('date'), opts.get('currentdate'),
2347 opts.get('date'), opts.get('currentdate'),
2340 opts.get('currentuser'), opts.get('rev'))):
2348 opts.get('currentuser'), opts.get('rev'))):
2341 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2349 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2342 return _stopgraft(ui, repo, graftstate)
2350 return _stopgraft(ui, repo, graftstate)
2343 elif opts.get('abort'):
2351 elif opts.get('abort'):
2344 if opts.get('continue'):
2352 if opts.get('continue'):
2345 raise error.Abort(_("cannot use '--continue' and "
2353 raise error.Abort(_("cannot use '--continue' and "
2346 "'--abort' together"))
2354 "'--abort' together"))
2347 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2355 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2348 opts.get('date'), opts.get('currentdate'),
2356 opts.get('date'), opts.get('currentdate'),
2349 opts.get('currentuser'), opts.get('rev'))):
2357 opts.get('currentuser'), opts.get('rev'))):
2350 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2358 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2351
2359
2352 return _abortgraft(ui, repo, graftstate)
2360 return _abortgraft(ui, repo, graftstate)
2353 elif opts.get('continue'):
2361 elif opts.get('continue'):
2354 cont = True
2362 cont = True
2355 if revs:
2363 if revs:
2356 raise error.Abort(_("can't specify --continue and revisions"))
2364 raise error.Abort(_("can't specify --continue and revisions"))
2357 # read in unfinished revisions
2365 # read in unfinished revisions
2358 if graftstate.exists():
2366 if graftstate.exists():
2359 statedata = _readgraftstate(repo, graftstate)
2367 statedata = _readgraftstate(repo, graftstate)
2360 if statedata.get('date'):
2368 if statedata.get('date'):
2361 opts['date'] = statedata['date']
2369 opts['date'] = statedata['date']
2362 if statedata.get('user'):
2370 if statedata.get('user'):
2363 opts['user'] = statedata['user']
2371 opts['user'] = statedata['user']
2364 if statedata.get('log'):
2372 if statedata.get('log'):
2365 opts['log'] = True
2373 opts['log'] = True
2366 if statedata.get('no_commit'):
2374 if statedata.get('no_commit'):
2367 opts['no_commit'] = statedata.get('no_commit')
2375 opts['no_commit'] = statedata.get('no_commit')
2368 nodes = statedata['nodes']
2376 nodes = statedata['nodes']
2369 revs = [repo[node].rev() for node in nodes]
2377 revs = [repo[node].rev() for node in nodes]
2370 else:
2378 else:
2371 cmdutil.wrongtooltocontinue(repo, _('graft'))
2379 cmdutil.wrongtooltocontinue(repo, _('graft'))
2372 else:
2380 else:
2373 if not revs:
2381 if not revs:
2374 raise error.Abort(_('no revisions specified'))
2382 raise error.Abort(_('no revisions specified'))
2375 cmdutil.checkunfinished(repo)
2383 cmdutil.checkunfinished(repo)
2376 cmdutil.bailifchanged(repo)
2384 cmdutil.bailifchanged(repo)
2377 revs = scmutil.revrange(repo, revs)
2385 revs = scmutil.revrange(repo, revs)
2378
2386
2379 skipped = set()
2387 skipped = set()
2380 # check for merges
2388 # check for merges
2381 for rev in repo.revs('%ld and merge()', revs):
2389 for rev in repo.revs('%ld and merge()', revs):
2382 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2390 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2383 skipped.add(rev)
2391 skipped.add(rev)
2384 revs = [r for r in revs if r not in skipped]
2392 revs = [r for r in revs if r not in skipped]
2385 if not revs:
2393 if not revs:
2386 return -1
2394 return -1
2387
2395
2388 # Don't check in the --continue case, in effect retaining --force across
2396 # Don't check in the --continue case, in effect retaining --force across
2389 # --continues. That's because without --force, any revisions we decided to
2397 # --continues. That's because without --force, any revisions we decided to
2390 # skip would have been filtered out here, so they wouldn't have made their
2398 # skip would have been filtered out here, so they wouldn't have made their
2391 # way to the graftstate. With --force, any revisions we would have otherwise
2399 # way to the graftstate. With --force, any revisions we would have otherwise
2392 # skipped would not have been filtered out, and if they hadn't been applied
2400 # skipped would not have been filtered out, and if they hadn't been applied
2393 # already, they'd have been in the graftstate.
2401 # already, they'd have been in the graftstate.
2394 if not (cont or opts.get('force')):
2402 if not (cont or opts.get('force')):
2395 # check for ancestors of dest branch
2403 # check for ancestors of dest branch
2396 crev = repo['.'].rev()
2404 crev = repo['.'].rev()
2397 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2405 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2398 # XXX make this lazy in the future
2406 # XXX make this lazy in the future
2399 # don't mutate while iterating, create a copy
2407 # don't mutate while iterating, create a copy
2400 for rev in list(revs):
2408 for rev in list(revs):
2401 if rev in ancestors:
2409 if rev in ancestors:
2402 ui.warn(_('skipping ancestor revision %d:%s\n') %
2410 ui.warn(_('skipping ancestor revision %d:%s\n') %
2403 (rev, repo[rev]))
2411 (rev, repo[rev]))
2404 # XXX remove on list is slow
2412 # XXX remove on list is slow
2405 revs.remove(rev)
2413 revs.remove(rev)
2406 if not revs:
2414 if not revs:
2407 return -1
2415 return -1
2408
2416
2409 # analyze revs for earlier grafts
2417 # analyze revs for earlier grafts
2410 ids = {}
2418 ids = {}
2411 for ctx in repo.set("%ld", revs):
2419 for ctx in repo.set("%ld", revs):
2412 ids[ctx.hex()] = ctx.rev()
2420 ids[ctx.hex()] = ctx.rev()
2413 n = ctx.extra().get('source')
2421 n = ctx.extra().get('source')
2414 if n:
2422 if n:
2415 ids[n] = ctx.rev()
2423 ids[n] = ctx.rev()
2416
2424
2417 # check ancestors for earlier grafts
2425 # check ancestors for earlier grafts
2418 ui.debug('scanning for duplicate grafts\n')
2426 ui.debug('scanning for duplicate grafts\n')
2419
2427
2420 # The only changesets we can be sure doesn't contain grafts of any
2428 # The only changesets we can be sure doesn't contain grafts of any
2421 # revs, are the ones that are common ancestors of *all* revs:
2429 # revs, are the ones that are common ancestors of *all* revs:
2422 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2430 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2423 ctx = repo[rev]
2431 ctx = repo[rev]
2424 n = ctx.extra().get('source')
2432 n = ctx.extra().get('source')
2425 if n in ids:
2433 if n in ids:
2426 try:
2434 try:
2427 r = repo[n].rev()
2435 r = repo[n].rev()
2428 except error.RepoLookupError:
2436 except error.RepoLookupError:
2429 r = None
2437 r = None
2430 if r in revs:
2438 if r in revs:
2431 ui.warn(_('skipping revision %d:%s '
2439 ui.warn(_('skipping revision %d:%s '
2432 '(already grafted to %d:%s)\n')
2440 '(already grafted to %d:%s)\n')
2433 % (r, repo[r], rev, ctx))
2441 % (r, repo[r], rev, ctx))
2434 revs.remove(r)
2442 revs.remove(r)
2435 elif ids[n] in revs:
2443 elif ids[n] in revs:
2436 if r is None:
2444 if r is None:
2437 ui.warn(_('skipping already grafted revision %d:%s '
2445 ui.warn(_('skipping already grafted revision %d:%s '
2438 '(%d:%s also has unknown origin %s)\n')
2446 '(%d:%s also has unknown origin %s)\n')
2439 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2447 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2440 else:
2448 else:
2441 ui.warn(_('skipping already grafted revision %d:%s '
2449 ui.warn(_('skipping already grafted revision %d:%s '
2442 '(%d:%s also has origin %d:%s)\n')
2450 '(%d:%s also has origin %d:%s)\n')
2443 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2451 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2444 revs.remove(ids[n])
2452 revs.remove(ids[n])
2445 elif ctx.hex() in ids:
2453 elif ctx.hex() in ids:
2446 r = ids[ctx.hex()]
2454 r = ids[ctx.hex()]
2447 ui.warn(_('skipping already grafted revision %d:%s '
2455 ui.warn(_('skipping already grafted revision %d:%s '
2448 '(was grafted from %d:%s)\n') %
2456 '(was grafted from %d:%s)\n') %
2449 (r, repo[r], rev, ctx))
2457 (r, repo[r], rev, ctx))
2450 revs.remove(r)
2458 revs.remove(r)
2451 if not revs:
2459 if not revs:
2452 return -1
2460 return -1
2453
2461
2454 if opts.get('no_commit'):
2462 if opts.get('no_commit'):
2455 statedata['no_commit'] = True
2463 statedata['no_commit'] = True
2456 for pos, ctx in enumerate(repo.set("%ld", revs)):
2464 for pos, ctx in enumerate(repo.set("%ld", revs)):
2457 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2465 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2458 ctx.description().split('\n', 1)[0])
2466 ctx.description().split('\n', 1)[0])
2459 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2467 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2460 if names:
2468 if names:
2461 desc += ' (%s)' % ' '.join(names)
2469 desc += ' (%s)' % ' '.join(names)
2462 ui.status(_('grafting %s\n') % desc)
2470 ui.status(_('grafting %s\n') % desc)
2463 if opts.get('dry_run'):
2471 if opts.get('dry_run'):
2464 continue
2472 continue
2465
2473
2466 source = ctx.extra().get('source')
2474 source = ctx.extra().get('source')
2467 extra = {}
2475 extra = {}
2468 if source:
2476 if source:
2469 extra['source'] = source
2477 extra['source'] = source
2470 extra['intermediate-source'] = ctx.hex()
2478 extra['intermediate-source'] = ctx.hex()
2471 else:
2479 else:
2472 extra['source'] = ctx.hex()
2480 extra['source'] = ctx.hex()
2473 user = ctx.user()
2481 user = ctx.user()
2474 if opts.get('user'):
2482 if opts.get('user'):
2475 user = opts['user']
2483 user = opts['user']
2476 statedata['user'] = user
2484 statedata['user'] = user
2477 date = ctx.date()
2485 date = ctx.date()
2478 if opts.get('date'):
2486 if opts.get('date'):
2479 date = opts['date']
2487 date = opts['date']
2480 statedata['date'] = date
2488 statedata['date'] = date
2481 message = ctx.description()
2489 message = ctx.description()
2482 if opts.get('log'):
2490 if opts.get('log'):
2483 message += '\n(grafted from %s)' % ctx.hex()
2491 message += '\n(grafted from %s)' % ctx.hex()
2484 statedata['log'] = True
2492 statedata['log'] = True
2485
2493
2486 # we don't merge the first commit when continuing
2494 # we don't merge the first commit when continuing
2487 if not cont:
2495 if not cont:
2488 # perform the graft merge with p1(rev) as 'ancestor'
2496 # perform the graft merge with p1(rev) as 'ancestor'
2489 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2497 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2490 with ui.configoverride(overrides, 'graft'):
2498 with ui.configoverride(overrides, 'graft'):
2491 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2499 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2492 # report any conflicts
2500 # report any conflicts
2493 if stats.unresolvedcount > 0:
2501 if stats.unresolvedcount > 0:
2494 # write out state for --continue
2502 # write out state for --continue
2495 nodes = [repo[rev].hex() for rev in revs[pos:]]
2503 nodes = [repo[rev].hex() for rev in revs[pos:]]
2496 statedata['nodes'] = nodes
2504 statedata['nodes'] = nodes
2497 stateversion = 1
2505 stateversion = 1
2498 graftstate.save(stateversion, statedata)
2506 graftstate.save(stateversion, statedata)
2499 hint = _("use 'hg resolve' and 'hg graft --continue'")
2507 hint = _("use 'hg resolve' and 'hg graft --continue'")
2500 raise error.Abort(
2508 raise error.Abort(
2501 _("unresolved conflicts, can't continue"),
2509 _("unresolved conflicts, can't continue"),
2502 hint=hint)
2510 hint=hint)
2503 else:
2511 else:
2504 cont = False
2512 cont = False
2505
2513
2506 # commit if --no-commit is false
2514 # commit if --no-commit is false
2507 if not opts.get('no_commit'):
2515 if not opts.get('no_commit'):
2508 node = repo.commit(text=message, user=user, date=date, extra=extra,
2516 node = repo.commit(text=message, user=user, date=date, extra=extra,
2509 editor=editor)
2517 editor=editor)
2510 if node is None:
2518 if node is None:
2511 ui.warn(
2519 ui.warn(
2512 _('note: graft of %d:%s created no changes to commit\n') %
2520 _('note: graft of %d:%s created no changes to commit\n') %
2513 (ctx.rev(), ctx))
2521 (ctx.rev(), ctx))
2514 # checking that newnodes exist because old state files won't have it
2522 # checking that newnodes exist because old state files won't have it
2515 elif statedata.get('newnodes') is not None:
2523 elif statedata.get('newnodes') is not None:
2516 statedata['newnodes'].append(node)
2524 statedata['newnodes'].append(node)
2517
2525
2518 # remove state when we complete successfully
2526 # remove state when we complete successfully
2519 if not opts.get('dry_run'):
2527 if not opts.get('dry_run'):
2520 graftstate.delete()
2528 graftstate.delete()
2521
2529
2522 return 0
2530 return 0
2523
2531
2524 def _abortgraft(ui, repo, graftstate):
2532 def _abortgraft(ui, repo, graftstate):
2525 """abort the interrupted graft and rollbacks to the state before interrupted
2533 """abort the interrupted graft and rollbacks to the state before interrupted
2526 graft"""
2534 graft"""
2527 if not graftstate.exists():
2535 if not graftstate.exists():
2528 raise error.Abort(_("no interrupted graft to abort"))
2536 raise error.Abort(_("no interrupted graft to abort"))
2529 statedata = _readgraftstate(repo, graftstate)
2537 statedata = _readgraftstate(repo, graftstate)
2530 newnodes = statedata.get('newnodes')
2538 newnodes = statedata.get('newnodes')
2531 if newnodes is None:
2539 if newnodes is None:
2532 # and old graft state which does not have all the data required to abort
2540 # and old graft state which does not have all the data required to abort
2533 # the graft
2541 # the graft
2534 raise error.Abort(_("cannot abort using an old graftstate"))
2542 raise error.Abort(_("cannot abort using an old graftstate"))
2535
2543
2536 # changeset from which graft operation was started
2544 # changeset from which graft operation was started
2537 startctx = None
2545 startctx = None
2538 if len(newnodes) > 0:
2546 if len(newnodes) > 0:
2539 startctx = repo[newnodes[0]].p1()
2547 startctx = repo[newnodes[0]].p1()
2540 else:
2548 else:
2541 startctx = repo['.']
2549 startctx = repo['.']
2542 # whether to strip or not
2550 # whether to strip or not
2543 cleanup = False
2551 cleanup = False
2544 if newnodes:
2552 if newnodes:
2545 newnodes = [repo[r].rev() for r in newnodes]
2553 newnodes = [repo[r].rev() for r in newnodes]
2546 cleanup = True
2554 cleanup = True
2547 # checking that none of the newnodes turned public or is public
2555 # checking that none of the newnodes turned public or is public
2548 immutable = [c for c in newnodes if not repo[c].mutable()]
2556 immutable = [c for c in newnodes if not repo[c].mutable()]
2549 if immutable:
2557 if immutable:
2550 repo.ui.warn(_("cannot clean up public changesets %s\n")
2558 repo.ui.warn(_("cannot clean up public changesets %s\n")
2551 % ', '.join(bytes(repo[r]) for r in immutable),
2559 % ', '.join(bytes(repo[r]) for r in immutable),
2552 hint=_("see 'hg help phases' for details"))
2560 hint=_("see 'hg help phases' for details"))
2553 cleanup = False
2561 cleanup = False
2554
2562
2555 # checking that no new nodes are created on top of grafted revs
2563 # checking that no new nodes are created on top of grafted revs
2556 desc = set(repo.changelog.descendants(newnodes))
2564 desc = set(repo.changelog.descendants(newnodes))
2557 if desc - set(newnodes):
2565 if desc - set(newnodes):
2558 repo.ui.warn(_("new changesets detected on destination "
2566 repo.ui.warn(_("new changesets detected on destination "
2559 "branch, can't strip\n"))
2567 "branch, can't strip\n"))
2560 cleanup = False
2568 cleanup = False
2561
2569
2562 if cleanup:
2570 if cleanup:
2563 with repo.wlock(), repo.lock():
2571 with repo.wlock(), repo.lock():
2564 hg.updaterepo(repo, startctx.node(), overwrite=True)
2572 hg.updaterepo(repo, startctx.node(), overwrite=True)
2565 # stripping the new nodes created
2573 # stripping the new nodes created
2566 strippoints = [c.node() for c in repo.set("roots(%ld)",
2574 strippoints = [c.node() for c in repo.set("roots(%ld)",
2567 newnodes)]
2575 newnodes)]
2568 repair.strip(repo.ui, repo, strippoints, backup=False)
2576 repair.strip(repo.ui, repo, strippoints, backup=False)
2569
2577
2570 if not cleanup:
2578 if not cleanup:
2571 # we don't update to the startnode if we can't strip
2579 # we don't update to the startnode if we can't strip
2572 startctx = repo['.']
2580 startctx = repo['.']
2573 hg.updaterepo(repo, startctx.node(), overwrite=True)
2581 hg.updaterepo(repo, startctx.node(), overwrite=True)
2574
2582
2575 ui.status(_("graft aborted\n"))
2583 ui.status(_("graft aborted\n"))
2576 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2584 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2577 graftstate.delete()
2585 graftstate.delete()
2578 return 0
2586 return 0
2579
2587
2580 def _readgraftstate(repo, graftstate):
2588 def _readgraftstate(repo, graftstate):
2581 """read the graft state file and return a dict of the data stored in it"""
2589 """read the graft state file and return a dict of the data stored in it"""
2582 try:
2590 try:
2583 return graftstate.read()
2591 return graftstate.read()
2584 except error.CorruptedState:
2592 except error.CorruptedState:
2585 nodes = repo.vfs.read('graftstate').splitlines()
2593 nodes = repo.vfs.read('graftstate').splitlines()
2586 return {'nodes': nodes}
2594 return {'nodes': nodes}
2587
2595
2588 def _stopgraft(ui, repo, graftstate):
2596 def _stopgraft(ui, repo, graftstate):
2589 """stop the interrupted graft"""
2597 """stop the interrupted graft"""
2590 if not graftstate.exists():
2598 if not graftstate.exists():
2591 raise error.Abort(_("no interrupted graft found"))
2599 raise error.Abort(_("no interrupted graft found"))
2592 pctx = repo['.']
2600 pctx = repo['.']
2593 hg.updaterepo(repo, pctx.node(), overwrite=True)
2601 hg.updaterepo(repo, pctx.node(), overwrite=True)
2594 graftstate.delete()
2602 graftstate.delete()
2595 ui.status(_("stopped the interrupted graft\n"))
2603 ui.status(_("stopped the interrupted graft\n"))
2596 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2604 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2597 return 0
2605 return 0
2598
2606
2599 @command('grep',
2607 @command('grep',
2600 [('0', 'print0', None, _('end fields with NUL')),
2608 [('0', 'print0', None, _('end fields with NUL')),
2601 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2609 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2602 ('', 'diff', None, _('print all revisions when the term was introduced '
2610 ('', 'diff', None, _('print all revisions when the term was introduced '
2603 'or removed')),
2611 'or removed')),
2604 ('a', 'text', None, _('treat all files as text')),
2612 ('a', 'text', None, _('treat all files as text')),
2605 ('f', 'follow', None,
2613 ('f', 'follow', None,
2606 _('follow changeset history,'
2614 _('follow changeset history,'
2607 ' or file history across copies and renames')),
2615 ' or file history across copies and renames')),
2608 ('i', 'ignore-case', None, _('ignore case when matching')),
2616 ('i', 'ignore-case', None, _('ignore case when matching')),
2609 ('l', 'files-with-matches', None,
2617 ('l', 'files-with-matches', None,
2610 _('print only filenames and revisions that match')),
2618 _('print only filenames and revisions that match')),
2611 ('n', 'line-number', None, _('print matching line numbers')),
2619 ('n', 'line-number', None, _('print matching line numbers')),
2612 ('r', 'rev', [],
2620 ('r', 'rev', [],
2613 _('only search files changed within revision range'), _('REV')),
2621 _('only search files changed within revision range'), _('REV')),
2614 ('', 'all-files', None,
2622 ('', 'all-files', None,
2615 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2623 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2616 ('u', 'user', None, _('list the author (long with -v)')),
2624 ('u', 'user', None, _('list the author (long with -v)')),
2617 ('d', 'date', None, _('list the date (short with -q)')),
2625 ('d', 'date', None, _('list the date (short with -q)')),
2618 ] + formatteropts + walkopts,
2626 ] + formatteropts + walkopts,
2619 _('[OPTION]... PATTERN [FILE]...'),
2627 _('[OPTION]... PATTERN [FILE]...'),
2620 inferrepo=True,
2628 inferrepo=True,
2621 intents={INTENT_READONLY})
2629 intents={INTENT_READONLY})
2622 def grep(ui, repo, pattern, *pats, **opts):
2630 def grep(ui, repo, pattern, *pats, **opts):
2623 """search revision history for a pattern in specified files
2631 """search revision history for a pattern in specified files
2624
2632
2625 Search revision history for a regular expression in the specified
2633 Search revision history for a regular expression in the specified
2626 files or the entire project.
2634 files or the entire project.
2627
2635
2628 By default, grep prints the most recent revision number for each
2636 By default, grep prints the most recent revision number for each
2629 file in which it finds a match. To get it to print every revision
2637 file in which it finds a match. To get it to print every revision
2630 that contains a change in match status ("-" for a match that becomes
2638 that contains a change in match status ("-" for a match that becomes
2631 a non-match, or "+" for a non-match that becomes a match), use the
2639 a non-match, or "+" for a non-match that becomes a match), use the
2632 --diff flag.
2640 --diff flag.
2633
2641
2634 PATTERN can be any Python (roughly Perl-compatible) regular
2642 PATTERN can be any Python (roughly Perl-compatible) regular
2635 expression.
2643 expression.
2636
2644
2637 If no FILEs are specified (and -f/--follow isn't set), all files in
2645 If no FILEs are specified (and -f/--follow isn't set), all files in
2638 the repository are searched, including those that don't exist in the
2646 the repository are searched, including those that don't exist in the
2639 current branch or have been deleted in a prior changeset.
2647 current branch or have been deleted in a prior changeset.
2640
2648
2641 Returns 0 if a match is found, 1 otherwise.
2649 Returns 0 if a match is found, 1 otherwise.
2642 """
2650 """
2643 opts = pycompat.byteskwargs(opts)
2651 opts = pycompat.byteskwargs(opts)
2644 diff = opts.get('all') or opts.get('diff')
2652 diff = opts.get('all') or opts.get('diff')
2645 all_files = opts.get('all_files')
2653 all_files = opts.get('all_files')
2646 if diff and opts.get('all_files'):
2654 if diff and opts.get('all_files'):
2647 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2655 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2648 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2656 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2649 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2657 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2650 # experimental config: commands.grep.all-files
2658 # experimental config: commands.grep.all-files
2651 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2659 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2652 plaingrep = opts.get('all_files') and not opts.get('rev')
2660 plaingrep = opts.get('all_files') and not opts.get('rev')
2653 if plaingrep:
2661 if plaingrep:
2654 opts['rev'] = ['wdir()']
2662 opts['rev'] = ['wdir()']
2655
2663
2656 reflags = re.M
2664 reflags = re.M
2657 if opts.get('ignore_case'):
2665 if opts.get('ignore_case'):
2658 reflags |= re.I
2666 reflags |= re.I
2659 try:
2667 try:
2660 regexp = util.re.compile(pattern, reflags)
2668 regexp = util.re.compile(pattern, reflags)
2661 except re.error as inst:
2669 except re.error as inst:
2662 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2670 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2663 return 1
2671 return 1
2664 sep, eol = ':', '\n'
2672 sep, eol = ':', '\n'
2665 if opts.get('print0'):
2673 if opts.get('print0'):
2666 sep = eol = '\0'
2674 sep = eol = '\0'
2667
2675
2668 getfile = util.lrucachefunc(repo.file)
2676 getfile = util.lrucachefunc(repo.file)
2669
2677
2670 def matchlines(body):
2678 def matchlines(body):
2671 begin = 0
2679 begin = 0
2672 linenum = 0
2680 linenum = 0
2673 while begin < len(body):
2681 while begin < len(body):
2674 match = regexp.search(body, begin)
2682 match = regexp.search(body, begin)
2675 if not match:
2683 if not match:
2676 break
2684 break
2677 mstart, mend = match.span()
2685 mstart, mend = match.span()
2678 linenum += body.count('\n', begin, mstart) + 1
2686 linenum += body.count('\n', begin, mstart) + 1
2679 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2687 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2680 begin = body.find('\n', mend) + 1 or len(body) + 1
2688 begin = body.find('\n', mend) + 1 or len(body) + 1
2681 lend = begin - 1
2689 lend = begin - 1
2682 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2690 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2683
2691
2684 class linestate(object):
2692 class linestate(object):
2685 def __init__(self, line, linenum, colstart, colend):
2693 def __init__(self, line, linenum, colstart, colend):
2686 self.line = line
2694 self.line = line
2687 self.linenum = linenum
2695 self.linenum = linenum
2688 self.colstart = colstart
2696 self.colstart = colstart
2689 self.colend = colend
2697 self.colend = colend
2690
2698
2691 def __hash__(self):
2699 def __hash__(self):
2692 return hash((self.linenum, self.line))
2700 return hash((self.linenum, self.line))
2693
2701
2694 def __eq__(self, other):
2702 def __eq__(self, other):
2695 return self.line == other.line
2703 return self.line == other.line
2696
2704
2697 def findpos(self):
2705 def findpos(self):
2698 """Iterate all (start, end) indices of matches"""
2706 """Iterate all (start, end) indices of matches"""
2699 yield self.colstart, self.colend
2707 yield self.colstart, self.colend
2700 p = self.colend
2708 p = self.colend
2701 while p < len(self.line):
2709 while p < len(self.line):
2702 m = regexp.search(self.line, p)
2710 m = regexp.search(self.line, p)
2703 if not m:
2711 if not m:
2704 break
2712 break
2705 yield m.span()
2713 yield m.span()
2706 p = m.end()
2714 p = m.end()
2707
2715
2708 matches = {}
2716 matches = {}
2709 copies = {}
2717 copies = {}
2710 def grepbody(fn, rev, body):
2718 def grepbody(fn, rev, body):
2711 matches[rev].setdefault(fn, [])
2719 matches[rev].setdefault(fn, [])
2712 m = matches[rev][fn]
2720 m = matches[rev][fn]
2713 for lnum, cstart, cend, line in matchlines(body):
2721 for lnum, cstart, cend, line in matchlines(body):
2714 s = linestate(line, lnum, cstart, cend)
2722 s = linestate(line, lnum, cstart, cend)
2715 m.append(s)
2723 m.append(s)
2716
2724
2717 def difflinestates(a, b):
2725 def difflinestates(a, b):
2718 sm = difflib.SequenceMatcher(None, a, b)
2726 sm = difflib.SequenceMatcher(None, a, b)
2719 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2727 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2720 if tag == r'insert':
2728 if tag == r'insert':
2721 for i in pycompat.xrange(blo, bhi):
2729 for i in pycompat.xrange(blo, bhi):
2722 yield ('+', b[i])
2730 yield ('+', b[i])
2723 elif tag == r'delete':
2731 elif tag == r'delete':
2724 for i in pycompat.xrange(alo, ahi):
2732 for i in pycompat.xrange(alo, ahi):
2725 yield ('-', a[i])
2733 yield ('-', a[i])
2726 elif tag == r'replace':
2734 elif tag == r'replace':
2727 for i in pycompat.xrange(alo, ahi):
2735 for i in pycompat.xrange(alo, ahi):
2728 yield ('-', a[i])
2736 yield ('-', a[i])
2729 for i in pycompat.xrange(blo, bhi):
2737 for i in pycompat.xrange(blo, bhi):
2730 yield ('+', b[i])
2738 yield ('+', b[i])
2731
2739
2732 def display(fm, fn, ctx, pstates, states):
2740 def display(fm, fn, ctx, pstates, states):
2733 rev = scmutil.intrev(ctx)
2741 rev = scmutil.intrev(ctx)
2734 if fm.isplain():
2742 if fm.isplain():
2735 formatuser = ui.shortuser
2743 formatuser = ui.shortuser
2736 else:
2744 else:
2737 formatuser = pycompat.bytestr
2745 formatuser = pycompat.bytestr
2738 if ui.quiet:
2746 if ui.quiet:
2739 datefmt = '%Y-%m-%d'
2747 datefmt = '%Y-%m-%d'
2740 else:
2748 else:
2741 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2749 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2742 found = False
2750 found = False
2743 @util.cachefunc
2751 @util.cachefunc
2744 def binary():
2752 def binary():
2745 flog = getfile(fn)
2753 flog = getfile(fn)
2746 try:
2754 try:
2747 return stringutil.binary(flog.read(ctx.filenode(fn)))
2755 return stringutil.binary(flog.read(ctx.filenode(fn)))
2748 except error.WdirUnsupported:
2756 except error.WdirUnsupported:
2749 return ctx[fn].isbinary()
2757 return ctx[fn].isbinary()
2750
2758
2751 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2759 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2752 if diff:
2760 if diff:
2753 iter = difflinestates(pstates, states)
2761 iter = difflinestates(pstates, states)
2754 else:
2762 else:
2755 iter = [('', l) for l in states]
2763 iter = [('', l) for l in states]
2756 for change, l in iter:
2764 for change, l in iter:
2757 fm.startitem()
2765 fm.startitem()
2758 fm.context(ctx=ctx)
2766 fm.context(ctx=ctx)
2759 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2767 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2760
2768
2761 cols = [
2769 cols = [
2762 ('filename', '%s', fn, True),
2770 ('filename', '%s', fn, True),
2763 ('rev', '%d', rev, not plaingrep),
2771 ('rev', '%d', rev, not plaingrep),
2764 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2772 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2765 ]
2773 ]
2766 if diff:
2774 if diff:
2767 cols.append(('change', '%s', change, True))
2775 cols.append(('change', '%s', change, True))
2768 cols.extend([
2776 cols.extend([
2769 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2777 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2770 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2778 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2771 opts.get('date')),
2779 opts.get('date')),
2772 ])
2780 ])
2773 lastcol = next(
2781 lastcol = next(
2774 name for name, fmt, data, cond in reversed(cols) if cond)
2782 name for name, fmt, data, cond in reversed(cols) if cond)
2775 for name, fmt, data, cond in cols:
2783 for name, fmt, data, cond in cols:
2776 field = fieldnamemap.get(name, name)
2784 field = fieldnamemap.get(name, name)
2777 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2785 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2778 if cond and name != lastcol:
2786 if cond and name != lastcol:
2779 fm.plain(sep, label='grep.sep')
2787 fm.plain(sep, label='grep.sep')
2780 if not opts.get('files_with_matches'):
2788 if not opts.get('files_with_matches'):
2781 fm.plain(sep, label='grep.sep')
2789 fm.plain(sep, label='grep.sep')
2782 if not opts.get('text') and binary():
2790 if not opts.get('text') and binary():
2783 fm.plain(_(" Binary file matches"))
2791 fm.plain(_(" Binary file matches"))
2784 else:
2792 else:
2785 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2793 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2786 fm.plain(eol)
2794 fm.plain(eol)
2787 found = True
2795 found = True
2788 if opts.get('files_with_matches'):
2796 if opts.get('files_with_matches'):
2789 break
2797 break
2790 return found
2798 return found
2791
2799
2792 def displaymatches(fm, l):
2800 def displaymatches(fm, l):
2793 p = 0
2801 p = 0
2794 for s, e in l.findpos():
2802 for s, e in l.findpos():
2795 if p < s:
2803 if p < s:
2796 fm.startitem()
2804 fm.startitem()
2797 fm.write('text', '%s', l.line[p:s])
2805 fm.write('text', '%s', l.line[p:s])
2798 fm.data(matched=False)
2806 fm.data(matched=False)
2799 fm.startitem()
2807 fm.startitem()
2800 fm.write('text', '%s', l.line[s:e], label='grep.match')
2808 fm.write('text', '%s', l.line[s:e], label='grep.match')
2801 fm.data(matched=True)
2809 fm.data(matched=True)
2802 p = e
2810 p = e
2803 if p < len(l.line):
2811 if p < len(l.line):
2804 fm.startitem()
2812 fm.startitem()
2805 fm.write('text', '%s', l.line[p:])
2813 fm.write('text', '%s', l.line[p:])
2806 fm.data(matched=False)
2814 fm.data(matched=False)
2807 fm.end()
2815 fm.end()
2808
2816
2809 skip = {}
2817 skip = {}
2810 revfiles = {}
2818 revfiles = {}
2811 match = scmutil.match(repo[None], pats, opts)
2819 match = scmutil.match(repo[None], pats, opts)
2812 found = False
2820 found = False
2813 follow = opts.get('follow')
2821 follow = opts.get('follow')
2814
2822
2815 def prep(ctx, fns):
2823 def prep(ctx, fns):
2816 rev = ctx.rev()
2824 rev = ctx.rev()
2817 pctx = ctx.p1()
2825 pctx = ctx.p1()
2818 parent = pctx.rev()
2826 parent = pctx.rev()
2819 matches.setdefault(rev, {})
2827 matches.setdefault(rev, {})
2820 matches.setdefault(parent, {})
2828 matches.setdefault(parent, {})
2821 files = revfiles.setdefault(rev, [])
2829 files = revfiles.setdefault(rev, [])
2822 for fn in fns:
2830 for fn in fns:
2823 flog = getfile(fn)
2831 flog = getfile(fn)
2824 try:
2832 try:
2825 fnode = ctx.filenode(fn)
2833 fnode = ctx.filenode(fn)
2826 except error.LookupError:
2834 except error.LookupError:
2827 continue
2835 continue
2828 try:
2836 try:
2829 copied = flog.renamed(fnode)
2837 copied = flog.renamed(fnode)
2830 except error.WdirUnsupported:
2838 except error.WdirUnsupported:
2831 copied = ctx[fn].renamed()
2839 copied = ctx[fn].renamed()
2832 copy = follow and copied and copied[0]
2840 copy = follow and copied and copied[0]
2833 if copy:
2841 if copy:
2834 copies.setdefault(rev, {})[fn] = copy
2842 copies.setdefault(rev, {})[fn] = copy
2835 if fn in skip:
2843 if fn in skip:
2836 if copy:
2844 if copy:
2837 skip[copy] = True
2845 skip[copy] = True
2838 continue
2846 continue
2839 files.append(fn)
2847 files.append(fn)
2840
2848
2841 if fn not in matches[rev]:
2849 if fn not in matches[rev]:
2842 try:
2850 try:
2843 content = flog.read(fnode)
2851 content = flog.read(fnode)
2844 except error.WdirUnsupported:
2852 except error.WdirUnsupported:
2845 content = ctx[fn].data()
2853 content = ctx[fn].data()
2846 grepbody(fn, rev, content)
2854 grepbody(fn, rev, content)
2847
2855
2848 pfn = copy or fn
2856 pfn = copy or fn
2849 if pfn not in matches[parent]:
2857 if pfn not in matches[parent]:
2850 try:
2858 try:
2851 fnode = pctx.filenode(pfn)
2859 fnode = pctx.filenode(pfn)
2852 grepbody(pfn, parent, flog.read(fnode))
2860 grepbody(pfn, parent, flog.read(fnode))
2853 except error.LookupError:
2861 except error.LookupError:
2854 pass
2862 pass
2855
2863
2856 ui.pager('grep')
2864 ui.pager('grep')
2857 fm = ui.formatter('grep', opts)
2865 fm = ui.formatter('grep', opts)
2858 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2866 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2859 rev = ctx.rev()
2867 rev = ctx.rev()
2860 parent = ctx.p1().rev()
2868 parent = ctx.p1().rev()
2861 for fn in sorted(revfiles.get(rev, [])):
2869 for fn in sorted(revfiles.get(rev, [])):
2862 states = matches[rev][fn]
2870 states = matches[rev][fn]
2863 copy = copies.get(rev, {}).get(fn)
2871 copy = copies.get(rev, {}).get(fn)
2864 if fn in skip:
2872 if fn in skip:
2865 if copy:
2873 if copy:
2866 skip[copy] = True
2874 skip[copy] = True
2867 continue
2875 continue
2868 pstates = matches.get(parent, {}).get(copy or fn, [])
2876 pstates = matches.get(parent, {}).get(copy or fn, [])
2869 if pstates or states:
2877 if pstates or states:
2870 r = display(fm, fn, ctx, pstates, states)
2878 r = display(fm, fn, ctx, pstates, states)
2871 found = found or r
2879 found = found or r
2872 if r and not diff and not all_files:
2880 if r and not diff and not all_files:
2873 skip[fn] = True
2881 skip[fn] = True
2874 if copy:
2882 if copy:
2875 skip[copy] = True
2883 skip[copy] = True
2876 del revfiles[rev]
2884 del revfiles[rev]
2877 # We will keep the matches dict for the duration of the window
2885 # We will keep the matches dict for the duration of the window
2878 # clear the matches dict once the window is over
2886 # clear the matches dict once the window is over
2879 if not revfiles:
2887 if not revfiles:
2880 matches.clear()
2888 matches.clear()
2881 fm.end()
2889 fm.end()
2882
2890
2883 return not found
2891 return not found
2884
2892
2885 @command('heads',
2893 @command('heads',
2886 [('r', 'rev', '',
2894 [('r', 'rev', '',
2887 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2895 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2888 ('t', 'topo', False, _('show topological heads only')),
2896 ('t', 'topo', False, _('show topological heads only')),
2889 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2897 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2890 ('c', 'closed', False, _('show normal and closed branch heads')),
2898 ('c', 'closed', False, _('show normal and closed branch heads')),
2891 ] + templateopts,
2899 ] + templateopts,
2892 _('[-ct] [-r STARTREV] [REV]...'),
2900 _('[-ct] [-r STARTREV] [REV]...'),
2893 intents={INTENT_READONLY})
2901 intents={INTENT_READONLY})
2894 def heads(ui, repo, *branchrevs, **opts):
2902 def heads(ui, repo, *branchrevs, **opts):
2895 """show branch heads
2903 """show branch heads
2896
2904
2897 With no arguments, show all open branch heads in the repository.
2905 With no arguments, show all open branch heads in the repository.
2898 Branch heads are changesets that have no descendants on the
2906 Branch heads are changesets that have no descendants on the
2899 same branch. They are where development generally takes place and
2907 same branch. They are where development generally takes place and
2900 are the usual targets for update and merge operations.
2908 are the usual targets for update and merge operations.
2901
2909
2902 If one or more REVs are given, only open branch heads on the
2910 If one or more REVs are given, only open branch heads on the
2903 branches associated with the specified changesets are shown. This
2911 branches associated with the specified changesets are shown. This
2904 means that you can use :hg:`heads .` to see the heads on the
2912 means that you can use :hg:`heads .` to see the heads on the
2905 currently checked-out branch.
2913 currently checked-out branch.
2906
2914
2907 If -c/--closed is specified, also show branch heads marked closed
2915 If -c/--closed is specified, also show branch heads marked closed
2908 (see :hg:`commit --close-branch`).
2916 (see :hg:`commit --close-branch`).
2909
2917
2910 If STARTREV is specified, only those heads that are descendants of
2918 If STARTREV is specified, only those heads that are descendants of
2911 STARTREV will be displayed.
2919 STARTREV will be displayed.
2912
2920
2913 If -t/--topo is specified, named branch mechanics will be ignored and only
2921 If -t/--topo is specified, named branch mechanics will be ignored and only
2914 topological heads (changesets with no children) will be shown.
2922 topological heads (changesets with no children) will be shown.
2915
2923
2916 Returns 0 if matching heads are found, 1 if not.
2924 Returns 0 if matching heads are found, 1 if not.
2917 """
2925 """
2918
2926
2919 opts = pycompat.byteskwargs(opts)
2927 opts = pycompat.byteskwargs(opts)
2920 start = None
2928 start = None
2921 rev = opts.get('rev')
2929 rev = opts.get('rev')
2922 if rev:
2930 if rev:
2923 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2931 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2924 start = scmutil.revsingle(repo, rev, None).node()
2932 start = scmutil.revsingle(repo, rev, None).node()
2925
2933
2926 if opts.get('topo'):
2934 if opts.get('topo'):
2927 heads = [repo[h] for h in repo.heads(start)]
2935 heads = [repo[h] for h in repo.heads(start)]
2928 else:
2936 else:
2929 heads = []
2937 heads = []
2930 for branch in repo.branchmap():
2938 for branch in repo.branchmap():
2931 heads += repo.branchheads(branch, start, opts.get('closed'))
2939 heads += repo.branchheads(branch, start, opts.get('closed'))
2932 heads = [repo[h] for h in heads]
2940 heads = [repo[h] for h in heads]
2933
2941
2934 if branchrevs:
2942 if branchrevs:
2935 branches = set(repo[r].branch()
2943 branches = set(repo[r].branch()
2936 for r in scmutil.revrange(repo, branchrevs))
2944 for r in scmutil.revrange(repo, branchrevs))
2937 heads = [h for h in heads if h.branch() in branches]
2945 heads = [h for h in heads if h.branch() in branches]
2938
2946
2939 if opts.get('active') and branchrevs:
2947 if opts.get('active') and branchrevs:
2940 dagheads = repo.heads(start)
2948 dagheads = repo.heads(start)
2941 heads = [h for h in heads if h.node() in dagheads]
2949 heads = [h for h in heads if h.node() in dagheads]
2942
2950
2943 if branchrevs:
2951 if branchrevs:
2944 haveheads = set(h.branch() for h in heads)
2952 haveheads = set(h.branch() for h in heads)
2945 if branches - haveheads:
2953 if branches - haveheads:
2946 headless = ', '.join(b for b in branches - haveheads)
2954 headless = ', '.join(b for b in branches - haveheads)
2947 msg = _('no open branch heads found on branches %s')
2955 msg = _('no open branch heads found on branches %s')
2948 if opts.get('rev'):
2956 if opts.get('rev'):
2949 msg += _(' (started at %s)') % opts['rev']
2957 msg += _(' (started at %s)') % opts['rev']
2950 ui.warn((msg + '\n') % headless)
2958 ui.warn((msg + '\n') % headless)
2951
2959
2952 if not heads:
2960 if not heads:
2953 return 1
2961 return 1
2954
2962
2955 ui.pager('heads')
2963 ui.pager('heads')
2956 heads = sorted(heads, key=lambda x: -x.rev())
2964 heads = sorted(heads, key=lambda x: -x.rev())
2957 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2965 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2958 for ctx in heads:
2966 for ctx in heads:
2959 displayer.show(ctx)
2967 displayer.show(ctx)
2960 displayer.close()
2968 displayer.close()
2961
2969
2962 @command('help',
2970 @command('help',
2963 [('e', 'extension', None, _('show only help for extensions')),
2971 [('e', 'extension', None, _('show only help for extensions')),
2964 ('c', 'command', None, _('show only help for commands')),
2972 ('c', 'command', None, _('show only help for commands')),
2965 ('k', 'keyword', None, _('show topics matching keyword')),
2973 ('k', 'keyword', None, _('show topics matching keyword')),
2966 ('s', 'system', [], _('show help for specific platform(s)')),
2974 ('s', 'system', [], _('show help for specific platform(s)')),
2967 ],
2975 ],
2968 _('[-ecks] [TOPIC]'),
2976 _('[-ecks] [TOPIC]'),
2969 norepo=True,
2977 norepo=True,
2970 intents={INTENT_READONLY})
2978 intents={INTENT_READONLY})
2971 def help_(ui, name=None, **opts):
2979 def help_(ui, name=None, **opts):
2972 """show help for a given topic or a help overview
2980 """show help for a given topic or a help overview
2973
2981
2974 With no arguments, print a list of commands with short help messages.
2982 With no arguments, print a list of commands with short help messages.
2975
2983
2976 Given a topic, extension, or command name, print help for that
2984 Given a topic, extension, or command name, print help for that
2977 topic.
2985 topic.
2978
2986
2979 Returns 0 if successful.
2987 Returns 0 if successful.
2980 """
2988 """
2981
2989
2982 keep = opts.get(r'system') or []
2990 keep = opts.get(r'system') or []
2983 if len(keep) == 0:
2991 if len(keep) == 0:
2984 if pycompat.sysplatform.startswith('win'):
2992 if pycompat.sysplatform.startswith('win'):
2985 keep.append('windows')
2993 keep.append('windows')
2986 elif pycompat.sysplatform == 'OpenVMS':
2994 elif pycompat.sysplatform == 'OpenVMS':
2987 keep.append('vms')
2995 keep.append('vms')
2988 elif pycompat.sysplatform == 'plan9':
2996 elif pycompat.sysplatform == 'plan9':
2989 keep.append('plan9')
2997 keep.append('plan9')
2990 else:
2998 else:
2991 keep.append('unix')
2999 keep.append('unix')
2992 keep.append(pycompat.sysplatform.lower())
3000 keep.append(pycompat.sysplatform.lower())
2993 if ui.verbose:
3001 if ui.verbose:
2994 keep.append('verbose')
3002 keep.append('verbose')
2995
3003
2996 commands = sys.modules[__name__]
3004 commands = sys.modules[__name__]
2997 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3005 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2998 ui.pager('help')
3006 ui.pager('help')
2999 ui.write(formatted)
3007 ui.write(formatted)
3000
3008
3001
3009
3002 @command('identify|id',
3010 @command('identify|id',
3003 [('r', 'rev', '',
3011 [('r', 'rev', '',
3004 _('identify the specified revision'), _('REV')),
3012 _('identify the specified revision'), _('REV')),
3005 ('n', 'num', None, _('show local revision number')),
3013 ('n', 'num', None, _('show local revision number')),
3006 ('i', 'id', None, _('show global revision id')),
3014 ('i', 'id', None, _('show global revision id')),
3007 ('b', 'branch', None, _('show branch')),
3015 ('b', 'branch', None, _('show branch')),
3008 ('t', 'tags', None, _('show tags')),
3016 ('t', 'tags', None, _('show tags')),
3009 ('B', 'bookmarks', None, _('show bookmarks')),
3017 ('B', 'bookmarks', None, _('show bookmarks')),
3010 ] + remoteopts + formatteropts,
3018 ] + remoteopts + formatteropts,
3011 _('[-nibtB] [-r REV] [SOURCE]'),
3019 _('[-nibtB] [-r REV] [SOURCE]'),
3012 optionalrepo=True,
3020 optionalrepo=True,
3013 intents={INTENT_READONLY})
3021 intents={INTENT_READONLY})
3014 def identify(ui, repo, source=None, rev=None,
3022 def identify(ui, repo, source=None, rev=None,
3015 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3023 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3016 """identify the working directory or specified revision
3024 """identify the working directory or specified revision
3017
3025
3018 Print a summary identifying the repository state at REV using one or
3026 Print a summary identifying the repository state at REV using one or
3019 two parent hash identifiers, followed by a "+" if the working
3027 two parent hash identifiers, followed by a "+" if the working
3020 directory has uncommitted changes, the branch name (if not default),
3028 directory has uncommitted changes, the branch name (if not default),
3021 a list of tags, and a list of bookmarks.
3029 a list of tags, and a list of bookmarks.
3022
3030
3023 When REV is not given, print a summary of the current state of the
3031 When REV is not given, print a summary of the current state of the
3024 repository including the working directory. Specify -r. to get information
3032 repository including the working directory. Specify -r. to get information
3025 of the working directory parent without scanning uncommitted changes.
3033 of the working directory parent without scanning uncommitted changes.
3026
3034
3027 Specifying a path to a repository root or Mercurial bundle will
3035 Specifying a path to a repository root or Mercurial bundle will
3028 cause lookup to operate on that repository/bundle.
3036 cause lookup to operate on that repository/bundle.
3029
3037
3030 .. container:: verbose
3038 .. container:: verbose
3031
3039
3032 Examples:
3040 Examples:
3033
3041
3034 - generate a build identifier for the working directory::
3042 - generate a build identifier for the working directory::
3035
3043
3036 hg id --id > build-id.dat
3044 hg id --id > build-id.dat
3037
3045
3038 - find the revision corresponding to a tag::
3046 - find the revision corresponding to a tag::
3039
3047
3040 hg id -n -r 1.3
3048 hg id -n -r 1.3
3041
3049
3042 - check the most recent revision of a remote repository::
3050 - check the most recent revision of a remote repository::
3043
3051
3044 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3052 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3045
3053
3046 See :hg:`log` for generating more information about specific revisions,
3054 See :hg:`log` for generating more information about specific revisions,
3047 including full hash identifiers.
3055 including full hash identifiers.
3048
3056
3049 Returns 0 if successful.
3057 Returns 0 if successful.
3050 """
3058 """
3051
3059
3052 opts = pycompat.byteskwargs(opts)
3060 opts = pycompat.byteskwargs(opts)
3053 if not repo and not source:
3061 if not repo and not source:
3054 raise error.Abort(_("there is no Mercurial repository here "
3062 raise error.Abort(_("there is no Mercurial repository here "
3055 "(.hg not found)"))
3063 "(.hg not found)"))
3056
3064
3057 default = not (num or id or branch or tags or bookmarks)
3065 default = not (num or id or branch or tags or bookmarks)
3058 output = []
3066 output = []
3059 revs = []
3067 revs = []
3060
3068
3061 if source:
3069 if source:
3062 source, branches = hg.parseurl(ui.expandpath(source))
3070 source, branches = hg.parseurl(ui.expandpath(source))
3063 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3071 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3064 repo = peer.local()
3072 repo = peer.local()
3065 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3073 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3066
3074
3067 fm = ui.formatter('identify', opts)
3075 fm = ui.formatter('identify', opts)
3068 fm.startitem()
3076 fm.startitem()
3069
3077
3070 if not repo:
3078 if not repo:
3071 if num or branch or tags:
3079 if num or branch or tags:
3072 raise error.Abort(
3080 raise error.Abort(
3073 _("can't query remote revision number, branch, or tags"))
3081 _("can't query remote revision number, branch, or tags"))
3074 if not rev and revs:
3082 if not rev and revs:
3075 rev = revs[0]
3083 rev = revs[0]
3076 if not rev:
3084 if not rev:
3077 rev = "tip"
3085 rev = "tip"
3078
3086
3079 remoterev = peer.lookup(rev)
3087 remoterev = peer.lookup(rev)
3080 hexrev = fm.hexfunc(remoterev)
3088 hexrev = fm.hexfunc(remoterev)
3081 if default or id:
3089 if default or id:
3082 output = [hexrev]
3090 output = [hexrev]
3083 fm.data(id=hexrev)
3091 fm.data(id=hexrev)
3084
3092
3085 @util.cachefunc
3093 @util.cachefunc
3086 def getbms():
3094 def getbms():
3087 bms = []
3095 bms = []
3088
3096
3089 if 'bookmarks' in peer.listkeys('namespaces'):
3097 if 'bookmarks' in peer.listkeys('namespaces'):
3090 hexremoterev = hex(remoterev)
3098 hexremoterev = hex(remoterev)
3091 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3099 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3092 if bmr == hexremoterev]
3100 if bmr == hexremoterev]
3093
3101
3094 return sorted(bms)
3102 return sorted(bms)
3095
3103
3096 if fm.isplain():
3104 if fm.isplain():
3097 if bookmarks:
3105 if bookmarks:
3098 output.extend(getbms())
3106 output.extend(getbms())
3099 elif default and not ui.quiet:
3107 elif default and not ui.quiet:
3100 # multiple bookmarks for a single parent separated by '/'
3108 # multiple bookmarks for a single parent separated by '/'
3101 bm = '/'.join(getbms())
3109 bm = '/'.join(getbms())
3102 if bm:
3110 if bm:
3103 output.append(bm)
3111 output.append(bm)
3104 else:
3112 else:
3105 fm.data(node=hex(remoterev))
3113 fm.data(node=hex(remoterev))
3106 if 'bookmarks' in fm.datahint():
3114 if 'bookmarks' in fm.datahint():
3107 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3115 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3108 else:
3116 else:
3109 if rev:
3117 if rev:
3110 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3118 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3111 ctx = scmutil.revsingle(repo, rev, None)
3119 ctx = scmutil.revsingle(repo, rev, None)
3112
3120
3113 if ctx.rev() is None:
3121 if ctx.rev() is None:
3114 ctx = repo[None]
3122 ctx = repo[None]
3115 parents = ctx.parents()
3123 parents = ctx.parents()
3116 taglist = []
3124 taglist = []
3117 for p in parents:
3125 for p in parents:
3118 taglist.extend(p.tags())
3126 taglist.extend(p.tags())
3119
3127
3120 dirty = ""
3128 dirty = ""
3121 if ctx.dirty(missing=True, merge=False, branch=False):
3129 if ctx.dirty(missing=True, merge=False, branch=False):
3122 dirty = '+'
3130 dirty = '+'
3123 fm.data(dirty=dirty)
3131 fm.data(dirty=dirty)
3124
3132
3125 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3133 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3126 if default or id:
3134 if default or id:
3127 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3135 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3128 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3136 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3129
3137
3130 if num:
3138 if num:
3131 numoutput = ["%d" % p.rev() for p in parents]
3139 numoutput = ["%d" % p.rev() for p in parents]
3132 output.append("%s%s" % ('+'.join(numoutput), dirty))
3140 output.append("%s%s" % ('+'.join(numoutput), dirty))
3133
3141
3134 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3142 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3135 for p in parents], name='node'))
3143 for p in parents], name='node'))
3136 else:
3144 else:
3137 hexoutput = fm.hexfunc(ctx.node())
3145 hexoutput = fm.hexfunc(ctx.node())
3138 if default or id:
3146 if default or id:
3139 output = [hexoutput]
3147 output = [hexoutput]
3140 fm.data(id=hexoutput)
3148 fm.data(id=hexoutput)
3141
3149
3142 if num:
3150 if num:
3143 output.append(pycompat.bytestr(ctx.rev()))
3151 output.append(pycompat.bytestr(ctx.rev()))
3144 taglist = ctx.tags()
3152 taglist = ctx.tags()
3145
3153
3146 if default and not ui.quiet:
3154 if default and not ui.quiet:
3147 b = ctx.branch()
3155 b = ctx.branch()
3148 if b != 'default':
3156 if b != 'default':
3149 output.append("(%s)" % b)
3157 output.append("(%s)" % b)
3150
3158
3151 # multiple tags for a single parent separated by '/'
3159 # multiple tags for a single parent separated by '/'
3152 t = '/'.join(taglist)
3160 t = '/'.join(taglist)
3153 if t:
3161 if t:
3154 output.append(t)
3162 output.append(t)
3155
3163
3156 # multiple bookmarks for a single parent separated by '/'
3164 # multiple bookmarks for a single parent separated by '/'
3157 bm = '/'.join(ctx.bookmarks())
3165 bm = '/'.join(ctx.bookmarks())
3158 if bm:
3166 if bm:
3159 output.append(bm)
3167 output.append(bm)
3160 else:
3168 else:
3161 if branch:
3169 if branch:
3162 output.append(ctx.branch())
3170 output.append(ctx.branch())
3163
3171
3164 if tags:
3172 if tags:
3165 output.extend(taglist)
3173 output.extend(taglist)
3166
3174
3167 if bookmarks:
3175 if bookmarks:
3168 output.extend(ctx.bookmarks())
3176 output.extend(ctx.bookmarks())
3169
3177
3170 fm.data(node=ctx.hex())
3178 fm.data(node=ctx.hex())
3171 fm.data(branch=ctx.branch())
3179 fm.data(branch=ctx.branch())
3172 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3180 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3173 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3181 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3174 fm.context(ctx=ctx)
3182 fm.context(ctx=ctx)
3175
3183
3176 fm.plain("%s\n" % ' '.join(output))
3184 fm.plain("%s\n" % ' '.join(output))
3177 fm.end()
3185 fm.end()
3178
3186
3179 @command('import|patch',
3187 @command('import|patch',
3180 [('p', 'strip', 1,
3188 [('p', 'strip', 1,
3181 _('directory strip option for patch. This has the same '
3189 _('directory strip option for patch. This has the same '
3182 'meaning as the corresponding patch option'), _('NUM')),
3190 'meaning as the corresponding patch option'), _('NUM')),
3183 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3191 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3184 ('e', 'edit', False, _('invoke editor on commit messages')),
3192 ('e', 'edit', False, _('invoke editor on commit messages')),
3185 ('f', 'force', None,
3193 ('f', 'force', None,
3186 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3194 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3187 ('', 'no-commit', None,
3195 ('', 'no-commit', None,
3188 _("don't commit, just update the working directory")),
3196 _("don't commit, just update the working directory")),
3189 ('', 'bypass', None,
3197 ('', 'bypass', None,
3190 _("apply patch without touching the working directory")),
3198 _("apply patch without touching the working directory")),
3191 ('', 'partial', None,
3199 ('', 'partial', None,
3192 _('commit even if some hunks fail')),
3200 _('commit even if some hunks fail')),
3193 ('', 'exact', None,
3201 ('', 'exact', None,
3194 _('abort if patch would apply lossily')),
3202 _('abort if patch would apply lossily')),
3195 ('', 'prefix', '',
3203 ('', 'prefix', '',
3196 _('apply patch to subdirectory'), _('DIR')),
3204 _('apply patch to subdirectory'), _('DIR')),
3197 ('', 'import-branch', None,
3205 ('', 'import-branch', None,
3198 _('use any branch information in patch (implied by --exact)'))] +
3206 _('use any branch information in patch (implied by --exact)'))] +
3199 commitopts + commitopts2 + similarityopts,
3207 commitopts + commitopts2 + similarityopts,
3200 _('[OPTION]... PATCH...'))
3208 _('[OPTION]... PATCH...'))
3201 def import_(ui, repo, patch1=None, *patches, **opts):
3209 def import_(ui, repo, patch1=None, *patches, **opts):
3202 """import an ordered set of patches
3210 """import an ordered set of patches
3203
3211
3204 Import a list of patches and commit them individually (unless
3212 Import a list of patches and commit them individually (unless
3205 --no-commit is specified).
3213 --no-commit is specified).
3206
3214
3207 To read a patch from standard input (stdin), use "-" as the patch
3215 To read a patch from standard input (stdin), use "-" as the patch
3208 name. If a URL is specified, the patch will be downloaded from
3216 name. If a URL is specified, the patch will be downloaded from
3209 there.
3217 there.
3210
3218
3211 Import first applies changes to the working directory (unless
3219 Import first applies changes to the working directory (unless
3212 --bypass is specified), import will abort if there are outstanding
3220 --bypass is specified), import will abort if there are outstanding
3213 changes.
3221 changes.
3214
3222
3215 Use --bypass to apply and commit patches directly to the
3223 Use --bypass to apply and commit patches directly to the
3216 repository, without affecting the working directory. Without
3224 repository, without affecting the working directory. Without
3217 --exact, patches will be applied on top of the working directory
3225 --exact, patches will be applied on top of the working directory
3218 parent revision.
3226 parent revision.
3219
3227
3220 You can import a patch straight from a mail message. Even patches
3228 You can import a patch straight from a mail message. Even patches
3221 as attachments work (to use the body part, it must have type
3229 as attachments work (to use the body part, it must have type
3222 text/plain or text/x-patch). From and Subject headers of email
3230 text/plain or text/x-patch). From and Subject headers of email
3223 message are used as default committer and commit message. All
3231 message are used as default committer and commit message. All
3224 text/plain body parts before first diff are added to the commit
3232 text/plain body parts before first diff are added to the commit
3225 message.
3233 message.
3226
3234
3227 If the imported patch was generated by :hg:`export`, user and
3235 If the imported patch was generated by :hg:`export`, user and
3228 description from patch override values from message headers and
3236 description from patch override values from message headers and
3229 body. Values given on command line with -m/--message and -u/--user
3237 body. Values given on command line with -m/--message and -u/--user
3230 override these.
3238 override these.
3231
3239
3232 If --exact is specified, import will set the working directory to
3240 If --exact is specified, import will set the working directory to
3233 the parent of each patch before applying it, and will abort if the
3241 the parent of each patch before applying it, and will abort if the
3234 resulting changeset has a different ID than the one recorded in
3242 resulting changeset has a different ID than the one recorded in
3235 the patch. This will guard against various ways that portable
3243 the patch. This will guard against various ways that portable
3236 patch formats and mail systems might fail to transfer Mercurial
3244 patch formats and mail systems might fail to transfer Mercurial
3237 data or metadata. See :hg:`bundle` for lossless transmission.
3245 data or metadata. See :hg:`bundle` for lossless transmission.
3238
3246
3239 Use --partial to ensure a changeset will be created from the patch
3247 Use --partial to ensure a changeset will be created from the patch
3240 even if some hunks fail to apply. Hunks that fail to apply will be
3248 even if some hunks fail to apply. Hunks that fail to apply will be
3241 written to a <target-file>.rej file. Conflicts can then be resolved
3249 written to a <target-file>.rej file. Conflicts can then be resolved
3242 by hand before :hg:`commit --amend` is run to update the created
3250 by hand before :hg:`commit --amend` is run to update the created
3243 changeset. This flag exists to let people import patches that
3251 changeset. This flag exists to let people import patches that
3244 partially apply without losing the associated metadata (author,
3252 partially apply without losing the associated metadata (author,
3245 date, description, ...).
3253 date, description, ...).
3246
3254
3247 .. note::
3255 .. note::
3248
3256
3249 When no hunks apply cleanly, :hg:`import --partial` will create
3257 When no hunks apply cleanly, :hg:`import --partial` will create
3250 an empty changeset, importing only the patch metadata.
3258 an empty changeset, importing only the patch metadata.
3251
3259
3252 With -s/--similarity, hg will attempt to discover renames and
3260 With -s/--similarity, hg will attempt to discover renames and
3253 copies in the patch in the same way as :hg:`addremove`.
3261 copies in the patch in the same way as :hg:`addremove`.
3254
3262
3255 It is possible to use external patch programs to perform the patch
3263 It is possible to use external patch programs to perform the patch
3256 by setting the ``ui.patch`` configuration option. For the default
3264 by setting the ``ui.patch`` configuration option. For the default
3257 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3265 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3258 See :hg:`help config` for more information about configuration
3266 See :hg:`help config` for more information about configuration
3259 files and how to use these options.
3267 files and how to use these options.
3260
3268
3261 See :hg:`help dates` for a list of formats valid for -d/--date.
3269 See :hg:`help dates` for a list of formats valid for -d/--date.
3262
3270
3263 .. container:: verbose
3271 .. container:: verbose
3264
3272
3265 Examples:
3273 Examples:
3266
3274
3267 - import a traditional patch from a website and detect renames::
3275 - import a traditional patch from a website and detect renames::
3268
3276
3269 hg import -s 80 http://example.com/bugfix.patch
3277 hg import -s 80 http://example.com/bugfix.patch
3270
3278
3271 - import a changeset from an hgweb server::
3279 - import a changeset from an hgweb server::
3272
3280
3273 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3281 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3274
3282
3275 - import all the patches in an Unix-style mbox::
3283 - import all the patches in an Unix-style mbox::
3276
3284
3277 hg import incoming-patches.mbox
3285 hg import incoming-patches.mbox
3278
3286
3279 - import patches from stdin::
3287 - import patches from stdin::
3280
3288
3281 hg import -
3289 hg import -
3282
3290
3283 - attempt to exactly restore an exported changeset (not always
3291 - attempt to exactly restore an exported changeset (not always
3284 possible)::
3292 possible)::
3285
3293
3286 hg import --exact proposed-fix.patch
3294 hg import --exact proposed-fix.patch
3287
3295
3288 - use an external tool to apply a patch which is too fuzzy for
3296 - use an external tool to apply a patch which is too fuzzy for
3289 the default internal tool.
3297 the default internal tool.
3290
3298
3291 hg import --config ui.patch="patch --merge" fuzzy.patch
3299 hg import --config ui.patch="patch --merge" fuzzy.patch
3292
3300
3293 - change the default fuzzing from 2 to a less strict 7
3301 - change the default fuzzing from 2 to a less strict 7
3294
3302
3295 hg import --config ui.fuzz=7 fuzz.patch
3303 hg import --config ui.fuzz=7 fuzz.patch
3296
3304
3297 Returns 0 on success, 1 on partial success (see --partial).
3305 Returns 0 on success, 1 on partial success (see --partial).
3298 """
3306 """
3299
3307
3300 opts = pycompat.byteskwargs(opts)
3308 opts = pycompat.byteskwargs(opts)
3301 if not patch1:
3309 if not patch1:
3302 raise error.Abort(_('need at least one patch to import'))
3310 raise error.Abort(_('need at least one patch to import'))
3303
3311
3304 patches = (patch1,) + patches
3312 patches = (patch1,) + patches
3305
3313
3306 date = opts.get('date')
3314 date = opts.get('date')
3307 if date:
3315 if date:
3308 opts['date'] = dateutil.parsedate(date)
3316 opts['date'] = dateutil.parsedate(date)
3309
3317
3310 exact = opts.get('exact')
3318 exact = opts.get('exact')
3311 update = not opts.get('bypass')
3319 update = not opts.get('bypass')
3312 if not update and opts.get('no_commit'):
3320 if not update and opts.get('no_commit'):
3313 raise error.Abort(_('cannot use --no-commit with --bypass'))
3321 raise error.Abort(_('cannot use --no-commit with --bypass'))
3314 try:
3322 try:
3315 sim = float(opts.get('similarity') or 0)
3323 sim = float(opts.get('similarity') or 0)
3316 except ValueError:
3324 except ValueError:
3317 raise error.Abort(_('similarity must be a number'))
3325 raise error.Abort(_('similarity must be a number'))
3318 if sim < 0 or sim > 100:
3326 if sim < 0 or sim > 100:
3319 raise error.Abort(_('similarity must be between 0 and 100'))
3327 raise error.Abort(_('similarity must be between 0 and 100'))
3320 if sim and not update:
3328 if sim and not update:
3321 raise error.Abort(_('cannot use --similarity with --bypass'))
3329 raise error.Abort(_('cannot use --similarity with --bypass'))
3322 if exact:
3330 if exact:
3323 if opts.get('edit'):
3331 if opts.get('edit'):
3324 raise error.Abort(_('cannot use --exact with --edit'))
3332 raise error.Abort(_('cannot use --exact with --edit'))
3325 if opts.get('prefix'):
3333 if opts.get('prefix'):
3326 raise error.Abort(_('cannot use --exact with --prefix'))
3334 raise error.Abort(_('cannot use --exact with --prefix'))
3327
3335
3328 base = opts["base"]
3336 base = opts["base"]
3329 msgs = []
3337 msgs = []
3330 ret = 0
3338 ret = 0
3331
3339
3332 with repo.wlock():
3340 with repo.wlock():
3333 if update:
3341 if update:
3334 cmdutil.checkunfinished(repo)
3342 cmdutil.checkunfinished(repo)
3335 if (exact or not opts.get('force')):
3343 if (exact or not opts.get('force')):
3336 cmdutil.bailifchanged(repo)
3344 cmdutil.bailifchanged(repo)
3337
3345
3338 if not opts.get('no_commit'):
3346 if not opts.get('no_commit'):
3339 lock = repo.lock
3347 lock = repo.lock
3340 tr = lambda: repo.transaction('import')
3348 tr = lambda: repo.transaction('import')
3341 dsguard = util.nullcontextmanager
3349 dsguard = util.nullcontextmanager
3342 else:
3350 else:
3343 lock = util.nullcontextmanager
3351 lock = util.nullcontextmanager
3344 tr = util.nullcontextmanager
3352 tr = util.nullcontextmanager
3345 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3353 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3346 with lock(), tr(), dsguard():
3354 with lock(), tr(), dsguard():
3347 parents = repo[None].parents()
3355 parents = repo[None].parents()
3348 for patchurl in patches:
3356 for patchurl in patches:
3349 if patchurl == '-':
3357 if patchurl == '-':
3350 ui.status(_('applying patch from stdin\n'))
3358 ui.status(_('applying patch from stdin\n'))
3351 patchfile = ui.fin
3359 patchfile = ui.fin
3352 patchurl = 'stdin' # for error message
3360 patchurl = 'stdin' # for error message
3353 else:
3361 else:
3354 patchurl = os.path.join(base, patchurl)
3362 patchurl = os.path.join(base, patchurl)
3355 ui.status(_('applying %s\n') % patchurl)
3363 ui.status(_('applying %s\n') % patchurl)
3356 patchfile = hg.openpath(ui, patchurl)
3364 patchfile = hg.openpath(ui, patchurl)
3357
3365
3358 haspatch = False
3366 haspatch = False
3359 for hunk in patch.split(patchfile):
3367 for hunk in patch.split(patchfile):
3360 with patch.extract(ui, hunk) as patchdata:
3368 with patch.extract(ui, hunk) as patchdata:
3361 msg, node, rej = cmdutil.tryimportone(ui, repo,
3369 msg, node, rej = cmdutil.tryimportone(ui, repo,
3362 patchdata,
3370 patchdata,
3363 parents, opts,
3371 parents, opts,
3364 msgs, hg.clean)
3372 msgs, hg.clean)
3365 if msg:
3373 if msg:
3366 haspatch = True
3374 haspatch = True
3367 ui.note(msg + '\n')
3375 ui.note(msg + '\n')
3368 if update or exact:
3376 if update or exact:
3369 parents = repo[None].parents()
3377 parents = repo[None].parents()
3370 else:
3378 else:
3371 parents = [repo[node]]
3379 parents = [repo[node]]
3372 if rej:
3380 if rej:
3373 ui.write_err(_("patch applied partially\n"))
3381 ui.write_err(_("patch applied partially\n"))
3374 ui.write_err(_("(fix the .rej files and run "
3382 ui.write_err(_("(fix the .rej files and run "
3375 "`hg commit --amend`)\n"))
3383 "`hg commit --amend`)\n"))
3376 ret = 1
3384 ret = 1
3377 break
3385 break
3378
3386
3379 if not haspatch:
3387 if not haspatch:
3380 raise error.Abort(_('%s: no diffs found') % patchurl)
3388 raise error.Abort(_('%s: no diffs found') % patchurl)
3381
3389
3382 if msgs:
3390 if msgs:
3383 repo.savecommitmessage('\n* * *\n'.join(msgs))
3391 repo.savecommitmessage('\n* * *\n'.join(msgs))
3384 return ret
3392 return ret
3385
3393
3386 @command('incoming|in',
3394 @command('incoming|in',
3387 [('f', 'force', None,
3395 [('f', 'force', None,
3388 _('run even if remote repository is unrelated')),
3396 _('run even if remote repository is unrelated')),
3389 ('n', 'newest-first', None, _('show newest record first')),
3397 ('n', 'newest-first', None, _('show newest record first')),
3390 ('', 'bundle', '',
3398 ('', 'bundle', '',
3391 _('file to store the bundles into'), _('FILE')),
3399 _('file to store the bundles into'), _('FILE')),
3392 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3400 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3393 ('B', 'bookmarks', False, _("compare bookmarks")),
3401 ('B', 'bookmarks', False, _("compare bookmarks")),
3394 ('b', 'branch', [],
3402 ('b', 'branch', [],
3395 _('a specific branch you would like to pull'), _('BRANCH')),
3403 _('a specific branch you would like to pull'), _('BRANCH')),
3396 ] + logopts + remoteopts + subrepoopts,
3404 ] + logopts + remoteopts + subrepoopts,
3397 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3405 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3398 def incoming(ui, repo, source="default", **opts):
3406 def incoming(ui, repo, source="default", **opts):
3399 """show new changesets found in source
3407 """show new changesets found in source
3400
3408
3401 Show new changesets found in the specified path/URL or the default
3409 Show new changesets found in the specified path/URL or the default
3402 pull location. These are the changesets that would have been pulled
3410 pull location. These are the changesets that would have been pulled
3403 by :hg:`pull` at the time you issued this command.
3411 by :hg:`pull` at the time you issued this command.
3404
3412
3405 See pull for valid source format details.
3413 See pull for valid source format details.
3406
3414
3407 .. container:: verbose
3415 .. container:: verbose
3408
3416
3409 With -B/--bookmarks, the result of bookmark comparison between
3417 With -B/--bookmarks, the result of bookmark comparison between
3410 local and remote repositories is displayed. With -v/--verbose,
3418 local and remote repositories is displayed. With -v/--verbose,
3411 status is also displayed for each bookmark like below::
3419 status is also displayed for each bookmark like below::
3412
3420
3413 BM1 01234567890a added
3421 BM1 01234567890a added
3414 BM2 1234567890ab advanced
3422 BM2 1234567890ab advanced
3415 BM3 234567890abc diverged
3423 BM3 234567890abc diverged
3416 BM4 34567890abcd changed
3424 BM4 34567890abcd changed
3417
3425
3418 The action taken locally when pulling depends on the
3426 The action taken locally when pulling depends on the
3419 status of each bookmark:
3427 status of each bookmark:
3420
3428
3421 :``added``: pull will create it
3429 :``added``: pull will create it
3422 :``advanced``: pull will update it
3430 :``advanced``: pull will update it
3423 :``diverged``: pull will create a divergent bookmark
3431 :``diverged``: pull will create a divergent bookmark
3424 :``changed``: result depends on remote changesets
3432 :``changed``: result depends on remote changesets
3425
3433
3426 From the point of view of pulling behavior, bookmark
3434 From the point of view of pulling behavior, bookmark
3427 existing only in the remote repository are treated as ``added``,
3435 existing only in the remote repository are treated as ``added``,
3428 even if it is in fact locally deleted.
3436 even if it is in fact locally deleted.
3429
3437
3430 .. container:: verbose
3438 .. container:: verbose
3431
3439
3432 For remote repository, using --bundle avoids downloading the
3440 For remote repository, using --bundle avoids downloading the
3433 changesets twice if the incoming is followed by a pull.
3441 changesets twice if the incoming is followed by a pull.
3434
3442
3435 Examples:
3443 Examples:
3436
3444
3437 - show incoming changes with patches and full description::
3445 - show incoming changes with patches and full description::
3438
3446
3439 hg incoming -vp
3447 hg incoming -vp
3440
3448
3441 - show incoming changes excluding merges, store a bundle::
3449 - show incoming changes excluding merges, store a bundle::
3442
3450
3443 hg in -vpM --bundle incoming.hg
3451 hg in -vpM --bundle incoming.hg
3444 hg pull incoming.hg
3452 hg pull incoming.hg
3445
3453
3446 - briefly list changes inside a bundle::
3454 - briefly list changes inside a bundle::
3447
3455
3448 hg in changes.hg -T "{desc|firstline}\\n"
3456 hg in changes.hg -T "{desc|firstline}\\n"
3449
3457
3450 Returns 0 if there are incoming changes, 1 otherwise.
3458 Returns 0 if there are incoming changes, 1 otherwise.
3451 """
3459 """
3452 opts = pycompat.byteskwargs(opts)
3460 opts = pycompat.byteskwargs(opts)
3453 if opts.get('graph'):
3461 if opts.get('graph'):
3454 logcmdutil.checkunsupportedgraphflags([], opts)
3462 logcmdutil.checkunsupportedgraphflags([], opts)
3455 def display(other, chlist, displayer):
3463 def display(other, chlist, displayer):
3456 revdag = logcmdutil.graphrevs(other, chlist, opts)
3464 revdag = logcmdutil.graphrevs(other, chlist, opts)
3457 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3465 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3458 graphmod.asciiedges)
3466 graphmod.asciiedges)
3459
3467
3460 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3468 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3461 return 0
3469 return 0
3462
3470
3463 if opts.get('bundle') and opts.get('subrepos'):
3471 if opts.get('bundle') and opts.get('subrepos'):
3464 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3472 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3465
3473
3466 if opts.get('bookmarks'):
3474 if opts.get('bookmarks'):
3467 source, branches = hg.parseurl(ui.expandpath(source),
3475 source, branches = hg.parseurl(ui.expandpath(source),
3468 opts.get('branch'))
3476 opts.get('branch'))
3469 other = hg.peer(repo, opts, source)
3477 other = hg.peer(repo, opts, source)
3470 if 'bookmarks' not in other.listkeys('namespaces'):
3478 if 'bookmarks' not in other.listkeys('namespaces'):
3471 ui.warn(_("remote doesn't support bookmarks\n"))
3479 ui.warn(_("remote doesn't support bookmarks\n"))
3472 return 0
3480 return 0
3473 ui.pager('incoming')
3481 ui.pager('incoming')
3474 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3482 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3475 return bookmarks.incoming(ui, repo, other)
3483 return bookmarks.incoming(ui, repo, other)
3476
3484
3477 repo._subtoppath = ui.expandpath(source)
3485 repo._subtoppath = ui.expandpath(source)
3478 try:
3486 try:
3479 return hg.incoming(ui, repo, source, opts)
3487 return hg.incoming(ui, repo, source, opts)
3480 finally:
3488 finally:
3481 del repo._subtoppath
3489 del repo._subtoppath
3482
3490
3483
3491
3484 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3492 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3485 norepo=True)
3493 norepo=True)
3486 def init(ui, dest=".", **opts):
3494 def init(ui, dest=".", **opts):
3487 """create a new repository in the given directory
3495 """create a new repository in the given directory
3488
3496
3489 Initialize a new repository in the given directory. If the given
3497 Initialize a new repository in the given directory. If the given
3490 directory does not exist, it will be created.
3498 directory does not exist, it will be created.
3491
3499
3492 If no directory is given, the current directory is used.
3500 If no directory is given, the current directory is used.
3493
3501
3494 It is possible to specify an ``ssh://`` URL as the destination.
3502 It is possible to specify an ``ssh://`` URL as the destination.
3495 See :hg:`help urls` for more information.
3503 See :hg:`help urls` for more information.
3496
3504
3497 Returns 0 on success.
3505 Returns 0 on success.
3498 """
3506 """
3499 opts = pycompat.byteskwargs(opts)
3507 opts = pycompat.byteskwargs(opts)
3500 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3508 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3501
3509
3502 @command('locate',
3510 @command('locate',
3503 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3511 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3504 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3512 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3505 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3513 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3506 ] + walkopts,
3514 ] + walkopts,
3507 _('[OPTION]... [PATTERN]...'))
3515 _('[OPTION]... [PATTERN]...'))
3508 def locate(ui, repo, *pats, **opts):
3516 def locate(ui, repo, *pats, **opts):
3509 """locate files matching specific patterns (DEPRECATED)
3517 """locate files matching specific patterns (DEPRECATED)
3510
3518
3511 Print files under Mercurial control in the working directory whose
3519 Print files under Mercurial control in the working directory whose
3512 names match the given patterns.
3520 names match the given patterns.
3513
3521
3514 By default, this command searches all directories in the working
3522 By default, this command searches all directories in the working
3515 directory. To search just the current directory and its
3523 directory. To search just the current directory and its
3516 subdirectories, use "--include .".
3524 subdirectories, use "--include .".
3517
3525
3518 If no patterns are given to match, this command prints the names
3526 If no patterns are given to match, this command prints the names
3519 of all files under Mercurial control in the working directory.
3527 of all files under Mercurial control in the working directory.
3520
3528
3521 If you want to feed the output of this command into the "xargs"
3529 If you want to feed the output of this command into the "xargs"
3522 command, use the -0 option to both this command and "xargs". This
3530 command, use the -0 option to both this command and "xargs". This
3523 will avoid the problem of "xargs" treating single filenames that
3531 will avoid the problem of "xargs" treating single filenames that
3524 contain whitespace as multiple filenames.
3532 contain whitespace as multiple filenames.
3525
3533
3526 See :hg:`help files` for a more versatile command.
3534 See :hg:`help files` for a more versatile command.
3527
3535
3528 Returns 0 if a match is found, 1 otherwise.
3536 Returns 0 if a match is found, 1 otherwise.
3529 """
3537 """
3530 opts = pycompat.byteskwargs(opts)
3538 opts = pycompat.byteskwargs(opts)
3531 if opts.get('print0'):
3539 if opts.get('print0'):
3532 end = '\0'
3540 end = '\0'
3533 else:
3541 else:
3534 end = '\n'
3542 end = '\n'
3535 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3543 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3536
3544
3537 ret = 1
3545 ret = 1
3538 m = scmutil.match(ctx, pats, opts, default='relglob',
3546 m = scmutil.match(ctx, pats, opts, default='relglob',
3539 badfn=lambda x, y: False)
3547 badfn=lambda x, y: False)
3540
3548
3541 ui.pager('locate')
3549 ui.pager('locate')
3542 if ctx.rev() is None:
3550 if ctx.rev() is None:
3543 # When run on the working copy, "locate" includes removed files, so
3551 # When run on the working copy, "locate" includes removed files, so
3544 # we get the list of files from the dirstate.
3552 # we get the list of files from the dirstate.
3545 filesgen = sorted(repo.dirstate.matches(m))
3553 filesgen = sorted(repo.dirstate.matches(m))
3546 else:
3554 else:
3547 filesgen = ctx.matches(m)
3555 filesgen = ctx.matches(m)
3548 for abs in filesgen:
3556 for abs in filesgen:
3549 if opts.get('fullpath'):
3557 if opts.get('fullpath'):
3550 ui.write(repo.wjoin(abs), end)
3558 ui.write(repo.wjoin(abs), end)
3551 else:
3559 else:
3552 ui.write(((pats and m.rel(abs)) or abs), end)
3560 ui.write(((pats and m.rel(abs)) or abs), end)
3553 ret = 0
3561 ret = 0
3554
3562
3555 return ret
3563 return ret
3556
3564
3557 @command('^log|history',
3565 @command('^log|history',
3558 [('f', 'follow', None,
3566 [('f', 'follow', None,
3559 _('follow changeset history, or file history across copies and renames')),
3567 _('follow changeset history, or file history across copies and renames')),
3560 ('', 'follow-first', None,
3568 ('', 'follow-first', None,
3561 _('only follow the first parent of merge changesets (DEPRECATED)')),
3569 _('only follow the first parent of merge changesets (DEPRECATED)')),
3562 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3570 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3563 ('C', 'copies', None, _('show copied files')),
3571 ('C', 'copies', None, _('show copied files')),
3564 ('k', 'keyword', [],
3572 ('k', 'keyword', [],
3565 _('do case-insensitive search for a given text'), _('TEXT')),
3573 _('do case-insensitive search for a given text'), _('TEXT')),
3566 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3574 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3567 ('L', 'line-range', [],
3575 ('L', 'line-range', [],
3568 _('follow line range of specified file (EXPERIMENTAL)'),
3576 _('follow line range of specified file (EXPERIMENTAL)'),
3569 _('FILE,RANGE')),
3577 _('FILE,RANGE')),
3570 ('', 'removed', None, _('include revisions where files were removed')),
3578 ('', 'removed', None, _('include revisions where files were removed')),
3571 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3579 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3572 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3580 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3573 ('', 'only-branch', [],
3581 ('', 'only-branch', [],
3574 _('show only changesets within the given named branch (DEPRECATED)'),
3582 _('show only changesets within the given named branch (DEPRECATED)'),
3575 _('BRANCH')),
3583 _('BRANCH')),
3576 ('b', 'branch', [],
3584 ('b', 'branch', [],
3577 _('show changesets within the given named branch'), _('BRANCH')),
3585 _('show changesets within the given named branch'), _('BRANCH')),
3578 ('P', 'prune', [],
3586 ('P', 'prune', [],
3579 _('do not display revision or any of its ancestors'), _('REV')),
3587 _('do not display revision or any of its ancestors'), _('REV')),
3580 ] + logopts + walkopts,
3588 ] + logopts + walkopts,
3581 _('[OPTION]... [FILE]'),
3589 _('[OPTION]... [FILE]'),
3582 inferrepo=True,
3590 inferrepo=True,
3583 intents={INTENT_READONLY})
3591 intents={INTENT_READONLY})
3584 def log(ui, repo, *pats, **opts):
3592 def log(ui, repo, *pats, **opts):
3585 """show revision history of entire repository or files
3593 """show revision history of entire repository or files
3586
3594
3587 Print the revision history of the specified files or the entire
3595 Print the revision history of the specified files or the entire
3588 project.
3596 project.
3589
3597
3590 If no revision range is specified, the default is ``tip:0`` unless
3598 If no revision range is specified, the default is ``tip:0`` unless
3591 --follow is set, in which case the working directory parent is
3599 --follow is set, in which case the working directory parent is
3592 used as the starting revision.
3600 used as the starting revision.
3593
3601
3594 File history is shown without following rename or copy history of
3602 File history is shown without following rename or copy history of
3595 files. Use -f/--follow with a filename to follow history across
3603 files. Use -f/--follow with a filename to follow history across
3596 renames and copies. --follow without a filename will only show
3604 renames and copies. --follow without a filename will only show
3597 ancestors of the starting revision.
3605 ancestors of the starting revision.
3598
3606
3599 By default this command prints revision number and changeset id,
3607 By default this command prints revision number and changeset id,
3600 tags, non-trivial parents, user, date and time, and a summary for
3608 tags, non-trivial parents, user, date and time, and a summary for
3601 each commit. When the -v/--verbose switch is used, the list of
3609 each commit. When the -v/--verbose switch is used, the list of
3602 changed files and full commit message are shown.
3610 changed files and full commit message are shown.
3603
3611
3604 With --graph the revisions are shown as an ASCII art DAG with the most
3612 With --graph the revisions are shown as an ASCII art DAG with the most
3605 recent changeset at the top.
3613 recent changeset at the top.
3606 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3614 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3607 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3615 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3608 changeset from the lines below is a parent of the 'o' merge on the same
3616 changeset from the lines below is a parent of the 'o' merge on the same
3609 line.
3617 line.
3610 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3618 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3611 of a '|' indicates one or more revisions in a path are omitted.
3619 of a '|' indicates one or more revisions in a path are omitted.
3612
3620
3613 .. container:: verbose
3621 .. container:: verbose
3614
3622
3615 Use -L/--line-range FILE,M:N options to follow the history of lines
3623 Use -L/--line-range FILE,M:N options to follow the history of lines
3616 from M to N in FILE. With -p/--patch only diff hunks affecting
3624 from M to N in FILE. With -p/--patch only diff hunks affecting
3617 specified line range will be shown. This option requires --follow;
3625 specified line range will be shown. This option requires --follow;
3618 it can be specified multiple times. Currently, this option is not
3626 it can be specified multiple times. Currently, this option is not
3619 compatible with --graph. This option is experimental.
3627 compatible with --graph. This option is experimental.
3620
3628
3621 .. note::
3629 .. note::
3622
3630
3623 :hg:`log --patch` may generate unexpected diff output for merge
3631 :hg:`log --patch` may generate unexpected diff output for merge
3624 changesets, as it will only compare the merge changeset against
3632 changesets, as it will only compare the merge changeset against
3625 its first parent. Also, only files different from BOTH parents
3633 its first parent. Also, only files different from BOTH parents
3626 will appear in files:.
3634 will appear in files:.
3627
3635
3628 .. note::
3636 .. note::
3629
3637
3630 For performance reasons, :hg:`log FILE` may omit duplicate changes
3638 For performance reasons, :hg:`log FILE` may omit duplicate changes
3631 made on branches and will not show removals or mode changes. To
3639 made on branches and will not show removals or mode changes. To
3632 see all such changes, use the --removed switch.
3640 see all such changes, use the --removed switch.
3633
3641
3634 .. container:: verbose
3642 .. container:: verbose
3635
3643
3636 .. note::
3644 .. note::
3637
3645
3638 The history resulting from -L/--line-range options depends on diff
3646 The history resulting from -L/--line-range options depends on diff
3639 options; for instance if white-spaces are ignored, respective changes
3647 options; for instance if white-spaces are ignored, respective changes
3640 with only white-spaces in specified line range will not be listed.
3648 with only white-spaces in specified line range will not be listed.
3641
3649
3642 .. container:: verbose
3650 .. container:: verbose
3643
3651
3644 Some examples:
3652 Some examples:
3645
3653
3646 - changesets with full descriptions and file lists::
3654 - changesets with full descriptions and file lists::
3647
3655
3648 hg log -v
3656 hg log -v
3649
3657
3650 - changesets ancestral to the working directory::
3658 - changesets ancestral to the working directory::
3651
3659
3652 hg log -f
3660 hg log -f
3653
3661
3654 - last 10 commits on the current branch::
3662 - last 10 commits on the current branch::
3655
3663
3656 hg log -l 10 -b .
3664 hg log -l 10 -b .
3657
3665
3658 - changesets showing all modifications of a file, including removals::
3666 - changesets showing all modifications of a file, including removals::
3659
3667
3660 hg log --removed file.c
3668 hg log --removed file.c
3661
3669
3662 - all changesets that touch a directory, with diffs, excluding merges::
3670 - all changesets that touch a directory, with diffs, excluding merges::
3663
3671
3664 hg log -Mp lib/
3672 hg log -Mp lib/
3665
3673
3666 - all revision numbers that match a keyword::
3674 - all revision numbers that match a keyword::
3667
3675
3668 hg log -k bug --template "{rev}\\n"
3676 hg log -k bug --template "{rev}\\n"
3669
3677
3670 - the full hash identifier of the working directory parent::
3678 - the full hash identifier of the working directory parent::
3671
3679
3672 hg log -r . --template "{node}\\n"
3680 hg log -r . --template "{node}\\n"
3673
3681
3674 - list available log templates::
3682 - list available log templates::
3675
3683
3676 hg log -T list
3684 hg log -T list
3677
3685
3678 - check if a given changeset is included in a tagged release::
3686 - check if a given changeset is included in a tagged release::
3679
3687
3680 hg log -r "a21ccf and ancestor(1.9)"
3688 hg log -r "a21ccf and ancestor(1.9)"
3681
3689
3682 - find all changesets by some user in a date range::
3690 - find all changesets by some user in a date range::
3683
3691
3684 hg log -k alice -d "may 2008 to jul 2008"
3692 hg log -k alice -d "may 2008 to jul 2008"
3685
3693
3686 - summary of all changesets after the last tag::
3694 - summary of all changesets after the last tag::
3687
3695
3688 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3696 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3689
3697
3690 - changesets touching lines 13 to 23 for file.c::
3698 - changesets touching lines 13 to 23 for file.c::
3691
3699
3692 hg log -L file.c,13:23
3700 hg log -L file.c,13:23
3693
3701
3694 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3702 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3695 main.c with patch::
3703 main.c with patch::
3696
3704
3697 hg log -L file.c,13:23 -L main.c,2:6 -p
3705 hg log -L file.c,13:23 -L main.c,2:6 -p
3698
3706
3699 See :hg:`help dates` for a list of formats valid for -d/--date.
3707 See :hg:`help dates` for a list of formats valid for -d/--date.
3700
3708
3701 See :hg:`help revisions` for more about specifying and ordering
3709 See :hg:`help revisions` for more about specifying and ordering
3702 revisions.
3710 revisions.
3703
3711
3704 See :hg:`help templates` for more about pre-packaged styles and
3712 See :hg:`help templates` for more about pre-packaged styles and
3705 specifying custom templates. The default template used by the log
3713 specifying custom templates. The default template used by the log
3706 command can be customized via the ``ui.logtemplate`` configuration
3714 command can be customized via the ``ui.logtemplate`` configuration
3707 setting.
3715 setting.
3708
3716
3709 Returns 0 on success.
3717 Returns 0 on success.
3710
3718
3711 """
3719 """
3712 opts = pycompat.byteskwargs(opts)
3720 opts = pycompat.byteskwargs(opts)
3713 linerange = opts.get('line_range')
3721 linerange = opts.get('line_range')
3714
3722
3715 if linerange and not opts.get('follow'):
3723 if linerange and not opts.get('follow'):
3716 raise error.Abort(_('--line-range requires --follow'))
3724 raise error.Abort(_('--line-range requires --follow'))
3717
3725
3718 if linerange and pats:
3726 if linerange and pats:
3719 # TODO: take pats as patterns with no line-range filter
3727 # TODO: take pats as patterns with no line-range filter
3720 raise error.Abort(
3728 raise error.Abort(
3721 _('FILE arguments are not compatible with --line-range option')
3729 _('FILE arguments are not compatible with --line-range option')
3722 )
3730 )
3723
3731
3724 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3732 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3725 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3733 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3726 if linerange:
3734 if linerange:
3727 # TODO: should follow file history from logcmdutil._initialrevs(),
3735 # TODO: should follow file history from logcmdutil._initialrevs(),
3728 # then filter the result by logcmdutil._makerevset() and --limit
3736 # then filter the result by logcmdutil._makerevset() and --limit
3729 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3737 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3730
3738
3731 getrenamed = None
3739 getrenamed = None
3732 if opts.get('copies'):
3740 if opts.get('copies'):
3733 endrev = None
3741 endrev = None
3734 if revs:
3742 if revs:
3735 endrev = revs.max() + 1
3743 endrev = revs.max() + 1
3736 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3744 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3737
3745
3738 ui.pager('log')
3746 ui.pager('log')
3739 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3747 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3740 buffered=True)
3748 buffered=True)
3741 if opts.get('graph'):
3749 if opts.get('graph'):
3742 displayfn = logcmdutil.displaygraphrevs
3750 displayfn = logcmdutil.displaygraphrevs
3743 else:
3751 else:
3744 displayfn = logcmdutil.displayrevs
3752 displayfn = logcmdutil.displayrevs
3745 displayfn(ui, repo, revs, displayer, getrenamed)
3753 displayfn(ui, repo, revs, displayer, getrenamed)
3746
3754
3747 @command('manifest',
3755 @command('manifest',
3748 [('r', 'rev', '', _('revision to display'), _('REV')),
3756 [('r', 'rev', '', _('revision to display'), _('REV')),
3749 ('', 'all', False, _("list files from all revisions"))]
3757 ('', 'all', False, _("list files from all revisions"))]
3750 + formatteropts,
3758 + formatteropts,
3751 _('[-r REV]'),
3759 _('[-r REV]'),
3752 intents={INTENT_READONLY})
3760 intents={INTENT_READONLY})
3753 def manifest(ui, repo, node=None, rev=None, **opts):
3761 def manifest(ui, repo, node=None, rev=None, **opts):
3754 """output the current or given revision of the project manifest
3762 """output the current or given revision of the project manifest
3755
3763
3756 Print a list of version controlled files for the given revision.
3764 Print a list of version controlled files for the given revision.
3757 If no revision is given, the first parent of the working directory
3765 If no revision is given, the first parent of the working directory
3758 is used, or the null revision if no revision is checked out.
3766 is used, or the null revision if no revision is checked out.
3759
3767
3760 With -v, print file permissions, symlink and executable bits.
3768 With -v, print file permissions, symlink and executable bits.
3761 With --debug, print file revision hashes.
3769 With --debug, print file revision hashes.
3762
3770
3763 If option --all is specified, the list of all files from all revisions
3771 If option --all is specified, the list of all files from all revisions
3764 is printed. This includes deleted and renamed files.
3772 is printed. This includes deleted and renamed files.
3765
3773
3766 Returns 0 on success.
3774 Returns 0 on success.
3767 """
3775 """
3768 opts = pycompat.byteskwargs(opts)
3776 opts = pycompat.byteskwargs(opts)
3769 fm = ui.formatter('manifest', opts)
3777 fm = ui.formatter('manifest', opts)
3770
3778
3771 if opts.get('all'):
3779 if opts.get('all'):
3772 if rev or node:
3780 if rev or node:
3773 raise error.Abort(_("can't specify a revision with --all"))
3781 raise error.Abort(_("can't specify a revision with --all"))
3774
3782
3775 res = set()
3783 res = set()
3776 for rev in repo:
3784 for rev in repo:
3777 ctx = repo[rev]
3785 ctx = repo[rev]
3778 res |= set(ctx.files())
3786 res |= set(ctx.files())
3779
3787
3780 ui.pager('manifest')
3788 ui.pager('manifest')
3781 for f in sorted(res):
3789 for f in sorted(res):
3782 fm.startitem()
3790 fm.startitem()
3783 fm.write("path", '%s\n', f)
3791 fm.write("path", '%s\n', f)
3784 fm.end()
3792 fm.end()
3785 return
3793 return
3786
3794
3787 if rev and node:
3795 if rev and node:
3788 raise error.Abort(_("please specify just one revision"))
3796 raise error.Abort(_("please specify just one revision"))
3789
3797
3790 if not node:
3798 if not node:
3791 node = rev
3799 node = rev
3792
3800
3793 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3801 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3794 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3802 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3795 if node:
3803 if node:
3796 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3804 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3797 ctx = scmutil.revsingle(repo, node)
3805 ctx = scmutil.revsingle(repo, node)
3798 mf = ctx.manifest()
3806 mf = ctx.manifest()
3799 ui.pager('manifest')
3807 ui.pager('manifest')
3800 for f in ctx:
3808 for f in ctx:
3801 fm.startitem()
3809 fm.startitem()
3802 fm.context(ctx=ctx)
3810 fm.context(ctx=ctx)
3803 fl = ctx[f].flags()
3811 fl = ctx[f].flags()
3804 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3812 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3805 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3813 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3806 fm.write('path', '%s\n', f)
3814 fm.write('path', '%s\n', f)
3807 fm.end()
3815 fm.end()
3808
3816
3809 @command('^merge',
3817 @command('^merge',
3810 [('f', 'force', None,
3818 [('f', 'force', None,
3811 _('force a merge including outstanding changes (DEPRECATED)')),
3819 _('force a merge including outstanding changes (DEPRECATED)')),
3812 ('r', 'rev', '', _('revision to merge'), _('REV')),
3820 ('r', 'rev', '', _('revision to merge'), _('REV')),
3813 ('P', 'preview', None,
3821 ('P', 'preview', None,
3814 _('review revisions to merge (no merge is performed)')),
3822 _('review revisions to merge (no merge is performed)')),
3815 ('', 'abort', None, _('abort the ongoing merge')),
3823 ('', 'abort', None, _('abort the ongoing merge')),
3816 ] + mergetoolopts,
3824 ] + mergetoolopts,
3817 _('[-P] [[-r] REV]'))
3825 _('[-P] [[-r] REV]'))
3818 def merge(ui, repo, node=None, **opts):
3826 def merge(ui, repo, node=None, **opts):
3819 """merge another revision into working directory
3827 """merge another revision into working directory
3820
3828
3821 The current working directory is updated with all changes made in
3829 The current working directory is updated with all changes made in
3822 the requested revision since the last common predecessor revision.
3830 the requested revision since the last common predecessor revision.
3823
3831
3824 Files that changed between either parent are marked as changed for
3832 Files that changed between either parent are marked as changed for
3825 the next commit and a commit must be performed before any further
3833 the next commit and a commit must be performed before any further
3826 updates to the repository are allowed. The next commit will have
3834 updates to the repository are allowed. The next commit will have
3827 two parents.
3835 two parents.
3828
3836
3829 ``--tool`` can be used to specify the merge tool used for file
3837 ``--tool`` can be used to specify the merge tool used for file
3830 merges. It overrides the HGMERGE environment variable and your
3838 merges. It overrides the HGMERGE environment variable and your
3831 configuration files. See :hg:`help merge-tools` for options.
3839 configuration files. See :hg:`help merge-tools` for options.
3832
3840
3833 If no revision is specified, the working directory's parent is a
3841 If no revision is specified, the working directory's parent is a
3834 head revision, and the current branch contains exactly one other
3842 head revision, and the current branch contains exactly one other
3835 head, the other head is merged with by default. Otherwise, an
3843 head, the other head is merged with by default. Otherwise, an
3836 explicit revision with which to merge with must be provided.
3844 explicit revision with which to merge with must be provided.
3837
3845
3838 See :hg:`help resolve` for information on handling file conflicts.
3846 See :hg:`help resolve` for information on handling file conflicts.
3839
3847
3840 To undo an uncommitted merge, use :hg:`merge --abort` which
3848 To undo an uncommitted merge, use :hg:`merge --abort` which
3841 will check out a clean copy of the original merge parent, losing
3849 will check out a clean copy of the original merge parent, losing
3842 all changes.
3850 all changes.
3843
3851
3844 Returns 0 on success, 1 if there are unresolved files.
3852 Returns 0 on success, 1 if there are unresolved files.
3845 """
3853 """
3846
3854
3847 opts = pycompat.byteskwargs(opts)
3855 opts = pycompat.byteskwargs(opts)
3848 abort = opts.get('abort')
3856 abort = opts.get('abort')
3849 if abort and repo.dirstate.p2() == nullid:
3857 if abort and repo.dirstate.p2() == nullid:
3850 cmdutil.wrongtooltocontinue(repo, _('merge'))
3858 cmdutil.wrongtooltocontinue(repo, _('merge'))
3851 if abort:
3859 if abort:
3852 if node:
3860 if node:
3853 raise error.Abort(_("cannot specify a node with --abort"))
3861 raise error.Abort(_("cannot specify a node with --abort"))
3854 if opts.get('rev'):
3862 if opts.get('rev'):
3855 raise error.Abort(_("cannot specify both --rev and --abort"))
3863 raise error.Abort(_("cannot specify both --rev and --abort"))
3856 if opts.get('preview'):
3864 if opts.get('preview'):
3857 raise error.Abort(_("cannot specify --preview with --abort"))
3865 raise error.Abort(_("cannot specify --preview with --abort"))
3858 if opts.get('rev') and node:
3866 if opts.get('rev') and node:
3859 raise error.Abort(_("please specify just one revision"))
3867 raise error.Abort(_("please specify just one revision"))
3860 if not node:
3868 if not node:
3861 node = opts.get('rev')
3869 node = opts.get('rev')
3862
3870
3863 if node:
3871 if node:
3864 node = scmutil.revsingle(repo, node).node()
3872 node = scmutil.revsingle(repo, node).node()
3865
3873
3866 if not node and not abort:
3874 if not node and not abort:
3867 node = repo[destutil.destmerge(repo)].node()
3875 node = repo[destutil.destmerge(repo)].node()
3868
3876
3869 if opts.get('preview'):
3877 if opts.get('preview'):
3870 # find nodes that are ancestors of p2 but not of p1
3878 # find nodes that are ancestors of p2 but not of p1
3871 p1 = repo.lookup('.')
3879 p1 = repo.lookup('.')
3872 p2 = node
3880 p2 = node
3873 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3881 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3874
3882
3875 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3883 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3876 for node in nodes:
3884 for node in nodes:
3877 displayer.show(repo[node])
3885 displayer.show(repo[node])
3878 displayer.close()
3886 displayer.close()
3879 return 0
3887 return 0
3880
3888
3881 # ui.forcemerge is an internal variable, do not document
3889 # ui.forcemerge is an internal variable, do not document
3882 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3890 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3883 with ui.configoverride(overrides, 'merge'):
3891 with ui.configoverride(overrides, 'merge'):
3884 force = opts.get('force')
3892 force = opts.get('force')
3885 labels = ['working copy', 'merge rev']
3893 labels = ['working copy', 'merge rev']
3886 return hg.merge(repo, node, force=force, mergeforce=force,
3894 return hg.merge(repo, node, force=force, mergeforce=force,
3887 labels=labels, abort=abort)
3895 labels=labels, abort=abort)
3888
3896
3889 @command('outgoing|out',
3897 @command('outgoing|out',
3890 [('f', 'force', None, _('run even when the destination is unrelated')),
3898 [('f', 'force', None, _('run even when the destination is unrelated')),
3891 ('r', 'rev', [],
3899 ('r', 'rev', [],
3892 _('a changeset intended to be included in the destination'), _('REV')),
3900 _('a changeset intended to be included in the destination'), _('REV')),
3893 ('n', 'newest-first', None, _('show newest record first')),
3901 ('n', 'newest-first', None, _('show newest record first')),
3894 ('B', 'bookmarks', False, _('compare bookmarks')),
3902 ('B', 'bookmarks', False, _('compare bookmarks')),
3895 ('b', 'branch', [], _('a specific branch you would like to push'),
3903 ('b', 'branch', [], _('a specific branch you would like to push'),
3896 _('BRANCH')),
3904 _('BRANCH')),
3897 ] + logopts + remoteopts + subrepoopts,
3905 ] + logopts + remoteopts + subrepoopts,
3898 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3906 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3899 def outgoing(ui, repo, dest=None, **opts):
3907 def outgoing(ui, repo, dest=None, **opts):
3900 """show changesets not found in the destination
3908 """show changesets not found in the destination
3901
3909
3902 Show changesets not found in the specified destination repository
3910 Show changesets not found in the specified destination repository
3903 or the default push location. These are the changesets that would
3911 or the default push location. These are the changesets that would
3904 be pushed if a push was requested.
3912 be pushed if a push was requested.
3905
3913
3906 See pull for details of valid destination formats.
3914 See pull for details of valid destination formats.
3907
3915
3908 .. container:: verbose
3916 .. container:: verbose
3909
3917
3910 With -B/--bookmarks, the result of bookmark comparison between
3918 With -B/--bookmarks, the result of bookmark comparison between
3911 local and remote repositories is displayed. With -v/--verbose,
3919 local and remote repositories is displayed. With -v/--verbose,
3912 status is also displayed for each bookmark like below::
3920 status is also displayed for each bookmark like below::
3913
3921
3914 BM1 01234567890a added
3922 BM1 01234567890a added
3915 BM2 deleted
3923 BM2 deleted
3916 BM3 234567890abc advanced
3924 BM3 234567890abc advanced
3917 BM4 34567890abcd diverged
3925 BM4 34567890abcd diverged
3918 BM5 4567890abcde changed
3926 BM5 4567890abcde changed
3919
3927
3920 The action taken when pushing depends on the
3928 The action taken when pushing depends on the
3921 status of each bookmark:
3929 status of each bookmark:
3922
3930
3923 :``added``: push with ``-B`` will create it
3931 :``added``: push with ``-B`` will create it
3924 :``deleted``: push with ``-B`` will delete it
3932 :``deleted``: push with ``-B`` will delete it
3925 :``advanced``: push will update it
3933 :``advanced``: push will update it
3926 :``diverged``: push with ``-B`` will update it
3934 :``diverged``: push with ``-B`` will update it
3927 :``changed``: push with ``-B`` will update it
3935 :``changed``: push with ``-B`` will update it
3928
3936
3929 From the point of view of pushing behavior, bookmarks
3937 From the point of view of pushing behavior, bookmarks
3930 existing only in the remote repository are treated as
3938 existing only in the remote repository are treated as
3931 ``deleted``, even if it is in fact added remotely.
3939 ``deleted``, even if it is in fact added remotely.
3932
3940
3933 Returns 0 if there are outgoing changes, 1 otherwise.
3941 Returns 0 if there are outgoing changes, 1 otherwise.
3934 """
3942 """
3935 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3943 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3936 # style URLs, so don't overwrite dest.
3944 # style URLs, so don't overwrite dest.
3937 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3945 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3938 if not path:
3946 if not path:
3939 raise error.Abort(_('default repository not configured!'),
3947 raise error.Abort(_('default repository not configured!'),
3940 hint=_("see 'hg help config.paths'"))
3948 hint=_("see 'hg help config.paths'"))
3941
3949
3942 opts = pycompat.byteskwargs(opts)
3950 opts = pycompat.byteskwargs(opts)
3943 if opts.get('graph'):
3951 if opts.get('graph'):
3944 logcmdutil.checkunsupportedgraphflags([], opts)
3952 logcmdutil.checkunsupportedgraphflags([], opts)
3945 o, other = hg._outgoing(ui, repo, dest, opts)
3953 o, other = hg._outgoing(ui, repo, dest, opts)
3946 if not o:
3954 if not o:
3947 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3955 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3948 return
3956 return
3949
3957
3950 revdag = logcmdutil.graphrevs(repo, o, opts)
3958 revdag = logcmdutil.graphrevs(repo, o, opts)
3951 ui.pager('outgoing')
3959 ui.pager('outgoing')
3952 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3960 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3953 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3961 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3954 graphmod.asciiedges)
3962 graphmod.asciiedges)
3955 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3963 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3956 return 0
3964 return 0
3957
3965
3958 if opts.get('bookmarks'):
3966 if opts.get('bookmarks'):
3959 dest = path.pushloc or path.loc
3967 dest = path.pushloc or path.loc
3960 other = hg.peer(repo, opts, dest)
3968 other = hg.peer(repo, opts, dest)
3961 if 'bookmarks' not in other.listkeys('namespaces'):
3969 if 'bookmarks' not in other.listkeys('namespaces'):
3962 ui.warn(_("remote doesn't support bookmarks\n"))
3970 ui.warn(_("remote doesn't support bookmarks\n"))
3963 return 0
3971 return 0
3964 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3972 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3965 ui.pager('outgoing')
3973 ui.pager('outgoing')
3966 return bookmarks.outgoing(ui, repo, other)
3974 return bookmarks.outgoing(ui, repo, other)
3967
3975
3968 repo._subtoppath = path.pushloc or path.loc
3976 repo._subtoppath = path.pushloc or path.loc
3969 try:
3977 try:
3970 return hg.outgoing(ui, repo, dest, opts)
3978 return hg.outgoing(ui, repo, dest, opts)
3971 finally:
3979 finally:
3972 del repo._subtoppath
3980 del repo._subtoppath
3973
3981
3974 @command('parents',
3982 @command('parents',
3975 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3983 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3976 ] + templateopts,
3984 ] + templateopts,
3977 _('[-r REV] [FILE]'),
3985 _('[-r REV] [FILE]'),
3978 inferrepo=True)
3986 inferrepo=True)
3979 def parents(ui, repo, file_=None, **opts):
3987 def parents(ui, repo, file_=None, **opts):
3980 """show the parents of the working directory or revision (DEPRECATED)
3988 """show the parents of the working directory or revision (DEPRECATED)
3981
3989
3982 Print the working directory's parent revisions. If a revision is
3990 Print the working directory's parent revisions. If a revision is
3983 given via -r/--rev, the parent of that revision will be printed.
3991 given via -r/--rev, the parent of that revision will be printed.
3984 If a file argument is given, the revision in which the file was
3992 If a file argument is given, the revision in which the file was
3985 last changed (before the working directory revision or the
3993 last changed (before the working directory revision or the
3986 argument to --rev if given) is printed.
3994 argument to --rev if given) is printed.
3987
3995
3988 This command is equivalent to::
3996 This command is equivalent to::
3989
3997
3990 hg log -r "p1()+p2()" or
3998 hg log -r "p1()+p2()" or
3991 hg log -r "p1(REV)+p2(REV)" or
3999 hg log -r "p1(REV)+p2(REV)" or
3992 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4000 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3993 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4001 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3994
4002
3995 See :hg:`summary` and :hg:`help revsets` for related information.
4003 See :hg:`summary` and :hg:`help revsets` for related information.
3996
4004
3997 Returns 0 on success.
4005 Returns 0 on success.
3998 """
4006 """
3999
4007
4000 opts = pycompat.byteskwargs(opts)
4008 opts = pycompat.byteskwargs(opts)
4001 rev = opts.get('rev')
4009 rev = opts.get('rev')
4002 if rev:
4010 if rev:
4003 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4011 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4004 ctx = scmutil.revsingle(repo, rev, None)
4012 ctx = scmutil.revsingle(repo, rev, None)
4005
4013
4006 if file_:
4014 if file_:
4007 m = scmutil.match(ctx, (file_,), opts)
4015 m = scmutil.match(ctx, (file_,), opts)
4008 if m.anypats() or len(m.files()) != 1:
4016 if m.anypats() or len(m.files()) != 1:
4009 raise error.Abort(_('can only specify an explicit filename'))
4017 raise error.Abort(_('can only specify an explicit filename'))
4010 file_ = m.files()[0]
4018 file_ = m.files()[0]
4011 filenodes = []
4019 filenodes = []
4012 for cp in ctx.parents():
4020 for cp in ctx.parents():
4013 if not cp:
4021 if not cp:
4014 continue
4022 continue
4015 try:
4023 try:
4016 filenodes.append(cp.filenode(file_))
4024 filenodes.append(cp.filenode(file_))
4017 except error.LookupError:
4025 except error.LookupError:
4018 pass
4026 pass
4019 if not filenodes:
4027 if not filenodes:
4020 raise error.Abort(_("'%s' not found in manifest!") % file_)
4028 raise error.Abort(_("'%s' not found in manifest!") % file_)
4021 p = []
4029 p = []
4022 for fn in filenodes:
4030 for fn in filenodes:
4023 fctx = repo.filectx(file_, fileid=fn)
4031 fctx = repo.filectx(file_, fileid=fn)
4024 p.append(fctx.node())
4032 p.append(fctx.node())
4025 else:
4033 else:
4026 p = [cp.node() for cp in ctx.parents()]
4034 p = [cp.node() for cp in ctx.parents()]
4027
4035
4028 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4036 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4029 for n in p:
4037 for n in p:
4030 if n != nullid:
4038 if n != nullid:
4031 displayer.show(repo[n])
4039 displayer.show(repo[n])
4032 displayer.close()
4040 displayer.close()
4033
4041
4034 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
4042 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
4035 intents={INTENT_READONLY})
4043 intents={INTENT_READONLY})
4036 def paths(ui, repo, search=None, **opts):
4044 def paths(ui, repo, search=None, **opts):
4037 """show aliases for remote repositories
4045 """show aliases for remote repositories
4038
4046
4039 Show definition of symbolic path name NAME. If no name is given,
4047 Show definition of symbolic path name NAME. If no name is given,
4040 show definition of all available names.
4048 show definition of all available names.
4041
4049
4042 Option -q/--quiet suppresses all output when searching for NAME
4050 Option -q/--quiet suppresses all output when searching for NAME
4043 and shows only the path names when listing all definitions.
4051 and shows only the path names when listing all definitions.
4044
4052
4045 Path names are defined in the [paths] section of your
4053 Path names are defined in the [paths] section of your
4046 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4054 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4047 repository, ``.hg/hgrc`` is used, too.
4055 repository, ``.hg/hgrc`` is used, too.
4048
4056
4049 The path names ``default`` and ``default-push`` have a special
4057 The path names ``default`` and ``default-push`` have a special
4050 meaning. When performing a push or pull operation, they are used
4058 meaning. When performing a push or pull operation, they are used
4051 as fallbacks if no location is specified on the command-line.
4059 as fallbacks if no location is specified on the command-line.
4052 When ``default-push`` is set, it will be used for push and
4060 When ``default-push`` is set, it will be used for push and
4053 ``default`` will be used for pull; otherwise ``default`` is used
4061 ``default`` will be used for pull; otherwise ``default`` is used
4054 as the fallback for both. When cloning a repository, the clone
4062 as the fallback for both. When cloning a repository, the clone
4055 source is written as ``default`` in ``.hg/hgrc``.
4063 source is written as ``default`` in ``.hg/hgrc``.
4056
4064
4057 .. note::
4065 .. note::
4058
4066
4059 ``default`` and ``default-push`` apply to all inbound (e.g.
4067 ``default`` and ``default-push`` apply to all inbound (e.g.
4060 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4068 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4061 and :hg:`bundle`) operations.
4069 and :hg:`bundle`) operations.
4062
4070
4063 See :hg:`help urls` for more information.
4071 See :hg:`help urls` for more information.
4064
4072
4065 Returns 0 on success.
4073 Returns 0 on success.
4066 """
4074 """
4067
4075
4068 opts = pycompat.byteskwargs(opts)
4076 opts = pycompat.byteskwargs(opts)
4069 ui.pager('paths')
4077 ui.pager('paths')
4070 if search:
4078 if search:
4071 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4079 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4072 if name == search]
4080 if name == search]
4073 else:
4081 else:
4074 pathitems = sorted(ui.paths.iteritems())
4082 pathitems = sorted(ui.paths.iteritems())
4075
4083
4076 fm = ui.formatter('paths', opts)
4084 fm = ui.formatter('paths', opts)
4077 if fm.isplain():
4085 if fm.isplain():
4078 hidepassword = util.hidepassword
4086 hidepassword = util.hidepassword
4079 else:
4087 else:
4080 hidepassword = bytes
4088 hidepassword = bytes
4081 if ui.quiet:
4089 if ui.quiet:
4082 namefmt = '%s\n'
4090 namefmt = '%s\n'
4083 else:
4091 else:
4084 namefmt = '%s = '
4092 namefmt = '%s = '
4085 showsubopts = not search and not ui.quiet
4093 showsubopts = not search and not ui.quiet
4086
4094
4087 for name, path in pathitems:
4095 for name, path in pathitems:
4088 fm.startitem()
4096 fm.startitem()
4089 fm.condwrite(not search, 'name', namefmt, name)
4097 fm.condwrite(not search, 'name', namefmt, name)
4090 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4098 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4091 for subopt, value in sorted(path.suboptions.items()):
4099 for subopt, value in sorted(path.suboptions.items()):
4092 assert subopt not in ('name', 'url')
4100 assert subopt not in ('name', 'url')
4093 if showsubopts:
4101 if showsubopts:
4094 fm.plain('%s:%s = ' % (name, subopt))
4102 fm.plain('%s:%s = ' % (name, subopt))
4095 fm.condwrite(showsubopts, subopt, '%s\n', value)
4103 fm.condwrite(showsubopts, subopt, '%s\n', value)
4096
4104
4097 fm.end()
4105 fm.end()
4098
4106
4099 if search and not pathitems:
4107 if search and not pathitems:
4100 if not ui.quiet:
4108 if not ui.quiet:
4101 ui.warn(_("not found!\n"))
4109 ui.warn(_("not found!\n"))
4102 return 1
4110 return 1
4103 else:
4111 else:
4104 return 0
4112 return 0
4105
4113
4106 @command('phase',
4114 @command('phase',
4107 [('p', 'public', False, _('set changeset phase to public')),
4115 [('p', 'public', False, _('set changeset phase to public')),
4108 ('d', 'draft', False, _('set changeset phase to draft')),
4116 ('d', 'draft', False, _('set changeset phase to draft')),
4109 ('s', 'secret', False, _('set changeset phase to secret')),
4117 ('s', 'secret', False, _('set changeset phase to secret')),
4110 ('f', 'force', False, _('allow to move boundary backward')),
4118 ('f', 'force', False, _('allow to move boundary backward')),
4111 ('r', 'rev', [], _('target revision'), _('REV')),
4119 ('r', 'rev', [], _('target revision'), _('REV')),
4112 ],
4120 ],
4113 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4121 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4114 def phase(ui, repo, *revs, **opts):
4122 def phase(ui, repo, *revs, **opts):
4115 """set or show the current phase name
4123 """set or show the current phase name
4116
4124
4117 With no argument, show the phase name of the current revision(s).
4125 With no argument, show the phase name of the current revision(s).
4118
4126
4119 With one of -p/--public, -d/--draft or -s/--secret, change the
4127 With one of -p/--public, -d/--draft or -s/--secret, change the
4120 phase value of the specified revisions.
4128 phase value of the specified revisions.
4121
4129
4122 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4130 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4123 lower phase to a higher phase. Phases are ordered as follows::
4131 lower phase to a higher phase. Phases are ordered as follows::
4124
4132
4125 public < draft < secret
4133 public < draft < secret
4126
4134
4127 Returns 0 on success, 1 if some phases could not be changed.
4135 Returns 0 on success, 1 if some phases could not be changed.
4128
4136
4129 (For more information about the phases concept, see :hg:`help phases`.)
4137 (For more information about the phases concept, see :hg:`help phases`.)
4130 """
4138 """
4131 opts = pycompat.byteskwargs(opts)
4139 opts = pycompat.byteskwargs(opts)
4132 # search for a unique phase argument
4140 # search for a unique phase argument
4133 targetphase = None
4141 targetphase = None
4134 for idx, name in enumerate(phases.phasenames):
4142 for idx, name in enumerate(phases.phasenames):
4135 if opts.get(name, False):
4143 if opts.get(name, False):
4136 if targetphase is not None:
4144 if targetphase is not None:
4137 raise error.Abort(_('only one phase can be specified'))
4145 raise error.Abort(_('only one phase can be specified'))
4138 targetphase = idx
4146 targetphase = idx
4139
4147
4140 # look for specified revision
4148 # look for specified revision
4141 revs = list(revs)
4149 revs = list(revs)
4142 revs.extend(opts['rev'])
4150 revs.extend(opts['rev'])
4143 if not revs:
4151 if not revs:
4144 # display both parents as the second parent phase can influence
4152 # display both parents as the second parent phase can influence
4145 # the phase of a merge commit
4153 # the phase of a merge commit
4146 revs = [c.rev() for c in repo[None].parents()]
4154 revs = [c.rev() for c in repo[None].parents()]
4147
4155
4148 revs = scmutil.revrange(repo, revs)
4156 revs = scmutil.revrange(repo, revs)
4149
4157
4150 ret = 0
4158 ret = 0
4151 if targetphase is None:
4159 if targetphase is None:
4152 # display
4160 # display
4153 for r in revs:
4161 for r in revs:
4154 ctx = repo[r]
4162 ctx = repo[r]
4155 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4163 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4156 else:
4164 else:
4157 with repo.lock(), repo.transaction("phase") as tr:
4165 with repo.lock(), repo.transaction("phase") as tr:
4158 # set phase
4166 # set phase
4159 if not revs:
4167 if not revs:
4160 raise error.Abort(_('empty revision set'))
4168 raise error.Abort(_('empty revision set'))
4161 nodes = [repo[r].node() for r in revs]
4169 nodes = [repo[r].node() for r in revs]
4162 # moving revision from public to draft may hide them
4170 # moving revision from public to draft may hide them
4163 # We have to check result on an unfiltered repository
4171 # We have to check result on an unfiltered repository
4164 unfi = repo.unfiltered()
4172 unfi = repo.unfiltered()
4165 getphase = unfi._phasecache.phase
4173 getphase = unfi._phasecache.phase
4166 olddata = [getphase(unfi, r) for r in unfi]
4174 olddata = [getphase(unfi, r) for r in unfi]
4167 phases.advanceboundary(repo, tr, targetphase, nodes)
4175 phases.advanceboundary(repo, tr, targetphase, nodes)
4168 if opts['force']:
4176 if opts['force']:
4169 phases.retractboundary(repo, tr, targetphase, nodes)
4177 phases.retractboundary(repo, tr, targetphase, nodes)
4170 getphase = unfi._phasecache.phase
4178 getphase = unfi._phasecache.phase
4171 newdata = [getphase(unfi, r) for r in unfi]
4179 newdata = [getphase(unfi, r) for r in unfi]
4172 changes = sum(newdata[r] != olddata[r] for r in unfi)
4180 changes = sum(newdata[r] != olddata[r] for r in unfi)
4173 cl = unfi.changelog
4181 cl = unfi.changelog
4174 rejected = [n for n in nodes
4182 rejected = [n for n in nodes
4175 if newdata[cl.rev(n)] < targetphase]
4183 if newdata[cl.rev(n)] < targetphase]
4176 if rejected:
4184 if rejected:
4177 ui.warn(_('cannot move %i changesets to a higher '
4185 ui.warn(_('cannot move %i changesets to a higher '
4178 'phase, use --force\n') % len(rejected))
4186 'phase, use --force\n') % len(rejected))
4179 ret = 1
4187 ret = 1
4180 if changes:
4188 if changes:
4181 msg = _('phase changed for %i changesets\n') % changes
4189 msg = _('phase changed for %i changesets\n') % changes
4182 if ret:
4190 if ret:
4183 ui.status(msg)
4191 ui.status(msg)
4184 else:
4192 else:
4185 ui.note(msg)
4193 ui.note(msg)
4186 else:
4194 else:
4187 ui.warn(_('no phases changed\n'))
4195 ui.warn(_('no phases changed\n'))
4188 return ret
4196 return ret
4189
4197
4190 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4198 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4191 """Run after a changegroup has been added via pull/unbundle
4199 """Run after a changegroup has been added via pull/unbundle
4192
4200
4193 This takes arguments below:
4201 This takes arguments below:
4194
4202
4195 :modheads: change of heads by pull/unbundle
4203 :modheads: change of heads by pull/unbundle
4196 :optupdate: updating working directory is needed or not
4204 :optupdate: updating working directory is needed or not
4197 :checkout: update destination revision (or None to default destination)
4205 :checkout: update destination revision (or None to default destination)
4198 :brev: a name, which might be a bookmark to be activated after updating
4206 :brev: a name, which might be a bookmark to be activated after updating
4199 """
4207 """
4200 if modheads == 0:
4208 if modheads == 0:
4201 return
4209 return
4202 if optupdate:
4210 if optupdate:
4203 try:
4211 try:
4204 return hg.updatetotally(ui, repo, checkout, brev)
4212 return hg.updatetotally(ui, repo, checkout, brev)
4205 except error.UpdateAbort as inst:
4213 except error.UpdateAbort as inst:
4206 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4214 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4207 hint = inst.hint
4215 hint = inst.hint
4208 raise error.UpdateAbort(msg, hint=hint)
4216 raise error.UpdateAbort(msg, hint=hint)
4209 if modheads > 1:
4217 if modheads > 1:
4210 currentbranchheads = len(repo.branchheads())
4218 currentbranchheads = len(repo.branchheads())
4211 if currentbranchheads == modheads:
4219 if currentbranchheads == modheads:
4212 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4220 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4213 elif currentbranchheads > 1:
4221 elif currentbranchheads > 1:
4214 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4222 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4215 "merge)\n"))
4223 "merge)\n"))
4216 else:
4224 else:
4217 ui.status(_("(run 'hg heads' to see heads)\n"))
4225 ui.status(_("(run 'hg heads' to see heads)\n"))
4218 elif not ui.configbool('commands', 'update.requiredest'):
4226 elif not ui.configbool('commands', 'update.requiredest'):
4219 ui.status(_("(run 'hg update' to get a working copy)\n"))
4227 ui.status(_("(run 'hg update' to get a working copy)\n"))
4220
4228
4221 @command('^pull',
4229 @command('^pull',
4222 [('u', 'update', None,
4230 [('u', 'update', None,
4223 _('update to new branch head if new descendants were pulled')),
4231 _('update to new branch head if new descendants were pulled')),
4224 ('f', 'force', None, _('run even when remote repository is unrelated')),
4232 ('f', 'force', None, _('run even when remote repository is unrelated')),
4225 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4233 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4226 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4234 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4227 ('b', 'branch', [], _('a specific branch you would like to pull'),
4235 ('b', 'branch', [], _('a specific branch you would like to pull'),
4228 _('BRANCH')),
4236 _('BRANCH')),
4229 ] + remoteopts,
4237 ] + remoteopts,
4230 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4238 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4231 def pull(ui, repo, source="default", **opts):
4239 def pull(ui, repo, source="default", **opts):
4232 """pull changes from the specified source
4240 """pull changes from the specified source
4233
4241
4234 Pull changes from a remote repository to a local one.
4242 Pull changes from a remote repository to a local one.
4235
4243
4236 This finds all changes from the repository at the specified path
4244 This finds all changes from the repository at the specified path
4237 or URL and adds them to a local repository (the current one unless
4245 or URL and adds them to a local repository (the current one unless
4238 -R is specified). By default, this does not update the copy of the
4246 -R is specified). By default, this does not update the copy of the
4239 project in the working directory.
4247 project in the working directory.
4240
4248
4241 When cloning from servers that support it, Mercurial may fetch
4249 When cloning from servers that support it, Mercurial may fetch
4242 pre-generated data. When this is done, hooks operating on incoming
4250 pre-generated data. When this is done, hooks operating on incoming
4243 changesets and changegroups may fire more than once, once for each
4251 changesets and changegroups may fire more than once, once for each
4244 pre-generated bundle and as well as for any additional remaining
4252 pre-generated bundle and as well as for any additional remaining
4245 data. See :hg:`help -e clonebundles` for more.
4253 data. See :hg:`help -e clonebundles` for more.
4246
4254
4247 Use :hg:`incoming` if you want to see what would have been added
4255 Use :hg:`incoming` if you want to see what would have been added
4248 by a pull at the time you issued this command. If you then decide
4256 by a pull at the time you issued this command. If you then decide
4249 to add those changes to the repository, you should use :hg:`pull
4257 to add those changes to the repository, you should use :hg:`pull
4250 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4258 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4251
4259
4252 If SOURCE is omitted, the 'default' path will be used.
4260 If SOURCE is omitted, the 'default' path will be used.
4253 See :hg:`help urls` for more information.
4261 See :hg:`help urls` for more information.
4254
4262
4255 Specifying bookmark as ``.`` is equivalent to specifying the active
4263 Specifying bookmark as ``.`` is equivalent to specifying the active
4256 bookmark's name.
4264 bookmark's name.
4257
4265
4258 Returns 0 on success, 1 if an update had unresolved files.
4266 Returns 0 on success, 1 if an update had unresolved files.
4259 """
4267 """
4260
4268
4261 opts = pycompat.byteskwargs(opts)
4269 opts = pycompat.byteskwargs(opts)
4262 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4270 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4263 msg = _('update destination required by configuration')
4271 msg = _('update destination required by configuration')
4264 hint = _('use hg pull followed by hg update DEST')
4272 hint = _('use hg pull followed by hg update DEST')
4265 raise error.Abort(msg, hint=hint)
4273 raise error.Abort(msg, hint=hint)
4266
4274
4267 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4275 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4268 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4276 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4269 other = hg.peer(repo, opts, source)
4277 other = hg.peer(repo, opts, source)
4270 try:
4278 try:
4271 revs, checkout = hg.addbranchrevs(repo, other, branches,
4279 revs, checkout = hg.addbranchrevs(repo, other, branches,
4272 opts.get('rev'))
4280 opts.get('rev'))
4273
4281
4274
4282
4275 pullopargs = {}
4283 pullopargs = {}
4276 if opts.get('bookmark'):
4284 if opts.get('bookmark'):
4277 if not revs:
4285 if not revs:
4278 revs = []
4286 revs = []
4279 # The list of bookmark used here is not the one used to actually
4287 # The list of bookmark used here is not the one used to actually
4280 # update the bookmark name. This can result in the revision pulled
4288 # update the bookmark name. This can result in the revision pulled
4281 # not ending up with the name of the bookmark because of a race
4289 # not ending up with the name of the bookmark because of a race
4282 # condition on the server. (See issue 4689 for details)
4290 # condition on the server. (See issue 4689 for details)
4283 remotebookmarks = other.listkeys('bookmarks')
4291 remotebookmarks = other.listkeys('bookmarks')
4284 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4292 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4285 pullopargs['remotebookmarks'] = remotebookmarks
4293 pullopargs['remotebookmarks'] = remotebookmarks
4286 for b in opts['bookmark']:
4294 for b in opts['bookmark']:
4287 b = repo._bookmarks.expandname(b)
4295 b = repo._bookmarks.expandname(b)
4288 if b not in remotebookmarks:
4296 if b not in remotebookmarks:
4289 raise error.Abort(_('remote bookmark %s not found!') % b)
4297 raise error.Abort(_('remote bookmark %s not found!') % b)
4290 revs.append(hex(remotebookmarks[b]))
4298 revs.append(hex(remotebookmarks[b]))
4291
4299
4292 if revs:
4300 if revs:
4293 try:
4301 try:
4294 # When 'rev' is a bookmark name, we cannot guarantee that it
4302 # When 'rev' is a bookmark name, we cannot guarantee that it
4295 # will be updated with that name because of a race condition
4303 # will be updated with that name because of a race condition
4296 # server side. (See issue 4689 for details)
4304 # server side. (See issue 4689 for details)
4297 oldrevs = revs
4305 oldrevs = revs
4298 revs = [] # actually, nodes
4306 revs = [] # actually, nodes
4299 for r in oldrevs:
4307 for r in oldrevs:
4300 with other.commandexecutor() as e:
4308 with other.commandexecutor() as e:
4301 node = e.callcommand('lookup', {'key': r}).result()
4309 node = e.callcommand('lookup', {'key': r}).result()
4302
4310
4303 revs.append(node)
4311 revs.append(node)
4304 if r == checkout:
4312 if r == checkout:
4305 checkout = node
4313 checkout = node
4306 except error.CapabilityError:
4314 except error.CapabilityError:
4307 err = _("other repository doesn't support revision lookup, "
4315 err = _("other repository doesn't support revision lookup, "
4308 "so a rev cannot be specified.")
4316 "so a rev cannot be specified.")
4309 raise error.Abort(err)
4317 raise error.Abort(err)
4310
4318
4311 wlock = util.nullcontextmanager()
4319 wlock = util.nullcontextmanager()
4312 if opts.get('update'):
4320 if opts.get('update'):
4313 wlock = repo.wlock()
4321 wlock = repo.wlock()
4314 with wlock:
4322 with wlock:
4315 pullopargs.update(opts.get('opargs', {}))
4323 pullopargs.update(opts.get('opargs', {}))
4316 modheads = exchange.pull(repo, other, heads=revs,
4324 modheads = exchange.pull(repo, other, heads=revs,
4317 force=opts.get('force'),
4325 force=opts.get('force'),
4318 bookmarks=opts.get('bookmark', ()),
4326 bookmarks=opts.get('bookmark', ()),
4319 opargs=pullopargs).cgresult
4327 opargs=pullopargs).cgresult
4320
4328
4321 # brev is a name, which might be a bookmark to be activated at
4329 # brev is a name, which might be a bookmark to be activated at
4322 # the end of the update. In other words, it is an explicit
4330 # the end of the update. In other words, it is an explicit
4323 # destination of the update
4331 # destination of the update
4324 brev = None
4332 brev = None
4325
4333
4326 if checkout:
4334 if checkout:
4327 checkout = repo.changelog.rev(checkout)
4335 checkout = repo.changelog.rev(checkout)
4328
4336
4329 # order below depends on implementation of
4337 # order below depends on implementation of
4330 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4338 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4331 # because 'checkout' is determined without it.
4339 # because 'checkout' is determined without it.
4332 if opts.get('rev'):
4340 if opts.get('rev'):
4333 brev = opts['rev'][0]
4341 brev = opts['rev'][0]
4334 elif opts.get('branch'):
4342 elif opts.get('branch'):
4335 brev = opts['branch'][0]
4343 brev = opts['branch'][0]
4336 else:
4344 else:
4337 brev = branches[0]
4345 brev = branches[0]
4338 repo._subtoppath = source
4346 repo._subtoppath = source
4339 try:
4347 try:
4340 ret = postincoming(ui, repo, modheads, opts.get('update'),
4348 ret = postincoming(ui, repo, modheads, opts.get('update'),
4341 checkout, brev)
4349 checkout, brev)
4342
4350
4343 finally:
4351 finally:
4344 del repo._subtoppath
4352 del repo._subtoppath
4345
4353
4346 finally:
4354 finally:
4347 other.close()
4355 other.close()
4348 return ret
4356 return ret
4349
4357
4350 @command('^push',
4358 @command('^push',
4351 [('f', 'force', None, _('force push')),
4359 [('f', 'force', None, _('force push')),
4352 ('r', 'rev', [],
4360 ('r', 'rev', [],
4353 _('a changeset intended to be included in the destination'),
4361 _('a changeset intended to be included in the destination'),
4354 _('REV')),
4362 _('REV')),
4355 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4363 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4356 ('b', 'branch', [],
4364 ('b', 'branch', [],
4357 _('a specific branch you would like to push'), _('BRANCH')),
4365 _('a specific branch you would like to push'), _('BRANCH')),
4358 ('', 'new-branch', False, _('allow pushing a new branch')),
4366 ('', 'new-branch', False, _('allow pushing a new branch')),
4359 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4367 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4360 ] + remoteopts,
4368 ] + remoteopts,
4361 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4369 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4362 def push(ui, repo, dest=None, **opts):
4370 def push(ui, repo, dest=None, **opts):
4363 """push changes to the specified destination
4371 """push changes to the specified destination
4364
4372
4365 Push changesets from the local repository to the specified
4373 Push changesets from the local repository to the specified
4366 destination.
4374 destination.
4367
4375
4368 This operation is symmetrical to pull: it is identical to a pull
4376 This operation is symmetrical to pull: it is identical to a pull
4369 in the destination repository from the current one.
4377 in the destination repository from the current one.
4370
4378
4371 By default, push will not allow creation of new heads at the
4379 By default, push will not allow creation of new heads at the
4372 destination, since multiple heads would make it unclear which head
4380 destination, since multiple heads would make it unclear which head
4373 to use. In this situation, it is recommended to pull and merge
4381 to use. In this situation, it is recommended to pull and merge
4374 before pushing.
4382 before pushing.
4375
4383
4376 Use --new-branch if you want to allow push to create a new named
4384 Use --new-branch if you want to allow push to create a new named
4377 branch that is not present at the destination. This allows you to
4385 branch that is not present at the destination. This allows you to
4378 only create a new branch without forcing other changes.
4386 only create a new branch without forcing other changes.
4379
4387
4380 .. note::
4388 .. note::
4381
4389
4382 Extra care should be taken with the -f/--force option,
4390 Extra care should be taken with the -f/--force option,
4383 which will push all new heads on all branches, an action which will
4391 which will push all new heads on all branches, an action which will
4384 almost always cause confusion for collaborators.
4392 almost always cause confusion for collaborators.
4385
4393
4386 If -r/--rev is used, the specified revision and all its ancestors
4394 If -r/--rev is used, the specified revision and all its ancestors
4387 will be pushed to the remote repository.
4395 will be pushed to the remote repository.
4388
4396
4389 If -B/--bookmark is used, the specified bookmarked revision, its
4397 If -B/--bookmark is used, the specified bookmarked revision, its
4390 ancestors, and the bookmark will be pushed to the remote
4398 ancestors, and the bookmark will be pushed to the remote
4391 repository. Specifying ``.`` is equivalent to specifying the active
4399 repository. Specifying ``.`` is equivalent to specifying the active
4392 bookmark's name.
4400 bookmark's name.
4393
4401
4394 Please see :hg:`help urls` for important details about ``ssh://``
4402 Please see :hg:`help urls` for important details about ``ssh://``
4395 URLs. If DESTINATION is omitted, a default path will be used.
4403 URLs. If DESTINATION is omitted, a default path will be used.
4396
4404
4397 .. container:: verbose
4405 .. container:: verbose
4398
4406
4399 The --pushvars option sends strings to the server that become
4407 The --pushvars option sends strings to the server that become
4400 environment variables prepended with ``HG_USERVAR_``. For example,
4408 environment variables prepended with ``HG_USERVAR_``. For example,
4401 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4409 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4402 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4410 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4403
4411
4404 pushvars can provide for user-overridable hooks as well as set debug
4412 pushvars can provide for user-overridable hooks as well as set debug
4405 levels. One example is having a hook that blocks commits containing
4413 levels. One example is having a hook that blocks commits containing
4406 conflict markers, but enables the user to override the hook if the file
4414 conflict markers, but enables the user to override the hook if the file
4407 is using conflict markers for testing purposes or the file format has
4415 is using conflict markers for testing purposes or the file format has
4408 strings that look like conflict markers.
4416 strings that look like conflict markers.
4409
4417
4410 By default, servers will ignore `--pushvars`. To enable it add the
4418 By default, servers will ignore `--pushvars`. To enable it add the
4411 following to your configuration file::
4419 following to your configuration file::
4412
4420
4413 [push]
4421 [push]
4414 pushvars.server = true
4422 pushvars.server = true
4415
4423
4416 Returns 0 if push was successful, 1 if nothing to push.
4424 Returns 0 if push was successful, 1 if nothing to push.
4417 """
4425 """
4418
4426
4419 opts = pycompat.byteskwargs(opts)
4427 opts = pycompat.byteskwargs(opts)
4420 if opts.get('bookmark'):
4428 if opts.get('bookmark'):
4421 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4429 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4422 for b in opts['bookmark']:
4430 for b in opts['bookmark']:
4423 # translate -B options to -r so changesets get pushed
4431 # translate -B options to -r so changesets get pushed
4424 b = repo._bookmarks.expandname(b)
4432 b = repo._bookmarks.expandname(b)
4425 if b in repo._bookmarks:
4433 if b in repo._bookmarks:
4426 opts.setdefault('rev', []).append(b)
4434 opts.setdefault('rev', []).append(b)
4427 else:
4435 else:
4428 # if we try to push a deleted bookmark, translate it to null
4436 # if we try to push a deleted bookmark, translate it to null
4429 # this lets simultaneous -r, -b options continue working
4437 # this lets simultaneous -r, -b options continue working
4430 opts.setdefault('rev', []).append("null")
4438 opts.setdefault('rev', []).append("null")
4431
4439
4432 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4440 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4433 if not path:
4441 if not path:
4434 raise error.Abort(_('default repository not configured!'),
4442 raise error.Abort(_('default repository not configured!'),
4435 hint=_("see 'hg help config.paths'"))
4443 hint=_("see 'hg help config.paths'"))
4436 dest = path.pushloc or path.loc
4444 dest = path.pushloc or path.loc
4437 branches = (path.branch, opts.get('branch') or [])
4445 branches = (path.branch, opts.get('branch') or [])
4438 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4446 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4439 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4447 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4440 other = hg.peer(repo, opts, dest)
4448 other = hg.peer(repo, opts, dest)
4441
4449
4442 if revs:
4450 if revs:
4443 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4451 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4444 if not revs:
4452 if not revs:
4445 raise error.Abort(_("specified revisions evaluate to an empty set"),
4453 raise error.Abort(_("specified revisions evaluate to an empty set"),
4446 hint=_("use different revision arguments"))
4454 hint=_("use different revision arguments"))
4447 elif path.pushrev:
4455 elif path.pushrev:
4448 # It doesn't make any sense to specify ancestor revisions. So limit
4456 # It doesn't make any sense to specify ancestor revisions. So limit
4449 # to DAG heads to make discovery simpler.
4457 # to DAG heads to make discovery simpler.
4450 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4458 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4451 revs = scmutil.revrange(repo, [expr])
4459 revs = scmutil.revrange(repo, [expr])
4452 revs = [repo[rev].node() for rev in revs]
4460 revs = [repo[rev].node() for rev in revs]
4453 if not revs:
4461 if not revs:
4454 raise error.Abort(_('default push revset for path evaluates to an '
4462 raise error.Abort(_('default push revset for path evaluates to an '
4455 'empty set'))
4463 'empty set'))
4456
4464
4457 repo._subtoppath = dest
4465 repo._subtoppath = dest
4458 try:
4466 try:
4459 # push subrepos depth-first for coherent ordering
4467 # push subrepos depth-first for coherent ordering
4460 c = repo['.']
4468 c = repo['.']
4461 subs = c.substate # only repos that are committed
4469 subs = c.substate # only repos that are committed
4462 for s in sorted(subs):
4470 for s in sorted(subs):
4463 result = c.sub(s).push(opts)
4471 result = c.sub(s).push(opts)
4464 if result == 0:
4472 if result == 0:
4465 return not result
4473 return not result
4466 finally:
4474 finally:
4467 del repo._subtoppath
4475 del repo._subtoppath
4468
4476
4469 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4477 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4470 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4478 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4471
4479
4472 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4480 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4473 newbranch=opts.get('new_branch'),
4481 newbranch=opts.get('new_branch'),
4474 bookmarks=opts.get('bookmark', ()),
4482 bookmarks=opts.get('bookmark', ()),
4475 opargs=opargs)
4483 opargs=opargs)
4476
4484
4477 result = not pushop.cgresult
4485 result = not pushop.cgresult
4478
4486
4479 if pushop.bkresult is not None:
4487 if pushop.bkresult is not None:
4480 if pushop.bkresult == 2:
4488 if pushop.bkresult == 2:
4481 result = 2
4489 result = 2
4482 elif not result and pushop.bkresult:
4490 elif not result and pushop.bkresult:
4483 result = 2
4491 result = 2
4484
4492
4485 return result
4493 return result
4486
4494
4487 @command('recover', [])
4495 @command('recover', [])
4488 def recover(ui, repo):
4496 def recover(ui, repo):
4489 """roll back an interrupted transaction
4497 """roll back an interrupted transaction
4490
4498
4491 Recover from an interrupted commit or pull.
4499 Recover from an interrupted commit or pull.
4492
4500
4493 This command tries to fix the repository status after an
4501 This command tries to fix the repository status after an
4494 interrupted operation. It should only be necessary when Mercurial
4502 interrupted operation. It should only be necessary when Mercurial
4495 suggests it.
4503 suggests it.
4496
4504
4497 Returns 0 if successful, 1 if nothing to recover or verify fails.
4505 Returns 0 if successful, 1 if nothing to recover or verify fails.
4498 """
4506 """
4499 if repo.recover():
4507 if repo.recover():
4500 return hg.verify(repo)
4508 return hg.verify(repo)
4501 return 1
4509 return 1
4502
4510
4503 @command('^remove|rm',
4511 @command('^remove|rm',
4504 [('A', 'after', None, _('record delete for missing files')),
4512 [('A', 'after', None, _('record delete for missing files')),
4505 ('f', 'force', None,
4513 ('f', 'force', None,
4506 _('forget added files, delete modified files')),
4514 _('forget added files, delete modified files')),
4507 ] + subrepoopts + walkopts + dryrunopts,
4515 ] + subrepoopts + walkopts + dryrunopts,
4508 _('[OPTION]... FILE...'),
4516 _('[OPTION]... FILE...'),
4509 inferrepo=True)
4517 inferrepo=True)
4510 def remove(ui, repo, *pats, **opts):
4518 def remove(ui, repo, *pats, **opts):
4511 """remove the specified files on the next commit
4519 """remove the specified files on the next commit
4512
4520
4513 Schedule the indicated files for removal from the current branch.
4521 Schedule the indicated files for removal from the current branch.
4514
4522
4515 This command schedules the files to be removed at the next commit.
4523 This command schedules the files to be removed at the next commit.
4516 To undo a remove before that, see :hg:`revert`. To undo added
4524 To undo a remove before that, see :hg:`revert`. To undo added
4517 files, see :hg:`forget`.
4525 files, see :hg:`forget`.
4518
4526
4519 .. container:: verbose
4527 .. container:: verbose
4520
4528
4521 -A/--after can be used to remove only files that have already
4529 -A/--after can be used to remove only files that have already
4522 been deleted, -f/--force can be used to force deletion, and -Af
4530 been deleted, -f/--force can be used to force deletion, and -Af
4523 can be used to remove files from the next revision without
4531 can be used to remove files from the next revision without
4524 deleting them from the working directory.
4532 deleting them from the working directory.
4525
4533
4526 The following table details the behavior of remove for different
4534 The following table details the behavior of remove for different
4527 file states (columns) and option combinations (rows). The file
4535 file states (columns) and option combinations (rows). The file
4528 states are Added [A], Clean [C], Modified [M] and Missing [!]
4536 states are Added [A], Clean [C], Modified [M] and Missing [!]
4529 (as reported by :hg:`status`). The actions are Warn, Remove
4537 (as reported by :hg:`status`). The actions are Warn, Remove
4530 (from branch) and Delete (from disk):
4538 (from branch) and Delete (from disk):
4531
4539
4532 ========= == == == ==
4540 ========= == == == ==
4533 opt/state A C M !
4541 opt/state A C M !
4534 ========= == == == ==
4542 ========= == == == ==
4535 none W RD W R
4543 none W RD W R
4536 -f R RD RD R
4544 -f R RD RD R
4537 -A W W W R
4545 -A W W W R
4538 -Af R R R R
4546 -Af R R R R
4539 ========= == == == ==
4547 ========= == == == ==
4540
4548
4541 .. note::
4549 .. note::
4542
4550
4543 :hg:`remove` never deletes files in Added [A] state from the
4551 :hg:`remove` never deletes files in Added [A] state from the
4544 working directory, not even if ``--force`` is specified.
4552 working directory, not even if ``--force`` is specified.
4545
4553
4546 Returns 0 on success, 1 if any warnings encountered.
4554 Returns 0 on success, 1 if any warnings encountered.
4547 """
4555 """
4548
4556
4549 opts = pycompat.byteskwargs(opts)
4557 opts = pycompat.byteskwargs(opts)
4550 after, force = opts.get('after'), opts.get('force')
4558 after, force = opts.get('after'), opts.get('force')
4551 dryrun = opts.get('dry_run')
4559 dryrun = opts.get('dry_run')
4552 if not pats and not after:
4560 if not pats and not after:
4553 raise error.Abort(_('no files specified'))
4561 raise error.Abort(_('no files specified'))
4554
4562
4555 m = scmutil.match(repo[None], pats, opts)
4563 m = scmutil.match(repo[None], pats, opts)
4556 subrepos = opts.get('subrepos')
4564 subrepos = opts.get('subrepos')
4557 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4565 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4558 dryrun=dryrun)
4566 dryrun=dryrun)
4559
4567
4560 @command('rename|move|mv',
4568 @command('rename|move|mv',
4561 [('A', 'after', None, _('record a rename that has already occurred')),
4569 [('A', 'after', None, _('record a rename that has already occurred')),
4562 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4570 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4563 ] + walkopts + dryrunopts,
4571 ] + walkopts + dryrunopts,
4564 _('[OPTION]... SOURCE... DEST'))
4572 _('[OPTION]... SOURCE... DEST'))
4565 def rename(ui, repo, *pats, **opts):
4573 def rename(ui, repo, *pats, **opts):
4566 """rename files; equivalent of copy + remove
4574 """rename files; equivalent of copy + remove
4567
4575
4568 Mark dest as copies of sources; mark sources for deletion. If dest
4576 Mark dest as copies of sources; mark sources for deletion. If dest
4569 is a directory, copies are put in that directory. If dest is a
4577 is a directory, copies are put in that directory. If dest is a
4570 file, there can only be one source.
4578 file, there can only be one source.
4571
4579
4572 By default, this command copies the contents of files as they
4580 By default, this command copies the contents of files as they
4573 exist in the working directory. If invoked with -A/--after, the
4581 exist in the working directory. If invoked with -A/--after, the
4574 operation is recorded, but no copying is performed.
4582 operation is recorded, but no copying is performed.
4575
4583
4576 This command takes effect at the next commit. To undo a rename
4584 This command takes effect at the next commit. To undo a rename
4577 before that, see :hg:`revert`.
4585 before that, see :hg:`revert`.
4578
4586
4579 Returns 0 on success, 1 if errors are encountered.
4587 Returns 0 on success, 1 if errors are encountered.
4580 """
4588 """
4581 opts = pycompat.byteskwargs(opts)
4589 opts = pycompat.byteskwargs(opts)
4582 with repo.wlock(False):
4590 with repo.wlock(False):
4583 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4591 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4584
4592
4585 @command('resolve',
4593 @command('resolve',
4586 [('a', 'all', None, _('select all unresolved files')),
4594 [('a', 'all', None, _('select all unresolved files')),
4587 ('l', 'list', None, _('list state of files needing merge')),
4595 ('l', 'list', None, _('list state of files needing merge')),
4588 ('m', 'mark', None, _('mark files as resolved')),
4596 ('m', 'mark', None, _('mark files as resolved')),
4589 ('u', 'unmark', None, _('mark files as unresolved')),
4597 ('u', 'unmark', None, _('mark files as unresolved')),
4590 ('n', 'no-status', None, _('hide status prefix')),
4598 ('n', 'no-status', None, _('hide status prefix')),
4591 ('', 're-merge', None, _('re-merge files'))]
4599 ('', 're-merge', None, _('re-merge files'))]
4592 + mergetoolopts + walkopts + formatteropts,
4600 + mergetoolopts + walkopts + formatteropts,
4593 _('[OPTION]... [FILE]...'),
4601 _('[OPTION]... [FILE]...'),
4594 inferrepo=True)
4602 inferrepo=True)
4595 def resolve(ui, repo, *pats, **opts):
4603 def resolve(ui, repo, *pats, **opts):
4596 """redo merges or set/view the merge status of files
4604 """redo merges or set/view the merge status of files
4597
4605
4598 Merges with unresolved conflicts are often the result of
4606 Merges with unresolved conflicts are often the result of
4599 non-interactive merging using the ``internal:merge`` configuration
4607 non-interactive merging using the ``internal:merge`` configuration
4600 setting, or a command-line merge tool like ``diff3``. The resolve
4608 setting, or a command-line merge tool like ``diff3``. The resolve
4601 command is used to manage the files involved in a merge, after
4609 command is used to manage the files involved in a merge, after
4602 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4610 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4603 working directory must have two parents). See :hg:`help
4611 working directory must have two parents). See :hg:`help
4604 merge-tools` for information on configuring merge tools.
4612 merge-tools` for information on configuring merge tools.
4605
4613
4606 The resolve command can be used in the following ways:
4614 The resolve command can be used in the following ways:
4607
4615
4608 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4616 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4609 the specified files, discarding any previous merge attempts. Re-merging
4617 the specified files, discarding any previous merge attempts. Re-merging
4610 is not performed for files already marked as resolved. Use ``--all/-a``
4618 is not performed for files already marked as resolved. Use ``--all/-a``
4611 to select all unresolved files. ``--tool`` can be used to specify
4619 to select all unresolved files. ``--tool`` can be used to specify
4612 the merge tool used for the given files. It overrides the HGMERGE
4620 the merge tool used for the given files. It overrides the HGMERGE
4613 environment variable and your configuration files. Previous file
4621 environment variable and your configuration files. Previous file
4614 contents are saved with a ``.orig`` suffix.
4622 contents are saved with a ``.orig`` suffix.
4615
4623
4616 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4624 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4617 (e.g. after having manually fixed-up the files). The default is
4625 (e.g. after having manually fixed-up the files). The default is
4618 to mark all unresolved files.
4626 to mark all unresolved files.
4619
4627
4620 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4628 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4621 default is to mark all resolved files.
4629 default is to mark all resolved files.
4622
4630
4623 - :hg:`resolve -l`: list files which had or still have conflicts.
4631 - :hg:`resolve -l`: list files which had or still have conflicts.
4624 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4632 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4625 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4633 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4626 the list. See :hg:`help filesets` for details.
4634 the list. See :hg:`help filesets` for details.
4627
4635
4628 .. note::
4636 .. note::
4629
4637
4630 Mercurial will not let you commit files with unresolved merge
4638 Mercurial will not let you commit files with unresolved merge
4631 conflicts. You must use :hg:`resolve -m ...` before you can
4639 conflicts. You must use :hg:`resolve -m ...` before you can
4632 commit after a conflicting merge.
4640 commit after a conflicting merge.
4633
4641
4634 Returns 0 on success, 1 if any files fail a resolve attempt.
4642 Returns 0 on success, 1 if any files fail a resolve attempt.
4635 """
4643 """
4636
4644
4637 opts = pycompat.byteskwargs(opts)
4645 opts = pycompat.byteskwargs(opts)
4638 confirm = ui.configbool('commands', 'resolve.confirm')
4646 confirm = ui.configbool('commands', 'resolve.confirm')
4639 flaglist = 'all mark unmark list no_status re_merge'.split()
4647 flaglist = 'all mark unmark list no_status re_merge'.split()
4640 all, mark, unmark, show, nostatus, remerge = \
4648 all, mark, unmark, show, nostatus, remerge = \
4641 [opts.get(o) for o in flaglist]
4649 [opts.get(o) for o in flaglist]
4642
4650
4643 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4651 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4644 if actioncount > 1:
4652 if actioncount > 1:
4645 raise error.Abort(_("too many actions specified"))
4653 raise error.Abort(_("too many actions specified"))
4646 elif (actioncount == 0
4654 elif (actioncount == 0
4647 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4655 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4648 hint = _('use --mark, --unmark, --list or --re-merge')
4656 hint = _('use --mark, --unmark, --list or --re-merge')
4649 raise error.Abort(_('no action specified'), hint=hint)
4657 raise error.Abort(_('no action specified'), hint=hint)
4650 if pats and all:
4658 if pats and all:
4651 raise error.Abort(_("can't specify --all and patterns"))
4659 raise error.Abort(_("can't specify --all and patterns"))
4652 if not (all or pats or show or mark or unmark):
4660 if not (all or pats or show or mark or unmark):
4653 raise error.Abort(_('no files or directories specified'),
4661 raise error.Abort(_('no files or directories specified'),
4654 hint=('use --all to re-merge all unresolved files'))
4662 hint=('use --all to re-merge all unresolved files'))
4655
4663
4656 if confirm:
4664 if confirm:
4657 if all:
4665 if all:
4658 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4666 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4659 b'$$ &Yes $$ &No')):
4667 b'$$ &Yes $$ &No')):
4660 raise error.Abort(_('user quit'))
4668 raise error.Abort(_('user quit'))
4661 if mark and not pats:
4669 if mark and not pats:
4662 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4670 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4663 b'$$ &Yes $$ &No')):
4671 b'$$ &Yes $$ &No')):
4664 raise error.Abort(_('user quit'))
4672 raise error.Abort(_('user quit'))
4665 if unmark and not pats:
4673 if unmark and not pats:
4666 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4674 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4667 b'$$ &Yes $$ &No')):
4675 b'$$ &Yes $$ &No')):
4668 raise error.Abort(_('user quit'))
4676 raise error.Abort(_('user quit'))
4669
4677
4670 if show:
4678 if show:
4671 ui.pager('resolve')
4679 ui.pager('resolve')
4672 fm = ui.formatter('resolve', opts)
4680 fm = ui.formatter('resolve', opts)
4673 ms = mergemod.mergestate.read(repo)
4681 ms = mergemod.mergestate.read(repo)
4674 wctx = repo[None]
4682 wctx = repo[None]
4675 m = scmutil.match(wctx, pats, opts)
4683 m = scmutil.match(wctx, pats, opts)
4676
4684
4677 # Labels and keys based on merge state. Unresolved path conflicts show
4685 # Labels and keys based on merge state. Unresolved path conflicts show
4678 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4686 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4679 # resolved conflicts.
4687 # resolved conflicts.
4680 mergestateinfo = {
4688 mergestateinfo = {
4681 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4689 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4682 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4690 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4683 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4691 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4684 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4692 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4685 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4693 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4686 'D'),
4694 'D'),
4687 }
4695 }
4688
4696
4689 for f in ms:
4697 for f in ms:
4690 if not m(f):
4698 if not m(f):
4691 continue
4699 continue
4692
4700
4693 label, key = mergestateinfo[ms[f]]
4701 label, key = mergestateinfo[ms[f]]
4694 fm.startitem()
4702 fm.startitem()
4695 fm.context(ctx=wctx)
4703 fm.context(ctx=wctx)
4696 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4704 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4697 fm.write('path', '%s\n', f, label=label)
4705 fm.write('path', '%s\n', f, label=label)
4698 fm.end()
4706 fm.end()
4699 return 0
4707 return 0
4700
4708
4701 with repo.wlock():
4709 with repo.wlock():
4702 ms = mergemod.mergestate.read(repo)
4710 ms = mergemod.mergestate.read(repo)
4703
4711
4704 if not (ms.active() or repo.dirstate.p2() != nullid):
4712 if not (ms.active() or repo.dirstate.p2() != nullid):
4705 raise error.Abort(
4713 raise error.Abort(
4706 _('resolve command not applicable when not merging'))
4714 _('resolve command not applicable when not merging'))
4707
4715
4708 wctx = repo[None]
4716 wctx = repo[None]
4709
4717
4710 if (ms.mergedriver
4718 if (ms.mergedriver
4711 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4719 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4712 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4720 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4713 ms.commit()
4721 ms.commit()
4714 # allow mark and unmark to go through
4722 # allow mark and unmark to go through
4715 if not mark and not unmark and not proceed:
4723 if not mark and not unmark and not proceed:
4716 return 1
4724 return 1
4717
4725
4718 m = scmutil.match(wctx, pats, opts)
4726 m = scmutil.match(wctx, pats, opts)
4719 ret = 0
4727 ret = 0
4720 didwork = False
4728 didwork = False
4721 runconclude = False
4729 runconclude = False
4722
4730
4723 tocomplete = []
4731 tocomplete = []
4724 hasconflictmarkers = []
4732 hasconflictmarkers = []
4725 if mark:
4733 if mark:
4726 markcheck = ui.config('commands', 'resolve.mark-check')
4734 markcheck = ui.config('commands', 'resolve.mark-check')
4727 if markcheck not in ['warn', 'abort']:
4735 if markcheck not in ['warn', 'abort']:
4728 # Treat all invalid / unrecognized values as 'none'.
4736 # Treat all invalid / unrecognized values as 'none'.
4729 markcheck = False
4737 markcheck = False
4730 for f in ms:
4738 for f in ms:
4731 if not m(f):
4739 if not m(f):
4732 continue
4740 continue
4733
4741
4734 didwork = True
4742 didwork = True
4735
4743
4736 # don't let driver-resolved files be marked, and run the conclude
4744 # don't let driver-resolved files be marked, and run the conclude
4737 # step if asked to resolve
4745 # step if asked to resolve
4738 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4746 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4739 exact = m.exact(f)
4747 exact = m.exact(f)
4740 if mark:
4748 if mark:
4741 if exact:
4749 if exact:
4742 ui.warn(_('not marking %s as it is driver-resolved\n')
4750 ui.warn(_('not marking %s as it is driver-resolved\n')
4743 % f)
4751 % f)
4744 elif unmark:
4752 elif unmark:
4745 if exact:
4753 if exact:
4746 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4754 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4747 % f)
4755 % f)
4748 else:
4756 else:
4749 runconclude = True
4757 runconclude = True
4750 continue
4758 continue
4751
4759
4752 # path conflicts must be resolved manually
4760 # path conflicts must be resolved manually
4753 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4761 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4754 mergemod.MERGE_RECORD_RESOLVED_PATH):
4762 mergemod.MERGE_RECORD_RESOLVED_PATH):
4755 if mark:
4763 if mark:
4756 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4764 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4757 elif unmark:
4765 elif unmark:
4758 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4766 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4759 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4767 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4760 ui.warn(_('%s: path conflict must be resolved manually\n')
4768 ui.warn(_('%s: path conflict must be resolved manually\n')
4761 % f)
4769 % f)
4762 continue
4770 continue
4763
4771
4764 if mark:
4772 if mark:
4765 if markcheck:
4773 if markcheck:
4766 with repo.wvfs(f) as fobj:
4774 with repo.wvfs(f) as fobj:
4767 fdata = fobj.read()
4775 fdata = fobj.read()
4768 if filemerge.hasconflictmarkers(fdata) and \
4776 if filemerge.hasconflictmarkers(fdata) and \
4769 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4777 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4770 hasconflictmarkers.append(f)
4778 hasconflictmarkers.append(f)
4771 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4779 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4772 elif unmark:
4780 elif unmark:
4773 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4781 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4774 else:
4782 else:
4775 # backup pre-resolve (merge uses .orig for its own purposes)
4783 # backup pre-resolve (merge uses .orig for its own purposes)
4776 a = repo.wjoin(f)
4784 a = repo.wjoin(f)
4777 try:
4785 try:
4778 util.copyfile(a, a + ".resolve")
4786 util.copyfile(a, a + ".resolve")
4779 except (IOError, OSError) as inst:
4787 except (IOError, OSError) as inst:
4780 if inst.errno != errno.ENOENT:
4788 if inst.errno != errno.ENOENT:
4781 raise
4789 raise
4782
4790
4783 try:
4791 try:
4784 # preresolve file
4792 # preresolve file
4785 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4793 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4786 with ui.configoverride(overrides, 'resolve'):
4794 with ui.configoverride(overrides, 'resolve'):
4787 complete, r = ms.preresolve(f, wctx)
4795 complete, r = ms.preresolve(f, wctx)
4788 if not complete:
4796 if not complete:
4789 tocomplete.append(f)
4797 tocomplete.append(f)
4790 elif r:
4798 elif r:
4791 ret = 1
4799 ret = 1
4792 finally:
4800 finally:
4793 ms.commit()
4801 ms.commit()
4794
4802
4795 # replace filemerge's .orig file with our resolve file, but only
4803 # replace filemerge's .orig file with our resolve file, but only
4796 # for merges that are complete
4804 # for merges that are complete
4797 if complete:
4805 if complete:
4798 try:
4806 try:
4799 util.rename(a + ".resolve",
4807 util.rename(a + ".resolve",
4800 scmutil.origpath(ui, repo, a))
4808 scmutil.origpath(ui, repo, a))
4801 except OSError as inst:
4809 except OSError as inst:
4802 if inst.errno != errno.ENOENT:
4810 if inst.errno != errno.ENOENT:
4803 raise
4811 raise
4804
4812
4805 if hasconflictmarkers:
4813 if hasconflictmarkers:
4806 ui.warn(_('warning: the following files still have conflict '
4814 ui.warn(_('warning: the following files still have conflict '
4807 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4815 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4808 if markcheck == 'abort' and not all:
4816 if markcheck == 'abort' and not all:
4809 raise error.Abort(_('conflict markers detected'),
4817 raise error.Abort(_('conflict markers detected'),
4810 hint=_('use --all to mark anyway'))
4818 hint=_('use --all to mark anyway'))
4811
4819
4812 for f in tocomplete:
4820 for f in tocomplete:
4813 try:
4821 try:
4814 # resolve file
4822 # resolve file
4815 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4823 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4816 with ui.configoverride(overrides, 'resolve'):
4824 with ui.configoverride(overrides, 'resolve'):
4817 r = ms.resolve(f, wctx)
4825 r = ms.resolve(f, wctx)
4818 if r:
4826 if r:
4819 ret = 1
4827 ret = 1
4820 finally:
4828 finally:
4821 ms.commit()
4829 ms.commit()
4822
4830
4823 # replace filemerge's .orig file with our resolve file
4831 # replace filemerge's .orig file with our resolve file
4824 a = repo.wjoin(f)
4832 a = repo.wjoin(f)
4825 try:
4833 try:
4826 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4834 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4827 except OSError as inst:
4835 except OSError as inst:
4828 if inst.errno != errno.ENOENT:
4836 if inst.errno != errno.ENOENT:
4829 raise
4837 raise
4830
4838
4831 ms.commit()
4839 ms.commit()
4832 ms.recordactions()
4840 ms.recordactions()
4833
4841
4834 if not didwork and pats:
4842 if not didwork and pats:
4835 hint = None
4843 hint = None
4836 if not any([p for p in pats if p.find(':') >= 0]):
4844 if not any([p for p in pats if p.find(':') >= 0]):
4837 pats = ['path:%s' % p for p in pats]
4845 pats = ['path:%s' % p for p in pats]
4838 m = scmutil.match(wctx, pats, opts)
4846 m = scmutil.match(wctx, pats, opts)
4839 for f in ms:
4847 for f in ms:
4840 if not m(f):
4848 if not m(f):
4841 continue
4849 continue
4842 def flag(o):
4850 def flag(o):
4843 if o == 're_merge':
4851 if o == 're_merge':
4844 return '--re-merge '
4852 return '--re-merge '
4845 return '-%s ' % o[0:1]
4853 return '-%s ' % o[0:1]
4846 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4854 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4847 hint = _("(try: hg resolve %s%s)\n") % (
4855 hint = _("(try: hg resolve %s%s)\n") % (
4848 flags,
4856 flags,
4849 ' '.join(pats))
4857 ' '.join(pats))
4850 break
4858 break
4851 ui.warn(_("arguments do not match paths that need resolving\n"))
4859 ui.warn(_("arguments do not match paths that need resolving\n"))
4852 if hint:
4860 if hint:
4853 ui.warn(hint)
4861 ui.warn(hint)
4854 elif ms.mergedriver and ms.mdstate() != 's':
4862 elif ms.mergedriver and ms.mdstate() != 's':
4855 # run conclude step when either a driver-resolved file is requested
4863 # run conclude step when either a driver-resolved file is requested
4856 # or there are no driver-resolved files
4864 # or there are no driver-resolved files
4857 # we can't use 'ret' to determine whether any files are unresolved
4865 # we can't use 'ret' to determine whether any files are unresolved
4858 # because we might not have tried to resolve some
4866 # because we might not have tried to resolve some
4859 if ((runconclude or not list(ms.driverresolved()))
4867 if ((runconclude or not list(ms.driverresolved()))
4860 and not list(ms.unresolved())):
4868 and not list(ms.unresolved())):
4861 proceed = mergemod.driverconclude(repo, ms, wctx)
4869 proceed = mergemod.driverconclude(repo, ms, wctx)
4862 ms.commit()
4870 ms.commit()
4863 if not proceed:
4871 if not proceed:
4864 return 1
4872 return 1
4865
4873
4866 # Nudge users into finishing an unfinished operation
4874 # Nudge users into finishing an unfinished operation
4867 unresolvedf = list(ms.unresolved())
4875 unresolvedf = list(ms.unresolved())
4868 driverresolvedf = list(ms.driverresolved())
4876 driverresolvedf = list(ms.driverresolved())
4869 if not unresolvedf and not driverresolvedf:
4877 if not unresolvedf and not driverresolvedf:
4870 ui.status(_('(no more unresolved files)\n'))
4878 ui.status(_('(no more unresolved files)\n'))
4871 cmdutil.checkafterresolved(repo)
4879 cmdutil.checkafterresolved(repo)
4872 elif not unresolvedf:
4880 elif not unresolvedf:
4873 ui.status(_('(no more unresolved files -- '
4881 ui.status(_('(no more unresolved files -- '
4874 'run "hg resolve --all" to conclude)\n'))
4882 'run "hg resolve --all" to conclude)\n'))
4875
4883
4876 return ret
4884 return ret
4877
4885
4878 @command('revert',
4886 @command('revert',
4879 [('a', 'all', None, _('revert all changes when no arguments given')),
4887 [('a', 'all', None, _('revert all changes when no arguments given')),
4880 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4888 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4881 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4889 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4882 ('C', 'no-backup', None, _('do not save backup copies of files')),
4890 ('C', 'no-backup', None, _('do not save backup copies of files')),
4883 ('i', 'interactive', None, _('interactively select the changes')),
4891 ('i', 'interactive', None, _('interactively select the changes')),
4884 ] + walkopts + dryrunopts,
4892 ] + walkopts + dryrunopts,
4885 _('[OPTION]... [-r REV] [NAME]...'))
4893 _('[OPTION]... [-r REV] [NAME]...'))
4886 def revert(ui, repo, *pats, **opts):
4894 def revert(ui, repo, *pats, **opts):
4887 """restore files to their checkout state
4895 """restore files to their checkout state
4888
4896
4889 .. note::
4897 .. note::
4890
4898
4891 To check out earlier revisions, you should use :hg:`update REV`.
4899 To check out earlier revisions, you should use :hg:`update REV`.
4892 To cancel an uncommitted merge (and lose your changes),
4900 To cancel an uncommitted merge (and lose your changes),
4893 use :hg:`merge --abort`.
4901 use :hg:`merge --abort`.
4894
4902
4895 With no revision specified, revert the specified files or directories
4903 With no revision specified, revert the specified files or directories
4896 to the contents they had in the parent of the working directory.
4904 to the contents they had in the parent of the working directory.
4897 This restores the contents of files to an unmodified
4905 This restores the contents of files to an unmodified
4898 state and unschedules adds, removes, copies, and renames. If the
4906 state and unschedules adds, removes, copies, and renames. If the
4899 working directory has two parents, you must explicitly specify a
4907 working directory has two parents, you must explicitly specify a
4900 revision.
4908 revision.
4901
4909
4902 Using the -r/--rev or -d/--date options, revert the given files or
4910 Using the -r/--rev or -d/--date options, revert the given files or
4903 directories to their states as of a specific revision. Because
4911 directories to their states as of a specific revision. Because
4904 revert does not change the working directory parents, this will
4912 revert does not change the working directory parents, this will
4905 cause these files to appear modified. This can be helpful to "back
4913 cause these files to appear modified. This can be helpful to "back
4906 out" some or all of an earlier change. See :hg:`backout` for a
4914 out" some or all of an earlier change. See :hg:`backout` for a
4907 related method.
4915 related method.
4908
4916
4909 Modified files are saved with a .orig suffix before reverting.
4917 Modified files are saved with a .orig suffix before reverting.
4910 To disable these backups, use --no-backup. It is possible to store
4918 To disable these backups, use --no-backup. It is possible to store
4911 the backup files in a custom directory relative to the root of the
4919 the backup files in a custom directory relative to the root of the
4912 repository by setting the ``ui.origbackuppath`` configuration
4920 repository by setting the ``ui.origbackuppath`` configuration
4913 option.
4921 option.
4914
4922
4915 See :hg:`help dates` for a list of formats valid for -d/--date.
4923 See :hg:`help dates` for a list of formats valid for -d/--date.
4916
4924
4917 See :hg:`help backout` for a way to reverse the effect of an
4925 See :hg:`help backout` for a way to reverse the effect of an
4918 earlier changeset.
4926 earlier changeset.
4919
4927
4920 Returns 0 on success.
4928 Returns 0 on success.
4921 """
4929 """
4922
4930
4923 opts = pycompat.byteskwargs(opts)
4931 opts = pycompat.byteskwargs(opts)
4924 if opts.get("date"):
4932 if opts.get("date"):
4925 if opts.get("rev"):
4933 if opts.get("rev"):
4926 raise error.Abort(_("you can't specify a revision and a date"))
4934 raise error.Abort(_("you can't specify a revision and a date"))
4927 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4935 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4928
4936
4929 parent, p2 = repo.dirstate.parents()
4937 parent, p2 = repo.dirstate.parents()
4930 if not opts.get('rev') and p2 != nullid:
4938 if not opts.get('rev') and p2 != nullid:
4931 # revert after merge is a trap for new users (issue2915)
4939 # revert after merge is a trap for new users (issue2915)
4932 raise error.Abort(_('uncommitted merge with no revision specified'),
4940 raise error.Abort(_('uncommitted merge with no revision specified'),
4933 hint=_("use 'hg update' or see 'hg help revert'"))
4941 hint=_("use 'hg update' or see 'hg help revert'"))
4934
4942
4935 rev = opts.get('rev')
4943 rev = opts.get('rev')
4936 if rev:
4944 if rev:
4937 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4945 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4938 ctx = scmutil.revsingle(repo, rev)
4946 ctx = scmutil.revsingle(repo, rev)
4939
4947
4940 if (not (pats or opts.get('include') or opts.get('exclude') or
4948 if (not (pats or opts.get('include') or opts.get('exclude') or
4941 opts.get('all') or opts.get('interactive'))):
4949 opts.get('all') or opts.get('interactive'))):
4942 msg = _("no files or directories specified")
4950 msg = _("no files or directories specified")
4943 if p2 != nullid:
4951 if p2 != nullid:
4944 hint = _("uncommitted merge, use --all to discard all changes,"
4952 hint = _("uncommitted merge, use --all to discard all changes,"
4945 " or 'hg update -C .' to abort the merge")
4953 " or 'hg update -C .' to abort the merge")
4946 raise error.Abort(msg, hint=hint)
4954 raise error.Abort(msg, hint=hint)
4947 dirty = any(repo.status())
4955 dirty = any(repo.status())
4948 node = ctx.node()
4956 node = ctx.node()
4949 if node != parent:
4957 if node != parent:
4950 if dirty:
4958 if dirty:
4951 hint = _("uncommitted changes, use --all to discard all"
4959 hint = _("uncommitted changes, use --all to discard all"
4952 " changes, or 'hg update %d' to update") % ctx.rev()
4960 " changes, or 'hg update %d' to update") % ctx.rev()
4953 else:
4961 else:
4954 hint = _("use --all to revert all files,"
4962 hint = _("use --all to revert all files,"
4955 " or 'hg update %d' to update") % ctx.rev()
4963 " or 'hg update %d' to update") % ctx.rev()
4956 elif dirty:
4964 elif dirty:
4957 hint = _("uncommitted changes, use --all to discard all changes")
4965 hint = _("uncommitted changes, use --all to discard all changes")
4958 else:
4966 else:
4959 hint = _("use --all to revert all files")
4967 hint = _("use --all to revert all files")
4960 raise error.Abort(msg, hint=hint)
4968 raise error.Abort(msg, hint=hint)
4961
4969
4962 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4970 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4963 **pycompat.strkwargs(opts))
4971 **pycompat.strkwargs(opts))
4964
4972
4965 @command('rollback', dryrunopts +
4973 @command('rollback', dryrunopts +
4966 [('f', 'force', False, _('ignore safety measures'))])
4974 [('f', 'force', False, _('ignore safety measures'))])
4967 def rollback(ui, repo, **opts):
4975 def rollback(ui, repo, **opts):
4968 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4976 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4969
4977
4970 Please use :hg:`commit --amend` instead of rollback to correct
4978 Please use :hg:`commit --amend` instead of rollback to correct
4971 mistakes in the last commit.
4979 mistakes in the last commit.
4972
4980
4973 This command should be used with care. There is only one level of
4981 This command should be used with care. There is only one level of
4974 rollback, and there is no way to undo a rollback. It will also
4982 rollback, and there is no way to undo a rollback. It will also
4975 restore the dirstate at the time of the last transaction, losing
4983 restore the dirstate at the time of the last transaction, losing
4976 any dirstate changes since that time. This command does not alter
4984 any dirstate changes since that time. This command does not alter
4977 the working directory.
4985 the working directory.
4978
4986
4979 Transactions are used to encapsulate the effects of all commands
4987 Transactions are used to encapsulate the effects of all commands
4980 that create new changesets or propagate existing changesets into a
4988 that create new changesets or propagate existing changesets into a
4981 repository.
4989 repository.
4982
4990
4983 .. container:: verbose
4991 .. container:: verbose
4984
4992
4985 For example, the following commands are transactional, and their
4993 For example, the following commands are transactional, and their
4986 effects can be rolled back:
4994 effects can be rolled back:
4987
4995
4988 - commit
4996 - commit
4989 - import
4997 - import
4990 - pull
4998 - pull
4991 - push (with this repository as the destination)
4999 - push (with this repository as the destination)
4992 - unbundle
5000 - unbundle
4993
5001
4994 To avoid permanent data loss, rollback will refuse to rollback a
5002 To avoid permanent data loss, rollback will refuse to rollback a
4995 commit transaction if it isn't checked out. Use --force to
5003 commit transaction if it isn't checked out. Use --force to
4996 override this protection.
5004 override this protection.
4997
5005
4998 The rollback command can be entirely disabled by setting the
5006 The rollback command can be entirely disabled by setting the
4999 ``ui.rollback`` configuration setting to false. If you're here
5007 ``ui.rollback`` configuration setting to false. If you're here
5000 because you want to use rollback and it's disabled, you can
5008 because you want to use rollback and it's disabled, you can
5001 re-enable the command by setting ``ui.rollback`` to true.
5009 re-enable the command by setting ``ui.rollback`` to true.
5002
5010
5003 This command is not intended for use on public repositories. Once
5011 This command is not intended for use on public repositories. Once
5004 changes are visible for pull by other users, rolling a transaction
5012 changes are visible for pull by other users, rolling a transaction
5005 back locally is ineffective (someone else may already have pulled
5013 back locally is ineffective (someone else may already have pulled
5006 the changes). Furthermore, a race is possible with readers of the
5014 the changes). Furthermore, a race is possible with readers of the
5007 repository; for example an in-progress pull from the repository
5015 repository; for example an in-progress pull from the repository
5008 may fail if a rollback is performed.
5016 may fail if a rollback is performed.
5009
5017
5010 Returns 0 on success, 1 if no rollback data is available.
5018 Returns 0 on success, 1 if no rollback data is available.
5011 """
5019 """
5012 if not ui.configbool('ui', 'rollback'):
5020 if not ui.configbool('ui', 'rollback'):
5013 raise error.Abort(_('rollback is disabled because it is unsafe'),
5021 raise error.Abort(_('rollback is disabled because it is unsafe'),
5014 hint=('see `hg help -v rollback` for information'))
5022 hint=('see `hg help -v rollback` for information'))
5015 return repo.rollback(dryrun=opts.get(r'dry_run'),
5023 return repo.rollback(dryrun=opts.get(r'dry_run'),
5016 force=opts.get(r'force'))
5024 force=opts.get(r'force'))
5017
5025
5018 @command('root', [], intents={INTENT_READONLY})
5026 @command('root', [], intents={INTENT_READONLY})
5019 def root(ui, repo):
5027 def root(ui, repo):
5020 """print the root (top) of the current working directory
5028 """print the root (top) of the current working directory
5021
5029
5022 Print the root directory of the current repository.
5030 Print the root directory of the current repository.
5023
5031
5024 Returns 0 on success.
5032 Returns 0 on success.
5025 """
5033 """
5026 ui.write(repo.root + "\n")
5034 ui.write(repo.root + "\n")
5027
5035
5028 @command('^serve',
5036 @command('^serve',
5029 [('A', 'accesslog', '', _('name of access log file to write to'),
5037 [('A', 'accesslog', '', _('name of access log file to write to'),
5030 _('FILE')),
5038 _('FILE')),
5031 ('d', 'daemon', None, _('run server in background')),
5039 ('d', 'daemon', None, _('run server in background')),
5032 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5040 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5033 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5041 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5034 # use string type, then we can check if something was passed
5042 # use string type, then we can check if something was passed
5035 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5043 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5036 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5044 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5037 _('ADDR')),
5045 _('ADDR')),
5038 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5046 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5039 _('PREFIX')),
5047 _('PREFIX')),
5040 ('n', 'name', '',
5048 ('n', 'name', '',
5041 _('name to show in web pages (default: working directory)'), _('NAME')),
5049 _('name to show in web pages (default: working directory)'), _('NAME')),
5042 ('', 'web-conf', '',
5050 ('', 'web-conf', '',
5043 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5051 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5044 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5052 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5045 _('FILE')),
5053 _('FILE')),
5046 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5054 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5047 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5055 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5048 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5056 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5049 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5057 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5050 ('', 'style', '', _('template style to use'), _('STYLE')),
5058 ('', 'style', '', _('template style to use'), _('STYLE')),
5051 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5059 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5052 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5060 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5053 ('', 'print-url', None, _('start and print only the URL'))]
5061 ('', 'print-url', None, _('start and print only the URL'))]
5054 + subrepoopts,
5062 + subrepoopts,
5055 _('[OPTION]...'),
5063 _('[OPTION]...'),
5056 optionalrepo=True)
5064 optionalrepo=True)
5057 def serve(ui, repo, **opts):
5065 def serve(ui, repo, **opts):
5058 """start stand-alone webserver
5066 """start stand-alone webserver
5059
5067
5060 Start a local HTTP repository browser and pull server. You can use
5068 Start a local HTTP repository browser and pull server. You can use
5061 this for ad-hoc sharing and browsing of repositories. It is
5069 this for ad-hoc sharing and browsing of repositories. It is
5062 recommended to use a real web server to serve a repository for
5070 recommended to use a real web server to serve a repository for
5063 longer periods of time.
5071 longer periods of time.
5064
5072
5065 Please note that the server does not implement access control.
5073 Please note that the server does not implement access control.
5066 This means that, by default, anybody can read from the server and
5074 This means that, by default, anybody can read from the server and
5067 nobody can write to it by default. Set the ``web.allow-push``
5075 nobody can write to it by default. Set the ``web.allow-push``
5068 option to ``*`` to allow everybody to push to the server. You
5076 option to ``*`` to allow everybody to push to the server. You
5069 should use a real web server if you need to authenticate users.
5077 should use a real web server if you need to authenticate users.
5070
5078
5071 By default, the server logs accesses to stdout and errors to
5079 By default, the server logs accesses to stdout and errors to
5072 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5080 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5073 files.
5081 files.
5074
5082
5075 To have the server choose a free port number to listen on, specify
5083 To have the server choose a free port number to listen on, specify
5076 a port number of 0; in this case, the server will print the port
5084 a port number of 0; in this case, the server will print the port
5077 number it uses.
5085 number it uses.
5078
5086
5079 Returns 0 on success.
5087 Returns 0 on success.
5080 """
5088 """
5081
5089
5082 opts = pycompat.byteskwargs(opts)
5090 opts = pycompat.byteskwargs(opts)
5083 if opts["stdio"] and opts["cmdserver"]:
5091 if opts["stdio"] and opts["cmdserver"]:
5084 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5092 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5085 if opts["print_url"] and ui.verbose:
5093 if opts["print_url"] and ui.verbose:
5086 raise error.Abort(_("cannot use --print-url with --verbose"))
5094 raise error.Abort(_("cannot use --print-url with --verbose"))
5087
5095
5088 if opts["stdio"]:
5096 if opts["stdio"]:
5089 if repo is None:
5097 if repo is None:
5090 raise error.RepoError(_("there is no Mercurial repository here"
5098 raise error.RepoError(_("there is no Mercurial repository here"
5091 " (.hg not found)"))
5099 " (.hg not found)"))
5092 s = wireprotoserver.sshserver(ui, repo)
5100 s = wireprotoserver.sshserver(ui, repo)
5093 s.serve_forever()
5101 s.serve_forever()
5094
5102
5095 service = server.createservice(ui, repo, opts)
5103 service = server.createservice(ui, repo, opts)
5096 return server.runservice(opts, initfn=service.init, runfn=service.run)
5104 return server.runservice(opts, initfn=service.init, runfn=service.run)
5097
5105
5098 _NOTTERSE = 'nothing'
5106 _NOTTERSE = 'nothing'
5099
5107
5100 @command('^status|st',
5108 @command('^status|st',
5101 [('A', 'all', None, _('show status of all files')),
5109 [('A', 'all', None, _('show status of all files')),
5102 ('m', 'modified', None, _('show only modified files')),
5110 ('m', 'modified', None, _('show only modified files')),
5103 ('a', 'added', None, _('show only added files')),
5111 ('a', 'added', None, _('show only added files')),
5104 ('r', 'removed', None, _('show only removed files')),
5112 ('r', 'removed', None, _('show only removed files')),
5105 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5113 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5106 ('c', 'clean', None, _('show only files without changes')),
5114 ('c', 'clean', None, _('show only files without changes')),
5107 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5115 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5108 ('i', 'ignored', None, _('show only ignored files')),
5116 ('i', 'ignored', None, _('show only ignored files')),
5109 ('n', 'no-status', None, _('hide status prefix')),
5117 ('n', 'no-status', None, _('hide status prefix')),
5110 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5118 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5111 ('C', 'copies', None, _('show source of copied files')),
5119 ('C', 'copies', None, _('show source of copied files')),
5112 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5120 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5113 ('', 'rev', [], _('show difference from revision'), _('REV')),
5121 ('', 'rev', [], _('show difference from revision'), _('REV')),
5114 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5122 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5115 ] + walkopts + subrepoopts + formatteropts,
5123 ] + walkopts + subrepoopts + formatteropts,
5116 _('[OPTION]... [FILE]...'),
5124 _('[OPTION]... [FILE]...'),
5117 inferrepo=True,
5125 inferrepo=True,
5118 intents={INTENT_READONLY})
5126 intents={INTENT_READONLY})
5119 def status(ui, repo, *pats, **opts):
5127 def status(ui, repo, *pats, **opts):
5120 """show changed files in the working directory
5128 """show changed files in the working directory
5121
5129
5122 Show status of files in the repository. If names are given, only
5130 Show status of files in the repository. If names are given, only
5123 files that match are shown. Files that are clean or ignored or
5131 files that match are shown. Files that are clean or ignored or
5124 the source of a copy/move operation, are not listed unless
5132 the source of a copy/move operation, are not listed unless
5125 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5133 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5126 Unless options described with "show only ..." are given, the
5134 Unless options described with "show only ..." are given, the
5127 options -mardu are used.
5135 options -mardu are used.
5128
5136
5129 Option -q/--quiet hides untracked (unknown and ignored) files
5137 Option -q/--quiet hides untracked (unknown and ignored) files
5130 unless explicitly requested with -u/--unknown or -i/--ignored.
5138 unless explicitly requested with -u/--unknown or -i/--ignored.
5131
5139
5132 .. note::
5140 .. note::
5133
5141
5134 :hg:`status` may appear to disagree with diff if permissions have
5142 :hg:`status` may appear to disagree with diff if permissions have
5135 changed or a merge has occurred. The standard diff format does
5143 changed or a merge has occurred. The standard diff format does
5136 not report permission changes and diff only reports changes
5144 not report permission changes and diff only reports changes
5137 relative to one merge parent.
5145 relative to one merge parent.
5138
5146
5139 If one revision is given, it is used as the base revision.
5147 If one revision is given, it is used as the base revision.
5140 If two revisions are given, the differences between them are
5148 If two revisions are given, the differences between them are
5141 shown. The --change option can also be used as a shortcut to list
5149 shown. The --change option can also be used as a shortcut to list
5142 the changed files of a revision from its first parent.
5150 the changed files of a revision from its first parent.
5143
5151
5144 The codes used to show the status of files are::
5152 The codes used to show the status of files are::
5145
5153
5146 M = modified
5154 M = modified
5147 A = added
5155 A = added
5148 R = removed
5156 R = removed
5149 C = clean
5157 C = clean
5150 ! = missing (deleted by non-hg command, but still tracked)
5158 ! = missing (deleted by non-hg command, but still tracked)
5151 ? = not tracked
5159 ? = not tracked
5152 I = ignored
5160 I = ignored
5153 = origin of the previous file (with --copies)
5161 = origin of the previous file (with --copies)
5154
5162
5155 .. container:: verbose
5163 .. container:: verbose
5156
5164
5157 The -t/--terse option abbreviates the output by showing only the directory
5165 The -t/--terse option abbreviates the output by showing only the directory
5158 name if all the files in it share the same status. The option takes an
5166 name if all the files in it share the same status. The option takes an
5159 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5167 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5160 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5168 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5161 for 'ignored' and 'c' for clean.
5169 for 'ignored' and 'c' for clean.
5162
5170
5163 It abbreviates only those statuses which are passed. Note that clean and
5171 It abbreviates only those statuses which are passed. Note that clean and
5164 ignored files are not displayed with '--terse ic' unless the -c/--clean
5172 ignored files are not displayed with '--terse ic' unless the -c/--clean
5165 and -i/--ignored options are also used.
5173 and -i/--ignored options are also used.
5166
5174
5167 The -v/--verbose option shows information when the repository is in an
5175 The -v/--verbose option shows information when the repository is in an
5168 unfinished merge, shelve, rebase state etc. You can have this behavior
5176 unfinished merge, shelve, rebase state etc. You can have this behavior
5169 turned on by default by enabling the ``commands.status.verbose`` option.
5177 turned on by default by enabling the ``commands.status.verbose`` option.
5170
5178
5171 You can skip displaying some of these states by setting
5179 You can skip displaying some of these states by setting
5172 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5180 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5173 'histedit', 'merge', 'rebase', or 'unshelve'.
5181 'histedit', 'merge', 'rebase', or 'unshelve'.
5174
5182
5175 Examples:
5183 Examples:
5176
5184
5177 - show changes in the working directory relative to a
5185 - show changes in the working directory relative to a
5178 changeset::
5186 changeset::
5179
5187
5180 hg status --rev 9353
5188 hg status --rev 9353
5181
5189
5182 - show changes in the working directory relative to the
5190 - show changes in the working directory relative to the
5183 current directory (see :hg:`help patterns` for more information)::
5191 current directory (see :hg:`help patterns` for more information)::
5184
5192
5185 hg status re:
5193 hg status re:
5186
5194
5187 - show all changes including copies in an existing changeset::
5195 - show all changes including copies in an existing changeset::
5188
5196
5189 hg status --copies --change 9353
5197 hg status --copies --change 9353
5190
5198
5191 - get a NUL separated list of added files, suitable for xargs::
5199 - get a NUL separated list of added files, suitable for xargs::
5192
5200
5193 hg status -an0
5201 hg status -an0
5194
5202
5195 - show more information about the repository status, abbreviating
5203 - show more information about the repository status, abbreviating
5196 added, removed, modified, deleted, and untracked paths::
5204 added, removed, modified, deleted, and untracked paths::
5197
5205
5198 hg status -v -t mardu
5206 hg status -v -t mardu
5199
5207
5200 Returns 0 on success.
5208 Returns 0 on success.
5201
5209
5202 """
5210 """
5203
5211
5204 opts = pycompat.byteskwargs(opts)
5212 opts = pycompat.byteskwargs(opts)
5205 revs = opts.get('rev')
5213 revs = opts.get('rev')
5206 change = opts.get('change')
5214 change = opts.get('change')
5207 terse = opts.get('terse')
5215 terse = opts.get('terse')
5208 if terse is _NOTTERSE:
5216 if terse is _NOTTERSE:
5209 if revs:
5217 if revs:
5210 terse = ''
5218 terse = ''
5211 else:
5219 else:
5212 terse = ui.config('commands', 'status.terse')
5220 terse = ui.config('commands', 'status.terse')
5213
5221
5214 if revs and change:
5222 if revs and change:
5215 msg = _('cannot specify --rev and --change at the same time')
5223 msg = _('cannot specify --rev and --change at the same time')
5216 raise error.Abort(msg)
5224 raise error.Abort(msg)
5217 elif revs and terse:
5225 elif revs and terse:
5218 msg = _('cannot use --terse with --rev')
5226 msg = _('cannot use --terse with --rev')
5219 raise error.Abort(msg)
5227 raise error.Abort(msg)
5220 elif change:
5228 elif change:
5221 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5229 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5222 ctx2 = scmutil.revsingle(repo, change, None)
5230 ctx2 = scmutil.revsingle(repo, change, None)
5223 ctx1 = ctx2.p1()
5231 ctx1 = ctx2.p1()
5224 else:
5232 else:
5225 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5233 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5226 ctx1, ctx2 = scmutil.revpair(repo, revs)
5234 ctx1, ctx2 = scmutil.revpair(repo, revs)
5227
5235
5228 if pats or ui.configbool('commands', 'status.relative'):
5236 if pats or ui.configbool('commands', 'status.relative'):
5229 cwd = repo.getcwd()
5237 cwd = repo.getcwd()
5230 else:
5238 else:
5231 cwd = ''
5239 cwd = ''
5232
5240
5233 if opts.get('print0'):
5241 if opts.get('print0'):
5234 end = '\0'
5242 end = '\0'
5235 else:
5243 else:
5236 end = '\n'
5244 end = '\n'
5237 copy = {}
5245 copy = {}
5238 states = 'modified added removed deleted unknown ignored clean'.split()
5246 states = 'modified added removed deleted unknown ignored clean'.split()
5239 show = [k for k in states if opts.get(k)]
5247 show = [k for k in states if opts.get(k)]
5240 if opts.get('all'):
5248 if opts.get('all'):
5241 show += ui.quiet and (states[:4] + ['clean']) or states
5249 show += ui.quiet and (states[:4] + ['clean']) or states
5242
5250
5243 if not show:
5251 if not show:
5244 if ui.quiet:
5252 if ui.quiet:
5245 show = states[:4]
5253 show = states[:4]
5246 else:
5254 else:
5247 show = states[:5]
5255 show = states[:5]
5248
5256
5249 m = scmutil.match(ctx2, pats, opts)
5257 m = scmutil.match(ctx2, pats, opts)
5250 if terse:
5258 if terse:
5251 # we need to compute clean and unknown to terse
5259 # we need to compute clean and unknown to terse
5252 stat = repo.status(ctx1.node(), ctx2.node(), m,
5260 stat = repo.status(ctx1.node(), ctx2.node(), m,
5253 'ignored' in show or 'i' in terse,
5261 'ignored' in show or 'i' in terse,
5254 clean=True, unknown=True,
5262 clean=True, unknown=True,
5255 listsubrepos=opts.get('subrepos'))
5263 listsubrepos=opts.get('subrepos'))
5256
5264
5257 stat = cmdutil.tersedir(stat, terse)
5265 stat = cmdutil.tersedir(stat, terse)
5258 else:
5266 else:
5259 stat = repo.status(ctx1.node(), ctx2.node(), m,
5267 stat = repo.status(ctx1.node(), ctx2.node(), m,
5260 'ignored' in show, 'clean' in show,
5268 'ignored' in show, 'clean' in show,
5261 'unknown' in show, opts.get('subrepos'))
5269 'unknown' in show, opts.get('subrepos'))
5262
5270
5263 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5271 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5264
5272
5265 if (opts.get('all') or opts.get('copies')
5273 if (opts.get('all') or opts.get('copies')
5266 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5274 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5267 copy = copies.pathcopies(ctx1, ctx2, m)
5275 copy = copies.pathcopies(ctx1, ctx2, m)
5268
5276
5269 ui.pager('status')
5277 ui.pager('status')
5270 fm = ui.formatter('status', opts)
5278 fm = ui.formatter('status', opts)
5271 fmt = '%s' + end
5279 fmt = '%s' + end
5272 showchar = not opts.get('no_status')
5280 showchar = not opts.get('no_status')
5273
5281
5274 for state, char, files in changestates:
5282 for state, char, files in changestates:
5275 if state in show:
5283 if state in show:
5276 label = 'status.' + state
5284 label = 'status.' + state
5277 for f in files:
5285 for f in files:
5278 fm.startitem()
5286 fm.startitem()
5279 fm.context(ctx=ctx2)
5287 fm.context(ctx=ctx2)
5280 fm.data(path=f)
5288 fm.data(path=f)
5281 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5289 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5282 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5290 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5283 if f in copy:
5291 if f in copy:
5284 fm.data(source=copy[f])
5292 fm.data(source=copy[f])
5285 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5293 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5286 label='status.copied')
5294 label='status.copied')
5287
5295
5288 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5296 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5289 and not ui.plain()):
5297 and not ui.plain()):
5290 cmdutil.morestatus(repo, fm)
5298 cmdutil.morestatus(repo, fm)
5291 fm.end()
5299 fm.end()
5292
5300
5293 @command('^summary|sum',
5301 @command('^summary|sum',
5294 [('', 'remote', None, _('check for push and pull'))],
5302 [('', 'remote', None, _('check for push and pull'))],
5295 '[--remote]',
5303 '[--remote]',
5296 intents={INTENT_READONLY})
5304 intents={INTENT_READONLY})
5297 def summary(ui, repo, **opts):
5305 def summary(ui, repo, **opts):
5298 """summarize working directory state
5306 """summarize working directory state
5299
5307
5300 This generates a brief summary of the working directory state,
5308 This generates a brief summary of the working directory state,
5301 including parents, branch, commit status, phase and available updates.
5309 including parents, branch, commit status, phase and available updates.
5302
5310
5303 With the --remote option, this will check the default paths for
5311 With the --remote option, this will check the default paths for
5304 incoming and outgoing changes. This can be time-consuming.
5312 incoming and outgoing changes. This can be time-consuming.
5305
5313
5306 Returns 0 on success.
5314 Returns 0 on success.
5307 """
5315 """
5308
5316
5309 opts = pycompat.byteskwargs(opts)
5317 opts = pycompat.byteskwargs(opts)
5310 ui.pager('summary')
5318 ui.pager('summary')
5311 ctx = repo[None]
5319 ctx = repo[None]
5312 parents = ctx.parents()
5320 parents = ctx.parents()
5313 pnode = parents[0].node()
5321 pnode = parents[0].node()
5314 marks = []
5322 marks = []
5315
5323
5316 ms = None
5324 ms = None
5317 try:
5325 try:
5318 ms = mergemod.mergestate.read(repo)
5326 ms = mergemod.mergestate.read(repo)
5319 except error.UnsupportedMergeRecords as e:
5327 except error.UnsupportedMergeRecords as e:
5320 s = ' '.join(e.recordtypes)
5328 s = ' '.join(e.recordtypes)
5321 ui.warn(
5329 ui.warn(
5322 _('warning: merge state has unsupported record types: %s\n') % s)
5330 _('warning: merge state has unsupported record types: %s\n') % s)
5323 unresolved = []
5331 unresolved = []
5324 else:
5332 else:
5325 unresolved = list(ms.unresolved())
5333 unresolved = list(ms.unresolved())
5326
5334
5327 for p in parents:
5335 for p in parents:
5328 # label with log.changeset (instead of log.parent) since this
5336 # label with log.changeset (instead of log.parent) since this
5329 # shows a working directory parent *changeset*:
5337 # shows a working directory parent *changeset*:
5330 # i18n: column positioning for "hg summary"
5338 # i18n: column positioning for "hg summary"
5331 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5339 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5332 label=logcmdutil.changesetlabels(p))
5340 label=logcmdutil.changesetlabels(p))
5333 ui.write(' '.join(p.tags()), label='log.tag')
5341 ui.write(' '.join(p.tags()), label='log.tag')
5334 if p.bookmarks():
5342 if p.bookmarks():
5335 marks.extend(p.bookmarks())
5343 marks.extend(p.bookmarks())
5336 if p.rev() == -1:
5344 if p.rev() == -1:
5337 if not len(repo):
5345 if not len(repo):
5338 ui.write(_(' (empty repository)'))
5346 ui.write(_(' (empty repository)'))
5339 else:
5347 else:
5340 ui.write(_(' (no revision checked out)'))
5348 ui.write(_(' (no revision checked out)'))
5341 if p.obsolete():
5349 if p.obsolete():
5342 ui.write(_(' (obsolete)'))
5350 ui.write(_(' (obsolete)'))
5343 if p.isunstable():
5351 if p.isunstable():
5344 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5352 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5345 for instability in p.instabilities())
5353 for instability in p.instabilities())
5346 ui.write(' ('
5354 ui.write(' ('
5347 + ', '.join(instabilities)
5355 + ', '.join(instabilities)
5348 + ')')
5356 + ')')
5349 ui.write('\n')
5357 ui.write('\n')
5350 if p.description():
5358 if p.description():
5351 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5359 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5352 label='log.summary')
5360 label='log.summary')
5353
5361
5354 branch = ctx.branch()
5362 branch = ctx.branch()
5355 bheads = repo.branchheads(branch)
5363 bheads = repo.branchheads(branch)
5356 # i18n: column positioning for "hg summary"
5364 # i18n: column positioning for "hg summary"
5357 m = _('branch: %s\n') % branch
5365 m = _('branch: %s\n') % branch
5358 if branch != 'default':
5366 if branch != 'default':
5359 ui.write(m, label='log.branch')
5367 ui.write(m, label='log.branch')
5360 else:
5368 else:
5361 ui.status(m, label='log.branch')
5369 ui.status(m, label='log.branch')
5362
5370
5363 if marks:
5371 if marks:
5364 active = repo._activebookmark
5372 active = repo._activebookmark
5365 # i18n: column positioning for "hg summary"
5373 # i18n: column positioning for "hg summary"
5366 ui.write(_('bookmarks:'), label='log.bookmark')
5374 ui.write(_('bookmarks:'), label='log.bookmark')
5367 if active is not None:
5375 if active is not None:
5368 if active in marks:
5376 if active in marks:
5369 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5377 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5370 marks.remove(active)
5378 marks.remove(active)
5371 else:
5379 else:
5372 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5380 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5373 for m in marks:
5381 for m in marks:
5374 ui.write(' ' + m, label='log.bookmark')
5382 ui.write(' ' + m, label='log.bookmark')
5375 ui.write('\n', label='log.bookmark')
5383 ui.write('\n', label='log.bookmark')
5376
5384
5377 status = repo.status(unknown=True)
5385 status = repo.status(unknown=True)
5378
5386
5379 c = repo.dirstate.copies()
5387 c = repo.dirstate.copies()
5380 copied, renamed = [], []
5388 copied, renamed = [], []
5381 for d, s in c.iteritems():
5389 for d, s in c.iteritems():
5382 if s in status.removed:
5390 if s in status.removed:
5383 status.removed.remove(s)
5391 status.removed.remove(s)
5384 renamed.append(d)
5392 renamed.append(d)
5385 else:
5393 else:
5386 copied.append(d)
5394 copied.append(d)
5387 if d in status.added:
5395 if d in status.added:
5388 status.added.remove(d)
5396 status.added.remove(d)
5389
5397
5390 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5398 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5391
5399
5392 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5400 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5393 (ui.label(_('%d added'), 'status.added'), status.added),
5401 (ui.label(_('%d added'), 'status.added'), status.added),
5394 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5402 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5395 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5403 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5396 (ui.label(_('%d copied'), 'status.copied'), copied),
5404 (ui.label(_('%d copied'), 'status.copied'), copied),
5397 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5405 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5398 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5406 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5399 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5407 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5400 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5408 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5401 t = []
5409 t = []
5402 for l, s in labels:
5410 for l, s in labels:
5403 if s:
5411 if s:
5404 t.append(l % len(s))
5412 t.append(l % len(s))
5405
5413
5406 t = ', '.join(t)
5414 t = ', '.join(t)
5407 cleanworkdir = False
5415 cleanworkdir = False
5408
5416
5409 if repo.vfs.exists('graftstate'):
5417 if repo.vfs.exists('graftstate'):
5410 t += _(' (graft in progress)')
5418 t += _(' (graft in progress)')
5411 if repo.vfs.exists('updatestate'):
5419 if repo.vfs.exists('updatestate'):
5412 t += _(' (interrupted update)')
5420 t += _(' (interrupted update)')
5413 elif len(parents) > 1:
5421 elif len(parents) > 1:
5414 t += _(' (merge)')
5422 t += _(' (merge)')
5415 elif branch != parents[0].branch():
5423 elif branch != parents[0].branch():
5416 t += _(' (new branch)')
5424 t += _(' (new branch)')
5417 elif (parents[0].closesbranch() and
5425 elif (parents[0].closesbranch() and
5418 pnode in repo.branchheads(branch, closed=True)):
5426 pnode in repo.branchheads(branch, closed=True)):
5419 t += _(' (head closed)')
5427 t += _(' (head closed)')
5420 elif not (status.modified or status.added or status.removed or renamed or
5428 elif not (status.modified or status.added or status.removed or renamed or
5421 copied or subs):
5429 copied or subs):
5422 t += _(' (clean)')
5430 t += _(' (clean)')
5423 cleanworkdir = True
5431 cleanworkdir = True
5424 elif pnode not in bheads:
5432 elif pnode not in bheads:
5425 t += _(' (new branch head)')
5433 t += _(' (new branch head)')
5426
5434
5427 if parents:
5435 if parents:
5428 pendingphase = max(p.phase() for p in parents)
5436 pendingphase = max(p.phase() for p in parents)
5429 else:
5437 else:
5430 pendingphase = phases.public
5438 pendingphase = phases.public
5431
5439
5432 if pendingphase > phases.newcommitphase(ui):
5440 if pendingphase > phases.newcommitphase(ui):
5433 t += ' (%s)' % phases.phasenames[pendingphase]
5441 t += ' (%s)' % phases.phasenames[pendingphase]
5434
5442
5435 if cleanworkdir:
5443 if cleanworkdir:
5436 # i18n: column positioning for "hg summary"
5444 # i18n: column positioning for "hg summary"
5437 ui.status(_('commit: %s\n') % t.strip())
5445 ui.status(_('commit: %s\n') % t.strip())
5438 else:
5446 else:
5439 # i18n: column positioning for "hg summary"
5447 # i18n: column positioning for "hg summary"
5440 ui.write(_('commit: %s\n') % t.strip())
5448 ui.write(_('commit: %s\n') % t.strip())
5441
5449
5442 # all ancestors of branch heads - all ancestors of parent = new csets
5450 # all ancestors of branch heads - all ancestors of parent = new csets
5443 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5451 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5444 bheads))
5452 bheads))
5445
5453
5446 if new == 0:
5454 if new == 0:
5447 # i18n: column positioning for "hg summary"
5455 # i18n: column positioning for "hg summary"
5448 ui.status(_('update: (current)\n'))
5456 ui.status(_('update: (current)\n'))
5449 elif pnode not in bheads:
5457 elif pnode not in bheads:
5450 # i18n: column positioning for "hg summary"
5458 # i18n: column positioning for "hg summary"
5451 ui.write(_('update: %d new changesets (update)\n') % new)
5459 ui.write(_('update: %d new changesets (update)\n') % new)
5452 else:
5460 else:
5453 # i18n: column positioning for "hg summary"
5461 # i18n: column positioning for "hg summary"
5454 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5462 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5455 (new, len(bheads)))
5463 (new, len(bheads)))
5456
5464
5457 t = []
5465 t = []
5458 draft = len(repo.revs('draft()'))
5466 draft = len(repo.revs('draft()'))
5459 if draft:
5467 if draft:
5460 t.append(_('%d draft') % draft)
5468 t.append(_('%d draft') % draft)
5461 secret = len(repo.revs('secret()'))
5469 secret = len(repo.revs('secret()'))
5462 if secret:
5470 if secret:
5463 t.append(_('%d secret') % secret)
5471 t.append(_('%d secret') % secret)
5464
5472
5465 if draft or secret:
5473 if draft or secret:
5466 ui.status(_('phases: %s\n') % ', '.join(t))
5474 ui.status(_('phases: %s\n') % ', '.join(t))
5467
5475
5468 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5476 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5469 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5477 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5470 numtrouble = len(repo.revs(trouble + "()"))
5478 numtrouble = len(repo.revs(trouble + "()"))
5471 # We write all the possibilities to ease translation
5479 # We write all the possibilities to ease translation
5472 troublemsg = {
5480 troublemsg = {
5473 "orphan": _("orphan: %d changesets"),
5481 "orphan": _("orphan: %d changesets"),
5474 "contentdivergent": _("content-divergent: %d changesets"),
5482 "contentdivergent": _("content-divergent: %d changesets"),
5475 "phasedivergent": _("phase-divergent: %d changesets"),
5483 "phasedivergent": _("phase-divergent: %d changesets"),
5476 }
5484 }
5477 if numtrouble > 0:
5485 if numtrouble > 0:
5478 ui.status(troublemsg[trouble] % numtrouble + "\n")
5486 ui.status(troublemsg[trouble] % numtrouble + "\n")
5479
5487
5480 cmdutil.summaryhooks(ui, repo)
5488 cmdutil.summaryhooks(ui, repo)
5481
5489
5482 if opts.get('remote'):
5490 if opts.get('remote'):
5483 needsincoming, needsoutgoing = True, True
5491 needsincoming, needsoutgoing = True, True
5484 else:
5492 else:
5485 needsincoming, needsoutgoing = False, False
5493 needsincoming, needsoutgoing = False, False
5486 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5494 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5487 if i:
5495 if i:
5488 needsincoming = True
5496 needsincoming = True
5489 if o:
5497 if o:
5490 needsoutgoing = True
5498 needsoutgoing = True
5491 if not needsincoming and not needsoutgoing:
5499 if not needsincoming and not needsoutgoing:
5492 return
5500 return
5493
5501
5494 def getincoming():
5502 def getincoming():
5495 source, branches = hg.parseurl(ui.expandpath('default'))
5503 source, branches = hg.parseurl(ui.expandpath('default'))
5496 sbranch = branches[0]
5504 sbranch = branches[0]
5497 try:
5505 try:
5498 other = hg.peer(repo, {}, source)
5506 other = hg.peer(repo, {}, source)
5499 except error.RepoError:
5507 except error.RepoError:
5500 if opts.get('remote'):
5508 if opts.get('remote'):
5501 raise
5509 raise
5502 return source, sbranch, None, None, None
5510 return source, sbranch, None, None, None
5503 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5511 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5504 if revs:
5512 if revs:
5505 revs = [other.lookup(rev) for rev in revs]
5513 revs = [other.lookup(rev) for rev in revs]
5506 ui.debug('comparing with %s\n' % util.hidepassword(source))
5514 ui.debug('comparing with %s\n' % util.hidepassword(source))
5507 repo.ui.pushbuffer()
5515 repo.ui.pushbuffer()
5508 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5516 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5509 repo.ui.popbuffer()
5517 repo.ui.popbuffer()
5510 return source, sbranch, other, commoninc, commoninc[1]
5518 return source, sbranch, other, commoninc, commoninc[1]
5511
5519
5512 if needsincoming:
5520 if needsincoming:
5513 source, sbranch, sother, commoninc, incoming = getincoming()
5521 source, sbranch, sother, commoninc, incoming = getincoming()
5514 else:
5522 else:
5515 source = sbranch = sother = commoninc = incoming = None
5523 source = sbranch = sother = commoninc = incoming = None
5516
5524
5517 def getoutgoing():
5525 def getoutgoing():
5518 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5526 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5519 dbranch = branches[0]
5527 dbranch = branches[0]
5520 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5528 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5521 if source != dest:
5529 if source != dest:
5522 try:
5530 try:
5523 dother = hg.peer(repo, {}, dest)
5531 dother = hg.peer(repo, {}, dest)
5524 except error.RepoError:
5532 except error.RepoError:
5525 if opts.get('remote'):
5533 if opts.get('remote'):
5526 raise
5534 raise
5527 return dest, dbranch, None, None
5535 return dest, dbranch, None, None
5528 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5536 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5529 elif sother is None:
5537 elif sother is None:
5530 # there is no explicit destination peer, but source one is invalid
5538 # there is no explicit destination peer, but source one is invalid
5531 return dest, dbranch, None, None
5539 return dest, dbranch, None, None
5532 else:
5540 else:
5533 dother = sother
5541 dother = sother
5534 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5542 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5535 common = None
5543 common = None
5536 else:
5544 else:
5537 common = commoninc
5545 common = commoninc
5538 if revs:
5546 if revs:
5539 revs = [repo.lookup(rev) for rev in revs]
5547 revs = [repo.lookup(rev) for rev in revs]
5540 repo.ui.pushbuffer()
5548 repo.ui.pushbuffer()
5541 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5549 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5542 commoninc=common)
5550 commoninc=common)
5543 repo.ui.popbuffer()
5551 repo.ui.popbuffer()
5544 return dest, dbranch, dother, outgoing
5552 return dest, dbranch, dother, outgoing
5545
5553
5546 if needsoutgoing:
5554 if needsoutgoing:
5547 dest, dbranch, dother, outgoing = getoutgoing()
5555 dest, dbranch, dother, outgoing = getoutgoing()
5548 else:
5556 else:
5549 dest = dbranch = dother = outgoing = None
5557 dest = dbranch = dother = outgoing = None
5550
5558
5551 if opts.get('remote'):
5559 if opts.get('remote'):
5552 t = []
5560 t = []
5553 if incoming:
5561 if incoming:
5554 t.append(_('1 or more incoming'))
5562 t.append(_('1 or more incoming'))
5555 o = outgoing.missing
5563 o = outgoing.missing
5556 if o:
5564 if o:
5557 t.append(_('%d outgoing') % len(o))
5565 t.append(_('%d outgoing') % len(o))
5558 other = dother or sother
5566 other = dother or sother
5559 if 'bookmarks' in other.listkeys('namespaces'):
5567 if 'bookmarks' in other.listkeys('namespaces'):
5560 counts = bookmarks.summary(repo, other)
5568 counts = bookmarks.summary(repo, other)
5561 if counts[0] > 0:
5569 if counts[0] > 0:
5562 t.append(_('%d incoming bookmarks') % counts[0])
5570 t.append(_('%d incoming bookmarks') % counts[0])
5563 if counts[1] > 0:
5571 if counts[1] > 0:
5564 t.append(_('%d outgoing bookmarks') % counts[1])
5572 t.append(_('%d outgoing bookmarks') % counts[1])
5565
5573
5566 if t:
5574 if t:
5567 # i18n: column positioning for "hg summary"
5575 # i18n: column positioning for "hg summary"
5568 ui.write(_('remote: %s\n') % (', '.join(t)))
5576 ui.write(_('remote: %s\n') % (', '.join(t)))
5569 else:
5577 else:
5570 # i18n: column positioning for "hg summary"
5578 # i18n: column positioning for "hg summary"
5571 ui.status(_('remote: (synced)\n'))
5579 ui.status(_('remote: (synced)\n'))
5572
5580
5573 cmdutil.summaryremotehooks(ui, repo, opts,
5581 cmdutil.summaryremotehooks(ui, repo, opts,
5574 ((source, sbranch, sother, commoninc),
5582 ((source, sbranch, sother, commoninc),
5575 (dest, dbranch, dother, outgoing)))
5583 (dest, dbranch, dother, outgoing)))
5576
5584
5577 @command('tag',
5585 @command('tag',
5578 [('f', 'force', None, _('force tag')),
5586 [('f', 'force', None, _('force tag')),
5579 ('l', 'local', None, _('make the tag local')),
5587 ('l', 'local', None, _('make the tag local')),
5580 ('r', 'rev', '', _('revision to tag'), _('REV')),
5588 ('r', 'rev', '', _('revision to tag'), _('REV')),
5581 ('', 'remove', None, _('remove a tag')),
5589 ('', 'remove', None, _('remove a tag')),
5582 # -l/--local is already there, commitopts cannot be used
5590 # -l/--local is already there, commitopts cannot be used
5583 ('e', 'edit', None, _('invoke editor on commit messages')),
5591 ('e', 'edit', None, _('invoke editor on commit messages')),
5584 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5592 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5585 ] + commitopts2,
5593 ] + commitopts2,
5586 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5594 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5587 def tag(ui, repo, name1, *names, **opts):
5595 def tag(ui, repo, name1, *names, **opts):
5588 """add one or more tags for the current or given revision
5596 """add one or more tags for the current or given revision
5589
5597
5590 Name a particular revision using <name>.
5598 Name a particular revision using <name>.
5591
5599
5592 Tags are used to name particular revisions of the repository and are
5600 Tags are used to name particular revisions of the repository and are
5593 very useful to compare different revisions, to go back to significant
5601 very useful to compare different revisions, to go back to significant
5594 earlier versions or to mark branch points as releases, etc. Changing
5602 earlier versions or to mark branch points as releases, etc. Changing
5595 an existing tag is normally disallowed; use -f/--force to override.
5603 an existing tag is normally disallowed; use -f/--force to override.
5596
5604
5597 If no revision is given, the parent of the working directory is
5605 If no revision is given, the parent of the working directory is
5598 used.
5606 used.
5599
5607
5600 To facilitate version control, distribution, and merging of tags,
5608 To facilitate version control, distribution, and merging of tags,
5601 they are stored as a file named ".hgtags" which is managed similarly
5609 they are stored as a file named ".hgtags" which is managed similarly
5602 to other project files and can be hand-edited if necessary. This
5610 to other project files and can be hand-edited if necessary. This
5603 also means that tagging creates a new commit. The file
5611 also means that tagging creates a new commit. The file
5604 ".hg/localtags" is used for local tags (not shared among
5612 ".hg/localtags" is used for local tags (not shared among
5605 repositories).
5613 repositories).
5606
5614
5607 Tag commits are usually made at the head of a branch. If the parent
5615 Tag commits are usually made at the head of a branch. If the parent
5608 of the working directory is not a branch head, :hg:`tag` aborts; use
5616 of the working directory is not a branch head, :hg:`tag` aborts; use
5609 -f/--force to force the tag commit to be based on a non-head
5617 -f/--force to force the tag commit to be based on a non-head
5610 changeset.
5618 changeset.
5611
5619
5612 See :hg:`help dates` for a list of formats valid for -d/--date.
5620 See :hg:`help dates` for a list of formats valid for -d/--date.
5613
5621
5614 Since tag names have priority over branch names during revision
5622 Since tag names have priority over branch names during revision
5615 lookup, using an existing branch name as a tag name is discouraged.
5623 lookup, using an existing branch name as a tag name is discouraged.
5616
5624
5617 Returns 0 on success.
5625 Returns 0 on success.
5618 """
5626 """
5619 opts = pycompat.byteskwargs(opts)
5627 opts = pycompat.byteskwargs(opts)
5620 with repo.wlock(), repo.lock():
5628 with repo.wlock(), repo.lock():
5621 rev_ = "."
5629 rev_ = "."
5622 names = [t.strip() for t in (name1,) + names]
5630 names = [t.strip() for t in (name1,) + names]
5623 if len(names) != len(set(names)):
5631 if len(names) != len(set(names)):
5624 raise error.Abort(_('tag names must be unique'))
5632 raise error.Abort(_('tag names must be unique'))
5625 for n in names:
5633 for n in names:
5626 scmutil.checknewlabel(repo, n, 'tag')
5634 scmutil.checknewlabel(repo, n, 'tag')
5627 if not n:
5635 if not n:
5628 raise error.Abort(_('tag names cannot consist entirely of '
5636 raise error.Abort(_('tag names cannot consist entirely of '
5629 'whitespace'))
5637 'whitespace'))
5630 if opts.get('rev') and opts.get('remove'):
5638 if opts.get('rev') and opts.get('remove'):
5631 raise error.Abort(_("--rev and --remove are incompatible"))
5639 raise error.Abort(_("--rev and --remove are incompatible"))
5632 if opts.get('rev'):
5640 if opts.get('rev'):
5633 rev_ = opts['rev']
5641 rev_ = opts['rev']
5634 message = opts.get('message')
5642 message = opts.get('message')
5635 if opts.get('remove'):
5643 if opts.get('remove'):
5636 if opts.get('local'):
5644 if opts.get('local'):
5637 expectedtype = 'local'
5645 expectedtype = 'local'
5638 else:
5646 else:
5639 expectedtype = 'global'
5647 expectedtype = 'global'
5640
5648
5641 for n in names:
5649 for n in names:
5642 if not repo.tagtype(n):
5650 if not repo.tagtype(n):
5643 raise error.Abort(_("tag '%s' does not exist") % n)
5651 raise error.Abort(_("tag '%s' does not exist") % n)
5644 if repo.tagtype(n) != expectedtype:
5652 if repo.tagtype(n) != expectedtype:
5645 if expectedtype == 'global':
5653 if expectedtype == 'global':
5646 raise error.Abort(_("tag '%s' is not a global tag") % n)
5654 raise error.Abort(_("tag '%s' is not a global tag") % n)
5647 else:
5655 else:
5648 raise error.Abort(_("tag '%s' is not a local tag") % n)
5656 raise error.Abort(_("tag '%s' is not a local tag") % n)
5649 rev_ = 'null'
5657 rev_ = 'null'
5650 if not message:
5658 if not message:
5651 # we don't translate commit messages
5659 # we don't translate commit messages
5652 message = 'Removed tag %s' % ', '.join(names)
5660 message = 'Removed tag %s' % ', '.join(names)
5653 elif not opts.get('force'):
5661 elif not opts.get('force'):
5654 for n in names:
5662 for n in names:
5655 if n in repo.tags():
5663 if n in repo.tags():
5656 raise error.Abort(_("tag '%s' already exists "
5664 raise error.Abort(_("tag '%s' already exists "
5657 "(use -f to force)") % n)
5665 "(use -f to force)") % n)
5658 if not opts.get('local'):
5666 if not opts.get('local'):
5659 p1, p2 = repo.dirstate.parents()
5667 p1, p2 = repo.dirstate.parents()
5660 if p2 != nullid:
5668 if p2 != nullid:
5661 raise error.Abort(_('uncommitted merge'))
5669 raise error.Abort(_('uncommitted merge'))
5662 bheads = repo.branchheads()
5670 bheads = repo.branchheads()
5663 if not opts.get('force') and bheads and p1 not in bheads:
5671 if not opts.get('force') and bheads and p1 not in bheads:
5664 raise error.Abort(_('working directory is not at a branch head '
5672 raise error.Abort(_('working directory is not at a branch head '
5665 '(use -f to force)'))
5673 '(use -f to force)'))
5666 node = scmutil.revsingle(repo, rev_).node()
5674 node = scmutil.revsingle(repo, rev_).node()
5667
5675
5668 if not message:
5676 if not message:
5669 # we don't translate commit messages
5677 # we don't translate commit messages
5670 message = ('Added tag %s for changeset %s' %
5678 message = ('Added tag %s for changeset %s' %
5671 (', '.join(names), short(node)))
5679 (', '.join(names), short(node)))
5672
5680
5673 date = opts.get('date')
5681 date = opts.get('date')
5674 if date:
5682 if date:
5675 date = dateutil.parsedate(date)
5683 date = dateutil.parsedate(date)
5676
5684
5677 if opts.get('remove'):
5685 if opts.get('remove'):
5678 editform = 'tag.remove'
5686 editform = 'tag.remove'
5679 else:
5687 else:
5680 editform = 'tag.add'
5688 editform = 'tag.add'
5681 editor = cmdutil.getcommiteditor(editform=editform,
5689 editor = cmdutil.getcommiteditor(editform=editform,
5682 **pycompat.strkwargs(opts))
5690 **pycompat.strkwargs(opts))
5683
5691
5684 # don't allow tagging the null rev
5692 # don't allow tagging the null rev
5685 if (not opts.get('remove') and
5693 if (not opts.get('remove') and
5686 scmutil.revsingle(repo, rev_).rev() == nullrev):
5694 scmutil.revsingle(repo, rev_).rev() == nullrev):
5687 raise error.Abort(_("cannot tag null revision"))
5695 raise error.Abort(_("cannot tag null revision"))
5688
5696
5689 tagsmod.tag(repo, names, node, message, opts.get('local'),
5697 tagsmod.tag(repo, names, node, message, opts.get('local'),
5690 opts.get('user'), date, editor=editor)
5698 opts.get('user'), date, editor=editor)
5691
5699
5692 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5700 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5693 def tags(ui, repo, **opts):
5701 def tags(ui, repo, **opts):
5694 """list repository tags
5702 """list repository tags
5695
5703
5696 This lists both regular and local tags. When the -v/--verbose
5704 This lists both regular and local tags. When the -v/--verbose
5697 switch is used, a third column "local" is printed for local tags.
5705 switch is used, a third column "local" is printed for local tags.
5698 When the -q/--quiet switch is used, only the tag name is printed.
5706 When the -q/--quiet switch is used, only the tag name is printed.
5699
5707
5700 Returns 0 on success.
5708 Returns 0 on success.
5701 """
5709 """
5702
5710
5703 opts = pycompat.byteskwargs(opts)
5711 opts = pycompat.byteskwargs(opts)
5704 ui.pager('tags')
5712 ui.pager('tags')
5705 fm = ui.formatter('tags', opts)
5713 fm = ui.formatter('tags', opts)
5706 hexfunc = fm.hexfunc
5714 hexfunc = fm.hexfunc
5707 tagtype = ""
5715 tagtype = ""
5708
5716
5709 for t, n in reversed(repo.tagslist()):
5717 for t, n in reversed(repo.tagslist()):
5710 hn = hexfunc(n)
5718 hn = hexfunc(n)
5711 label = 'tags.normal'
5719 label = 'tags.normal'
5712 tagtype = ''
5720 tagtype = ''
5713 if repo.tagtype(t) == 'local':
5721 if repo.tagtype(t) == 'local':
5714 label = 'tags.local'
5722 label = 'tags.local'
5715 tagtype = 'local'
5723 tagtype = 'local'
5716
5724
5717 fm.startitem()
5725 fm.startitem()
5718 fm.context(repo=repo)
5726 fm.context(repo=repo)
5719 fm.write('tag', '%s', t, label=label)
5727 fm.write('tag', '%s', t, label=label)
5720 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5728 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5721 fm.condwrite(not ui.quiet, 'rev node', fmt,
5729 fm.condwrite(not ui.quiet, 'rev node', fmt,
5722 repo.changelog.rev(n), hn, label=label)
5730 repo.changelog.rev(n), hn, label=label)
5723 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5731 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5724 tagtype, label=label)
5732 tagtype, label=label)
5725 fm.plain('\n')
5733 fm.plain('\n')
5726 fm.end()
5734 fm.end()
5727
5735
5728 @command('tip',
5736 @command('tip',
5729 [('p', 'patch', None, _('show patch')),
5737 [('p', 'patch', None, _('show patch')),
5730 ('g', 'git', None, _('use git extended diff format')),
5738 ('g', 'git', None, _('use git extended diff format')),
5731 ] + templateopts,
5739 ] + templateopts,
5732 _('[-p] [-g]'))
5740 _('[-p] [-g]'))
5733 def tip(ui, repo, **opts):
5741 def tip(ui, repo, **opts):
5734 """show the tip revision (DEPRECATED)
5742 """show the tip revision (DEPRECATED)
5735
5743
5736 The tip revision (usually just called the tip) is the changeset
5744 The tip revision (usually just called the tip) is the changeset
5737 most recently added to the repository (and therefore the most
5745 most recently added to the repository (and therefore the most
5738 recently changed head).
5746 recently changed head).
5739
5747
5740 If you have just made a commit, that commit will be the tip. If
5748 If you have just made a commit, that commit will be the tip. If
5741 you have just pulled changes from another repository, the tip of
5749 you have just pulled changes from another repository, the tip of
5742 that repository becomes the current tip. The "tip" tag is special
5750 that repository becomes the current tip. The "tip" tag is special
5743 and cannot be renamed or assigned to a different changeset.
5751 and cannot be renamed or assigned to a different changeset.
5744
5752
5745 This command is deprecated, please use :hg:`heads` instead.
5753 This command is deprecated, please use :hg:`heads` instead.
5746
5754
5747 Returns 0 on success.
5755 Returns 0 on success.
5748 """
5756 """
5749 opts = pycompat.byteskwargs(opts)
5757 opts = pycompat.byteskwargs(opts)
5750 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5758 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5751 displayer.show(repo['tip'])
5759 displayer.show(repo['tip'])
5752 displayer.close()
5760 displayer.close()
5753
5761
5754 @command('unbundle',
5762 @command('unbundle',
5755 [('u', 'update', None,
5763 [('u', 'update', None,
5756 _('update to new branch head if changesets were unbundled'))],
5764 _('update to new branch head if changesets were unbundled'))],
5757 _('[-u] FILE...'))
5765 _('[-u] FILE...'))
5758 def unbundle(ui, repo, fname1, *fnames, **opts):
5766 def unbundle(ui, repo, fname1, *fnames, **opts):
5759 """apply one or more bundle files
5767 """apply one or more bundle files
5760
5768
5761 Apply one or more bundle files generated by :hg:`bundle`.
5769 Apply one or more bundle files generated by :hg:`bundle`.
5762
5770
5763 Returns 0 on success, 1 if an update has unresolved files.
5771 Returns 0 on success, 1 if an update has unresolved files.
5764 """
5772 """
5765 fnames = (fname1,) + fnames
5773 fnames = (fname1,) + fnames
5766
5774
5767 with repo.lock():
5775 with repo.lock():
5768 for fname in fnames:
5776 for fname in fnames:
5769 f = hg.openpath(ui, fname)
5777 f = hg.openpath(ui, fname)
5770 gen = exchange.readbundle(ui, f, fname)
5778 gen = exchange.readbundle(ui, f, fname)
5771 if isinstance(gen, streamclone.streamcloneapplier):
5779 if isinstance(gen, streamclone.streamcloneapplier):
5772 raise error.Abort(
5780 raise error.Abort(
5773 _('packed bundles cannot be applied with '
5781 _('packed bundles cannot be applied with '
5774 '"hg unbundle"'),
5782 '"hg unbundle"'),
5775 hint=_('use "hg debugapplystreamclonebundle"'))
5783 hint=_('use "hg debugapplystreamclonebundle"'))
5776 url = 'bundle:' + fname
5784 url = 'bundle:' + fname
5777 try:
5785 try:
5778 txnname = 'unbundle'
5786 txnname = 'unbundle'
5779 if not isinstance(gen, bundle2.unbundle20):
5787 if not isinstance(gen, bundle2.unbundle20):
5780 txnname = 'unbundle\n%s' % util.hidepassword(url)
5788 txnname = 'unbundle\n%s' % util.hidepassword(url)
5781 with repo.transaction(txnname) as tr:
5789 with repo.transaction(txnname) as tr:
5782 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5790 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5783 url=url)
5791 url=url)
5784 except error.BundleUnknownFeatureError as exc:
5792 except error.BundleUnknownFeatureError as exc:
5785 raise error.Abort(
5793 raise error.Abort(
5786 _('%s: unknown bundle feature, %s') % (fname, exc),
5794 _('%s: unknown bundle feature, %s') % (fname, exc),
5787 hint=_("see https://mercurial-scm.org/"
5795 hint=_("see https://mercurial-scm.org/"
5788 "wiki/BundleFeature for more "
5796 "wiki/BundleFeature for more "
5789 "information"))
5797 "information"))
5790 modheads = bundle2.combinechangegroupresults(op)
5798 modheads = bundle2.combinechangegroupresults(op)
5791
5799
5792 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5800 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5793
5801
5794 @command('^update|up|checkout|co',
5802 @command('^update|up|checkout|co',
5795 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5803 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5796 ('c', 'check', None, _('require clean working directory')),
5804 ('c', 'check', None, _('require clean working directory')),
5797 ('m', 'merge', None, _('merge uncommitted changes')),
5805 ('m', 'merge', None, _('merge uncommitted changes')),
5798 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5806 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5799 ('r', 'rev', '', _('revision'), _('REV'))
5807 ('r', 'rev', '', _('revision'), _('REV'))
5800 ] + mergetoolopts,
5808 ] + mergetoolopts,
5801 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5809 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5802 def update(ui, repo, node=None, **opts):
5810 def update(ui, repo, node=None, **opts):
5803 """update working directory (or switch revisions)
5811 """update working directory (or switch revisions)
5804
5812
5805 Update the repository's working directory to the specified
5813 Update the repository's working directory to the specified
5806 changeset. If no changeset is specified, update to the tip of the
5814 changeset. If no changeset is specified, update to the tip of the
5807 current named branch and move the active bookmark (see :hg:`help
5815 current named branch and move the active bookmark (see :hg:`help
5808 bookmarks`).
5816 bookmarks`).
5809
5817
5810 Update sets the working directory's parent revision to the specified
5818 Update sets the working directory's parent revision to the specified
5811 changeset (see :hg:`help parents`).
5819 changeset (see :hg:`help parents`).
5812
5820
5813 If the changeset is not a descendant or ancestor of the working
5821 If the changeset is not a descendant or ancestor of the working
5814 directory's parent and there are uncommitted changes, the update is
5822 directory's parent and there are uncommitted changes, the update is
5815 aborted. With the -c/--check option, the working directory is checked
5823 aborted. With the -c/--check option, the working directory is checked
5816 for uncommitted changes; if none are found, the working directory is
5824 for uncommitted changes; if none are found, the working directory is
5817 updated to the specified changeset.
5825 updated to the specified changeset.
5818
5826
5819 .. container:: verbose
5827 .. container:: verbose
5820
5828
5821 The -C/--clean, -c/--check, and -m/--merge options control what
5829 The -C/--clean, -c/--check, and -m/--merge options control what
5822 happens if the working directory contains uncommitted changes.
5830 happens if the working directory contains uncommitted changes.
5823 At most of one of them can be specified.
5831 At most of one of them can be specified.
5824
5832
5825 1. If no option is specified, and if
5833 1. If no option is specified, and if
5826 the requested changeset is an ancestor or descendant of
5834 the requested changeset is an ancestor or descendant of
5827 the working directory's parent, the uncommitted changes
5835 the working directory's parent, the uncommitted changes
5828 are merged into the requested changeset and the merged
5836 are merged into the requested changeset and the merged
5829 result is left uncommitted. If the requested changeset is
5837 result is left uncommitted. If the requested changeset is
5830 not an ancestor or descendant (that is, it is on another
5838 not an ancestor or descendant (that is, it is on another
5831 branch), the update is aborted and the uncommitted changes
5839 branch), the update is aborted and the uncommitted changes
5832 are preserved.
5840 are preserved.
5833
5841
5834 2. With the -m/--merge option, the update is allowed even if the
5842 2. With the -m/--merge option, the update is allowed even if the
5835 requested changeset is not an ancestor or descendant of
5843 requested changeset is not an ancestor or descendant of
5836 the working directory's parent.
5844 the working directory's parent.
5837
5845
5838 3. With the -c/--check option, the update is aborted and the
5846 3. With the -c/--check option, the update is aborted and the
5839 uncommitted changes are preserved.
5847 uncommitted changes are preserved.
5840
5848
5841 4. With the -C/--clean option, uncommitted changes are discarded and
5849 4. With the -C/--clean option, uncommitted changes are discarded and
5842 the working directory is updated to the requested changeset.
5850 the working directory is updated to the requested changeset.
5843
5851
5844 To cancel an uncommitted merge (and lose your changes), use
5852 To cancel an uncommitted merge (and lose your changes), use
5845 :hg:`merge --abort`.
5853 :hg:`merge --abort`.
5846
5854
5847 Use null as the changeset to remove the working directory (like
5855 Use null as the changeset to remove the working directory (like
5848 :hg:`clone -U`).
5856 :hg:`clone -U`).
5849
5857
5850 If you want to revert just one file to an older revision, use
5858 If you want to revert just one file to an older revision, use
5851 :hg:`revert [-r REV] NAME`.
5859 :hg:`revert [-r REV] NAME`.
5852
5860
5853 See :hg:`help dates` for a list of formats valid for -d/--date.
5861 See :hg:`help dates` for a list of formats valid for -d/--date.
5854
5862
5855 Returns 0 on success, 1 if there are unresolved files.
5863 Returns 0 on success, 1 if there are unresolved files.
5856 """
5864 """
5857 rev = opts.get(r'rev')
5865 rev = opts.get(r'rev')
5858 date = opts.get(r'date')
5866 date = opts.get(r'date')
5859 clean = opts.get(r'clean')
5867 clean = opts.get(r'clean')
5860 check = opts.get(r'check')
5868 check = opts.get(r'check')
5861 merge = opts.get(r'merge')
5869 merge = opts.get(r'merge')
5862 if rev and node:
5870 if rev and node:
5863 raise error.Abort(_("please specify just one revision"))
5871 raise error.Abort(_("please specify just one revision"))
5864
5872
5865 if ui.configbool('commands', 'update.requiredest'):
5873 if ui.configbool('commands', 'update.requiredest'):
5866 if not node and not rev and not date:
5874 if not node and not rev and not date:
5867 raise error.Abort(_('you must specify a destination'),
5875 raise error.Abort(_('you must specify a destination'),
5868 hint=_('for example: hg update ".::"'))
5876 hint=_('for example: hg update ".::"'))
5869
5877
5870 if rev is None or rev == '':
5878 if rev is None or rev == '':
5871 rev = node
5879 rev = node
5872
5880
5873 if date and rev is not None:
5881 if date and rev is not None:
5874 raise error.Abort(_("you can't specify a revision and a date"))
5882 raise error.Abort(_("you can't specify a revision and a date"))
5875
5883
5876 if len([x for x in (clean, check, merge) if x]) > 1:
5884 if len([x for x in (clean, check, merge) if x]) > 1:
5877 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5885 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5878 "or -m/--merge"))
5886 "or -m/--merge"))
5879
5887
5880 updatecheck = None
5888 updatecheck = None
5881 if check:
5889 if check:
5882 updatecheck = 'abort'
5890 updatecheck = 'abort'
5883 elif merge:
5891 elif merge:
5884 updatecheck = 'none'
5892 updatecheck = 'none'
5885
5893
5886 with repo.wlock():
5894 with repo.wlock():
5887 cmdutil.clearunfinished(repo)
5895 cmdutil.clearunfinished(repo)
5888
5896
5889 if date:
5897 if date:
5890 rev = cmdutil.finddate(ui, repo, date)
5898 rev = cmdutil.finddate(ui, repo, date)
5891
5899
5892 # if we defined a bookmark, we have to remember the original name
5900 # if we defined a bookmark, we have to remember the original name
5893 brev = rev
5901 brev = rev
5894 if rev:
5902 if rev:
5895 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5903 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5896 ctx = scmutil.revsingle(repo, rev, rev)
5904 ctx = scmutil.revsingle(repo, rev, rev)
5897 rev = ctx.rev()
5905 rev = ctx.rev()
5898 hidden = ctx.hidden()
5906 hidden = ctx.hidden()
5899 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5907 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5900 with ui.configoverride(overrides, 'update'):
5908 with ui.configoverride(overrides, 'update'):
5901 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5909 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5902 updatecheck=updatecheck)
5910 updatecheck=updatecheck)
5903 if hidden:
5911 if hidden:
5904 ctxstr = ctx.hex()[:12]
5912 ctxstr = ctx.hex()[:12]
5905 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5913 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5906
5914
5907 if ctx.obsolete():
5915 if ctx.obsolete():
5908 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5916 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5909 ui.warn("(%s)\n" % obsfatemsg)
5917 ui.warn("(%s)\n" % obsfatemsg)
5910 return ret
5918 return ret
5911
5919
5912 @command('verify', [])
5920 @command('verify', [])
5913 def verify(ui, repo):
5921 def verify(ui, repo):
5914 """verify the integrity of the repository
5922 """verify the integrity of the repository
5915
5923
5916 Verify the integrity of the current repository.
5924 Verify the integrity of the current repository.
5917
5925
5918 This will perform an extensive check of the repository's
5926 This will perform an extensive check of the repository's
5919 integrity, validating the hashes and checksums of each entry in
5927 integrity, validating the hashes and checksums of each entry in
5920 the changelog, manifest, and tracked files, as well as the
5928 the changelog, manifest, and tracked files, as well as the
5921 integrity of their crosslinks and indices.
5929 integrity of their crosslinks and indices.
5922
5930
5923 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5931 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5924 for more information about recovery from corruption of the
5932 for more information about recovery from corruption of the
5925 repository.
5933 repository.
5926
5934
5927 Returns 0 on success, 1 if errors are encountered.
5935 Returns 0 on success, 1 if errors are encountered.
5928 """
5936 """
5929 return hg.verify(repo)
5937 return hg.verify(repo)
5930
5938
5931 @command('version', [] + formatteropts, norepo=True,
5939 @command('version', [] + formatteropts, norepo=True,
5932 intents={INTENT_READONLY})
5940 intents={INTENT_READONLY})
5933 def version_(ui, **opts):
5941 def version_(ui, **opts):
5934 """output version and copyright information"""
5942 """output version and copyright information"""
5935 opts = pycompat.byteskwargs(opts)
5943 opts = pycompat.byteskwargs(opts)
5936 if ui.verbose:
5944 if ui.verbose:
5937 ui.pager('version')
5945 ui.pager('version')
5938 fm = ui.formatter("version", opts)
5946 fm = ui.formatter("version", opts)
5939 fm.startitem()
5947 fm.startitem()
5940 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5948 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5941 util.version())
5949 util.version())
5942 license = _(
5950 license = _(
5943 "(see https://mercurial-scm.org for more information)\n"
5951 "(see https://mercurial-scm.org for more information)\n"
5944 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5952 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5945 "This is free software; see the source for copying conditions. "
5953 "This is free software; see the source for copying conditions. "
5946 "There is NO\nwarranty; "
5954 "There is NO\nwarranty; "
5947 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5955 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5948 )
5956 )
5949 if not ui.quiet:
5957 if not ui.quiet:
5950 fm.plain(license)
5958 fm.plain(license)
5951
5959
5952 if ui.verbose:
5960 if ui.verbose:
5953 fm.plain(_("\nEnabled extensions:\n\n"))
5961 fm.plain(_("\nEnabled extensions:\n\n"))
5954 # format names and versions into columns
5962 # format names and versions into columns
5955 names = []
5963 names = []
5956 vers = []
5964 vers = []
5957 isinternals = []
5965 isinternals = []
5958 for name, module in extensions.extensions():
5966 for name, module in extensions.extensions():
5959 names.append(name)
5967 names.append(name)
5960 vers.append(extensions.moduleversion(module) or None)
5968 vers.append(extensions.moduleversion(module) or None)
5961 isinternals.append(extensions.ismoduleinternal(module))
5969 isinternals.append(extensions.ismoduleinternal(module))
5962 fn = fm.nested("extensions", tmpl='{name}\n')
5970 fn = fm.nested("extensions", tmpl='{name}\n')
5963 if names:
5971 if names:
5964 namefmt = " %%-%ds " % max(len(n) for n in names)
5972 namefmt = " %%-%ds " % max(len(n) for n in names)
5965 places = [_("external"), _("internal")]
5973 places = [_("external"), _("internal")]
5966 for n, v, p in zip(names, vers, isinternals):
5974 for n, v, p in zip(names, vers, isinternals):
5967 fn.startitem()
5975 fn.startitem()
5968 fn.condwrite(ui.verbose, "name", namefmt, n)
5976 fn.condwrite(ui.verbose, "name", namefmt, n)
5969 if ui.verbose:
5977 if ui.verbose:
5970 fn.plain("%s " % places[p])
5978 fn.plain("%s " % places[p])
5971 fn.data(bundled=p)
5979 fn.data(bundled=p)
5972 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5980 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5973 if ui.verbose:
5981 if ui.verbose:
5974 fn.plain("\n")
5982 fn.plain("\n")
5975 fn.end()
5983 fn.end()
5976 fm.end()
5984 fm.end()
5977
5985
5978 def loadcmdtable(ui, name, cmdtable):
5986 def loadcmdtable(ui, name, cmdtable):
5979 """Load command functions from specified cmdtable
5987 """Load command functions from specified cmdtable
5980 """
5988 """
5981 overrides = [cmd for cmd in cmdtable if cmd in table]
5989 overrides = [cmd for cmd in cmdtable if cmd in table]
5982 if overrides:
5990 if overrides:
5983 ui.warn(_("extension '%s' overrides commands: %s\n")
5991 ui.warn(_("extension '%s' overrides commands: %s\n")
5984 % (name, " ".join(overrides)))
5992 % (name, " ".join(overrides)))
5985 table.update(cmdtable)
5993 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now