##// END OF EJS Templates
help: document about "version" template keywords
Yuya Nishihara -
r40153:dd23eb81 default
parent child Browse files
Show More
@@ -1,6062 +1,6078
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 merge as mergemod,
47 merge as mergemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 repair,
56 repair,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
63 tags as tagsmod,
63 tags as tagsmod,
64 templatekw,
64 templatekw,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 wireprotoserver,
67 wireprotoserver,
68 )
68 )
69 from .utils import (
69 from .utils import (
70 dateutil,
70 dateutil,
71 stringutil,
71 stringutil,
72 )
72 )
73
73
74 table = {}
74 table = {}
75 table.update(debugcommandsmod.command._table)
75 table.update(debugcommandsmod.command._table)
76
76
77 command = registrar.command(table)
77 command = registrar.command(table)
78 INTENT_READONLY = registrar.INTENT_READONLY
78 INTENT_READONLY = registrar.INTENT_READONLY
79
79
80 # common command options
80 # common command options
81
81
82 globalopts = [
82 globalopts = [
83 ('R', 'repository', '',
83 ('R', 'repository', '',
84 _('repository root directory or name of overlay bundle file'),
84 _('repository root directory or name of overlay bundle file'),
85 _('REPO')),
85 _('REPO')),
86 ('', 'cwd', '',
86 ('', 'cwd', '',
87 _('change working directory'), _('DIR')),
87 _('change working directory'), _('DIR')),
88 ('y', 'noninteractive', None,
88 ('y', 'noninteractive', None,
89 _('do not prompt, automatically pick the first choice for all prompts')),
89 _('do not prompt, automatically pick the first choice for all prompts')),
90 ('q', 'quiet', None, _('suppress output')),
90 ('q', 'quiet', None, _('suppress output')),
91 ('v', 'verbose', None, _('enable additional output')),
91 ('v', 'verbose', None, _('enable additional output')),
92 ('', 'color', '',
92 ('', 'color', '',
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # and should not be translated
94 # and should not be translated
95 _("when to colorize (boolean, always, auto, never, or debug)"),
95 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _('TYPE')),
96 _('TYPE')),
97 ('', 'config', [],
97 ('', 'config', [],
98 _('set/override config option (use \'section.name=value\')'),
98 _('set/override config option (use \'section.name=value\')'),
99 _('CONFIG')),
99 _('CONFIG')),
100 ('', 'debug', None, _('enable debugging output')),
100 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debugger', None, _('start debugger')),
101 ('', 'debugger', None, _('start debugger')),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 _('ENCODE')),
103 _('ENCODE')),
104 ('', 'encodingmode', encoding.encodingmode,
104 ('', 'encodingmode', encoding.encodingmode,
105 _('set the charset encoding mode'), _('MODE')),
105 _('set the charset encoding mode'), _('MODE')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'time', None, _('time how long the command takes')),
107 ('', 'time', None, _('time how long the command takes')),
108 ('', 'profile', None, _('print command execution profile')),
108 ('', 'profile', None, _('print command execution profile')),
109 ('', 'version', None, _('output version information and exit')),
109 ('', 'version', None, _('output version information and exit')),
110 ('h', 'help', None, _('display help and exit')),
110 ('h', 'help', None, _('display help and exit')),
111 ('', 'hidden', False, _('consider hidden changesets')),
111 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'pager', 'auto',
112 ('', 'pager', 'auto',
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 ]
114 ]
115
115
116 dryrunopts = cmdutil.dryrunopts
116 dryrunopts = cmdutil.dryrunopts
117 remoteopts = cmdutil.remoteopts
117 remoteopts = cmdutil.remoteopts
118 walkopts = cmdutil.walkopts
118 walkopts = cmdutil.walkopts
119 commitopts = cmdutil.commitopts
119 commitopts = cmdutil.commitopts
120 commitopts2 = cmdutil.commitopts2
120 commitopts2 = cmdutil.commitopts2
121 formatteropts = cmdutil.formatteropts
121 formatteropts = cmdutil.formatteropts
122 templateopts = cmdutil.templateopts
122 templateopts = cmdutil.templateopts
123 logopts = cmdutil.logopts
123 logopts = cmdutil.logopts
124 diffopts = cmdutil.diffopts
124 diffopts = cmdutil.diffopts
125 diffwsopts = cmdutil.diffwsopts
125 diffwsopts = cmdutil.diffwsopts
126 diffopts2 = cmdutil.diffopts2
126 diffopts2 = cmdutil.diffopts2
127 mergetoolopts = cmdutil.mergetoolopts
127 mergetoolopts = cmdutil.mergetoolopts
128 similarityopts = cmdutil.similarityopts
128 similarityopts = cmdutil.similarityopts
129 subrepoopts = cmdutil.subrepoopts
129 subrepoopts = cmdutil.subrepoopts
130 debugrevlogopts = cmdutil.debugrevlogopts
130 debugrevlogopts = cmdutil.debugrevlogopts
131
131
132 # Commands start here, listed alphabetically
132 # Commands start here, listed alphabetically
133
133
134 @command('^add',
134 @command('^add',
135 walkopts + subrepoopts + dryrunopts,
135 walkopts + subrepoopts + dryrunopts,
136 _('[OPTION]... [FILE]...'),
136 _('[OPTION]... [FILE]...'),
137 inferrepo=True)
137 inferrepo=True)
138 def add(ui, repo, *pats, **opts):
138 def add(ui, repo, *pats, **opts):
139 """add the specified files on the next commit
139 """add the specified files on the next commit
140
140
141 Schedule files to be version controlled and added to the
141 Schedule files to be version controlled and added to the
142 repository.
142 repository.
143
143
144 The files will be added to the repository at the next commit. To
144 The files will be added to the repository at the next commit. To
145 undo an add before that, see :hg:`forget`.
145 undo an add before that, see :hg:`forget`.
146
146
147 If no names are given, add all files to the repository (except
147 If no names are given, add all files to the repository (except
148 files matching ``.hgignore``).
148 files matching ``.hgignore``).
149
149
150 .. container:: verbose
150 .. container:: verbose
151
151
152 Examples:
152 Examples:
153
153
154 - New (unknown) files are added
154 - New (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 - Specific files to be added can be specified::
166 - Specific files to be added can be specified::
167
167
168 $ ls
168 $ ls
169 bar.c foo.c
169 bar.c foo.c
170 $ hg status
170 $ hg status
171 ? bar.c
171 ? bar.c
172 ? foo.c
172 ? foo.c
173 $ hg add bar.c
173 $ hg add bar.c
174 $ hg status
174 $ hg status
175 A bar.c
175 A bar.c
176 ? foo.c
176 ? foo.c
177
177
178 Returns 0 if all files are successfully added.
178 Returns 0 if all files are successfully added.
179 """
179 """
180
180
181 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
181 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
182 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 return rejected and 1 or 0
183 return rejected and 1 or 0
184
184
185 @command('addremove',
185 @command('addremove',
186 similarityopts + subrepoopts + walkopts + dryrunopts,
186 similarityopts + subrepoopts + walkopts + dryrunopts,
187 _('[OPTION]... [FILE]...'),
187 _('[OPTION]... [FILE]...'),
188 inferrepo=True)
188 inferrepo=True)
189 def addremove(ui, repo, *pats, **opts):
189 def addremove(ui, repo, *pats, **opts):
190 """add all new files, delete all missing files
190 """add all new files, delete all missing files
191
191
192 Add all new files and remove all missing files from the
192 Add all new files and remove all missing files from the
193 repository.
193 repository.
194
194
195 Unless names are given, new files are ignored if they match any of
195 Unless names are given, new files are ignored if they match any of
196 the patterns in ``.hgignore``. As with add, these changes take
196 the patterns in ``.hgignore``. As with add, these changes take
197 effect at the next commit.
197 effect at the next commit.
198
198
199 Use the -s/--similarity option to detect renamed files. This
199 Use the -s/--similarity option to detect renamed files. This
200 option takes a percentage between 0 (disabled) and 100 (files must
200 option takes a percentage between 0 (disabled) and 100 (files must
201 be identical) as its parameter. With a parameter greater than 0,
201 be identical) as its parameter. With a parameter greater than 0,
202 this compares every removed file with every added file and records
202 this compares every removed file with every added file and records
203 those similar enough as renames. Detecting renamed files this way
203 those similar enough as renames. Detecting renamed files this way
204 can be expensive. After using this option, :hg:`status -C` can be
204 can be expensive. After using this option, :hg:`status -C` can be
205 used to check which files were identified as moved or renamed. If
205 used to check which files were identified as moved or renamed. If
206 not specified, -s/--similarity defaults to 100 and only renames of
206 not specified, -s/--similarity defaults to 100 and only renames of
207 identical files are detected.
207 identical files are detected.
208
208
209 .. container:: verbose
209 .. container:: verbose
210
210
211 Examples:
211 Examples:
212
212
213 - A number of files (bar.c and foo.c) are new,
213 - A number of files (bar.c and foo.c) are new,
214 while foobar.c has been removed (without using :hg:`remove`)
214 while foobar.c has been removed (without using :hg:`remove`)
215 from the repository::
215 from the repository::
216
216
217 $ ls
217 $ ls
218 bar.c foo.c
218 bar.c foo.c
219 $ hg status
219 $ hg status
220 ! foobar.c
220 ! foobar.c
221 ? bar.c
221 ? bar.c
222 ? foo.c
222 ? foo.c
223 $ hg addremove
223 $ hg addremove
224 adding bar.c
224 adding bar.c
225 adding foo.c
225 adding foo.c
226 removing foobar.c
226 removing foobar.c
227 $ hg status
227 $ hg status
228 A bar.c
228 A bar.c
229 A foo.c
229 A foo.c
230 R foobar.c
230 R foobar.c
231
231
232 - A file foobar.c was moved to foo.c without using :hg:`rename`.
232 - A file foobar.c was moved to foo.c without using :hg:`rename`.
233 Afterwards, it was edited slightly::
233 Afterwards, it was edited slightly::
234
234
235 $ ls
235 $ ls
236 foo.c
236 foo.c
237 $ hg status
237 $ hg status
238 ! foobar.c
238 ! foobar.c
239 ? foo.c
239 ? foo.c
240 $ hg addremove --similarity 90
240 $ hg addremove --similarity 90
241 removing foobar.c
241 removing foobar.c
242 adding foo.c
242 adding foo.c
243 recording removal of foobar.c as rename to foo.c (94% similar)
243 recording removal of foobar.c as rename to foo.c (94% similar)
244 $ hg status -C
244 $ hg status -C
245 A foo.c
245 A foo.c
246 foobar.c
246 foobar.c
247 R foobar.c
247 R foobar.c
248
248
249 Returns 0 if all files are successfully added.
249 Returns 0 if all files are successfully added.
250 """
250 """
251 opts = pycompat.byteskwargs(opts)
251 opts = pycompat.byteskwargs(opts)
252 if not opts.get('similarity'):
252 if not opts.get('similarity'):
253 opts['similarity'] = '100'
253 opts['similarity'] = '100'
254 matcher = scmutil.match(repo[None], pats, opts)
254 matcher = scmutil.match(repo[None], pats, opts)
255 return scmutil.addremove(repo, matcher, "", opts)
255 return scmutil.addremove(repo, matcher, "", opts)
256
256
257 @command('^annotate|blame',
257 @command('^annotate|blame',
258 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
258 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
259 ('', 'follow', None,
259 ('', 'follow', None,
260 _('follow copies/renames and list the filename (DEPRECATED)')),
260 _('follow copies/renames and list the filename (DEPRECATED)')),
261 ('', 'no-follow', None, _("don't follow copies and renames")),
261 ('', 'no-follow', None, _("don't follow copies and renames")),
262 ('a', 'text', None, _('treat all files as text')),
262 ('a', 'text', None, _('treat all files as text')),
263 ('u', 'user', None, _('list the author (long with -v)')),
263 ('u', 'user', None, _('list the author (long with -v)')),
264 ('f', 'file', None, _('list the filename')),
264 ('f', 'file', None, _('list the filename')),
265 ('d', 'date', None, _('list the date (short with -q)')),
265 ('d', 'date', None, _('list the date (short with -q)')),
266 ('n', 'number', None, _('list the revision number (default)')),
266 ('n', 'number', None, _('list the revision number (default)')),
267 ('c', 'changeset', None, _('list the changeset')),
267 ('c', 'changeset', None, _('list the changeset')),
268 ('l', 'line-number', None, _('show line number at the first appearance')),
268 ('l', 'line-number', None, _('show line number at the first appearance')),
269 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
269 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
270 ] + diffwsopts + walkopts + formatteropts,
270 ] + diffwsopts + walkopts + formatteropts,
271 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
271 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
272 inferrepo=True)
272 inferrepo=True)
273 def annotate(ui, repo, *pats, **opts):
273 def annotate(ui, repo, *pats, **opts):
274 """show changeset information by line for each file
274 """show changeset information by line for each file
275
275
276 List changes in files, showing the revision id responsible for
276 List changes in files, showing the revision id responsible for
277 each line.
277 each line.
278
278
279 This command is useful for discovering when a change was made and
279 This command is useful for discovering when a change was made and
280 by whom.
280 by whom.
281
281
282 If you include --file, --user, or --date, the revision number is
282 If you include --file, --user, or --date, the revision number is
283 suppressed unless you also include --number.
283 suppressed unless you also include --number.
284
284
285 Without the -a/--text option, annotate will avoid processing files
285 Without the -a/--text option, annotate will avoid processing files
286 it detects as binary. With -a, annotate will annotate the file
286 it detects as binary. With -a, annotate will annotate the file
287 anyway, although the results will probably be neither useful
287 anyway, although the results will probably be neither useful
288 nor desirable.
288 nor desirable.
289
289
290 .. container:: verbose
290 .. container:: verbose
291
291
292 Template:
292 Template:
293
293
294 The following keywords are supported in addition to the common template
294 The following keywords are supported in addition to the common template
295 keywords and functions. See also :hg:`help templates`.
295 keywords and functions. See also :hg:`help templates`.
296
296
297 :lines: List of lines with annotation data.
297 :lines: List of lines with annotation data.
298 :path: String. Repository-absolute path of the specified file.
298 :path: String. Repository-absolute path of the specified file.
299
299
300 And each entry of ``{lines}`` provides the following sub-keywords in
300 And each entry of ``{lines}`` provides the following sub-keywords in
301 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
301 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
302
302
303 :line: String. Line content.
303 :line: String. Line content.
304 :lineno: Integer. Line number at that revision.
304 :lineno: Integer. Line number at that revision.
305 :path: String. Repository-absolute path of the file at that revision.
305 :path: String. Repository-absolute path of the file at that revision.
306
306
307 See :hg:`help templates.operators` for the list expansion syntax.
307 See :hg:`help templates.operators` for the list expansion syntax.
308
308
309 Returns 0 on success.
309 Returns 0 on success.
310 """
310 """
311 opts = pycompat.byteskwargs(opts)
311 opts = pycompat.byteskwargs(opts)
312 if not pats:
312 if not pats:
313 raise error.Abort(_('at least one filename or pattern is required'))
313 raise error.Abort(_('at least one filename or pattern is required'))
314
314
315 if opts.get('follow'):
315 if opts.get('follow'):
316 # --follow is deprecated and now just an alias for -f/--file
316 # --follow is deprecated and now just an alias for -f/--file
317 # to mimic the behavior of Mercurial before version 1.5
317 # to mimic the behavior of Mercurial before version 1.5
318 opts['file'] = True
318 opts['file'] = True
319
319
320 rev = opts.get('rev')
320 rev = opts.get('rev')
321 if rev:
321 if rev:
322 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
322 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
323 ctx = scmutil.revsingle(repo, rev)
323 ctx = scmutil.revsingle(repo, rev)
324
324
325 rootfm = ui.formatter('annotate', opts)
325 rootfm = ui.formatter('annotate', opts)
326 if ui.debugflag:
326 if ui.debugflag:
327 shorthex = pycompat.identity
327 shorthex = pycompat.identity
328 else:
328 else:
329 def shorthex(h):
329 def shorthex(h):
330 return h[:12]
330 return h[:12]
331 if ui.quiet:
331 if ui.quiet:
332 datefunc = dateutil.shortdate
332 datefunc = dateutil.shortdate
333 else:
333 else:
334 datefunc = dateutil.datestr
334 datefunc = dateutil.datestr
335 if ctx.rev() is None:
335 if ctx.rev() is None:
336 if opts.get('changeset'):
336 if opts.get('changeset'):
337 # omit "+" suffix which is appended to node hex
337 # omit "+" suffix which is appended to node hex
338 def formatrev(rev):
338 def formatrev(rev):
339 if rev == wdirrev:
339 if rev == wdirrev:
340 return '%d' % ctx.p1().rev()
340 return '%d' % ctx.p1().rev()
341 else:
341 else:
342 return '%d' % rev
342 return '%d' % rev
343 else:
343 else:
344 def formatrev(rev):
344 def formatrev(rev):
345 if rev == wdirrev:
345 if rev == wdirrev:
346 return '%d+' % ctx.p1().rev()
346 return '%d+' % ctx.p1().rev()
347 else:
347 else:
348 return '%d ' % rev
348 return '%d ' % rev
349 def formathex(h):
349 def formathex(h):
350 if h == wdirhex:
350 if h == wdirhex:
351 return '%s+' % shorthex(hex(ctx.p1().node()))
351 return '%s+' % shorthex(hex(ctx.p1().node()))
352 else:
352 else:
353 return '%s ' % shorthex(h)
353 return '%s ' % shorthex(h)
354 else:
354 else:
355 formatrev = b'%d'.__mod__
355 formatrev = b'%d'.__mod__
356 formathex = shorthex
356 formathex = shorthex
357
357
358 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
358 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
359 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
359 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
360 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
360 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
361 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
361 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
362 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
362 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
363 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
363 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
364 ]
364 ]
365 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
365 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
366 'lineno': 'line_number'}
366 'lineno': 'line_number'}
367
367
368 if (not opts.get('user') and not opts.get('changeset')
368 if (not opts.get('user') and not opts.get('changeset')
369 and not opts.get('date') and not opts.get('file')):
369 and not opts.get('date') and not opts.get('file')):
370 opts['number'] = True
370 opts['number'] = True
371
371
372 linenumber = opts.get('line_number') is not None
372 linenumber = opts.get('line_number') is not None
373 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
373 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
374 raise error.Abort(_('at least one of -n/-c is required for -l'))
374 raise error.Abort(_('at least one of -n/-c is required for -l'))
375
375
376 ui.pager('annotate')
376 ui.pager('annotate')
377
377
378 if rootfm.isplain():
378 if rootfm.isplain():
379 def makefunc(get, fmt):
379 def makefunc(get, fmt):
380 return lambda x: fmt(get(x))
380 return lambda x: fmt(get(x))
381 else:
381 else:
382 def makefunc(get, fmt):
382 def makefunc(get, fmt):
383 return get
383 return get
384 datahint = rootfm.datahint()
384 datahint = rootfm.datahint()
385 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
385 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
386 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
386 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
387 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
387 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
388 fields = ' '.join(fn for fn, sep, get, fmt in opmap
388 fields = ' '.join(fn for fn, sep, get, fmt in opmap
389 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
389 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
390
390
391 def bad(x, y):
391 def bad(x, y):
392 raise error.Abort("%s: %s" % (x, y))
392 raise error.Abort("%s: %s" % (x, y))
393
393
394 m = scmutil.match(ctx, pats, opts, badfn=bad)
394 m = scmutil.match(ctx, pats, opts, badfn=bad)
395
395
396 follow = not opts.get('no_follow')
396 follow = not opts.get('no_follow')
397 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
397 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
398 whitespace=True)
398 whitespace=True)
399 skiprevs = opts.get('skip')
399 skiprevs = opts.get('skip')
400 if skiprevs:
400 if skiprevs:
401 skiprevs = scmutil.revrange(repo, skiprevs)
401 skiprevs = scmutil.revrange(repo, skiprevs)
402
402
403 for abs in ctx.walk(m):
403 for abs in ctx.walk(m):
404 fctx = ctx[abs]
404 fctx = ctx[abs]
405 rootfm.startitem()
405 rootfm.startitem()
406 rootfm.data(path=abs)
406 rootfm.data(path=abs)
407 if not opts.get('text') and fctx.isbinary():
407 if not opts.get('text') and fctx.isbinary():
408 rootfm.plain(_("%s: binary file\n")
408 rootfm.plain(_("%s: binary file\n")
409 % ((pats and m.rel(abs)) or abs))
409 % ((pats and m.rel(abs)) or abs))
410 continue
410 continue
411
411
412 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
412 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
413 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
413 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
414 diffopts=diffopts)
414 diffopts=diffopts)
415 if not lines:
415 if not lines:
416 fm.end()
416 fm.end()
417 continue
417 continue
418 formats = []
418 formats = []
419 pieces = []
419 pieces = []
420
420
421 for f, sep in funcmap:
421 for f, sep in funcmap:
422 l = [f(n) for n in lines]
422 l = [f(n) for n in lines]
423 if fm.isplain():
423 if fm.isplain():
424 sizes = [encoding.colwidth(x) for x in l]
424 sizes = [encoding.colwidth(x) for x in l]
425 ml = max(sizes)
425 ml = max(sizes)
426 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
426 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
427 else:
427 else:
428 formats.append(['%s' for x in l])
428 formats.append(['%s' for x in l])
429 pieces.append(l)
429 pieces.append(l)
430
430
431 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
431 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
432 fm.startitem()
432 fm.startitem()
433 fm.context(fctx=n.fctx)
433 fm.context(fctx=n.fctx)
434 fm.write(fields, "".join(f), *p)
434 fm.write(fields, "".join(f), *p)
435 if n.skip:
435 if n.skip:
436 fmt = "* %s"
436 fmt = "* %s"
437 else:
437 else:
438 fmt = ": %s"
438 fmt = ": %s"
439 fm.write('line', fmt, n.text)
439 fm.write('line', fmt, n.text)
440
440
441 if not lines[-1].text.endswith('\n'):
441 if not lines[-1].text.endswith('\n'):
442 fm.plain('\n')
442 fm.plain('\n')
443 fm.end()
443 fm.end()
444
444
445 rootfm.end()
445 rootfm.end()
446
446
447 @command('archive',
447 @command('archive',
448 [('', 'no-decode', None, _('do not pass files through decoders')),
448 [('', 'no-decode', None, _('do not pass files through decoders')),
449 ('p', 'prefix', '', _('directory prefix for files in archive'),
449 ('p', 'prefix', '', _('directory prefix for files in archive'),
450 _('PREFIX')),
450 _('PREFIX')),
451 ('r', 'rev', '', _('revision to distribute'), _('REV')),
451 ('r', 'rev', '', _('revision to distribute'), _('REV')),
452 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
452 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
453 ] + subrepoopts + walkopts,
453 ] + subrepoopts + walkopts,
454 _('[OPTION]... DEST'))
454 _('[OPTION]... DEST'))
455 def archive(ui, repo, dest, **opts):
455 def archive(ui, repo, dest, **opts):
456 '''create an unversioned archive of a repository revision
456 '''create an unversioned archive of a repository revision
457
457
458 By default, the revision used is the parent of the working
458 By default, the revision used is the parent of the working
459 directory; use -r/--rev to specify a different revision.
459 directory; use -r/--rev to specify a different revision.
460
460
461 The archive type is automatically detected based on file
461 The archive type is automatically detected based on file
462 extension (to override, use -t/--type).
462 extension (to override, use -t/--type).
463
463
464 .. container:: verbose
464 .. container:: verbose
465
465
466 Examples:
466 Examples:
467
467
468 - create a zip file containing the 1.0 release::
468 - create a zip file containing the 1.0 release::
469
469
470 hg archive -r 1.0 project-1.0.zip
470 hg archive -r 1.0 project-1.0.zip
471
471
472 - create a tarball excluding .hg files::
472 - create a tarball excluding .hg files::
473
473
474 hg archive project.tar.gz -X ".hg*"
474 hg archive project.tar.gz -X ".hg*"
475
475
476 Valid types are:
476 Valid types are:
477
477
478 :``files``: a directory full of files (default)
478 :``files``: a directory full of files (default)
479 :``tar``: tar archive, uncompressed
479 :``tar``: tar archive, uncompressed
480 :``tbz2``: tar archive, compressed using bzip2
480 :``tbz2``: tar archive, compressed using bzip2
481 :``tgz``: tar archive, compressed using gzip
481 :``tgz``: tar archive, compressed using gzip
482 :``uzip``: zip archive, uncompressed
482 :``uzip``: zip archive, uncompressed
483 :``zip``: zip archive, compressed using deflate
483 :``zip``: zip archive, compressed using deflate
484
484
485 The exact name of the destination archive or directory is given
485 The exact name of the destination archive or directory is given
486 using a format string; see :hg:`help export` for details.
486 using a format string; see :hg:`help export` for details.
487
487
488 Each member added to an archive file has a directory prefix
488 Each member added to an archive file has a directory prefix
489 prepended. Use -p/--prefix to specify a format string for the
489 prepended. Use -p/--prefix to specify a format string for the
490 prefix. The default is the basename of the archive, with suffixes
490 prefix. The default is the basename of the archive, with suffixes
491 removed.
491 removed.
492
492
493 Returns 0 on success.
493 Returns 0 on success.
494 '''
494 '''
495
495
496 opts = pycompat.byteskwargs(opts)
496 opts = pycompat.byteskwargs(opts)
497 rev = opts.get('rev')
497 rev = opts.get('rev')
498 if rev:
498 if rev:
499 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
499 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
500 ctx = scmutil.revsingle(repo, rev)
500 ctx = scmutil.revsingle(repo, rev)
501 if not ctx:
501 if not ctx:
502 raise error.Abort(_('no working directory: please specify a revision'))
502 raise error.Abort(_('no working directory: please specify a revision'))
503 node = ctx.node()
503 node = ctx.node()
504 dest = cmdutil.makefilename(ctx, dest)
504 dest = cmdutil.makefilename(ctx, dest)
505 if os.path.realpath(dest) == repo.root:
505 if os.path.realpath(dest) == repo.root:
506 raise error.Abort(_('repository root cannot be destination'))
506 raise error.Abort(_('repository root cannot be destination'))
507
507
508 kind = opts.get('type') or archival.guesskind(dest) or 'files'
508 kind = opts.get('type') or archival.guesskind(dest) or 'files'
509 prefix = opts.get('prefix')
509 prefix = opts.get('prefix')
510
510
511 if dest == '-':
511 if dest == '-':
512 if kind == 'files':
512 if kind == 'files':
513 raise error.Abort(_('cannot archive plain files to stdout'))
513 raise error.Abort(_('cannot archive plain files to stdout'))
514 dest = cmdutil.makefileobj(ctx, dest)
514 dest = cmdutil.makefileobj(ctx, dest)
515 if not prefix:
515 if not prefix:
516 prefix = os.path.basename(repo.root) + '-%h'
516 prefix = os.path.basename(repo.root) + '-%h'
517
517
518 prefix = cmdutil.makefilename(ctx, prefix)
518 prefix = cmdutil.makefilename(ctx, prefix)
519 match = scmutil.match(ctx, [], opts)
519 match = scmutil.match(ctx, [], opts)
520 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
520 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
521 match, prefix, subrepos=opts.get('subrepos'))
521 match, prefix, subrepos=opts.get('subrepos'))
522
522
523 @command('backout',
523 @command('backout',
524 [('', 'merge', None, _('merge with old dirstate parent after backout')),
524 [('', 'merge', None, _('merge with old dirstate parent after backout')),
525 ('', 'commit', None,
525 ('', 'commit', None,
526 _('commit if no conflicts were encountered (DEPRECATED)')),
526 _('commit if no conflicts were encountered (DEPRECATED)')),
527 ('', 'no-commit', None, _('do not commit')),
527 ('', 'no-commit', None, _('do not commit')),
528 ('', 'parent', '',
528 ('', 'parent', '',
529 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
529 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
530 ('r', 'rev', '', _('revision to backout'), _('REV')),
530 ('r', 'rev', '', _('revision to backout'), _('REV')),
531 ('e', 'edit', False, _('invoke editor on commit messages')),
531 ('e', 'edit', False, _('invoke editor on commit messages')),
532 ] + mergetoolopts + walkopts + commitopts + commitopts2,
532 ] + mergetoolopts + walkopts + commitopts + commitopts2,
533 _('[OPTION]... [-r] REV'))
533 _('[OPTION]... [-r] REV'))
534 def backout(ui, repo, node=None, rev=None, **opts):
534 def backout(ui, repo, node=None, rev=None, **opts):
535 '''reverse effect of earlier changeset
535 '''reverse effect of earlier changeset
536
536
537 Prepare a new changeset with the effect of REV undone in the
537 Prepare a new changeset with the effect of REV undone in the
538 current working directory. If no conflicts were encountered,
538 current working directory. If no conflicts were encountered,
539 it will be committed immediately.
539 it will be committed immediately.
540
540
541 If REV is the parent of the working directory, then this new changeset
541 If REV is the parent of the working directory, then this new changeset
542 is committed automatically (unless --no-commit is specified).
542 is committed automatically (unless --no-commit is specified).
543
543
544 .. note::
544 .. note::
545
545
546 :hg:`backout` cannot be used to fix either an unwanted or
546 :hg:`backout` cannot be used to fix either an unwanted or
547 incorrect merge.
547 incorrect merge.
548
548
549 .. container:: verbose
549 .. container:: verbose
550
550
551 Examples:
551 Examples:
552
552
553 - Reverse the effect of the parent of the working directory.
553 - Reverse the effect of the parent of the working directory.
554 This backout will be committed immediately::
554 This backout will be committed immediately::
555
555
556 hg backout -r .
556 hg backout -r .
557
557
558 - Reverse the effect of previous bad revision 23::
558 - Reverse the effect of previous bad revision 23::
559
559
560 hg backout -r 23
560 hg backout -r 23
561
561
562 - Reverse the effect of previous bad revision 23 and
562 - Reverse the effect of previous bad revision 23 and
563 leave changes uncommitted::
563 leave changes uncommitted::
564
564
565 hg backout -r 23 --no-commit
565 hg backout -r 23 --no-commit
566 hg commit -m "Backout revision 23"
566 hg commit -m "Backout revision 23"
567
567
568 By default, the pending changeset will have one parent,
568 By default, the pending changeset will have one parent,
569 maintaining a linear history. With --merge, the pending
569 maintaining a linear history. With --merge, the pending
570 changeset will instead have two parents: the old parent of the
570 changeset will instead have two parents: the old parent of the
571 working directory and a new child of REV that simply undoes REV.
571 working directory and a new child of REV that simply undoes REV.
572
572
573 Before version 1.7, the behavior without --merge was equivalent
573 Before version 1.7, the behavior without --merge was equivalent
574 to specifying --merge followed by :hg:`update --clean .` to
574 to specifying --merge followed by :hg:`update --clean .` to
575 cancel the merge and leave the child of REV as a head to be
575 cancel the merge and leave the child of REV as a head to be
576 merged separately.
576 merged separately.
577
577
578 See :hg:`help dates` for a list of formats valid for -d/--date.
578 See :hg:`help dates` for a list of formats valid for -d/--date.
579
579
580 See :hg:`help revert` for a way to restore files to the state
580 See :hg:`help revert` for a way to restore files to the state
581 of another revision.
581 of another revision.
582
582
583 Returns 0 on success, 1 if nothing to backout or there are unresolved
583 Returns 0 on success, 1 if nothing to backout or there are unresolved
584 files.
584 files.
585 '''
585 '''
586 with repo.wlock(), repo.lock():
586 with repo.wlock(), repo.lock():
587 return _dobackout(ui, repo, node, rev, **opts)
587 return _dobackout(ui, repo, node, rev, **opts)
588
588
589 def _dobackout(ui, repo, node=None, rev=None, **opts):
589 def _dobackout(ui, repo, node=None, rev=None, **opts):
590 opts = pycompat.byteskwargs(opts)
590 opts = pycompat.byteskwargs(opts)
591 if opts.get('commit') and opts.get('no_commit'):
591 if opts.get('commit') and opts.get('no_commit'):
592 raise error.Abort(_("cannot use --commit with --no-commit"))
592 raise error.Abort(_("cannot use --commit with --no-commit"))
593 if opts.get('merge') and opts.get('no_commit'):
593 if opts.get('merge') and opts.get('no_commit'):
594 raise error.Abort(_("cannot use --merge with --no-commit"))
594 raise error.Abort(_("cannot use --merge with --no-commit"))
595
595
596 if rev and node:
596 if rev and node:
597 raise error.Abort(_("please specify just one revision"))
597 raise error.Abort(_("please specify just one revision"))
598
598
599 if not rev:
599 if not rev:
600 rev = node
600 rev = node
601
601
602 if not rev:
602 if not rev:
603 raise error.Abort(_("please specify a revision to backout"))
603 raise error.Abort(_("please specify a revision to backout"))
604
604
605 date = opts.get('date')
605 date = opts.get('date')
606 if date:
606 if date:
607 opts['date'] = dateutil.parsedate(date)
607 opts['date'] = dateutil.parsedate(date)
608
608
609 cmdutil.checkunfinished(repo)
609 cmdutil.checkunfinished(repo)
610 cmdutil.bailifchanged(repo)
610 cmdutil.bailifchanged(repo)
611 node = scmutil.revsingle(repo, rev).node()
611 node = scmutil.revsingle(repo, rev).node()
612
612
613 op1, op2 = repo.dirstate.parents()
613 op1, op2 = repo.dirstate.parents()
614 if not repo.changelog.isancestor(node, op1):
614 if not repo.changelog.isancestor(node, op1):
615 raise error.Abort(_('cannot backout change that is not an ancestor'))
615 raise error.Abort(_('cannot backout change that is not an ancestor'))
616
616
617 p1, p2 = repo.changelog.parents(node)
617 p1, p2 = repo.changelog.parents(node)
618 if p1 == nullid:
618 if p1 == nullid:
619 raise error.Abort(_('cannot backout a change with no parents'))
619 raise error.Abort(_('cannot backout a change with no parents'))
620 if p2 != nullid:
620 if p2 != nullid:
621 if not opts.get('parent'):
621 if not opts.get('parent'):
622 raise error.Abort(_('cannot backout a merge changeset'))
622 raise error.Abort(_('cannot backout a merge changeset'))
623 p = repo.lookup(opts['parent'])
623 p = repo.lookup(opts['parent'])
624 if p not in (p1, p2):
624 if p not in (p1, p2):
625 raise error.Abort(_('%s is not a parent of %s') %
625 raise error.Abort(_('%s is not a parent of %s') %
626 (short(p), short(node)))
626 (short(p), short(node)))
627 parent = p
627 parent = p
628 else:
628 else:
629 if opts.get('parent'):
629 if opts.get('parent'):
630 raise error.Abort(_('cannot use --parent on non-merge changeset'))
630 raise error.Abort(_('cannot use --parent on non-merge changeset'))
631 parent = p1
631 parent = p1
632
632
633 # the backout should appear on the same branch
633 # the backout should appear on the same branch
634 branch = repo.dirstate.branch()
634 branch = repo.dirstate.branch()
635 bheads = repo.branchheads(branch)
635 bheads = repo.branchheads(branch)
636 rctx = scmutil.revsingle(repo, hex(parent))
636 rctx = scmutil.revsingle(repo, hex(parent))
637 if not opts.get('merge') and op1 != node:
637 if not opts.get('merge') and op1 != node:
638 with dirstateguard.dirstateguard(repo, 'backout'):
638 with dirstateguard.dirstateguard(repo, 'backout'):
639 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
639 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
640 with ui.configoverride(overrides, 'backout'):
640 with ui.configoverride(overrides, 'backout'):
641 stats = mergemod.update(repo, parent, True, True, node, False)
641 stats = mergemod.update(repo, parent, True, True, node, False)
642 repo.setparents(op1, op2)
642 repo.setparents(op1, op2)
643 hg._showstats(repo, stats)
643 hg._showstats(repo, stats)
644 if stats.unresolvedcount:
644 if stats.unresolvedcount:
645 repo.ui.status(_("use 'hg resolve' to retry unresolved "
645 repo.ui.status(_("use 'hg resolve' to retry unresolved "
646 "file merges\n"))
646 "file merges\n"))
647 return 1
647 return 1
648 else:
648 else:
649 hg.clean(repo, node, show_stats=False)
649 hg.clean(repo, node, show_stats=False)
650 repo.dirstate.setbranch(branch)
650 repo.dirstate.setbranch(branch)
651 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
651 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
652
652
653 if opts.get('no_commit'):
653 if opts.get('no_commit'):
654 msg = _("changeset %s backed out, "
654 msg = _("changeset %s backed out, "
655 "don't forget to commit.\n")
655 "don't forget to commit.\n")
656 ui.status(msg % short(node))
656 ui.status(msg % short(node))
657 return 0
657 return 0
658
658
659 def commitfunc(ui, repo, message, match, opts):
659 def commitfunc(ui, repo, message, match, opts):
660 editform = 'backout'
660 editform = 'backout'
661 e = cmdutil.getcommiteditor(editform=editform,
661 e = cmdutil.getcommiteditor(editform=editform,
662 **pycompat.strkwargs(opts))
662 **pycompat.strkwargs(opts))
663 if not message:
663 if not message:
664 # we don't translate commit messages
664 # we don't translate commit messages
665 message = "Backed out changeset %s" % short(node)
665 message = "Backed out changeset %s" % short(node)
666 e = cmdutil.getcommiteditor(edit=True, editform=editform)
666 e = cmdutil.getcommiteditor(edit=True, editform=editform)
667 return repo.commit(message, opts.get('user'), opts.get('date'),
667 return repo.commit(message, opts.get('user'), opts.get('date'),
668 match, editor=e)
668 match, editor=e)
669 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
669 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
670 if not newnode:
670 if not newnode:
671 ui.status(_("nothing changed\n"))
671 ui.status(_("nothing changed\n"))
672 return 1
672 return 1
673 cmdutil.commitstatus(repo, newnode, branch, bheads)
673 cmdutil.commitstatus(repo, newnode, branch, bheads)
674
674
675 def nice(node):
675 def nice(node):
676 return '%d:%s' % (repo.changelog.rev(node), short(node))
676 return '%d:%s' % (repo.changelog.rev(node), short(node))
677 ui.status(_('changeset %s backs out changeset %s\n') %
677 ui.status(_('changeset %s backs out changeset %s\n') %
678 (nice(repo.changelog.tip()), nice(node)))
678 (nice(repo.changelog.tip()), nice(node)))
679 if opts.get('merge') and op1 != node:
679 if opts.get('merge') and op1 != node:
680 hg.clean(repo, op1, show_stats=False)
680 hg.clean(repo, op1, show_stats=False)
681 ui.status(_('merging with changeset %s\n')
681 ui.status(_('merging with changeset %s\n')
682 % nice(repo.changelog.tip()))
682 % nice(repo.changelog.tip()))
683 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
683 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
684 with ui.configoverride(overrides, 'backout'):
684 with ui.configoverride(overrides, 'backout'):
685 return hg.merge(repo, hex(repo.changelog.tip()))
685 return hg.merge(repo, hex(repo.changelog.tip()))
686 return 0
686 return 0
687
687
688 @command('bisect',
688 @command('bisect',
689 [('r', 'reset', False, _('reset bisect state')),
689 [('r', 'reset', False, _('reset bisect state')),
690 ('g', 'good', False, _('mark changeset good')),
690 ('g', 'good', False, _('mark changeset good')),
691 ('b', 'bad', False, _('mark changeset bad')),
691 ('b', 'bad', False, _('mark changeset bad')),
692 ('s', 'skip', False, _('skip testing changeset')),
692 ('s', 'skip', False, _('skip testing changeset')),
693 ('e', 'extend', False, _('extend the bisect range')),
693 ('e', 'extend', False, _('extend the bisect range')),
694 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
694 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
695 ('U', 'noupdate', False, _('do not update to target'))],
695 ('U', 'noupdate', False, _('do not update to target'))],
696 _("[-gbsr] [-U] [-c CMD] [REV]"))
696 _("[-gbsr] [-U] [-c CMD] [REV]"))
697 def bisect(ui, repo, rev=None, extra=None, command=None,
697 def bisect(ui, repo, rev=None, extra=None, command=None,
698 reset=None, good=None, bad=None, skip=None, extend=None,
698 reset=None, good=None, bad=None, skip=None, extend=None,
699 noupdate=None):
699 noupdate=None):
700 """subdivision search of changesets
700 """subdivision search of changesets
701
701
702 This command helps to find changesets which introduce problems. To
702 This command helps to find changesets which introduce problems. To
703 use, mark the earliest changeset you know exhibits the problem as
703 use, mark the earliest changeset you know exhibits the problem as
704 bad, then mark the latest changeset which is free from the problem
704 bad, then mark the latest changeset which is free from the problem
705 as good. Bisect will update your working directory to a revision
705 as good. Bisect will update your working directory to a revision
706 for testing (unless the -U/--noupdate option is specified). Once
706 for testing (unless the -U/--noupdate option is specified). Once
707 you have performed tests, mark the working directory as good or
707 you have performed tests, mark the working directory as good or
708 bad, and bisect will either update to another candidate changeset
708 bad, and bisect will either update to another candidate changeset
709 or announce that it has found the bad revision.
709 or announce that it has found the bad revision.
710
710
711 As a shortcut, you can also use the revision argument to mark a
711 As a shortcut, you can also use the revision argument to mark a
712 revision as good or bad without checking it out first.
712 revision as good or bad without checking it out first.
713
713
714 If you supply a command, it will be used for automatic bisection.
714 If you supply a command, it will be used for automatic bisection.
715 The environment variable HG_NODE will contain the ID of the
715 The environment variable HG_NODE will contain the ID of the
716 changeset being tested. The exit status of the command will be
716 changeset being tested. The exit status of the command will be
717 used to mark revisions as good or bad: status 0 means good, 125
717 used to mark revisions as good or bad: status 0 means good, 125
718 means to skip the revision, 127 (command not found) will abort the
718 means to skip the revision, 127 (command not found) will abort the
719 bisection, and any other non-zero exit status means the revision
719 bisection, and any other non-zero exit status means the revision
720 is bad.
720 is bad.
721
721
722 .. container:: verbose
722 .. container:: verbose
723
723
724 Some examples:
724 Some examples:
725
725
726 - start a bisection with known bad revision 34, and good revision 12::
726 - start a bisection with known bad revision 34, and good revision 12::
727
727
728 hg bisect --bad 34
728 hg bisect --bad 34
729 hg bisect --good 12
729 hg bisect --good 12
730
730
731 - advance the current bisection by marking current revision as good or
731 - advance the current bisection by marking current revision as good or
732 bad::
732 bad::
733
733
734 hg bisect --good
734 hg bisect --good
735 hg bisect --bad
735 hg bisect --bad
736
736
737 - mark the current revision, or a known revision, to be skipped (e.g. if
737 - mark the current revision, or a known revision, to be skipped (e.g. if
738 that revision is not usable because of another issue)::
738 that revision is not usable because of another issue)::
739
739
740 hg bisect --skip
740 hg bisect --skip
741 hg bisect --skip 23
741 hg bisect --skip 23
742
742
743 - skip all revisions that do not touch directories ``foo`` or ``bar``::
743 - skip all revisions that do not touch directories ``foo`` or ``bar``::
744
744
745 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
745 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
746
746
747 - forget the current bisection::
747 - forget the current bisection::
748
748
749 hg bisect --reset
749 hg bisect --reset
750
750
751 - use 'make && make tests' to automatically find the first broken
751 - use 'make && make tests' to automatically find the first broken
752 revision::
752 revision::
753
753
754 hg bisect --reset
754 hg bisect --reset
755 hg bisect --bad 34
755 hg bisect --bad 34
756 hg bisect --good 12
756 hg bisect --good 12
757 hg bisect --command "make && make tests"
757 hg bisect --command "make && make tests"
758
758
759 - see all changesets whose states are already known in the current
759 - see all changesets whose states are already known in the current
760 bisection::
760 bisection::
761
761
762 hg log -r "bisect(pruned)"
762 hg log -r "bisect(pruned)"
763
763
764 - see the changeset currently being bisected (especially useful
764 - see the changeset currently being bisected (especially useful
765 if running with -U/--noupdate)::
765 if running with -U/--noupdate)::
766
766
767 hg log -r "bisect(current)"
767 hg log -r "bisect(current)"
768
768
769 - see all changesets that took part in the current bisection::
769 - see all changesets that took part in the current bisection::
770
770
771 hg log -r "bisect(range)"
771 hg log -r "bisect(range)"
772
772
773 - you can even get a nice graph::
773 - you can even get a nice graph::
774
774
775 hg log --graph -r "bisect(range)"
775 hg log --graph -r "bisect(range)"
776
776
777 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
777 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
778
778
779 Returns 0 on success.
779 Returns 0 on success.
780 """
780 """
781 # backward compatibility
781 # backward compatibility
782 if rev in "good bad reset init".split():
782 if rev in "good bad reset init".split():
783 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
783 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
784 cmd, rev, extra = rev, extra, None
784 cmd, rev, extra = rev, extra, None
785 if cmd == "good":
785 if cmd == "good":
786 good = True
786 good = True
787 elif cmd == "bad":
787 elif cmd == "bad":
788 bad = True
788 bad = True
789 else:
789 else:
790 reset = True
790 reset = True
791 elif extra:
791 elif extra:
792 raise error.Abort(_('incompatible arguments'))
792 raise error.Abort(_('incompatible arguments'))
793
793
794 incompatibles = {
794 incompatibles = {
795 '--bad': bad,
795 '--bad': bad,
796 '--command': bool(command),
796 '--command': bool(command),
797 '--extend': extend,
797 '--extend': extend,
798 '--good': good,
798 '--good': good,
799 '--reset': reset,
799 '--reset': reset,
800 '--skip': skip,
800 '--skip': skip,
801 }
801 }
802
802
803 enabled = [x for x in incompatibles if incompatibles[x]]
803 enabled = [x for x in incompatibles if incompatibles[x]]
804
804
805 if len(enabled) > 1:
805 if len(enabled) > 1:
806 raise error.Abort(_('%s and %s are incompatible') %
806 raise error.Abort(_('%s and %s are incompatible') %
807 tuple(sorted(enabled)[0:2]))
807 tuple(sorted(enabled)[0:2]))
808
808
809 if reset:
809 if reset:
810 hbisect.resetstate(repo)
810 hbisect.resetstate(repo)
811 return
811 return
812
812
813 state = hbisect.load_state(repo)
813 state = hbisect.load_state(repo)
814
814
815 # update state
815 # update state
816 if good or bad or skip:
816 if good or bad or skip:
817 if rev:
817 if rev:
818 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
818 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
819 else:
819 else:
820 nodes = [repo.lookup('.')]
820 nodes = [repo.lookup('.')]
821 if good:
821 if good:
822 state['good'] += nodes
822 state['good'] += nodes
823 elif bad:
823 elif bad:
824 state['bad'] += nodes
824 state['bad'] += nodes
825 elif skip:
825 elif skip:
826 state['skip'] += nodes
826 state['skip'] += nodes
827 hbisect.save_state(repo, state)
827 hbisect.save_state(repo, state)
828 if not (state['good'] and state['bad']):
828 if not (state['good'] and state['bad']):
829 return
829 return
830
830
831 def mayupdate(repo, node, show_stats=True):
831 def mayupdate(repo, node, show_stats=True):
832 """common used update sequence"""
832 """common used update sequence"""
833 if noupdate:
833 if noupdate:
834 return
834 return
835 cmdutil.checkunfinished(repo)
835 cmdutil.checkunfinished(repo)
836 cmdutil.bailifchanged(repo)
836 cmdutil.bailifchanged(repo)
837 return hg.clean(repo, node, show_stats=show_stats)
837 return hg.clean(repo, node, show_stats=show_stats)
838
838
839 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
839 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
840
840
841 if command:
841 if command:
842 changesets = 1
842 changesets = 1
843 if noupdate:
843 if noupdate:
844 try:
844 try:
845 node = state['current'][0]
845 node = state['current'][0]
846 except LookupError:
846 except LookupError:
847 raise error.Abort(_('current bisect revision is unknown - '
847 raise error.Abort(_('current bisect revision is unknown - '
848 'start a new bisect to fix'))
848 'start a new bisect to fix'))
849 else:
849 else:
850 node, p2 = repo.dirstate.parents()
850 node, p2 = repo.dirstate.parents()
851 if p2 != nullid:
851 if p2 != nullid:
852 raise error.Abort(_('current bisect revision is a merge'))
852 raise error.Abort(_('current bisect revision is a merge'))
853 if rev:
853 if rev:
854 node = repo[scmutil.revsingle(repo, rev, node)].node()
854 node = repo[scmutil.revsingle(repo, rev, node)].node()
855 try:
855 try:
856 while changesets:
856 while changesets:
857 # update state
857 # update state
858 state['current'] = [node]
858 state['current'] = [node]
859 hbisect.save_state(repo, state)
859 hbisect.save_state(repo, state)
860 status = ui.system(command, environ={'HG_NODE': hex(node)},
860 status = ui.system(command, environ={'HG_NODE': hex(node)},
861 blockedtag='bisect_check')
861 blockedtag='bisect_check')
862 if status == 125:
862 if status == 125:
863 transition = "skip"
863 transition = "skip"
864 elif status == 0:
864 elif status == 0:
865 transition = "good"
865 transition = "good"
866 # status < 0 means process was killed
866 # status < 0 means process was killed
867 elif status == 127:
867 elif status == 127:
868 raise error.Abort(_("failed to execute %s") % command)
868 raise error.Abort(_("failed to execute %s") % command)
869 elif status < 0:
869 elif status < 0:
870 raise error.Abort(_("%s killed") % command)
870 raise error.Abort(_("%s killed") % command)
871 else:
871 else:
872 transition = "bad"
872 transition = "bad"
873 state[transition].append(node)
873 state[transition].append(node)
874 ctx = repo[node]
874 ctx = repo[node]
875 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
875 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
876 transition))
876 transition))
877 hbisect.checkstate(state)
877 hbisect.checkstate(state)
878 # bisect
878 # bisect
879 nodes, changesets, bgood = hbisect.bisect(repo, state)
879 nodes, changesets, bgood = hbisect.bisect(repo, state)
880 # update to next check
880 # update to next check
881 node = nodes[0]
881 node = nodes[0]
882 mayupdate(repo, node, show_stats=False)
882 mayupdate(repo, node, show_stats=False)
883 finally:
883 finally:
884 state['current'] = [node]
884 state['current'] = [node]
885 hbisect.save_state(repo, state)
885 hbisect.save_state(repo, state)
886 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
886 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
887 return
887 return
888
888
889 hbisect.checkstate(state)
889 hbisect.checkstate(state)
890
890
891 # actually bisect
891 # actually bisect
892 nodes, changesets, good = hbisect.bisect(repo, state)
892 nodes, changesets, good = hbisect.bisect(repo, state)
893 if extend:
893 if extend:
894 if not changesets:
894 if not changesets:
895 extendnode = hbisect.extendrange(repo, state, nodes, good)
895 extendnode = hbisect.extendrange(repo, state, nodes, good)
896 if extendnode is not None:
896 if extendnode is not None:
897 ui.write(_("Extending search to changeset %d:%s\n")
897 ui.write(_("Extending search to changeset %d:%s\n")
898 % (extendnode.rev(), extendnode))
898 % (extendnode.rev(), extendnode))
899 state['current'] = [extendnode.node()]
899 state['current'] = [extendnode.node()]
900 hbisect.save_state(repo, state)
900 hbisect.save_state(repo, state)
901 return mayupdate(repo, extendnode.node())
901 return mayupdate(repo, extendnode.node())
902 raise error.Abort(_("nothing to extend"))
902 raise error.Abort(_("nothing to extend"))
903
903
904 if changesets == 0:
904 if changesets == 0:
905 hbisect.printresult(ui, repo, state, displayer, nodes, good)
905 hbisect.printresult(ui, repo, state, displayer, nodes, good)
906 else:
906 else:
907 assert len(nodes) == 1 # only a single node can be tested next
907 assert len(nodes) == 1 # only a single node can be tested next
908 node = nodes[0]
908 node = nodes[0]
909 # compute the approximate number of remaining tests
909 # compute the approximate number of remaining tests
910 tests, size = 0, 2
910 tests, size = 0, 2
911 while size <= changesets:
911 while size <= changesets:
912 tests, size = tests + 1, size * 2
912 tests, size = tests + 1, size * 2
913 rev = repo.changelog.rev(node)
913 rev = repo.changelog.rev(node)
914 ui.write(_("Testing changeset %d:%s "
914 ui.write(_("Testing changeset %d:%s "
915 "(%d changesets remaining, ~%d tests)\n")
915 "(%d changesets remaining, ~%d tests)\n")
916 % (rev, short(node), changesets, tests))
916 % (rev, short(node), changesets, tests))
917 state['current'] = [node]
917 state['current'] = [node]
918 hbisect.save_state(repo, state)
918 hbisect.save_state(repo, state)
919 return mayupdate(repo, node)
919 return mayupdate(repo, node)
920
920
921 @command('bookmarks|bookmark',
921 @command('bookmarks|bookmark',
922 [('f', 'force', False, _('force')),
922 [('f', 'force', False, _('force')),
923 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
923 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
924 ('d', 'delete', False, _('delete a given bookmark')),
924 ('d', 'delete', False, _('delete a given bookmark')),
925 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
925 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
926 ('i', 'inactive', False, _('mark a bookmark inactive')),
926 ('i', 'inactive', False, _('mark a bookmark inactive')),
927 ('l', 'list', False, _('list existing bookmarks')),
927 ('l', 'list', False, _('list existing bookmarks')),
928 ] + formatteropts,
928 ] + formatteropts,
929 _('hg bookmarks [OPTIONS]... [NAME]...'))
929 _('hg bookmarks [OPTIONS]... [NAME]...'))
930 def bookmark(ui, repo, *names, **opts):
930 def bookmark(ui, repo, *names, **opts):
931 '''create a new bookmark or list existing bookmarks
931 '''create a new bookmark or list existing bookmarks
932
932
933 Bookmarks are labels on changesets to help track lines of development.
933 Bookmarks are labels on changesets to help track lines of development.
934 Bookmarks are unversioned and can be moved, renamed and deleted.
934 Bookmarks are unversioned and can be moved, renamed and deleted.
935 Deleting or moving a bookmark has no effect on the associated changesets.
935 Deleting or moving a bookmark has no effect on the associated changesets.
936
936
937 Creating or updating to a bookmark causes it to be marked as 'active'.
937 Creating or updating to a bookmark causes it to be marked as 'active'.
938 The active bookmark is indicated with a '*'.
938 The active bookmark is indicated with a '*'.
939 When a commit is made, the active bookmark will advance to the new commit.
939 When a commit is made, the active bookmark will advance to the new commit.
940 A plain :hg:`update` will also advance an active bookmark, if possible.
940 A plain :hg:`update` will also advance an active bookmark, if possible.
941 Updating away from a bookmark will cause it to be deactivated.
941 Updating away from a bookmark will cause it to be deactivated.
942
942
943 Bookmarks can be pushed and pulled between repositories (see
943 Bookmarks can be pushed and pulled between repositories (see
944 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
944 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
945 diverged, a new 'divergent bookmark' of the form 'name@path' will
945 diverged, a new 'divergent bookmark' of the form 'name@path' will
946 be created. Using :hg:`merge` will resolve the divergence.
946 be created. Using :hg:`merge` will resolve the divergence.
947
947
948 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
948 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
949 the active bookmark's name.
949 the active bookmark's name.
950
950
951 A bookmark named '@' has the special property that :hg:`clone` will
951 A bookmark named '@' has the special property that :hg:`clone` will
952 check it out by default if it exists.
952 check it out by default if it exists.
953
953
954 .. container:: verbose
954 .. container:: verbose
955
955
956 Template:
956 Template:
957
957
958 The following keywords are supported in addition to the common template
958 The following keywords are supported in addition to the common template
959 keywords and functions such as ``{bookmark}``. See also
959 keywords and functions such as ``{bookmark}``. See also
960 :hg:`help templates`.
960 :hg:`help templates`.
961
961
962 :active: Boolean. True if the bookmark is active.
962 :active: Boolean. True if the bookmark is active.
963
963
964 Examples:
964 Examples:
965
965
966 - create an active bookmark for a new line of development::
966 - create an active bookmark for a new line of development::
967
967
968 hg book new-feature
968 hg book new-feature
969
969
970 - create an inactive bookmark as a place marker::
970 - create an inactive bookmark as a place marker::
971
971
972 hg book -i reviewed
972 hg book -i reviewed
973
973
974 - create an inactive bookmark on another changeset::
974 - create an inactive bookmark on another changeset::
975
975
976 hg book -r .^ tested
976 hg book -r .^ tested
977
977
978 - rename bookmark turkey to dinner::
978 - rename bookmark turkey to dinner::
979
979
980 hg book -m turkey dinner
980 hg book -m turkey dinner
981
981
982 - move the '@' bookmark from another branch::
982 - move the '@' bookmark from another branch::
983
983
984 hg book -f @
984 hg book -f @
985
985
986 - print only the active bookmark name::
986 - print only the active bookmark name::
987
987
988 hg book -ql .
988 hg book -ql .
989 '''
989 '''
990 opts = pycompat.byteskwargs(opts)
990 opts = pycompat.byteskwargs(opts)
991 force = opts.get('force')
991 force = opts.get('force')
992 rev = opts.get('rev')
992 rev = opts.get('rev')
993 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
993 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
994
994
995 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
995 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
996 if len(selactions) > 1:
996 if len(selactions) > 1:
997 raise error.Abort(_('--%s and --%s are incompatible')
997 raise error.Abort(_('--%s and --%s are incompatible')
998 % tuple(selactions[:2]))
998 % tuple(selactions[:2]))
999 if selactions:
999 if selactions:
1000 action = selactions[0]
1000 action = selactions[0]
1001 elif names or rev:
1001 elif names or rev:
1002 action = 'add'
1002 action = 'add'
1003 elif inactive:
1003 elif inactive:
1004 action = 'inactive' # meaning deactivate
1004 action = 'inactive' # meaning deactivate
1005 else:
1005 else:
1006 action = 'list'
1006 action = 'list'
1007
1007
1008 if rev and action in {'delete', 'rename', 'list'}:
1008 if rev and action in {'delete', 'rename', 'list'}:
1009 raise error.Abort(_("--rev is incompatible with --%s") % action)
1009 raise error.Abort(_("--rev is incompatible with --%s") % action)
1010 if inactive and action in {'delete', 'list'}:
1010 if inactive and action in {'delete', 'list'}:
1011 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1011 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1012 if not names and action in {'add', 'delete'}:
1012 if not names and action in {'add', 'delete'}:
1013 raise error.Abort(_("bookmark name required"))
1013 raise error.Abort(_("bookmark name required"))
1014
1014
1015 if action in {'add', 'delete', 'rename', 'inactive'}:
1015 if action in {'add', 'delete', 'rename', 'inactive'}:
1016 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1016 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1017 if action == 'delete':
1017 if action == 'delete':
1018 names = pycompat.maplist(repo._bookmarks.expandname, names)
1018 names = pycompat.maplist(repo._bookmarks.expandname, names)
1019 bookmarks.delete(repo, tr, names)
1019 bookmarks.delete(repo, tr, names)
1020 elif action == 'rename':
1020 elif action == 'rename':
1021 if not names:
1021 if not names:
1022 raise error.Abort(_("new bookmark name required"))
1022 raise error.Abort(_("new bookmark name required"))
1023 elif len(names) > 1:
1023 elif len(names) > 1:
1024 raise error.Abort(_("only one new bookmark name allowed"))
1024 raise error.Abort(_("only one new bookmark name allowed"))
1025 oldname = repo._bookmarks.expandname(opts['rename'])
1025 oldname = repo._bookmarks.expandname(opts['rename'])
1026 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1026 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1027 elif action == 'add':
1027 elif action == 'add':
1028 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1028 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1029 elif action == 'inactive':
1029 elif action == 'inactive':
1030 if len(repo._bookmarks) == 0:
1030 if len(repo._bookmarks) == 0:
1031 ui.status(_("no bookmarks set\n"))
1031 ui.status(_("no bookmarks set\n"))
1032 elif not repo._activebookmark:
1032 elif not repo._activebookmark:
1033 ui.status(_("no active bookmark\n"))
1033 ui.status(_("no active bookmark\n"))
1034 else:
1034 else:
1035 bookmarks.deactivate(repo)
1035 bookmarks.deactivate(repo)
1036 elif action == 'list':
1036 elif action == 'list':
1037 names = pycompat.maplist(repo._bookmarks.expandname, names)
1037 names = pycompat.maplist(repo._bookmarks.expandname, names)
1038 with ui.formatter('bookmarks', opts) as fm:
1038 with ui.formatter('bookmarks', opts) as fm:
1039 bookmarks.printbookmarks(ui, repo, fm, names)
1039 bookmarks.printbookmarks(ui, repo, fm, names)
1040 else:
1040 else:
1041 raise error.ProgrammingError('invalid action: %s' % action)
1041 raise error.ProgrammingError('invalid action: %s' % action)
1042
1042
1043 @command('branch',
1043 @command('branch',
1044 [('f', 'force', None,
1044 [('f', 'force', None,
1045 _('set branch name even if it shadows an existing branch')),
1045 _('set branch name even if it shadows an existing branch')),
1046 ('C', 'clean', None, _('reset branch name to parent branch name')),
1046 ('C', 'clean', None, _('reset branch name to parent branch name')),
1047 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1047 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1048 ],
1048 ],
1049 _('[-fC] [NAME]'))
1049 _('[-fC] [NAME]'))
1050 def branch(ui, repo, label=None, **opts):
1050 def branch(ui, repo, label=None, **opts):
1051 """set or show the current branch name
1051 """set or show the current branch name
1052
1052
1053 .. note::
1053 .. note::
1054
1054
1055 Branch names are permanent and global. Use :hg:`bookmark` to create a
1055 Branch names are permanent and global. Use :hg:`bookmark` to create a
1056 light-weight bookmark instead. See :hg:`help glossary` for more
1056 light-weight bookmark instead. See :hg:`help glossary` for more
1057 information about named branches and bookmarks.
1057 information about named branches and bookmarks.
1058
1058
1059 With no argument, show the current branch name. With one argument,
1059 With no argument, show the current branch name. With one argument,
1060 set the working directory branch name (the branch will not exist
1060 set the working directory branch name (the branch will not exist
1061 in the repository until the next commit). Standard practice
1061 in the repository until the next commit). Standard practice
1062 recommends that primary development take place on the 'default'
1062 recommends that primary development take place on the 'default'
1063 branch.
1063 branch.
1064
1064
1065 Unless -f/--force is specified, branch will not let you set a
1065 Unless -f/--force is specified, branch will not let you set a
1066 branch name that already exists.
1066 branch name that already exists.
1067
1067
1068 Use -C/--clean to reset the working directory branch to that of
1068 Use -C/--clean to reset the working directory branch to that of
1069 the parent of the working directory, negating a previous branch
1069 the parent of the working directory, negating a previous branch
1070 change.
1070 change.
1071
1071
1072 Use the command :hg:`update` to switch to an existing branch. Use
1072 Use the command :hg:`update` to switch to an existing branch. Use
1073 :hg:`commit --close-branch` to mark this branch head as closed.
1073 :hg:`commit --close-branch` to mark this branch head as closed.
1074 When all heads of a branch are closed, the branch will be
1074 When all heads of a branch are closed, the branch will be
1075 considered closed.
1075 considered closed.
1076
1076
1077 Returns 0 on success.
1077 Returns 0 on success.
1078 """
1078 """
1079 opts = pycompat.byteskwargs(opts)
1079 opts = pycompat.byteskwargs(opts)
1080 revs = opts.get('rev')
1080 revs = opts.get('rev')
1081 if label:
1081 if label:
1082 label = label.strip()
1082 label = label.strip()
1083
1083
1084 if not opts.get('clean') and not label:
1084 if not opts.get('clean') and not label:
1085 if revs:
1085 if revs:
1086 raise error.Abort(_("no branch name specified for the revisions"))
1086 raise error.Abort(_("no branch name specified for the revisions"))
1087 ui.write("%s\n" % repo.dirstate.branch())
1087 ui.write("%s\n" % repo.dirstate.branch())
1088 return
1088 return
1089
1089
1090 with repo.wlock():
1090 with repo.wlock():
1091 if opts.get('clean'):
1091 if opts.get('clean'):
1092 label = repo[None].p1().branch()
1092 label = repo[None].p1().branch()
1093 repo.dirstate.setbranch(label)
1093 repo.dirstate.setbranch(label)
1094 ui.status(_('reset working directory to branch %s\n') % label)
1094 ui.status(_('reset working directory to branch %s\n') % label)
1095 elif label:
1095 elif label:
1096
1096
1097 scmutil.checknewlabel(repo, label, 'branch')
1097 scmutil.checknewlabel(repo, label, 'branch')
1098 if revs:
1098 if revs:
1099 return cmdutil.changebranch(ui, repo, revs, label)
1099 return cmdutil.changebranch(ui, repo, revs, label)
1100
1100
1101 if not opts.get('force') and label in repo.branchmap():
1101 if not opts.get('force') and label in repo.branchmap():
1102 if label not in [p.branch() for p in repo[None].parents()]:
1102 if label not in [p.branch() for p in repo[None].parents()]:
1103 raise error.Abort(_('a branch of the same name already'
1103 raise error.Abort(_('a branch of the same name already'
1104 ' exists'),
1104 ' exists'),
1105 # i18n: "it" refers to an existing branch
1105 # i18n: "it" refers to an existing branch
1106 hint=_("use 'hg update' to switch to it"))
1106 hint=_("use 'hg update' to switch to it"))
1107
1107
1108 repo.dirstate.setbranch(label)
1108 repo.dirstate.setbranch(label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1110
1110
1111 # find any open named branches aside from default
1111 # find any open named branches aside from default
1112 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1112 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1113 if n != "default" and not c]
1113 if n != "default" and not c]
1114 if not others:
1114 if not others:
1115 ui.status(_('(branches are permanent and global, '
1115 ui.status(_('(branches are permanent and global, '
1116 'did you want a bookmark?)\n'))
1116 'did you want a bookmark?)\n'))
1117
1117
1118 @command('branches',
1118 @command('branches',
1119 [('a', 'active', False,
1119 [('a', 'active', False,
1120 _('show only branches that have unmerged heads (DEPRECATED)')),
1120 _('show only branches that have unmerged heads (DEPRECATED)')),
1121 ('c', 'closed', False, _('show normal and closed branches')),
1121 ('c', 'closed', False, _('show normal and closed branches')),
1122 ] + formatteropts,
1122 ] + formatteropts,
1123 _('[-c]'),
1123 _('[-c]'),
1124 intents={INTENT_READONLY})
1124 intents={INTENT_READONLY})
1125 def branches(ui, repo, active=False, closed=False, **opts):
1125 def branches(ui, repo, active=False, closed=False, **opts):
1126 """list repository named branches
1126 """list repository named branches
1127
1127
1128 List the repository's named branches, indicating which ones are
1128 List the repository's named branches, indicating which ones are
1129 inactive. If -c/--closed is specified, also list branches which have
1129 inactive. If -c/--closed is specified, also list branches which have
1130 been marked closed (see :hg:`commit --close-branch`).
1130 been marked closed (see :hg:`commit --close-branch`).
1131
1131
1132 Use the command :hg:`update` to switch to an existing branch.
1132 Use the command :hg:`update` to switch to an existing branch.
1133
1133
1134 .. container:: verbose
1134 .. container:: verbose
1135
1135
1136 Template:
1136 Template:
1137
1137
1138 The following keywords are supported in addition to the common template
1138 The following keywords are supported in addition to the common template
1139 keywords and functions such as ``{branch}``. See also
1139 keywords and functions such as ``{branch}``. See also
1140 :hg:`help templates`.
1140 :hg:`help templates`.
1141
1141
1142 :active: Boolean. True if the branch is active.
1142 :active: Boolean. True if the branch is active.
1143 :closed: Boolean. True if the branch is closed.
1143 :closed: Boolean. True if the branch is closed.
1144 :current: Boolean. True if it is the current branch.
1144 :current: Boolean. True if it is the current branch.
1145
1145
1146 Returns 0.
1146 Returns 0.
1147 """
1147 """
1148
1148
1149 opts = pycompat.byteskwargs(opts)
1149 opts = pycompat.byteskwargs(opts)
1150 ui.pager('branches')
1150 ui.pager('branches')
1151 fm = ui.formatter('branches', opts)
1151 fm = ui.formatter('branches', opts)
1152 hexfunc = fm.hexfunc
1152 hexfunc = fm.hexfunc
1153
1153
1154 allheads = set(repo.heads())
1154 allheads = set(repo.heads())
1155 branches = []
1155 branches = []
1156 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1156 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1157 isactive = False
1157 isactive = False
1158 if not isclosed:
1158 if not isclosed:
1159 openheads = set(repo.branchmap().iteropen(heads))
1159 openheads = set(repo.branchmap().iteropen(heads))
1160 isactive = bool(openheads & allheads)
1160 isactive = bool(openheads & allheads)
1161 branches.append((tag, repo[tip], isactive, not isclosed))
1161 branches.append((tag, repo[tip], isactive, not isclosed))
1162 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1162 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1163 reverse=True)
1163 reverse=True)
1164
1164
1165 for tag, ctx, isactive, isopen in branches:
1165 for tag, ctx, isactive, isopen in branches:
1166 if active and not isactive:
1166 if active and not isactive:
1167 continue
1167 continue
1168 if isactive:
1168 if isactive:
1169 label = 'branches.active'
1169 label = 'branches.active'
1170 notice = ''
1170 notice = ''
1171 elif not isopen:
1171 elif not isopen:
1172 if not closed:
1172 if not closed:
1173 continue
1173 continue
1174 label = 'branches.closed'
1174 label = 'branches.closed'
1175 notice = _(' (closed)')
1175 notice = _(' (closed)')
1176 else:
1176 else:
1177 label = 'branches.inactive'
1177 label = 'branches.inactive'
1178 notice = _(' (inactive)')
1178 notice = _(' (inactive)')
1179 current = (tag == repo.dirstate.branch())
1179 current = (tag == repo.dirstate.branch())
1180 if current:
1180 if current:
1181 label = 'branches.current'
1181 label = 'branches.current'
1182
1182
1183 fm.startitem()
1183 fm.startitem()
1184 fm.write('branch', '%s', tag, label=label)
1184 fm.write('branch', '%s', tag, label=label)
1185 rev = ctx.rev()
1185 rev = ctx.rev()
1186 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1186 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1187 fmt = ' ' * padsize + ' %d:%s'
1187 fmt = ' ' * padsize + ' %d:%s'
1188 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1188 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1189 label='log.changeset changeset.%s' % ctx.phasestr())
1189 label='log.changeset changeset.%s' % ctx.phasestr())
1190 fm.context(ctx=ctx)
1190 fm.context(ctx=ctx)
1191 fm.data(active=isactive, closed=not isopen, current=current)
1191 fm.data(active=isactive, closed=not isopen, current=current)
1192 if not ui.quiet:
1192 if not ui.quiet:
1193 fm.plain(notice)
1193 fm.plain(notice)
1194 fm.plain('\n')
1194 fm.plain('\n')
1195 fm.end()
1195 fm.end()
1196
1196
1197 @command('bundle',
1197 @command('bundle',
1198 [('f', 'force', None, _('run even when the destination is unrelated')),
1198 [('f', 'force', None, _('run even when the destination is unrelated')),
1199 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1199 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1200 _('REV')),
1200 _('REV')),
1201 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1201 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1202 _('BRANCH')),
1202 _('BRANCH')),
1203 ('', 'base', [],
1203 ('', 'base', [],
1204 _('a base changeset assumed to be available at the destination'),
1204 _('a base changeset assumed to be available at the destination'),
1205 _('REV')),
1205 _('REV')),
1206 ('a', 'all', None, _('bundle all changesets in the repository')),
1206 ('a', 'all', None, _('bundle all changesets in the repository')),
1207 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1207 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1208 ] + remoteopts,
1208 ] + remoteopts,
1209 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1209 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1210 def bundle(ui, repo, fname, dest=None, **opts):
1210 def bundle(ui, repo, fname, dest=None, **opts):
1211 """create a bundle file
1211 """create a bundle file
1212
1212
1213 Generate a bundle file containing data to be transferred to another
1213 Generate a bundle file containing data to be transferred to another
1214 repository.
1214 repository.
1215
1215
1216 To create a bundle containing all changesets, use -a/--all
1216 To create a bundle containing all changesets, use -a/--all
1217 (or --base null). Otherwise, hg assumes the destination will have
1217 (or --base null). Otherwise, hg assumes the destination will have
1218 all the nodes you specify with --base parameters. Otherwise, hg
1218 all the nodes you specify with --base parameters. Otherwise, hg
1219 will assume the repository has all the nodes in destination, or
1219 will assume the repository has all the nodes in destination, or
1220 default-push/default if no destination is specified, where destination
1220 default-push/default if no destination is specified, where destination
1221 is the repository you provide through DEST option.
1221 is the repository you provide through DEST option.
1222
1222
1223 You can change bundle format with the -t/--type option. See
1223 You can change bundle format with the -t/--type option. See
1224 :hg:`help bundlespec` for documentation on this format. By default,
1224 :hg:`help bundlespec` for documentation on this format. By default,
1225 the most appropriate format is used and compression defaults to
1225 the most appropriate format is used and compression defaults to
1226 bzip2.
1226 bzip2.
1227
1227
1228 The bundle file can then be transferred using conventional means
1228 The bundle file can then be transferred using conventional means
1229 and applied to another repository with the unbundle or pull
1229 and applied to another repository with the unbundle or pull
1230 command. This is useful when direct push and pull are not
1230 command. This is useful when direct push and pull are not
1231 available or when exporting an entire repository is undesirable.
1231 available or when exporting an entire repository is undesirable.
1232
1232
1233 Applying bundles preserves all changeset contents including
1233 Applying bundles preserves all changeset contents including
1234 permissions, copy/rename information, and revision history.
1234 permissions, copy/rename information, and revision history.
1235
1235
1236 Returns 0 on success, 1 if no changes found.
1236 Returns 0 on success, 1 if no changes found.
1237 """
1237 """
1238 opts = pycompat.byteskwargs(opts)
1238 opts = pycompat.byteskwargs(opts)
1239 revs = None
1239 revs = None
1240 if 'rev' in opts:
1240 if 'rev' in opts:
1241 revstrings = opts['rev']
1241 revstrings = opts['rev']
1242 revs = scmutil.revrange(repo, revstrings)
1242 revs = scmutil.revrange(repo, revstrings)
1243 if revstrings and not revs:
1243 if revstrings and not revs:
1244 raise error.Abort(_('no commits to bundle'))
1244 raise error.Abort(_('no commits to bundle'))
1245
1245
1246 bundletype = opts.get('type', 'bzip2').lower()
1246 bundletype = opts.get('type', 'bzip2').lower()
1247 try:
1247 try:
1248 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1248 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1249 except error.UnsupportedBundleSpecification as e:
1249 except error.UnsupportedBundleSpecification as e:
1250 raise error.Abort(pycompat.bytestr(e),
1250 raise error.Abort(pycompat.bytestr(e),
1251 hint=_("see 'hg help bundlespec' for supported "
1251 hint=_("see 'hg help bundlespec' for supported "
1252 "values for --type"))
1252 "values for --type"))
1253 cgversion = bundlespec.contentopts["cg.version"]
1253 cgversion = bundlespec.contentopts["cg.version"]
1254
1254
1255 # Packed bundles are a pseudo bundle format for now.
1255 # Packed bundles are a pseudo bundle format for now.
1256 if cgversion == 's1':
1256 if cgversion == 's1':
1257 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1257 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1258 hint=_("use 'hg debugcreatestreamclonebundle'"))
1258 hint=_("use 'hg debugcreatestreamclonebundle'"))
1259
1259
1260 if opts.get('all'):
1260 if opts.get('all'):
1261 if dest:
1261 if dest:
1262 raise error.Abort(_("--all is incompatible with specifying "
1262 raise error.Abort(_("--all is incompatible with specifying "
1263 "a destination"))
1263 "a destination"))
1264 if opts.get('base'):
1264 if opts.get('base'):
1265 ui.warn(_("ignoring --base because --all was specified\n"))
1265 ui.warn(_("ignoring --base because --all was specified\n"))
1266 base = [nullrev]
1266 base = [nullrev]
1267 else:
1267 else:
1268 base = scmutil.revrange(repo, opts.get('base'))
1268 base = scmutil.revrange(repo, opts.get('base'))
1269 if cgversion not in changegroup.supportedoutgoingversions(repo):
1269 if cgversion not in changegroup.supportedoutgoingversions(repo):
1270 raise error.Abort(_("repository does not support bundle version %s") %
1270 raise error.Abort(_("repository does not support bundle version %s") %
1271 cgversion)
1271 cgversion)
1272
1272
1273 if base:
1273 if base:
1274 if dest:
1274 if dest:
1275 raise error.Abort(_("--base is incompatible with specifying "
1275 raise error.Abort(_("--base is incompatible with specifying "
1276 "a destination"))
1276 "a destination"))
1277 common = [repo[rev].node() for rev in base]
1277 common = [repo[rev].node() for rev in base]
1278 heads = [repo[r].node() for r in revs] if revs else None
1278 heads = [repo[r].node() for r in revs] if revs else None
1279 outgoing = discovery.outgoing(repo, common, heads)
1279 outgoing = discovery.outgoing(repo, common, heads)
1280 else:
1280 else:
1281 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1281 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1282 dest, branches = hg.parseurl(dest, opts.get('branch'))
1282 dest, branches = hg.parseurl(dest, opts.get('branch'))
1283 other = hg.peer(repo, opts, dest)
1283 other = hg.peer(repo, opts, dest)
1284 revs = [repo[r].hex() for r in revs]
1284 revs = [repo[r].hex() for r in revs]
1285 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1285 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1286 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1286 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1287 outgoing = discovery.findcommonoutgoing(repo, other,
1287 outgoing = discovery.findcommonoutgoing(repo, other,
1288 onlyheads=heads,
1288 onlyheads=heads,
1289 force=opts.get('force'),
1289 force=opts.get('force'),
1290 portable=True)
1290 portable=True)
1291
1291
1292 if not outgoing.missing:
1292 if not outgoing.missing:
1293 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1293 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1294 return 1
1294 return 1
1295
1295
1296 if cgversion == '01': #bundle1
1296 if cgversion == '01': #bundle1
1297 bversion = 'HG10' + bundlespec.wirecompression
1297 bversion = 'HG10' + bundlespec.wirecompression
1298 bcompression = None
1298 bcompression = None
1299 elif cgversion in ('02', '03'):
1299 elif cgversion in ('02', '03'):
1300 bversion = 'HG20'
1300 bversion = 'HG20'
1301 bcompression = bundlespec.wirecompression
1301 bcompression = bundlespec.wirecompression
1302 else:
1302 else:
1303 raise error.ProgrammingError(
1303 raise error.ProgrammingError(
1304 'bundle: unexpected changegroup version %s' % cgversion)
1304 'bundle: unexpected changegroup version %s' % cgversion)
1305
1305
1306 # TODO compression options should be derived from bundlespec parsing.
1306 # TODO compression options should be derived from bundlespec parsing.
1307 # This is a temporary hack to allow adjusting bundle compression
1307 # This is a temporary hack to allow adjusting bundle compression
1308 # level without a) formalizing the bundlespec changes to declare it
1308 # level without a) formalizing the bundlespec changes to declare it
1309 # b) introducing a command flag.
1309 # b) introducing a command flag.
1310 compopts = {}
1310 compopts = {}
1311 complevel = ui.configint('experimental',
1311 complevel = ui.configint('experimental',
1312 'bundlecomplevel.' + bundlespec.compression)
1312 'bundlecomplevel.' + bundlespec.compression)
1313 if complevel is None:
1313 if complevel is None:
1314 complevel = ui.configint('experimental', 'bundlecomplevel')
1314 complevel = ui.configint('experimental', 'bundlecomplevel')
1315 if complevel is not None:
1315 if complevel is not None:
1316 compopts['level'] = complevel
1316 compopts['level'] = complevel
1317
1317
1318 # Allow overriding the bundling of obsmarker in phases through
1318 # Allow overriding the bundling of obsmarker in phases through
1319 # configuration while we don't have a bundle version that include them
1319 # configuration while we don't have a bundle version that include them
1320 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1320 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1321 bundlespec.contentopts['obsolescence'] = True
1321 bundlespec.contentopts['obsolescence'] = True
1322 if repo.ui.configbool('experimental', 'bundle-phases'):
1322 if repo.ui.configbool('experimental', 'bundle-phases'):
1323 bundlespec.contentopts['phases'] = True
1323 bundlespec.contentopts['phases'] = True
1324
1324
1325 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1325 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1326 bundlespec.contentopts, compression=bcompression,
1326 bundlespec.contentopts, compression=bcompression,
1327 compopts=compopts)
1327 compopts=compopts)
1328
1328
1329 @command('cat',
1329 @command('cat',
1330 [('o', 'output', '',
1330 [('o', 'output', '',
1331 _('print output to file with formatted name'), _('FORMAT')),
1331 _('print output to file with formatted name'), _('FORMAT')),
1332 ('r', 'rev', '', _('print the given revision'), _('REV')),
1332 ('r', 'rev', '', _('print the given revision'), _('REV')),
1333 ('', 'decode', None, _('apply any matching decode filter')),
1333 ('', 'decode', None, _('apply any matching decode filter')),
1334 ] + walkopts + formatteropts,
1334 ] + walkopts + formatteropts,
1335 _('[OPTION]... FILE...'),
1335 _('[OPTION]... FILE...'),
1336 inferrepo=True,
1336 inferrepo=True,
1337 intents={INTENT_READONLY})
1337 intents={INTENT_READONLY})
1338 def cat(ui, repo, file1, *pats, **opts):
1338 def cat(ui, repo, file1, *pats, **opts):
1339 """output the current or given revision of files
1339 """output the current or given revision of files
1340
1340
1341 Print the specified files as they were at the given revision. If
1341 Print the specified files as they were at the given revision. If
1342 no revision is given, the parent of the working directory is used.
1342 no revision is given, the parent of the working directory is used.
1343
1343
1344 Output may be to a file, in which case the name of the file is
1344 Output may be to a file, in which case the name of the file is
1345 given using a template string. See :hg:`help templates`. In addition
1345 given using a template string. See :hg:`help templates`. In addition
1346 to the common template keywords, the following formatting rules are
1346 to the common template keywords, the following formatting rules are
1347 supported:
1347 supported:
1348
1348
1349 :``%%``: literal "%" character
1349 :``%%``: literal "%" character
1350 :``%s``: basename of file being printed
1350 :``%s``: basename of file being printed
1351 :``%d``: dirname of file being printed, or '.' if in repository root
1351 :``%d``: dirname of file being printed, or '.' if in repository root
1352 :``%p``: root-relative path name of file being printed
1352 :``%p``: root-relative path name of file being printed
1353 :``%H``: changeset hash (40 hexadecimal digits)
1353 :``%H``: changeset hash (40 hexadecimal digits)
1354 :``%R``: changeset revision number
1354 :``%R``: changeset revision number
1355 :``%h``: short-form changeset hash (12 hexadecimal digits)
1355 :``%h``: short-form changeset hash (12 hexadecimal digits)
1356 :``%r``: zero-padded changeset revision number
1356 :``%r``: zero-padded changeset revision number
1357 :``%b``: basename of the exporting repository
1357 :``%b``: basename of the exporting repository
1358 :``\\``: literal "\\" character
1358 :``\\``: literal "\\" character
1359
1359
1360 .. container:: verbose
1360 .. container:: verbose
1361
1361
1362 Template:
1362 Template:
1363
1363
1364 The following keywords are supported in addition to the common template
1364 The following keywords are supported in addition to the common template
1365 keywords and functions. See also :hg:`help templates`.
1365 keywords and functions. See also :hg:`help templates`.
1366
1366
1367 :data: String. File content.
1367 :data: String. File content.
1368 :path: String. Repository-absolute path of the file.
1368 :path: String. Repository-absolute path of the file.
1369
1369
1370 Returns 0 on success.
1370 Returns 0 on success.
1371 """
1371 """
1372 opts = pycompat.byteskwargs(opts)
1372 opts = pycompat.byteskwargs(opts)
1373 rev = opts.get('rev')
1373 rev = opts.get('rev')
1374 if rev:
1374 if rev:
1375 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1375 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1376 ctx = scmutil.revsingle(repo, rev)
1376 ctx = scmutil.revsingle(repo, rev)
1377 m = scmutil.match(ctx, (file1,) + pats, opts)
1377 m = scmutil.match(ctx, (file1,) + pats, opts)
1378 fntemplate = opts.pop('output', '')
1378 fntemplate = opts.pop('output', '')
1379 if cmdutil.isstdiofilename(fntemplate):
1379 if cmdutil.isstdiofilename(fntemplate):
1380 fntemplate = ''
1380 fntemplate = ''
1381
1381
1382 if fntemplate:
1382 if fntemplate:
1383 fm = formatter.nullformatter(ui, 'cat', opts)
1383 fm = formatter.nullformatter(ui, 'cat', opts)
1384 else:
1384 else:
1385 ui.pager('cat')
1385 ui.pager('cat')
1386 fm = ui.formatter('cat', opts)
1386 fm = ui.formatter('cat', opts)
1387 with fm:
1387 with fm:
1388 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1388 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1389 **pycompat.strkwargs(opts))
1389 **pycompat.strkwargs(opts))
1390
1390
1391 @command('^clone',
1391 @command('^clone',
1392 [('U', 'noupdate', None, _('the clone will include an empty working '
1392 [('U', 'noupdate', None, _('the clone will include an empty working '
1393 'directory (only a repository)')),
1393 'directory (only a repository)')),
1394 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1394 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1395 _('REV')),
1395 _('REV')),
1396 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1396 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1397 ' and its ancestors'), _('REV')),
1397 ' and its ancestors'), _('REV')),
1398 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1398 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1399 ' changesets and their ancestors'), _('BRANCH')),
1399 ' changesets and their ancestors'), _('BRANCH')),
1400 ('', 'pull', None, _('use pull protocol to copy metadata')),
1400 ('', 'pull', None, _('use pull protocol to copy metadata')),
1401 ('', 'uncompressed', None,
1401 ('', 'uncompressed', None,
1402 _('an alias to --stream (DEPRECATED)')),
1402 _('an alias to --stream (DEPRECATED)')),
1403 ('', 'stream', None,
1403 ('', 'stream', None,
1404 _('clone with minimal data processing')),
1404 _('clone with minimal data processing')),
1405 ] + remoteopts,
1405 ] + remoteopts,
1406 _('[OPTION]... SOURCE [DEST]'),
1406 _('[OPTION]... SOURCE [DEST]'),
1407 norepo=True)
1407 norepo=True)
1408 def clone(ui, source, dest=None, **opts):
1408 def clone(ui, source, dest=None, **opts):
1409 """make a copy of an existing repository
1409 """make a copy of an existing repository
1410
1410
1411 Create a copy of an existing repository in a new directory.
1411 Create a copy of an existing repository in a new directory.
1412
1412
1413 If no destination directory name is specified, it defaults to the
1413 If no destination directory name is specified, it defaults to the
1414 basename of the source.
1414 basename of the source.
1415
1415
1416 The location of the source is added to the new repository's
1416 The location of the source is added to the new repository's
1417 ``.hg/hgrc`` file, as the default to be used for future pulls.
1417 ``.hg/hgrc`` file, as the default to be used for future pulls.
1418
1418
1419 Only local paths and ``ssh://`` URLs are supported as
1419 Only local paths and ``ssh://`` URLs are supported as
1420 destinations. For ``ssh://`` destinations, no working directory or
1420 destinations. For ``ssh://`` destinations, no working directory or
1421 ``.hg/hgrc`` will be created on the remote side.
1421 ``.hg/hgrc`` will be created on the remote side.
1422
1422
1423 If the source repository has a bookmark called '@' set, that
1423 If the source repository has a bookmark called '@' set, that
1424 revision will be checked out in the new repository by default.
1424 revision will be checked out in the new repository by default.
1425
1425
1426 To check out a particular version, use -u/--update, or
1426 To check out a particular version, use -u/--update, or
1427 -U/--noupdate to create a clone with no working directory.
1427 -U/--noupdate to create a clone with no working directory.
1428
1428
1429 To pull only a subset of changesets, specify one or more revisions
1429 To pull only a subset of changesets, specify one or more revisions
1430 identifiers with -r/--rev or branches with -b/--branch. The
1430 identifiers with -r/--rev or branches with -b/--branch. The
1431 resulting clone will contain only the specified changesets and
1431 resulting clone will contain only the specified changesets and
1432 their ancestors. These options (or 'clone src#rev dest') imply
1432 their ancestors. These options (or 'clone src#rev dest') imply
1433 --pull, even for local source repositories.
1433 --pull, even for local source repositories.
1434
1434
1435 In normal clone mode, the remote normalizes repository data into a common
1435 In normal clone mode, the remote normalizes repository data into a common
1436 exchange format and the receiving end translates this data into its local
1436 exchange format and the receiving end translates this data into its local
1437 storage format. --stream activates a different clone mode that essentially
1437 storage format. --stream activates a different clone mode that essentially
1438 copies repository files from the remote with minimal data processing. This
1438 copies repository files from the remote with minimal data processing. This
1439 significantly reduces the CPU cost of a clone both remotely and locally.
1439 significantly reduces the CPU cost of a clone both remotely and locally.
1440 However, it often increases the transferred data size by 30-40%. This can
1440 However, it often increases the transferred data size by 30-40%. This can
1441 result in substantially faster clones where I/O throughput is plentiful,
1441 result in substantially faster clones where I/O throughput is plentiful,
1442 especially for larger repositories. A side-effect of --stream clones is
1442 especially for larger repositories. A side-effect of --stream clones is
1443 that storage settings and requirements on the remote are applied locally:
1443 that storage settings and requirements on the remote are applied locally:
1444 a modern client may inherit legacy or inefficient storage used by the
1444 a modern client may inherit legacy or inefficient storage used by the
1445 remote or a legacy Mercurial client may not be able to clone from a
1445 remote or a legacy Mercurial client may not be able to clone from a
1446 modern Mercurial remote.
1446 modern Mercurial remote.
1447
1447
1448 .. note::
1448 .. note::
1449
1449
1450 Specifying a tag will include the tagged changeset but not the
1450 Specifying a tag will include the tagged changeset but not the
1451 changeset containing the tag.
1451 changeset containing the tag.
1452
1452
1453 .. container:: verbose
1453 .. container:: verbose
1454
1454
1455 For efficiency, hardlinks are used for cloning whenever the
1455 For efficiency, hardlinks are used for cloning whenever the
1456 source and destination are on the same filesystem (note this
1456 source and destination are on the same filesystem (note this
1457 applies only to the repository data, not to the working
1457 applies only to the repository data, not to the working
1458 directory). Some filesystems, such as AFS, implement hardlinking
1458 directory). Some filesystems, such as AFS, implement hardlinking
1459 incorrectly, but do not report errors. In these cases, use the
1459 incorrectly, but do not report errors. In these cases, use the
1460 --pull option to avoid hardlinking.
1460 --pull option to avoid hardlinking.
1461
1461
1462 Mercurial will update the working directory to the first applicable
1462 Mercurial will update the working directory to the first applicable
1463 revision from this list:
1463 revision from this list:
1464
1464
1465 a) null if -U or the source repository has no changesets
1465 a) null if -U or the source repository has no changesets
1466 b) if -u . and the source repository is local, the first parent of
1466 b) if -u . and the source repository is local, the first parent of
1467 the source repository's working directory
1467 the source repository's working directory
1468 c) the changeset specified with -u (if a branch name, this means the
1468 c) the changeset specified with -u (if a branch name, this means the
1469 latest head of that branch)
1469 latest head of that branch)
1470 d) the changeset specified with -r
1470 d) the changeset specified with -r
1471 e) the tipmost head specified with -b
1471 e) the tipmost head specified with -b
1472 f) the tipmost head specified with the url#branch source syntax
1472 f) the tipmost head specified with the url#branch source syntax
1473 g) the revision marked with the '@' bookmark, if present
1473 g) the revision marked with the '@' bookmark, if present
1474 h) the tipmost head of the default branch
1474 h) the tipmost head of the default branch
1475 i) tip
1475 i) tip
1476
1476
1477 When cloning from servers that support it, Mercurial may fetch
1477 When cloning from servers that support it, Mercurial may fetch
1478 pre-generated data from a server-advertised URL or inline from the
1478 pre-generated data from a server-advertised URL or inline from the
1479 same stream. When this is done, hooks operating on incoming changesets
1479 same stream. When this is done, hooks operating on incoming changesets
1480 and changegroups may fire more than once, once for each pre-generated
1480 and changegroups may fire more than once, once for each pre-generated
1481 bundle and as well as for any additional remaining data. In addition,
1481 bundle and as well as for any additional remaining data. In addition,
1482 if an error occurs, the repository may be rolled back to a partial
1482 if an error occurs, the repository may be rolled back to a partial
1483 clone. This behavior may change in future releases.
1483 clone. This behavior may change in future releases.
1484 See :hg:`help -e clonebundles` for more.
1484 See :hg:`help -e clonebundles` for more.
1485
1485
1486 Examples:
1486 Examples:
1487
1487
1488 - clone a remote repository to a new directory named hg/::
1488 - clone a remote repository to a new directory named hg/::
1489
1489
1490 hg clone https://www.mercurial-scm.org/repo/hg/
1490 hg clone https://www.mercurial-scm.org/repo/hg/
1491
1491
1492 - create a lightweight local clone::
1492 - create a lightweight local clone::
1493
1493
1494 hg clone project/ project-feature/
1494 hg clone project/ project-feature/
1495
1495
1496 - clone from an absolute path on an ssh server (note double-slash)::
1496 - clone from an absolute path on an ssh server (note double-slash)::
1497
1497
1498 hg clone ssh://user@server//home/projects/alpha/
1498 hg clone ssh://user@server//home/projects/alpha/
1499
1499
1500 - do a streaming clone while checking out a specified version::
1500 - do a streaming clone while checking out a specified version::
1501
1501
1502 hg clone --stream http://server/repo -u 1.5
1502 hg clone --stream http://server/repo -u 1.5
1503
1503
1504 - create a repository without changesets after a particular revision::
1504 - create a repository without changesets after a particular revision::
1505
1505
1506 hg clone -r 04e544 experimental/ good/
1506 hg clone -r 04e544 experimental/ good/
1507
1507
1508 - clone (and track) a particular named branch::
1508 - clone (and track) a particular named branch::
1509
1509
1510 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1510 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1511
1511
1512 See :hg:`help urls` for details on specifying URLs.
1512 See :hg:`help urls` for details on specifying URLs.
1513
1513
1514 Returns 0 on success.
1514 Returns 0 on success.
1515 """
1515 """
1516 opts = pycompat.byteskwargs(opts)
1516 opts = pycompat.byteskwargs(opts)
1517 if opts.get('noupdate') and opts.get('updaterev'):
1517 if opts.get('noupdate') and opts.get('updaterev'):
1518 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1518 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1519
1519
1520 # --include/--exclude can come from narrow or sparse.
1520 # --include/--exclude can come from narrow or sparse.
1521 includepats, excludepats = None, None
1521 includepats, excludepats = None, None
1522
1522
1523 # hg.clone() differentiates between None and an empty set. So make sure
1523 # hg.clone() differentiates between None and an empty set. So make sure
1524 # patterns are sets if narrow is requested without patterns.
1524 # patterns are sets if narrow is requested without patterns.
1525 if opts.get('narrow'):
1525 if opts.get('narrow'):
1526 includepats = set()
1526 includepats = set()
1527 excludepats = set()
1527 excludepats = set()
1528
1528
1529 if opts.get('include'):
1529 if opts.get('include'):
1530 includepats = narrowspec.parsepatterns(opts.get('include'))
1530 includepats = narrowspec.parsepatterns(opts.get('include'))
1531 if opts.get('exclude'):
1531 if opts.get('exclude'):
1532 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1532 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1533
1533
1534 r = hg.clone(ui, opts, source, dest,
1534 r = hg.clone(ui, opts, source, dest,
1535 pull=opts.get('pull'),
1535 pull=opts.get('pull'),
1536 stream=opts.get('stream') or opts.get('uncompressed'),
1536 stream=opts.get('stream') or opts.get('uncompressed'),
1537 revs=opts.get('rev'),
1537 revs=opts.get('rev'),
1538 update=opts.get('updaterev') or not opts.get('noupdate'),
1538 update=opts.get('updaterev') or not opts.get('noupdate'),
1539 branch=opts.get('branch'),
1539 branch=opts.get('branch'),
1540 shareopts=opts.get('shareopts'),
1540 shareopts=opts.get('shareopts'),
1541 storeincludepats=includepats,
1541 storeincludepats=includepats,
1542 storeexcludepats=excludepats)
1542 storeexcludepats=excludepats)
1543
1543
1544 return r is None
1544 return r is None
1545
1545
1546 @command('^commit|ci',
1546 @command('^commit|ci',
1547 [('A', 'addremove', None,
1547 [('A', 'addremove', None,
1548 _('mark new/missing files as added/removed before committing')),
1548 _('mark new/missing files as added/removed before committing')),
1549 ('', 'close-branch', None,
1549 ('', 'close-branch', None,
1550 _('mark a branch head as closed')),
1550 _('mark a branch head as closed')),
1551 ('', 'amend', None, _('amend the parent of the working directory')),
1551 ('', 'amend', None, _('amend the parent of the working directory')),
1552 ('s', 'secret', None, _('use the secret phase for committing')),
1552 ('s', 'secret', None, _('use the secret phase for committing')),
1553 ('e', 'edit', None, _('invoke editor on commit messages')),
1553 ('e', 'edit', None, _('invoke editor on commit messages')),
1554 ('i', 'interactive', None, _('use interactive mode')),
1554 ('i', 'interactive', None, _('use interactive mode')),
1555 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1555 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1556 _('[OPTION]... [FILE]...'),
1556 _('[OPTION]... [FILE]...'),
1557 inferrepo=True)
1557 inferrepo=True)
1558 def commit(ui, repo, *pats, **opts):
1558 def commit(ui, repo, *pats, **opts):
1559 """commit the specified files or all outstanding changes
1559 """commit the specified files or all outstanding changes
1560
1560
1561 Commit changes to the given files into the repository. Unlike a
1561 Commit changes to the given files into the repository. Unlike a
1562 centralized SCM, this operation is a local operation. See
1562 centralized SCM, this operation is a local operation. See
1563 :hg:`push` for a way to actively distribute your changes.
1563 :hg:`push` for a way to actively distribute your changes.
1564
1564
1565 If a list of files is omitted, all changes reported by :hg:`status`
1565 If a list of files is omitted, all changes reported by :hg:`status`
1566 will be committed.
1566 will be committed.
1567
1567
1568 If you are committing the result of a merge, do not provide any
1568 If you are committing the result of a merge, do not provide any
1569 filenames or -I/-X filters.
1569 filenames or -I/-X filters.
1570
1570
1571 If no commit message is specified, Mercurial starts your
1571 If no commit message is specified, Mercurial starts your
1572 configured editor where you can enter a message. In case your
1572 configured editor where you can enter a message. In case your
1573 commit fails, you will find a backup of your message in
1573 commit fails, you will find a backup of your message in
1574 ``.hg/last-message.txt``.
1574 ``.hg/last-message.txt``.
1575
1575
1576 The --close-branch flag can be used to mark the current branch
1576 The --close-branch flag can be used to mark the current branch
1577 head closed. When all heads of a branch are closed, the branch
1577 head closed. When all heads of a branch are closed, the branch
1578 will be considered closed and no longer listed.
1578 will be considered closed and no longer listed.
1579
1579
1580 The --amend flag can be used to amend the parent of the
1580 The --amend flag can be used to amend the parent of the
1581 working directory with a new commit that contains the changes
1581 working directory with a new commit that contains the changes
1582 in the parent in addition to those currently reported by :hg:`status`,
1582 in the parent in addition to those currently reported by :hg:`status`,
1583 if there are any. The old commit is stored in a backup bundle in
1583 if there are any. The old commit is stored in a backup bundle in
1584 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1584 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1585 on how to restore it).
1585 on how to restore it).
1586
1586
1587 Message, user and date are taken from the amended commit unless
1587 Message, user and date are taken from the amended commit unless
1588 specified. When a message isn't specified on the command line,
1588 specified. When a message isn't specified on the command line,
1589 the editor will open with the message of the amended commit.
1589 the editor will open with the message of the amended commit.
1590
1590
1591 It is not possible to amend public changesets (see :hg:`help phases`)
1591 It is not possible to amend public changesets (see :hg:`help phases`)
1592 or changesets that have children.
1592 or changesets that have children.
1593
1593
1594 See :hg:`help dates` for a list of formats valid for -d/--date.
1594 See :hg:`help dates` for a list of formats valid for -d/--date.
1595
1595
1596 Returns 0 on success, 1 if nothing changed.
1596 Returns 0 on success, 1 if nothing changed.
1597
1597
1598 .. container:: verbose
1598 .. container:: verbose
1599
1599
1600 Examples:
1600 Examples:
1601
1601
1602 - commit all files ending in .py::
1602 - commit all files ending in .py::
1603
1603
1604 hg commit --include "set:**.py"
1604 hg commit --include "set:**.py"
1605
1605
1606 - commit all non-binary files::
1606 - commit all non-binary files::
1607
1607
1608 hg commit --exclude "set:binary()"
1608 hg commit --exclude "set:binary()"
1609
1609
1610 - amend the current commit and set the date to now::
1610 - amend the current commit and set the date to now::
1611
1611
1612 hg commit --amend --date now
1612 hg commit --amend --date now
1613 """
1613 """
1614 with repo.wlock(), repo.lock():
1614 with repo.wlock(), repo.lock():
1615 return _docommit(ui, repo, *pats, **opts)
1615 return _docommit(ui, repo, *pats, **opts)
1616
1616
1617 def _docommit(ui, repo, *pats, **opts):
1617 def _docommit(ui, repo, *pats, **opts):
1618 if opts.get(r'interactive'):
1618 if opts.get(r'interactive'):
1619 opts.pop(r'interactive')
1619 opts.pop(r'interactive')
1620 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1620 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1621 cmdutil.recordfilter, *pats,
1621 cmdutil.recordfilter, *pats,
1622 **opts)
1622 **opts)
1623 # ret can be 0 (no changes to record) or the value returned by
1623 # ret can be 0 (no changes to record) or the value returned by
1624 # commit(), 1 if nothing changed or None on success.
1624 # commit(), 1 if nothing changed or None on success.
1625 return 1 if ret == 0 else ret
1625 return 1 if ret == 0 else ret
1626
1626
1627 opts = pycompat.byteskwargs(opts)
1627 opts = pycompat.byteskwargs(opts)
1628 if opts.get('subrepos'):
1628 if opts.get('subrepos'):
1629 if opts.get('amend'):
1629 if opts.get('amend'):
1630 raise error.Abort(_('cannot amend with --subrepos'))
1630 raise error.Abort(_('cannot amend with --subrepos'))
1631 # Let --subrepos on the command line override config setting.
1631 # Let --subrepos on the command line override config setting.
1632 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1632 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1633
1633
1634 cmdutil.checkunfinished(repo, commit=True)
1634 cmdutil.checkunfinished(repo, commit=True)
1635
1635
1636 branch = repo[None].branch()
1636 branch = repo[None].branch()
1637 bheads = repo.branchheads(branch)
1637 bheads = repo.branchheads(branch)
1638
1638
1639 extra = {}
1639 extra = {}
1640 if opts.get('close_branch'):
1640 if opts.get('close_branch'):
1641 extra['close'] = '1'
1641 extra['close'] = '1'
1642
1642
1643 if not bheads:
1643 if not bheads:
1644 raise error.Abort(_('can only close branch heads'))
1644 raise error.Abort(_('can only close branch heads'))
1645 elif opts.get('amend'):
1645 elif opts.get('amend'):
1646 if repo[None].parents()[0].p1().branch() != branch and \
1646 if repo[None].parents()[0].p1().branch() != branch and \
1647 repo[None].parents()[0].p2().branch() != branch:
1647 repo[None].parents()[0].p2().branch() != branch:
1648 raise error.Abort(_('can only close branch heads'))
1648 raise error.Abort(_('can only close branch heads'))
1649
1649
1650 if opts.get('amend'):
1650 if opts.get('amend'):
1651 if ui.configbool('ui', 'commitsubrepos'):
1651 if ui.configbool('ui', 'commitsubrepos'):
1652 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1652 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1653
1653
1654 old = repo['.']
1654 old = repo['.']
1655 rewriteutil.precheck(repo, [old.rev()], 'amend')
1655 rewriteutil.precheck(repo, [old.rev()], 'amend')
1656
1656
1657 # Currently histedit gets confused if an amend happens while histedit
1657 # Currently histedit gets confused if an amend happens while histedit
1658 # is in progress. Since we have a checkunfinished command, we are
1658 # is in progress. Since we have a checkunfinished command, we are
1659 # temporarily honoring it.
1659 # temporarily honoring it.
1660 #
1660 #
1661 # Note: eventually this guard will be removed. Please do not expect
1661 # Note: eventually this guard will be removed. Please do not expect
1662 # this behavior to remain.
1662 # this behavior to remain.
1663 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1663 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1664 cmdutil.checkunfinished(repo)
1664 cmdutil.checkunfinished(repo)
1665
1665
1666 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1666 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1667 if node == old.node():
1667 if node == old.node():
1668 ui.status(_("nothing changed\n"))
1668 ui.status(_("nothing changed\n"))
1669 return 1
1669 return 1
1670 else:
1670 else:
1671 def commitfunc(ui, repo, message, match, opts):
1671 def commitfunc(ui, repo, message, match, opts):
1672 overrides = {}
1672 overrides = {}
1673 if opts.get('secret'):
1673 if opts.get('secret'):
1674 overrides[('phases', 'new-commit')] = 'secret'
1674 overrides[('phases', 'new-commit')] = 'secret'
1675
1675
1676 baseui = repo.baseui
1676 baseui = repo.baseui
1677 with baseui.configoverride(overrides, 'commit'):
1677 with baseui.configoverride(overrides, 'commit'):
1678 with ui.configoverride(overrides, 'commit'):
1678 with ui.configoverride(overrides, 'commit'):
1679 editform = cmdutil.mergeeditform(repo[None],
1679 editform = cmdutil.mergeeditform(repo[None],
1680 'commit.normal')
1680 'commit.normal')
1681 editor = cmdutil.getcommiteditor(
1681 editor = cmdutil.getcommiteditor(
1682 editform=editform, **pycompat.strkwargs(opts))
1682 editform=editform, **pycompat.strkwargs(opts))
1683 return repo.commit(message,
1683 return repo.commit(message,
1684 opts.get('user'),
1684 opts.get('user'),
1685 opts.get('date'),
1685 opts.get('date'),
1686 match,
1686 match,
1687 editor=editor,
1687 editor=editor,
1688 extra=extra)
1688 extra=extra)
1689
1689
1690 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1690 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1691
1691
1692 if not node:
1692 if not node:
1693 stat = cmdutil.postcommitstatus(repo, pats, opts)
1693 stat = cmdutil.postcommitstatus(repo, pats, opts)
1694 if stat[3]:
1694 if stat[3]:
1695 ui.status(_("nothing changed (%d missing files, see "
1695 ui.status(_("nothing changed (%d missing files, see "
1696 "'hg status')\n") % len(stat[3]))
1696 "'hg status')\n") % len(stat[3]))
1697 else:
1697 else:
1698 ui.status(_("nothing changed\n"))
1698 ui.status(_("nothing changed\n"))
1699 return 1
1699 return 1
1700
1700
1701 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1701 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1702
1702
1703 @command('config|showconfig|debugconfig',
1703 @command('config|showconfig|debugconfig',
1704 [('u', 'untrusted', None, _('show untrusted configuration options')),
1704 [('u', 'untrusted', None, _('show untrusted configuration options')),
1705 ('e', 'edit', None, _('edit user config')),
1705 ('e', 'edit', None, _('edit user config')),
1706 ('l', 'local', None, _('edit repository config')),
1706 ('l', 'local', None, _('edit repository config')),
1707 ('g', 'global', None, _('edit global config'))] + formatteropts,
1707 ('g', 'global', None, _('edit global config'))] + formatteropts,
1708 _('[-u] [NAME]...'),
1708 _('[-u] [NAME]...'),
1709 optionalrepo=True,
1709 optionalrepo=True,
1710 intents={INTENT_READONLY})
1710 intents={INTENT_READONLY})
1711 def config(ui, repo, *values, **opts):
1711 def config(ui, repo, *values, **opts):
1712 """show combined config settings from all hgrc files
1712 """show combined config settings from all hgrc files
1713
1713
1714 With no arguments, print names and values of all config items.
1714 With no arguments, print names and values of all config items.
1715
1715
1716 With one argument of the form section.name, print just the value
1716 With one argument of the form section.name, print just the value
1717 of that config item.
1717 of that config item.
1718
1718
1719 With multiple arguments, print names and values of all config
1719 With multiple arguments, print names and values of all config
1720 items with matching section names or section.names.
1720 items with matching section names or section.names.
1721
1721
1722 With --edit, start an editor on the user-level config file. With
1722 With --edit, start an editor on the user-level config file. With
1723 --global, edit the system-wide config file. With --local, edit the
1723 --global, edit the system-wide config file. With --local, edit the
1724 repository-level config file.
1724 repository-level config file.
1725
1725
1726 With --debug, the source (filename and line number) is printed
1726 With --debug, the source (filename and line number) is printed
1727 for each config item.
1727 for each config item.
1728
1728
1729 See :hg:`help config` for more information about config files.
1729 See :hg:`help config` for more information about config files.
1730
1730
1731 .. container:: verbose
1731 .. container:: verbose
1732
1732
1733 Template:
1733 Template:
1734
1734
1735 The following keywords are supported. See also :hg:`help templates`.
1735 The following keywords are supported. See also :hg:`help templates`.
1736
1736
1737 :name: String. Config name.
1737 :name: String. Config name.
1738 :source: String. Filename and line number where the item is defined.
1738 :source: String. Filename and line number where the item is defined.
1739 :value: String. Config value.
1739 :value: String. Config value.
1740
1740
1741 Returns 0 on success, 1 if NAME does not exist.
1741 Returns 0 on success, 1 if NAME does not exist.
1742
1742
1743 """
1743 """
1744
1744
1745 opts = pycompat.byteskwargs(opts)
1745 opts = pycompat.byteskwargs(opts)
1746 if opts.get('edit') or opts.get('local') or opts.get('global'):
1746 if opts.get('edit') or opts.get('local') or opts.get('global'):
1747 if opts.get('local') and opts.get('global'):
1747 if opts.get('local') and opts.get('global'):
1748 raise error.Abort(_("can't use --local and --global together"))
1748 raise error.Abort(_("can't use --local and --global together"))
1749
1749
1750 if opts.get('local'):
1750 if opts.get('local'):
1751 if not repo:
1751 if not repo:
1752 raise error.Abort(_("can't use --local outside a repository"))
1752 raise error.Abort(_("can't use --local outside a repository"))
1753 paths = [repo.vfs.join('hgrc')]
1753 paths = [repo.vfs.join('hgrc')]
1754 elif opts.get('global'):
1754 elif opts.get('global'):
1755 paths = rcutil.systemrcpath()
1755 paths = rcutil.systemrcpath()
1756 else:
1756 else:
1757 paths = rcutil.userrcpath()
1757 paths = rcutil.userrcpath()
1758
1758
1759 for f in paths:
1759 for f in paths:
1760 if os.path.exists(f):
1760 if os.path.exists(f):
1761 break
1761 break
1762 else:
1762 else:
1763 if opts.get('global'):
1763 if opts.get('global'):
1764 samplehgrc = uimod.samplehgrcs['global']
1764 samplehgrc = uimod.samplehgrcs['global']
1765 elif opts.get('local'):
1765 elif opts.get('local'):
1766 samplehgrc = uimod.samplehgrcs['local']
1766 samplehgrc = uimod.samplehgrcs['local']
1767 else:
1767 else:
1768 samplehgrc = uimod.samplehgrcs['user']
1768 samplehgrc = uimod.samplehgrcs['user']
1769
1769
1770 f = paths[0]
1770 f = paths[0]
1771 fp = open(f, "wb")
1771 fp = open(f, "wb")
1772 fp.write(util.tonativeeol(samplehgrc))
1772 fp.write(util.tonativeeol(samplehgrc))
1773 fp.close()
1773 fp.close()
1774
1774
1775 editor = ui.geteditor()
1775 editor = ui.geteditor()
1776 ui.system("%s \"%s\"" % (editor, f),
1776 ui.system("%s \"%s\"" % (editor, f),
1777 onerr=error.Abort, errprefix=_("edit failed"),
1777 onerr=error.Abort, errprefix=_("edit failed"),
1778 blockedtag='config_edit')
1778 blockedtag='config_edit')
1779 return
1779 return
1780 ui.pager('config')
1780 ui.pager('config')
1781 fm = ui.formatter('config', opts)
1781 fm = ui.formatter('config', opts)
1782 for t, f in rcutil.rccomponents():
1782 for t, f in rcutil.rccomponents():
1783 if t == 'path':
1783 if t == 'path':
1784 ui.debug('read config from: %s\n' % f)
1784 ui.debug('read config from: %s\n' % f)
1785 elif t == 'items':
1785 elif t == 'items':
1786 for section, name, value, source in f:
1786 for section, name, value, source in f:
1787 ui.debug('set config by: %s\n' % source)
1787 ui.debug('set config by: %s\n' % source)
1788 else:
1788 else:
1789 raise error.ProgrammingError('unknown rctype: %s' % t)
1789 raise error.ProgrammingError('unknown rctype: %s' % t)
1790 untrusted = bool(opts.get('untrusted'))
1790 untrusted = bool(opts.get('untrusted'))
1791
1791
1792 selsections = selentries = []
1792 selsections = selentries = []
1793 if values:
1793 if values:
1794 selsections = [v for v in values if '.' not in v]
1794 selsections = [v for v in values if '.' not in v]
1795 selentries = [v for v in values if '.' in v]
1795 selentries = [v for v in values if '.' in v]
1796 uniquesel = (len(selentries) == 1 and not selsections)
1796 uniquesel = (len(selentries) == 1 and not selsections)
1797 selsections = set(selsections)
1797 selsections = set(selsections)
1798 selentries = set(selentries)
1798 selentries = set(selentries)
1799
1799
1800 matched = False
1800 matched = False
1801 for section, name, value in ui.walkconfig(untrusted=untrusted):
1801 for section, name, value in ui.walkconfig(untrusted=untrusted):
1802 source = ui.configsource(section, name, untrusted)
1802 source = ui.configsource(section, name, untrusted)
1803 value = pycompat.bytestr(value)
1803 value = pycompat.bytestr(value)
1804 if fm.isplain():
1804 if fm.isplain():
1805 source = source or 'none'
1805 source = source or 'none'
1806 value = value.replace('\n', '\\n')
1806 value = value.replace('\n', '\\n')
1807 entryname = section + '.' + name
1807 entryname = section + '.' + name
1808 if values and not (section in selsections or entryname in selentries):
1808 if values and not (section in selsections or entryname in selentries):
1809 continue
1809 continue
1810 fm.startitem()
1810 fm.startitem()
1811 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1811 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1812 if uniquesel:
1812 if uniquesel:
1813 fm.data(name=entryname)
1813 fm.data(name=entryname)
1814 fm.write('value', '%s\n', value)
1814 fm.write('value', '%s\n', value)
1815 else:
1815 else:
1816 fm.write('name value', '%s=%s\n', entryname, value)
1816 fm.write('name value', '%s=%s\n', entryname, value)
1817 matched = True
1817 matched = True
1818 fm.end()
1818 fm.end()
1819 if matched:
1819 if matched:
1820 return 0
1820 return 0
1821 return 1
1821 return 1
1822
1822
1823 @command('copy|cp',
1823 @command('copy|cp',
1824 [('A', 'after', None, _('record a copy that has already occurred')),
1824 [('A', 'after', None, _('record a copy that has already occurred')),
1825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1826 ] + walkopts + dryrunopts,
1826 ] + walkopts + dryrunopts,
1827 _('[OPTION]... [SOURCE]... DEST'))
1827 _('[OPTION]... [SOURCE]... DEST'))
1828 def copy(ui, repo, *pats, **opts):
1828 def copy(ui, repo, *pats, **opts):
1829 """mark files as copied for the next commit
1829 """mark files as copied for the next commit
1830
1830
1831 Mark dest as having copies of source files. If dest is a
1831 Mark dest as having copies of source files. If dest is a
1832 directory, copies are put in that directory. If dest is a file,
1832 directory, copies are put in that directory. If dest is a file,
1833 the source must be a single file.
1833 the source must be a single file.
1834
1834
1835 By default, this command copies the contents of files as they
1835 By default, this command copies the contents of files as they
1836 exist in the working directory. If invoked with -A/--after, the
1836 exist in the working directory. If invoked with -A/--after, the
1837 operation is recorded, but no copying is performed.
1837 operation is recorded, but no copying is performed.
1838
1838
1839 This command takes effect with the next commit. To undo a copy
1839 This command takes effect with the next commit. To undo a copy
1840 before that, see :hg:`revert`.
1840 before that, see :hg:`revert`.
1841
1841
1842 Returns 0 on success, 1 if errors are encountered.
1842 Returns 0 on success, 1 if errors are encountered.
1843 """
1843 """
1844 opts = pycompat.byteskwargs(opts)
1844 opts = pycompat.byteskwargs(opts)
1845 with repo.wlock(False):
1845 with repo.wlock(False):
1846 return cmdutil.copy(ui, repo, pats, opts)
1846 return cmdutil.copy(ui, repo, pats, opts)
1847
1847
1848 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1848 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1849 def debugcommands(ui, cmd='', *args):
1849 def debugcommands(ui, cmd='', *args):
1850 """list all available commands and options"""
1850 """list all available commands and options"""
1851 for cmd, vals in sorted(table.iteritems()):
1851 for cmd, vals in sorted(table.iteritems()):
1852 cmd = cmd.split('|')[0].strip('^')
1852 cmd = cmd.split('|')[0].strip('^')
1853 opts = ', '.join([i[1] for i in vals[1]])
1853 opts = ', '.join([i[1] for i in vals[1]])
1854 ui.write('%s: %s\n' % (cmd, opts))
1854 ui.write('%s: %s\n' % (cmd, opts))
1855
1855
1856 @command('debugcomplete',
1856 @command('debugcomplete',
1857 [('o', 'options', None, _('show the command options'))],
1857 [('o', 'options', None, _('show the command options'))],
1858 _('[-o] CMD'),
1858 _('[-o] CMD'),
1859 norepo=True)
1859 norepo=True)
1860 def debugcomplete(ui, cmd='', **opts):
1860 def debugcomplete(ui, cmd='', **opts):
1861 """returns the completion list associated with the given command"""
1861 """returns the completion list associated with the given command"""
1862
1862
1863 if opts.get(r'options'):
1863 if opts.get(r'options'):
1864 options = []
1864 options = []
1865 otables = [globalopts]
1865 otables = [globalopts]
1866 if cmd:
1866 if cmd:
1867 aliases, entry = cmdutil.findcmd(cmd, table, False)
1867 aliases, entry = cmdutil.findcmd(cmd, table, False)
1868 otables.append(entry[1])
1868 otables.append(entry[1])
1869 for t in otables:
1869 for t in otables:
1870 for o in t:
1870 for o in t:
1871 if "(DEPRECATED)" in o[3]:
1871 if "(DEPRECATED)" in o[3]:
1872 continue
1872 continue
1873 if o[0]:
1873 if o[0]:
1874 options.append('-%s' % o[0])
1874 options.append('-%s' % o[0])
1875 options.append('--%s' % o[1])
1875 options.append('--%s' % o[1])
1876 ui.write("%s\n" % "\n".join(options))
1876 ui.write("%s\n" % "\n".join(options))
1877 return
1877 return
1878
1878
1879 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1879 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1880 if ui.verbose:
1880 if ui.verbose:
1881 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1881 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1882 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1882 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1883
1883
1884 @command('^diff',
1884 @command('^diff',
1885 [('r', 'rev', [], _('revision'), _('REV')),
1885 [('r', 'rev', [], _('revision'), _('REV')),
1886 ('c', 'change', '', _('change made by revision'), _('REV'))
1886 ('c', 'change', '', _('change made by revision'), _('REV'))
1887 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1887 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1888 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1888 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1889 inferrepo=True,
1889 inferrepo=True,
1890 intents={INTENT_READONLY})
1890 intents={INTENT_READONLY})
1891 def diff(ui, repo, *pats, **opts):
1891 def diff(ui, repo, *pats, **opts):
1892 """diff repository (or selected files)
1892 """diff repository (or selected files)
1893
1893
1894 Show differences between revisions for the specified files.
1894 Show differences between revisions for the specified files.
1895
1895
1896 Differences between files are shown using the unified diff format.
1896 Differences between files are shown using the unified diff format.
1897
1897
1898 .. note::
1898 .. note::
1899
1899
1900 :hg:`diff` may generate unexpected results for merges, as it will
1900 :hg:`diff` may generate unexpected results for merges, as it will
1901 default to comparing against the working directory's first
1901 default to comparing against the working directory's first
1902 parent changeset if no revisions are specified.
1902 parent changeset if no revisions are specified.
1903
1903
1904 When two revision arguments are given, then changes are shown
1904 When two revision arguments are given, then changes are shown
1905 between those revisions. If only one revision is specified then
1905 between those revisions. If only one revision is specified then
1906 that revision is compared to the working directory, and, when no
1906 that revision is compared to the working directory, and, when no
1907 revisions are specified, the working directory files are compared
1907 revisions are specified, the working directory files are compared
1908 to its first parent.
1908 to its first parent.
1909
1909
1910 Alternatively you can specify -c/--change with a revision to see
1910 Alternatively you can specify -c/--change with a revision to see
1911 the changes in that changeset relative to its first parent.
1911 the changes in that changeset relative to its first parent.
1912
1912
1913 Without the -a/--text option, diff will avoid generating diffs of
1913 Without the -a/--text option, diff will avoid generating diffs of
1914 files it detects as binary. With -a, diff will generate a diff
1914 files it detects as binary. With -a, diff will generate a diff
1915 anyway, probably with undesirable results.
1915 anyway, probably with undesirable results.
1916
1916
1917 Use the -g/--git option to generate diffs in the git extended diff
1917 Use the -g/--git option to generate diffs in the git extended diff
1918 format. For more information, read :hg:`help diffs`.
1918 format. For more information, read :hg:`help diffs`.
1919
1919
1920 .. container:: verbose
1920 .. container:: verbose
1921
1921
1922 Examples:
1922 Examples:
1923
1923
1924 - compare a file in the current working directory to its parent::
1924 - compare a file in the current working directory to its parent::
1925
1925
1926 hg diff foo.c
1926 hg diff foo.c
1927
1927
1928 - compare two historical versions of a directory, with rename info::
1928 - compare two historical versions of a directory, with rename info::
1929
1929
1930 hg diff --git -r 1.0:1.2 lib/
1930 hg diff --git -r 1.0:1.2 lib/
1931
1931
1932 - get change stats relative to the last change on some date::
1932 - get change stats relative to the last change on some date::
1933
1933
1934 hg diff --stat -r "date('may 2')"
1934 hg diff --stat -r "date('may 2')"
1935
1935
1936 - diff all newly-added files that contain a keyword::
1936 - diff all newly-added files that contain a keyword::
1937
1937
1938 hg diff "set:added() and grep(GNU)"
1938 hg diff "set:added() and grep(GNU)"
1939
1939
1940 - compare a revision and its parents::
1940 - compare a revision and its parents::
1941
1941
1942 hg diff -c 9353 # compare against first parent
1942 hg diff -c 9353 # compare against first parent
1943 hg diff -r 9353^:9353 # same using revset syntax
1943 hg diff -r 9353^:9353 # same using revset syntax
1944 hg diff -r 9353^2:9353 # compare against the second parent
1944 hg diff -r 9353^2:9353 # compare against the second parent
1945
1945
1946 Returns 0 on success.
1946 Returns 0 on success.
1947 """
1947 """
1948
1948
1949 opts = pycompat.byteskwargs(opts)
1949 opts = pycompat.byteskwargs(opts)
1950 revs = opts.get('rev')
1950 revs = opts.get('rev')
1951 change = opts.get('change')
1951 change = opts.get('change')
1952 stat = opts.get('stat')
1952 stat = opts.get('stat')
1953 reverse = opts.get('reverse')
1953 reverse = opts.get('reverse')
1954
1954
1955 if revs and change:
1955 if revs and change:
1956 msg = _('cannot specify --rev and --change at the same time')
1956 msg = _('cannot specify --rev and --change at the same time')
1957 raise error.Abort(msg)
1957 raise error.Abort(msg)
1958 elif change:
1958 elif change:
1959 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1959 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1960 ctx2 = scmutil.revsingle(repo, change, None)
1960 ctx2 = scmutil.revsingle(repo, change, None)
1961 ctx1 = ctx2.p1()
1961 ctx1 = ctx2.p1()
1962 else:
1962 else:
1963 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1963 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1964 ctx1, ctx2 = scmutil.revpair(repo, revs)
1964 ctx1, ctx2 = scmutil.revpair(repo, revs)
1965 node1, node2 = ctx1.node(), ctx2.node()
1965 node1, node2 = ctx1.node(), ctx2.node()
1966
1966
1967 if reverse:
1967 if reverse:
1968 node1, node2 = node2, node1
1968 node1, node2 = node2, node1
1969
1969
1970 diffopts = patch.diffallopts(ui, opts)
1970 diffopts = patch.diffallopts(ui, opts)
1971 m = scmutil.match(ctx2, pats, opts)
1971 m = scmutil.match(ctx2, pats, opts)
1972 m = repo.narrowmatch(m)
1972 m = repo.narrowmatch(m)
1973 ui.pager('diff')
1973 ui.pager('diff')
1974 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1974 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1975 listsubrepos=opts.get('subrepos'),
1975 listsubrepos=opts.get('subrepos'),
1976 root=opts.get('root'))
1976 root=opts.get('root'))
1977
1977
1978 @command('^export',
1978 @command('^export',
1979 [('B', 'bookmark', '',
1979 [('B', 'bookmark', '',
1980 _('export changes only reachable by given bookmark')),
1980 _('export changes only reachable by given bookmark')),
1981 ('o', 'output', '',
1981 ('o', 'output', '',
1982 _('print output to file with formatted name'), _('FORMAT')),
1982 _('print output to file with formatted name'), _('FORMAT')),
1983 ('', 'switch-parent', None, _('diff against the second parent')),
1983 ('', 'switch-parent', None, _('diff against the second parent')),
1984 ('r', 'rev', [], _('revisions to export'), _('REV')),
1984 ('r', 'rev', [], _('revisions to export'), _('REV')),
1985 ] + diffopts + formatteropts,
1985 ] + diffopts + formatteropts,
1986 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1986 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1987 intents={INTENT_READONLY})
1987 intents={INTENT_READONLY})
1988 def export(ui, repo, *changesets, **opts):
1988 def export(ui, repo, *changesets, **opts):
1989 """dump the header and diffs for one or more changesets
1989 """dump the header and diffs for one or more changesets
1990
1990
1991 Print the changeset header and diffs for one or more revisions.
1991 Print the changeset header and diffs for one or more revisions.
1992 If no revision is given, the parent of the working directory is used.
1992 If no revision is given, the parent of the working directory is used.
1993
1993
1994 The information shown in the changeset header is: author, date,
1994 The information shown in the changeset header is: author, date,
1995 branch name (if non-default), changeset hash, parent(s) and commit
1995 branch name (if non-default), changeset hash, parent(s) and commit
1996 comment.
1996 comment.
1997
1997
1998 .. note::
1998 .. note::
1999
1999
2000 :hg:`export` may generate unexpected diff output for merge
2000 :hg:`export` may generate unexpected diff output for merge
2001 changesets, as it will compare the merge changeset against its
2001 changesets, as it will compare the merge changeset against its
2002 first parent only.
2002 first parent only.
2003
2003
2004 Output may be to a file, in which case the name of the file is
2004 Output may be to a file, in which case the name of the file is
2005 given using a template string. See :hg:`help templates`. In addition
2005 given using a template string. See :hg:`help templates`. In addition
2006 to the common template keywords, the following formatting rules are
2006 to the common template keywords, the following formatting rules are
2007 supported:
2007 supported:
2008
2008
2009 :``%%``: literal "%" character
2009 :``%%``: literal "%" character
2010 :``%H``: changeset hash (40 hexadecimal digits)
2010 :``%H``: changeset hash (40 hexadecimal digits)
2011 :``%N``: number of patches being generated
2011 :``%N``: number of patches being generated
2012 :``%R``: changeset revision number
2012 :``%R``: changeset revision number
2013 :``%b``: basename of the exporting repository
2013 :``%b``: basename of the exporting repository
2014 :``%h``: short-form changeset hash (12 hexadecimal digits)
2014 :``%h``: short-form changeset hash (12 hexadecimal digits)
2015 :``%m``: first line of the commit message (only alphanumeric characters)
2015 :``%m``: first line of the commit message (only alphanumeric characters)
2016 :``%n``: zero-padded sequence number, starting at 1
2016 :``%n``: zero-padded sequence number, starting at 1
2017 :``%r``: zero-padded changeset revision number
2017 :``%r``: zero-padded changeset revision number
2018 :``\\``: literal "\\" character
2018 :``\\``: literal "\\" character
2019
2019
2020 Without the -a/--text option, export will avoid generating diffs
2020 Without the -a/--text option, export will avoid generating diffs
2021 of files it detects as binary. With -a, export will generate a
2021 of files it detects as binary. With -a, export will generate a
2022 diff anyway, probably with undesirable results.
2022 diff anyway, probably with undesirable results.
2023
2023
2024 With -B/--bookmark changesets reachable by the given bookmark are
2024 With -B/--bookmark changesets reachable by the given bookmark are
2025 selected.
2025 selected.
2026
2026
2027 Use the -g/--git option to generate diffs in the git extended diff
2027 Use the -g/--git option to generate diffs in the git extended diff
2028 format. See :hg:`help diffs` for more information.
2028 format. See :hg:`help diffs` for more information.
2029
2029
2030 With the --switch-parent option, the diff will be against the
2030 With the --switch-parent option, the diff will be against the
2031 second parent. It can be useful to review a merge.
2031 second parent. It can be useful to review a merge.
2032
2032
2033 .. container:: verbose
2033 .. container:: verbose
2034
2034
2035 Template:
2035 Template:
2036
2036
2037 The following keywords are supported in addition to the common template
2037 The following keywords are supported in addition to the common template
2038 keywords and functions. See also :hg:`help templates`.
2038 keywords and functions. See also :hg:`help templates`.
2039
2039
2040 :diff: String. Diff content.
2040 :diff: String. Diff content.
2041 :parents: List of strings. Parent nodes of the changeset.
2041 :parents: List of strings. Parent nodes of the changeset.
2042
2042
2043 Examples:
2043 Examples:
2044
2044
2045 - use export and import to transplant a bugfix to the current
2045 - use export and import to transplant a bugfix to the current
2046 branch::
2046 branch::
2047
2047
2048 hg export -r 9353 | hg import -
2048 hg export -r 9353 | hg import -
2049
2049
2050 - export all the changesets between two revisions to a file with
2050 - export all the changesets between two revisions to a file with
2051 rename information::
2051 rename information::
2052
2052
2053 hg export --git -r 123:150 > changes.txt
2053 hg export --git -r 123:150 > changes.txt
2054
2054
2055 - split outgoing changes into a series of patches with
2055 - split outgoing changes into a series of patches with
2056 descriptive names::
2056 descriptive names::
2057
2057
2058 hg export -r "outgoing()" -o "%n-%m.patch"
2058 hg export -r "outgoing()" -o "%n-%m.patch"
2059
2059
2060 Returns 0 on success.
2060 Returns 0 on success.
2061 """
2061 """
2062 opts = pycompat.byteskwargs(opts)
2062 opts = pycompat.byteskwargs(opts)
2063 bookmark = opts.get('bookmark')
2063 bookmark = opts.get('bookmark')
2064 changesets += tuple(opts.get('rev', []))
2064 changesets += tuple(opts.get('rev', []))
2065
2065
2066 if bookmark and changesets:
2066 if bookmark and changesets:
2067 raise error.Abort(_("-r and -B are mutually exclusive"))
2067 raise error.Abort(_("-r and -B are mutually exclusive"))
2068
2068
2069 if bookmark:
2069 if bookmark:
2070 if bookmark not in repo._bookmarks:
2070 if bookmark not in repo._bookmarks:
2071 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2071 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2072
2072
2073 revs = scmutil.bookmarkrevs(repo, bookmark)
2073 revs = scmutil.bookmarkrevs(repo, bookmark)
2074 else:
2074 else:
2075 if not changesets:
2075 if not changesets:
2076 changesets = ['.']
2076 changesets = ['.']
2077
2077
2078 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2078 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2079 revs = scmutil.revrange(repo, changesets)
2079 revs = scmutil.revrange(repo, changesets)
2080
2080
2081 if not revs:
2081 if not revs:
2082 raise error.Abort(_("export requires at least one changeset"))
2082 raise error.Abort(_("export requires at least one changeset"))
2083 if len(revs) > 1:
2083 if len(revs) > 1:
2084 ui.note(_('exporting patches:\n'))
2084 ui.note(_('exporting patches:\n'))
2085 else:
2085 else:
2086 ui.note(_('exporting patch:\n'))
2086 ui.note(_('exporting patch:\n'))
2087
2087
2088 fntemplate = opts.get('output')
2088 fntemplate = opts.get('output')
2089 if cmdutil.isstdiofilename(fntemplate):
2089 if cmdutil.isstdiofilename(fntemplate):
2090 fntemplate = ''
2090 fntemplate = ''
2091
2091
2092 if fntemplate:
2092 if fntemplate:
2093 fm = formatter.nullformatter(ui, 'export', opts)
2093 fm = formatter.nullformatter(ui, 'export', opts)
2094 else:
2094 else:
2095 ui.pager('export')
2095 ui.pager('export')
2096 fm = ui.formatter('export', opts)
2096 fm = ui.formatter('export', opts)
2097 with fm:
2097 with fm:
2098 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2098 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2099 switch_parent=opts.get('switch_parent'),
2099 switch_parent=opts.get('switch_parent'),
2100 opts=patch.diffallopts(ui, opts))
2100 opts=patch.diffallopts(ui, opts))
2101
2101
2102 @command('files',
2102 @command('files',
2103 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2103 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2104 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2104 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2105 ] + walkopts + formatteropts + subrepoopts,
2105 ] + walkopts + formatteropts + subrepoopts,
2106 _('[OPTION]... [FILE]...'),
2106 _('[OPTION]... [FILE]...'),
2107 intents={INTENT_READONLY})
2107 intents={INTENT_READONLY})
2108 def files(ui, repo, *pats, **opts):
2108 def files(ui, repo, *pats, **opts):
2109 """list tracked files
2109 """list tracked files
2110
2110
2111 Print files under Mercurial control in the working directory or
2111 Print files under Mercurial control in the working directory or
2112 specified revision for given files (excluding removed files).
2112 specified revision for given files (excluding removed files).
2113 Files can be specified as filenames or filesets.
2113 Files can be specified as filenames or filesets.
2114
2114
2115 If no files are given to match, this command prints the names
2115 If no files are given to match, this command prints the names
2116 of all files under Mercurial control.
2116 of all files under Mercurial control.
2117
2117
2118 .. container:: verbose
2118 .. container:: verbose
2119
2119
2120 Template:
2120 Template:
2121
2121
2122 The following keywords are supported in addition to the common template
2122 The following keywords are supported in addition to the common template
2123 keywords and functions. See also :hg:`help templates`.
2123 keywords and functions. See also :hg:`help templates`.
2124
2124
2125 :flags: String. Character denoting file's symlink and executable bits.
2125 :flags: String. Character denoting file's symlink and executable bits.
2126 :path: String. Repository-absolute path of the file.
2126 :path: String. Repository-absolute path of the file.
2127 :size: Integer. Size of the file in bytes.
2127 :size: Integer. Size of the file in bytes.
2128
2128
2129 Examples:
2129 Examples:
2130
2130
2131 - list all files under the current directory::
2131 - list all files under the current directory::
2132
2132
2133 hg files .
2133 hg files .
2134
2134
2135 - shows sizes and flags for current revision::
2135 - shows sizes and flags for current revision::
2136
2136
2137 hg files -vr .
2137 hg files -vr .
2138
2138
2139 - list all files named README::
2139 - list all files named README::
2140
2140
2141 hg files -I "**/README"
2141 hg files -I "**/README"
2142
2142
2143 - list all binary files::
2143 - list all binary files::
2144
2144
2145 hg files "set:binary()"
2145 hg files "set:binary()"
2146
2146
2147 - find files containing a regular expression::
2147 - find files containing a regular expression::
2148
2148
2149 hg files "set:grep('bob')"
2149 hg files "set:grep('bob')"
2150
2150
2151 - search tracked file contents with xargs and grep::
2151 - search tracked file contents with xargs and grep::
2152
2152
2153 hg files -0 | xargs -0 grep foo
2153 hg files -0 | xargs -0 grep foo
2154
2154
2155 See :hg:`help patterns` and :hg:`help filesets` for more information
2155 See :hg:`help patterns` and :hg:`help filesets` for more information
2156 on specifying file patterns.
2156 on specifying file patterns.
2157
2157
2158 Returns 0 if a match is found, 1 otherwise.
2158 Returns 0 if a match is found, 1 otherwise.
2159
2159
2160 """
2160 """
2161
2161
2162 opts = pycompat.byteskwargs(opts)
2162 opts = pycompat.byteskwargs(opts)
2163 rev = opts.get('rev')
2163 rev = opts.get('rev')
2164 if rev:
2164 if rev:
2165 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2165 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2166 ctx = scmutil.revsingle(repo, rev, None)
2166 ctx = scmutil.revsingle(repo, rev, None)
2167
2167
2168 end = '\n'
2168 end = '\n'
2169 if opts.get('print0'):
2169 if opts.get('print0'):
2170 end = '\0'
2170 end = '\0'
2171 fmt = '%s' + end
2171 fmt = '%s' + end
2172
2172
2173 m = scmutil.match(ctx, pats, opts)
2173 m = scmutil.match(ctx, pats, opts)
2174 ui.pager('files')
2174 ui.pager('files')
2175 with ui.formatter('files', opts) as fm:
2175 with ui.formatter('files', opts) as fm:
2176 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2176 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2177
2177
2178 @command(
2178 @command(
2179 '^forget',
2179 '^forget',
2180 [('i', 'interactive', None, _('use interactive mode')),
2180 [('i', 'interactive', None, _('use interactive mode')),
2181 ] + walkopts + dryrunopts,
2181 ] + walkopts + dryrunopts,
2182 _('[OPTION]... FILE...'), inferrepo=True)
2182 _('[OPTION]... FILE...'), inferrepo=True)
2183 def forget(ui, repo, *pats, **opts):
2183 def forget(ui, repo, *pats, **opts):
2184 """forget the specified files on the next commit
2184 """forget the specified files on the next commit
2185
2185
2186 Mark the specified files so they will no longer be tracked
2186 Mark the specified files so they will no longer be tracked
2187 after the next commit.
2187 after the next commit.
2188
2188
2189 This only removes files from the current branch, not from the
2189 This only removes files from the current branch, not from the
2190 entire project history, and it does not delete them from the
2190 entire project history, and it does not delete them from the
2191 working directory.
2191 working directory.
2192
2192
2193 To delete the file from the working directory, see :hg:`remove`.
2193 To delete the file from the working directory, see :hg:`remove`.
2194
2194
2195 To undo a forget before the next commit, see :hg:`add`.
2195 To undo a forget before the next commit, see :hg:`add`.
2196
2196
2197 .. container:: verbose
2197 .. container:: verbose
2198
2198
2199 Examples:
2199 Examples:
2200
2200
2201 - forget newly-added binary files::
2201 - forget newly-added binary files::
2202
2202
2203 hg forget "set:added() and binary()"
2203 hg forget "set:added() and binary()"
2204
2204
2205 - forget files that would be excluded by .hgignore::
2205 - forget files that would be excluded by .hgignore::
2206
2206
2207 hg forget "set:hgignore()"
2207 hg forget "set:hgignore()"
2208
2208
2209 Returns 0 on success.
2209 Returns 0 on success.
2210 """
2210 """
2211
2211
2212 opts = pycompat.byteskwargs(opts)
2212 opts = pycompat.byteskwargs(opts)
2213 if not pats:
2213 if not pats:
2214 raise error.Abort(_('no files specified'))
2214 raise error.Abort(_('no files specified'))
2215
2215
2216 m = scmutil.match(repo[None], pats, opts)
2216 m = scmutil.match(repo[None], pats, opts)
2217 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2217 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2218 rejected = cmdutil.forget(ui, repo, m, prefix="",
2218 rejected = cmdutil.forget(ui, repo, m, prefix="",
2219 explicitonly=False, dryrun=dryrun,
2219 explicitonly=False, dryrun=dryrun,
2220 interactive=interactive)[0]
2220 interactive=interactive)[0]
2221 return rejected and 1 or 0
2221 return rejected and 1 or 0
2222
2222
2223 @command(
2223 @command(
2224 'graft',
2224 'graft',
2225 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2225 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2226 ('c', 'continue', False, _('resume interrupted graft')),
2226 ('c', 'continue', False, _('resume interrupted graft')),
2227 ('', 'stop', False, _('stop interrupted graft')),
2227 ('', 'stop', False, _('stop interrupted graft')),
2228 ('', 'abort', False, _('abort interrupted graft')),
2228 ('', 'abort', False, _('abort interrupted graft')),
2229 ('e', 'edit', False, _('invoke editor on commit messages')),
2229 ('e', 'edit', False, _('invoke editor on commit messages')),
2230 ('', 'log', None, _('append graft info to log message')),
2230 ('', 'log', None, _('append graft info to log message')),
2231 ('', 'no-commit', None,
2231 ('', 'no-commit', None,
2232 _("don't commit, just apply the changes in working directory")),
2232 _("don't commit, just apply the changes in working directory")),
2233 ('f', 'force', False, _('force graft')),
2233 ('f', 'force', False, _('force graft')),
2234 ('D', 'currentdate', False,
2234 ('D', 'currentdate', False,
2235 _('record the current date as commit date')),
2235 _('record the current date as commit date')),
2236 ('U', 'currentuser', False,
2236 ('U', 'currentuser', False,
2237 _('record the current user as committer'), _('DATE'))]
2237 _('record the current user as committer'), _('DATE'))]
2238 + commitopts2 + mergetoolopts + dryrunopts,
2238 + commitopts2 + mergetoolopts + dryrunopts,
2239 _('[OPTION]... [-r REV]... REV...'))
2239 _('[OPTION]... [-r REV]... REV...'))
2240 def graft(ui, repo, *revs, **opts):
2240 def graft(ui, repo, *revs, **opts):
2241 '''copy changes from other branches onto the current branch
2241 '''copy changes from other branches onto the current branch
2242
2242
2243 This command uses Mercurial's merge logic to copy individual
2243 This command uses Mercurial's merge logic to copy individual
2244 changes from other branches without merging branches in the
2244 changes from other branches without merging branches in the
2245 history graph. This is sometimes known as 'backporting' or
2245 history graph. This is sometimes known as 'backporting' or
2246 'cherry-picking'. By default, graft will copy user, date, and
2246 'cherry-picking'. By default, graft will copy user, date, and
2247 description from the source changesets.
2247 description from the source changesets.
2248
2248
2249 Changesets that are ancestors of the current revision, that have
2249 Changesets that are ancestors of the current revision, that have
2250 already been grafted, or that are merges will be skipped.
2250 already been grafted, or that are merges will be skipped.
2251
2251
2252 If --log is specified, log messages will have a comment appended
2252 If --log is specified, log messages will have a comment appended
2253 of the form::
2253 of the form::
2254
2254
2255 (grafted from CHANGESETHASH)
2255 (grafted from CHANGESETHASH)
2256
2256
2257 If --force is specified, revisions will be grafted even if they
2257 If --force is specified, revisions will be grafted even if they
2258 are already ancestors of, or have been grafted to, the destination.
2258 are already ancestors of, or have been grafted to, the destination.
2259 This is useful when the revisions have since been backed out.
2259 This is useful when the revisions have since been backed out.
2260
2260
2261 If a graft merge results in conflicts, the graft process is
2261 If a graft merge results in conflicts, the graft process is
2262 interrupted so that the current merge can be manually resolved.
2262 interrupted so that the current merge can be manually resolved.
2263 Once all conflicts are addressed, the graft process can be
2263 Once all conflicts are addressed, the graft process can be
2264 continued with the -c/--continue option.
2264 continued with the -c/--continue option.
2265
2265
2266 The -c/--continue option reapplies all the earlier options.
2266 The -c/--continue option reapplies all the earlier options.
2267
2267
2268 .. container:: verbose
2268 .. container:: verbose
2269
2269
2270 Examples:
2270 Examples:
2271
2271
2272 - copy a single change to the stable branch and edit its description::
2272 - copy a single change to the stable branch and edit its description::
2273
2273
2274 hg update stable
2274 hg update stable
2275 hg graft --edit 9393
2275 hg graft --edit 9393
2276
2276
2277 - graft a range of changesets with one exception, updating dates::
2277 - graft a range of changesets with one exception, updating dates::
2278
2278
2279 hg graft -D "2085::2093 and not 2091"
2279 hg graft -D "2085::2093 and not 2091"
2280
2280
2281 - continue a graft after resolving conflicts::
2281 - continue a graft after resolving conflicts::
2282
2282
2283 hg graft -c
2283 hg graft -c
2284
2284
2285 - show the source of a grafted changeset::
2285 - show the source of a grafted changeset::
2286
2286
2287 hg log --debug -r .
2287 hg log --debug -r .
2288
2288
2289 - show revisions sorted by date::
2289 - show revisions sorted by date::
2290
2290
2291 hg log -r "sort(all(), date)"
2291 hg log -r "sort(all(), date)"
2292
2292
2293 See :hg:`help revisions` for more about specifying revisions.
2293 See :hg:`help revisions` for more about specifying revisions.
2294
2294
2295 Returns 0 on successful completion.
2295 Returns 0 on successful completion.
2296 '''
2296 '''
2297 with repo.wlock():
2297 with repo.wlock():
2298 return _dograft(ui, repo, *revs, **opts)
2298 return _dograft(ui, repo, *revs, **opts)
2299
2299
2300 def _dograft(ui, repo, *revs, **opts):
2300 def _dograft(ui, repo, *revs, **opts):
2301 opts = pycompat.byteskwargs(opts)
2301 opts = pycompat.byteskwargs(opts)
2302 if revs and opts.get('rev'):
2302 if revs and opts.get('rev'):
2303 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2303 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2304 'revision ordering!\n'))
2304 'revision ordering!\n'))
2305
2305
2306 revs = list(revs)
2306 revs = list(revs)
2307 revs.extend(opts.get('rev'))
2307 revs.extend(opts.get('rev'))
2308 # a dict of data to be stored in state file
2308 # a dict of data to be stored in state file
2309 statedata = {}
2309 statedata = {}
2310 # list of new nodes created by ongoing graft
2310 # list of new nodes created by ongoing graft
2311 statedata['newnodes'] = []
2311 statedata['newnodes'] = []
2312
2312
2313 if not opts.get('user') and opts.get('currentuser'):
2313 if not opts.get('user') and opts.get('currentuser'):
2314 opts['user'] = ui.username()
2314 opts['user'] = ui.username()
2315 if not opts.get('date') and opts.get('currentdate'):
2315 if not opts.get('date') and opts.get('currentdate'):
2316 opts['date'] = "%d %d" % dateutil.makedate()
2316 opts['date'] = "%d %d" % dateutil.makedate()
2317
2317
2318 editor = cmdutil.getcommiteditor(editform='graft',
2318 editor = cmdutil.getcommiteditor(editform='graft',
2319 **pycompat.strkwargs(opts))
2319 **pycompat.strkwargs(opts))
2320
2320
2321 cont = False
2321 cont = False
2322 if opts.get('no_commit'):
2322 if opts.get('no_commit'):
2323 if opts.get('edit'):
2323 if opts.get('edit'):
2324 raise error.Abort(_("cannot specify --no-commit and "
2324 raise error.Abort(_("cannot specify --no-commit and "
2325 "--edit together"))
2325 "--edit together"))
2326 if opts.get('currentuser'):
2326 if opts.get('currentuser'):
2327 raise error.Abort(_("cannot specify --no-commit and "
2327 raise error.Abort(_("cannot specify --no-commit and "
2328 "--currentuser together"))
2328 "--currentuser together"))
2329 if opts.get('currentdate'):
2329 if opts.get('currentdate'):
2330 raise error.Abort(_("cannot specify --no-commit and "
2330 raise error.Abort(_("cannot specify --no-commit and "
2331 "--currentdate together"))
2331 "--currentdate together"))
2332 if opts.get('log'):
2332 if opts.get('log'):
2333 raise error.Abort(_("cannot specify --no-commit and "
2333 raise error.Abort(_("cannot specify --no-commit and "
2334 "--log together"))
2334 "--log together"))
2335
2335
2336 graftstate = statemod.cmdstate(repo, 'graftstate')
2336 graftstate = statemod.cmdstate(repo, 'graftstate')
2337
2337
2338 if opts.get('stop'):
2338 if opts.get('stop'):
2339 if opts.get('continue'):
2339 if opts.get('continue'):
2340 raise error.Abort(_("cannot use '--continue' and "
2340 raise error.Abort(_("cannot use '--continue' and "
2341 "'--stop' together"))
2341 "'--stop' together"))
2342 if opts.get('abort'):
2342 if opts.get('abort'):
2343 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2343 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2344
2344
2345 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2345 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2346 opts.get('date'), opts.get('currentdate'),
2346 opts.get('date'), opts.get('currentdate'),
2347 opts.get('currentuser'), opts.get('rev'))):
2347 opts.get('currentuser'), opts.get('rev'))):
2348 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2348 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2349 return _stopgraft(ui, repo, graftstate)
2349 return _stopgraft(ui, repo, graftstate)
2350 elif opts.get('abort'):
2350 elif opts.get('abort'):
2351 if opts.get('continue'):
2351 if opts.get('continue'):
2352 raise error.Abort(_("cannot use '--continue' and "
2352 raise error.Abort(_("cannot use '--continue' and "
2353 "'--abort' together"))
2353 "'--abort' together"))
2354 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2354 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2355 opts.get('date'), opts.get('currentdate'),
2355 opts.get('date'), opts.get('currentdate'),
2356 opts.get('currentuser'), opts.get('rev'))):
2356 opts.get('currentuser'), opts.get('rev'))):
2357 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2357 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2358
2358
2359 return _abortgraft(ui, repo, graftstate)
2359 return _abortgraft(ui, repo, graftstate)
2360 elif opts.get('continue'):
2360 elif opts.get('continue'):
2361 cont = True
2361 cont = True
2362 if revs:
2362 if revs:
2363 raise error.Abort(_("can't specify --continue and revisions"))
2363 raise error.Abort(_("can't specify --continue and revisions"))
2364 # read in unfinished revisions
2364 # read in unfinished revisions
2365 if graftstate.exists():
2365 if graftstate.exists():
2366 statedata = _readgraftstate(repo, graftstate)
2366 statedata = _readgraftstate(repo, graftstate)
2367 if statedata.get('date'):
2367 if statedata.get('date'):
2368 opts['date'] = statedata['date']
2368 opts['date'] = statedata['date']
2369 if statedata.get('user'):
2369 if statedata.get('user'):
2370 opts['user'] = statedata['user']
2370 opts['user'] = statedata['user']
2371 if statedata.get('log'):
2371 if statedata.get('log'):
2372 opts['log'] = True
2372 opts['log'] = True
2373 if statedata.get('no_commit'):
2373 if statedata.get('no_commit'):
2374 opts['no_commit'] = statedata.get('no_commit')
2374 opts['no_commit'] = statedata.get('no_commit')
2375 nodes = statedata['nodes']
2375 nodes = statedata['nodes']
2376 revs = [repo[node].rev() for node in nodes]
2376 revs = [repo[node].rev() for node in nodes]
2377 else:
2377 else:
2378 cmdutil.wrongtooltocontinue(repo, _('graft'))
2378 cmdutil.wrongtooltocontinue(repo, _('graft'))
2379 else:
2379 else:
2380 if not revs:
2380 if not revs:
2381 raise error.Abort(_('no revisions specified'))
2381 raise error.Abort(_('no revisions specified'))
2382 cmdutil.checkunfinished(repo)
2382 cmdutil.checkunfinished(repo)
2383 cmdutil.bailifchanged(repo)
2383 cmdutil.bailifchanged(repo)
2384 revs = scmutil.revrange(repo, revs)
2384 revs = scmutil.revrange(repo, revs)
2385
2385
2386 skipped = set()
2386 skipped = set()
2387 # check for merges
2387 # check for merges
2388 for rev in repo.revs('%ld and merge()', revs):
2388 for rev in repo.revs('%ld and merge()', revs):
2389 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2389 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2390 skipped.add(rev)
2390 skipped.add(rev)
2391 revs = [r for r in revs if r not in skipped]
2391 revs = [r for r in revs if r not in skipped]
2392 if not revs:
2392 if not revs:
2393 return -1
2393 return -1
2394
2394
2395 # Don't check in the --continue case, in effect retaining --force across
2395 # Don't check in the --continue case, in effect retaining --force across
2396 # --continues. That's because without --force, any revisions we decided to
2396 # --continues. That's because without --force, any revisions we decided to
2397 # skip would have been filtered out here, so they wouldn't have made their
2397 # skip would have been filtered out here, so they wouldn't have made their
2398 # way to the graftstate. With --force, any revisions we would have otherwise
2398 # way to the graftstate. With --force, any revisions we would have otherwise
2399 # skipped would not have been filtered out, and if they hadn't been applied
2399 # skipped would not have been filtered out, and if they hadn't been applied
2400 # already, they'd have been in the graftstate.
2400 # already, they'd have been in the graftstate.
2401 if not (cont or opts.get('force')):
2401 if not (cont or opts.get('force')):
2402 # check for ancestors of dest branch
2402 # check for ancestors of dest branch
2403 crev = repo['.'].rev()
2403 crev = repo['.'].rev()
2404 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2404 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2405 # XXX make this lazy in the future
2405 # XXX make this lazy in the future
2406 # don't mutate while iterating, create a copy
2406 # don't mutate while iterating, create a copy
2407 for rev in list(revs):
2407 for rev in list(revs):
2408 if rev in ancestors:
2408 if rev in ancestors:
2409 ui.warn(_('skipping ancestor revision %d:%s\n') %
2409 ui.warn(_('skipping ancestor revision %d:%s\n') %
2410 (rev, repo[rev]))
2410 (rev, repo[rev]))
2411 # XXX remove on list is slow
2411 # XXX remove on list is slow
2412 revs.remove(rev)
2412 revs.remove(rev)
2413 if not revs:
2413 if not revs:
2414 return -1
2414 return -1
2415
2415
2416 # analyze revs for earlier grafts
2416 # analyze revs for earlier grafts
2417 ids = {}
2417 ids = {}
2418 for ctx in repo.set("%ld", revs):
2418 for ctx in repo.set("%ld", revs):
2419 ids[ctx.hex()] = ctx.rev()
2419 ids[ctx.hex()] = ctx.rev()
2420 n = ctx.extra().get('source')
2420 n = ctx.extra().get('source')
2421 if n:
2421 if n:
2422 ids[n] = ctx.rev()
2422 ids[n] = ctx.rev()
2423
2423
2424 # check ancestors for earlier grafts
2424 # check ancestors for earlier grafts
2425 ui.debug('scanning for duplicate grafts\n')
2425 ui.debug('scanning for duplicate grafts\n')
2426
2426
2427 # The only changesets we can be sure doesn't contain grafts of any
2427 # The only changesets we can be sure doesn't contain grafts of any
2428 # revs, are the ones that are common ancestors of *all* revs:
2428 # revs, are the ones that are common ancestors of *all* revs:
2429 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2429 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2430 ctx = repo[rev]
2430 ctx = repo[rev]
2431 n = ctx.extra().get('source')
2431 n = ctx.extra().get('source')
2432 if n in ids:
2432 if n in ids:
2433 try:
2433 try:
2434 r = repo[n].rev()
2434 r = repo[n].rev()
2435 except error.RepoLookupError:
2435 except error.RepoLookupError:
2436 r = None
2436 r = None
2437 if r in revs:
2437 if r in revs:
2438 ui.warn(_('skipping revision %d:%s '
2438 ui.warn(_('skipping revision %d:%s '
2439 '(already grafted to %d:%s)\n')
2439 '(already grafted to %d:%s)\n')
2440 % (r, repo[r], rev, ctx))
2440 % (r, repo[r], rev, ctx))
2441 revs.remove(r)
2441 revs.remove(r)
2442 elif ids[n] in revs:
2442 elif ids[n] in revs:
2443 if r is None:
2443 if r is None:
2444 ui.warn(_('skipping already grafted revision %d:%s '
2444 ui.warn(_('skipping already grafted revision %d:%s '
2445 '(%d:%s also has unknown origin %s)\n')
2445 '(%d:%s also has unknown origin %s)\n')
2446 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2446 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2447 else:
2447 else:
2448 ui.warn(_('skipping already grafted revision %d:%s '
2448 ui.warn(_('skipping already grafted revision %d:%s '
2449 '(%d:%s also has origin %d:%s)\n')
2449 '(%d:%s also has origin %d:%s)\n')
2450 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2450 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2451 revs.remove(ids[n])
2451 revs.remove(ids[n])
2452 elif ctx.hex() in ids:
2452 elif ctx.hex() in ids:
2453 r = ids[ctx.hex()]
2453 r = ids[ctx.hex()]
2454 ui.warn(_('skipping already grafted revision %d:%s '
2454 ui.warn(_('skipping already grafted revision %d:%s '
2455 '(was grafted from %d:%s)\n') %
2455 '(was grafted from %d:%s)\n') %
2456 (r, repo[r], rev, ctx))
2456 (r, repo[r], rev, ctx))
2457 revs.remove(r)
2457 revs.remove(r)
2458 if not revs:
2458 if not revs:
2459 return -1
2459 return -1
2460
2460
2461 if opts.get('no_commit'):
2461 if opts.get('no_commit'):
2462 statedata['no_commit'] = True
2462 statedata['no_commit'] = True
2463 for pos, ctx in enumerate(repo.set("%ld", revs)):
2463 for pos, ctx in enumerate(repo.set("%ld", revs)):
2464 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2464 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2465 ctx.description().split('\n', 1)[0])
2465 ctx.description().split('\n', 1)[0])
2466 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2466 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2467 if names:
2467 if names:
2468 desc += ' (%s)' % ' '.join(names)
2468 desc += ' (%s)' % ' '.join(names)
2469 ui.status(_('grafting %s\n') % desc)
2469 ui.status(_('grafting %s\n') % desc)
2470 if opts.get('dry_run'):
2470 if opts.get('dry_run'):
2471 continue
2471 continue
2472
2472
2473 source = ctx.extra().get('source')
2473 source = ctx.extra().get('source')
2474 extra = {}
2474 extra = {}
2475 if source:
2475 if source:
2476 extra['source'] = source
2476 extra['source'] = source
2477 extra['intermediate-source'] = ctx.hex()
2477 extra['intermediate-source'] = ctx.hex()
2478 else:
2478 else:
2479 extra['source'] = ctx.hex()
2479 extra['source'] = ctx.hex()
2480 user = ctx.user()
2480 user = ctx.user()
2481 if opts.get('user'):
2481 if opts.get('user'):
2482 user = opts['user']
2482 user = opts['user']
2483 statedata['user'] = user
2483 statedata['user'] = user
2484 date = ctx.date()
2484 date = ctx.date()
2485 if opts.get('date'):
2485 if opts.get('date'):
2486 date = opts['date']
2486 date = opts['date']
2487 statedata['date'] = date
2487 statedata['date'] = date
2488 message = ctx.description()
2488 message = ctx.description()
2489 if opts.get('log'):
2489 if opts.get('log'):
2490 message += '\n(grafted from %s)' % ctx.hex()
2490 message += '\n(grafted from %s)' % ctx.hex()
2491 statedata['log'] = True
2491 statedata['log'] = True
2492
2492
2493 # we don't merge the first commit when continuing
2493 # we don't merge the first commit when continuing
2494 if not cont:
2494 if not cont:
2495 # perform the graft merge with p1(rev) as 'ancestor'
2495 # perform the graft merge with p1(rev) as 'ancestor'
2496 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2496 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2497 with ui.configoverride(overrides, 'graft'):
2497 with ui.configoverride(overrides, 'graft'):
2498 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2498 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2499 # report any conflicts
2499 # report any conflicts
2500 if stats.unresolvedcount > 0:
2500 if stats.unresolvedcount > 0:
2501 # write out state for --continue
2501 # write out state for --continue
2502 nodes = [repo[rev].hex() for rev in revs[pos:]]
2502 nodes = [repo[rev].hex() for rev in revs[pos:]]
2503 statedata['nodes'] = nodes
2503 statedata['nodes'] = nodes
2504 stateversion = 1
2504 stateversion = 1
2505 graftstate.save(stateversion, statedata)
2505 graftstate.save(stateversion, statedata)
2506 hint = _("use 'hg resolve' and 'hg graft --continue'")
2506 hint = _("use 'hg resolve' and 'hg graft --continue'")
2507 raise error.Abort(
2507 raise error.Abort(
2508 _("unresolved conflicts, can't continue"),
2508 _("unresolved conflicts, can't continue"),
2509 hint=hint)
2509 hint=hint)
2510 else:
2510 else:
2511 cont = False
2511 cont = False
2512
2512
2513 # commit if --no-commit is false
2513 # commit if --no-commit is false
2514 if not opts.get('no_commit'):
2514 if not opts.get('no_commit'):
2515 node = repo.commit(text=message, user=user, date=date, extra=extra,
2515 node = repo.commit(text=message, user=user, date=date, extra=extra,
2516 editor=editor)
2516 editor=editor)
2517 if node is None:
2517 if node is None:
2518 ui.warn(
2518 ui.warn(
2519 _('note: graft of %d:%s created no changes to commit\n') %
2519 _('note: graft of %d:%s created no changes to commit\n') %
2520 (ctx.rev(), ctx))
2520 (ctx.rev(), ctx))
2521 # checking that newnodes exist because old state files won't have it
2521 # checking that newnodes exist because old state files won't have it
2522 elif statedata.get('newnodes') is not None:
2522 elif statedata.get('newnodes') is not None:
2523 statedata['newnodes'].append(node)
2523 statedata['newnodes'].append(node)
2524
2524
2525 # remove state when we complete successfully
2525 # remove state when we complete successfully
2526 if not opts.get('dry_run'):
2526 if not opts.get('dry_run'):
2527 graftstate.delete()
2527 graftstate.delete()
2528
2528
2529 return 0
2529 return 0
2530
2530
2531 def _abortgraft(ui, repo, graftstate):
2531 def _abortgraft(ui, repo, graftstate):
2532 """abort the interrupted graft and rollbacks to the state before interrupted
2532 """abort the interrupted graft and rollbacks to the state before interrupted
2533 graft"""
2533 graft"""
2534 if not graftstate.exists():
2534 if not graftstate.exists():
2535 raise error.Abort(_("no interrupted graft to abort"))
2535 raise error.Abort(_("no interrupted graft to abort"))
2536 statedata = _readgraftstate(repo, graftstate)
2536 statedata = _readgraftstate(repo, graftstate)
2537 newnodes = statedata.get('newnodes')
2537 newnodes = statedata.get('newnodes')
2538 if newnodes is None:
2538 if newnodes is None:
2539 # and old graft state which does not have all the data required to abort
2539 # and old graft state which does not have all the data required to abort
2540 # the graft
2540 # the graft
2541 raise error.Abort(_("cannot abort using an old graftstate"))
2541 raise error.Abort(_("cannot abort using an old graftstate"))
2542
2542
2543 # changeset from which graft operation was started
2543 # changeset from which graft operation was started
2544 startctx = None
2544 startctx = None
2545 if len(newnodes) > 0:
2545 if len(newnodes) > 0:
2546 startctx = repo[newnodes[0]].p1()
2546 startctx = repo[newnodes[0]].p1()
2547 else:
2547 else:
2548 startctx = repo['.']
2548 startctx = repo['.']
2549 # whether to strip or not
2549 # whether to strip or not
2550 cleanup = False
2550 cleanup = False
2551 if newnodes:
2551 if newnodes:
2552 newnodes = [repo[r].rev() for r in newnodes]
2552 newnodes = [repo[r].rev() for r in newnodes]
2553 cleanup = True
2553 cleanup = True
2554 # checking that none of the newnodes turned public or is public
2554 # checking that none of the newnodes turned public or is public
2555 immutable = [c for c in newnodes if not repo[c].mutable()]
2555 immutable = [c for c in newnodes if not repo[c].mutable()]
2556 if immutable:
2556 if immutable:
2557 repo.ui.warn(_("cannot clean up public changesets %s\n")
2557 repo.ui.warn(_("cannot clean up public changesets %s\n")
2558 % ', '.join(bytes(repo[r]) for r in immutable),
2558 % ', '.join(bytes(repo[r]) for r in immutable),
2559 hint=_("see 'hg help phases' for details"))
2559 hint=_("see 'hg help phases' for details"))
2560 cleanup = False
2560 cleanup = False
2561
2561
2562 # checking that no new nodes are created on top of grafted revs
2562 # checking that no new nodes are created on top of grafted revs
2563 desc = set(repo.changelog.descendants(newnodes))
2563 desc = set(repo.changelog.descendants(newnodes))
2564 if desc - set(newnodes):
2564 if desc - set(newnodes):
2565 repo.ui.warn(_("new changesets detected on destination "
2565 repo.ui.warn(_("new changesets detected on destination "
2566 "branch, can't strip\n"))
2566 "branch, can't strip\n"))
2567 cleanup = False
2567 cleanup = False
2568
2568
2569 if cleanup:
2569 if cleanup:
2570 with repo.wlock(), repo.lock():
2570 with repo.wlock(), repo.lock():
2571 hg.updaterepo(repo, startctx.node(), overwrite=True)
2571 hg.updaterepo(repo, startctx.node(), overwrite=True)
2572 # stripping the new nodes created
2572 # stripping the new nodes created
2573 strippoints = [c.node() for c in repo.set("roots(%ld)",
2573 strippoints = [c.node() for c in repo.set("roots(%ld)",
2574 newnodes)]
2574 newnodes)]
2575 repair.strip(repo.ui, repo, strippoints, backup=False)
2575 repair.strip(repo.ui, repo, strippoints, backup=False)
2576
2576
2577 if not cleanup:
2577 if not cleanup:
2578 # we don't update to the startnode if we can't strip
2578 # we don't update to the startnode if we can't strip
2579 startctx = repo['.']
2579 startctx = repo['.']
2580 hg.updaterepo(repo, startctx.node(), overwrite=True)
2580 hg.updaterepo(repo, startctx.node(), overwrite=True)
2581
2581
2582 ui.status(_("graft aborted\n"))
2582 ui.status(_("graft aborted\n"))
2583 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2583 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2584 graftstate.delete()
2584 graftstate.delete()
2585 return 0
2585 return 0
2586
2586
2587 def _readgraftstate(repo, graftstate):
2587 def _readgraftstate(repo, graftstate):
2588 """read the graft state file and return a dict of the data stored in it"""
2588 """read the graft state file and return a dict of the data stored in it"""
2589 try:
2589 try:
2590 return graftstate.read()
2590 return graftstate.read()
2591 except error.CorruptedState:
2591 except error.CorruptedState:
2592 nodes = repo.vfs.read('graftstate').splitlines()
2592 nodes = repo.vfs.read('graftstate').splitlines()
2593 return {'nodes': nodes}
2593 return {'nodes': nodes}
2594
2594
2595 def _stopgraft(ui, repo, graftstate):
2595 def _stopgraft(ui, repo, graftstate):
2596 """stop the interrupted graft"""
2596 """stop the interrupted graft"""
2597 if not graftstate.exists():
2597 if not graftstate.exists():
2598 raise error.Abort(_("no interrupted graft found"))
2598 raise error.Abort(_("no interrupted graft found"))
2599 pctx = repo['.']
2599 pctx = repo['.']
2600 hg.updaterepo(repo, pctx.node(), overwrite=True)
2600 hg.updaterepo(repo, pctx.node(), overwrite=True)
2601 graftstate.delete()
2601 graftstate.delete()
2602 ui.status(_("stopped the interrupted graft\n"))
2602 ui.status(_("stopped the interrupted graft\n"))
2603 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2603 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2604 return 0
2604 return 0
2605
2605
2606 @command('grep',
2606 @command('grep',
2607 [('0', 'print0', None, _('end fields with NUL')),
2607 [('0', 'print0', None, _('end fields with NUL')),
2608 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2608 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2609 ('', 'diff', None, _('print all revisions when the term was introduced '
2609 ('', 'diff', None, _('print all revisions when the term was introduced '
2610 'or removed')),
2610 'or removed')),
2611 ('a', 'text', None, _('treat all files as text')),
2611 ('a', 'text', None, _('treat all files as text')),
2612 ('f', 'follow', None,
2612 ('f', 'follow', None,
2613 _('follow changeset history,'
2613 _('follow changeset history,'
2614 ' or file history across copies and renames')),
2614 ' or file history across copies and renames')),
2615 ('i', 'ignore-case', None, _('ignore case when matching')),
2615 ('i', 'ignore-case', None, _('ignore case when matching')),
2616 ('l', 'files-with-matches', None,
2616 ('l', 'files-with-matches', None,
2617 _('print only filenames and revisions that match')),
2617 _('print only filenames and revisions that match')),
2618 ('n', 'line-number', None, _('print matching line numbers')),
2618 ('n', 'line-number', None, _('print matching line numbers')),
2619 ('r', 'rev', [],
2619 ('r', 'rev', [],
2620 _('only search files changed within revision range'), _('REV')),
2620 _('only search files changed within revision range'), _('REV')),
2621 ('', 'all-files', None,
2621 ('', 'all-files', None,
2622 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2622 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2623 ('u', 'user', None, _('list the author (long with -v)')),
2623 ('u', 'user', None, _('list the author (long with -v)')),
2624 ('d', 'date', None, _('list the date (short with -q)')),
2624 ('d', 'date', None, _('list the date (short with -q)')),
2625 ] + formatteropts + walkopts,
2625 ] + formatteropts + walkopts,
2626 _('[OPTION]... PATTERN [FILE]...'),
2626 _('[OPTION]... PATTERN [FILE]...'),
2627 inferrepo=True,
2627 inferrepo=True,
2628 intents={INTENT_READONLY})
2628 intents={INTENT_READONLY})
2629 def grep(ui, repo, pattern, *pats, **opts):
2629 def grep(ui, repo, pattern, *pats, **opts):
2630 """search revision history for a pattern in specified files
2630 """search revision history for a pattern in specified files
2631
2631
2632 Search revision history for a regular expression in the specified
2632 Search revision history for a regular expression in the specified
2633 files or the entire project.
2633 files or the entire project.
2634
2634
2635 By default, grep prints the most recent revision number for each
2635 By default, grep prints the most recent revision number for each
2636 file in which it finds a match. To get it to print every revision
2636 file in which it finds a match. To get it to print every revision
2637 that contains a change in match status ("-" for a match that becomes
2637 that contains a change in match status ("-" for a match that becomes
2638 a non-match, or "+" for a non-match that becomes a match), use the
2638 a non-match, or "+" for a non-match that becomes a match), use the
2639 --diff flag.
2639 --diff flag.
2640
2640
2641 PATTERN can be any Python (roughly Perl-compatible) regular
2641 PATTERN can be any Python (roughly Perl-compatible) regular
2642 expression.
2642 expression.
2643
2643
2644 If no FILEs are specified (and -f/--follow isn't set), all files in
2644 If no FILEs are specified (and -f/--follow isn't set), all files in
2645 the repository are searched, including those that don't exist in the
2645 the repository are searched, including those that don't exist in the
2646 current branch or have been deleted in a prior changeset.
2646 current branch or have been deleted in a prior changeset.
2647
2647
2648 .. container:: verbose
2648 .. container:: verbose
2649
2649
2650 Template:
2650 Template:
2651
2651
2652 The following keywords are supported in addition to the common template
2652 The following keywords are supported in addition to the common template
2653 keywords and functions. See also :hg:`help templates`.
2653 keywords and functions. See also :hg:`help templates`.
2654
2654
2655 :change: String. Character denoting insertion ``+`` or removal ``-``.
2655 :change: String. Character denoting insertion ``+`` or removal ``-``.
2656 Available if ``--diff`` is specified.
2656 Available if ``--diff`` is specified.
2657 :lineno: Integer. Line number of the match.
2657 :lineno: Integer. Line number of the match.
2658 :path: String. Repository-absolute path of the file.
2658 :path: String. Repository-absolute path of the file.
2659 :texts: List of text chunks.
2659 :texts: List of text chunks.
2660
2660
2661 And each entry of ``{texts}`` provides the following sub-keywords.
2661 And each entry of ``{texts}`` provides the following sub-keywords.
2662
2662
2663 :matched: Boolean. True if the chunk matches the specified pattern.
2663 :matched: Boolean. True if the chunk matches the specified pattern.
2664 :text: String. Chunk content.
2664 :text: String. Chunk content.
2665
2665
2666 See :hg:`help templates.operators` for the list expansion syntax.
2666 See :hg:`help templates.operators` for the list expansion syntax.
2667
2667
2668 Returns 0 if a match is found, 1 otherwise.
2668 Returns 0 if a match is found, 1 otherwise.
2669 """
2669 """
2670 opts = pycompat.byteskwargs(opts)
2670 opts = pycompat.byteskwargs(opts)
2671 diff = opts.get('all') or opts.get('diff')
2671 diff = opts.get('all') or opts.get('diff')
2672 all_files = opts.get('all_files')
2672 all_files = opts.get('all_files')
2673 if diff and opts.get('all_files'):
2673 if diff and opts.get('all_files'):
2674 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2674 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2675 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2675 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2676 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2676 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2677 # experimental config: commands.grep.all-files
2677 # experimental config: commands.grep.all-files
2678 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2678 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2679 plaingrep = opts.get('all_files') and not opts.get('rev')
2679 plaingrep = opts.get('all_files') and not opts.get('rev')
2680 if plaingrep:
2680 if plaingrep:
2681 opts['rev'] = ['wdir()']
2681 opts['rev'] = ['wdir()']
2682
2682
2683 reflags = re.M
2683 reflags = re.M
2684 if opts.get('ignore_case'):
2684 if opts.get('ignore_case'):
2685 reflags |= re.I
2685 reflags |= re.I
2686 try:
2686 try:
2687 regexp = util.re.compile(pattern, reflags)
2687 regexp = util.re.compile(pattern, reflags)
2688 except re.error as inst:
2688 except re.error as inst:
2689 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2689 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2690 return 1
2690 return 1
2691 sep, eol = ':', '\n'
2691 sep, eol = ':', '\n'
2692 if opts.get('print0'):
2692 if opts.get('print0'):
2693 sep = eol = '\0'
2693 sep = eol = '\0'
2694
2694
2695 getfile = util.lrucachefunc(repo.file)
2695 getfile = util.lrucachefunc(repo.file)
2696
2696
2697 def matchlines(body):
2697 def matchlines(body):
2698 begin = 0
2698 begin = 0
2699 linenum = 0
2699 linenum = 0
2700 while begin < len(body):
2700 while begin < len(body):
2701 match = regexp.search(body, begin)
2701 match = regexp.search(body, begin)
2702 if not match:
2702 if not match:
2703 break
2703 break
2704 mstart, mend = match.span()
2704 mstart, mend = match.span()
2705 linenum += body.count('\n', begin, mstart) + 1
2705 linenum += body.count('\n', begin, mstart) + 1
2706 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2706 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2707 begin = body.find('\n', mend) + 1 or len(body) + 1
2707 begin = body.find('\n', mend) + 1 or len(body) + 1
2708 lend = begin - 1
2708 lend = begin - 1
2709 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2709 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2710
2710
2711 class linestate(object):
2711 class linestate(object):
2712 def __init__(self, line, linenum, colstart, colend):
2712 def __init__(self, line, linenum, colstart, colend):
2713 self.line = line
2713 self.line = line
2714 self.linenum = linenum
2714 self.linenum = linenum
2715 self.colstart = colstart
2715 self.colstart = colstart
2716 self.colend = colend
2716 self.colend = colend
2717
2717
2718 def __hash__(self):
2718 def __hash__(self):
2719 return hash((self.linenum, self.line))
2719 return hash((self.linenum, self.line))
2720
2720
2721 def __eq__(self, other):
2721 def __eq__(self, other):
2722 return self.line == other.line
2722 return self.line == other.line
2723
2723
2724 def findpos(self):
2724 def findpos(self):
2725 """Iterate all (start, end) indices of matches"""
2725 """Iterate all (start, end) indices of matches"""
2726 yield self.colstart, self.colend
2726 yield self.colstart, self.colend
2727 p = self.colend
2727 p = self.colend
2728 while p < len(self.line):
2728 while p < len(self.line):
2729 m = regexp.search(self.line, p)
2729 m = regexp.search(self.line, p)
2730 if not m:
2730 if not m:
2731 break
2731 break
2732 yield m.span()
2732 yield m.span()
2733 p = m.end()
2733 p = m.end()
2734
2734
2735 matches = {}
2735 matches = {}
2736 copies = {}
2736 copies = {}
2737 def grepbody(fn, rev, body):
2737 def grepbody(fn, rev, body):
2738 matches[rev].setdefault(fn, [])
2738 matches[rev].setdefault(fn, [])
2739 m = matches[rev][fn]
2739 m = matches[rev][fn]
2740 for lnum, cstart, cend, line in matchlines(body):
2740 for lnum, cstart, cend, line in matchlines(body):
2741 s = linestate(line, lnum, cstart, cend)
2741 s = linestate(line, lnum, cstart, cend)
2742 m.append(s)
2742 m.append(s)
2743
2743
2744 def difflinestates(a, b):
2744 def difflinestates(a, b):
2745 sm = difflib.SequenceMatcher(None, a, b)
2745 sm = difflib.SequenceMatcher(None, a, b)
2746 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2746 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2747 if tag == r'insert':
2747 if tag == r'insert':
2748 for i in pycompat.xrange(blo, bhi):
2748 for i in pycompat.xrange(blo, bhi):
2749 yield ('+', b[i])
2749 yield ('+', b[i])
2750 elif tag == r'delete':
2750 elif tag == r'delete':
2751 for i in pycompat.xrange(alo, ahi):
2751 for i in pycompat.xrange(alo, ahi):
2752 yield ('-', a[i])
2752 yield ('-', a[i])
2753 elif tag == r'replace':
2753 elif tag == r'replace':
2754 for i in pycompat.xrange(alo, ahi):
2754 for i in pycompat.xrange(alo, ahi):
2755 yield ('-', a[i])
2755 yield ('-', a[i])
2756 for i in pycompat.xrange(blo, bhi):
2756 for i in pycompat.xrange(blo, bhi):
2757 yield ('+', b[i])
2757 yield ('+', b[i])
2758
2758
2759 def display(fm, fn, ctx, pstates, states):
2759 def display(fm, fn, ctx, pstates, states):
2760 rev = scmutil.intrev(ctx)
2760 rev = scmutil.intrev(ctx)
2761 if fm.isplain():
2761 if fm.isplain():
2762 formatuser = ui.shortuser
2762 formatuser = ui.shortuser
2763 else:
2763 else:
2764 formatuser = pycompat.bytestr
2764 formatuser = pycompat.bytestr
2765 if ui.quiet:
2765 if ui.quiet:
2766 datefmt = '%Y-%m-%d'
2766 datefmt = '%Y-%m-%d'
2767 else:
2767 else:
2768 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2768 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2769 found = False
2769 found = False
2770 @util.cachefunc
2770 @util.cachefunc
2771 def binary():
2771 def binary():
2772 flog = getfile(fn)
2772 flog = getfile(fn)
2773 try:
2773 try:
2774 return stringutil.binary(flog.read(ctx.filenode(fn)))
2774 return stringutil.binary(flog.read(ctx.filenode(fn)))
2775 except error.WdirUnsupported:
2775 except error.WdirUnsupported:
2776 return ctx[fn].isbinary()
2776 return ctx[fn].isbinary()
2777
2777
2778 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2778 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2779 if diff:
2779 if diff:
2780 iter = difflinestates(pstates, states)
2780 iter = difflinestates(pstates, states)
2781 else:
2781 else:
2782 iter = [('', l) for l in states]
2782 iter = [('', l) for l in states]
2783 for change, l in iter:
2783 for change, l in iter:
2784 fm.startitem()
2784 fm.startitem()
2785 fm.context(ctx=ctx)
2785 fm.context(ctx=ctx)
2786 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2786 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2787
2787
2788 cols = [
2788 cols = [
2789 ('filename', '%s', fn, True),
2789 ('filename', '%s', fn, True),
2790 ('rev', '%d', rev, not plaingrep),
2790 ('rev', '%d', rev, not plaingrep),
2791 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2791 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2792 ]
2792 ]
2793 if diff:
2793 if diff:
2794 cols.append(('change', '%s', change, True))
2794 cols.append(('change', '%s', change, True))
2795 cols.extend([
2795 cols.extend([
2796 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2796 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2797 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2797 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2798 opts.get('date')),
2798 opts.get('date')),
2799 ])
2799 ])
2800 lastcol = next(
2800 lastcol = next(
2801 name for name, fmt, data, cond in reversed(cols) if cond)
2801 name for name, fmt, data, cond in reversed(cols) if cond)
2802 for name, fmt, data, cond in cols:
2802 for name, fmt, data, cond in cols:
2803 field = fieldnamemap.get(name, name)
2803 field = fieldnamemap.get(name, name)
2804 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2804 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2805 if cond and name != lastcol:
2805 if cond and name != lastcol:
2806 fm.plain(sep, label='grep.sep')
2806 fm.plain(sep, label='grep.sep')
2807 if not opts.get('files_with_matches'):
2807 if not opts.get('files_with_matches'):
2808 fm.plain(sep, label='grep.sep')
2808 fm.plain(sep, label='grep.sep')
2809 if not opts.get('text') and binary():
2809 if not opts.get('text') and binary():
2810 fm.plain(_(" Binary file matches"))
2810 fm.plain(_(" Binary file matches"))
2811 else:
2811 else:
2812 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2812 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2813 fm.plain(eol)
2813 fm.plain(eol)
2814 found = True
2814 found = True
2815 if opts.get('files_with_matches'):
2815 if opts.get('files_with_matches'):
2816 break
2816 break
2817 return found
2817 return found
2818
2818
2819 def displaymatches(fm, l):
2819 def displaymatches(fm, l):
2820 p = 0
2820 p = 0
2821 for s, e in l.findpos():
2821 for s, e in l.findpos():
2822 if p < s:
2822 if p < s:
2823 fm.startitem()
2823 fm.startitem()
2824 fm.write('text', '%s', l.line[p:s])
2824 fm.write('text', '%s', l.line[p:s])
2825 fm.data(matched=False)
2825 fm.data(matched=False)
2826 fm.startitem()
2826 fm.startitem()
2827 fm.write('text', '%s', l.line[s:e], label='grep.match')
2827 fm.write('text', '%s', l.line[s:e], label='grep.match')
2828 fm.data(matched=True)
2828 fm.data(matched=True)
2829 p = e
2829 p = e
2830 if p < len(l.line):
2830 if p < len(l.line):
2831 fm.startitem()
2831 fm.startitem()
2832 fm.write('text', '%s', l.line[p:])
2832 fm.write('text', '%s', l.line[p:])
2833 fm.data(matched=False)
2833 fm.data(matched=False)
2834 fm.end()
2834 fm.end()
2835
2835
2836 skip = {}
2836 skip = {}
2837 revfiles = {}
2837 revfiles = {}
2838 match = scmutil.match(repo[None], pats, opts)
2838 match = scmutil.match(repo[None], pats, opts)
2839 found = False
2839 found = False
2840 follow = opts.get('follow')
2840 follow = opts.get('follow')
2841
2841
2842 def prep(ctx, fns):
2842 def prep(ctx, fns):
2843 rev = ctx.rev()
2843 rev = ctx.rev()
2844 pctx = ctx.p1()
2844 pctx = ctx.p1()
2845 parent = pctx.rev()
2845 parent = pctx.rev()
2846 matches.setdefault(rev, {})
2846 matches.setdefault(rev, {})
2847 matches.setdefault(parent, {})
2847 matches.setdefault(parent, {})
2848 files = revfiles.setdefault(rev, [])
2848 files = revfiles.setdefault(rev, [])
2849 for fn in fns:
2849 for fn in fns:
2850 flog = getfile(fn)
2850 flog = getfile(fn)
2851 try:
2851 try:
2852 fnode = ctx.filenode(fn)
2852 fnode = ctx.filenode(fn)
2853 except error.LookupError:
2853 except error.LookupError:
2854 continue
2854 continue
2855 try:
2855 try:
2856 copied = flog.renamed(fnode)
2856 copied = flog.renamed(fnode)
2857 except error.WdirUnsupported:
2857 except error.WdirUnsupported:
2858 copied = ctx[fn].renamed()
2858 copied = ctx[fn].renamed()
2859 copy = follow and copied and copied[0]
2859 copy = follow and copied and copied[0]
2860 if copy:
2860 if copy:
2861 copies.setdefault(rev, {})[fn] = copy
2861 copies.setdefault(rev, {})[fn] = copy
2862 if fn in skip:
2862 if fn in skip:
2863 if copy:
2863 if copy:
2864 skip[copy] = True
2864 skip[copy] = True
2865 continue
2865 continue
2866 files.append(fn)
2866 files.append(fn)
2867
2867
2868 if fn not in matches[rev]:
2868 if fn not in matches[rev]:
2869 try:
2869 try:
2870 content = flog.read(fnode)
2870 content = flog.read(fnode)
2871 except error.WdirUnsupported:
2871 except error.WdirUnsupported:
2872 content = ctx[fn].data()
2872 content = ctx[fn].data()
2873 grepbody(fn, rev, content)
2873 grepbody(fn, rev, content)
2874
2874
2875 pfn = copy or fn
2875 pfn = copy or fn
2876 if pfn not in matches[parent]:
2876 if pfn not in matches[parent]:
2877 try:
2877 try:
2878 fnode = pctx.filenode(pfn)
2878 fnode = pctx.filenode(pfn)
2879 grepbody(pfn, parent, flog.read(fnode))
2879 grepbody(pfn, parent, flog.read(fnode))
2880 except error.LookupError:
2880 except error.LookupError:
2881 pass
2881 pass
2882
2882
2883 ui.pager('grep')
2883 ui.pager('grep')
2884 fm = ui.formatter('grep', opts)
2884 fm = ui.formatter('grep', opts)
2885 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2885 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2886 rev = ctx.rev()
2886 rev = ctx.rev()
2887 parent = ctx.p1().rev()
2887 parent = ctx.p1().rev()
2888 for fn in sorted(revfiles.get(rev, [])):
2888 for fn in sorted(revfiles.get(rev, [])):
2889 states = matches[rev][fn]
2889 states = matches[rev][fn]
2890 copy = copies.get(rev, {}).get(fn)
2890 copy = copies.get(rev, {}).get(fn)
2891 if fn in skip:
2891 if fn in skip:
2892 if copy:
2892 if copy:
2893 skip[copy] = True
2893 skip[copy] = True
2894 continue
2894 continue
2895 pstates = matches.get(parent, {}).get(copy or fn, [])
2895 pstates = matches.get(parent, {}).get(copy or fn, [])
2896 if pstates or states:
2896 if pstates or states:
2897 r = display(fm, fn, ctx, pstates, states)
2897 r = display(fm, fn, ctx, pstates, states)
2898 found = found or r
2898 found = found or r
2899 if r and not diff and not all_files:
2899 if r and not diff and not all_files:
2900 skip[fn] = True
2900 skip[fn] = True
2901 if copy:
2901 if copy:
2902 skip[copy] = True
2902 skip[copy] = True
2903 del revfiles[rev]
2903 del revfiles[rev]
2904 # We will keep the matches dict for the duration of the window
2904 # We will keep the matches dict for the duration of the window
2905 # clear the matches dict once the window is over
2905 # clear the matches dict once the window is over
2906 if not revfiles:
2906 if not revfiles:
2907 matches.clear()
2907 matches.clear()
2908 fm.end()
2908 fm.end()
2909
2909
2910 return not found
2910 return not found
2911
2911
2912 @command('heads',
2912 @command('heads',
2913 [('r', 'rev', '',
2913 [('r', 'rev', '',
2914 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2914 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2915 ('t', 'topo', False, _('show topological heads only')),
2915 ('t', 'topo', False, _('show topological heads only')),
2916 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2916 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2917 ('c', 'closed', False, _('show normal and closed branch heads')),
2917 ('c', 'closed', False, _('show normal and closed branch heads')),
2918 ] + templateopts,
2918 ] + templateopts,
2919 _('[-ct] [-r STARTREV] [REV]...'),
2919 _('[-ct] [-r STARTREV] [REV]...'),
2920 intents={INTENT_READONLY})
2920 intents={INTENT_READONLY})
2921 def heads(ui, repo, *branchrevs, **opts):
2921 def heads(ui, repo, *branchrevs, **opts):
2922 """show branch heads
2922 """show branch heads
2923
2923
2924 With no arguments, show all open branch heads in the repository.
2924 With no arguments, show all open branch heads in the repository.
2925 Branch heads are changesets that have no descendants on the
2925 Branch heads are changesets that have no descendants on the
2926 same branch. They are where development generally takes place and
2926 same branch. They are where development generally takes place and
2927 are the usual targets for update and merge operations.
2927 are the usual targets for update and merge operations.
2928
2928
2929 If one or more REVs are given, only open branch heads on the
2929 If one or more REVs are given, only open branch heads on the
2930 branches associated with the specified changesets are shown. This
2930 branches associated with the specified changesets are shown. This
2931 means that you can use :hg:`heads .` to see the heads on the
2931 means that you can use :hg:`heads .` to see the heads on the
2932 currently checked-out branch.
2932 currently checked-out branch.
2933
2933
2934 If -c/--closed is specified, also show branch heads marked closed
2934 If -c/--closed is specified, also show branch heads marked closed
2935 (see :hg:`commit --close-branch`).
2935 (see :hg:`commit --close-branch`).
2936
2936
2937 If STARTREV is specified, only those heads that are descendants of
2937 If STARTREV is specified, only those heads that are descendants of
2938 STARTREV will be displayed.
2938 STARTREV will be displayed.
2939
2939
2940 If -t/--topo is specified, named branch mechanics will be ignored and only
2940 If -t/--topo is specified, named branch mechanics will be ignored and only
2941 topological heads (changesets with no children) will be shown.
2941 topological heads (changesets with no children) will be shown.
2942
2942
2943 Returns 0 if matching heads are found, 1 if not.
2943 Returns 0 if matching heads are found, 1 if not.
2944 """
2944 """
2945
2945
2946 opts = pycompat.byteskwargs(opts)
2946 opts = pycompat.byteskwargs(opts)
2947 start = None
2947 start = None
2948 rev = opts.get('rev')
2948 rev = opts.get('rev')
2949 if rev:
2949 if rev:
2950 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2950 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2951 start = scmutil.revsingle(repo, rev, None).node()
2951 start = scmutil.revsingle(repo, rev, None).node()
2952
2952
2953 if opts.get('topo'):
2953 if opts.get('topo'):
2954 heads = [repo[h] for h in repo.heads(start)]
2954 heads = [repo[h] for h in repo.heads(start)]
2955 else:
2955 else:
2956 heads = []
2956 heads = []
2957 for branch in repo.branchmap():
2957 for branch in repo.branchmap():
2958 heads += repo.branchheads(branch, start, opts.get('closed'))
2958 heads += repo.branchheads(branch, start, opts.get('closed'))
2959 heads = [repo[h] for h in heads]
2959 heads = [repo[h] for h in heads]
2960
2960
2961 if branchrevs:
2961 if branchrevs:
2962 branches = set(repo[r].branch()
2962 branches = set(repo[r].branch()
2963 for r in scmutil.revrange(repo, branchrevs))
2963 for r in scmutil.revrange(repo, branchrevs))
2964 heads = [h for h in heads if h.branch() in branches]
2964 heads = [h for h in heads if h.branch() in branches]
2965
2965
2966 if opts.get('active') and branchrevs:
2966 if opts.get('active') and branchrevs:
2967 dagheads = repo.heads(start)
2967 dagheads = repo.heads(start)
2968 heads = [h for h in heads if h.node() in dagheads]
2968 heads = [h for h in heads if h.node() in dagheads]
2969
2969
2970 if branchrevs:
2970 if branchrevs:
2971 haveheads = set(h.branch() for h in heads)
2971 haveheads = set(h.branch() for h in heads)
2972 if branches - haveheads:
2972 if branches - haveheads:
2973 headless = ', '.join(b for b in branches - haveheads)
2973 headless = ', '.join(b for b in branches - haveheads)
2974 msg = _('no open branch heads found on branches %s')
2974 msg = _('no open branch heads found on branches %s')
2975 if opts.get('rev'):
2975 if opts.get('rev'):
2976 msg += _(' (started at %s)') % opts['rev']
2976 msg += _(' (started at %s)') % opts['rev']
2977 ui.warn((msg + '\n') % headless)
2977 ui.warn((msg + '\n') % headless)
2978
2978
2979 if not heads:
2979 if not heads:
2980 return 1
2980 return 1
2981
2981
2982 ui.pager('heads')
2982 ui.pager('heads')
2983 heads = sorted(heads, key=lambda x: -x.rev())
2983 heads = sorted(heads, key=lambda x: -x.rev())
2984 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2984 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2985 for ctx in heads:
2985 for ctx in heads:
2986 displayer.show(ctx)
2986 displayer.show(ctx)
2987 displayer.close()
2987 displayer.close()
2988
2988
2989 @command('help',
2989 @command('help',
2990 [('e', 'extension', None, _('show only help for extensions')),
2990 [('e', 'extension', None, _('show only help for extensions')),
2991 ('c', 'command', None, _('show only help for commands')),
2991 ('c', 'command', None, _('show only help for commands')),
2992 ('k', 'keyword', None, _('show topics matching keyword')),
2992 ('k', 'keyword', None, _('show topics matching keyword')),
2993 ('s', 'system', [], _('show help for specific platform(s)')),
2993 ('s', 'system', [], _('show help for specific platform(s)')),
2994 ],
2994 ],
2995 _('[-ecks] [TOPIC]'),
2995 _('[-ecks] [TOPIC]'),
2996 norepo=True,
2996 norepo=True,
2997 intents={INTENT_READONLY})
2997 intents={INTENT_READONLY})
2998 def help_(ui, name=None, **opts):
2998 def help_(ui, name=None, **opts):
2999 """show help for a given topic or a help overview
2999 """show help for a given topic or a help overview
3000
3000
3001 With no arguments, print a list of commands with short help messages.
3001 With no arguments, print a list of commands with short help messages.
3002
3002
3003 Given a topic, extension, or command name, print help for that
3003 Given a topic, extension, or command name, print help for that
3004 topic.
3004 topic.
3005
3005
3006 Returns 0 if successful.
3006 Returns 0 if successful.
3007 """
3007 """
3008
3008
3009 keep = opts.get(r'system') or []
3009 keep = opts.get(r'system') or []
3010 if len(keep) == 0:
3010 if len(keep) == 0:
3011 if pycompat.sysplatform.startswith('win'):
3011 if pycompat.sysplatform.startswith('win'):
3012 keep.append('windows')
3012 keep.append('windows')
3013 elif pycompat.sysplatform == 'OpenVMS':
3013 elif pycompat.sysplatform == 'OpenVMS':
3014 keep.append('vms')
3014 keep.append('vms')
3015 elif pycompat.sysplatform == 'plan9':
3015 elif pycompat.sysplatform == 'plan9':
3016 keep.append('plan9')
3016 keep.append('plan9')
3017 else:
3017 else:
3018 keep.append('unix')
3018 keep.append('unix')
3019 keep.append(pycompat.sysplatform.lower())
3019 keep.append(pycompat.sysplatform.lower())
3020 if ui.verbose:
3020 if ui.verbose:
3021 keep.append('verbose')
3021 keep.append('verbose')
3022
3022
3023 commands = sys.modules[__name__]
3023 commands = sys.modules[__name__]
3024 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3024 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3025 ui.pager('help')
3025 ui.pager('help')
3026 ui.write(formatted)
3026 ui.write(formatted)
3027
3027
3028
3028
3029 @command('identify|id',
3029 @command('identify|id',
3030 [('r', 'rev', '',
3030 [('r', 'rev', '',
3031 _('identify the specified revision'), _('REV')),
3031 _('identify the specified revision'), _('REV')),
3032 ('n', 'num', None, _('show local revision number')),
3032 ('n', 'num', None, _('show local revision number')),
3033 ('i', 'id', None, _('show global revision id')),
3033 ('i', 'id', None, _('show global revision id')),
3034 ('b', 'branch', None, _('show branch')),
3034 ('b', 'branch', None, _('show branch')),
3035 ('t', 'tags', None, _('show tags')),
3035 ('t', 'tags', None, _('show tags')),
3036 ('B', 'bookmarks', None, _('show bookmarks')),
3036 ('B', 'bookmarks', None, _('show bookmarks')),
3037 ] + remoteopts + formatteropts,
3037 ] + remoteopts + formatteropts,
3038 _('[-nibtB] [-r REV] [SOURCE]'),
3038 _('[-nibtB] [-r REV] [SOURCE]'),
3039 optionalrepo=True,
3039 optionalrepo=True,
3040 intents={INTENT_READONLY})
3040 intents={INTENT_READONLY})
3041 def identify(ui, repo, source=None, rev=None,
3041 def identify(ui, repo, source=None, rev=None,
3042 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3042 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3043 """identify the working directory or specified revision
3043 """identify the working directory or specified revision
3044
3044
3045 Print a summary identifying the repository state at REV using one or
3045 Print a summary identifying the repository state at REV using one or
3046 two parent hash identifiers, followed by a "+" if the working
3046 two parent hash identifiers, followed by a "+" if the working
3047 directory has uncommitted changes, the branch name (if not default),
3047 directory has uncommitted changes, the branch name (if not default),
3048 a list of tags, and a list of bookmarks.
3048 a list of tags, and a list of bookmarks.
3049
3049
3050 When REV is not given, print a summary of the current state of the
3050 When REV is not given, print a summary of the current state of the
3051 repository including the working directory. Specify -r. to get information
3051 repository including the working directory. Specify -r. to get information
3052 of the working directory parent without scanning uncommitted changes.
3052 of the working directory parent without scanning uncommitted changes.
3053
3053
3054 Specifying a path to a repository root or Mercurial bundle will
3054 Specifying a path to a repository root or Mercurial bundle will
3055 cause lookup to operate on that repository/bundle.
3055 cause lookup to operate on that repository/bundle.
3056
3056
3057 .. container:: verbose
3057 .. container:: verbose
3058
3058
3059 Template:
3059 Template:
3060
3060
3061 The following keywords are supported in addition to the common template
3061 The following keywords are supported in addition to the common template
3062 keywords and functions. See also :hg:`help templates`.
3062 keywords and functions. See also :hg:`help templates`.
3063
3063
3064 :dirty: String. Character ``+`` denoting if the working directory has
3064 :dirty: String. Character ``+`` denoting if the working directory has
3065 uncommitted changes.
3065 uncommitted changes.
3066 :id: String. One or two nodes, optionally followed by ``+``.
3066 :id: String. One or two nodes, optionally followed by ``+``.
3067 :parents: List of strings. Parent nodes of the changeset.
3067 :parents: List of strings. Parent nodes of the changeset.
3068
3068
3069 Examples:
3069 Examples:
3070
3070
3071 - generate a build identifier for the working directory::
3071 - generate a build identifier for the working directory::
3072
3072
3073 hg id --id > build-id.dat
3073 hg id --id > build-id.dat
3074
3074
3075 - find the revision corresponding to a tag::
3075 - find the revision corresponding to a tag::
3076
3076
3077 hg id -n -r 1.3
3077 hg id -n -r 1.3
3078
3078
3079 - check the most recent revision of a remote repository::
3079 - check the most recent revision of a remote repository::
3080
3080
3081 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3081 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3082
3082
3083 See :hg:`log` for generating more information about specific revisions,
3083 See :hg:`log` for generating more information about specific revisions,
3084 including full hash identifiers.
3084 including full hash identifiers.
3085
3085
3086 Returns 0 if successful.
3086 Returns 0 if successful.
3087 """
3087 """
3088
3088
3089 opts = pycompat.byteskwargs(opts)
3089 opts = pycompat.byteskwargs(opts)
3090 if not repo and not source:
3090 if not repo and not source:
3091 raise error.Abort(_("there is no Mercurial repository here "
3091 raise error.Abort(_("there is no Mercurial repository here "
3092 "(.hg not found)"))
3092 "(.hg not found)"))
3093
3093
3094 default = not (num or id or branch or tags or bookmarks)
3094 default = not (num or id or branch or tags or bookmarks)
3095 output = []
3095 output = []
3096 revs = []
3096 revs = []
3097
3097
3098 if source:
3098 if source:
3099 source, branches = hg.parseurl(ui.expandpath(source))
3099 source, branches = hg.parseurl(ui.expandpath(source))
3100 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3100 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3101 repo = peer.local()
3101 repo = peer.local()
3102 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3102 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3103
3103
3104 fm = ui.formatter('identify', opts)
3104 fm = ui.formatter('identify', opts)
3105 fm.startitem()
3105 fm.startitem()
3106
3106
3107 if not repo:
3107 if not repo:
3108 if num or branch or tags:
3108 if num or branch or tags:
3109 raise error.Abort(
3109 raise error.Abort(
3110 _("can't query remote revision number, branch, or tags"))
3110 _("can't query remote revision number, branch, or tags"))
3111 if not rev and revs:
3111 if not rev and revs:
3112 rev = revs[0]
3112 rev = revs[0]
3113 if not rev:
3113 if not rev:
3114 rev = "tip"
3114 rev = "tip"
3115
3115
3116 remoterev = peer.lookup(rev)
3116 remoterev = peer.lookup(rev)
3117 hexrev = fm.hexfunc(remoterev)
3117 hexrev = fm.hexfunc(remoterev)
3118 if default or id:
3118 if default or id:
3119 output = [hexrev]
3119 output = [hexrev]
3120 fm.data(id=hexrev)
3120 fm.data(id=hexrev)
3121
3121
3122 @util.cachefunc
3122 @util.cachefunc
3123 def getbms():
3123 def getbms():
3124 bms = []
3124 bms = []
3125
3125
3126 if 'bookmarks' in peer.listkeys('namespaces'):
3126 if 'bookmarks' in peer.listkeys('namespaces'):
3127 hexremoterev = hex(remoterev)
3127 hexremoterev = hex(remoterev)
3128 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3128 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3129 if bmr == hexremoterev]
3129 if bmr == hexremoterev]
3130
3130
3131 return sorted(bms)
3131 return sorted(bms)
3132
3132
3133 if fm.isplain():
3133 if fm.isplain():
3134 if bookmarks:
3134 if bookmarks:
3135 output.extend(getbms())
3135 output.extend(getbms())
3136 elif default and not ui.quiet:
3136 elif default and not ui.quiet:
3137 # multiple bookmarks for a single parent separated by '/'
3137 # multiple bookmarks for a single parent separated by '/'
3138 bm = '/'.join(getbms())
3138 bm = '/'.join(getbms())
3139 if bm:
3139 if bm:
3140 output.append(bm)
3140 output.append(bm)
3141 else:
3141 else:
3142 fm.data(node=hex(remoterev))
3142 fm.data(node=hex(remoterev))
3143 if bookmarks or 'bookmarks' in fm.datahint():
3143 if bookmarks or 'bookmarks' in fm.datahint():
3144 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3144 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3145 else:
3145 else:
3146 if rev:
3146 if rev:
3147 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3147 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3148 ctx = scmutil.revsingle(repo, rev, None)
3148 ctx = scmutil.revsingle(repo, rev, None)
3149
3149
3150 if ctx.rev() is None:
3150 if ctx.rev() is None:
3151 ctx = repo[None]
3151 ctx = repo[None]
3152 parents = ctx.parents()
3152 parents = ctx.parents()
3153 taglist = []
3153 taglist = []
3154 for p in parents:
3154 for p in parents:
3155 taglist.extend(p.tags())
3155 taglist.extend(p.tags())
3156
3156
3157 dirty = ""
3157 dirty = ""
3158 if ctx.dirty(missing=True, merge=False, branch=False):
3158 if ctx.dirty(missing=True, merge=False, branch=False):
3159 dirty = '+'
3159 dirty = '+'
3160 fm.data(dirty=dirty)
3160 fm.data(dirty=dirty)
3161
3161
3162 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3162 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3163 if default or id:
3163 if default or id:
3164 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3164 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3165 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3165 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3166
3166
3167 if num:
3167 if num:
3168 numoutput = ["%d" % p.rev() for p in parents]
3168 numoutput = ["%d" % p.rev() for p in parents]
3169 output.append("%s%s" % ('+'.join(numoutput), dirty))
3169 output.append("%s%s" % ('+'.join(numoutput), dirty))
3170
3170
3171 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3171 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3172 for p in parents], name='node'))
3172 for p in parents], name='node'))
3173 else:
3173 else:
3174 hexoutput = fm.hexfunc(ctx.node())
3174 hexoutput = fm.hexfunc(ctx.node())
3175 if default or id:
3175 if default or id:
3176 output = [hexoutput]
3176 output = [hexoutput]
3177 fm.data(id=hexoutput)
3177 fm.data(id=hexoutput)
3178
3178
3179 if num:
3179 if num:
3180 output.append(pycompat.bytestr(ctx.rev()))
3180 output.append(pycompat.bytestr(ctx.rev()))
3181 taglist = ctx.tags()
3181 taglist = ctx.tags()
3182
3182
3183 if default and not ui.quiet:
3183 if default and not ui.quiet:
3184 b = ctx.branch()
3184 b = ctx.branch()
3185 if b != 'default':
3185 if b != 'default':
3186 output.append("(%s)" % b)
3186 output.append("(%s)" % b)
3187
3187
3188 # multiple tags for a single parent separated by '/'
3188 # multiple tags for a single parent separated by '/'
3189 t = '/'.join(taglist)
3189 t = '/'.join(taglist)
3190 if t:
3190 if t:
3191 output.append(t)
3191 output.append(t)
3192
3192
3193 # multiple bookmarks for a single parent separated by '/'
3193 # multiple bookmarks for a single parent separated by '/'
3194 bm = '/'.join(ctx.bookmarks())
3194 bm = '/'.join(ctx.bookmarks())
3195 if bm:
3195 if bm:
3196 output.append(bm)
3196 output.append(bm)
3197 else:
3197 else:
3198 if branch:
3198 if branch:
3199 output.append(ctx.branch())
3199 output.append(ctx.branch())
3200
3200
3201 if tags:
3201 if tags:
3202 output.extend(taglist)
3202 output.extend(taglist)
3203
3203
3204 if bookmarks:
3204 if bookmarks:
3205 output.extend(ctx.bookmarks())
3205 output.extend(ctx.bookmarks())
3206
3206
3207 fm.data(node=ctx.hex())
3207 fm.data(node=ctx.hex())
3208 fm.data(branch=ctx.branch())
3208 fm.data(branch=ctx.branch())
3209 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3209 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3210 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3210 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3211 fm.context(ctx=ctx)
3211 fm.context(ctx=ctx)
3212
3212
3213 fm.plain("%s\n" % ' '.join(output))
3213 fm.plain("%s\n" % ' '.join(output))
3214 fm.end()
3214 fm.end()
3215
3215
3216 @command('import|patch',
3216 @command('import|patch',
3217 [('p', 'strip', 1,
3217 [('p', 'strip', 1,
3218 _('directory strip option for patch. This has the same '
3218 _('directory strip option for patch. This has the same '
3219 'meaning as the corresponding patch option'), _('NUM')),
3219 'meaning as the corresponding patch option'), _('NUM')),
3220 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3220 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3221 ('e', 'edit', False, _('invoke editor on commit messages')),
3221 ('e', 'edit', False, _('invoke editor on commit messages')),
3222 ('f', 'force', None,
3222 ('f', 'force', None,
3223 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3223 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3224 ('', 'no-commit', None,
3224 ('', 'no-commit', None,
3225 _("don't commit, just update the working directory")),
3225 _("don't commit, just update the working directory")),
3226 ('', 'bypass', None,
3226 ('', 'bypass', None,
3227 _("apply patch without touching the working directory")),
3227 _("apply patch without touching the working directory")),
3228 ('', 'partial', None,
3228 ('', 'partial', None,
3229 _('commit even if some hunks fail')),
3229 _('commit even if some hunks fail')),
3230 ('', 'exact', None,
3230 ('', 'exact', None,
3231 _('abort if patch would apply lossily')),
3231 _('abort if patch would apply lossily')),
3232 ('', 'prefix', '',
3232 ('', 'prefix', '',
3233 _('apply patch to subdirectory'), _('DIR')),
3233 _('apply patch to subdirectory'), _('DIR')),
3234 ('', 'import-branch', None,
3234 ('', 'import-branch', None,
3235 _('use any branch information in patch (implied by --exact)'))] +
3235 _('use any branch information in patch (implied by --exact)'))] +
3236 commitopts + commitopts2 + similarityopts,
3236 commitopts + commitopts2 + similarityopts,
3237 _('[OPTION]... PATCH...'))
3237 _('[OPTION]... PATCH...'))
3238 def import_(ui, repo, patch1=None, *patches, **opts):
3238 def import_(ui, repo, patch1=None, *patches, **opts):
3239 """import an ordered set of patches
3239 """import an ordered set of patches
3240
3240
3241 Import a list of patches and commit them individually (unless
3241 Import a list of patches and commit them individually (unless
3242 --no-commit is specified).
3242 --no-commit is specified).
3243
3243
3244 To read a patch from standard input (stdin), use "-" as the patch
3244 To read a patch from standard input (stdin), use "-" as the patch
3245 name. If a URL is specified, the patch will be downloaded from
3245 name. If a URL is specified, the patch will be downloaded from
3246 there.
3246 there.
3247
3247
3248 Import first applies changes to the working directory (unless
3248 Import first applies changes to the working directory (unless
3249 --bypass is specified), import will abort if there are outstanding
3249 --bypass is specified), import will abort if there are outstanding
3250 changes.
3250 changes.
3251
3251
3252 Use --bypass to apply and commit patches directly to the
3252 Use --bypass to apply and commit patches directly to the
3253 repository, without affecting the working directory. Without
3253 repository, without affecting the working directory. Without
3254 --exact, patches will be applied on top of the working directory
3254 --exact, patches will be applied on top of the working directory
3255 parent revision.
3255 parent revision.
3256
3256
3257 You can import a patch straight from a mail message. Even patches
3257 You can import a patch straight from a mail message. Even patches
3258 as attachments work (to use the body part, it must have type
3258 as attachments work (to use the body part, it must have type
3259 text/plain or text/x-patch). From and Subject headers of email
3259 text/plain or text/x-patch). From and Subject headers of email
3260 message are used as default committer and commit message. All
3260 message are used as default committer and commit message. All
3261 text/plain body parts before first diff are added to the commit
3261 text/plain body parts before first diff are added to the commit
3262 message.
3262 message.
3263
3263
3264 If the imported patch was generated by :hg:`export`, user and
3264 If the imported patch was generated by :hg:`export`, user and
3265 description from patch override values from message headers and
3265 description from patch override values from message headers and
3266 body. Values given on command line with -m/--message and -u/--user
3266 body. Values given on command line with -m/--message and -u/--user
3267 override these.
3267 override these.
3268
3268
3269 If --exact is specified, import will set the working directory to
3269 If --exact is specified, import will set the working directory to
3270 the parent of each patch before applying it, and will abort if the
3270 the parent of each patch before applying it, and will abort if the
3271 resulting changeset has a different ID than the one recorded in
3271 resulting changeset has a different ID than the one recorded in
3272 the patch. This will guard against various ways that portable
3272 the patch. This will guard against various ways that portable
3273 patch formats and mail systems might fail to transfer Mercurial
3273 patch formats and mail systems might fail to transfer Mercurial
3274 data or metadata. See :hg:`bundle` for lossless transmission.
3274 data or metadata. See :hg:`bundle` for lossless transmission.
3275
3275
3276 Use --partial to ensure a changeset will be created from the patch
3276 Use --partial to ensure a changeset will be created from the patch
3277 even if some hunks fail to apply. Hunks that fail to apply will be
3277 even if some hunks fail to apply. Hunks that fail to apply will be
3278 written to a <target-file>.rej file. Conflicts can then be resolved
3278 written to a <target-file>.rej file. Conflicts can then be resolved
3279 by hand before :hg:`commit --amend` is run to update the created
3279 by hand before :hg:`commit --amend` is run to update the created
3280 changeset. This flag exists to let people import patches that
3280 changeset. This flag exists to let people import patches that
3281 partially apply without losing the associated metadata (author,
3281 partially apply without losing the associated metadata (author,
3282 date, description, ...).
3282 date, description, ...).
3283
3283
3284 .. note::
3284 .. note::
3285
3285
3286 When no hunks apply cleanly, :hg:`import --partial` will create
3286 When no hunks apply cleanly, :hg:`import --partial` will create
3287 an empty changeset, importing only the patch metadata.
3287 an empty changeset, importing only the patch metadata.
3288
3288
3289 With -s/--similarity, hg will attempt to discover renames and
3289 With -s/--similarity, hg will attempt to discover renames and
3290 copies in the patch in the same way as :hg:`addremove`.
3290 copies in the patch in the same way as :hg:`addremove`.
3291
3291
3292 It is possible to use external patch programs to perform the patch
3292 It is possible to use external patch programs to perform the patch
3293 by setting the ``ui.patch`` configuration option. For the default
3293 by setting the ``ui.patch`` configuration option. For the default
3294 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3294 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3295 See :hg:`help config` for more information about configuration
3295 See :hg:`help config` for more information about configuration
3296 files and how to use these options.
3296 files and how to use these options.
3297
3297
3298 See :hg:`help dates` for a list of formats valid for -d/--date.
3298 See :hg:`help dates` for a list of formats valid for -d/--date.
3299
3299
3300 .. container:: verbose
3300 .. container:: verbose
3301
3301
3302 Examples:
3302 Examples:
3303
3303
3304 - import a traditional patch from a website and detect renames::
3304 - import a traditional patch from a website and detect renames::
3305
3305
3306 hg import -s 80 http://example.com/bugfix.patch
3306 hg import -s 80 http://example.com/bugfix.patch
3307
3307
3308 - import a changeset from an hgweb server::
3308 - import a changeset from an hgweb server::
3309
3309
3310 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3310 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3311
3311
3312 - import all the patches in an Unix-style mbox::
3312 - import all the patches in an Unix-style mbox::
3313
3313
3314 hg import incoming-patches.mbox
3314 hg import incoming-patches.mbox
3315
3315
3316 - import patches from stdin::
3316 - import patches from stdin::
3317
3317
3318 hg import -
3318 hg import -
3319
3319
3320 - attempt to exactly restore an exported changeset (not always
3320 - attempt to exactly restore an exported changeset (not always
3321 possible)::
3321 possible)::
3322
3322
3323 hg import --exact proposed-fix.patch
3323 hg import --exact proposed-fix.patch
3324
3324
3325 - use an external tool to apply a patch which is too fuzzy for
3325 - use an external tool to apply a patch which is too fuzzy for
3326 the default internal tool.
3326 the default internal tool.
3327
3327
3328 hg import --config ui.patch="patch --merge" fuzzy.patch
3328 hg import --config ui.patch="patch --merge" fuzzy.patch
3329
3329
3330 - change the default fuzzing from 2 to a less strict 7
3330 - change the default fuzzing from 2 to a less strict 7
3331
3331
3332 hg import --config ui.fuzz=7 fuzz.patch
3332 hg import --config ui.fuzz=7 fuzz.patch
3333
3333
3334 Returns 0 on success, 1 on partial success (see --partial).
3334 Returns 0 on success, 1 on partial success (see --partial).
3335 """
3335 """
3336
3336
3337 opts = pycompat.byteskwargs(opts)
3337 opts = pycompat.byteskwargs(opts)
3338 if not patch1:
3338 if not patch1:
3339 raise error.Abort(_('need at least one patch to import'))
3339 raise error.Abort(_('need at least one patch to import'))
3340
3340
3341 patches = (patch1,) + patches
3341 patches = (patch1,) + patches
3342
3342
3343 date = opts.get('date')
3343 date = opts.get('date')
3344 if date:
3344 if date:
3345 opts['date'] = dateutil.parsedate(date)
3345 opts['date'] = dateutil.parsedate(date)
3346
3346
3347 exact = opts.get('exact')
3347 exact = opts.get('exact')
3348 update = not opts.get('bypass')
3348 update = not opts.get('bypass')
3349 if not update and opts.get('no_commit'):
3349 if not update and opts.get('no_commit'):
3350 raise error.Abort(_('cannot use --no-commit with --bypass'))
3350 raise error.Abort(_('cannot use --no-commit with --bypass'))
3351 try:
3351 try:
3352 sim = float(opts.get('similarity') or 0)
3352 sim = float(opts.get('similarity') or 0)
3353 except ValueError:
3353 except ValueError:
3354 raise error.Abort(_('similarity must be a number'))
3354 raise error.Abort(_('similarity must be a number'))
3355 if sim < 0 or sim > 100:
3355 if sim < 0 or sim > 100:
3356 raise error.Abort(_('similarity must be between 0 and 100'))
3356 raise error.Abort(_('similarity must be between 0 and 100'))
3357 if sim and not update:
3357 if sim and not update:
3358 raise error.Abort(_('cannot use --similarity with --bypass'))
3358 raise error.Abort(_('cannot use --similarity with --bypass'))
3359 if exact:
3359 if exact:
3360 if opts.get('edit'):
3360 if opts.get('edit'):
3361 raise error.Abort(_('cannot use --exact with --edit'))
3361 raise error.Abort(_('cannot use --exact with --edit'))
3362 if opts.get('prefix'):
3362 if opts.get('prefix'):
3363 raise error.Abort(_('cannot use --exact with --prefix'))
3363 raise error.Abort(_('cannot use --exact with --prefix'))
3364
3364
3365 base = opts["base"]
3365 base = opts["base"]
3366 msgs = []
3366 msgs = []
3367 ret = 0
3367 ret = 0
3368
3368
3369 with repo.wlock():
3369 with repo.wlock():
3370 if update:
3370 if update:
3371 cmdutil.checkunfinished(repo)
3371 cmdutil.checkunfinished(repo)
3372 if (exact or not opts.get('force')):
3372 if (exact or not opts.get('force')):
3373 cmdutil.bailifchanged(repo)
3373 cmdutil.bailifchanged(repo)
3374
3374
3375 if not opts.get('no_commit'):
3375 if not opts.get('no_commit'):
3376 lock = repo.lock
3376 lock = repo.lock
3377 tr = lambda: repo.transaction('import')
3377 tr = lambda: repo.transaction('import')
3378 dsguard = util.nullcontextmanager
3378 dsguard = util.nullcontextmanager
3379 else:
3379 else:
3380 lock = util.nullcontextmanager
3380 lock = util.nullcontextmanager
3381 tr = util.nullcontextmanager
3381 tr = util.nullcontextmanager
3382 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3382 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3383 with lock(), tr(), dsguard():
3383 with lock(), tr(), dsguard():
3384 parents = repo[None].parents()
3384 parents = repo[None].parents()
3385 for patchurl in patches:
3385 for patchurl in patches:
3386 if patchurl == '-':
3386 if patchurl == '-':
3387 ui.status(_('applying patch from stdin\n'))
3387 ui.status(_('applying patch from stdin\n'))
3388 patchfile = ui.fin
3388 patchfile = ui.fin
3389 patchurl = 'stdin' # for error message
3389 patchurl = 'stdin' # for error message
3390 else:
3390 else:
3391 patchurl = os.path.join(base, patchurl)
3391 patchurl = os.path.join(base, patchurl)
3392 ui.status(_('applying %s\n') % patchurl)
3392 ui.status(_('applying %s\n') % patchurl)
3393 patchfile = hg.openpath(ui, patchurl)
3393 patchfile = hg.openpath(ui, patchurl)
3394
3394
3395 haspatch = False
3395 haspatch = False
3396 for hunk in patch.split(patchfile):
3396 for hunk in patch.split(patchfile):
3397 with patch.extract(ui, hunk) as patchdata:
3397 with patch.extract(ui, hunk) as patchdata:
3398 msg, node, rej = cmdutil.tryimportone(ui, repo,
3398 msg, node, rej = cmdutil.tryimportone(ui, repo,
3399 patchdata,
3399 patchdata,
3400 parents, opts,
3400 parents, opts,
3401 msgs, hg.clean)
3401 msgs, hg.clean)
3402 if msg:
3402 if msg:
3403 haspatch = True
3403 haspatch = True
3404 ui.note(msg + '\n')
3404 ui.note(msg + '\n')
3405 if update or exact:
3405 if update or exact:
3406 parents = repo[None].parents()
3406 parents = repo[None].parents()
3407 else:
3407 else:
3408 parents = [repo[node]]
3408 parents = [repo[node]]
3409 if rej:
3409 if rej:
3410 ui.write_err(_("patch applied partially\n"))
3410 ui.write_err(_("patch applied partially\n"))
3411 ui.write_err(_("(fix the .rej files and run "
3411 ui.write_err(_("(fix the .rej files and run "
3412 "`hg commit --amend`)\n"))
3412 "`hg commit --amend`)\n"))
3413 ret = 1
3413 ret = 1
3414 break
3414 break
3415
3415
3416 if not haspatch:
3416 if not haspatch:
3417 raise error.Abort(_('%s: no diffs found') % patchurl)
3417 raise error.Abort(_('%s: no diffs found') % patchurl)
3418
3418
3419 if msgs:
3419 if msgs:
3420 repo.savecommitmessage('\n* * *\n'.join(msgs))
3420 repo.savecommitmessage('\n* * *\n'.join(msgs))
3421 return ret
3421 return ret
3422
3422
3423 @command('incoming|in',
3423 @command('incoming|in',
3424 [('f', 'force', None,
3424 [('f', 'force', None,
3425 _('run even if remote repository is unrelated')),
3425 _('run even if remote repository is unrelated')),
3426 ('n', 'newest-first', None, _('show newest record first')),
3426 ('n', 'newest-first', None, _('show newest record first')),
3427 ('', 'bundle', '',
3427 ('', 'bundle', '',
3428 _('file to store the bundles into'), _('FILE')),
3428 _('file to store the bundles into'), _('FILE')),
3429 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3429 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3430 ('B', 'bookmarks', False, _("compare bookmarks")),
3430 ('B', 'bookmarks', False, _("compare bookmarks")),
3431 ('b', 'branch', [],
3431 ('b', 'branch', [],
3432 _('a specific branch you would like to pull'), _('BRANCH')),
3432 _('a specific branch you would like to pull'), _('BRANCH')),
3433 ] + logopts + remoteopts + subrepoopts,
3433 ] + logopts + remoteopts + subrepoopts,
3434 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3434 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3435 def incoming(ui, repo, source="default", **opts):
3435 def incoming(ui, repo, source="default", **opts):
3436 """show new changesets found in source
3436 """show new changesets found in source
3437
3437
3438 Show new changesets found in the specified path/URL or the default
3438 Show new changesets found in the specified path/URL or the default
3439 pull location. These are the changesets that would have been pulled
3439 pull location. These are the changesets that would have been pulled
3440 by :hg:`pull` at the time you issued this command.
3440 by :hg:`pull` at the time you issued this command.
3441
3441
3442 See pull for valid source format details.
3442 See pull for valid source format details.
3443
3443
3444 .. container:: verbose
3444 .. container:: verbose
3445
3445
3446 With -B/--bookmarks, the result of bookmark comparison between
3446 With -B/--bookmarks, the result of bookmark comparison between
3447 local and remote repositories is displayed. With -v/--verbose,
3447 local and remote repositories is displayed. With -v/--verbose,
3448 status is also displayed for each bookmark like below::
3448 status is also displayed for each bookmark like below::
3449
3449
3450 BM1 01234567890a added
3450 BM1 01234567890a added
3451 BM2 1234567890ab advanced
3451 BM2 1234567890ab advanced
3452 BM3 234567890abc diverged
3452 BM3 234567890abc diverged
3453 BM4 34567890abcd changed
3453 BM4 34567890abcd changed
3454
3454
3455 The action taken locally when pulling depends on the
3455 The action taken locally when pulling depends on the
3456 status of each bookmark:
3456 status of each bookmark:
3457
3457
3458 :``added``: pull will create it
3458 :``added``: pull will create it
3459 :``advanced``: pull will update it
3459 :``advanced``: pull will update it
3460 :``diverged``: pull will create a divergent bookmark
3460 :``diverged``: pull will create a divergent bookmark
3461 :``changed``: result depends on remote changesets
3461 :``changed``: result depends on remote changesets
3462
3462
3463 From the point of view of pulling behavior, bookmark
3463 From the point of view of pulling behavior, bookmark
3464 existing only in the remote repository are treated as ``added``,
3464 existing only in the remote repository are treated as ``added``,
3465 even if it is in fact locally deleted.
3465 even if it is in fact locally deleted.
3466
3466
3467 .. container:: verbose
3467 .. container:: verbose
3468
3468
3469 For remote repository, using --bundle avoids downloading the
3469 For remote repository, using --bundle avoids downloading the
3470 changesets twice if the incoming is followed by a pull.
3470 changesets twice if the incoming is followed by a pull.
3471
3471
3472 Examples:
3472 Examples:
3473
3473
3474 - show incoming changes with patches and full description::
3474 - show incoming changes with patches and full description::
3475
3475
3476 hg incoming -vp
3476 hg incoming -vp
3477
3477
3478 - show incoming changes excluding merges, store a bundle::
3478 - show incoming changes excluding merges, store a bundle::
3479
3479
3480 hg in -vpM --bundle incoming.hg
3480 hg in -vpM --bundle incoming.hg
3481 hg pull incoming.hg
3481 hg pull incoming.hg
3482
3482
3483 - briefly list changes inside a bundle::
3483 - briefly list changes inside a bundle::
3484
3484
3485 hg in changes.hg -T "{desc|firstline}\\n"
3485 hg in changes.hg -T "{desc|firstline}\\n"
3486
3486
3487 Returns 0 if there are incoming changes, 1 otherwise.
3487 Returns 0 if there are incoming changes, 1 otherwise.
3488 """
3488 """
3489 opts = pycompat.byteskwargs(opts)
3489 opts = pycompat.byteskwargs(opts)
3490 if opts.get('graph'):
3490 if opts.get('graph'):
3491 logcmdutil.checkunsupportedgraphflags([], opts)
3491 logcmdutil.checkunsupportedgraphflags([], opts)
3492 def display(other, chlist, displayer):
3492 def display(other, chlist, displayer):
3493 revdag = logcmdutil.graphrevs(other, chlist, opts)
3493 revdag = logcmdutil.graphrevs(other, chlist, opts)
3494 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3494 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3495 graphmod.asciiedges)
3495 graphmod.asciiedges)
3496
3496
3497 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3497 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3498 return 0
3498 return 0
3499
3499
3500 if opts.get('bundle') and opts.get('subrepos'):
3500 if opts.get('bundle') and opts.get('subrepos'):
3501 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3501 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3502
3502
3503 if opts.get('bookmarks'):
3503 if opts.get('bookmarks'):
3504 source, branches = hg.parseurl(ui.expandpath(source),
3504 source, branches = hg.parseurl(ui.expandpath(source),
3505 opts.get('branch'))
3505 opts.get('branch'))
3506 other = hg.peer(repo, opts, source)
3506 other = hg.peer(repo, opts, source)
3507 if 'bookmarks' not in other.listkeys('namespaces'):
3507 if 'bookmarks' not in other.listkeys('namespaces'):
3508 ui.warn(_("remote doesn't support bookmarks\n"))
3508 ui.warn(_("remote doesn't support bookmarks\n"))
3509 return 0
3509 return 0
3510 ui.pager('incoming')
3510 ui.pager('incoming')
3511 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3511 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3512 return bookmarks.incoming(ui, repo, other)
3512 return bookmarks.incoming(ui, repo, other)
3513
3513
3514 repo._subtoppath = ui.expandpath(source)
3514 repo._subtoppath = ui.expandpath(source)
3515 try:
3515 try:
3516 return hg.incoming(ui, repo, source, opts)
3516 return hg.incoming(ui, repo, source, opts)
3517 finally:
3517 finally:
3518 del repo._subtoppath
3518 del repo._subtoppath
3519
3519
3520
3520
3521 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3521 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3522 norepo=True)
3522 norepo=True)
3523 def init(ui, dest=".", **opts):
3523 def init(ui, dest=".", **opts):
3524 """create a new repository in the given directory
3524 """create a new repository in the given directory
3525
3525
3526 Initialize a new repository in the given directory. If the given
3526 Initialize a new repository in the given directory. If the given
3527 directory does not exist, it will be created.
3527 directory does not exist, it will be created.
3528
3528
3529 If no directory is given, the current directory is used.
3529 If no directory is given, the current directory is used.
3530
3530
3531 It is possible to specify an ``ssh://`` URL as the destination.
3531 It is possible to specify an ``ssh://`` URL as the destination.
3532 See :hg:`help urls` for more information.
3532 See :hg:`help urls` for more information.
3533
3533
3534 Returns 0 on success.
3534 Returns 0 on success.
3535 """
3535 """
3536 opts = pycompat.byteskwargs(opts)
3536 opts = pycompat.byteskwargs(opts)
3537 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3537 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3538
3538
3539 @command('locate',
3539 @command('locate',
3540 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3540 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3541 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3541 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3542 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3542 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3543 ] + walkopts,
3543 ] + walkopts,
3544 _('[OPTION]... [PATTERN]...'))
3544 _('[OPTION]... [PATTERN]...'))
3545 def locate(ui, repo, *pats, **opts):
3545 def locate(ui, repo, *pats, **opts):
3546 """locate files matching specific patterns (DEPRECATED)
3546 """locate files matching specific patterns (DEPRECATED)
3547
3547
3548 Print files under Mercurial control in the working directory whose
3548 Print files under Mercurial control in the working directory whose
3549 names match the given patterns.
3549 names match the given patterns.
3550
3550
3551 By default, this command searches all directories in the working
3551 By default, this command searches all directories in the working
3552 directory. To search just the current directory and its
3552 directory. To search just the current directory and its
3553 subdirectories, use "--include .".
3553 subdirectories, use "--include .".
3554
3554
3555 If no patterns are given to match, this command prints the names
3555 If no patterns are given to match, this command prints the names
3556 of all files under Mercurial control in the working directory.
3556 of all files under Mercurial control in the working directory.
3557
3557
3558 If you want to feed the output of this command into the "xargs"
3558 If you want to feed the output of this command into the "xargs"
3559 command, use the -0 option to both this command and "xargs". This
3559 command, use the -0 option to both this command and "xargs". This
3560 will avoid the problem of "xargs" treating single filenames that
3560 will avoid the problem of "xargs" treating single filenames that
3561 contain whitespace as multiple filenames.
3561 contain whitespace as multiple filenames.
3562
3562
3563 See :hg:`help files` for a more versatile command.
3563 See :hg:`help files` for a more versatile command.
3564
3564
3565 Returns 0 if a match is found, 1 otherwise.
3565 Returns 0 if a match is found, 1 otherwise.
3566 """
3566 """
3567 opts = pycompat.byteskwargs(opts)
3567 opts = pycompat.byteskwargs(opts)
3568 if opts.get('print0'):
3568 if opts.get('print0'):
3569 end = '\0'
3569 end = '\0'
3570 else:
3570 else:
3571 end = '\n'
3571 end = '\n'
3572 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3572 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3573
3573
3574 ret = 1
3574 ret = 1
3575 m = scmutil.match(ctx, pats, opts, default='relglob',
3575 m = scmutil.match(ctx, pats, opts, default='relglob',
3576 badfn=lambda x, y: False)
3576 badfn=lambda x, y: False)
3577
3577
3578 ui.pager('locate')
3578 ui.pager('locate')
3579 if ctx.rev() is None:
3579 if ctx.rev() is None:
3580 # When run on the working copy, "locate" includes removed files, so
3580 # When run on the working copy, "locate" includes removed files, so
3581 # we get the list of files from the dirstate.
3581 # we get the list of files from the dirstate.
3582 filesgen = sorted(repo.dirstate.matches(m))
3582 filesgen = sorted(repo.dirstate.matches(m))
3583 else:
3583 else:
3584 filesgen = ctx.matches(m)
3584 filesgen = ctx.matches(m)
3585 for abs in filesgen:
3585 for abs in filesgen:
3586 if opts.get('fullpath'):
3586 if opts.get('fullpath'):
3587 ui.write(repo.wjoin(abs), end)
3587 ui.write(repo.wjoin(abs), end)
3588 else:
3588 else:
3589 ui.write(((pats and m.rel(abs)) or abs), end)
3589 ui.write(((pats and m.rel(abs)) or abs), end)
3590 ret = 0
3590 ret = 0
3591
3591
3592 return ret
3592 return ret
3593
3593
3594 @command('^log|history',
3594 @command('^log|history',
3595 [('f', 'follow', None,
3595 [('f', 'follow', None,
3596 _('follow changeset history, or file history across copies and renames')),
3596 _('follow changeset history, or file history across copies and renames')),
3597 ('', 'follow-first', None,
3597 ('', 'follow-first', None,
3598 _('only follow the first parent of merge changesets (DEPRECATED)')),
3598 _('only follow the first parent of merge changesets (DEPRECATED)')),
3599 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3599 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3600 ('C', 'copies', None, _('show copied files')),
3600 ('C', 'copies', None, _('show copied files')),
3601 ('k', 'keyword', [],
3601 ('k', 'keyword', [],
3602 _('do case-insensitive search for a given text'), _('TEXT')),
3602 _('do case-insensitive search for a given text'), _('TEXT')),
3603 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3603 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3604 ('L', 'line-range', [],
3604 ('L', 'line-range', [],
3605 _('follow line range of specified file (EXPERIMENTAL)'),
3605 _('follow line range of specified file (EXPERIMENTAL)'),
3606 _('FILE,RANGE')),
3606 _('FILE,RANGE')),
3607 ('', 'removed', None, _('include revisions where files were removed')),
3607 ('', 'removed', None, _('include revisions where files were removed')),
3608 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3608 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3609 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3609 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3610 ('', 'only-branch', [],
3610 ('', 'only-branch', [],
3611 _('show only changesets within the given named branch (DEPRECATED)'),
3611 _('show only changesets within the given named branch (DEPRECATED)'),
3612 _('BRANCH')),
3612 _('BRANCH')),
3613 ('b', 'branch', [],
3613 ('b', 'branch', [],
3614 _('show changesets within the given named branch'), _('BRANCH')),
3614 _('show changesets within the given named branch'), _('BRANCH')),
3615 ('P', 'prune', [],
3615 ('P', 'prune', [],
3616 _('do not display revision or any of its ancestors'), _('REV')),
3616 _('do not display revision or any of its ancestors'), _('REV')),
3617 ] + logopts + walkopts,
3617 ] + logopts + walkopts,
3618 _('[OPTION]... [FILE]'),
3618 _('[OPTION]... [FILE]'),
3619 inferrepo=True,
3619 inferrepo=True,
3620 intents={INTENT_READONLY})
3620 intents={INTENT_READONLY})
3621 def log(ui, repo, *pats, **opts):
3621 def log(ui, repo, *pats, **opts):
3622 """show revision history of entire repository or files
3622 """show revision history of entire repository or files
3623
3623
3624 Print the revision history of the specified files or the entire
3624 Print the revision history of the specified files or the entire
3625 project.
3625 project.
3626
3626
3627 If no revision range is specified, the default is ``tip:0`` unless
3627 If no revision range is specified, the default is ``tip:0`` unless
3628 --follow is set, in which case the working directory parent is
3628 --follow is set, in which case the working directory parent is
3629 used as the starting revision.
3629 used as the starting revision.
3630
3630
3631 File history is shown without following rename or copy history of
3631 File history is shown without following rename or copy history of
3632 files. Use -f/--follow with a filename to follow history across
3632 files. Use -f/--follow with a filename to follow history across
3633 renames and copies. --follow without a filename will only show
3633 renames and copies. --follow without a filename will only show
3634 ancestors of the starting revision.
3634 ancestors of the starting revision.
3635
3635
3636 By default this command prints revision number and changeset id,
3636 By default this command prints revision number and changeset id,
3637 tags, non-trivial parents, user, date and time, and a summary for
3637 tags, non-trivial parents, user, date and time, and a summary for
3638 each commit. When the -v/--verbose switch is used, the list of
3638 each commit. When the -v/--verbose switch is used, the list of
3639 changed files and full commit message are shown.
3639 changed files and full commit message are shown.
3640
3640
3641 With --graph the revisions are shown as an ASCII art DAG with the most
3641 With --graph the revisions are shown as an ASCII art DAG with the most
3642 recent changeset at the top.
3642 recent changeset at the top.
3643 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3643 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3644 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3644 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3645 changeset from the lines below is a parent of the 'o' merge on the same
3645 changeset from the lines below is a parent of the 'o' merge on the same
3646 line.
3646 line.
3647 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3647 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3648 of a '|' indicates one or more revisions in a path are omitted.
3648 of a '|' indicates one or more revisions in a path are omitted.
3649
3649
3650 .. container:: verbose
3650 .. container:: verbose
3651
3651
3652 Use -L/--line-range FILE,M:N options to follow the history of lines
3652 Use -L/--line-range FILE,M:N options to follow the history of lines
3653 from M to N in FILE. With -p/--patch only diff hunks affecting
3653 from M to N in FILE. With -p/--patch only diff hunks affecting
3654 specified line range will be shown. This option requires --follow;
3654 specified line range will be shown. This option requires --follow;
3655 it can be specified multiple times. Currently, this option is not
3655 it can be specified multiple times. Currently, this option is not
3656 compatible with --graph. This option is experimental.
3656 compatible with --graph. This option is experimental.
3657
3657
3658 .. note::
3658 .. note::
3659
3659
3660 :hg:`log --patch` may generate unexpected diff output for merge
3660 :hg:`log --patch` may generate unexpected diff output for merge
3661 changesets, as it will only compare the merge changeset against
3661 changesets, as it will only compare the merge changeset against
3662 its first parent. Also, only files different from BOTH parents
3662 its first parent. Also, only files different from BOTH parents
3663 will appear in files:.
3663 will appear in files:.
3664
3664
3665 .. note::
3665 .. note::
3666
3666
3667 For performance reasons, :hg:`log FILE` may omit duplicate changes
3667 For performance reasons, :hg:`log FILE` may omit duplicate changes
3668 made on branches and will not show removals or mode changes. To
3668 made on branches and will not show removals or mode changes. To
3669 see all such changes, use the --removed switch.
3669 see all such changes, use the --removed switch.
3670
3670
3671 .. container:: verbose
3671 .. container:: verbose
3672
3672
3673 .. note::
3673 .. note::
3674
3674
3675 The history resulting from -L/--line-range options depends on diff
3675 The history resulting from -L/--line-range options depends on diff
3676 options; for instance if white-spaces are ignored, respective changes
3676 options; for instance if white-spaces are ignored, respective changes
3677 with only white-spaces in specified line range will not be listed.
3677 with only white-spaces in specified line range will not be listed.
3678
3678
3679 .. container:: verbose
3679 .. container:: verbose
3680
3680
3681 Some examples:
3681 Some examples:
3682
3682
3683 - changesets with full descriptions and file lists::
3683 - changesets with full descriptions and file lists::
3684
3684
3685 hg log -v
3685 hg log -v
3686
3686
3687 - changesets ancestral to the working directory::
3687 - changesets ancestral to the working directory::
3688
3688
3689 hg log -f
3689 hg log -f
3690
3690
3691 - last 10 commits on the current branch::
3691 - last 10 commits on the current branch::
3692
3692
3693 hg log -l 10 -b .
3693 hg log -l 10 -b .
3694
3694
3695 - changesets showing all modifications of a file, including removals::
3695 - changesets showing all modifications of a file, including removals::
3696
3696
3697 hg log --removed file.c
3697 hg log --removed file.c
3698
3698
3699 - all changesets that touch a directory, with diffs, excluding merges::
3699 - all changesets that touch a directory, with diffs, excluding merges::
3700
3700
3701 hg log -Mp lib/
3701 hg log -Mp lib/
3702
3702
3703 - all revision numbers that match a keyword::
3703 - all revision numbers that match a keyword::
3704
3704
3705 hg log -k bug --template "{rev}\\n"
3705 hg log -k bug --template "{rev}\\n"
3706
3706
3707 - the full hash identifier of the working directory parent::
3707 - the full hash identifier of the working directory parent::
3708
3708
3709 hg log -r . --template "{node}\\n"
3709 hg log -r . --template "{node}\\n"
3710
3710
3711 - list available log templates::
3711 - list available log templates::
3712
3712
3713 hg log -T list
3713 hg log -T list
3714
3714
3715 - check if a given changeset is included in a tagged release::
3715 - check if a given changeset is included in a tagged release::
3716
3716
3717 hg log -r "a21ccf and ancestor(1.9)"
3717 hg log -r "a21ccf and ancestor(1.9)"
3718
3718
3719 - find all changesets by some user in a date range::
3719 - find all changesets by some user in a date range::
3720
3720
3721 hg log -k alice -d "may 2008 to jul 2008"
3721 hg log -k alice -d "may 2008 to jul 2008"
3722
3722
3723 - summary of all changesets after the last tag::
3723 - summary of all changesets after the last tag::
3724
3724
3725 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3725 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3726
3726
3727 - changesets touching lines 13 to 23 for file.c::
3727 - changesets touching lines 13 to 23 for file.c::
3728
3728
3729 hg log -L file.c,13:23
3729 hg log -L file.c,13:23
3730
3730
3731 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3731 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3732 main.c with patch::
3732 main.c with patch::
3733
3733
3734 hg log -L file.c,13:23 -L main.c,2:6 -p
3734 hg log -L file.c,13:23 -L main.c,2:6 -p
3735
3735
3736 See :hg:`help dates` for a list of formats valid for -d/--date.
3736 See :hg:`help dates` for a list of formats valid for -d/--date.
3737
3737
3738 See :hg:`help revisions` for more about specifying and ordering
3738 See :hg:`help revisions` for more about specifying and ordering
3739 revisions.
3739 revisions.
3740
3740
3741 See :hg:`help templates` for more about pre-packaged styles and
3741 See :hg:`help templates` for more about pre-packaged styles and
3742 specifying custom templates. The default template used by the log
3742 specifying custom templates. The default template used by the log
3743 command can be customized via the ``ui.logtemplate`` configuration
3743 command can be customized via the ``ui.logtemplate`` configuration
3744 setting.
3744 setting.
3745
3745
3746 Returns 0 on success.
3746 Returns 0 on success.
3747
3747
3748 """
3748 """
3749 opts = pycompat.byteskwargs(opts)
3749 opts = pycompat.byteskwargs(opts)
3750 linerange = opts.get('line_range')
3750 linerange = opts.get('line_range')
3751
3751
3752 if linerange and not opts.get('follow'):
3752 if linerange and not opts.get('follow'):
3753 raise error.Abort(_('--line-range requires --follow'))
3753 raise error.Abort(_('--line-range requires --follow'))
3754
3754
3755 if linerange and pats:
3755 if linerange and pats:
3756 # TODO: take pats as patterns with no line-range filter
3756 # TODO: take pats as patterns with no line-range filter
3757 raise error.Abort(
3757 raise error.Abort(
3758 _('FILE arguments are not compatible with --line-range option')
3758 _('FILE arguments are not compatible with --line-range option')
3759 )
3759 )
3760
3760
3761 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3761 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3762 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3762 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3763 if linerange:
3763 if linerange:
3764 # TODO: should follow file history from logcmdutil._initialrevs(),
3764 # TODO: should follow file history from logcmdutil._initialrevs(),
3765 # then filter the result by logcmdutil._makerevset() and --limit
3765 # then filter the result by logcmdutil._makerevset() and --limit
3766 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3766 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3767
3767
3768 getrenamed = None
3768 getrenamed = None
3769 if opts.get('copies'):
3769 if opts.get('copies'):
3770 endrev = None
3770 endrev = None
3771 if revs:
3771 if revs:
3772 endrev = revs.max() + 1
3772 endrev = revs.max() + 1
3773 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3773 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3774
3774
3775 ui.pager('log')
3775 ui.pager('log')
3776 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3776 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3777 buffered=True)
3777 buffered=True)
3778 if opts.get('graph'):
3778 if opts.get('graph'):
3779 displayfn = logcmdutil.displaygraphrevs
3779 displayfn = logcmdutil.displaygraphrevs
3780 else:
3780 else:
3781 displayfn = logcmdutil.displayrevs
3781 displayfn = logcmdutil.displayrevs
3782 displayfn(ui, repo, revs, displayer, getrenamed)
3782 displayfn(ui, repo, revs, displayer, getrenamed)
3783
3783
3784 @command('manifest',
3784 @command('manifest',
3785 [('r', 'rev', '', _('revision to display'), _('REV')),
3785 [('r', 'rev', '', _('revision to display'), _('REV')),
3786 ('', 'all', False, _("list files from all revisions"))]
3786 ('', 'all', False, _("list files from all revisions"))]
3787 + formatteropts,
3787 + formatteropts,
3788 _('[-r REV]'),
3788 _('[-r REV]'),
3789 intents={INTENT_READONLY})
3789 intents={INTENT_READONLY})
3790 def manifest(ui, repo, node=None, rev=None, **opts):
3790 def manifest(ui, repo, node=None, rev=None, **opts):
3791 """output the current or given revision of the project manifest
3791 """output the current or given revision of the project manifest
3792
3792
3793 Print a list of version controlled files for the given revision.
3793 Print a list of version controlled files for the given revision.
3794 If no revision is given, the first parent of the working directory
3794 If no revision is given, the first parent of the working directory
3795 is used, or the null revision if no revision is checked out.
3795 is used, or the null revision if no revision is checked out.
3796
3796
3797 With -v, print file permissions, symlink and executable bits.
3797 With -v, print file permissions, symlink and executable bits.
3798 With --debug, print file revision hashes.
3798 With --debug, print file revision hashes.
3799
3799
3800 If option --all is specified, the list of all files from all revisions
3800 If option --all is specified, the list of all files from all revisions
3801 is printed. This includes deleted and renamed files.
3801 is printed. This includes deleted and renamed files.
3802
3802
3803 Returns 0 on success.
3803 Returns 0 on success.
3804 """
3804 """
3805 opts = pycompat.byteskwargs(opts)
3805 opts = pycompat.byteskwargs(opts)
3806 fm = ui.formatter('manifest', opts)
3806 fm = ui.formatter('manifest', opts)
3807
3807
3808 if opts.get('all'):
3808 if opts.get('all'):
3809 if rev or node:
3809 if rev or node:
3810 raise error.Abort(_("can't specify a revision with --all"))
3810 raise error.Abort(_("can't specify a revision with --all"))
3811
3811
3812 res = set()
3812 res = set()
3813 for rev in repo:
3813 for rev in repo:
3814 ctx = repo[rev]
3814 ctx = repo[rev]
3815 res |= set(ctx.files())
3815 res |= set(ctx.files())
3816
3816
3817 ui.pager('manifest')
3817 ui.pager('manifest')
3818 for f in sorted(res):
3818 for f in sorted(res):
3819 fm.startitem()
3819 fm.startitem()
3820 fm.write("path", '%s\n', f)
3820 fm.write("path", '%s\n', f)
3821 fm.end()
3821 fm.end()
3822 return
3822 return
3823
3823
3824 if rev and node:
3824 if rev and node:
3825 raise error.Abort(_("please specify just one revision"))
3825 raise error.Abort(_("please specify just one revision"))
3826
3826
3827 if not node:
3827 if not node:
3828 node = rev
3828 node = rev
3829
3829
3830 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3830 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3831 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3831 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3832 if node:
3832 if node:
3833 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3833 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3834 ctx = scmutil.revsingle(repo, node)
3834 ctx = scmutil.revsingle(repo, node)
3835 mf = ctx.manifest()
3835 mf = ctx.manifest()
3836 ui.pager('manifest')
3836 ui.pager('manifest')
3837 for f in ctx:
3837 for f in ctx:
3838 fm.startitem()
3838 fm.startitem()
3839 fm.context(ctx=ctx)
3839 fm.context(ctx=ctx)
3840 fl = ctx[f].flags()
3840 fl = ctx[f].flags()
3841 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3841 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3842 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3842 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3843 fm.write('path', '%s\n', f)
3843 fm.write('path', '%s\n', f)
3844 fm.end()
3844 fm.end()
3845
3845
3846 @command('^merge',
3846 @command('^merge',
3847 [('f', 'force', None,
3847 [('f', 'force', None,
3848 _('force a merge including outstanding changes (DEPRECATED)')),
3848 _('force a merge including outstanding changes (DEPRECATED)')),
3849 ('r', 'rev', '', _('revision to merge'), _('REV')),
3849 ('r', 'rev', '', _('revision to merge'), _('REV')),
3850 ('P', 'preview', None,
3850 ('P', 'preview', None,
3851 _('review revisions to merge (no merge is performed)')),
3851 _('review revisions to merge (no merge is performed)')),
3852 ('', 'abort', None, _('abort the ongoing merge')),
3852 ('', 'abort', None, _('abort the ongoing merge')),
3853 ] + mergetoolopts,
3853 ] + mergetoolopts,
3854 _('[-P] [[-r] REV]'))
3854 _('[-P] [[-r] REV]'))
3855 def merge(ui, repo, node=None, **opts):
3855 def merge(ui, repo, node=None, **opts):
3856 """merge another revision into working directory
3856 """merge another revision into working directory
3857
3857
3858 The current working directory is updated with all changes made in
3858 The current working directory is updated with all changes made in
3859 the requested revision since the last common predecessor revision.
3859 the requested revision since the last common predecessor revision.
3860
3860
3861 Files that changed between either parent are marked as changed for
3861 Files that changed between either parent are marked as changed for
3862 the next commit and a commit must be performed before any further
3862 the next commit and a commit must be performed before any further
3863 updates to the repository are allowed. The next commit will have
3863 updates to the repository are allowed. The next commit will have
3864 two parents.
3864 two parents.
3865
3865
3866 ``--tool`` can be used to specify the merge tool used for file
3866 ``--tool`` can be used to specify the merge tool used for file
3867 merges. It overrides the HGMERGE environment variable and your
3867 merges. It overrides the HGMERGE environment variable and your
3868 configuration files. See :hg:`help merge-tools` for options.
3868 configuration files. See :hg:`help merge-tools` for options.
3869
3869
3870 If no revision is specified, the working directory's parent is a
3870 If no revision is specified, the working directory's parent is a
3871 head revision, and the current branch contains exactly one other
3871 head revision, and the current branch contains exactly one other
3872 head, the other head is merged with by default. Otherwise, an
3872 head, the other head is merged with by default. Otherwise, an
3873 explicit revision with which to merge with must be provided.
3873 explicit revision with which to merge with must be provided.
3874
3874
3875 See :hg:`help resolve` for information on handling file conflicts.
3875 See :hg:`help resolve` for information on handling file conflicts.
3876
3876
3877 To undo an uncommitted merge, use :hg:`merge --abort` which
3877 To undo an uncommitted merge, use :hg:`merge --abort` which
3878 will check out a clean copy of the original merge parent, losing
3878 will check out a clean copy of the original merge parent, losing
3879 all changes.
3879 all changes.
3880
3880
3881 Returns 0 on success, 1 if there are unresolved files.
3881 Returns 0 on success, 1 if there are unresolved files.
3882 """
3882 """
3883
3883
3884 opts = pycompat.byteskwargs(opts)
3884 opts = pycompat.byteskwargs(opts)
3885 abort = opts.get('abort')
3885 abort = opts.get('abort')
3886 if abort and repo.dirstate.p2() == nullid:
3886 if abort and repo.dirstate.p2() == nullid:
3887 cmdutil.wrongtooltocontinue(repo, _('merge'))
3887 cmdutil.wrongtooltocontinue(repo, _('merge'))
3888 if abort:
3888 if abort:
3889 if node:
3889 if node:
3890 raise error.Abort(_("cannot specify a node with --abort"))
3890 raise error.Abort(_("cannot specify a node with --abort"))
3891 if opts.get('rev'):
3891 if opts.get('rev'):
3892 raise error.Abort(_("cannot specify both --rev and --abort"))
3892 raise error.Abort(_("cannot specify both --rev and --abort"))
3893 if opts.get('preview'):
3893 if opts.get('preview'):
3894 raise error.Abort(_("cannot specify --preview with --abort"))
3894 raise error.Abort(_("cannot specify --preview with --abort"))
3895 if opts.get('rev') and node:
3895 if opts.get('rev') and node:
3896 raise error.Abort(_("please specify just one revision"))
3896 raise error.Abort(_("please specify just one revision"))
3897 if not node:
3897 if not node:
3898 node = opts.get('rev')
3898 node = opts.get('rev')
3899
3899
3900 if node:
3900 if node:
3901 node = scmutil.revsingle(repo, node).node()
3901 node = scmutil.revsingle(repo, node).node()
3902
3902
3903 if not node and not abort:
3903 if not node and not abort:
3904 node = repo[destutil.destmerge(repo)].node()
3904 node = repo[destutil.destmerge(repo)].node()
3905
3905
3906 if opts.get('preview'):
3906 if opts.get('preview'):
3907 # find nodes that are ancestors of p2 but not of p1
3907 # find nodes that are ancestors of p2 but not of p1
3908 p1 = repo.lookup('.')
3908 p1 = repo.lookup('.')
3909 p2 = node
3909 p2 = node
3910 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3910 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3911
3911
3912 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3912 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3913 for node in nodes:
3913 for node in nodes:
3914 displayer.show(repo[node])
3914 displayer.show(repo[node])
3915 displayer.close()
3915 displayer.close()
3916 return 0
3916 return 0
3917
3917
3918 # ui.forcemerge is an internal variable, do not document
3918 # ui.forcemerge is an internal variable, do not document
3919 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3919 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3920 with ui.configoverride(overrides, 'merge'):
3920 with ui.configoverride(overrides, 'merge'):
3921 force = opts.get('force')
3921 force = opts.get('force')
3922 labels = ['working copy', 'merge rev']
3922 labels = ['working copy', 'merge rev']
3923 return hg.merge(repo, node, force=force, mergeforce=force,
3923 return hg.merge(repo, node, force=force, mergeforce=force,
3924 labels=labels, abort=abort)
3924 labels=labels, abort=abort)
3925
3925
3926 @command('outgoing|out',
3926 @command('outgoing|out',
3927 [('f', 'force', None, _('run even when the destination is unrelated')),
3927 [('f', 'force', None, _('run even when the destination is unrelated')),
3928 ('r', 'rev', [],
3928 ('r', 'rev', [],
3929 _('a changeset intended to be included in the destination'), _('REV')),
3929 _('a changeset intended to be included in the destination'), _('REV')),
3930 ('n', 'newest-first', None, _('show newest record first')),
3930 ('n', 'newest-first', None, _('show newest record first')),
3931 ('B', 'bookmarks', False, _('compare bookmarks')),
3931 ('B', 'bookmarks', False, _('compare bookmarks')),
3932 ('b', 'branch', [], _('a specific branch you would like to push'),
3932 ('b', 'branch', [], _('a specific branch you would like to push'),
3933 _('BRANCH')),
3933 _('BRANCH')),
3934 ] + logopts + remoteopts + subrepoopts,
3934 ] + logopts + remoteopts + subrepoopts,
3935 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3935 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3936 def outgoing(ui, repo, dest=None, **opts):
3936 def outgoing(ui, repo, dest=None, **opts):
3937 """show changesets not found in the destination
3937 """show changesets not found in the destination
3938
3938
3939 Show changesets not found in the specified destination repository
3939 Show changesets not found in the specified destination repository
3940 or the default push location. These are the changesets that would
3940 or the default push location. These are the changesets that would
3941 be pushed if a push was requested.
3941 be pushed if a push was requested.
3942
3942
3943 See pull for details of valid destination formats.
3943 See pull for details of valid destination formats.
3944
3944
3945 .. container:: verbose
3945 .. container:: verbose
3946
3946
3947 With -B/--bookmarks, the result of bookmark comparison between
3947 With -B/--bookmarks, the result of bookmark comparison between
3948 local and remote repositories is displayed. With -v/--verbose,
3948 local and remote repositories is displayed. With -v/--verbose,
3949 status is also displayed for each bookmark like below::
3949 status is also displayed for each bookmark like below::
3950
3950
3951 BM1 01234567890a added
3951 BM1 01234567890a added
3952 BM2 deleted
3952 BM2 deleted
3953 BM3 234567890abc advanced
3953 BM3 234567890abc advanced
3954 BM4 34567890abcd diverged
3954 BM4 34567890abcd diverged
3955 BM5 4567890abcde changed
3955 BM5 4567890abcde changed
3956
3956
3957 The action taken when pushing depends on the
3957 The action taken when pushing depends on the
3958 status of each bookmark:
3958 status of each bookmark:
3959
3959
3960 :``added``: push with ``-B`` will create it
3960 :``added``: push with ``-B`` will create it
3961 :``deleted``: push with ``-B`` will delete it
3961 :``deleted``: push with ``-B`` will delete it
3962 :``advanced``: push will update it
3962 :``advanced``: push will update it
3963 :``diverged``: push with ``-B`` will update it
3963 :``diverged``: push with ``-B`` will update it
3964 :``changed``: push with ``-B`` will update it
3964 :``changed``: push with ``-B`` will update it
3965
3965
3966 From the point of view of pushing behavior, bookmarks
3966 From the point of view of pushing behavior, bookmarks
3967 existing only in the remote repository are treated as
3967 existing only in the remote repository are treated as
3968 ``deleted``, even if it is in fact added remotely.
3968 ``deleted``, even if it is in fact added remotely.
3969
3969
3970 Returns 0 if there are outgoing changes, 1 otherwise.
3970 Returns 0 if there are outgoing changes, 1 otherwise.
3971 """
3971 """
3972 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3972 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3973 # style URLs, so don't overwrite dest.
3973 # style URLs, so don't overwrite dest.
3974 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3974 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3975 if not path:
3975 if not path:
3976 raise error.Abort(_('default repository not configured!'),
3976 raise error.Abort(_('default repository not configured!'),
3977 hint=_("see 'hg help config.paths'"))
3977 hint=_("see 'hg help config.paths'"))
3978
3978
3979 opts = pycompat.byteskwargs(opts)
3979 opts = pycompat.byteskwargs(opts)
3980 if opts.get('graph'):
3980 if opts.get('graph'):
3981 logcmdutil.checkunsupportedgraphflags([], opts)
3981 logcmdutil.checkunsupportedgraphflags([], opts)
3982 o, other = hg._outgoing(ui, repo, dest, opts)
3982 o, other = hg._outgoing(ui, repo, dest, opts)
3983 if not o:
3983 if not o:
3984 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3984 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3985 return
3985 return
3986
3986
3987 revdag = logcmdutil.graphrevs(repo, o, opts)
3987 revdag = logcmdutil.graphrevs(repo, o, opts)
3988 ui.pager('outgoing')
3988 ui.pager('outgoing')
3989 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3989 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3990 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3990 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3991 graphmod.asciiedges)
3991 graphmod.asciiedges)
3992 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3992 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3993 return 0
3993 return 0
3994
3994
3995 if opts.get('bookmarks'):
3995 if opts.get('bookmarks'):
3996 dest = path.pushloc or path.loc
3996 dest = path.pushloc or path.loc
3997 other = hg.peer(repo, opts, dest)
3997 other = hg.peer(repo, opts, dest)
3998 if 'bookmarks' not in other.listkeys('namespaces'):
3998 if 'bookmarks' not in other.listkeys('namespaces'):
3999 ui.warn(_("remote doesn't support bookmarks\n"))
3999 ui.warn(_("remote doesn't support bookmarks\n"))
4000 return 0
4000 return 0
4001 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4001 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4002 ui.pager('outgoing')
4002 ui.pager('outgoing')
4003 return bookmarks.outgoing(ui, repo, other)
4003 return bookmarks.outgoing(ui, repo, other)
4004
4004
4005 repo._subtoppath = path.pushloc or path.loc
4005 repo._subtoppath = path.pushloc or path.loc
4006 try:
4006 try:
4007 return hg.outgoing(ui, repo, dest, opts)
4007 return hg.outgoing(ui, repo, dest, opts)
4008 finally:
4008 finally:
4009 del repo._subtoppath
4009 del repo._subtoppath
4010
4010
4011 @command('parents',
4011 @command('parents',
4012 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4012 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4013 ] + templateopts,
4013 ] + templateopts,
4014 _('[-r REV] [FILE]'),
4014 _('[-r REV] [FILE]'),
4015 inferrepo=True)
4015 inferrepo=True)
4016 def parents(ui, repo, file_=None, **opts):
4016 def parents(ui, repo, file_=None, **opts):
4017 """show the parents of the working directory or revision (DEPRECATED)
4017 """show the parents of the working directory or revision (DEPRECATED)
4018
4018
4019 Print the working directory's parent revisions. If a revision is
4019 Print the working directory's parent revisions. If a revision is
4020 given via -r/--rev, the parent of that revision will be printed.
4020 given via -r/--rev, the parent of that revision will be printed.
4021 If a file argument is given, the revision in which the file was
4021 If a file argument is given, the revision in which the file was
4022 last changed (before the working directory revision or the
4022 last changed (before the working directory revision or the
4023 argument to --rev if given) is printed.
4023 argument to --rev if given) is printed.
4024
4024
4025 This command is equivalent to::
4025 This command is equivalent to::
4026
4026
4027 hg log -r "p1()+p2()" or
4027 hg log -r "p1()+p2()" or
4028 hg log -r "p1(REV)+p2(REV)" or
4028 hg log -r "p1(REV)+p2(REV)" or
4029 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4029 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4030 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4030 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4031
4031
4032 See :hg:`summary` and :hg:`help revsets` for related information.
4032 See :hg:`summary` and :hg:`help revsets` for related information.
4033
4033
4034 Returns 0 on success.
4034 Returns 0 on success.
4035 """
4035 """
4036
4036
4037 opts = pycompat.byteskwargs(opts)
4037 opts = pycompat.byteskwargs(opts)
4038 rev = opts.get('rev')
4038 rev = opts.get('rev')
4039 if rev:
4039 if rev:
4040 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4040 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4041 ctx = scmutil.revsingle(repo, rev, None)
4041 ctx = scmutil.revsingle(repo, rev, None)
4042
4042
4043 if file_:
4043 if file_:
4044 m = scmutil.match(ctx, (file_,), opts)
4044 m = scmutil.match(ctx, (file_,), opts)
4045 if m.anypats() or len(m.files()) != 1:
4045 if m.anypats() or len(m.files()) != 1:
4046 raise error.Abort(_('can only specify an explicit filename'))
4046 raise error.Abort(_('can only specify an explicit filename'))
4047 file_ = m.files()[0]
4047 file_ = m.files()[0]
4048 filenodes = []
4048 filenodes = []
4049 for cp in ctx.parents():
4049 for cp in ctx.parents():
4050 if not cp:
4050 if not cp:
4051 continue
4051 continue
4052 try:
4052 try:
4053 filenodes.append(cp.filenode(file_))
4053 filenodes.append(cp.filenode(file_))
4054 except error.LookupError:
4054 except error.LookupError:
4055 pass
4055 pass
4056 if not filenodes:
4056 if not filenodes:
4057 raise error.Abort(_("'%s' not found in manifest!") % file_)
4057 raise error.Abort(_("'%s' not found in manifest!") % file_)
4058 p = []
4058 p = []
4059 for fn in filenodes:
4059 for fn in filenodes:
4060 fctx = repo.filectx(file_, fileid=fn)
4060 fctx = repo.filectx(file_, fileid=fn)
4061 p.append(fctx.node())
4061 p.append(fctx.node())
4062 else:
4062 else:
4063 p = [cp.node() for cp in ctx.parents()]
4063 p = [cp.node() for cp in ctx.parents()]
4064
4064
4065 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4065 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4066 for n in p:
4066 for n in p:
4067 if n != nullid:
4067 if n != nullid:
4068 displayer.show(repo[n])
4068 displayer.show(repo[n])
4069 displayer.close()
4069 displayer.close()
4070
4070
4071 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
4071 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
4072 intents={INTENT_READONLY})
4072 intents={INTENT_READONLY})
4073 def paths(ui, repo, search=None, **opts):
4073 def paths(ui, repo, search=None, **opts):
4074 """show aliases for remote repositories
4074 """show aliases for remote repositories
4075
4075
4076 Show definition of symbolic path name NAME. If no name is given,
4076 Show definition of symbolic path name NAME. If no name is given,
4077 show definition of all available names.
4077 show definition of all available names.
4078
4078
4079 Option -q/--quiet suppresses all output when searching for NAME
4079 Option -q/--quiet suppresses all output when searching for NAME
4080 and shows only the path names when listing all definitions.
4080 and shows only the path names when listing all definitions.
4081
4081
4082 Path names are defined in the [paths] section of your
4082 Path names are defined in the [paths] section of your
4083 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4083 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4084 repository, ``.hg/hgrc`` is used, too.
4084 repository, ``.hg/hgrc`` is used, too.
4085
4085
4086 The path names ``default`` and ``default-push`` have a special
4086 The path names ``default`` and ``default-push`` have a special
4087 meaning. When performing a push or pull operation, they are used
4087 meaning. When performing a push or pull operation, they are used
4088 as fallbacks if no location is specified on the command-line.
4088 as fallbacks if no location is specified on the command-line.
4089 When ``default-push`` is set, it will be used for push and
4089 When ``default-push`` is set, it will be used for push and
4090 ``default`` will be used for pull; otherwise ``default`` is used
4090 ``default`` will be used for pull; otherwise ``default`` is used
4091 as the fallback for both. When cloning a repository, the clone
4091 as the fallback for both. When cloning a repository, the clone
4092 source is written as ``default`` in ``.hg/hgrc``.
4092 source is written as ``default`` in ``.hg/hgrc``.
4093
4093
4094 .. note::
4094 .. note::
4095
4095
4096 ``default`` and ``default-push`` apply to all inbound (e.g.
4096 ``default`` and ``default-push`` apply to all inbound (e.g.
4097 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4097 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4098 and :hg:`bundle`) operations.
4098 and :hg:`bundle`) operations.
4099
4099
4100 See :hg:`help urls` for more information.
4100 See :hg:`help urls` for more information.
4101
4101
4102 .. container:: verbose
4102 .. container:: verbose
4103
4103
4104 Template:
4104 Template:
4105
4105
4106 The following keywords are supported. See also :hg:`help templates`.
4106 The following keywords are supported. See also :hg:`help templates`.
4107
4107
4108 :name: String. Symbolic name of the path alias.
4108 :name: String. Symbolic name of the path alias.
4109 :pushurl: String. URL for push operations.
4109 :pushurl: String. URL for push operations.
4110 :url: String. URL or directory path for the other operations.
4110 :url: String. URL or directory path for the other operations.
4111
4111
4112 Returns 0 on success.
4112 Returns 0 on success.
4113 """
4113 """
4114
4114
4115 opts = pycompat.byteskwargs(opts)
4115 opts = pycompat.byteskwargs(opts)
4116 ui.pager('paths')
4116 ui.pager('paths')
4117 if search:
4117 if search:
4118 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4118 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4119 if name == search]
4119 if name == search]
4120 else:
4120 else:
4121 pathitems = sorted(ui.paths.iteritems())
4121 pathitems = sorted(ui.paths.iteritems())
4122
4122
4123 fm = ui.formatter('paths', opts)
4123 fm = ui.formatter('paths', opts)
4124 if fm.isplain():
4124 if fm.isplain():
4125 hidepassword = util.hidepassword
4125 hidepassword = util.hidepassword
4126 else:
4126 else:
4127 hidepassword = bytes
4127 hidepassword = bytes
4128 if ui.quiet:
4128 if ui.quiet:
4129 namefmt = '%s\n'
4129 namefmt = '%s\n'
4130 else:
4130 else:
4131 namefmt = '%s = '
4131 namefmt = '%s = '
4132 showsubopts = not search and not ui.quiet
4132 showsubopts = not search and not ui.quiet
4133
4133
4134 for name, path in pathitems:
4134 for name, path in pathitems:
4135 fm.startitem()
4135 fm.startitem()
4136 fm.condwrite(not search, 'name', namefmt, name)
4136 fm.condwrite(not search, 'name', namefmt, name)
4137 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4137 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4138 for subopt, value in sorted(path.suboptions.items()):
4138 for subopt, value in sorted(path.suboptions.items()):
4139 assert subopt not in ('name', 'url')
4139 assert subopt not in ('name', 'url')
4140 if showsubopts:
4140 if showsubopts:
4141 fm.plain('%s:%s = ' % (name, subopt))
4141 fm.plain('%s:%s = ' % (name, subopt))
4142 fm.condwrite(showsubopts, subopt, '%s\n', value)
4142 fm.condwrite(showsubopts, subopt, '%s\n', value)
4143
4143
4144 fm.end()
4144 fm.end()
4145
4145
4146 if search and not pathitems:
4146 if search and not pathitems:
4147 if not ui.quiet:
4147 if not ui.quiet:
4148 ui.warn(_("not found!\n"))
4148 ui.warn(_("not found!\n"))
4149 return 1
4149 return 1
4150 else:
4150 else:
4151 return 0
4151 return 0
4152
4152
4153 @command('phase',
4153 @command('phase',
4154 [('p', 'public', False, _('set changeset phase to public')),
4154 [('p', 'public', False, _('set changeset phase to public')),
4155 ('d', 'draft', False, _('set changeset phase to draft')),
4155 ('d', 'draft', False, _('set changeset phase to draft')),
4156 ('s', 'secret', False, _('set changeset phase to secret')),
4156 ('s', 'secret', False, _('set changeset phase to secret')),
4157 ('f', 'force', False, _('allow to move boundary backward')),
4157 ('f', 'force', False, _('allow to move boundary backward')),
4158 ('r', 'rev', [], _('target revision'), _('REV')),
4158 ('r', 'rev', [], _('target revision'), _('REV')),
4159 ],
4159 ],
4160 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4160 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4161 def phase(ui, repo, *revs, **opts):
4161 def phase(ui, repo, *revs, **opts):
4162 """set or show the current phase name
4162 """set or show the current phase name
4163
4163
4164 With no argument, show the phase name of the current revision(s).
4164 With no argument, show the phase name of the current revision(s).
4165
4165
4166 With one of -p/--public, -d/--draft or -s/--secret, change the
4166 With one of -p/--public, -d/--draft or -s/--secret, change the
4167 phase value of the specified revisions.
4167 phase value of the specified revisions.
4168
4168
4169 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4169 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4170 lower phase to a higher phase. Phases are ordered as follows::
4170 lower phase to a higher phase. Phases are ordered as follows::
4171
4171
4172 public < draft < secret
4172 public < draft < secret
4173
4173
4174 Returns 0 on success, 1 if some phases could not be changed.
4174 Returns 0 on success, 1 if some phases could not be changed.
4175
4175
4176 (For more information about the phases concept, see :hg:`help phases`.)
4176 (For more information about the phases concept, see :hg:`help phases`.)
4177 """
4177 """
4178 opts = pycompat.byteskwargs(opts)
4178 opts = pycompat.byteskwargs(opts)
4179 # search for a unique phase argument
4179 # search for a unique phase argument
4180 targetphase = None
4180 targetphase = None
4181 for idx, name in enumerate(phases.phasenames):
4181 for idx, name in enumerate(phases.phasenames):
4182 if opts.get(name, False):
4182 if opts.get(name, False):
4183 if targetphase is not None:
4183 if targetphase is not None:
4184 raise error.Abort(_('only one phase can be specified'))
4184 raise error.Abort(_('only one phase can be specified'))
4185 targetphase = idx
4185 targetphase = idx
4186
4186
4187 # look for specified revision
4187 # look for specified revision
4188 revs = list(revs)
4188 revs = list(revs)
4189 revs.extend(opts['rev'])
4189 revs.extend(opts['rev'])
4190 if not revs:
4190 if not revs:
4191 # display both parents as the second parent phase can influence
4191 # display both parents as the second parent phase can influence
4192 # the phase of a merge commit
4192 # the phase of a merge commit
4193 revs = [c.rev() for c in repo[None].parents()]
4193 revs = [c.rev() for c in repo[None].parents()]
4194
4194
4195 revs = scmutil.revrange(repo, revs)
4195 revs = scmutil.revrange(repo, revs)
4196
4196
4197 ret = 0
4197 ret = 0
4198 if targetphase is None:
4198 if targetphase is None:
4199 # display
4199 # display
4200 for r in revs:
4200 for r in revs:
4201 ctx = repo[r]
4201 ctx = repo[r]
4202 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4202 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4203 else:
4203 else:
4204 with repo.lock(), repo.transaction("phase") as tr:
4204 with repo.lock(), repo.transaction("phase") as tr:
4205 # set phase
4205 # set phase
4206 if not revs:
4206 if not revs:
4207 raise error.Abort(_('empty revision set'))
4207 raise error.Abort(_('empty revision set'))
4208 nodes = [repo[r].node() for r in revs]
4208 nodes = [repo[r].node() for r in revs]
4209 # moving revision from public to draft may hide them
4209 # moving revision from public to draft may hide them
4210 # We have to check result on an unfiltered repository
4210 # We have to check result on an unfiltered repository
4211 unfi = repo.unfiltered()
4211 unfi = repo.unfiltered()
4212 getphase = unfi._phasecache.phase
4212 getphase = unfi._phasecache.phase
4213 olddata = [getphase(unfi, r) for r in unfi]
4213 olddata = [getphase(unfi, r) for r in unfi]
4214 phases.advanceboundary(repo, tr, targetphase, nodes)
4214 phases.advanceboundary(repo, tr, targetphase, nodes)
4215 if opts['force']:
4215 if opts['force']:
4216 phases.retractboundary(repo, tr, targetphase, nodes)
4216 phases.retractboundary(repo, tr, targetphase, nodes)
4217 getphase = unfi._phasecache.phase
4217 getphase = unfi._phasecache.phase
4218 newdata = [getphase(unfi, r) for r in unfi]
4218 newdata = [getphase(unfi, r) for r in unfi]
4219 changes = sum(newdata[r] != olddata[r] for r in unfi)
4219 changes = sum(newdata[r] != olddata[r] for r in unfi)
4220 cl = unfi.changelog
4220 cl = unfi.changelog
4221 rejected = [n for n in nodes
4221 rejected = [n for n in nodes
4222 if newdata[cl.rev(n)] < targetphase]
4222 if newdata[cl.rev(n)] < targetphase]
4223 if rejected:
4223 if rejected:
4224 ui.warn(_('cannot move %i changesets to a higher '
4224 ui.warn(_('cannot move %i changesets to a higher '
4225 'phase, use --force\n') % len(rejected))
4225 'phase, use --force\n') % len(rejected))
4226 ret = 1
4226 ret = 1
4227 if changes:
4227 if changes:
4228 msg = _('phase changed for %i changesets\n') % changes
4228 msg = _('phase changed for %i changesets\n') % changes
4229 if ret:
4229 if ret:
4230 ui.status(msg)
4230 ui.status(msg)
4231 else:
4231 else:
4232 ui.note(msg)
4232 ui.note(msg)
4233 else:
4233 else:
4234 ui.warn(_('no phases changed\n'))
4234 ui.warn(_('no phases changed\n'))
4235 return ret
4235 return ret
4236
4236
4237 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4237 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4238 """Run after a changegroup has been added via pull/unbundle
4238 """Run after a changegroup has been added via pull/unbundle
4239
4239
4240 This takes arguments below:
4240 This takes arguments below:
4241
4241
4242 :modheads: change of heads by pull/unbundle
4242 :modheads: change of heads by pull/unbundle
4243 :optupdate: updating working directory is needed or not
4243 :optupdate: updating working directory is needed or not
4244 :checkout: update destination revision (or None to default destination)
4244 :checkout: update destination revision (or None to default destination)
4245 :brev: a name, which might be a bookmark to be activated after updating
4245 :brev: a name, which might be a bookmark to be activated after updating
4246 """
4246 """
4247 if modheads == 0:
4247 if modheads == 0:
4248 return
4248 return
4249 if optupdate:
4249 if optupdate:
4250 try:
4250 try:
4251 return hg.updatetotally(ui, repo, checkout, brev)
4251 return hg.updatetotally(ui, repo, checkout, brev)
4252 except error.UpdateAbort as inst:
4252 except error.UpdateAbort as inst:
4253 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4253 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4254 hint = inst.hint
4254 hint = inst.hint
4255 raise error.UpdateAbort(msg, hint=hint)
4255 raise error.UpdateAbort(msg, hint=hint)
4256 if modheads > 1:
4256 if modheads > 1:
4257 currentbranchheads = len(repo.branchheads())
4257 currentbranchheads = len(repo.branchheads())
4258 if currentbranchheads == modheads:
4258 if currentbranchheads == modheads:
4259 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4259 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4260 elif currentbranchheads > 1:
4260 elif currentbranchheads > 1:
4261 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4261 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4262 "merge)\n"))
4262 "merge)\n"))
4263 else:
4263 else:
4264 ui.status(_("(run 'hg heads' to see heads)\n"))
4264 ui.status(_("(run 'hg heads' to see heads)\n"))
4265 elif not ui.configbool('commands', 'update.requiredest'):
4265 elif not ui.configbool('commands', 'update.requiredest'):
4266 ui.status(_("(run 'hg update' to get a working copy)\n"))
4266 ui.status(_("(run 'hg update' to get a working copy)\n"))
4267
4267
4268 @command('^pull',
4268 @command('^pull',
4269 [('u', 'update', None,
4269 [('u', 'update', None,
4270 _('update to new branch head if new descendants were pulled')),
4270 _('update to new branch head if new descendants were pulled')),
4271 ('f', 'force', None, _('run even when remote repository is unrelated')),
4271 ('f', 'force', None, _('run even when remote repository is unrelated')),
4272 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4272 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4273 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4273 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4274 ('b', 'branch', [], _('a specific branch you would like to pull'),
4274 ('b', 'branch', [], _('a specific branch you would like to pull'),
4275 _('BRANCH')),
4275 _('BRANCH')),
4276 ] + remoteopts,
4276 ] + remoteopts,
4277 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4277 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4278 def pull(ui, repo, source="default", **opts):
4278 def pull(ui, repo, source="default", **opts):
4279 """pull changes from the specified source
4279 """pull changes from the specified source
4280
4280
4281 Pull changes from a remote repository to a local one.
4281 Pull changes from a remote repository to a local one.
4282
4282
4283 This finds all changes from the repository at the specified path
4283 This finds all changes from the repository at the specified path
4284 or URL and adds them to a local repository (the current one unless
4284 or URL and adds them to a local repository (the current one unless
4285 -R is specified). By default, this does not update the copy of the
4285 -R is specified). By default, this does not update the copy of the
4286 project in the working directory.
4286 project in the working directory.
4287
4287
4288 When cloning from servers that support it, Mercurial may fetch
4288 When cloning from servers that support it, Mercurial may fetch
4289 pre-generated data. When this is done, hooks operating on incoming
4289 pre-generated data. When this is done, hooks operating on incoming
4290 changesets and changegroups may fire more than once, once for each
4290 changesets and changegroups may fire more than once, once for each
4291 pre-generated bundle and as well as for any additional remaining
4291 pre-generated bundle and as well as for any additional remaining
4292 data. See :hg:`help -e clonebundles` for more.
4292 data. See :hg:`help -e clonebundles` for more.
4293
4293
4294 Use :hg:`incoming` if you want to see what would have been added
4294 Use :hg:`incoming` if you want to see what would have been added
4295 by a pull at the time you issued this command. If you then decide
4295 by a pull at the time you issued this command. If you then decide
4296 to add those changes to the repository, you should use :hg:`pull
4296 to add those changes to the repository, you should use :hg:`pull
4297 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4297 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4298
4298
4299 If SOURCE is omitted, the 'default' path will be used.
4299 If SOURCE is omitted, the 'default' path will be used.
4300 See :hg:`help urls` for more information.
4300 See :hg:`help urls` for more information.
4301
4301
4302 Specifying bookmark as ``.`` is equivalent to specifying the active
4302 Specifying bookmark as ``.`` is equivalent to specifying the active
4303 bookmark's name.
4303 bookmark's name.
4304
4304
4305 Returns 0 on success, 1 if an update had unresolved files.
4305 Returns 0 on success, 1 if an update had unresolved files.
4306 """
4306 """
4307
4307
4308 opts = pycompat.byteskwargs(opts)
4308 opts = pycompat.byteskwargs(opts)
4309 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4309 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4310 msg = _('update destination required by configuration')
4310 msg = _('update destination required by configuration')
4311 hint = _('use hg pull followed by hg update DEST')
4311 hint = _('use hg pull followed by hg update DEST')
4312 raise error.Abort(msg, hint=hint)
4312 raise error.Abort(msg, hint=hint)
4313
4313
4314 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4314 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4315 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4315 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4316 other = hg.peer(repo, opts, source)
4316 other = hg.peer(repo, opts, source)
4317 try:
4317 try:
4318 revs, checkout = hg.addbranchrevs(repo, other, branches,
4318 revs, checkout = hg.addbranchrevs(repo, other, branches,
4319 opts.get('rev'))
4319 opts.get('rev'))
4320
4320
4321
4321
4322 pullopargs = {}
4322 pullopargs = {}
4323 if opts.get('bookmark'):
4323 if opts.get('bookmark'):
4324 if not revs:
4324 if not revs:
4325 revs = []
4325 revs = []
4326 # The list of bookmark used here is not the one used to actually
4326 # The list of bookmark used here is not the one used to actually
4327 # update the bookmark name. This can result in the revision pulled
4327 # update the bookmark name. This can result in the revision pulled
4328 # not ending up with the name of the bookmark because of a race
4328 # not ending up with the name of the bookmark because of a race
4329 # condition on the server. (See issue 4689 for details)
4329 # condition on the server. (See issue 4689 for details)
4330 remotebookmarks = other.listkeys('bookmarks')
4330 remotebookmarks = other.listkeys('bookmarks')
4331 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4331 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4332 pullopargs['remotebookmarks'] = remotebookmarks
4332 pullopargs['remotebookmarks'] = remotebookmarks
4333 for b in opts['bookmark']:
4333 for b in opts['bookmark']:
4334 b = repo._bookmarks.expandname(b)
4334 b = repo._bookmarks.expandname(b)
4335 if b not in remotebookmarks:
4335 if b not in remotebookmarks:
4336 raise error.Abort(_('remote bookmark %s not found!') % b)
4336 raise error.Abort(_('remote bookmark %s not found!') % b)
4337 revs.append(hex(remotebookmarks[b]))
4337 revs.append(hex(remotebookmarks[b]))
4338
4338
4339 if revs:
4339 if revs:
4340 try:
4340 try:
4341 # When 'rev' is a bookmark name, we cannot guarantee that it
4341 # When 'rev' is a bookmark name, we cannot guarantee that it
4342 # will be updated with that name because of a race condition
4342 # will be updated with that name because of a race condition
4343 # server side. (See issue 4689 for details)
4343 # server side. (See issue 4689 for details)
4344 oldrevs = revs
4344 oldrevs = revs
4345 revs = [] # actually, nodes
4345 revs = [] # actually, nodes
4346 for r in oldrevs:
4346 for r in oldrevs:
4347 with other.commandexecutor() as e:
4347 with other.commandexecutor() as e:
4348 node = e.callcommand('lookup', {'key': r}).result()
4348 node = e.callcommand('lookup', {'key': r}).result()
4349
4349
4350 revs.append(node)
4350 revs.append(node)
4351 if r == checkout:
4351 if r == checkout:
4352 checkout = node
4352 checkout = node
4353 except error.CapabilityError:
4353 except error.CapabilityError:
4354 err = _("other repository doesn't support revision lookup, "
4354 err = _("other repository doesn't support revision lookup, "
4355 "so a rev cannot be specified.")
4355 "so a rev cannot be specified.")
4356 raise error.Abort(err)
4356 raise error.Abort(err)
4357
4357
4358 wlock = util.nullcontextmanager()
4358 wlock = util.nullcontextmanager()
4359 if opts.get('update'):
4359 if opts.get('update'):
4360 wlock = repo.wlock()
4360 wlock = repo.wlock()
4361 with wlock:
4361 with wlock:
4362 pullopargs.update(opts.get('opargs', {}))
4362 pullopargs.update(opts.get('opargs', {}))
4363 modheads = exchange.pull(repo, other, heads=revs,
4363 modheads = exchange.pull(repo, other, heads=revs,
4364 force=opts.get('force'),
4364 force=opts.get('force'),
4365 bookmarks=opts.get('bookmark', ()),
4365 bookmarks=opts.get('bookmark', ()),
4366 opargs=pullopargs).cgresult
4366 opargs=pullopargs).cgresult
4367
4367
4368 # brev is a name, which might be a bookmark to be activated at
4368 # brev is a name, which might be a bookmark to be activated at
4369 # the end of the update. In other words, it is an explicit
4369 # the end of the update. In other words, it is an explicit
4370 # destination of the update
4370 # destination of the update
4371 brev = None
4371 brev = None
4372
4372
4373 if checkout:
4373 if checkout:
4374 checkout = repo.changelog.rev(checkout)
4374 checkout = repo.changelog.rev(checkout)
4375
4375
4376 # order below depends on implementation of
4376 # order below depends on implementation of
4377 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4377 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4378 # because 'checkout' is determined without it.
4378 # because 'checkout' is determined without it.
4379 if opts.get('rev'):
4379 if opts.get('rev'):
4380 brev = opts['rev'][0]
4380 brev = opts['rev'][0]
4381 elif opts.get('branch'):
4381 elif opts.get('branch'):
4382 brev = opts['branch'][0]
4382 brev = opts['branch'][0]
4383 else:
4383 else:
4384 brev = branches[0]
4384 brev = branches[0]
4385 repo._subtoppath = source
4385 repo._subtoppath = source
4386 try:
4386 try:
4387 ret = postincoming(ui, repo, modheads, opts.get('update'),
4387 ret = postincoming(ui, repo, modheads, opts.get('update'),
4388 checkout, brev)
4388 checkout, brev)
4389
4389
4390 finally:
4390 finally:
4391 del repo._subtoppath
4391 del repo._subtoppath
4392
4392
4393 finally:
4393 finally:
4394 other.close()
4394 other.close()
4395 return ret
4395 return ret
4396
4396
4397 @command('^push',
4397 @command('^push',
4398 [('f', 'force', None, _('force push')),
4398 [('f', 'force', None, _('force push')),
4399 ('r', 'rev', [],
4399 ('r', 'rev', [],
4400 _('a changeset intended to be included in the destination'),
4400 _('a changeset intended to be included in the destination'),
4401 _('REV')),
4401 _('REV')),
4402 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4402 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4403 ('b', 'branch', [],
4403 ('b', 'branch', [],
4404 _('a specific branch you would like to push'), _('BRANCH')),
4404 _('a specific branch you would like to push'), _('BRANCH')),
4405 ('', 'new-branch', False, _('allow pushing a new branch')),
4405 ('', 'new-branch', False, _('allow pushing a new branch')),
4406 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4406 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4407 ] + remoteopts,
4407 ] + remoteopts,
4408 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4408 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4409 def push(ui, repo, dest=None, **opts):
4409 def push(ui, repo, dest=None, **opts):
4410 """push changes to the specified destination
4410 """push changes to the specified destination
4411
4411
4412 Push changesets from the local repository to the specified
4412 Push changesets from the local repository to the specified
4413 destination.
4413 destination.
4414
4414
4415 This operation is symmetrical to pull: it is identical to a pull
4415 This operation is symmetrical to pull: it is identical to a pull
4416 in the destination repository from the current one.
4416 in the destination repository from the current one.
4417
4417
4418 By default, push will not allow creation of new heads at the
4418 By default, push will not allow creation of new heads at the
4419 destination, since multiple heads would make it unclear which head
4419 destination, since multiple heads would make it unclear which head
4420 to use. In this situation, it is recommended to pull and merge
4420 to use. In this situation, it is recommended to pull and merge
4421 before pushing.
4421 before pushing.
4422
4422
4423 Use --new-branch if you want to allow push to create a new named
4423 Use --new-branch if you want to allow push to create a new named
4424 branch that is not present at the destination. This allows you to
4424 branch that is not present at the destination. This allows you to
4425 only create a new branch without forcing other changes.
4425 only create a new branch without forcing other changes.
4426
4426
4427 .. note::
4427 .. note::
4428
4428
4429 Extra care should be taken with the -f/--force option,
4429 Extra care should be taken with the -f/--force option,
4430 which will push all new heads on all branches, an action which will
4430 which will push all new heads on all branches, an action which will
4431 almost always cause confusion for collaborators.
4431 almost always cause confusion for collaborators.
4432
4432
4433 If -r/--rev is used, the specified revision and all its ancestors
4433 If -r/--rev is used, the specified revision and all its ancestors
4434 will be pushed to the remote repository.
4434 will be pushed to the remote repository.
4435
4435
4436 If -B/--bookmark is used, the specified bookmarked revision, its
4436 If -B/--bookmark is used, the specified bookmarked revision, its
4437 ancestors, and the bookmark will be pushed to the remote
4437 ancestors, and the bookmark will be pushed to the remote
4438 repository. Specifying ``.`` is equivalent to specifying the active
4438 repository. Specifying ``.`` is equivalent to specifying the active
4439 bookmark's name.
4439 bookmark's name.
4440
4440
4441 Please see :hg:`help urls` for important details about ``ssh://``
4441 Please see :hg:`help urls` for important details about ``ssh://``
4442 URLs. If DESTINATION is omitted, a default path will be used.
4442 URLs. If DESTINATION is omitted, a default path will be used.
4443
4443
4444 .. container:: verbose
4444 .. container:: verbose
4445
4445
4446 The --pushvars option sends strings to the server that become
4446 The --pushvars option sends strings to the server that become
4447 environment variables prepended with ``HG_USERVAR_``. For example,
4447 environment variables prepended with ``HG_USERVAR_``. For example,
4448 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4448 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4449 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4449 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4450
4450
4451 pushvars can provide for user-overridable hooks as well as set debug
4451 pushvars can provide for user-overridable hooks as well as set debug
4452 levels. One example is having a hook that blocks commits containing
4452 levels. One example is having a hook that blocks commits containing
4453 conflict markers, but enables the user to override the hook if the file
4453 conflict markers, but enables the user to override the hook if the file
4454 is using conflict markers for testing purposes or the file format has
4454 is using conflict markers for testing purposes or the file format has
4455 strings that look like conflict markers.
4455 strings that look like conflict markers.
4456
4456
4457 By default, servers will ignore `--pushvars`. To enable it add the
4457 By default, servers will ignore `--pushvars`. To enable it add the
4458 following to your configuration file::
4458 following to your configuration file::
4459
4459
4460 [push]
4460 [push]
4461 pushvars.server = true
4461 pushvars.server = true
4462
4462
4463 Returns 0 if push was successful, 1 if nothing to push.
4463 Returns 0 if push was successful, 1 if nothing to push.
4464 """
4464 """
4465
4465
4466 opts = pycompat.byteskwargs(opts)
4466 opts = pycompat.byteskwargs(opts)
4467 if opts.get('bookmark'):
4467 if opts.get('bookmark'):
4468 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4468 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4469 for b in opts['bookmark']:
4469 for b in opts['bookmark']:
4470 # translate -B options to -r so changesets get pushed
4470 # translate -B options to -r so changesets get pushed
4471 b = repo._bookmarks.expandname(b)
4471 b = repo._bookmarks.expandname(b)
4472 if b in repo._bookmarks:
4472 if b in repo._bookmarks:
4473 opts.setdefault('rev', []).append(b)
4473 opts.setdefault('rev', []).append(b)
4474 else:
4474 else:
4475 # if we try to push a deleted bookmark, translate it to null
4475 # if we try to push a deleted bookmark, translate it to null
4476 # this lets simultaneous -r, -b options continue working
4476 # this lets simultaneous -r, -b options continue working
4477 opts.setdefault('rev', []).append("null")
4477 opts.setdefault('rev', []).append("null")
4478
4478
4479 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4479 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4480 if not path:
4480 if not path:
4481 raise error.Abort(_('default repository not configured!'),
4481 raise error.Abort(_('default repository not configured!'),
4482 hint=_("see 'hg help config.paths'"))
4482 hint=_("see 'hg help config.paths'"))
4483 dest = path.pushloc or path.loc
4483 dest = path.pushloc or path.loc
4484 branches = (path.branch, opts.get('branch') or [])
4484 branches = (path.branch, opts.get('branch') or [])
4485 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4485 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4486 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4486 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4487 other = hg.peer(repo, opts, dest)
4487 other = hg.peer(repo, opts, dest)
4488
4488
4489 if revs:
4489 if revs:
4490 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4490 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4491 if not revs:
4491 if not revs:
4492 raise error.Abort(_("specified revisions evaluate to an empty set"),
4492 raise error.Abort(_("specified revisions evaluate to an empty set"),
4493 hint=_("use different revision arguments"))
4493 hint=_("use different revision arguments"))
4494 elif path.pushrev:
4494 elif path.pushrev:
4495 # It doesn't make any sense to specify ancestor revisions. So limit
4495 # It doesn't make any sense to specify ancestor revisions. So limit
4496 # to DAG heads to make discovery simpler.
4496 # to DAG heads to make discovery simpler.
4497 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4497 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4498 revs = scmutil.revrange(repo, [expr])
4498 revs = scmutil.revrange(repo, [expr])
4499 revs = [repo[rev].node() for rev in revs]
4499 revs = [repo[rev].node() for rev in revs]
4500 if not revs:
4500 if not revs:
4501 raise error.Abort(_('default push revset for path evaluates to an '
4501 raise error.Abort(_('default push revset for path evaluates to an '
4502 'empty set'))
4502 'empty set'))
4503
4503
4504 repo._subtoppath = dest
4504 repo._subtoppath = dest
4505 try:
4505 try:
4506 # push subrepos depth-first for coherent ordering
4506 # push subrepos depth-first for coherent ordering
4507 c = repo['.']
4507 c = repo['.']
4508 subs = c.substate # only repos that are committed
4508 subs = c.substate # only repos that are committed
4509 for s in sorted(subs):
4509 for s in sorted(subs):
4510 result = c.sub(s).push(opts)
4510 result = c.sub(s).push(opts)
4511 if result == 0:
4511 if result == 0:
4512 return not result
4512 return not result
4513 finally:
4513 finally:
4514 del repo._subtoppath
4514 del repo._subtoppath
4515
4515
4516 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4516 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4517 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4517 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4518
4518
4519 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4519 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4520 newbranch=opts.get('new_branch'),
4520 newbranch=opts.get('new_branch'),
4521 bookmarks=opts.get('bookmark', ()),
4521 bookmarks=opts.get('bookmark', ()),
4522 opargs=opargs)
4522 opargs=opargs)
4523
4523
4524 result = not pushop.cgresult
4524 result = not pushop.cgresult
4525
4525
4526 if pushop.bkresult is not None:
4526 if pushop.bkresult is not None:
4527 if pushop.bkresult == 2:
4527 if pushop.bkresult == 2:
4528 result = 2
4528 result = 2
4529 elif not result and pushop.bkresult:
4529 elif not result and pushop.bkresult:
4530 result = 2
4530 result = 2
4531
4531
4532 return result
4532 return result
4533
4533
4534 @command('recover', [])
4534 @command('recover', [])
4535 def recover(ui, repo):
4535 def recover(ui, repo):
4536 """roll back an interrupted transaction
4536 """roll back an interrupted transaction
4537
4537
4538 Recover from an interrupted commit or pull.
4538 Recover from an interrupted commit or pull.
4539
4539
4540 This command tries to fix the repository status after an
4540 This command tries to fix the repository status after an
4541 interrupted operation. It should only be necessary when Mercurial
4541 interrupted operation. It should only be necessary when Mercurial
4542 suggests it.
4542 suggests it.
4543
4543
4544 Returns 0 if successful, 1 if nothing to recover or verify fails.
4544 Returns 0 if successful, 1 if nothing to recover or verify fails.
4545 """
4545 """
4546 if repo.recover():
4546 if repo.recover():
4547 return hg.verify(repo)
4547 return hg.verify(repo)
4548 return 1
4548 return 1
4549
4549
4550 @command('^remove|rm',
4550 @command('^remove|rm',
4551 [('A', 'after', None, _('record delete for missing files')),
4551 [('A', 'after', None, _('record delete for missing files')),
4552 ('f', 'force', None,
4552 ('f', 'force', None,
4553 _('forget added files, delete modified files')),
4553 _('forget added files, delete modified files')),
4554 ] + subrepoopts + walkopts + dryrunopts,
4554 ] + subrepoopts + walkopts + dryrunopts,
4555 _('[OPTION]... FILE...'),
4555 _('[OPTION]... FILE...'),
4556 inferrepo=True)
4556 inferrepo=True)
4557 def remove(ui, repo, *pats, **opts):
4557 def remove(ui, repo, *pats, **opts):
4558 """remove the specified files on the next commit
4558 """remove the specified files on the next commit
4559
4559
4560 Schedule the indicated files for removal from the current branch.
4560 Schedule the indicated files for removal from the current branch.
4561
4561
4562 This command schedules the files to be removed at the next commit.
4562 This command schedules the files to be removed at the next commit.
4563 To undo a remove before that, see :hg:`revert`. To undo added
4563 To undo a remove before that, see :hg:`revert`. To undo added
4564 files, see :hg:`forget`.
4564 files, see :hg:`forget`.
4565
4565
4566 .. container:: verbose
4566 .. container:: verbose
4567
4567
4568 -A/--after can be used to remove only files that have already
4568 -A/--after can be used to remove only files that have already
4569 been deleted, -f/--force can be used to force deletion, and -Af
4569 been deleted, -f/--force can be used to force deletion, and -Af
4570 can be used to remove files from the next revision without
4570 can be used to remove files from the next revision without
4571 deleting them from the working directory.
4571 deleting them from the working directory.
4572
4572
4573 The following table details the behavior of remove for different
4573 The following table details the behavior of remove for different
4574 file states (columns) and option combinations (rows). The file
4574 file states (columns) and option combinations (rows). The file
4575 states are Added [A], Clean [C], Modified [M] and Missing [!]
4575 states are Added [A], Clean [C], Modified [M] and Missing [!]
4576 (as reported by :hg:`status`). The actions are Warn, Remove
4576 (as reported by :hg:`status`). The actions are Warn, Remove
4577 (from branch) and Delete (from disk):
4577 (from branch) and Delete (from disk):
4578
4578
4579 ========= == == == ==
4579 ========= == == == ==
4580 opt/state A C M !
4580 opt/state A C M !
4581 ========= == == == ==
4581 ========= == == == ==
4582 none W RD W R
4582 none W RD W R
4583 -f R RD RD R
4583 -f R RD RD R
4584 -A W W W R
4584 -A W W W R
4585 -Af R R R R
4585 -Af R R R R
4586 ========= == == == ==
4586 ========= == == == ==
4587
4587
4588 .. note::
4588 .. note::
4589
4589
4590 :hg:`remove` never deletes files in Added [A] state from the
4590 :hg:`remove` never deletes files in Added [A] state from the
4591 working directory, not even if ``--force`` is specified.
4591 working directory, not even if ``--force`` is specified.
4592
4592
4593 Returns 0 on success, 1 if any warnings encountered.
4593 Returns 0 on success, 1 if any warnings encountered.
4594 """
4594 """
4595
4595
4596 opts = pycompat.byteskwargs(opts)
4596 opts = pycompat.byteskwargs(opts)
4597 after, force = opts.get('after'), opts.get('force')
4597 after, force = opts.get('after'), opts.get('force')
4598 dryrun = opts.get('dry_run')
4598 dryrun = opts.get('dry_run')
4599 if not pats and not after:
4599 if not pats and not after:
4600 raise error.Abort(_('no files specified'))
4600 raise error.Abort(_('no files specified'))
4601
4601
4602 m = scmutil.match(repo[None], pats, opts)
4602 m = scmutil.match(repo[None], pats, opts)
4603 subrepos = opts.get('subrepos')
4603 subrepos = opts.get('subrepos')
4604 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4604 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4605 dryrun=dryrun)
4605 dryrun=dryrun)
4606
4606
4607 @command('rename|move|mv',
4607 @command('rename|move|mv',
4608 [('A', 'after', None, _('record a rename that has already occurred')),
4608 [('A', 'after', None, _('record a rename that has already occurred')),
4609 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4609 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4610 ] + walkopts + dryrunopts,
4610 ] + walkopts + dryrunopts,
4611 _('[OPTION]... SOURCE... DEST'))
4611 _('[OPTION]... SOURCE... DEST'))
4612 def rename(ui, repo, *pats, **opts):
4612 def rename(ui, repo, *pats, **opts):
4613 """rename files; equivalent of copy + remove
4613 """rename files; equivalent of copy + remove
4614
4614
4615 Mark dest as copies of sources; mark sources for deletion. If dest
4615 Mark dest as copies of sources; mark sources for deletion. If dest
4616 is a directory, copies are put in that directory. If dest is a
4616 is a directory, copies are put in that directory. If dest is a
4617 file, there can only be one source.
4617 file, there can only be one source.
4618
4618
4619 By default, this command copies the contents of files as they
4619 By default, this command copies the contents of files as they
4620 exist in the working directory. If invoked with -A/--after, the
4620 exist in the working directory. If invoked with -A/--after, the
4621 operation is recorded, but no copying is performed.
4621 operation is recorded, but no copying is performed.
4622
4622
4623 This command takes effect at the next commit. To undo a rename
4623 This command takes effect at the next commit. To undo a rename
4624 before that, see :hg:`revert`.
4624 before that, see :hg:`revert`.
4625
4625
4626 Returns 0 on success, 1 if errors are encountered.
4626 Returns 0 on success, 1 if errors are encountered.
4627 """
4627 """
4628 opts = pycompat.byteskwargs(opts)
4628 opts = pycompat.byteskwargs(opts)
4629 with repo.wlock(False):
4629 with repo.wlock(False):
4630 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4630 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4631
4631
4632 @command('resolve',
4632 @command('resolve',
4633 [('a', 'all', None, _('select all unresolved files')),
4633 [('a', 'all', None, _('select all unresolved files')),
4634 ('l', 'list', None, _('list state of files needing merge')),
4634 ('l', 'list', None, _('list state of files needing merge')),
4635 ('m', 'mark', None, _('mark files as resolved')),
4635 ('m', 'mark', None, _('mark files as resolved')),
4636 ('u', 'unmark', None, _('mark files as unresolved')),
4636 ('u', 'unmark', None, _('mark files as unresolved')),
4637 ('n', 'no-status', None, _('hide status prefix')),
4637 ('n', 'no-status', None, _('hide status prefix')),
4638 ('', 're-merge', None, _('re-merge files'))]
4638 ('', 're-merge', None, _('re-merge files'))]
4639 + mergetoolopts + walkopts + formatteropts,
4639 + mergetoolopts + walkopts + formatteropts,
4640 _('[OPTION]... [FILE]...'),
4640 _('[OPTION]... [FILE]...'),
4641 inferrepo=True)
4641 inferrepo=True)
4642 def resolve(ui, repo, *pats, **opts):
4642 def resolve(ui, repo, *pats, **opts):
4643 """redo merges or set/view the merge status of files
4643 """redo merges or set/view the merge status of files
4644
4644
4645 Merges with unresolved conflicts are often the result of
4645 Merges with unresolved conflicts are often the result of
4646 non-interactive merging using the ``internal:merge`` configuration
4646 non-interactive merging using the ``internal:merge`` configuration
4647 setting, or a command-line merge tool like ``diff3``. The resolve
4647 setting, or a command-line merge tool like ``diff3``. The resolve
4648 command is used to manage the files involved in a merge, after
4648 command is used to manage the files involved in a merge, after
4649 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4649 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4650 working directory must have two parents). See :hg:`help
4650 working directory must have two parents). See :hg:`help
4651 merge-tools` for information on configuring merge tools.
4651 merge-tools` for information on configuring merge tools.
4652
4652
4653 The resolve command can be used in the following ways:
4653 The resolve command can be used in the following ways:
4654
4654
4655 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4655 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4656 the specified files, discarding any previous merge attempts. Re-merging
4656 the specified files, discarding any previous merge attempts. Re-merging
4657 is not performed for files already marked as resolved. Use ``--all/-a``
4657 is not performed for files already marked as resolved. Use ``--all/-a``
4658 to select all unresolved files. ``--tool`` can be used to specify
4658 to select all unresolved files. ``--tool`` can be used to specify
4659 the merge tool used for the given files. It overrides the HGMERGE
4659 the merge tool used for the given files. It overrides the HGMERGE
4660 environment variable and your configuration files. Previous file
4660 environment variable and your configuration files. Previous file
4661 contents are saved with a ``.orig`` suffix.
4661 contents are saved with a ``.orig`` suffix.
4662
4662
4663 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4663 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4664 (e.g. after having manually fixed-up the files). The default is
4664 (e.g. after having manually fixed-up the files). The default is
4665 to mark all unresolved files.
4665 to mark all unresolved files.
4666
4666
4667 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4667 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4668 default is to mark all resolved files.
4668 default is to mark all resolved files.
4669
4669
4670 - :hg:`resolve -l`: list files which had or still have conflicts.
4670 - :hg:`resolve -l`: list files which had or still have conflicts.
4671 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4671 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4672 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4672 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4673 the list. See :hg:`help filesets` for details.
4673 the list. See :hg:`help filesets` for details.
4674
4674
4675 .. note::
4675 .. note::
4676
4676
4677 Mercurial will not let you commit files with unresolved merge
4677 Mercurial will not let you commit files with unresolved merge
4678 conflicts. You must use :hg:`resolve -m ...` before you can
4678 conflicts. You must use :hg:`resolve -m ...` before you can
4679 commit after a conflicting merge.
4679 commit after a conflicting merge.
4680
4680
4681 .. container:: verbose
4681 .. container:: verbose
4682
4682
4683 Template:
4683 Template:
4684
4684
4685 The following keywords are supported in addition to the common template
4685 The following keywords are supported in addition to the common template
4686 keywords and functions. See also :hg:`help templates`.
4686 keywords and functions. See also :hg:`help templates`.
4687
4687
4688 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4688 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4689 :path: String. Repository-absolute path of the file.
4689 :path: String. Repository-absolute path of the file.
4690
4690
4691 Returns 0 on success, 1 if any files fail a resolve attempt.
4691 Returns 0 on success, 1 if any files fail a resolve attempt.
4692 """
4692 """
4693
4693
4694 opts = pycompat.byteskwargs(opts)
4694 opts = pycompat.byteskwargs(opts)
4695 confirm = ui.configbool('commands', 'resolve.confirm')
4695 confirm = ui.configbool('commands', 'resolve.confirm')
4696 flaglist = 'all mark unmark list no_status re_merge'.split()
4696 flaglist = 'all mark unmark list no_status re_merge'.split()
4697 all, mark, unmark, show, nostatus, remerge = \
4697 all, mark, unmark, show, nostatus, remerge = \
4698 [opts.get(o) for o in flaglist]
4698 [opts.get(o) for o in flaglist]
4699
4699
4700 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4700 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4701 if actioncount > 1:
4701 if actioncount > 1:
4702 raise error.Abort(_("too many actions specified"))
4702 raise error.Abort(_("too many actions specified"))
4703 elif (actioncount == 0
4703 elif (actioncount == 0
4704 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4704 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4705 hint = _('use --mark, --unmark, --list or --re-merge')
4705 hint = _('use --mark, --unmark, --list or --re-merge')
4706 raise error.Abort(_('no action specified'), hint=hint)
4706 raise error.Abort(_('no action specified'), hint=hint)
4707 if pats and all:
4707 if pats and all:
4708 raise error.Abort(_("can't specify --all and patterns"))
4708 raise error.Abort(_("can't specify --all and patterns"))
4709 if not (all or pats or show or mark or unmark):
4709 if not (all or pats or show or mark or unmark):
4710 raise error.Abort(_('no files or directories specified'),
4710 raise error.Abort(_('no files or directories specified'),
4711 hint=('use --all to re-merge all unresolved files'))
4711 hint=('use --all to re-merge all unresolved files'))
4712
4712
4713 if confirm:
4713 if confirm:
4714 if all:
4714 if all:
4715 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4715 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4716 b'$$ &Yes $$ &No')):
4716 b'$$ &Yes $$ &No')):
4717 raise error.Abort(_('user quit'))
4717 raise error.Abort(_('user quit'))
4718 if mark and not pats:
4718 if mark and not pats:
4719 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4719 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4720 b'$$ &Yes $$ &No')):
4720 b'$$ &Yes $$ &No')):
4721 raise error.Abort(_('user quit'))
4721 raise error.Abort(_('user quit'))
4722 if unmark and not pats:
4722 if unmark and not pats:
4723 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4723 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4724 b'$$ &Yes $$ &No')):
4724 b'$$ &Yes $$ &No')):
4725 raise error.Abort(_('user quit'))
4725 raise error.Abort(_('user quit'))
4726
4726
4727 if show:
4727 if show:
4728 ui.pager('resolve')
4728 ui.pager('resolve')
4729 fm = ui.formatter('resolve', opts)
4729 fm = ui.formatter('resolve', opts)
4730 ms = mergemod.mergestate.read(repo)
4730 ms = mergemod.mergestate.read(repo)
4731 wctx = repo[None]
4731 wctx = repo[None]
4732 m = scmutil.match(wctx, pats, opts)
4732 m = scmutil.match(wctx, pats, opts)
4733
4733
4734 # Labels and keys based on merge state. Unresolved path conflicts show
4734 # Labels and keys based on merge state. Unresolved path conflicts show
4735 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4735 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4736 # resolved conflicts.
4736 # resolved conflicts.
4737 mergestateinfo = {
4737 mergestateinfo = {
4738 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4738 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4739 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4739 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4740 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4740 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4741 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4741 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4742 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4742 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4743 'D'),
4743 'D'),
4744 }
4744 }
4745
4745
4746 for f in ms:
4746 for f in ms:
4747 if not m(f):
4747 if not m(f):
4748 continue
4748 continue
4749
4749
4750 label, key = mergestateinfo[ms[f]]
4750 label, key = mergestateinfo[ms[f]]
4751 fm.startitem()
4751 fm.startitem()
4752 fm.context(ctx=wctx)
4752 fm.context(ctx=wctx)
4753 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4753 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4754 fm.write('path', '%s\n', f, label=label)
4754 fm.write('path', '%s\n', f, label=label)
4755 fm.end()
4755 fm.end()
4756 return 0
4756 return 0
4757
4757
4758 with repo.wlock():
4758 with repo.wlock():
4759 ms = mergemod.mergestate.read(repo)
4759 ms = mergemod.mergestate.read(repo)
4760
4760
4761 if not (ms.active() or repo.dirstate.p2() != nullid):
4761 if not (ms.active() or repo.dirstate.p2() != nullid):
4762 raise error.Abort(
4762 raise error.Abort(
4763 _('resolve command not applicable when not merging'))
4763 _('resolve command not applicable when not merging'))
4764
4764
4765 wctx = repo[None]
4765 wctx = repo[None]
4766
4766
4767 if (ms.mergedriver
4767 if (ms.mergedriver
4768 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4768 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4769 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4769 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4770 ms.commit()
4770 ms.commit()
4771 # allow mark and unmark to go through
4771 # allow mark and unmark to go through
4772 if not mark and not unmark and not proceed:
4772 if not mark and not unmark and not proceed:
4773 return 1
4773 return 1
4774
4774
4775 m = scmutil.match(wctx, pats, opts)
4775 m = scmutil.match(wctx, pats, opts)
4776 ret = 0
4776 ret = 0
4777 didwork = False
4777 didwork = False
4778 runconclude = False
4778 runconclude = False
4779
4779
4780 tocomplete = []
4780 tocomplete = []
4781 hasconflictmarkers = []
4781 hasconflictmarkers = []
4782 if mark:
4782 if mark:
4783 markcheck = ui.config('commands', 'resolve.mark-check')
4783 markcheck = ui.config('commands', 'resolve.mark-check')
4784 if markcheck not in ['warn', 'abort']:
4784 if markcheck not in ['warn', 'abort']:
4785 # Treat all invalid / unrecognized values as 'none'.
4785 # Treat all invalid / unrecognized values as 'none'.
4786 markcheck = False
4786 markcheck = False
4787 for f in ms:
4787 for f in ms:
4788 if not m(f):
4788 if not m(f):
4789 continue
4789 continue
4790
4790
4791 didwork = True
4791 didwork = True
4792
4792
4793 # don't let driver-resolved files be marked, and run the conclude
4793 # don't let driver-resolved files be marked, and run the conclude
4794 # step if asked to resolve
4794 # step if asked to resolve
4795 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4795 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4796 exact = m.exact(f)
4796 exact = m.exact(f)
4797 if mark:
4797 if mark:
4798 if exact:
4798 if exact:
4799 ui.warn(_('not marking %s as it is driver-resolved\n')
4799 ui.warn(_('not marking %s as it is driver-resolved\n')
4800 % f)
4800 % f)
4801 elif unmark:
4801 elif unmark:
4802 if exact:
4802 if exact:
4803 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4803 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4804 % f)
4804 % f)
4805 else:
4805 else:
4806 runconclude = True
4806 runconclude = True
4807 continue
4807 continue
4808
4808
4809 # path conflicts must be resolved manually
4809 # path conflicts must be resolved manually
4810 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4810 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4811 mergemod.MERGE_RECORD_RESOLVED_PATH):
4811 mergemod.MERGE_RECORD_RESOLVED_PATH):
4812 if mark:
4812 if mark:
4813 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4813 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4814 elif unmark:
4814 elif unmark:
4815 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4815 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4816 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4816 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4817 ui.warn(_('%s: path conflict must be resolved manually\n')
4817 ui.warn(_('%s: path conflict must be resolved manually\n')
4818 % f)
4818 % f)
4819 continue
4819 continue
4820
4820
4821 if mark:
4821 if mark:
4822 if markcheck:
4822 if markcheck:
4823 with repo.wvfs(f) as fobj:
4823 with repo.wvfs(f) as fobj:
4824 fdata = fobj.read()
4824 fdata = fobj.read()
4825 if filemerge.hasconflictmarkers(fdata) and \
4825 if filemerge.hasconflictmarkers(fdata) and \
4826 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4826 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4827 hasconflictmarkers.append(f)
4827 hasconflictmarkers.append(f)
4828 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4828 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4829 elif unmark:
4829 elif unmark:
4830 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4830 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4831 else:
4831 else:
4832 # backup pre-resolve (merge uses .orig for its own purposes)
4832 # backup pre-resolve (merge uses .orig for its own purposes)
4833 a = repo.wjoin(f)
4833 a = repo.wjoin(f)
4834 try:
4834 try:
4835 util.copyfile(a, a + ".resolve")
4835 util.copyfile(a, a + ".resolve")
4836 except (IOError, OSError) as inst:
4836 except (IOError, OSError) as inst:
4837 if inst.errno != errno.ENOENT:
4837 if inst.errno != errno.ENOENT:
4838 raise
4838 raise
4839
4839
4840 try:
4840 try:
4841 # preresolve file
4841 # preresolve file
4842 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4842 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4843 with ui.configoverride(overrides, 'resolve'):
4843 with ui.configoverride(overrides, 'resolve'):
4844 complete, r = ms.preresolve(f, wctx)
4844 complete, r = ms.preresolve(f, wctx)
4845 if not complete:
4845 if not complete:
4846 tocomplete.append(f)
4846 tocomplete.append(f)
4847 elif r:
4847 elif r:
4848 ret = 1
4848 ret = 1
4849 finally:
4849 finally:
4850 ms.commit()
4850 ms.commit()
4851
4851
4852 # replace filemerge's .orig file with our resolve file, but only
4852 # replace filemerge's .orig file with our resolve file, but only
4853 # for merges that are complete
4853 # for merges that are complete
4854 if complete:
4854 if complete:
4855 try:
4855 try:
4856 util.rename(a + ".resolve",
4856 util.rename(a + ".resolve",
4857 scmutil.origpath(ui, repo, a))
4857 scmutil.origpath(ui, repo, a))
4858 except OSError as inst:
4858 except OSError as inst:
4859 if inst.errno != errno.ENOENT:
4859 if inst.errno != errno.ENOENT:
4860 raise
4860 raise
4861
4861
4862 if hasconflictmarkers:
4862 if hasconflictmarkers:
4863 ui.warn(_('warning: the following files still have conflict '
4863 ui.warn(_('warning: the following files still have conflict '
4864 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4864 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4865 if markcheck == 'abort' and not all:
4865 if markcheck == 'abort' and not all:
4866 raise error.Abort(_('conflict markers detected'),
4866 raise error.Abort(_('conflict markers detected'),
4867 hint=_('use --all to mark anyway'))
4867 hint=_('use --all to mark anyway'))
4868
4868
4869 for f in tocomplete:
4869 for f in tocomplete:
4870 try:
4870 try:
4871 # resolve file
4871 # resolve file
4872 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4872 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4873 with ui.configoverride(overrides, 'resolve'):
4873 with ui.configoverride(overrides, 'resolve'):
4874 r = ms.resolve(f, wctx)
4874 r = ms.resolve(f, wctx)
4875 if r:
4875 if r:
4876 ret = 1
4876 ret = 1
4877 finally:
4877 finally:
4878 ms.commit()
4878 ms.commit()
4879
4879
4880 # replace filemerge's .orig file with our resolve file
4880 # replace filemerge's .orig file with our resolve file
4881 a = repo.wjoin(f)
4881 a = repo.wjoin(f)
4882 try:
4882 try:
4883 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4883 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4884 except OSError as inst:
4884 except OSError as inst:
4885 if inst.errno != errno.ENOENT:
4885 if inst.errno != errno.ENOENT:
4886 raise
4886 raise
4887
4887
4888 ms.commit()
4888 ms.commit()
4889 ms.recordactions()
4889 ms.recordactions()
4890
4890
4891 if not didwork and pats:
4891 if not didwork and pats:
4892 hint = None
4892 hint = None
4893 if not any([p for p in pats if p.find(':') >= 0]):
4893 if not any([p for p in pats if p.find(':') >= 0]):
4894 pats = ['path:%s' % p for p in pats]
4894 pats = ['path:%s' % p for p in pats]
4895 m = scmutil.match(wctx, pats, opts)
4895 m = scmutil.match(wctx, pats, opts)
4896 for f in ms:
4896 for f in ms:
4897 if not m(f):
4897 if not m(f):
4898 continue
4898 continue
4899 def flag(o):
4899 def flag(o):
4900 if o == 're_merge':
4900 if o == 're_merge':
4901 return '--re-merge '
4901 return '--re-merge '
4902 return '-%s ' % o[0:1]
4902 return '-%s ' % o[0:1]
4903 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4903 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4904 hint = _("(try: hg resolve %s%s)\n") % (
4904 hint = _("(try: hg resolve %s%s)\n") % (
4905 flags,
4905 flags,
4906 ' '.join(pats))
4906 ' '.join(pats))
4907 break
4907 break
4908 ui.warn(_("arguments do not match paths that need resolving\n"))
4908 ui.warn(_("arguments do not match paths that need resolving\n"))
4909 if hint:
4909 if hint:
4910 ui.warn(hint)
4910 ui.warn(hint)
4911 elif ms.mergedriver and ms.mdstate() != 's':
4911 elif ms.mergedriver and ms.mdstate() != 's':
4912 # run conclude step when either a driver-resolved file is requested
4912 # run conclude step when either a driver-resolved file is requested
4913 # or there are no driver-resolved files
4913 # or there are no driver-resolved files
4914 # we can't use 'ret' to determine whether any files are unresolved
4914 # we can't use 'ret' to determine whether any files are unresolved
4915 # because we might not have tried to resolve some
4915 # because we might not have tried to resolve some
4916 if ((runconclude or not list(ms.driverresolved()))
4916 if ((runconclude or not list(ms.driverresolved()))
4917 and not list(ms.unresolved())):
4917 and not list(ms.unresolved())):
4918 proceed = mergemod.driverconclude(repo, ms, wctx)
4918 proceed = mergemod.driverconclude(repo, ms, wctx)
4919 ms.commit()
4919 ms.commit()
4920 if not proceed:
4920 if not proceed:
4921 return 1
4921 return 1
4922
4922
4923 # Nudge users into finishing an unfinished operation
4923 # Nudge users into finishing an unfinished operation
4924 unresolvedf = list(ms.unresolved())
4924 unresolvedf = list(ms.unresolved())
4925 driverresolvedf = list(ms.driverresolved())
4925 driverresolvedf = list(ms.driverresolved())
4926 if not unresolvedf and not driverresolvedf:
4926 if not unresolvedf and not driverresolvedf:
4927 ui.status(_('(no more unresolved files)\n'))
4927 ui.status(_('(no more unresolved files)\n'))
4928 cmdutil.checkafterresolved(repo)
4928 cmdutil.checkafterresolved(repo)
4929 elif not unresolvedf:
4929 elif not unresolvedf:
4930 ui.status(_('(no more unresolved files -- '
4930 ui.status(_('(no more unresolved files -- '
4931 'run "hg resolve --all" to conclude)\n'))
4931 'run "hg resolve --all" to conclude)\n'))
4932
4932
4933 return ret
4933 return ret
4934
4934
4935 @command('revert',
4935 @command('revert',
4936 [('a', 'all', None, _('revert all changes when no arguments given')),
4936 [('a', 'all', None, _('revert all changes when no arguments given')),
4937 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4937 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4938 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4938 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4939 ('C', 'no-backup', None, _('do not save backup copies of files')),
4939 ('C', 'no-backup', None, _('do not save backup copies of files')),
4940 ('i', 'interactive', None, _('interactively select the changes')),
4940 ('i', 'interactive', None, _('interactively select the changes')),
4941 ] + walkopts + dryrunopts,
4941 ] + walkopts + dryrunopts,
4942 _('[OPTION]... [-r REV] [NAME]...'))
4942 _('[OPTION]... [-r REV] [NAME]...'))
4943 def revert(ui, repo, *pats, **opts):
4943 def revert(ui, repo, *pats, **opts):
4944 """restore files to their checkout state
4944 """restore files to their checkout state
4945
4945
4946 .. note::
4946 .. note::
4947
4947
4948 To check out earlier revisions, you should use :hg:`update REV`.
4948 To check out earlier revisions, you should use :hg:`update REV`.
4949 To cancel an uncommitted merge (and lose your changes),
4949 To cancel an uncommitted merge (and lose your changes),
4950 use :hg:`merge --abort`.
4950 use :hg:`merge --abort`.
4951
4951
4952 With no revision specified, revert the specified files or directories
4952 With no revision specified, revert the specified files or directories
4953 to the contents they had in the parent of the working directory.
4953 to the contents they had in the parent of the working directory.
4954 This restores the contents of files to an unmodified
4954 This restores the contents of files to an unmodified
4955 state and unschedules adds, removes, copies, and renames. If the
4955 state and unschedules adds, removes, copies, and renames. If the
4956 working directory has two parents, you must explicitly specify a
4956 working directory has two parents, you must explicitly specify a
4957 revision.
4957 revision.
4958
4958
4959 Using the -r/--rev or -d/--date options, revert the given files or
4959 Using the -r/--rev or -d/--date options, revert the given files or
4960 directories to their states as of a specific revision. Because
4960 directories to their states as of a specific revision. Because
4961 revert does not change the working directory parents, this will
4961 revert does not change the working directory parents, this will
4962 cause these files to appear modified. This can be helpful to "back
4962 cause these files to appear modified. This can be helpful to "back
4963 out" some or all of an earlier change. See :hg:`backout` for a
4963 out" some or all of an earlier change. See :hg:`backout` for a
4964 related method.
4964 related method.
4965
4965
4966 Modified files are saved with a .orig suffix before reverting.
4966 Modified files are saved with a .orig suffix before reverting.
4967 To disable these backups, use --no-backup. It is possible to store
4967 To disable these backups, use --no-backup. It is possible to store
4968 the backup files in a custom directory relative to the root of the
4968 the backup files in a custom directory relative to the root of the
4969 repository by setting the ``ui.origbackuppath`` configuration
4969 repository by setting the ``ui.origbackuppath`` configuration
4970 option.
4970 option.
4971
4971
4972 See :hg:`help dates` for a list of formats valid for -d/--date.
4972 See :hg:`help dates` for a list of formats valid for -d/--date.
4973
4973
4974 See :hg:`help backout` for a way to reverse the effect of an
4974 See :hg:`help backout` for a way to reverse the effect of an
4975 earlier changeset.
4975 earlier changeset.
4976
4976
4977 Returns 0 on success.
4977 Returns 0 on success.
4978 """
4978 """
4979
4979
4980 opts = pycompat.byteskwargs(opts)
4980 opts = pycompat.byteskwargs(opts)
4981 if opts.get("date"):
4981 if opts.get("date"):
4982 if opts.get("rev"):
4982 if opts.get("rev"):
4983 raise error.Abort(_("you can't specify a revision and a date"))
4983 raise error.Abort(_("you can't specify a revision and a date"))
4984 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4984 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4985
4985
4986 parent, p2 = repo.dirstate.parents()
4986 parent, p2 = repo.dirstate.parents()
4987 if not opts.get('rev') and p2 != nullid:
4987 if not opts.get('rev') and p2 != nullid:
4988 # revert after merge is a trap for new users (issue2915)
4988 # revert after merge is a trap for new users (issue2915)
4989 raise error.Abort(_('uncommitted merge with no revision specified'),
4989 raise error.Abort(_('uncommitted merge with no revision specified'),
4990 hint=_("use 'hg update' or see 'hg help revert'"))
4990 hint=_("use 'hg update' or see 'hg help revert'"))
4991
4991
4992 rev = opts.get('rev')
4992 rev = opts.get('rev')
4993 if rev:
4993 if rev:
4994 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4994 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4995 ctx = scmutil.revsingle(repo, rev)
4995 ctx = scmutil.revsingle(repo, rev)
4996
4996
4997 if (not (pats or opts.get('include') or opts.get('exclude') or
4997 if (not (pats or opts.get('include') or opts.get('exclude') or
4998 opts.get('all') or opts.get('interactive'))):
4998 opts.get('all') or opts.get('interactive'))):
4999 msg = _("no files or directories specified")
4999 msg = _("no files or directories specified")
5000 if p2 != nullid:
5000 if p2 != nullid:
5001 hint = _("uncommitted merge, use --all to discard all changes,"
5001 hint = _("uncommitted merge, use --all to discard all changes,"
5002 " or 'hg update -C .' to abort the merge")
5002 " or 'hg update -C .' to abort the merge")
5003 raise error.Abort(msg, hint=hint)
5003 raise error.Abort(msg, hint=hint)
5004 dirty = any(repo.status())
5004 dirty = any(repo.status())
5005 node = ctx.node()
5005 node = ctx.node()
5006 if node != parent:
5006 if node != parent:
5007 if dirty:
5007 if dirty:
5008 hint = _("uncommitted changes, use --all to discard all"
5008 hint = _("uncommitted changes, use --all to discard all"
5009 " changes, or 'hg update %d' to update") % ctx.rev()
5009 " changes, or 'hg update %d' to update") % ctx.rev()
5010 else:
5010 else:
5011 hint = _("use --all to revert all files,"
5011 hint = _("use --all to revert all files,"
5012 " or 'hg update %d' to update") % ctx.rev()
5012 " or 'hg update %d' to update") % ctx.rev()
5013 elif dirty:
5013 elif dirty:
5014 hint = _("uncommitted changes, use --all to discard all changes")
5014 hint = _("uncommitted changes, use --all to discard all changes")
5015 else:
5015 else:
5016 hint = _("use --all to revert all files")
5016 hint = _("use --all to revert all files")
5017 raise error.Abort(msg, hint=hint)
5017 raise error.Abort(msg, hint=hint)
5018
5018
5019 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5019 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5020 **pycompat.strkwargs(opts))
5020 **pycompat.strkwargs(opts))
5021
5021
5022 @command('rollback', dryrunopts +
5022 @command('rollback', dryrunopts +
5023 [('f', 'force', False, _('ignore safety measures'))])
5023 [('f', 'force', False, _('ignore safety measures'))])
5024 def rollback(ui, repo, **opts):
5024 def rollback(ui, repo, **opts):
5025 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5025 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5026
5026
5027 Please use :hg:`commit --amend` instead of rollback to correct
5027 Please use :hg:`commit --amend` instead of rollback to correct
5028 mistakes in the last commit.
5028 mistakes in the last commit.
5029
5029
5030 This command should be used with care. There is only one level of
5030 This command should be used with care. There is only one level of
5031 rollback, and there is no way to undo a rollback. It will also
5031 rollback, and there is no way to undo a rollback. It will also
5032 restore the dirstate at the time of the last transaction, losing
5032 restore the dirstate at the time of the last transaction, losing
5033 any dirstate changes since that time. This command does not alter
5033 any dirstate changes since that time. This command does not alter
5034 the working directory.
5034 the working directory.
5035
5035
5036 Transactions are used to encapsulate the effects of all commands
5036 Transactions are used to encapsulate the effects of all commands
5037 that create new changesets or propagate existing changesets into a
5037 that create new changesets or propagate existing changesets into a
5038 repository.
5038 repository.
5039
5039
5040 .. container:: verbose
5040 .. container:: verbose
5041
5041
5042 For example, the following commands are transactional, and their
5042 For example, the following commands are transactional, and their
5043 effects can be rolled back:
5043 effects can be rolled back:
5044
5044
5045 - commit
5045 - commit
5046 - import
5046 - import
5047 - pull
5047 - pull
5048 - push (with this repository as the destination)
5048 - push (with this repository as the destination)
5049 - unbundle
5049 - unbundle
5050
5050
5051 To avoid permanent data loss, rollback will refuse to rollback a
5051 To avoid permanent data loss, rollback will refuse to rollback a
5052 commit transaction if it isn't checked out. Use --force to
5052 commit transaction if it isn't checked out. Use --force to
5053 override this protection.
5053 override this protection.
5054
5054
5055 The rollback command can be entirely disabled by setting the
5055 The rollback command can be entirely disabled by setting the
5056 ``ui.rollback`` configuration setting to false. If you're here
5056 ``ui.rollback`` configuration setting to false. If you're here
5057 because you want to use rollback and it's disabled, you can
5057 because you want to use rollback and it's disabled, you can
5058 re-enable the command by setting ``ui.rollback`` to true.
5058 re-enable the command by setting ``ui.rollback`` to true.
5059
5059
5060 This command is not intended for use on public repositories. Once
5060 This command is not intended for use on public repositories. Once
5061 changes are visible for pull by other users, rolling a transaction
5061 changes are visible for pull by other users, rolling a transaction
5062 back locally is ineffective (someone else may already have pulled
5062 back locally is ineffective (someone else may already have pulled
5063 the changes). Furthermore, a race is possible with readers of the
5063 the changes). Furthermore, a race is possible with readers of the
5064 repository; for example an in-progress pull from the repository
5064 repository; for example an in-progress pull from the repository
5065 may fail if a rollback is performed.
5065 may fail if a rollback is performed.
5066
5066
5067 Returns 0 on success, 1 if no rollback data is available.
5067 Returns 0 on success, 1 if no rollback data is available.
5068 """
5068 """
5069 if not ui.configbool('ui', 'rollback'):
5069 if not ui.configbool('ui', 'rollback'):
5070 raise error.Abort(_('rollback is disabled because it is unsafe'),
5070 raise error.Abort(_('rollback is disabled because it is unsafe'),
5071 hint=('see `hg help -v rollback` for information'))
5071 hint=('see `hg help -v rollback` for information'))
5072 return repo.rollback(dryrun=opts.get(r'dry_run'),
5072 return repo.rollback(dryrun=opts.get(r'dry_run'),
5073 force=opts.get(r'force'))
5073 force=opts.get(r'force'))
5074
5074
5075 @command('root', [], intents={INTENT_READONLY})
5075 @command('root', [], intents={INTENT_READONLY})
5076 def root(ui, repo):
5076 def root(ui, repo):
5077 """print the root (top) of the current working directory
5077 """print the root (top) of the current working directory
5078
5078
5079 Print the root directory of the current repository.
5079 Print the root directory of the current repository.
5080
5080
5081 Returns 0 on success.
5081 Returns 0 on success.
5082 """
5082 """
5083 ui.write(repo.root + "\n")
5083 ui.write(repo.root + "\n")
5084
5084
5085 @command('^serve',
5085 @command('^serve',
5086 [('A', 'accesslog', '', _('name of access log file to write to'),
5086 [('A', 'accesslog', '', _('name of access log file to write to'),
5087 _('FILE')),
5087 _('FILE')),
5088 ('d', 'daemon', None, _('run server in background')),
5088 ('d', 'daemon', None, _('run server in background')),
5089 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5089 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5090 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5090 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5091 # use string type, then we can check if something was passed
5091 # use string type, then we can check if something was passed
5092 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5092 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5093 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5093 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5094 _('ADDR')),
5094 _('ADDR')),
5095 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5095 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5096 _('PREFIX')),
5096 _('PREFIX')),
5097 ('n', 'name', '',
5097 ('n', 'name', '',
5098 _('name to show in web pages (default: working directory)'), _('NAME')),
5098 _('name to show in web pages (default: working directory)'), _('NAME')),
5099 ('', 'web-conf', '',
5099 ('', 'web-conf', '',
5100 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5100 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5101 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5101 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5102 _('FILE')),
5102 _('FILE')),
5103 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5103 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5104 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5104 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5105 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5105 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5106 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5106 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5107 ('', 'style', '', _('template style to use'), _('STYLE')),
5107 ('', 'style', '', _('template style to use'), _('STYLE')),
5108 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5108 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5109 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5109 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5110 ('', 'print-url', None, _('start and print only the URL'))]
5110 ('', 'print-url', None, _('start and print only the URL'))]
5111 + subrepoopts,
5111 + subrepoopts,
5112 _('[OPTION]...'),
5112 _('[OPTION]...'),
5113 optionalrepo=True)
5113 optionalrepo=True)
5114 def serve(ui, repo, **opts):
5114 def serve(ui, repo, **opts):
5115 """start stand-alone webserver
5115 """start stand-alone webserver
5116
5116
5117 Start a local HTTP repository browser and pull server. You can use
5117 Start a local HTTP repository browser and pull server. You can use
5118 this for ad-hoc sharing and browsing of repositories. It is
5118 this for ad-hoc sharing and browsing of repositories. It is
5119 recommended to use a real web server to serve a repository for
5119 recommended to use a real web server to serve a repository for
5120 longer periods of time.
5120 longer periods of time.
5121
5121
5122 Please note that the server does not implement access control.
5122 Please note that the server does not implement access control.
5123 This means that, by default, anybody can read from the server and
5123 This means that, by default, anybody can read from the server and
5124 nobody can write to it by default. Set the ``web.allow-push``
5124 nobody can write to it by default. Set the ``web.allow-push``
5125 option to ``*`` to allow everybody to push to the server. You
5125 option to ``*`` to allow everybody to push to the server. You
5126 should use a real web server if you need to authenticate users.
5126 should use a real web server if you need to authenticate users.
5127
5127
5128 By default, the server logs accesses to stdout and errors to
5128 By default, the server logs accesses to stdout and errors to
5129 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5129 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5130 files.
5130 files.
5131
5131
5132 To have the server choose a free port number to listen on, specify
5132 To have the server choose a free port number to listen on, specify
5133 a port number of 0; in this case, the server will print the port
5133 a port number of 0; in this case, the server will print the port
5134 number it uses.
5134 number it uses.
5135
5135
5136 Returns 0 on success.
5136 Returns 0 on success.
5137 """
5137 """
5138
5138
5139 opts = pycompat.byteskwargs(opts)
5139 opts = pycompat.byteskwargs(opts)
5140 if opts["stdio"] and opts["cmdserver"]:
5140 if opts["stdio"] and opts["cmdserver"]:
5141 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5141 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5142 if opts["print_url"] and ui.verbose:
5142 if opts["print_url"] and ui.verbose:
5143 raise error.Abort(_("cannot use --print-url with --verbose"))
5143 raise error.Abort(_("cannot use --print-url with --verbose"))
5144
5144
5145 if opts["stdio"]:
5145 if opts["stdio"]:
5146 if repo is None:
5146 if repo is None:
5147 raise error.RepoError(_("there is no Mercurial repository here"
5147 raise error.RepoError(_("there is no Mercurial repository here"
5148 " (.hg not found)"))
5148 " (.hg not found)"))
5149 s = wireprotoserver.sshserver(ui, repo)
5149 s = wireprotoserver.sshserver(ui, repo)
5150 s.serve_forever()
5150 s.serve_forever()
5151
5151
5152 service = server.createservice(ui, repo, opts)
5152 service = server.createservice(ui, repo, opts)
5153 return server.runservice(opts, initfn=service.init, runfn=service.run)
5153 return server.runservice(opts, initfn=service.init, runfn=service.run)
5154
5154
5155 _NOTTERSE = 'nothing'
5155 _NOTTERSE = 'nothing'
5156
5156
5157 @command('^status|st',
5157 @command('^status|st',
5158 [('A', 'all', None, _('show status of all files')),
5158 [('A', 'all', None, _('show status of all files')),
5159 ('m', 'modified', None, _('show only modified files')),
5159 ('m', 'modified', None, _('show only modified files')),
5160 ('a', 'added', None, _('show only added files')),
5160 ('a', 'added', None, _('show only added files')),
5161 ('r', 'removed', None, _('show only removed files')),
5161 ('r', 'removed', None, _('show only removed files')),
5162 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5162 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5163 ('c', 'clean', None, _('show only files without changes')),
5163 ('c', 'clean', None, _('show only files without changes')),
5164 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5164 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5165 ('i', 'ignored', None, _('show only ignored files')),
5165 ('i', 'ignored', None, _('show only ignored files')),
5166 ('n', 'no-status', None, _('hide status prefix')),
5166 ('n', 'no-status', None, _('hide status prefix')),
5167 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5167 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5168 ('C', 'copies', None, _('show source of copied files')),
5168 ('C', 'copies', None, _('show source of copied files')),
5169 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5169 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5170 ('', 'rev', [], _('show difference from revision'), _('REV')),
5170 ('', 'rev', [], _('show difference from revision'), _('REV')),
5171 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5171 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5172 ] + walkopts + subrepoopts + formatteropts,
5172 ] + walkopts + subrepoopts + formatteropts,
5173 _('[OPTION]... [FILE]...'),
5173 _('[OPTION]... [FILE]...'),
5174 inferrepo=True,
5174 inferrepo=True,
5175 intents={INTENT_READONLY})
5175 intents={INTENT_READONLY})
5176 def status(ui, repo, *pats, **opts):
5176 def status(ui, repo, *pats, **opts):
5177 """show changed files in the working directory
5177 """show changed files in the working directory
5178
5178
5179 Show status of files in the repository. If names are given, only
5179 Show status of files in the repository. If names are given, only
5180 files that match are shown. Files that are clean or ignored or
5180 files that match are shown. Files that are clean or ignored or
5181 the source of a copy/move operation, are not listed unless
5181 the source of a copy/move operation, are not listed unless
5182 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5182 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5183 Unless options described with "show only ..." are given, the
5183 Unless options described with "show only ..." are given, the
5184 options -mardu are used.
5184 options -mardu are used.
5185
5185
5186 Option -q/--quiet hides untracked (unknown and ignored) files
5186 Option -q/--quiet hides untracked (unknown and ignored) files
5187 unless explicitly requested with -u/--unknown or -i/--ignored.
5187 unless explicitly requested with -u/--unknown or -i/--ignored.
5188
5188
5189 .. note::
5189 .. note::
5190
5190
5191 :hg:`status` may appear to disagree with diff if permissions have
5191 :hg:`status` may appear to disagree with diff if permissions have
5192 changed or a merge has occurred. The standard diff format does
5192 changed or a merge has occurred. The standard diff format does
5193 not report permission changes and diff only reports changes
5193 not report permission changes and diff only reports changes
5194 relative to one merge parent.
5194 relative to one merge parent.
5195
5195
5196 If one revision is given, it is used as the base revision.
5196 If one revision is given, it is used as the base revision.
5197 If two revisions are given, the differences between them are
5197 If two revisions are given, the differences between them are
5198 shown. The --change option can also be used as a shortcut to list
5198 shown. The --change option can also be used as a shortcut to list
5199 the changed files of a revision from its first parent.
5199 the changed files of a revision from its first parent.
5200
5200
5201 The codes used to show the status of files are::
5201 The codes used to show the status of files are::
5202
5202
5203 M = modified
5203 M = modified
5204 A = added
5204 A = added
5205 R = removed
5205 R = removed
5206 C = clean
5206 C = clean
5207 ! = missing (deleted by non-hg command, but still tracked)
5207 ! = missing (deleted by non-hg command, but still tracked)
5208 ? = not tracked
5208 ? = not tracked
5209 I = ignored
5209 I = ignored
5210 = origin of the previous file (with --copies)
5210 = origin of the previous file (with --copies)
5211
5211
5212 .. container:: verbose
5212 .. container:: verbose
5213
5213
5214 The -t/--terse option abbreviates the output by showing only the directory
5214 The -t/--terse option abbreviates the output by showing only the directory
5215 name if all the files in it share the same status. The option takes an
5215 name if all the files in it share the same status. The option takes an
5216 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5216 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5217 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5217 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5218 for 'ignored' and 'c' for clean.
5218 for 'ignored' and 'c' for clean.
5219
5219
5220 It abbreviates only those statuses which are passed. Note that clean and
5220 It abbreviates only those statuses which are passed. Note that clean and
5221 ignored files are not displayed with '--terse ic' unless the -c/--clean
5221 ignored files are not displayed with '--terse ic' unless the -c/--clean
5222 and -i/--ignored options are also used.
5222 and -i/--ignored options are also used.
5223
5223
5224 The -v/--verbose option shows information when the repository is in an
5224 The -v/--verbose option shows information when the repository is in an
5225 unfinished merge, shelve, rebase state etc. You can have this behavior
5225 unfinished merge, shelve, rebase state etc. You can have this behavior
5226 turned on by default by enabling the ``commands.status.verbose`` option.
5226 turned on by default by enabling the ``commands.status.verbose`` option.
5227
5227
5228 You can skip displaying some of these states by setting
5228 You can skip displaying some of these states by setting
5229 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5229 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5230 'histedit', 'merge', 'rebase', or 'unshelve'.
5230 'histedit', 'merge', 'rebase', or 'unshelve'.
5231
5231
5232 Template:
5232 Template:
5233
5233
5234 The following keywords are supported in addition to the common template
5234 The following keywords are supported in addition to the common template
5235 keywords and functions. See also :hg:`help templates`.
5235 keywords and functions. See also :hg:`help templates`.
5236
5236
5237 :path: String. Repository-absolute path of the file.
5237 :path: String. Repository-absolute path of the file.
5238 :source: String. Repository-absolute path of the file originated from.
5238 :source: String. Repository-absolute path of the file originated from.
5239 Available if ``--copies`` is specified.
5239 Available if ``--copies`` is specified.
5240 :status: String. Character denoting file's status.
5240 :status: String. Character denoting file's status.
5241
5241
5242 Examples:
5242 Examples:
5243
5243
5244 - show changes in the working directory relative to a
5244 - show changes in the working directory relative to a
5245 changeset::
5245 changeset::
5246
5246
5247 hg status --rev 9353
5247 hg status --rev 9353
5248
5248
5249 - show changes in the working directory relative to the
5249 - show changes in the working directory relative to the
5250 current directory (see :hg:`help patterns` for more information)::
5250 current directory (see :hg:`help patterns` for more information)::
5251
5251
5252 hg status re:
5252 hg status re:
5253
5253
5254 - show all changes including copies in an existing changeset::
5254 - show all changes including copies in an existing changeset::
5255
5255
5256 hg status --copies --change 9353
5256 hg status --copies --change 9353
5257
5257
5258 - get a NUL separated list of added files, suitable for xargs::
5258 - get a NUL separated list of added files, suitable for xargs::
5259
5259
5260 hg status -an0
5260 hg status -an0
5261
5261
5262 - show more information about the repository status, abbreviating
5262 - show more information about the repository status, abbreviating
5263 added, removed, modified, deleted, and untracked paths::
5263 added, removed, modified, deleted, and untracked paths::
5264
5264
5265 hg status -v -t mardu
5265 hg status -v -t mardu
5266
5266
5267 Returns 0 on success.
5267 Returns 0 on success.
5268
5268
5269 """
5269 """
5270
5270
5271 opts = pycompat.byteskwargs(opts)
5271 opts = pycompat.byteskwargs(opts)
5272 revs = opts.get('rev')
5272 revs = opts.get('rev')
5273 change = opts.get('change')
5273 change = opts.get('change')
5274 terse = opts.get('terse')
5274 terse = opts.get('terse')
5275 if terse is _NOTTERSE:
5275 if terse is _NOTTERSE:
5276 if revs:
5276 if revs:
5277 terse = ''
5277 terse = ''
5278 else:
5278 else:
5279 terse = ui.config('commands', 'status.terse')
5279 terse = ui.config('commands', 'status.terse')
5280
5280
5281 if revs and change:
5281 if revs and change:
5282 msg = _('cannot specify --rev and --change at the same time')
5282 msg = _('cannot specify --rev and --change at the same time')
5283 raise error.Abort(msg)
5283 raise error.Abort(msg)
5284 elif revs and terse:
5284 elif revs and terse:
5285 msg = _('cannot use --terse with --rev')
5285 msg = _('cannot use --terse with --rev')
5286 raise error.Abort(msg)
5286 raise error.Abort(msg)
5287 elif change:
5287 elif change:
5288 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5288 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5289 ctx2 = scmutil.revsingle(repo, change, None)
5289 ctx2 = scmutil.revsingle(repo, change, None)
5290 ctx1 = ctx2.p1()
5290 ctx1 = ctx2.p1()
5291 else:
5291 else:
5292 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5292 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5293 ctx1, ctx2 = scmutil.revpair(repo, revs)
5293 ctx1, ctx2 = scmutil.revpair(repo, revs)
5294
5294
5295 if pats or ui.configbool('commands', 'status.relative'):
5295 if pats or ui.configbool('commands', 'status.relative'):
5296 cwd = repo.getcwd()
5296 cwd = repo.getcwd()
5297 else:
5297 else:
5298 cwd = ''
5298 cwd = ''
5299
5299
5300 if opts.get('print0'):
5300 if opts.get('print0'):
5301 end = '\0'
5301 end = '\0'
5302 else:
5302 else:
5303 end = '\n'
5303 end = '\n'
5304 copy = {}
5304 copy = {}
5305 states = 'modified added removed deleted unknown ignored clean'.split()
5305 states = 'modified added removed deleted unknown ignored clean'.split()
5306 show = [k for k in states if opts.get(k)]
5306 show = [k for k in states if opts.get(k)]
5307 if opts.get('all'):
5307 if opts.get('all'):
5308 show += ui.quiet and (states[:4] + ['clean']) or states
5308 show += ui.quiet and (states[:4] + ['clean']) or states
5309
5309
5310 if not show:
5310 if not show:
5311 if ui.quiet:
5311 if ui.quiet:
5312 show = states[:4]
5312 show = states[:4]
5313 else:
5313 else:
5314 show = states[:5]
5314 show = states[:5]
5315
5315
5316 m = scmutil.match(ctx2, pats, opts)
5316 m = scmutil.match(ctx2, pats, opts)
5317 if terse:
5317 if terse:
5318 # we need to compute clean and unknown to terse
5318 # we need to compute clean and unknown to terse
5319 stat = repo.status(ctx1.node(), ctx2.node(), m,
5319 stat = repo.status(ctx1.node(), ctx2.node(), m,
5320 'ignored' in show or 'i' in terse,
5320 'ignored' in show or 'i' in terse,
5321 clean=True, unknown=True,
5321 clean=True, unknown=True,
5322 listsubrepos=opts.get('subrepos'))
5322 listsubrepos=opts.get('subrepos'))
5323
5323
5324 stat = cmdutil.tersedir(stat, terse)
5324 stat = cmdutil.tersedir(stat, terse)
5325 else:
5325 else:
5326 stat = repo.status(ctx1.node(), ctx2.node(), m,
5326 stat = repo.status(ctx1.node(), ctx2.node(), m,
5327 'ignored' in show, 'clean' in show,
5327 'ignored' in show, 'clean' in show,
5328 'unknown' in show, opts.get('subrepos'))
5328 'unknown' in show, opts.get('subrepos'))
5329
5329
5330 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5330 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5331
5331
5332 if (opts.get('all') or opts.get('copies')
5332 if (opts.get('all') or opts.get('copies')
5333 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5333 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5334 copy = copies.pathcopies(ctx1, ctx2, m)
5334 copy = copies.pathcopies(ctx1, ctx2, m)
5335
5335
5336 ui.pager('status')
5336 ui.pager('status')
5337 fm = ui.formatter('status', opts)
5337 fm = ui.formatter('status', opts)
5338 fmt = '%s' + end
5338 fmt = '%s' + end
5339 showchar = not opts.get('no_status')
5339 showchar = not opts.get('no_status')
5340
5340
5341 for state, char, files in changestates:
5341 for state, char, files in changestates:
5342 if state in show:
5342 if state in show:
5343 label = 'status.' + state
5343 label = 'status.' + state
5344 for f in files:
5344 for f in files:
5345 fm.startitem()
5345 fm.startitem()
5346 fm.context(ctx=ctx2)
5346 fm.context(ctx=ctx2)
5347 fm.data(path=f)
5347 fm.data(path=f)
5348 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5348 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5349 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5349 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5350 if f in copy:
5350 if f in copy:
5351 fm.data(source=copy[f])
5351 fm.data(source=copy[f])
5352 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5352 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5353 label='status.copied')
5353 label='status.copied')
5354
5354
5355 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5355 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5356 and not ui.plain()):
5356 and not ui.plain()):
5357 cmdutil.morestatus(repo, fm)
5357 cmdutil.morestatus(repo, fm)
5358 fm.end()
5358 fm.end()
5359
5359
5360 @command('^summary|sum',
5360 @command('^summary|sum',
5361 [('', 'remote', None, _('check for push and pull'))],
5361 [('', 'remote', None, _('check for push and pull'))],
5362 '[--remote]',
5362 '[--remote]',
5363 intents={INTENT_READONLY})
5363 intents={INTENT_READONLY})
5364 def summary(ui, repo, **opts):
5364 def summary(ui, repo, **opts):
5365 """summarize working directory state
5365 """summarize working directory state
5366
5366
5367 This generates a brief summary of the working directory state,
5367 This generates a brief summary of the working directory state,
5368 including parents, branch, commit status, phase and available updates.
5368 including parents, branch, commit status, phase and available updates.
5369
5369
5370 With the --remote option, this will check the default paths for
5370 With the --remote option, this will check the default paths for
5371 incoming and outgoing changes. This can be time-consuming.
5371 incoming and outgoing changes. This can be time-consuming.
5372
5372
5373 Returns 0 on success.
5373 Returns 0 on success.
5374 """
5374 """
5375
5375
5376 opts = pycompat.byteskwargs(opts)
5376 opts = pycompat.byteskwargs(opts)
5377 ui.pager('summary')
5377 ui.pager('summary')
5378 ctx = repo[None]
5378 ctx = repo[None]
5379 parents = ctx.parents()
5379 parents = ctx.parents()
5380 pnode = parents[0].node()
5380 pnode = parents[0].node()
5381 marks = []
5381 marks = []
5382
5382
5383 ms = None
5383 ms = None
5384 try:
5384 try:
5385 ms = mergemod.mergestate.read(repo)
5385 ms = mergemod.mergestate.read(repo)
5386 except error.UnsupportedMergeRecords as e:
5386 except error.UnsupportedMergeRecords as e:
5387 s = ' '.join(e.recordtypes)
5387 s = ' '.join(e.recordtypes)
5388 ui.warn(
5388 ui.warn(
5389 _('warning: merge state has unsupported record types: %s\n') % s)
5389 _('warning: merge state has unsupported record types: %s\n') % s)
5390 unresolved = []
5390 unresolved = []
5391 else:
5391 else:
5392 unresolved = list(ms.unresolved())
5392 unresolved = list(ms.unresolved())
5393
5393
5394 for p in parents:
5394 for p in parents:
5395 # label with log.changeset (instead of log.parent) since this
5395 # label with log.changeset (instead of log.parent) since this
5396 # shows a working directory parent *changeset*:
5396 # shows a working directory parent *changeset*:
5397 # i18n: column positioning for "hg summary"
5397 # i18n: column positioning for "hg summary"
5398 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5398 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5399 label=logcmdutil.changesetlabels(p))
5399 label=logcmdutil.changesetlabels(p))
5400 ui.write(' '.join(p.tags()), label='log.tag')
5400 ui.write(' '.join(p.tags()), label='log.tag')
5401 if p.bookmarks():
5401 if p.bookmarks():
5402 marks.extend(p.bookmarks())
5402 marks.extend(p.bookmarks())
5403 if p.rev() == -1:
5403 if p.rev() == -1:
5404 if not len(repo):
5404 if not len(repo):
5405 ui.write(_(' (empty repository)'))
5405 ui.write(_(' (empty repository)'))
5406 else:
5406 else:
5407 ui.write(_(' (no revision checked out)'))
5407 ui.write(_(' (no revision checked out)'))
5408 if p.obsolete():
5408 if p.obsolete():
5409 ui.write(_(' (obsolete)'))
5409 ui.write(_(' (obsolete)'))
5410 if p.isunstable():
5410 if p.isunstable():
5411 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5411 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5412 for instability in p.instabilities())
5412 for instability in p.instabilities())
5413 ui.write(' ('
5413 ui.write(' ('
5414 + ', '.join(instabilities)
5414 + ', '.join(instabilities)
5415 + ')')
5415 + ')')
5416 ui.write('\n')
5416 ui.write('\n')
5417 if p.description():
5417 if p.description():
5418 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5418 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5419 label='log.summary')
5419 label='log.summary')
5420
5420
5421 branch = ctx.branch()
5421 branch = ctx.branch()
5422 bheads = repo.branchheads(branch)
5422 bheads = repo.branchheads(branch)
5423 # i18n: column positioning for "hg summary"
5423 # i18n: column positioning for "hg summary"
5424 m = _('branch: %s\n') % branch
5424 m = _('branch: %s\n') % branch
5425 if branch != 'default':
5425 if branch != 'default':
5426 ui.write(m, label='log.branch')
5426 ui.write(m, label='log.branch')
5427 else:
5427 else:
5428 ui.status(m, label='log.branch')
5428 ui.status(m, label='log.branch')
5429
5429
5430 if marks:
5430 if marks:
5431 active = repo._activebookmark
5431 active = repo._activebookmark
5432 # i18n: column positioning for "hg summary"
5432 # i18n: column positioning for "hg summary"
5433 ui.write(_('bookmarks:'), label='log.bookmark')
5433 ui.write(_('bookmarks:'), label='log.bookmark')
5434 if active is not None:
5434 if active is not None:
5435 if active in marks:
5435 if active in marks:
5436 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5436 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5437 marks.remove(active)
5437 marks.remove(active)
5438 else:
5438 else:
5439 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5439 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5440 for m in marks:
5440 for m in marks:
5441 ui.write(' ' + m, label='log.bookmark')
5441 ui.write(' ' + m, label='log.bookmark')
5442 ui.write('\n', label='log.bookmark')
5442 ui.write('\n', label='log.bookmark')
5443
5443
5444 status = repo.status(unknown=True)
5444 status = repo.status(unknown=True)
5445
5445
5446 c = repo.dirstate.copies()
5446 c = repo.dirstate.copies()
5447 copied, renamed = [], []
5447 copied, renamed = [], []
5448 for d, s in c.iteritems():
5448 for d, s in c.iteritems():
5449 if s in status.removed:
5449 if s in status.removed:
5450 status.removed.remove(s)
5450 status.removed.remove(s)
5451 renamed.append(d)
5451 renamed.append(d)
5452 else:
5452 else:
5453 copied.append(d)
5453 copied.append(d)
5454 if d in status.added:
5454 if d in status.added:
5455 status.added.remove(d)
5455 status.added.remove(d)
5456
5456
5457 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5457 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5458
5458
5459 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5459 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5460 (ui.label(_('%d added'), 'status.added'), status.added),
5460 (ui.label(_('%d added'), 'status.added'), status.added),
5461 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5461 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5462 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5462 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5463 (ui.label(_('%d copied'), 'status.copied'), copied),
5463 (ui.label(_('%d copied'), 'status.copied'), copied),
5464 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5464 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5465 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5465 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5466 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5466 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5467 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5467 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5468 t = []
5468 t = []
5469 for l, s in labels:
5469 for l, s in labels:
5470 if s:
5470 if s:
5471 t.append(l % len(s))
5471 t.append(l % len(s))
5472
5472
5473 t = ', '.join(t)
5473 t = ', '.join(t)
5474 cleanworkdir = False
5474 cleanworkdir = False
5475
5475
5476 if repo.vfs.exists('graftstate'):
5476 if repo.vfs.exists('graftstate'):
5477 t += _(' (graft in progress)')
5477 t += _(' (graft in progress)')
5478 if repo.vfs.exists('updatestate'):
5478 if repo.vfs.exists('updatestate'):
5479 t += _(' (interrupted update)')
5479 t += _(' (interrupted update)')
5480 elif len(parents) > 1:
5480 elif len(parents) > 1:
5481 t += _(' (merge)')
5481 t += _(' (merge)')
5482 elif branch != parents[0].branch():
5482 elif branch != parents[0].branch():
5483 t += _(' (new branch)')
5483 t += _(' (new branch)')
5484 elif (parents[0].closesbranch() and
5484 elif (parents[0].closesbranch() and
5485 pnode in repo.branchheads(branch, closed=True)):
5485 pnode in repo.branchheads(branch, closed=True)):
5486 t += _(' (head closed)')
5486 t += _(' (head closed)')
5487 elif not (status.modified or status.added or status.removed or renamed or
5487 elif not (status.modified or status.added or status.removed or renamed or
5488 copied or subs):
5488 copied or subs):
5489 t += _(' (clean)')
5489 t += _(' (clean)')
5490 cleanworkdir = True
5490 cleanworkdir = True
5491 elif pnode not in bheads:
5491 elif pnode not in bheads:
5492 t += _(' (new branch head)')
5492 t += _(' (new branch head)')
5493
5493
5494 if parents:
5494 if parents:
5495 pendingphase = max(p.phase() for p in parents)
5495 pendingphase = max(p.phase() for p in parents)
5496 else:
5496 else:
5497 pendingphase = phases.public
5497 pendingphase = phases.public
5498
5498
5499 if pendingphase > phases.newcommitphase(ui):
5499 if pendingphase > phases.newcommitphase(ui):
5500 t += ' (%s)' % phases.phasenames[pendingphase]
5500 t += ' (%s)' % phases.phasenames[pendingphase]
5501
5501
5502 if cleanworkdir:
5502 if cleanworkdir:
5503 # i18n: column positioning for "hg summary"
5503 # i18n: column positioning for "hg summary"
5504 ui.status(_('commit: %s\n') % t.strip())
5504 ui.status(_('commit: %s\n') % t.strip())
5505 else:
5505 else:
5506 # i18n: column positioning for "hg summary"
5506 # i18n: column positioning for "hg summary"
5507 ui.write(_('commit: %s\n') % t.strip())
5507 ui.write(_('commit: %s\n') % t.strip())
5508
5508
5509 # all ancestors of branch heads - all ancestors of parent = new csets
5509 # all ancestors of branch heads - all ancestors of parent = new csets
5510 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5510 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5511 bheads))
5511 bheads))
5512
5512
5513 if new == 0:
5513 if new == 0:
5514 # i18n: column positioning for "hg summary"
5514 # i18n: column positioning for "hg summary"
5515 ui.status(_('update: (current)\n'))
5515 ui.status(_('update: (current)\n'))
5516 elif pnode not in bheads:
5516 elif pnode not in bheads:
5517 # i18n: column positioning for "hg summary"
5517 # i18n: column positioning for "hg summary"
5518 ui.write(_('update: %d new changesets (update)\n') % new)
5518 ui.write(_('update: %d new changesets (update)\n') % new)
5519 else:
5519 else:
5520 # i18n: column positioning for "hg summary"
5520 # i18n: column positioning for "hg summary"
5521 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5521 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5522 (new, len(bheads)))
5522 (new, len(bheads)))
5523
5523
5524 t = []
5524 t = []
5525 draft = len(repo.revs('draft()'))
5525 draft = len(repo.revs('draft()'))
5526 if draft:
5526 if draft:
5527 t.append(_('%d draft') % draft)
5527 t.append(_('%d draft') % draft)
5528 secret = len(repo.revs('secret()'))
5528 secret = len(repo.revs('secret()'))
5529 if secret:
5529 if secret:
5530 t.append(_('%d secret') % secret)
5530 t.append(_('%d secret') % secret)
5531
5531
5532 if draft or secret:
5532 if draft or secret:
5533 ui.status(_('phases: %s\n') % ', '.join(t))
5533 ui.status(_('phases: %s\n') % ', '.join(t))
5534
5534
5535 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5535 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5536 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5536 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5537 numtrouble = len(repo.revs(trouble + "()"))
5537 numtrouble = len(repo.revs(trouble + "()"))
5538 # We write all the possibilities to ease translation
5538 # We write all the possibilities to ease translation
5539 troublemsg = {
5539 troublemsg = {
5540 "orphan": _("orphan: %d changesets"),
5540 "orphan": _("orphan: %d changesets"),
5541 "contentdivergent": _("content-divergent: %d changesets"),
5541 "contentdivergent": _("content-divergent: %d changesets"),
5542 "phasedivergent": _("phase-divergent: %d changesets"),
5542 "phasedivergent": _("phase-divergent: %d changesets"),
5543 }
5543 }
5544 if numtrouble > 0:
5544 if numtrouble > 0:
5545 ui.status(troublemsg[trouble] % numtrouble + "\n")
5545 ui.status(troublemsg[trouble] % numtrouble + "\n")
5546
5546
5547 cmdutil.summaryhooks(ui, repo)
5547 cmdutil.summaryhooks(ui, repo)
5548
5548
5549 if opts.get('remote'):
5549 if opts.get('remote'):
5550 needsincoming, needsoutgoing = True, True
5550 needsincoming, needsoutgoing = True, True
5551 else:
5551 else:
5552 needsincoming, needsoutgoing = False, False
5552 needsincoming, needsoutgoing = False, False
5553 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5553 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5554 if i:
5554 if i:
5555 needsincoming = True
5555 needsincoming = True
5556 if o:
5556 if o:
5557 needsoutgoing = True
5557 needsoutgoing = True
5558 if not needsincoming and not needsoutgoing:
5558 if not needsincoming and not needsoutgoing:
5559 return
5559 return
5560
5560
5561 def getincoming():
5561 def getincoming():
5562 source, branches = hg.parseurl(ui.expandpath('default'))
5562 source, branches = hg.parseurl(ui.expandpath('default'))
5563 sbranch = branches[0]
5563 sbranch = branches[0]
5564 try:
5564 try:
5565 other = hg.peer(repo, {}, source)
5565 other = hg.peer(repo, {}, source)
5566 except error.RepoError:
5566 except error.RepoError:
5567 if opts.get('remote'):
5567 if opts.get('remote'):
5568 raise
5568 raise
5569 return source, sbranch, None, None, None
5569 return source, sbranch, None, None, None
5570 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5570 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5571 if revs:
5571 if revs:
5572 revs = [other.lookup(rev) for rev in revs]
5572 revs = [other.lookup(rev) for rev in revs]
5573 ui.debug('comparing with %s\n' % util.hidepassword(source))
5573 ui.debug('comparing with %s\n' % util.hidepassword(source))
5574 repo.ui.pushbuffer()
5574 repo.ui.pushbuffer()
5575 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5575 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5576 repo.ui.popbuffer()
5576 repo.ui.popbuffer()
5577 return source, sbranch, other, commoninc, commoninc[1]
5577 return source, sbranch, other, commoninc, commoninc[1]
5578
5578
5579 if needsincoming:
5579 if needsincoming:
5580 source, sbranch, sother, commoninc, incoming = getincoming()
5580 source, sbranch, sother, commoninc, incoming = getincoming()
5581 else:
5581 else:
5582 source = sbranch = sother = commoninc = incoming = None
5582 source = sbranch = sother = commoninc = incoming = None
5583
5583
5584 def getoutgoing():
5584 def getoutgoing():
5585 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5585 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5586 dbranch = branches[0]
5586 dbranch = branches[0]
5587 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5587 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5588 if source != dest:
5588 if source != dest:
5589 try:
5589 try:
5590 dother = hg.peer(repo, {}, dest)
5590 dother = hg.peer(repo, {}, dest)
5591 except error.RepoError:
5591 except error.RepoError:
5592 if opts.get('remote'):
5592 if opts.get('remote'):
5593 raise
5593 raise
5594 return dest, dbranch, None, None
5594 return dest, dbranch, None, None
5595 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5595 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5596 elif sother is None:
5596 elif sother is None:
5597 # there is no explicit destination peer, but source one is invalid
5597 # there is no explicit destination peer, but source one is invalid
5598 return dest, dbranch, None, None
5598 return dest, dbranch, None, None
5599 else:
5599 else:
5600 dother = sother
5600 dother = sother
5601 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5601 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5602 common = None
5602 common = None
5603 else:
5603 else:
5604 common = commoninc
5604 common = commoninc
5605 if revs:
5605 if revs:
5606 revs = [repo.lookup(rev) for rev in revs]
5606 revs = [repo.lookup(rev) for rev in revs]
5607 repo.ui.pushbuffer()
5607 repo.ui.pushbuffer()
5608 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5608 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5609 commoninc=common)
5609 commoninc=common)
5610 repo.ui.popbuffer()
5610 repo.ui.popbuffer()
5611 return dest, dbranch, dother, outgoing
5611 return dest, dbranch, dother, outgoing
5612
5612
5613 if needsoutgoing:
5613 if needsoutgoing:
5614 dest, dbranch, dother, outgoing = getoutgoing()
5614 dest, dbranch, dother, outgoing = getoutgoing()
5615 else:
5615 else:
5616 dest = dbranch = dother = outgoing = None
5616 dest = dbranch = dother = outgoing = None
5617
5617
5618 if opts.get('remote'):
5618 if opts.get('remote'):
5619 t = []
5619 t = []
5620 if incoming:
5620 if incoming:
5621 t.append(_('1 or more incoming'))
5621 t.append(_('1 or more incoming'))
5622 o = outgoing.missing
5622 o = outgoing.missing
5623 if o:
5623 if o:
5624 t.append(_('%d outgoing') % len(o))
5624 t.append(_('%d outgoing') % len(o))
5625 other = dother or sother
5625 other = dother or sother
5626 if 'bookmarks' in other.listkeys('namespaces'):
5626 if 'bookmarks' in other.listkeys('namespaces'):
5627 counts = bookmarks.summary(repo, other)
5627 counts = bookmarks.summary(repo, other)
5628 if counts[0] > 0:
5628 if counts[0] > 0:
5629 t.append(_('%d incoming bookmarks') % counts[0])
5629 t.append(_('%d incoming bookmarks') % counts[0])
5630 if counts[1] > 0:
5630 if counts[1] > 0:
5631 t.append(_('%d outgoing bookmarks') % counts[1])
5631 t.append(_('%d outgoing bookmarks') % counts[1])
5632
5632
5633 if t:
5633 if t:
5634 # i18n: column positioning for "hg summary"
5634 # i18n: column positioning for "hg summary"
5635 ui.write(_('remote: %s\n') % (', '.join(t)))
5635 ui.write(_('remote: %s\n') % (', '.join(t)))
5636 else:
5636 else:
5637 # i18n: column positioning for "hg summary"
5637 # i18n: column positioning for "hg summary"
5638 ui.status(_('remote: (synced)\n'))
5638 ui.status(_('remote: (synced)\n'))
5639
5639
5640 cmdutil.summaryremotehooks(ui, repo, opts,
5640 cmdutil.summaryremotehooks(ui, repo, opts,
5641 ((source, sbranch, sother, commoninc),
5641 ((source, sbranch, sother, commoninc),
5642 (dest, dbranch, dother, outgoing)))
5642 (dest, dbranch, dother, outgoing)))
5643
5643
5644 @command('tag',
5644 @command('tag',
5645 [('f', 'force', None, _('force tag')),
5645 [('f', 'force', None, _('force tag')),
5646 ('l', 'local', None, _('make the tag local')),
5646 ('l', 'local', None, _('make the tag local')),
5647 ('r', 'rev', '', _('revision to tag'), _('REV')),
5647 ('r', 'rev', '', _('revision to tag'), _('REV')),
5648 ('', 'remove', None, _('remove a tag')),
5648 ('', 'remove', None, _('remove a tag')),
5649 # -l/--local is already there, commitopts cannot be used
5649 # -l/--local is already there, commitopts cannot be used
5650 ('e', 'edit', None, _('invoke editor on commit messages')),
5650 ('e', 'edit', None, _('invoke editor on commit messages')),
5651 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5651 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5652 ] + commitopts2,
5652 ] + commitopts2,
5653 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5653 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5654 def tag(ui, repo, name1, *names, **opts):
5654 def tag(ui, repo, name1, *names, **opts):
5655 """add one or more tags for the current or given revision
5655 """add one or more tags for the current or given revision
5656
5656
5657 Name a particular revision using <name>.
5657 Name a particular revision using <name>.
5658
5658
5659 Tags are used to name particular revisions of the repository and are
5659 Tags are used to name particular revisions of the repository and are
5660 very useful to compare different revisions, to go back to significant
5660 very useful to compare different revisions, to go back to significant
5661 earlier versions or to mark branch points as releases, etc. Changing
5661 earlier versions or to mark branch points as releases, etc. Changing
5662 an existing tag is normally disallowed; use -f/--force to override.
5662 an existing tag is normally disallowed; use -f/--force to override.
5663
5663
5664 If no revision is given, the parent of the working directory is
5664 If no revision is given, the parent of the working directory is
5665 used.
5665 used.
5666
5666
5667 To facilitate version control, distribution, and merging of tags,
5667 To facilitate version control, distribution, and merging of tags,
5668 they are stored as a file named ".hgtags" which is managed similarly
5668 they are stored as a file named ".hgtags" which is managed similarly
5669 to other project files and can be hand-edited if necessary. This
5669 to other project files and can be hand-edited if necessary. This
5670 also means that tagging creates a new commit. The file
5670 also means that tagging creates a new commit. The file
5671 ".hg/localtags" is used for local tags (not shared among
5671 ".hg/localtags" is used for local tags (not shared among
5672 repositories).
5672 repositories).
5673
5673
5674 Tag commits are usually made at the head of a branch. If the parent
5674 Tag commits are usually made at the head of a branch. If the parent
5675 of the working directory is not a branch head, :hg:`tag` aborts; use
5675 of the working directory is not a branch head, :hg:`tag` aborts; use
5676 -f/--force to force the tag commit to be based on a non-head
5676 -f/--force to force the tag commit to be based on a non-head
5677 changeset.
5677 changeset.
5678
5678
5679 See :hg:`help dates` for a list of formats valid for -d/--date.
5679 See :hg:`help dates` for a list of formats valid for -d/--date.
5680
5680
5681 Since tag names have priority over branch names during revision
5681 Since tag names have priority over branch names during revision
5682 lookup, using an existing branch name as a tag name is discouraged.
5682 lookup, using an existing branch name as a tag name is discouraged.
5683
5683
5684 Returns 0 on success.
5684 Returns 0 on success.
5685 """
5685 """
5686 opts = pycompat.byteskwargs(opts)
5686 opts = pycompat.byteskwargs(opts)
5687 with repo.wlock(), repo.lock():
5687 with repo.wlock(), repo.lock():
5688 rev_ = "."
5688 rev_ = "."
5689 names = [t.strip() for t in (name1,) + names]
5689 names = [t.strip() for t in (name1,) + names]
5690 if len(names) != len(set(names)):
5690 if len(names) != len(set(names)):
5691 raise error.Abort(_('tag names must be unique'))
5691 raise error.Abort(_('tag names must be unique'))
5692 for n in names:
5692 for n in names:
5693 scmutil.checknewlabel(repo, n, 'tag')
5693 scmutil.checknewlabel(repo, n, 'tag')
5694 if not n:
5694 if not n:
5695 raise error.Abort(_('tag names cannot consist entirely of '
5695 raise error.Abort(_('tag names cannot consist entirely of '
5696 'whitespace'))
5696 'whitespace'))
5697 if opts.get('rev') and opts.get('remove'):
5697 if opts.get('rev') and opts.get('remove'):
5698 raise error.Abort(_("--rev and --remove are incompatible"))
5698 raise error.Abort(_("--rev and --remove are incompatible"))
5699 if opts.get('rev'):
5699 if opts.get('rev'):
5700 rev_ = opts['rev']
5700 rev_ = opts['rev']
5701 message = opts.get('message')
5701 message = opts.get('message')
5702 if opts.get('remove'):
5702 if opts.get('remove'):
5703 if opts.get('local'):
5703 if opts.get('local'):
5704 expectedtype = 'local'
5704 expectedtype = 'local'
5705 else:
5705 else:
5706 expectedtype = 'global'
5706 expectedtype = 'global'
5707
5707
5708 for n in names:
5708 for n in names:
5709 if not repo.tagtype(n):
5709 if not repo.tagtype(n):
5710 raise error.Abort(_("tag '%s' does not exist") % n)
5710 raise error.Abort(_("tag '%s' does not exist") % n)
5711 if repo.tagtype(n) != expectedtype:
5711 if repo.tagtype(n) != expectedtype:
5712 if expectedtype == 'global':
5712 if expectedtype == 'global':
5713 raise error.Abort(_("tag '%s' is not a global tag") % n)
5713 raise error.Abort(_("tag '%s' is not a global tag") % n)
5714 else:
5714 else:
5715 raise error.Abort(_("tag '%s' is not a local tag") % n)
5715 raise error.Abort(_("tag '%s' is not a local tag") % n)
5716 rev_ = 'null'
5716 rev_ = 'null'
5717 if not message:
5717 if not message:
5718 # we don't translate commit messages
5718 # we don't translate commit messages
5719 message = 'Removed tag %s' % ', '.join(names)
5719 message = 'Removed tag %s' % ', '.join(names)
5720 elif not opts.get('force'):
5720 elif not opts.get('force'):
5721 for n in names:
5721 for n in names:
5722 if n in repo.tags():
5722 if n in repo.tags():
5723 raise error.Abort(_("tag '%s' already exists "
5723 raise error.Abort(_("tag '%s' already exists "
5724 "(use -f to force)") % n)
5724 "(use -f to force)") % n)
5725 if not opts.get('local'):
5725 if not opts.get('local'):
5726 p1, p2 = repo.dirstate.parents()
5726 p1, p2 = repo.dirstate.parents()
5727 if p2 != nullid:
5727 if p2 != nullid:
5728 raise error.Abort(_('uncommitted merge'))
5728 raise error.Abort(_('uncommitted merge'))
5729 bheads = repo.branchheads()
5729 bheads = repo.branchheads()
5730 if not opts.get('force') and bheads and p1 not in bheads:
5730 if not opts.get('force') and bheads and p1 not in bheads:
5731 raise error.Abort(_('working directory is not at a branch head '
5731 raise error.Abort(_('working directory is not at a branch head '
5732 '(use -f to force)'))
5732 '(use -f to force)'))
5733 node = scmutil.revsingle(repo, rev_).node()
5733 node = scmutil.revsingle(repo, rev_).node()
5734
5734
5735 if not message:
5735 if not message:
5736 # we don't translate commit messages
5736 # we don't translate commit messages
5737 message = ('Added tag %s for changeset %s' %
5737 message = ('Added tag %s for changeset %s' %
5738 (', '.join(names), short(node)))
5738 (', '.join(names), short(node)))
5739
5739
5740 date = opts.get('date')
5740 date = opts.get('date')
5741 if date:
5741 if date:
5742 date = dateutil.parsedate(date)
5742 date = dateutil.parsedate(date)
5743
5743
5744 if opts.get('remove'):
5744 if opts.get('remove'):
5745 editform = 'tag.remove'
5745 editform = 'tag.remove'
5746 else:
5746 else:
5747 editform = 'tag.add'
5747 editform = 'tag.add'
5748 editor = cmdutil.getcommiteditor(editform=editform,
5748 editor = cmdutil.getcommiteditor(editform=editform,
5749 **pycompat.strkwargs(opts))
5749 **pycompat.strkwargs(opts))
5750
5750
5751 # don't allow tagging the null rev
5751 # don't allow tagging the null rev
5752 if (not opts.get('remove') and
5752 if (not opts.get('remove') and
5753 scmutil.revsingle(repo, rev_).rev() == nullrev):
5753 scmutil.revsingle(repo, rev_).rev() == nullrev):
5754 raise error.Abort(_("cannot tag null revision"))
5754 raise error.Abort(_("cannot tag null revision"))
5755
5755
5756 tagsmod.tag(repo, names, node, message, opts.get('local'),
5756 tagsmod.tag(repo, names, node, message, opts.get('local'),
5757 opts.get('user'), date, editor=editor)
5757 opts.get('user'), date, editor=editor)
5758
5758
5759 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5759 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5760 def tags(ui, repo, **opts):
5760 def tags(ui, repo, **opts):
5761 """list repository tags
5761 """list repository tags
5762
5762
5763 This lists both regular and local tags. When the -v/--verbose
5763 This lists both regular and local tags. When the -v/--verbose
5764 switch is used, a third column "local" is printed for local tags.
5764 switch is used, a third column "local" is printed for local tags.
5765 When the -q/--quiet switch is used, only the tag name is printed.
5765 When the -q/--quiet switch is used, only the tag name is printed.
5766
5766
5767 .. container:: verbose
5767 .. container:: verbose
5768
5768
5769 Template:
5769 Template:
5770
5770
5771 The following keywords are supported in addition to the common template
5771 The following keywords are supported in addition to the common template
5772 keywords and functions such as ``{tag}``. See also
5772 keywords and functions such as ``{tag}``. See also
5773 :hg:`help templates`.
5773 :hg:`help templates`.
5774
5774
5775 :type: String. ``local`` for local tags.
5775 :type: String. ``local`` for local tags.
5776
5776
5777 Returns 0 on success.
5777 Returns 0 on success.
5778 """
5778 """
5779
5779
5780 opts = pycompat.byteskwargs(opts)
5780 opts = pycompat.byteskwargs(opts)
5781 ui.pager('tags')
5781 ui.pager('tags')
5782 fm = ui.formatter('tags', opts)
5782 fm = ui.formatter('tags', opts)
5783 hexfunc = fm.hexfunc
5783 hexfunc = fm.hexfunc
5784 tagtype = ""
5784 tagtype = ""
5785
5785
5786 for t, n in reversed(repo.tagslist()):
5786 for t, n in reversed(repo.tagslist()):
5787 hn = hexfunc(n)
5787 hn = hexfunc(n)
5788 label = 'tags.normal'
5788 label = 'tags.normal'
5789 tagtype = ''
5789 tagtype = ''
5790 if repo.tagtype(t) == 'local':
5790 if repo.tagtype(t) == 'local':
5791 label = 'tags.local'
5791 label = 'tags.local'
5792 tagtype = 'local'
5792 tagtype = 'local'
5793
5793
5794 fm.startitem()
5794 fm.startitem()
5795 fm.context(repo=repo)
5795 fm.context(repo=repo)
5796 fm.write('tag', '%s', t, label=label)
5796 fm.write('tag', '%s', t, label=label)
5797 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5797 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5798 fm.condwrite(not ui.quiet, 'rev node', fmt,
5798 fm.condwrite(not ui.quiet, 'rev node', fmt,
5799 repo.changelog.rev(n), hn, label=label)
5799 repo.changelog.rev(n), hn, label=label)
5800 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5800 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5801 tagtype, label=label)
5801 tagtype, label=label)
5802 fm.plain('\n')
5802 fm.plain('\n')
5803 fm.end()
5803 fm.end()
5804
5804
5805 @command('tip',
5805 @command('tip',
5806 [('p', 'patch', None, _('show patch')),
5806 [('p', 'patch', None, _('show patch')),
5807 ('g', 'git', None, _('use git extended diff format')),
5807 ('g', 'git', None, _('use git extended diff format')),
5808 ] + templateopts,
5808 ] + templateopts,
5809 _('[-p] [-g]'))
5809 _('[-p] [-g]'))
5810 def tip(ui, repo, **opts):
5810 def tip(ui, repo, **opts):
5811 """show the tip revision (DEPRECATED)
5811 """show the tip revision (DEPRECATED)
5812
5812
5813 The tip revision (usually just called the tip) is the changeset
5813 The tip revision (usually just called the tip) is the changeset
5814 most recently added to the repository (and therefore the most
5814 most recently added to the repository (and therefore the most
5815 recently changed head).
5815 recently changed head).
5816
5816
5817 If you have just made a commit, that commit will be the tip. If
5817 If you have just made a commit, that commit will be the tip. If
5818 you have just pulled changes from another repository, the tip of
5818 you have just pulled changes from another repository, the tip of
5819 that repository becomes the current tip. The "tip" tag is special
5819 that repository becomes the current tip. The "tip" tag is special
5820 and cannot be renamed or assigned to a different changeset.
5820 and cannot be renamed or assigned to a different changeset.
5821
5821
5822 This command is deprecated, please use :hg:`heads` instead.
5822 This command is deprecated, please use :hg:`heads` instead.
5823
5823
5824 Returns 0 on success.
5824 Returns 0 on success.
5825 """
5825 """
5826 opts = pycompat.byteskwargs(opts)
5826 opts = pycompat.byteskwargs(opts)
5827 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5827 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5828 displayer.show(repo['tip'])
5828 displayer.show(repo['tip'])
5829 displayer.close()
5829 displayer.close()
5830
5830
5831 @command('unbundle',
5831 @command('unbundle',
5832 [('u', 'update', None,
5832 [('u', 'update', None,
5833 _('update to new branch head if changesets were unbundled'))],
5833 _('update to new branch head if changesets were unbundled'))],
5834 _('[-u] FILE...'))
5834 _('[-u] FILE...'))
5835 def unbundle(ui, repo, fname1, *fnames, **opts):
5835 def unbundle(ui, repo, fname1, *fnames, **opts):
5836 """apply one or more bundle files
5836 """apply one or more bundle files
5837
5837
5838 Apply one or more bundle files generated by :hg:`bundle`.
5838 Apply one or more bundle files generated by :hg:`bundle`.
5839
5839
5840 Returns 0 on success, 1 if an update has unresolved files.
5840 Returns 0 on success, 1 if an update has unresolved files.
5841 """
5841 """
5842 fnames = (fname1,) + fnames
5842 fnames = (fname1,) + fnames
5843
5843
5844 with repo.lock():
5844 with repo.lock():
5845 for fname in fnames:
5845 for fname in fnames:
5846 f = hg.openpath(ui, fname)
5846 f = hg.openpath(ui, fname)
5847 gen = exchange.readbundle(ui, f, fname)
5847 gen = exchange.readbundle(ui, f, fname)
5848 if isinstance(gen, streamclone.streamcloneapplier):
5848 if isinstance(gen, streamclone.streamcloneapplier):
5849 raise error.Abort(
5849 raise error.Abort(
5850 _('packed bundles cannot be applied with '
5850 _('packed bundles cannot be applied with '
5851 '"hg unbundle"'),
5851 '"hg unbundle"'),
5852 hint=_('use "hg debugapplystreamclonebundle"'))
5852 hint=_('use "hg debugapplystreamclonebundle"'))
5853 url = 'bundle:' + fname
5853 url = 'bundle:' + fname
5854 try:
5854 try:
5855 txnname = 'unbundle'
5855 txnname = 'unbundle'
5856 if not isinstance(gen, bundle2.unbundle20):
5856 if not isinstance(gen, bundle2.unbundle20):
5857 txnname = 'unbundle\n%s' % util.hidepassword(url)
5857 txnname = 'unbundle\n%s' % util.hidepassword(url)
5858 with repo.transaction(txnname) as tr:
5858 with repo.transaction(txnname) as tr:
5859 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5859 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5860 url=url)
5860 url=url)
5861 except error.BundleUnknownFeatureError as exc:
5861 except error.BundleUnknownFeatureError as exc:
5862 raise error.Abort(
5862 raise error.Abort(
5863 _('%s: unknown bundle feature, %s') % (fname, exc),
5863 _('%s: unknown bundle feature, %s') % (fname, exc),
5864 hint=_("see https://mercurial-scm.org/"
5864 hint=_("see https://mercurial-scm.org/"
5865 "wiki/BundleFeature for more "
5865 "wiki/BundleFeature for more "
5866 "information"))
5866 "information"))
5867 modheads = bundle2.combinechangegroupresults(op)
5867 modheads = bundle2.combinechangegroupresults(op)
5868
5868
5869 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5869 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5870
5870
5871 @command('^update|up|checkout|co',
5871 @command('^update|up|checkout|co',
5872 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5872 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5873 ('c', 'check', None, _('require clean working directory')),
5873 ('c', 'check', None, _('require clean working directory')),
5874 ('m', 'merge', None, _('merge uncommitted changes')),
5874 ('m', 'merge', None, _('merge uncommitted changes')),
5875 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5875 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5876 ('r', 'rev', '', _('revision'), _('REV'))
5876 ('r', 'rev', '', _('revision'), _('REV'))
5877 ] + mergetoolopts,
5877 ] + mergetoolopts,
5878 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5878 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5879 def update(ui, repo, node=None, **opts):
5879 def update(ui, repo, node=None, **opts):
5880 """update working directory (or switch revisions)
5880 """update working directory (or switch revisions)
5881
5881
5882 Update the repository's working directory to the specified
5882 Update the repository's working directory to the specified
5883 changeset. If no changeset is specified, update to the tip of the
5883 changeset. If no changeset is specified, update to the tip of the
5884 current named branch and move the active bookmark (see :hg:`help
5884 current named branch and move the active bookmark (see :hg:`help
5885 bookmarks`).
5885 bookmarks`).
5886
5886
5887 Update sets the working directory's parent revision to the specified
5887 Update sets the working directory's parent revision to the specified
5888 changeset (see :hg:`help parents`).
5888 changeset (see :hg:`help parents`).
5889
5889
5890 If the changeset is not a descendant or ancestor of the working
5890 If the changeset is not a descendant or ancestor of the working
5891 directory's parent and there are uncommitted changes, the update is
5891 directory's parent and there are uncommitted changes, the update is
5892 aborted. With the -c/--check option, the working directory is checked
5892 aborted. With the -c/--check option, the working directory is checked
5893 for uncommitted changes; if none are found, the working directory is
5893 for uncommitted changes; if none are found, the working directory is
5894 updated to the specified changeset.
5894 updated to the specified changeset.
5895
5895
5896 .. container:: verbose
5896 .. container:: verbose
5897
5897
5898 The -C/--clean, -c/--check, and -m/--merge options control what
5898 The -C/--clean, -c/--check, and -m/--merge options control what
5899 happens if the working directory contains uncommitted changes.
5899 happens if the working directory contains uncommitted changes.
5900 At most of one of them can be specified.
5900 At most of one of them can be specified.
5901
5901
5902 1. If no option is specified, and if
5902 1. If no option is specified, and if
5903 the requested changeset is an ancestor or descendant of
5903 the requested changeset is an ancestor or descendant of
5904 the working directory's parent, the uncommitted changes
5904 the working directory's parent, the uncommitted changes
5905 are merged into the requested changeset and the merged
5905 are merged into the requested changeset and the merged
5906 result is left uncommitted. If the requested changeset is
5906 result is left uncommitted. If the requested changeset is
5907 not an ancestor or descendant (that is, it is on another
5907 not an ancestor or descendant (that is, it is on another
5908 branch), the update is aborted and the uncommitted changes
5908 branch), the update is aborted and the uncommitted changes
5909 are preserved.
5909 are preserved.
5910
5910
5911 2. With the -m/--merge option, the update is allowed even if the
5911 2. With the -m/--merge option, the update is allowed even if the
5912 requested changeset is not an ancestor or descendant of
5912 requested changeset is not an ancestor or descendant of
5913 the working directory's parent.
5913 the working directory's parent.
5914
5914
5915 3. With the -c/--check option, the update is aborted and the
5915 3. With the -c/--check option, the update is aborted and the
5916 uncommitted changes are preserved.
5916 uncommitted changes are preserved.
5917
5917
5918 4. With the -C/--clean option, uncommitted changes are discarded and
5918 4. With the -C/--clean option, uncommitted changes are discarded and
5919 the working directory is updated to the requested changeset.
5919 the working directory is updated to the requested changeset.
5920
5920
5921 To cancel an uncommitted merge (and lose your changes), use
5921 To cancel an uncommitted merge (and lose your changes), use
5922 :hg:`merge --abort`.
5922 :hg:`merge --abort`.
5923
5923
5924 Use null as the changeset to remove the working directory (like
5924 Use null as the changeset to remove the working directory (like
5925 :hg:`clone -U`).
5925 :hg:`clone -U`).
5926
5926
5927 If you want to revert just one file to an older revision, use
5927 If you want to revert just one file to an older revision, use
5928 :hg:`revert [-r REV] NAME`.
5928 :hg:`revert [-r REV] NAME`.
5929
5929
5930 See :hg:`help dates` for a list of formats valid for -d/--date.
5930 See :hg:`help dates` for a list of formats valid for -d/--date.
5931
5931
5932 Returns 0 on success, 1 if there are unresolved files.
5932 Returns 0 on success, 1 if there are unresolved files.
5933 """
5933 """
5934 rev = opts.get(r'rev')
5934 rev = opts.get(r'rev')
5935 date = opts.get(r'date')
5935 date = opts.get(r'date')
5936 clean = opts.get(r'clean')
5936 clean = opts.get(r'clean')
5937 check = opts.get(r'check')
5937 check = opts.get(r'check')
5938 merge = opts.get(r'merge')
5938 merge = opts.get(r'merge')
5939 if rev and node:
5939 if rev and node:
5940 raise error.Abort(_("please specify just one revision"))
5940 raise error.Abort(_("please specify just one revision"))
5941
5941
5942 if ui.configbool('commands', 'update.requiredest'):
5942 if ui.configbool('commands', 'update.requiredest'):
5943 if not node and not rev and not date:
5943 if not node and not rev and not date:
5944 raise error.Abort(_('you must specify a destination'),
5944 raise error.Abort(_('you must specify a destination'),
5945 hint=_('for example: hg update ".::"'))
5945 hint=_('for example: hg update ".::"'))
5946
5946
5947 if rev is None or rev == '':
5947 if rev is None or rev == '':
5948 rev = node
5948 rev = node
5949
5949
5950 if date and rev is not None:
5950 if date and rev is not None:
5951 raise error.Abort(_("you can't specify a revision and a date"))
5951 raise error.Abort(_("you can't specify a revision and a date"))
5952
5952
5953 if len([x for x in (clean, check, merge) if x]) > 1:
5953 if len([x for x in (clean, check, merge) if x]) > 1:
5954 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5954 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5955 "or -m/--merge"))
5955 "or -m/--merge"))
5956
5956
5957 updatecheck = None
5957 updatecheck = None
5958 if check:
5958 if check:
5959 updatecheck = 'abort'
5959 updatecheck = 'abort'
5960 elif merge:
5960 elif merge:
5961 updatecheck = 'none'
5961 updatecheck = 'none'
5962
5962
5963 with repo.wlock():
5963 with repo.wlock():
5964 cmdutil.clearunfinished(repo)
5964 cmdutil.clearunfinished(repo)
5965
5965
5966 if date:
5966 if date:
5967 rev = cmdutil.finddate(ui, repo, date)
5967 rev = cmdutil.finddate(ui, repo, date)
5968
5968
5969 # if we defined a bookmark, we have to remember the original name
5969 # if we defined a bookmark, we have to remember the original name
5970 brev = rev
5970 brev = rev
5971 if rev:
5971 if rev:
5972 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5972 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5973 ctx = scmutil.revsingle(repo, rev, rev)
5973 ctx = scmutil.revsingle(repo, rev, rev)
5974 rev = ctx.rev()
5974 rev = ctx.rev()
5975 hidden = ctx.hidden()
5975 hidden = ctx.hidden()
5976 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5976 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5977 with ui.configoverride(overrides, 'update'):
5977 with ui.configoverride(overrides, 'update'):
5978 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5978 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5979 updatecheck=updatecheck)
5979 updatecheck=updatecheck)
5980 if hidden:
5980 if hidden:
5981 ctxstr = ctx.hex()[:12]
5981 ctxstr = ctx.hex()[:12]
5982 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5982 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5983
5983
5984 if ctx.obsolete():
5984 if ctx.obsolete():
5985 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5985 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5986 ui.warn("(%s)\n" % obsfatemsg)
5986 ui.warn("(%s)\n" % obsfatemsg)
5987 return ret
5987 return ret
5988
5988
5989 @command('verify', [])
5989 @command('verify', [])
5990 def verify(ui, repo):
5990 def verify(ui, repo):
5991 """verify the integrity of the repository
5991 """verify the integrity of the repository
5992
5992
5993 Verify the integrity of the current repository.
5993 Verify the integrity of the current repository.
5994
5994
5995 This will perform an extensive check of the repository's
5995 This will perform an extensive check of the repository's
5996 integrity, validating the hashes and checksums of each entry in
5996 integrity, validating the hashes and checksums of each entry in
5997 the changelog, manifest, and tracked files, as well as the
5997 the changelog, manifest, and tracked files, as well as the
5998 integrity of their crosslinks and indices.
5998 integrity of their crosslinks and indices.
5999
5999
6000 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6000 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6001 for more information about recovery from corruption of the
6001 for more information about recovery from corruption of the
6002 repository.
6002 repository.
6003
6003
6004 Returns 0 on success, 1 if errors are encountered.
6004 Returns 0 on success, 1 if errors are encountered.
6005 """
6005 """
6006 return hg.verify(repo)
6006 return hg.verify(repo)
6007
6007
6008 @command('version', [] + formatteropts, norepo=True,
6008 @command('version', [] + formatteropts, norepo=True,
6009 intents={INTENT_READONLY})
6009 intents={INTENT_READONLY})
6010 def version_(ui, **opts):
6010 def version_(ui, **opts):
6011 """output version and copyright information"""
6011 """output version and copyright information
6012
6013 .. container:: verbose
6014
6015 Template:
6016
6017 The following keywords are supported. See also :hg:`help templates`.
6018
6019 :extensions: List of extensions.
6020 :ver: String. Version number.
6021
6022 And each entry of ``{extensions}`` provides the following sub-keywords
6023 in addition to ``{ver}``.
6024
6025 :bundled: Boolean. True if included in the release.
6026 :name: String. Extension name.
6027 """
6012 opts = pycompat.byteskwargs(opts)
6028 opts = pycompat.byteskwargs(opts)
6013 if ui.verbose:
6029 if ui.verbose:
6014 ui.pager('version')
6030 ui.pager('version')
6015 fm = ui.formatter("version", opts)
6031 fm = ui.formatter("version", opts)
6016 fm.startitem()
6032 fm.startitem()
6017 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6033 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6018 util.version())
6034 util.version())
6019 license = _(
6035 license = _(
6020 "(see https://mercurial-scm.org for more information)\n"
6036 "(see https://mercurial-scm.org for more information)\n"
6021 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6037 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6022 "This is free software; see the source for copying conditions. "
6038 "This is free software; see the source for copying conditions. "
6023 "There is NO\nwarranty; "
6039 "There is NO\nwarranty; "
6024 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6040 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6025 )
6041 )
6026 if not ui.quiet:
6042 if not ui.quiet:
6027 fm.plain(license)
6043 fm.plain(license)
6028
6044
6029 if ui.verbose:
6045 if ui.verbose:
6030 fm.plain(_("\nEnabled extensions:\n\n"))
6046 fm.plain(_("\nEnabled extensions:\n\n"))
6031 # format names and versions into columns
6047 # format names and versions into columns
6032 names = []
6048 names = []
6033 vers = []
6049 vers = []
6034 isinternals = []
6050 isinternals = []
6035 for name, module in extensions.extensions():
6051 for name, module in extensions.extensions():
6036 names.append(name)
6052 names.append(name)
6037 vers.append(extensions.moduleversion(module) or None)
6053 vers.append(extensions.moduleversion(module) or None)
6038 isinternals.append(extensions.ismoduleinternal(module))
6054 isinternals.append(extensions.ismoduleinternal(module))
6039 fn = fm.nested("extensions", tmpl='{name}\n')
6055 fn = fm.nested("extensions", tmpl='{name}\n')
6040 if names:
6056 if names:
6041 namefmt = " %%-%ds " % max(len(n) for n in names)
6057 namefmt = " %%-%ds " % max(len(n) for n in names)
6042 places = [_("external"), _("internal")]
6058 places = [_("external"), _("internal")]
6043 for n, v, p in zip(names, vers, isinternals):
6059 for n, v, p in zip(names, vers, isinternals):
6044 fn.startitem()
6060 fn.startitem()
6045 fn.condwrite(ui.verbose, "name", namefmt, n)
6061 fn.condwrite(ui.verbose, "name", namefmt, n)
6046 if ui.verbose:
6062 if ui.verbose:
6047 fn.plain("%s " % places[p])
6063 fn.plain("%s " % places[p])
6048 fn.data(bundled=p)
6064 fn.data(bundled=p)
6049 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6065 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6050 if ui.verbose:
6066 if ui.verbose:
6051 fn.plain("\n")
6067 fn.plain("\n")
6052 fn.end()
6068 fn.end()
6053 fm.end()
6069 fm.end()
6054
6070
6055 def loadcmdtable(ui, name, cmdtable):
6071 def loadcmdtable(ui, name, cmdtable):
6056 """Load command functions from specified cmdtable
6072 """Load command functions from specified cmdtable
6057 """
6073 """
6058 overrides = [cmd for cmd in cmdtable if cmd in table]
6074 overrides = [cmd for cmd in cmdtable if cmd in table]
6059 if overrides:
6075 if overrides:
6060 ui.warn(_("extension '%s' overrides commands: %s\n")
6076 ui.warn(_("extension '%s' overrides commands: %s\n")
6061 % (name, " ".join(overrides)))
6077 % (name, " ".join(overrides)))
6062 table.update(cmdtable)
6078 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now