##// END OF EJS Templates
update: do not pass in user revspec as default destination (issue6044)...
Yuya Nishihara -
r41130:fbd5e2f0 stable
parent child Browse files
Show More
@@ -1,6157 +1,6157 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 copies,
31 copies,
32 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 discovery,
35 discovery,
36 encoding,
36 encoding,
37 error,
37 error,
38 exchange,
38 exchange,
39 extensions,
39 extensions,
40 filemerge,
40 filemerge,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 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 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
137 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
138 helpbasic=True, inferrepo=True)
138 helpbasic=True, inferrepo=True)
139 def add(ui, repo, *pats, **opts):
139 def add(ui, repo, *pats, **opts):
140 """add the specified files on the next commit
140 """add the specified files on the next commit
141
141
142 Schedule files to be version controlled and added to the
142 Schedule files to be version controlled and added to the
143 repository.
143 repository.
144
144
145 The files will be added to the repository at the next commit. To
145 The files will be added to the repository at the next commit. To
146 undo an add before that, see :hg:`forget`.
146 undo an add before that, see :hg:`forget`.
147
147
148 If no names are given, add all files to the repository (except
148 If no names are given, add all files to the repository (except
149 files matching ``.hgignore``).
149 files matching ``.hgignore``).
150
150
151 .. container:: verbose
151 .. container:: verbose
152
152
153 Examples:
153 Examples:
154
154
155 - New (unknown) files are added
155 - New (unknown) files are added
156 automatically by :hg:`add`::
156 automatically by :hg:`add`::
157
157
158 $ ls
158 $ ls
159 foo.c
159 foo.c
160 $ hg status
160 $ hg status
161 ? foo.c
161 ? foo.c
162 $ hg add
162 $ hg add
163 adding foo.c
163 adding foo.c
164 $ hg status
164 $ hg status
165 A foo.c
165 A foo.c
166
166
167 - Specific files to be added can be specified::
167 - Specific files to be added can be specified::
168
168
169 $ ls
169 $ ls
170 bar.c foo.c
170 bar.c foo.c
171 $ hg status
171 $ hg status
172 ? bar.c
172 ? bar.c
173 ? foo.c
173 ? foo.c
174 $ hg add bar.c
174 $ hg add bar.c
175 $ hg status
175 $ hg status
176 A bar.c
176 A bar.c
177 ? foo.c
177 ? foo.c
178
178
179 Returns 0 if all files are successfully added.
179 Returns 0 if all files are successfully added.
180 """
180 """
181
181
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
184 return rejected and 1 or 0
184 return rejected and 1 or 0
185
185
186 @command('addremove',
186 @command('addremove',
187 similarityopts + subrepoopts + walkopts + dryrunopts,
187 similarityopts + subrepoopts + walkopts + dryrunopts,
188 _('[OPTION]... [FILE]...'),
188 _('[OPTION]... [FILE]...'),
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
190 inferrepo=True)
190 inferrepo=True)
191 def addremove(ui, repo, *pats, **opts):
191 def addremove(ui, repo, *pats, **opts):
192 """add all new files, delete all missing files
192 """add all new files, delete all missing files
193
193
194 Add all new files and remove all missing files from the
194 Add all new files and remove all missing files from the
195 repository.
195 repository.
196
196
197 Unless names are given, new files are ignored if they match any of
197 Unless names are given, new files are ignored if they match any of
198 the patterns in ``.hgignore``. As with add, these changes take
198 the patterns in ``.hgignore``. As with add, these changes take
199 effect at the next commit.
199 effect at the next commit.
200
200
201 Use the -s/--similarity option to detect renamed files. This
201 Use the -s/--similarity option to detect renamed files. This
202 option takes a percentage between 0 (disabled) and 100 (files must
202 option takes a percentage between 0 (disabled) and 100 (files must
203 be identical) as its parameter. With a parameter greater than 0,
203 be identical) as its parameter. With a parameter greater than 0,
204 this compares every removed file with every added file and records
204 this compares every removed file with every added file and records
205 those similar enough as renames. Detecting renamed files this way
205 those similar enough as renames. Detecting renamed files this way
206 can be expensive. After using this option, :hg:`status -C` can be
206 can be expensive. After using this option, :hg:`status -C` can be
207 used to check which files were identified as moved or renamed. If
207 used to check which files were identified as moved or renamed. If
208 not specified, -s/--similarity defaults to 100 and only renames of
208 not specified, -s/--similarity defaults to 100 and only renames of
209 identical files are detected.
209 identical files are detected.
210
210
211 .. container:: verbose
211 .. container:: verbose
212
212
213 Examples:
213 Examples:
214
214
215 - A number of files (bar.c and foo.c) are new,
215 - A number of files (bar.c and foo.c) are new,
216 while foobar.c has been removed (without using :hg:`remove`)
216 while foobar.c has been removed (without using :hg:`remove`)
217 from the repository::
217 from the repository::
218
218
219 $ ls
219 $ ls
220 bar.c foo.c
220 bar.c foo.c
221 $ hg status
221 $ hg status
222 ! foobar.c
222 ! foobar.c
223 ? bar.c
223 ? bar.c
224 ? foo.c
224 ? foo.c
225 $ hg addremove
225 $ hg addremove
226 adding bar.c
226 adding bar.c
227 adding foo.c
227 adding foo.c
228 removing foobar.c
228 removing foobar.c
229 $ hg status
229 $ hg status
230 A bar.c
230 A bar.c
231 A foo.c
231 A foo.c
232 R foobar.c
232 R foobar.c
233
233
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
235 Afterwards, it was edited slightly::
235 Afterwards, it was edited slightly::
236
236
237 $ ls
237 $ ls
238 foo.c
238 foo.c
239 $ hg status
239 $ hg status
240 ! foobar.c
240 ! foobar.c
241 ? foo.c
241 ? foo.c
242 $ hg addremove --similarity 90
242 $ hg addremove --similarity 90
243 removing foobar.c
243 removing foobar.c
244 adding foo.c
244 adding foo.c
245 recording removal of foobar.c as rename to foo.c (94% similar)
245 recording removal of foobar.c as rename to foo.c (94% similar)
246 $ hg status -C
246 $ hg status -C
247 A foo.c
247 A foo.c
248 foobar.c
248 foobar.c
249 R foobar.c
249 R foobar.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253 opts = pycompat.byteskwargs(opts)
253 opts = pycompat.byteskwargs(opts)
254 if not opts.get('similarity'):
254 if not opts.get('similarity'):
255 opts['similarity'] = '100'
255 opts['similarity'] = '100'
256 matcher = scmutil.match(repo[None], pats, opts)
256 matcher = scmutil.match(repo[None], pats, opts)
257 return scmutil.addremove(repo, matcher, "", opts)
257 return scmutil.addremove(repo, matcher, "", opts)
258
258
259 @command('annotate|blame',
259 @command('annotate|blame',
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
261 ('', 'follow', None,
261 ('', 'follow', None,
262 _('follow copies/renames and list the filename (DEPRECATED)')),
262 _('follow copies/renames and list the filename (DEPRECATED)')),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
264 ('a', 'text', None, _('treat all files as text')),
264 ('a', 'text', None, _('treat all files as text')),
265 ('u', 'user', None, _('list the author (long with -v)')),
265 ('u', 'user', None, _('list the author (long with -v)')),
266 ('f', 'file', None, _('list the filename')),
266 ('f', 'file', None, _('list the filename')),
267 ('d', 'date', None, _('list the date (short with -q)')),
267 ('d', 'date', None, _('list the date (short with -q)')),
268 ('n', 'number', None, _('list the revision number (default)')),
268 ('n', 'number', None, _('list the revision number (default)')),
269 ('c', 'changeset', None, _('list the changeset')),
269 ('c', 'changeset', None, _('list the changeset')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
272 ] + diffwsopts + walkopts + formatteropts,
272 ] + diffwsopts + walkopts + formatteropts,
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
275 helpbasic=True, inferrepo=True)
275 helpbasic=True, inferrepo=True)
276 def annotate(ui, repo, *pats, **opts):
276 def annotate(ui, repo, *pats, **opts):
277 """show changeset information by line for each file
277 """show changeset information by line for each file
278
278
279 List changes in files, showing the revision id responsible for
279 List changes in files, showing the revision id responsible for
280 each line.
280 each line.
281
281
282 This command is useful for discovering when a change was made and
282 This command is useful for discovering when a change was made and
283 by whom.
283 by whom.
284
284
285 If you include --file, --user, or --date, the revision number is
285 If you include --file, --user, or --date, the revision number is
286 suppressed unless you also include --number.
286 suppressed unless you also include --number.
287
287
288 Without the -a/--text option, annotate will avoid processing files
288 Without the -a/--text option, annotate will avoid processing files
289 it detects as binary. With -a, annotate will annotate the file
289 it detects as binary. With -a, annotate will annotate the file
290 anyway, although the results will probably be neither useful
290 anyway, although the results will probably be neither useful
291 nor desirable.
291 nor desirable.
292
292
293 .. container:: verbose
293 .. container:: verbose
294
294
295 Template:
295 Template:
296
296
297 The following keywords are supported in addition to the common template
297 The following keywords are supported in addition to the common template
298 keywords and functions. See also :hg:`help templates`.
298 keywords and functions. See also :hg:`help templates`.
299
299
300 :lines: List of lines with annotation data.
300 :lines: List of lines with annotation data.
301 :path: String. Repository-absolute path of the specified file.
301 :path: String. Repository-absolute path of the specified file.
302
302
303 And each entry of ``{lines}`` provides the following sub-keywords in
303 And each entry of ``{lines}`` provides the following sub-keywords in
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
305
305
306 :line: String. Line content.
306 :line: String. Line content.
307 :lineno: Integer. Line number at that revision.
307 :lineno: Integer. Line number at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
309
309
310 See :hg:`help templates.operators` for the list expansion syntax.
310 See :hg:`help templates.operators` for the list expansion syntax.
311
311
312 Returns 0 on success.
312 Returns 0 on success.
313 """
313 """
314 opts = pycompat.byteskwargs(opts)
314 opts = pycompat.byteskwargs(opts)
315 if not pats:
315 if not pats:
316 raise error.Abort(_('at least one filename or pattern is required'))
316 raise error.Abort(_('at least one filename or pattern is required'))
317
317
318 if opts.get('follow'):
318 if opts.get('follow'):
319 # --follow is deprecated and now just an alias for -f/--file
319 # --follow is deprecated and now just an alias for -f/--file
320 # to mimic the behavior of Mercurial before version 1.5
320 # to mimic the behavior of Mercurial before version 1.5
321 opts['file'] = True
321 opts['file'] = True
322
322
323 rev = opts.get('rev')
323 rev = opts.get('rev')
324 if rev:
324 if rev:
325 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
325 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
326 ctx = scmutil.revsingle(repo, rev)
326 ctx = scmutil.revsingle(repo, rev)
327
327
328 rootfm = ui.formatter('annotate', opts)
328 rootfm = ui.formatter('annotate', opts)
329 if ui.debugflag:
329 if ui.debugflag:
330 shorthex = pycompat.identity
330 shorthex = pycompat.identity
331 else:
331 else:
332 def shorthex(h):
332 def shorthex(h):
333 return h[:12]
333 return h[:12]
334 if ui.quiet:
334 if ui.quiet:
335 datefunc = dateutil.shortdate
335 datefunc = dateutil.shortdate
336 else:
336 else:
337 datefunc = dateutil.datestr
337 datefunc = dateutil.datestr
338 if ctx.rev() is None:
338 if ctx.rev() is None:
339 if opts.get('changeset'):
339 if opts.get('changeset'):
340 # omit "+" suffix which is appended to node hex
340 # omit "+" suffix which is appended to node hex
341 def formatrev(rev):
341 def formatrev(rev):
342 if rev == wdirrev:
342 if rev == wdirrev:
343 return '%d' % ctx.p1().rev()
343 return '%d' % ctx.p1().rev()
344 else:
344 else:
345 return '%d' % rev
345 return '%d' % rev
346 else:
346 else:
347 def formatrev(rev):
347 def formatrev(rev):
348 if rev == wdirrev:
348 if rev == wdirrev:
349 return '%d+' % ctx.p1().rev()
349 return '%d+' % ctx.p1().rev()
350 else:
350 else:
351 return '%d ' % rev
351 return '%d ' % rev
352 def formathex(h):
352 def formathex(h):
353 if h == wdirhex:
353 if h == wdirhex:
354 return '%s+' % shorthex(hex(ctx.p1().node()))
354 return '%s+' % shorthex(hex(ctx.p1().node()))
355 else:
355 else:
356 return '%s ' % shorthex(h)
356 return '%s ' % shorthex(h)
357 else:
357 else:
358 formatrev = b'%d'.__mod__
358 formatrev = b'%d'.__mod__
359 formathex = shorthex
359 formathex = shorthex
360
360
361 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
361 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
362 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
362 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
363 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
363 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
364 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
364 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
365 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
365 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
366 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
366 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
367 ]
367 ]
368 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
368 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
369 'lineno': 'line_number'}
369 'lineno': 'line_number'}
370
370
371 if (not opts.get('user') and not opts.get('changeset')
371 if (not opts.get('user') and not opts.get('changeset')
372 and not opts.get('date') and not opts.get('file')):
372 and not opts.get('date') and not opts.get('file')):
373 opts['number'] = True
373 opts['number'] = True
374
374
375 linenumber = opts.get('line_number') is not None
375 linenumber = opts.get('line_number') is not None
376 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
376 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
377 raise error.Abort(_('at least one of -n/-c is required for -l'))
377 raise error.Abort(_('at least one of -n/-c is required for -l'))
378
378
379 ui.pager('annotate')
379 ui.pager('annotate')
380
380
381 if rootfm.isplain():
381 if rootfm.isplain():
382 def makefunc(get, fmt):
382 def makefunc(get, fmt):
383 return lambda x: fmt(get(x))
383 return lambda x: fmt(get(x))
384 else:
384 else:
385 def makefunc(get, fmt):
385 def makefunc(get, fmt):
386 return get
386 return get
387 datahint = rootfm.datahint()
387 datahint = rootfm.datahint()
388 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
388 funcmap = [(makefunc(get, fmt), sep) 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 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
390 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
391 fields = ' '.join(fn for fn, sep, get, fmt in opmap
391 fields = ' '.join(fn for fn, sep, get, fmt in opmap
392 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
392 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
393
393
394 def bad(x, y):
394 def bad(x, y):
395 raise error.Abort("%s: %s" % (x, y))
395 raise error.Abort("%s: %s" % (x, y))
396
396
397 m = scmutil.match(ctx, pats, opts, badfn=bad)
397 m = scmutil.match(ctx, pats, opts, badfn=bad)
398
398
399 follow = not opts.get('no_follow')
399 follow = not opts.get('no_follow')
400 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
400 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
401 whitespace=True)
401 whitespace=True)
402 skiprevs = opts.get('skip')
402 skiprevs = opts.get('skip')
403 if skiprevs:
403 if skiprevs:
404 skiprevs = scmutil.revrange(repo, skiprevs)
404 skiprevs = scmutil.revrange(repo, skiprevs)
405
405
406 for abs in ctx.walk(m):
406 for abs in ctx.walk(m):
407 fctx = ctx[abs]
407 fctx = ctx[abs]
408 rootfm.startitem()
408 rootfm.startitem()
409 rootfm.data(path=abs)
409 rootfm.data(path=abs)
410 if not opts.get('text') and fctx.isbinary():
410 if not opts.get('text') and fctx.isbinary():
411 rootfm.plain(_("%s: binary file\n")
411 rootfm.plain(_("%s: binary file\n")
412 % ((pats and m.rel(abs)) or abs))
412 % ((pats and m.rel(abs)) or abs))
413 continue
413 continue
414
414
415 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
415 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
416 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
416 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
417 diffopts=diffopts)
417 diffopts=diffopts)
418 if not lines:
418 if not lines:
419 fm.end()
419 fm.end()
420 continue
420 continue
421 formats = []
421 formats = []
422 pieces = []
422 pieces = []
423
423
424 for f, sep in funcmap:
424 for f, sep in funcmap:
425 l = [f(n) for n in lines]
425 l = [f(n) for n in lines]
426 if fm.isplain():
426 if fm.isplain():
427 sizes = [encoding.colwidth(x) for x in l]
427 sizes = [encoding.colwidth(x) for x in l]
428 ml = max(sizes)
428 ml = max(sizes)
429 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
429 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
430 else:
430 else:
431 formats.append(['%s' for x in l])
431 formats.append(['%s' for x in l])
432 pieces.append(l)
432 pieces.append(l)
433
433
434 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
434 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
435 fm.startitem()
435 fm.startitem()
436 fm.context(fctx=n.fctx)
436 fm.context(fctx=n.fctx)
437 fm.write(fields, "".join(f), *p)
437 fm.write(fields, "".join(f), *p)
438 if n.skip:
438 if n.skip:
439 fmt = "* %s"
439 fmt = "* %s"
440 else:
440 else:
441 fmt = ": %s"
441 fmt = ": %s"
442 fm.write('line', fmt, n.text)
442 fm.write('line', fmt, n.text)
443
443
444 if not lines[-1].text.endswith('\n'):
444 if not lines[-1].text.endswith('\n'):
445 fm.plain('\n')
445 fm.plain('\n')
446 fm.end()
446 fm.end()
447
447
448 rootfm.end()
448 rootfm.end()
449
449
450 @command('archive',
450 @command('archive',
451 [('', 'no-decode', None, _('do not pass files through decoders')),
451 [('', 'no-decode', None, _('do not pass files through decoders')),
452 ('p', 'prefix', '', _('directory prefix for files in archive'),
452 ('p', 'prefix', '', _('directory prefix for files in archive'),
453 _('PREFIX')),
453 _('PREFIX')),
454 ('r', 'rev', '', _('revision to distribute'), _('REV')),
454 ('r', 'rev', '', _('revision to distribute'), _('REV')),
455 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
455 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
456 ] + subrepoopts + walkopts,
456 ] + subrepoopts + walkopts,
457 _('[OPTION]... DEST'),
457 _('[OPTION]... DEST'),
458 helpcategory=command.CATEGORY_IMPORT_EXPORT)
458 helpcategory=command.CATEGORY_IMPORT_EXPORT)
459 def archive(ui, repo, dest, **opts):
459 def archive(ui, repo, dest, **opts):
460 '''create an unversioned archive of a repository revision
460 '''create an unversioned archive of a repository revision
461
461
462 By default, the revision used is the parent of the working
462 By default, the revision used is the parent of the working
463 directory; use -r/--rev to specify a different revision.
463 directory; use -r/--rev to specify a different revision.
464
464
465 The archive type is automatically detected based on file
465 The archive type is automatically detected based on file
466 extension (to override, use -t/--type).
466 extension (to override, use -t/--type).
467
467
468 .. container:: verbose
468 .. container:: verbose
469
469
470 Examples:
470 Examples:
471
471
472 - create a zip file containing the 1.0 release::
472 - create a zip file containing the 1.0 release::
473
473
474 hg archive -r 1.0 project-1.0.zip
474 hg archive -r 1.0 project-1.0.zip
475
475
476 - create a tarball excluding .hg files::
476 - create a tarball excluding .hg files::
477
477
478 hg archive project.tar.gz -X ".hg*"
478 hg archive project.tar.gz -X ".hg*"
479
479
480 Valid types are:
480 Valid types are:
481
481
482 :``files``: a directory full of files (default)
482 :``files``: a directory full of files (default)
483 :``tar``: tar archive, uncompressed
483 :``tar``: tar archive, uncompressed
484 :``tbz2``: tar archive, compressed using bzip2
484 :``tbz2``: tar archive, compressed using bzip2
485 :``tgz``: tar archive, compressed using gzip
485 :``tgz``: tar archive, compressed using gzip
486 :``uzip``: zip archive, uncompressed
486 :``uzip``: zip archive, uncompressed
487 :``zip``: zip archive, compressed using deflate
487 :``zip``: zip archive, compressed using deflate
488
488
489 The exact name of the destination archive or directory is given
489 The exact name of the destination archive or directory is given
490 using a format string; see :hg:`help export` for details.
490 using a format string; see :hg:`help export` for details.
491
491
492 Each member added to an archive file has a directory prefix
492 Each member added to an archive file has a directory prefix
493 prepended. Use -p/--prefix to specify a format string for the
493 prepended. Use -p/--prefix to specify a format string for the
494 prefix. The default is the basename of the archive, with suffixes
494 prefix. The default is the basename of the archive, with suffixes
495 removed.
495 removed.
496
496
497 Returns 0 on success.
497 Returns 0 on success.
498 '''
498 '''
499
499
500 opts = pycompat.byteskwargs(opts)
500 opts = pycompat.byteskwargs(opts)
501 rev = opts.get('rev')
501 rev = opts.get('rev')
502 if rev:
502 if rev:
503 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
503 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
504 ctx = scmutil.revsingle(repo, rev)
504 ctx = scmutil.revsingle(repo, rev)
505 if not ctx:
505 if not ctx:
506 raise error.Abort(_('no working directory: please specify a revision'))
506 raise error.Abort(_('no working directory: please specify a revision'))
507 node = ctx.node()
507 node = ctx.node()
508 dest = cmdutil.makefilename(ctx, dest)
508 dest = cmdutil.makefilename(ctx, dest)
509 if os.path.realpath(dest) == repo.root:
509 if os.path.realpath(dest) == repo.root:
510 raise error.Abort(_('repository root cannot be destination'))
510 raise error.Abort(_('repository root cannot be destination'))
511
511
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
513 prefix = opts.get('prefix')
513 prefix = opts.get('prefix')
514
514
515 if dest == '-':
515 if dest == '-':
516 if kind == 'files':
516 if kind == 'files':
517 raise error.Abort(_('cannot archive plain files to stdout'))
517 raise error.Abort(_('cannot archive plain files to stdout'))
518 dest = cmdutil.makefileobj(ctx, dest)
518 dest = cmdutil.makefileobj(ctx, dest)
519 if not prefix:
519 if not prefix:
520 prefix = os.path.basename(repo.root) + '-%h'
520 prefix = os.path.basename(repo.root) + '-%h'
521
521
522 prefix = cmdutil.makefilename(ctx, prefix)
522 prefix = cmdutil.makefilename(ctx, prefix)
523 match = scmutil.match(ctx, [], opts)
523 match = scmutil.match(ctx, [], opts)
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
525 match, prefix, subrepos=opts.get('subrepos'))
525 match, prefix, subrepos=opts.get('subrepos'))
526
526
527 @command('backout',
527 @command('backout',
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
529 ('', 'commit', None,
529 ('', 'commit', None,
530 _('commit if no conflicts were encountered (DEPRECATED)')),
530 _('commit if no conflicts were encountered (DEPRECATED)')),
531 ('', 'no-commit', None, _('do not commit')),
531 ('', 'no-commit', None, _('do not commit')),
532 ('', 'parent', '',
532 ('', 'parent', '',
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
537 _('[OPTION]... [-r] REV'),
537 _('[OPTION]... [-r] REV'),
538 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
538 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
539 def backout(ui, repo, node=None, rev=None, **opts):
539 def backout(ui, repo, node=None, rev=None, **opts):
540 '''reverse effect of earlier changeset
540 '''reverse effect of earlier changeset
541
541
542 Prepare a new changeset with the effect of REV undone in the
542 Prepare a new changeset with the effect of REV undone in the
543 current working directory. If no conflicts were encountered,
543 current working directory. If no conflicts were encountered,
544 it will be committed immediately.
544 it will be committed immediately.
545
545
546 If REV is the parent of the working directory, then this new changeset
546 If REV is the parent of the working directory, then this new changeset
547 is committed automatically (unless --no-commit is specified).
547 is committed automatically (unless --no-commit is specified).
548
548
549 .. note::
549 .. note::
550
550
551 :hg:`backout` cannot be used to fix either an unwanted or
551 :hg:`backout` cannot be used to fix either an unwanted or
552 incorrect merge.
552 incorrect merge.
553
553
554 .. container:: verbose
554 .. container:: verbose
555
555
556 Examples:
556 Examples:
557
557
558 - Reverse the effect of the parent of the working directory.
558 - Reverse the effect of the parent of the working directory.
559 This backout will be committed immediately::
559 This backout will be committed immediately::
560
560
561 hg backout -r .
561 hg backout -r .
562
562
563 - Reverse the effect of previous bad revision 23::
563 - Reverse the effect of previous bad revision 23::
564
564
565 hg backout -r 23
565 hg backout -r 23
566
566
567 - Reverse the effect of previous bad revision 23 and
567 - Reverse the effect of previous bad revision 23 and
568 leave changes uncommitted::
568 leave changes uncommitted::
569
569
570 hg backout -r 23 --no-commit
570 hg backout -r 23 --no-commit
571 hg commit -m "Backout revision 23"
571 hg commit -m "Backout revision 23"
572
572
573 By default, the pending changeset will have one parent,
573 By default, the pending changeset will have one parent,
574 maintaining a linear history. With --merge, the pending
574 maintaining a linear history. With --merge, the pending
575 changeset will instead have two parents: the old parent of the
575 changeset will instead have two parents: the old parent of the
576 working directory and a new child of REV that simply undoes REV.
576 working directory and a new child of REV that simply undoes REV.
577
577
578 Before version 1.7, the behavior without --merge was equivalent
578 Before version 1.7, the behavior without --merge was equivalent
579 to specifying --merge followed by :hg:`update --clean .` to
579 to specifying --merge followed by :hg:`update --clean .` to
580 cancel the merge and leave the child of REV as a head to be
580 cancel the merge and leave the child of REV as a head to be
581 merged separately.
581 merged separately.
582
582
583 See :hg:`help dates` for a list of formats valid for -d/--date.
583 See :hg:`help dates` for a list of formats valid for -d/--date.
584
584
585 See :hg:`help revert` for a way to restore files to the state
585 See :hg:`help revert` for a way to restore files to the state
586 of another revision.
586 of another revision.
587
587
588 Returns 0 on success, 1 if nothing to backout or there are unresolved
588 Returns 0 on success, 1 if nothing to backout or there are unresolved
589 files.
589 files.
590 '''
590 '''
591 with repo.wlock(), repo.lock():
591 with repo.wlock(), repo.lock():
592 return _dobackout(ui, repo, node, rev, **opts)
592 return _dobackout(ui, repo, node, rev, **opts)
593
593
594 def _dobackout(ui, repo, node=None, rev=None, **opts):
594 def _dobackout(ui, repo, node=None, rev=None, **opts):
595 opts = pycompat.byteskwargs(opts)
595 opts = pycompat.byteskwargs(opts)
596 if opts.get('commit') and opts.get('no_commit'):
596 if opts.get('commit') and opts.get('no_commit'):
597 raise error.Abort(_("cannot use --commit with --no-commit"))
597 raise error.Abort(_("cannot use --commit with --no-commit"))
598 if opts.get('merge') and opts.get('no_commit'):
598 if opts.get('merge') and opts.get('no_commit'):
599 raise error.Abort(_("cannot use --merge with --no-commit"))
599 raise error.Abort(_("cannot use --merge with --no-commit"))
600
600
601 if rev and node:
601 if rev and node:
602 raise error.Abort(_("please specify just one revision"))
602 raise error.Abort(_("please specify just one revision"))
603
603
604 if not rev:
604 if not rev:
605 rev = node
605 rev = node
606
606
607 if not rev:
607 if not rev:
608 raise error.Abort(_("please specify a revision to backout"))
608 raise error.Abort(_("please specify a revision to backout"))
609
609
610 date = opts.get('date')
610 date = opts.get('date')
611 if date:
611 if date:
612 opts['date'] = dateutil.parsedate(date)
612 opts['date'] = dateutil.parsedate(date)
613
613
614 cmdutil.checkunfinished(repo)
614 cmdutil.checkunfinished(repo)
615 cmdutil.bailifchanged(repo)
615 cmdutil.bailifchanged(repo)
616 node = scmutil.revsingle(repo, rev).node()
616 node = scmutil.revsingle(repo, rev).node()
617
617
618 op1, op2 = repo.dirstate.parents()
618 op1, op2 = repo.dirstate.parents()
619 if not repo.changelog.isancestor(node, op1):
619 if not repo.changelog.isancestor(node, op1):
620 raise error.Abort(_('cannot backout change that is not an ancestor'))
620 raise error.Abort(_('cannot backout change that is not an ancestor'))
621
621
622 p1, p2 = repo.changelog.parents(node)
622 p1, p2 = repo.changelog.parents(node)
623 if p1 == nullid:
623 if p1 == nullid:
624 raise error.Abort(_('cannot backout a change with no parents'))
624 raise error.Abort(_('cannot backout a change with no parents'))
625 if p2 != nullid:
625 if p2 != nullid:
626 if not opts.get('parent'):
626 if not opts.get('parent'):
627 raise error.Abort(_('cannot backout a merge changeset'))
627 raise error.Abort(_('cannot backout a merge changeset'))
628 p = repo.lookup(opts['parent'])
628 p = repo.lookup(opts['parent'])
629 if p not in (p1, p2):
629 if p not in (p1, p2):
630 raise error.Abort(_('%s is not a parent of %s') %
630 raise error.Abort(_('%s is not a parent of %s') %
631 (short(p), short(node)))
631 (short(p), short(node)))
632 parent = p
632 parent = p
633 else:
633 else:
634 if opts.get('parent'):
634 if opts.get('parent'):
635 raise error.Abort(_('cannot use --parent on non-merge changeset'))
635 raise error.Abort(_('cannot use --parent on non-merge changeset'))
636 parent = p1
636 parent = p1
637
637
638 # the backout should appear on the same branch
638 # the backout should appear on the same branch
639 branch = repo.dirstate.branch()
639 branch = repo.dirstate.branch()
640 bheads = repo.branchheads(branch)
640 bheads = repo.branchheads(branch)
641 rctx = scmutil.revsingle(repo, hex(parent))
641 rctx = scmutil.revsingle(repo, hex(parent))
642 if not opts.get('merge') and op1 != node:
642 if not opts.get('merge') and op1 != node:
643 with dirstateguard.dirstateguard(repo, 'backout'):
643 with dirstateguard.dirstateguard(repo, 'backout'):
644 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
644 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
645 with ui.configoverride(overrides, 'backout'):
645 with ui.configoverride(overrides, 'backout'):
646 stats = mergemod.update(repo, parent, branchmerge=True,
646 stats = mergemod.update(repo, parent, branchmerge=True,
647 force=True, ancestor=node,
647 force=True, ancestor=node,
648 mergeancestor=False)
648 mergeancestor=False)
649 repo.setparents(op1, op2)
649 repo.setparents(op1, op2)
650 hg._showstats(repo, stats)
650 hg._showstats(repo, stats)
651 if stats.unresolvedcount:
651 if stats.unresolvedcount:
652 repo.ui.status(_("use 'hg resolve' to retry unresolved "
652 repo.ui.status(_("use 'hg resolve' to retry unresolved "
653 "file merges\n"))
653 "file merges\n"))
654 return 1
654 return 1
655 else:
655 else:
656 hg.clean(repo, node, show_stats=False)
656 hg.clean(repo, node, show_stats=False)
657 repo.dirstate.setbranch(branch)
657 repo.dirstate.setbranch(branch)
658 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
658 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
659
659
660 if opts.get('no_commit'):
660 if opts.get('no_commit'):
661 msg = _("changeset %s backed out, "
661 msg = _("changeset %s backed out, "
662 "don't forget to commit.\n")
662 "don't forget to commit.\n")
663 ui.status(msg % short(node))
663 ui.status(msg % short(node))
664 return 0
664 return 0
665
665
666 def commitfunc(ui, repo, message, match, opts):
666 def commitfunc(ui, repo, message, match, opts):
667 editform = 'backout'
667 editform = 'backout'
668 e = cmdutil.getcommiteditor(editform=editform,
668 e = cmdutil.getcommiteditor(editform=editform,
669 **pycompat.strkwargs(opts))
669 **pycompat.strkwargs(opts))
670 if not message:
670 if not message:
671 # we don't translate commit messages
671 # we don't translate commit messages
672 message = "Backed out changeset %s" % short(node)
672 message = "Backed out changeset %s" % short(node)
673 e = cmdutil.getcommiteditor(edit=True, editform=editform)
673 e = cmdutil.getcommiteditor(edit=True, editform=editform)
674 return repo.commit(message, opts.get('user'), opts.get('date'),
674 return repo.commit(message, opts.get('user'), opts.get('date'),
675 match, editor=e)
675 match, editor=e)
676 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
676 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
677 if not newnode:
677 if not newnode:
678 ui.status(_("nothing changed\n"))
678 ui.status(_("nothing changed\n"))
679 return 1
679 return 1
680 cmdutil.commitstatus(repo, newnode, branch, bheads)
680 cmdutil.commitstatus(repo, newnode, branch, bheads)
681
681
682 def nice(node):
682 def nice(node):
683 return '%d:%s' % (repo.changelog.rev(node), short(node))
683 return '%d:%s' % (repo.changelog.rev(node), short(node))
684 ui.status(_('changeset %s backs out changeset %s\n') %
684 ui.status(_('changeset %s backs out changeset %s\n') %
685 (nice(repo.changelog.tip()), nice(node)))
685 (nice(repo.changelog.tip()), nice(node)))
686 if opts.get('merge') and op1 != node:
686 if opts.get('merge') and op1 != node:
687 hg.clean(repo, op1, show_stats=False)
687 hg.clean(repo, op1, show_stats=False)
688 ui.status(_('merging with changeset %s\n')
688 ui.status(_('merging with changeset %s\n')
689 % nice(repo.changelog.tip()))
689 % nice(repo.changelog.tip()))
690 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
690 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
691 with ui.configoverride(overrides, 'backout'):
691 with ui.configoverride(overrides, 'backout'):
692 return hg.merge(repo, hex(repo.changelog.tip()))
692 return hg.merge(repo, hex(repo.changelog.tip()))
693 return 0
693 return 0
694
694
695 @command('bisect',
695 @command('bisect',
696 [('r', 'reset', False, _('reset bisect state')),
696 [('r', 'reset', False, _('reset bisect state')),
697 ('g', 'good', False, _('mark changeset good')),
697 ('g', 'good', False, _('mark changeset good')),
698 ('b', 'bad', False, _('mark changeset bad')),
698 ('b', 'bad', False, _('mark changeset bad')),
699 ('s', 'skip', False, _('skip testing changeset')),
699 ('s', 'skip', False, _('skip testing changeset')),
700 ('e', 'extend', False, _('extend the bisect range')),
700 ('e', 'extend', False, _('extend the bisect range')),
701 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
701 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
702 ('U', 'noupdate', False, _('do not update to target'))],
702 ('U', 'noupdate', False, _('do not update to target'))],
703 _("[-gbsr] [-U] [-c CMD] [REV]"),
703 _("[-gbsr] [-U] [-c CMD] [REV]"),
704 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
704 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
705 def bisect(ui, repo, rev=None, extra=None, command=None,
705 def bisect(ui, repo, rev=None, extra=None, command=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
707 noupdate=None):
707 noupdate=None):
708 """subdivision search of changesets
708 """subdivision search of changesets
709
709
710 This command helps to find changesets which introduce problems. To
710 This command helps to find changesets which introduce problems. To
711 use, mark the earliest changeset you know exhibits the problem as
711 use, mark the earliest changeset you know exhibits the problem as
712 bad, then mark the latest changeset which is free from the problem
712 bad, then mark the latest changeset which is free from the problem
713 as good. Bisect will update your working directory to a revision
713 as good. Bisect will update your working directory to a revision
714 for testing (unless the -U/--noupdate option is specified). Once
714 for testing (unless the -U/--noupdate option is specified). Once
715 you have performed tests, mark the working directory as good or
715 you have performed tests, mark the working directory as good or
716 bad, and bisect will either update to another candidate changeset
716 bad, and bisect will either update to another candidate changeset
717 or announce that it has found the bad revision.
717 or announce that it has found the bad revision.
718
718
719 As a shortcut, you can also use the revision argument to mark a
719 As a shortcut, you can also use the revision argument to mark a
720 revision as good or bad without checking it out first.
720 revision as good or bad without checking it out first.
721
721
722 If you supply a command, it will be used for automatic bisection.
722 If you supply a command, it will be used for automatic bisection.
723 The environment variable HG_NODE will contain the ID of the
723 The environment variable HG_NODE will contain the ID of the
724 changeset being tested. The exit status of the command will be
724 changeset being tested. The exit status of the command will be
725 used to mark revisions as good or bad: status 0 means good, 125
725 used to mark revisions as good or bad: status 0 means good, 125
726 means to skip the revision, 127 (command not found) will abort the
726 means to skip the revision, 127 (command not found) will abort the
727 bisection, and any other non-zero exit status means the revision
727 bisection, and any other non-zero exit status means the revision
728 is bad.
728 is bad.
729
729
730 .. container:: verbose
730 .. container:: verbose
731
731
732 Some examples:
732 Some examples:
733
733
734 - start a bisection with known bad revision 34, and good revision 12::
734 - start a bisection with known bad revision 34, and good revision 12::
735
735
736 hg bisect --bad 34
736 hg bisect --bad 34
737 hg bisect --good 12
737 hg bisect --good 12
738
738
739 - advance the current bisection by marking current revision as good or
739 - advance the current bisection by marking current revision as good or
740 bad::
740 bad::
741
741
742 hg bisect --good
742 hg bisect --good
743 hg bisect --bad
743 hg bisect --bad
744
744
745 - mark the current revision, or a known revision, to be skipped (e.g. if
745 - mark the current revision, or a known revision, to be skipped (e.g. if
746 that revision is not usable because of another issue)::
746 that revision is not usable because of another issue)::
747
747
748 hg bisect --skip
748 hg bisect --skip
749 hg bisect --skip 23
749 hg bisect --skip 23
750
750
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
752
752
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
754
754
755 - forget the current bisection::
755 - forget the current bisection::
756
756
757 hg bisect --reset
757 hg bisect --reset
758
758
759 - use 'make && make tests' to automatically find the first broken
759 - use 'make && make tests' to automatically find the first broken
760 revision::
760 revision::
761
761
762 hg bisect --reset
762 hg bisect --reset
763 hg bisect --bad 34
763 hg bisect --bad 34
764 hg bisect --good 12
764 hg bisect --good 12
765 hg bisect --command "make && make tests"
765 hg bisect --command "make && make tests"
766
766
767 - see all changesets whose states are already known in the current
767 - see all changesets whose states are already known in the current
768 bisection::
768 bisection::
769
769
770 hg log -r "bisect(pruned)"
770 hg log -r "bisect(pruned)"
771
771
772 - see the changeset currently being bisected (especially useful
772 - see the changeset currently being bisected (especially useful
773 if running with -U/--noupdate)::
773 if running with -U/--noupdate)::
774
774
775 hg log -r "bisect(current)"
775 hg log -r "bisect(current)"
776
776
777 - see all changesets that took part in the current bisection::
777 - see all changesets that took part in the current bisection::
778
778
779 hg log -r "bisect(range)"
779 hg log -r "bisect(range)"
780
780
781 - you can even get a nice graph::
781 - you can even get a nice graph::
782
782
783 hg log --graph -r "bisect(range)"
783 hg log --graph -r "bisect(range)"
784
784
785 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
785 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
786
786
787 Returns 0 on success.
787 Returns 0 on success.
788 """
788 """
789 # backward compatibility
789 # backward compatibility
790 if rev in "good bad reset init".split():
790 if rev in "good bad reset init".split():
791 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
791 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
792 cmd, rev, extra = rev, extra, None
792 cmd, rev, extra = rev, extra, None
793 if cmd == "good":
793 if cmd == "good":
794 good = True
794 good = True
795 elif cmd == "bad":
795 elif cmd == "bad":
796 bad = True
796 bad = True
797 else:
797 else:
798 reset = True
798 reset = True
799 elif extra:
799 elif extra:
800 raise error.Abort(_('incompatible arguments'))
800 raise error.Abort(_('incompatible arguments'))
801
801
802 incompatibles = {
802 incompatibles = {
803 '--bad': bad,
803 '--bad': bad,
804 '--command': bool(command),
804 '--command': bool(command),
805 '--extend': extend,
805 '--extend': extend,
806 '--good': good,
806 '--good': good,
807 '--reset': reset,
807 '--reset': reset,
808 '--skip': skip,
808 '--skip': skip,
809 }
809 }
810
810
811 enabled = [x for x in incompatibles if incompatibles[x]]
811 enabled = [x for x in incompatibles if incompatibles[x]]
812
812
813 if len(enabled) > 1:
813 if len(enabled) > 1:
814 raise error.Abort(_('%s and %s are incompatible') %
814 raise error.Abort(_('%s and %s are incompatible') %
815 tuple(sorted(enabled)[0:2]))
815 tuple(sorted(enabled)[0:2]))
816
816
817 if reset:
817 if reset:
818 hbisect.resetstate(repo)
818 hbisect.resetstate(repo)
819 return
819 return
820
820
821 state = hbisect.load_state(repo)
821 state = hbisect.load_state(repo)
822
822
823 # update state
823 # update state
824 if good or bad or skip:
824 if good or bad or skip:
825 if rev:
825 if rev:
826 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
826 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
827 else:
827 else:
828 nodes = [repo.lookup('.')]
828 nodes = [repo.lookup('.')]
829 if good:
829 if good:
830 state['good'] += nodes
830 state['good'] += nodes
831 elif bad:
831 elif bad:
832 state['bad'] += nodes
832 state['bad'] += nodes
833 elif skip:
833 elif skip:
834 state['skip'] += nodes
834 state['skip'] += nodes
835 hbisect.save_state(repo, state)
835 hbisect.save_state(repo, state)
836 if not (state['good'] and state['bad']):
836 if not (state['good'] and state['bad']):
837 return
837 return
838
838
839 def mayupdate(repo, node, show_stats=True):
839 def mayupdate(repo, node, show_stats=True):
840 """common used update sequence"""
840 """common used update sequence"""
841 if noupdate:
841 if noupdate:
842 return
842 return
843 cmdutil.checkunfinished(repo)
843 cmdutil.checkunfinished(repo)
844 cmdutil.bailifchanged(repo)
844 cmdutil.bailifchanged(repo)
845 return hg.clean(repo, node, show_stats=show_stats)
845 return hg.clean(repo, node, show_stats=show_stats)
846
846
847 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
847 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
848
848
849 if command:
849 if command:
850 changesets = 1
850 changesets = 1
851 if noupdate:
851 if noupdate:
852 try:
852 try:
853 node = state['current'][0]
853 node = state['current'][0]
854 except LookupError:
854 except LookupError:
855 raise error.Abort(_('current bisect revision is unknown - '
855 raise error.Abort(_('current bisect revision is unknown - '
856 'start a new bisect to fix'))
856 'start a new bisect to fix'))
857 else:
857 else:
858 node, p2 = repo.dirstate.parents()
858 node, p2 = repo.dirstate.parents()
859 if p2 != nullid:
859 if p2 != nullid:
860 raise error.Abort(_('current bisect revision is a merge'))
860 raise error.Abort(_('current bisect revision is a merge'))
861 if rev:
861 if rev:
862 node = repo[scmutil.revsingle(repo, rev, node)].node()
862 node = repo[scmutil.revsingle(repo, rev, node)].node()
863 try:
863 try:
864 while changesets:
864 while changesets:
865 # update state
865 # update state
866 state['current'] = [node]
866 state['current'] = [node]
867 hbisect.save_state(repo, state)
867 hbisect.save_state(repo, state)
868 status = ui.system(command, environ={'HG_NODE': hex(node)},
868 status = ui.system(command, environ={'HG_NODE': hex(node)},
869 blockedtag='bisect_check')
869 blockedtag='bisect_check')
870 if status == 125:
870 if status == 125:
871 transition = "skip"
871 transition = "skip"
872 elif status == 0:
872 elif status == 0:
873 transition = "good"
873 transition = "good"
874 # status < 0 means process was killed
874 # status < 0 means process was killed
875 elif status == 127:
875 elif status == 127:
876 raise error.Abort(_("failed to execute %s") % command)
876 raise error.Abort(_("failed to execute %s") % command)
877 elif status < 0:
877 elif status < 0:
878 raise error.Abort(_("%s killed") % command)
878 raise error.Abort(_("%s killed") % command)
879 else:
879 else:
880 transition = "bad"
880 transition = "bad"
881 state[transition].append(node)
881 state[transition].append(node)
882 ctx = repo[node]
882 ctx = repo[node]
883 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
883 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
884 transition))
884 transition))
885 hbisect.checkstate(state)
885 hbisect.checkstate(state)
886 # bisect
886 # bisect
887 nodes, changesets, bgood = hbisect.bisect(repo, state)
887 nodes, changesets, bgood = hbisect.bisect(repo, state)
888 # update to next check
888 # update to next check
889 node = nodes[0]
889 node = nodes[0]
890 mayupdate(repo, node, show_stats=False)
890 mayupdate(repo, node, show_stats=False)
891 finally:
891 finally:
892 state['current'] = [node]
892 state['current'] = [node]
893 hbisect.save_state(repo, state)
893 hbisect.save_state(repo, state)
894 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
894 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
895 return
895 return
896
896
897 hbisect.checkstate(state)
897 hbisect.checkstate(state)
898
898
899 # actually bisect
899 # actually bisect
900 nodes, changesets, good = hbisect.bisect(repo, state)
900 nodes, changesets, good = hbisect.bisect(repo, state)
901 if extend:
901 if extend:
902 if not changesets:
902 if not changesets:
903 extendnode = hbisect.extendrange(repo, state, nodes, good)
903 extendnode = hbisect.extendrange(repo, state, nodes, good)
904 if extendnode is not None:
904 if extendnode is not None:
905 ui.write(_("Extending search to changeset %d:%s\n")
905 ui.write(_("Extending search to changeset %d:%s\n")
906 % (extendnode.rev(), extendnode))
906 % (extendnode.rev(), extendnode))
907 state['current'] = [extendnode.node()]
907 state['current'] = [extendnode.node()]
908 hbisect.save_state(repo, state)
908 hbisect.save_state(repo, state)
909 return mayupdate(repo, extendnode.node())
909 return mayupdate(repo, extendnode.node())
910 raise error.Abort(_("nothing to extend"))
910 raise error.Abort(_("nothing to extend"))
911
911
912 if changesets == 0:
912 if changesets == 0:
913 hbisect.printresult(ui, repo, state, displayer, nodes, good)
913 hbisect.printresult(ui, repo, state, displayer, nodes, good)
914 else:
914 else:
915 assert len(nodes) == 1 # only a single node can be tested next
915 assert len(nodes) == 1 # only a single node can be tested next
916 node = nodes[0]
916 node = nodes[0]
917 # compute the approximate number of remaining tests
917 # compute the approximate number of remaining tests
918 tests, size = 0, 2
918 tests, size = 0, 2
919 while size <= changesets:
919 while size <= changesets:
920 tests, size = tests + 1, size * 2
920 tests, size = tests + 1, size * 2
921 rev = repo.changelog.rev(node)
921 rev = repo.changelog.rev(node)
922 ui.write(_("Testing changeset %d:%s "
922 ui.write(_("Testing changeset %d:%s "
923 "(%d changesets remaining, ~%d tests)\n")
923 "(%d changesets remaining, ~%d tests)\n")
924 % (rev, short(node), changesets, tests))
924 % (rev, short(node), changesets, tests))
925 state['current'] = [node]
925 state['current'] = [node]
926 hbisect.save_state(repo, state)
926 hbisect.save_state(repo, state)
927 return mayupdate(repo, node)
927 return mayupdate(repo, node)
928
928
929 @command('bookmarks|bookmark',
929 @command('bookmarks|bookmark',
930 [('f', 'force', False, _('force')),
930 [('f', 'force', False, _('force')),
931 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
931 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
932 ('d', 'delete', False, _('delete a given bookmark')),
932 ('d', 'delete', False, _('delete a given bookmark')),
933 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
933 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
934 ('i', 'inactive', False, _('mark a bookmark inactive')),
934 ('i', 'inactive', False, _('mark a bookmark inactive')),
935 ('l', 'list', False, _('list existing bookmarks')),
935 ('l', 'list', False, _('list existing bookmarks')),
936 ] + formatteropts,
936 ] + formatteropts,
937 _('hg bookmarks [OPTIONS]... [NAME]...'),
937 _('hg bookmarks [OPTIONS]... [NAME]...'),
938 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
938 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
939 def bookmark(ui, repo, *names, **opts):
939 def bookmark(ui, repo, *names, **opts):
940 '''create a new bookmark or list existing bookmarks
940 '''create a new bookmark or list existing bookmarks
941
941
942 Bookmarks are labels on changesets to help track lines of development.
942 Bookmarks are labels on changesets to help track lines of development.
943 Bookmarks are unversioned and can be moved, renamed and deleted.
943 Bookmarks are unversioned and can be moved, renamed and deleted.
944 Deleting or moving a bookmark has no effect on the associated changesets.
944 Deleting or moving a bookmark has no effect on the associated changesets.
945
945
946 Creating or updating to a bookmark causes it to be marked as 'active'.
946 Creating or updating to a bookmark causes it to be marked as 'active'.
947 The active bookmark is indicated with a '*'.
947 The active bookmark is indicated with a '*'.
948 When a commit is made, the active bookmark will advance to the new commit.
948 When a commit is made, the active bookmark will advance to the new commit.
949 A plain :hg:`update` will also advance an active bookmark, if possible.
949 A plain :hg:`update` will also advance an active bookmark, if possible.
950 Updating away from a bookmark will cause it to be deactivated.
950 Updating away from a bookmark will cause it to be deactivated.
951
951
952 Bookmarks can be pushed and pulled between repositories (see
952 Bookmarks can be pushed and pulled between repositories (see
953 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
953 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
954 diverged, a new 'divergent bookmark' of the form 'name@path' will
954 diverged, a new 'divergent bookmark' of the form 'name@path' will
955 be created. Using :hg:`merge` will resolve the divergence.
955 be created. Using :hg:`merge` will resolve the divergence.
956
956
957 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
957 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
958 the active bookmark's name.
958 the active bookmark's name.
959
959
960 A bookmark named '@' has the special property that :hg:`clone` will
960 A bookmark named '@' has the special property that :hg:`clone` will
961 check it out by default if it exists.
961 check it out by default if it exists.
962
962
963 .. container:: verbose
963 .. container:: verbose
964
964
965 Template:
965 Template:
966
966
967 The following keywords are supported in addition to the common template
967 The following keywords are supported in addition to the common template
968 keywords and functions such as ``{bookmark}``. See also
968 keywords and functions such as ``{bookmark}``. See also
969 :hg:`help templates`.
969 :hg:`help templates`.
970
970
971 :active: Boolean. True if the bookmark is active.
971 :active: Boolean. True if the bookmark is active.
972
972
973 Examples:
973 Examples:
974
974
975 - create an active bookmark for a new line of development::
975 - create an active bookmark for a new line of development::
976
976
977 hg book new-feature
977 hg book new-feature
978
978
979 - create an inactive bookmark as a place marker::
979 - create an inactive bookmark as a place marker::
980
980
981 hg book -i reviewed
981 hg book -i reviewed
982
982
983 - create an inactive bookmark on another changeset::
983 - create an inactive bookmark on another changeset::
984
984
985 hg book -r .^ tested
985 hg book -r .^ tested
986
986
987 - rename bookmark turkey to dinner::
987 - rename bookmark turkey to dinner::
988
988
989 hg book -m turkey dinner
989 hg book -m turkey dinner
990
990
991 - move the '@' bookmark from another branch::
991 - move the '@' bookmark from another branch::
992
992
993 hg book -f @
993 hg book -f @
994
994
995 - print only the active bookmark name::
995 - print only the active bookmark name::
996
996
997 hg book -ql .
997 hg book -ql .
998 '''
998 '''
999 opts = pycompat.byteskwargs(opts)
999 opts = pycompat.byteskwargs(opts)
1000 force = opts.get('force')
1000 force = opts.get('force')
1001 rev = opts.get('rev')
1001 rev = opts.get('rev')
1002 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1002 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1003
1003
1004 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1004 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1005 if len(selactions) > 1:
1005 if len(selactions) > 1:
1006 raise error.Abort(_('--%s and --%s are incompatible')
1006 raise error.Abort(_('--%s and --%s are incompatible')
1007 % tuple(selactions[:2]))
1007 % tuple(selactions[:2]))
1008 if selactions:
1008 if selactions:
1009 action = selactions[0]
1009 action = selactions[0]
1010 elif names or rev:
1010 elif names or rev:
1011 action = 'add'
1011 action = 'add'
1012 elif inactive:
1012 elif inactive:
1013 action = 'inactive' # meaning deactivate
1013 action = 'inactive' # meaning deactivate
1014 else:
1014 else:
1015 action = 'list'
1015 action = 'list'
1016
1016
1017 if rev and action in {'delete', 'rename', 'list'}:
1017 if rev and action in {'delete', 'rename', 'list'}:
1018 raise error.Abort(_("--rev is incompatible with --%s") % action)
1018 raise error.Abort(_("--rev is incompatible with --%s") % action)
1019 if inactive and action in {'delete', 'list'}:
1019 if inactive and action in {'delete', 'list'}:
1020 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1020 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1021 if not names and action in {'add', 'delete'}:
1021 if not names and action in {'add', 'delete'}:
1022 raise error.Abort(_("bookmark name required"))
1022 raise error.Abort(_("bookmark name required"))
1023
1023
1024 if action in {'add', 'delete', 'rename', 'inactive'}:
1024 if action in {'add', 'delete', 'rename', 'inactive'}:
1025 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1025 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1026 if action == 'delete':
1026 if action == 'delete':
1027 names = pycompat.maplist(repo._bookmarks.expandname, names)
1027 names = pycompat.maplist(repo._bookmarks.expandname, names)
1028 bookmarks.delete(repo, tr, names)
1028 bookmarks.delete(repo, tr, names)
1029 elif action == 'rename':
1029 elif action == 'rename':
1030 if not names:
1030 if not names:
1031 raise error.Abort(_("new bookmark name required"))
1031 raise error.Abort(_("new bookmark name required"))
1032 elif len(names) > 1:
1032 elif len(names) > 1:
1033 raise error.Abort(_("only one new bookmark name allowed"))
1033 raise error.Abort(_("only one new bookmark name allowed"))
1034 oldname = repo._bookmarks.expandname(opts['rename'])
1034 oldname = repo._bookmarks.expandname(opts['rename'])
1035 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1035 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1036 elif action == 'add':
1036 elif action == 'add':
1037 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1037 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1038 elif action == 'inactive':
1038 elif action == 'inactive':
1039 if len(repo._bookmarks) == 0:
1039 if len(repo._bookmarks) == 0:
1040 ui.status(_("no bookmarks set\n"))
1040 ui.status(_("no bookmarks set\n"))
1041 elif not repo._activebookmark:
1041 elif not repo._activebookmark:
1042 ui.status(_("no active bookmark\n"))
1042 ui.status(_("no active bookmark\n"))
1043 else:
1043 else:
1044 bookmarks.deactivate(repo)
1044 bookmarks.deactivate(repo)
1045 elif action == 'list':
1045 elif action == 'list':
1046 names = pycompat.maplist(repo._bookmarks.expandname, names)
1046 names = pycompat.maplist(repo._bookmarks.expandname, names)
1047 with ui.formatter('bookmarks', opts) as fm:
1047 with ui.formatter('bookmarks', opts) as fm:
1048 bookmarks.printbookmarks(ui, repo, fm, names)
1048 bookmarks.printbookmarks(ui, repo, fm, names)
1049 else:
1049 else:
1050 raise error.ProgrammingError('invalid action: %s' % action)
1050 raise error.ProgrammingError('invalid action: %s' % action)
1051
1051
1052 @command('branch',
1052 @command('branch',
1053 [('f', 'force', None,
1053 [('f', 'force', None,
1054 _('set branch name even if it shadows an existing branch')),
1054 _('set branch name even if it shadows an existing branch')),
1055 ('C', 'clean', None, _('reset branch name to parent branch name')),
1055 ('C', 'clean', None, _('reset branch name to parent branch name')),
1056 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1056 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1057 ],
1057 ],
1058 _('[-fC] [NAME]'),
1058 _('[-fC] [NAME]'),
1059 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1059 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1060 def branch(ui, repo, label=None, **opts):
1060 def branch(ui, repo, label=None, **opts):
1061 """set or show the current branch name
1061 """set or show the current branch name
1062
1062
1063 .. note::
1063 .. note::
1064
1064
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1067 information about named branches and bookmarks.
1067 information about named branches and bookmarks.
1068
1068
1069 With no argument, show the current branch name. With one argument,
1069 With no argument, show the current branch name. With one argument,
1070 set the working directory branch name (the branch will not exist
1070 set the working directory branch name (the branch will not exist
1071 in the repository until the next commit). Standard practice
1071 in the repository until the next commit). Standard practice
1072 recommends that primary development take place on the 'default'
1072 recommends that primary development take place on the 'default'
1073 branch.
1073 branch.
1074
1074
1075 Unless -f/--force is specified, branch will not let you set a
1075 Unless -f/--force is specified, branch will not let you set a
1076 branch name that already exists.
1076 branch name that already exists.
1077
1077
1078 Use -C/--clean to reset the working directory branch to that of
1078 Use -C/--clean to reset the working directory branch to that of
1079 the parent of the working directory, negating a previous branch
1079 the parent of the working directory, negating a previous branch
1080 change.
1080 change.
1081
1081
1082 Use the command :hg:`update` to switch to an existing branch. Use
1082 Use the command :hg:`update` to switch to an existing branch. Use
1083 :hg:`commit --close-branch` to mark this branch head as closed.
1083 :hg:`commit --close-branch` to mark this branch head as closed.
1084 When all heads of a branch are closed, the branch will be
1084 When all heads of a branch are closed, the branch will be
1085 considered closed.
1085 considered closed.
1086
1086
1087 Returns 0 on success.
1087 Returns 0 on success.
1088 """
1088 """
1089 opts = pycompat.byteskwargs(opts)
1089 opts = pycompat.byteskwargs(opts)
1090 revs = opts.get('rev')
1090 revs = opts.get('rev')
1091 if label:
1091 if label:
1092 label = label.strip()
1092 label = label.strip()
1093
1093
1094 if not opts.get('clean') and not label:
1094 if not opts.get('clean') and not label:
1095 if revs:
1095 if revs:
1096 raise error.Abort(_("no branch name specified for the revisions"))
1096 raise error.Abort(_("no branch name specified for the revisions"))
1097 ui.write("%s\n" % repo.dirstate.branch())
1097 ui.write("%s\n" % repo.dirstate.branch())
1098 return
1098 return
1099
1099
1100 with repo.wlock():
1100 with repo.wlock():
1101 if opts.get('clean'):
1101 if opts.get('clean'):
1102 label = repo[None].p1().branch()
1102 label = repo[None].p1().branch()
1103 repo.dirstate.setbranch(label)
1103 repo.dirstate.setbranch(label)
1104 ui.status(_('reset working directory to branch %s\n') % label)
1104 ui.status(_('reset working directory to branch %s\n') % label)
1105 elif label:
1105 elif label:
1106
1106
1107 scmutil.checknewlabel(repo, label, 'branch')
1107 scmutil.checknewlabel(repo, label, 'branch')
1108 if revs:
1108 if revs:
1109 return cmdutil.changebranch(ui, repo, revs, label)
1109 return cmdutil.changebranch(ui, repo, revs, label)
1110
1110
1111 if not opts.get('force') and label in repo.branchmap():
1111 if not opts.get('force') and label in repo.branchmap():
1112 if label not in [p.branch() for p in repo[None].parents()]:
1112 if label not in [p.branch() for p in repo[None].parents()]:
1113 raise error.Abort(_('a branch of the same name already'
1113 raise error.Abort(_('a branch of the same name already'
1114 ' exists'),
1114 ' exists'),
1115 # i18n: "it" refers to an existing branch
1115 # i18n: "it" refers to an existing branch
1116 hint=_("use 'hg update' to switch to it"))
1116 hint=_("use 'hg update' to switch to it"))
1117
1117
1118 repo.dirstate.setbranch(label)
1118 repo.dirstate.setbranch(label)
1119 ui.status(_('marked working directory as branch %s\n') % label)
1119 ui.status(_('marked working directory as branch %s\n') % label)
1120
1120
1121 # find any open named branches aside from default
1121 # find any open named branches aside from default
1122 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1122 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1123 if n != "default" and not c]
1123 if n != "default" and not c]
1124 if not others:
1124 if not others:
1125 ui.status(_('(branches are permanent and global, '
1125 ui.status(_('(branches are permanent and global, '
1126 'did you want a bookmark?)\n'))
1126 'did you want a bookmark?)\n'))
1127
1127
1128 @command('branches',
1128 @command('branches',
1129 [('a', 'active', False,
1129 [('a', 'active', False,
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1132 ] + formatteropts,
1132 ] + formatteropts,
1133 _('[-c]'),
1133 _('[-c]'),
1134 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1134 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1135 intents={INTENT_READONLY})
1135 intents={INTENT_READONLY})
1136 def branches(ui, repo, active=False, closed=False, **opts):
1136 def branches(ui, repo, active=False, closed=False, **opts):
1137 """list repository named branches
1137 """list repository named branches
1138
1138
1139 List the repository's named branches, indicating which ones are
1139 List the repository's named branches, indicating which ones are
1140 inactive. If -c/--closed is specified, also list branches which have
1140 inactive. If -c/--closed is specified, also list branches which have
1141 been marked closed (see :hg:`commit --close-branch`).
1141 been marked closed (see :hg:`commit --close-branch`).
1142
1142
1143 Use the command :hg:`update` to switch to an existing branch.
1143 Use the command :hg:`update` to switch to an existing branch.
1144
1144
1145 .. container:: verbose
1145 .. container:: verbose
1146
1146
1147 Template:
1147 Template:
1148
1148
1149 The following keywords are supported in addition to the common template
1149 The following keywords are supported in addition to the common template
1150 keywords and functions such as ``{branch}``. See also
1150 keywords and functions such as ``{branch}``. See also
1151 :hg:`help templates`.
1151 :hg:`help templates`.
1152
1152
1153 :active: Boolean. True if the branch is active.
1153 :active: Boolean. True if the branch is active.
1154 :closed: Boolean. True if the branch is closed.
1154 :closed: Boolean. True if the branch is closed.
1155 :current: Boolean. True if it is the current branch.
1155 :current: Boolean. True if it is the current branch.
1156
1156
1157 Returns 0.
1157 Returns 0.
1158 """
1158 """
1159
1159
1160 opts = pycompat.byteskwargs(opts)
1160 opts = pycompat.byteskwargs(opts)
1161 ui.pager('branches')
1161 ui.pager('branches')
1162 fm = ui.formatter('branches', opts)
1162 fm = ui.formatter('branches', opts)
1163 hexfunc = fm.hexfunc
1163 hexfunc = fm.hexfunc
1164
1164
1165 allheads = set(repo.heads())
1165 allheads = set(repo.heads())
1166 branches = []
1166 branches = []
1167 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1167 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1168 isactive = False
1168 isactive = False
1169 if not isclosed:
1169 if not isclosed:
1170 openheads = set(repo.branchmap().iteropen(heads))
1170 openheads = set(repo.branchmap().iteropen(heads))
1171 isactive = bool(openheads & allheads)
1171 isactive = bool(openheads & allheads)
1172 branches.append((tag, repo[tip], isactive, not isclosed))
1172 branches.append((tag, repo[tip], isactive, not isclosed))
1173 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1173 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1174 reverse=True)
1174 reverse=True)
1175
1175
1176 for tag, ctx, isactive, isopen in branches:
1176 for tag, ctx, isactive, isopen in branches:
1177 if active and not isactive:
1177 if active and not isactive:
1178 continue
1178 continue
1179 if isactive:
1179 if isactive:
1180 label = 'branches.active'
1180 label = 'branches.active'
1181 notice = ''
1181 notice = ''
1182 elif not isopen:
1182 elif not isopen:
1183 if not closed:
1183 if not closed:
1184 continue
1184 continue
1185 label = 'branches.closed'
1185 label = 'branches.closed'
1186 notice = _(' (closed)')
1186 notice = _(' (closed)')
1187 else:
1187 else:
1188 label = 'branches.inactive'
1188 label = 'branches.inactive'
1189 notice = _(' (inactive)')
1189 notice = _(' (inactive)')
1190 current = (tag == repo.dirstate.branch())
1190 current = (tag == repo.dirstate.branch())
1191 if current:
1191 if current:
1192 label = 'branches.current'
1192 label = 'branches.current'
1193
1193
1194 fm.startitem()
1194 fm.startitem()
1195 fm.write('branch', '%s', tag, label=label)
1195 fm.write('branch', '%s', tag, label=label)
1196 rev = ctx.rev()
1196 rev = ctx.rev()
1197 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1197 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1198 fmt = ' ' * padsize + ' %d:%s'
1198 fmt = ' ' * padsize + ' %d:%s'
1199 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1199 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1200 label='log.changeset changeset.%s' % ctx.phasestr())
1200 label='log.changeset changeset.%s' % ctx.phasestr())
1201 fm.context(ctx=ctx)
1201 fm.context(ctx=ctx)
1202 fm.data(active=isactive, closed=not isopen, current=current)
1202 fm.data(active=isactive, closed=not isopen, current=current)
1203 if not ui.quiet:
1203 if not ui.quiet:
1204 fm.plain(notice)
1204 fm.plain(notice)
1205 fm.plain('\n')
1205 fm.plain('\n')
1206 fm.end()
1206 fm.end()
1207
1207
1208 @command('bundle',
1208 @command('bundle',
1209 [('f', 'force', None, _('run even when the destination is unrelated')),
1209 [('f', 'force', None, _('run even when the destination is unrelated')),
1210 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1210 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1211 _('REV')),
1211 _('REV')),
1212 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1212 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1213 _('BRANCH')),
1213 _('BRANCH')),
1214 ('', 'base', [],
1214 ('', 'base', [],
1215 _('a base changeset assumed to be available at the destination'),
1215 _('a base changeset assumed to be available at the destination'),
1216 _('REV')),
1216 _('REV')),
1217 ('a', 'all', None, _('bundle all changesets in the repository')),
1217 ('a', 'all', None, _('bundle all changesets in the repository')),
1218 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1218 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1219 ] + remoteopts,
1219 ] + remoteopts,
1220 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1220 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1221 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1221 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1222 def bundle(ui, repo, fname, dest=None, **opts):
1222 def bundle(ui, repo, fname, dest=None, **opts):
1223 """create a bundle file
1223 """create a bundle file
1224
1224
1225 Generate a bundle file containing data to be transferred to another
1225 Generate a bundle file containing data to be transferred to another
1226 repository.
1226 repository.
1227
1227
1228 To create a bundle containing all changesets, use -a/--all
1228 To create a bundle containing all changesets, use -a/--all
1229 (or --base null). Otherwise, hg assumes the destination will have
1229 (or --base null). Otherwise, hg assumes the destination will have
1230 all the nodes you specify with --base parameters. Otherwise, hg
1230 all the nodes you specify with --base parameters. Otherwise, hg
1231 will assume the repository has all the nodes in destination, or
1231 will assume the repository has all the nodes in destination, or
1232 default-push/default if no destination is specified, where destination
1232 default-push/default if no destination is specified, where destination
1233 is the repository you provide through DEST option.
1233 is the repository you provide through DEST option.
1234
1234
1235 You can change bundle format with the -t/--type option. See
1235 You can change bundle format with the -t/--type option. See
1236 :hg:`help bundlespec` for documentation on this format. By default,
1236 :hg:`help bundlespec` for documentation on this format. By default,
1237 the most appropriate format is used and compression defaults to
1237 the most appropriate format is used and compression defaults to
1238 bzip2.
1238 bzip2.
1239
1239
1240 The bundle file can then be transferred using conventional means
1240 The bundle file can then be transferred using conventional means
1241 and applied to another repository with the unbundle or pull
1241 and applied to another repository with the unbundle or pull
1242 command. This is useful when direct push and pull are not
1242 command. This is useful when direct push and pull are not
1243 available or when exporting an entire repository is undesirable.
1243 available or when exporting an entire repository is undesirable.
1244
1244
1245 Applying bundles preserves all changeset contents including
1245 Applying bundles preserves all changeset contents including
1246 permissions, copy/rename information, and revision history.
1246 permissions, copy/rename information, and revision history.
1247
1247
1248 Returns 0 on success, 1 if no changes found.
1248 Returns 0 on success, 1 if no changes found.
1249 """
1249 """
1250 opts = pycompat.byteskwargs(opts)
1250 opts = pycompat.byteskwargs(opts)
1251 revs = None
1251 revs = None
1252 if 'rev' in opts:
1252 if 'rev' in opts:
1253 revstrings = opts['rev']
1253 revstrings = opts['rev']
1254 revs = scmutil.revrange(repo, revstrings)
1254 revs = scmutil.revrange(repo, revstrings)
1255 if revstrings and not revs:
1255 if revstrings and not revs:
1256 raise error.Abort(_('no commits to bundle'))
1256 raise error.Abort(_('no commits to bundle'))
1257
1257
1258 bundletype = opts.get('type', 'bzip2').lower()
1258 bundletype = opts.get('type', 'bzip2').lower()
1259 try:
1259 try:
1260 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1260 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1261 except error.UnsupportedBundleSpecification as e:
1261 except error.UnsupportedBundleSpecification as e:
1262 raise error.Abort(pycompat.bytestr(e),
1262 raise error.Abort(pycompat.bytestr(e),
1263 hint=_("see 'hg help bundlespec' for supported "
1263 hint=_("see 'hg help bundlespec' for supported "
1264 "values for --type"))
1264 "values for --type"))
1265 cgversion = bundlespec.contentopts["cg.version"]
1265 cgversion = bundlespec.contentopts["cg.version"]
1266
1266
1267 # Packed bundles are a pseudo bundle format for now.
1267 # Packed bundles are a pseudo bundle format for now.
1268 if cgversion == 's1':
1268 if cgversion == 's1':
1269 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1269 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1270 hint=_("use 'hg debugcreatestreamclonebundle'"))
1270 hint=_("use 'hg debugcreatestreamclonebundle'"))
1271
1271
1272 if opts.get('all'):
1272 if opts.get('all'):
1273 if dest:
1273 if dest:
1274 raise error.Abort(_("--all is incompatible with specifying "
1274 raise error.Abort(_("--all is incompatible with specifying "
1275 "a destination"))
1275 "a destination"))
1276 if opts.get('base'):
1276 if opts.get('base'):
1277 ui.warn(_("ignoring --base because --all was specified\n"))
1277 ui.warn(_("ignoring --base because --all was specified\n"))
1278 base = [nullrev]
1278 base = [nullrev]
1279 else:
1279 else:
1280 base = scmutil.revrange(repo, opts.get('base'))
1280 base = scmutil.revrange(repo, opts.get('base'))
1281 if cgversion not in changegroup.supportedoutgoingversions(repo):
1281 if cgversion not in changegroup.supportedoutgoingversions(repo):
1282 raise error.Abort(_("repository does not support bundle version %s") %
1282 raise error.Abort(_("repository does not support bundle version %s") %
1283 cgversion)
1283 cgversion)
1284
1284
1285 if base:
1285 if base:
1286 if dest:
1286 if dest:
1287 raise error.Abort(_("--base is incompatible with specifying "
1287 raise error.Abort(_("--base is incompatible with specifying "
1288 "a destination"))
1288 "a destination"))
1289 common = [repo[rev].node() for rev in base]
1289 common = [repo[rev].node() for rev in base]
1290 heads = [repo[r].node() for r in revs] if revs else None
1290 heads = [repo[r].node() for r in revs] if revs else None
1291 outgoing = discovery.outgoing(repo, common, heads)
1291 outgoing = discovery.outgoing(repo, common, heads)
1292 else:
1292 else:
1293 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1293 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1294 dest, branches = hg.parseurl(dest, opts.get('branch'))
1294 dest, branches = hg.parseurl(dest, opts.get('branch'))
1295 other = hg.peer(repo, opts, dest)
1295 other = hg.peer(repo, opts, dest)
1296 revs = [repo[r].hex() for r in revs]
1296 revs = [repo[r].hex() for r in revs]
1297 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1297 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1298 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1298 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1299 outgoing = discovery.findcommonoutgoing(repo, other,
1299 outgoing = discovery.findcommonoutgoing(repo, other,
1300 onlyheads=heads,
1300 onlyheads=heads,
1301 force=opts.get('force'),
1301 force=opts.get('force'),
1302 portable=True)
1302 portable=True)
1303
1303
1304 if not outgoing.missing:
1304 if not outgoing.missing:
1305 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1305 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1306 return 1
1306 return 1
1307
1307
1308 if cgversion == '01': #bundle1
1308 if cgversion == '01': #bundle1
1309 bversion = 'HG10' + bundlespec.wirecompression
1309 bversion = 'HG10' + bundlespec.wirecompression
1310 bcompression = None
1310 bcompression = None
1311 elif cgversion in ('02', '03'):
1311 elif cgversion in ('02', '03'):
1312 bversion = 'HG20'
1312 bversion = 'HG20'
1313 bcompression = bundlespec.wirecompression
1313 bcompression = bundlespec.wirecompression
1314 else:
1314 else:
1315 raise error.ProgrammingError(
1315 raise error.ProgrammingError(
1316 'bundle: unexpected changegroup version %s' % cgversion)
1316 'bundle: unexpected changegroup version %s' % cgversion)
1317
1317
1318 # TODO compression options should be derived from bundlespec parsing.
1318 # TODO compression options should be derived from bundlespec parsing.
1319 # This is a temporary hack to allow adjusting bundle compression
1319 # This is a temporary hack to allow adjusting bundle compression
1320 # level without a) formalizing the bundlespec changes to declare it
1320 # level without a) formalizing the bundlespec changes to declare it
1321 # b) introducing a command flag.
1321 # b) introducing a command flag.
1322 compopts = {}
1322 compopts = {}
1323 complevel = ui.configint('experimental',
1323 complevel = ui.configint('experimental',
1324 'bundlecomplevel.' + bundlespec.compression)
1324 'bundlecomplevel.' + bundlespec.compression)
1325 if complevel is None:
1325 if complevel is None:
1326 complevel = ui.configint('experimental', 'bundlecomplevel')
1326 complevel = ui.configint('experimental', 'bundlecomplevel')
1327 if complevel is not None:
1327 if complevel is not None:
1328 compopts['level'] = complevel
1328 compopts['level'] = complevel
1329
1329
1330 # Allow overriding the bundling of obsmarker in phases through
1330 # Allow overriding the bundling of obsmarker in phases through
1331 # configuration while we don't have a bundle version that include them
1331 # configuration while we don't have a bundle version that include them
1332 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1332 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1333 bundlespec.contentopts['obsolescence'] = True
1333 bundlespec.contentopts['obsolescence'] = True
1334 if repo.ui.configbool('experimental', 'bundle-phases'):
1334 if repo.ui.configbool('experimental', 'bundle-phases'):
1335 bundlespec.contentopts['phases'] = True
1335 bundlespec.contentopts['phases'] = True
1336
1336
1337 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1337 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1338 bundlespec.contentopts, compression=bcompression,
1338 bundlespec.contentopts, compression=bcompression,
1339 compopts=compopts)
1339 compopts=compopts)
1340
1340
1341 @command('cat',
1341 @command('cat',
1342 [('o', 'output', '',
1342 [('o', 'output', '',
1343 _('print output to file with formatted name'), _('FORMAT')),
1343 _('print output to file with formatted name'), _('FORMAT')),
1344 ('r', 'rev', '', _('print the given revision'), _('REV')),
1344 ('r', 'rev', '', _('print the given revision'), _('REV')),
1345 ('', 'decode', None, _('apply any matching decode filter')),
1345 ('', 'decode', None, _('apply any matching decode filter')),
1346 ] + walkopts + formatteropts,
1346 ] + walkopts + formatteropts,
1347 _('[OPTION]... FILE...'),
1347 _('[OPTION]... FILE...'),
1348 helpcategory=command.CATEGORY_FILE_CONTENTS,
1348 helpcategory=command.CATEGORY_FILE_CONTENTS,
1349 inferrepo=True,
1349 inferrepo=True,
1350 intents={INTENT_READONLY})
1350 intents={INTENT_READONLY})
1351 def cat(ui, repo, file1, *pats, **opts):
1351 def cat(ui, repo, file1, *pats, **opts):
1352 """output the current or given revision of files
1352 """output the current or given revision of files
1353
1353
1354 Print the specified files as they were at the given revision. If
1354 Print the specified files as they were at the given revision. If
1355 no revision is given, the parent of the working directory is used.
1355 no revision is given, the parent of the working directory is used.
1356
1356
1357 Output may be to a file, in which case the name of the file is
1357 Output may be to a file, in which case the name of the file is
1358 given using a template string. See :hg:`help templates`. In addition
1358 given using a template string. See :hg:`help templates`. In addition
1359 to the common template keywords, the following formatting rules are
1359 to the common template keywords, the following formatting rules are
1360 supported:
1360 supported:
1361
1361
1362 :``%%``: literal "%" character
1362 :``%%``: literal "%" character
1363 :``%s``: basename of file being printed
1363 :``%s``: basename of file being printed
1364 :``%d``: dirname of file being printed, or '.' if in repository root
1364 :``%d``: dirname of file being printed, or '.' if in repository root
1365 :``%p``: root-relative path name of file being printed
1365 :``%p``: root-relative path name of file being printed
1366 :``%H``: changeset hash (40 hexadecimal digits)
1366 :``%H``: changeset hash (40 hexadecimal digits)
1367 :``%R``: changeset revision number
1367 :``%R``: changeset revision number
1368 :``%h``: short-form changeset hash (12 hexadecimal digits)
1368 :``%h``: short-form changeset hash (12 hexadecimal digits)
1369 :``%r``: zero-padded changeset revision number
1369 :``%r``: zero-padded changeset revision number
1370 :``%b``: basename of the exporting repository
1370 :``%b``: basename of the exporting repository
1371 :``\\``: literal "\\" character
1371 :``\\``: literal "\\" character
1372
1372
1373 .. container:: verbose
1373 .. container:: verbose
1374
1374
1375 Template:
1375 Template:
1376
1376
1377 The following keywords are supported in addition to the common template
1377 The following keywords are supported in addition to the common template
1378 keywords and functions. See also :hg:`help templates`.
1378 keywords and functions. See also :hg:`help templates`.
1379
1379
1380 :data: String. File content.
1380 :data: String. File content.
1381 :path: String. Repository-absolute path of the file.
1381 :path: String. Repository-absolute path of the file.
1382
1382
1383 Returns 0 on success.
1383 Returns 0 on success.
1384 """
1384 """
1385 opts = pycompat.byteskwargs(opts)
1385 opts = pycompat.byteskwargs(opts)
1386 rev = opts.get('rev')
1386 rev = opts.get('rev')
1387 if rev:
1387 if rev:
1388 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1388 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1389 ctx = scmutil.revsingle(repo, rev)
1389 ctx = scmutil.revsingle(repo, rev)
1390 m = scmutil.match(ctx, (file1,) + pats, opts)
1390 m = scmutil.match(ctx, (file1,) + pats, opts)
1391 fntemplate = opts.pop('output', '')
1391 fntemplate = opts.pop('output', '')
1392 if cmdutil.isstdiofilename(fntemplate):
1392 if cmdutil.isstdiofilename(fntemplate):
1393 fntemplate = ''
1393 fntemplate = ''
1394
1394
1395 if fntemplate:
1395 if fntemplate:
1396 fm = formatter.nullformatter(ui, 'cat', opts)
1396 fm = formatter.nullformatter(ui, 'cat', opts)
1397 else:
1397 else:
1398 ui.pager('cat')
1398 ui.pager('cat')
1399 fm = ui.formatter('cat', opts)
1399 fm = ui.formatter('cat', opts)
1400 with fm:
1400 with fm:
1401 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1401 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1402 **pycompat.strkwargs(opts))
1402 **pycompat.strkwargs(opts))
1403
1403
1404 @command('clone',
1404 @command('clone',
1405 [('U', 'noupdate', None, _('the clone will include an empty working '
1405 [('U', 'noupdate', None, _('the clone will include an empty working '
1406 'directory (only a repository)')),
1406 'directory (only a repository)')),
1407 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1407 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1408 _('REV')),
1408 _('REV')),
1409 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1409 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1410 ' and its ancestors'), _('REV')),
1410 ' and its ancestors'), _('REV')),
1411 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1411 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1412 ' changesets and their ancestors'), _('BRANCH')),
1412 ' changesets and their ancestors'), _('BRANCH')),
1413 ('', 'pull', None, _('use pull protocol to copy metadata')),
1413 ('', 'pull', None, _('use pull protocol to copy metadata')),
1414 ('', 'uncompressed', None,
1414 ('', 'uncompressed', None,
1415 _('an alias to --stream (DEPRECATED)')),
1415 _('an alias to --stream (DEPRECATED)')),
1416 ('', 'stream', None,
1416 ('', 'stream', None,
1417 _('clone with minimal data processing')),
1417 _('clone with minimal data processing')),
1418 ] + remoteopts,
1418 ] + remoteopts,
1419 _('[OPTION]... SOURCE [DEST]'),
1419 _('[OPTION]... SOURCE [DEST]'),
1420 helpcategory=command.CATEGORY_REPO_CREATION,
1420 helpcategory=command.CATEGORY_REPO_CREATION,
1421 helpbasic=True, norepo=True)
1421 helpbasic=True, norepo=True)
1422 def clone(ui, source, dest=None, **opts):
1422 def clone(ui, source, dest=None, **opts):
1423 """make a copy of an existing repository
1423 """make a copy of an existing repository
1424
1424
1425 Create a copy of an existing repository in a new directory.
1425 Create a copy of an existing repository in a new directory.
1426
1426
1427 If no destination directory name is specified, it defaults to the
1427 If no destination directory name is specified, it defaults to the
1428 basename of the source.
1428 basename of the source.
1429
1429
1430 The location of the source is added to the new repository's
1430 The location of the source is added to the new repository's
1431 ``.hg/hgrc`` file, as the default to be used for future pulls.
1431 ``.hg/hgrc`` file, as the default to be used for future pulls.
1432
1432
1433 Only local paths and ``ssh://`` URLs are supported as
1433 Only local paths and ``ssh://`` URLs are supported as
1434 destinations. For ``ssh://`` destinations, no working directory or
1434 destinations. For ``ssh://`` destinations, no working directory or
1435 ``.hg/hgrc`` will be created on the remote side.
1435 ``.hg/hgrc`` will be created on the remote side.
1436
1436
1437 If the source repository has a bookmark called '@' set, that
1437 If the source repository has a bookmark called '@' set, that
1438 revision will be checked out in the new repository by default.
1438 revision will be checked out in the new repository by default.
1439
1439
1440 To check out a particular version, use -u/--update, or
1440 To check out a particular version, use -u/--update, or
1441 -U/--noupdate to create a clone with no working directory.
1441 -U/--noupdate to create a clone with no working directory.
1442
1442
1443 To pull only a subset of changesets, specify one or more revisions
1443 To pull only a subset of changesets, specify one or more revisions
1444 identifiers with -r/--rev or branches with -b/--branch. The
1444 identifiers with -r/--rev or branches with -b/--branch. The
1445 resulting clone will contain only the specified changesets and
1445 resulting clone will contain only the specified changesets and
1446 their ancestors. These options (or 'clone src#rev dest') imply
1446 their ancestors. These options (or 'clone src#rev dest') imply
1447 --pull, even for local source repositories.
1447 --pull, even for local source repositories.
1448
1448
1449 In normal clone mode, the remote normalizes repository data into a common
1449 In normal clone mode, the remote normalizes repository data into a common
1450 exchange format and the receiving end translates this data into its local
1450 exchange format and the receiving end translates this data into its local
1451 storage format. --stream activates a different clone mode that essentially
1451 storage format. --stream activates a different clone mode that essentially
1452 copies repository files from the remote with minimal data processing. This
1452 copies repository files from the remote with minimal data processing. This
1453 significantly reduces the CPU cost of a clone both remotely and locally.
1453 significantly reduces the CPU cost of a clone both remotely and locally.
1454 However, it often increases the transferred data size by 30-40%. This can
1454 However, it often increases the transferred data size by 30-40%. This can
1455 result in substantially faster clones where I/O throughput is plentiful,
1455 result in substantially faster clones where I/O throughput is plentiful,
1456 especially for larger repositories. A side-effect of --stream clones is
1456 especially for larger repositories. A side-effect of --stream clones is
1457 that storage settings and requirements on the remote are applied locally:
1457 that storage settings and requirements on the remote are applied locally:
1458 a modern client may inherit legacy or inefficient storage used by the
1458 a modern client may inherit legacy or inefficient storage used by the
1459 remote or a legacy Mercurial client may not be able to clone from a
1459 remote or a legacy Mercurial client may not be able to clone from a
1460 modern Mercurial remote.
1460 modern Mercurial remote.
1461
1461
1462 .. note::
1462 .. note::
1463
1463
1464 Specifying a tag will include the tagged changeset but not the
1464 Specifying a tag will include the tagged changeset but not the
1465 changeset containing the tag.
1465 changeset containing the tag.
1466
1466
1467 .. container:: verbose
1467 .. container:: verbose
1468
1468
1469 For efficiency, hardlinks are used for cloning whenever the
1469 For efficiency, hardlinks are used for cloning whenever the
1470 source and destination are on the same filesystem (note this
1470 source and destination are on the same filesystem (note this
1471 applies only to the repository data, not to the working
1471 applies only to the repository data, not to the working
1472 directory). Some filesystems, such as AFS, implement hardlinking
1472 directory). Some filesystems, such as AFS, implement hardlinking
1473 incorrectly, but do not report errors. In these cases, use the
1473 incorrectly, but do not report errors. In these cases, use the
1474 --pull option to avoid hardlinking.
1474 --pull option to avoid hardlinking.
1475
1475
1476 Mercurial will update the working directory to the first applicable
1476 Mercurial will update the working directory to the first applicable
1477 revision from this list:
1477 revision from this list:
1478
1478
1479 a) null if -U or the source repository has no changesets
1479 a) null if -U or the source repository has no changesets
1480 b) if -u . and the source repository is local, the first parent of
1480 b) if -u . and the source repository is local, the first parent of
1481 the source repository's working directory
1481 the source repository's working directory
1482 c) the changeset specified with -u (if a branch name, this means the
1482 c) the changeset specified with -u (if a branch name, this means the
1483 latest head of that branch)
1483 latest head of that branch)
1484 d) the changeset specified with -r
1484 d) the changeset specified with -r
1485 e) the tipmost head specified with -b
1485 e) the tipmost head specified with -b
1486 f) the tipmost head specified with the url#branch source syntax
1486 f) the tipmost head specified with the url#branch source syntax
1487 g) the revision marked with the '@' bookmark, if present
1487 g) the revision marked with the '@' bookmark, if present
1488 h) the tipmost head of the default branch
1488 h) the tipmost head of the default branch
1489 i) tip
1489 i) tip
1490
1490
1491 When cloning from servers that support it, Mercurial may fetch
1491 When cloning from servers that support it, Mercurial may fetch
1492 pre-generated data from a server-advertised URL or inline from the
1492 pre-generated data from a server-advertised URL or inline from the
1493 same stream. When this is done, hooks operating on incoming changesets
1493 same stream. When this is done, hooks operating on incoming changesets
1494 and changegroups may fire more than once, once for each pre-generated
1494 and changegroups may fire more than once, once for each pre-generated
1495 bundle and as well as for any additional remaining data. In addition,
1495 bundle and as well as for any additional remaining data. In addition,
1496 if an error occurs, the repository may be rolled back to a partial
1496 if an error occurs, the repository may be rolled back to a partial
1497 clone. This behavior may change in future releases.
1497 clone. This behavior may change in future releases.
1498 See :hg:`help -e clonebundles` for more.
1498 See :hg:`help -e clonebundles` for more.
1499
1499
1500 Examples:
1500 Examples:
1501
1501
1502 - clone a remote repository to a new directory named hg/::
1502 - clone a remote repository to a new directory named hg/::
1503
1503
1504 hg clone https://www.mercurial-scm.org/repo/hg/
1504 hg clone https://www.mercurial-scm.org/repo/hg/
1505
1505
1506 - create a lightweight local clone::
1506 - create a lightweight local clone::
1507
1507
1508 hg clone project/ project-feature/
1508 hg clone project/ project-feature/
1509
1509
1510 - clone from an absolute path on an ssh server (note double-slash)::
1510 - clone from an absolute path on an ssh server (note double-slash)::
1511
1511
1512 hg clone ssh://user@server//home/projects/alpha/
1512 hg clone ssh://user@server//home/projects/alpha/
1513
1513
1514 - do a streaming clone while checking out a specified version::
1514 - do a streaming clone while checking out a specified version::
1515
1515
1516 hg clone --stream http://server/repo -u 1.5
1516 hg clone --stream http://server/repo -u 1.5
1517
1517
1518 - create a repository without changesets after a particular revision::
1518 - create a repository without changesets after a particular revision::
1519
1519
1520 hg clone -r 04e544 experimental/ good/
1520 hg clone -r 04e544 experimental/ good/
1521
1521
1522 - clone (and track) a particular named branch::
1522 - clone (and track) a particular named branch::
1523
1523
1524 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1524 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1525
1525
1526 See :hg:`help urls` for details on specifying URLs.
1526 See :hg:`help urls` for details on specifying URLs.
1527
1527
1528 Returns 0 on success.
1528 Returns 0 on success.
1529 """
1529 """
1530 opts = pycompat.byteskwargs(opts)
1530 opts = pycompat.byteskwargs(opts)
1531 if opts.get('noupdate') and opts.get('updaterev'):
1531 if opts.get('noupdate') and opts.get('updaterev'):
1532 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1532 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1533
1533
1534 # --include/--exclude can come from narrow or sparse.
1534 # --include/--exclude can come from narrow or sparse.
1535 includepats, excludepats = None, None
1535 includepats, excludepats = None, None
1536
1536
1537 # hg.clone() differentiates between None and an empty set. So make sure
1537 # hg.clone() differentiates between None and an empty set. So make sure
1538 # patterns are sets if narrow is requested without patterns.
1538 # patterns are sets if narrow is requested without patterns.
1539 if opts.get('narrow'):
1539 if opts.get('narrow'):
1540 includepats = set()
1540 includepats = set()
1541 excludepats = set()
1541 excludepats = set()
1542
1542
1543 if opts.get('include'):
1543 if opts.get('include'):
1544 includepats = narrowspec.parsepatterns(opts.get('include'))
1544 includepats = narrowspec.parsepatterns(opts.get('include'))
1545 if opts.get('exclude'):
1545 if opts.get('exclude'):
1546 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1546 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1547
1547
1548 r = hg.clone(ui, opts, source, dest,
1548 r = hg.clone(ui, opts, source, dest,
1549 pull=opts.get('pull'),
1549 pull=opts.get('pull'),
1550 stream=opts.get('stream') or opts.get('uncompressed'),
1550 stream=opts.get('stream') or opts.get('uncompressed'),
1551 revs=opts.get('rev'),
1551 revs=opts.get('rev'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1553 branch=opts.get('branch'),
1553 branch=opts.get('branch'),
1554 shareopts=opts.get('shareopts'),
1554 shareopts=opts.get('shareopts'),
1555 storeincludepats=includepats,
1555 storeincludepats=includepats,
1556 storeexcludepats=excludepats,
1556 storeexcludepats=excludepats,
1557 depth=opts.get('depth') or None)
1557 depth=opts.get('depth') or None)
1558
1558
1559 return r is None
1559 return r is None
1560
1560
1561 @command('commit|ci',
1561 @command('commit|ci',
1562 [('A', 'addremove', None,
1562 [('A', 'addremove', None,
1563 _('mark new/missing files as added/removed before committing')),
1563 _('mark new/missing files as added/removed before committing')),
1564 ('', 'close-branch', None,
1564 ('', 'close-branch', None,
1565 _('mark a branch head as closed')),
1565 _('mark a branch head as closed')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1571 _('[OPTION]... [FILE]...'),
1571 _('[OPTION]... [FILE]...'),
1572 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1572 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1573 inferrepo=True)
1573 inferrepo=True)
1574 def commit(ui, repo, *pats, **opts):
1574 def commit(ui, repo, *pats, **opts):
1575 """commit the specified files or all outstanding changes
1575 """commit the specified files or all outstanding changes
1576
1576
1577 Commit changes to the given files into the repository. Unlike a
1577 Commit changes to the given files into the repository. Unlike a
1578 centralized SCM, this operation is a local operation. See
1578 centralized SCM, this operation is a local operation. See
1579 :hg:`push` for a way to actively distribute your changes.
1579 :hg:`push` for a way to actively distribute your changes.
1580
1580
1581 If a list of files is omitted, all changes reported by :hg:`status`
1581 If a list of files is omitted, all changes reported by :hg:`status`
1582 will be committed.
1582 will be committed.
1583
1583
1584 If you are committing the result of a merge, do not provide any
1584 If you are committing the result of a merge, do not provide any
1585 filenames or -I/-X filters.
1585 filenames or -I/-X filters.
1586
1586
1587 If no commit message is specified, Mercurial starts your
1587 If no commit message is specified, Mercurial starts your
1588 configured editor where you can enter a message. In case your
1588 configured editor where you can enter a message. In case your
1589 commit fails, you will find a backup of your message in
1589 commit fails, you will find a backup of your message in
1590 ``.hg/last-message.txt``.
1590 ``.hg/last-message.txt``.
1591
1591
1592 The --close-branch flag can be used to mark the current branch
1592 The --close-branch flag can be used to mark the current branch
1593 head closed. When all heads of a branch are closed, the branch
1593 head closed. When all heads of a branch are closed, the branch
1594 will be considered closed and no longer listed.
1594 will be considered closed and no longer listed.
1595
1595
1596 The --amend flag can be used to amend the parent of the
1596 The --amend flag can be used to amend the parent of the
1597 working directory with a new commit that contains the changes
1597 working directory with a new commit that contains the changes
1598 in the parent in addition to those currently reported by :hg:`status`,
1598 in the parent in addition to those currently reported by :hg:`status`,
1599 if there are any. The old commit is stored in a backup bundle in
1599 if there are any. The old commit is stored in a backup bundle in
1600 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1600 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1601 on how to restore it).
1601 on how to restore it).
1602
1602
1603 Message, user and date are taken from the amended commit unless
1603 Message, user and date are taken from the amended commit unless
1604 specified. When a message isn't specified on the command line,
1604 specified. When a message isn't specified on the command line,
1605 the editor will open with the message of the amended commit.
1605 the editor will open with the message of the amended commit.
1606
1606
1607 It is not possible to amend public changesets (see :hg:`help phases`)
1607 It is not possible to amend public changesets (see :hg:`help phases`)
1608 or changesets that have children.
1608 or changesets that have children.
1609
1609
1610 See :hg:`help dates` for a list of formats valid for -d/--date.
1610 See :hg:`help dates` for a list of formats valid for -d/--date.
1611
1611
1612 Returns 0 on success, 1 if nothing changed.
1612 Returns 0 on success, 1 if nothing changed.
1613
1613
1614 .. container:: verbose
1614 .. container:: verbose
1615
1615
1616 Examples:
1616 Examples:
1617
1617
1618 - commit all files ending in .py::
1618 - commit all files ending in .py::
1619
1619
1620 hg commit --include "set:**.py"
1620 hg commit --include "set:**.py"
1621
1621
1622 - commit all non-binary files::
1622 - commit all non-binary files::
1623
1623
1624 hg commit --exclude "set:binary()"
1624 hg commit --exclude "set:binary()"
1625
1625
1626 - amend the current commit and set the date to now::
1626 - amend the current commit and set the date to now::
1627
1627
1628 hg commit --amend --date now
1628 hg commit --amend --date now
1629 """
1629 """
1630 with repo.wlock(), repo.lock():
1630 with repo.wlock(), repo.lock():
1631 return _docommit(ui, repo, *pats, **opts)
1631 return _docommit(ui, repo, *pats, **opts)
1632
1632
1633 def _docommit(ui, repo, *pats, **opts):
1633 def _docommit(ui, repo, *pats, **opts):
1634 if opts.get(r'interactive'):
1634 if opts.get(r'interactive'):
1635 opts.pop(r'interactive')
1635 opts.pop(r'interactive')
1636 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1636 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1637 cmdutil.recordfilter, *pats,
1637 cmdutil.recordfilter, *pats,
1638 **opts)
1638 **opts)
1639 # ret can be 0 (no changes to record) or the value returned by
1639 # ret can be 0 (no changes to record) or the value returned by
1640 # commit(), 1 if nothing changed or None on success.
1640 # commit(), 1 if nothing changed or None on success.
1641 return 1 if ret == 0 else ret
1641 return 1 if ret == 0 else ret
1642
1642
1643 opts = pycompat.byteskwargs(opts)
1643 opts = pycompat.byteskwargs(opts)
1644 if opts.get('subrepos'):
1644 if opts.get('subrepos'):
1645 if opts.get('amend'):
1645 if opts.get('amend'):
1646 raise error.Abort(_('cannot amend with --subrepos'))
1646 raise error.Abort(_('cannot amend with --subrepos'))
1647 # Let --subrepos on the command line override config setting.
1647 # Let --subrepos on the command line override config setting.
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1649
1649
1650 cmdutil.checkunfinished(repo, commit=True)
1650 cmdutil.checkunfinished(repo, commit=True)
1651
1651
1652 branch = repo[None].branch()
1652 branch = repo[None].branch()
1653 bheads = repo.branchheads(branch)
1653 bheads = repo.branchheads(branch)
1654
1654
1655 extra = {}
1655 extra = {}
1656 if opts.get('close_branch'):
1656 if opts.get('close_branch'):
1657 extra['close'] = '1'
1657 extra['close'] = '1'
1658
1658
1659 if not bheads:
1659 if not bheads:
1660 raise error.Abort(_('can only close branch heads'))
1660 raise error.Abort(_('can only close branch heads'))
1661 elif opts.get('amend'):
1661 elif opts.get('amend'):
1662 if repo[None].parents()[0].p1().branch() != branch and \
1662 if repo[None].parents()[0].p1().branch() != branch and \
1663 repo[None].parents()[0].p2().branch() != branch:
1663 repo[None].parents()[0].p2().branch() != branch:
1664 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1665
1665
1666 if opts.get('amend'):
1666 if opts.get('amend'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1669
1669
1670 old = repo['.']
1670 old = repo['.']
1671 rewriteutil.precheck(repo, [old.rev()], 'amend')
1671 rewriteutil.precheck(repo, [old.rev()], 'amend')
1672
1672
1673 # Currently histedit gets confused if an amend happens while histedit
1673 # Currently histedit gets confused if an amend happens while histedit
1674 # is in progress. Since we have a checkunfinished command, we are
1674 # is in progress. Since we have a checkunfinished command, we are
1675 # temporarily honoring it.
1675 # temporarily honoring it.
1676 #
1676 #
1677 # Note: eventually this guard will be removed. Please do not expect
1677 # Note: eventually this guard will be removed. Please do not expect
1678 # this behavior to remain.
1678 # this behavior to remain.
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1680 cmdutil.checkunfinished(repo)
1680 cmdutil.checkunfinished(repo)
1681
1681
1682 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1682 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1683 if node == old.node():
1683 if node == old.node():
1684 ui.status(_("nothing changed\n"))
1684 ui.status(_("nothing changed\n"))
1685 return 1
1685 return 1
1686 else:
1686 else:
1687 def commitfunc(ui, repo, message, match, opts):
1687 def commitfunc(ui, repo, message, match, opts):
1688 overrides = {}
1688 overrides = {}
1689 if opts.get('secret'):
1689 if opts.get('secret'):
1690 overrides[('phases', 'new-commit')] = 'secret'
1690 overrides[('phases', 'new-commit')] = 'secret'
1691
1691
1692 baseui = repo.baseui
1692 baseui = repo.baseui
1693 with baseui.configoverride(overrides, 'commit'):
1693 with baseui.configoverride(overrides, 'commit'):
1694 with ui.configoverride(overrides, 'commit'):
1694 with ui.configoverride(overrides, 'commit'):
1695 editform = cmdutil.mergeeditform(repo[None],
1695 editform = cmdutil.mergeeditform(repo[None],
1696 'commit.normal')
1696 'commit.normal')
1697 editor = cmdutil.getcommiteditor(
1697 editor = cmdutil.getcommiteditor(
1698 editform=editform, **pycompat.strkwargs(opts))
1698 editform=editform, **pycompat.strkwargs(opts))
1699 return repo.commit(message,
1699 return repo.commit(message,
1700 opts.get('user'),
1700 opts.get('user'),
1701 opts.get('date'),
1701 opts.get('date'),
1702 match,
1702 match,
1703 editor=editor,
1703 editor=editor,
1704 extra=extra)
1704 extra=extra)
1705
1705
1706 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1706 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1707
1707
1708 if not node:
1708 if not node:
1709 stat = cmdutil.postcommitstatus(repo, pats, opts)
1709 stat = cmdutil.postcommitstatus(repo, pats, opts)
1710 if stat[3]:
1710 if stat[3]:
1711 ui.status(_("nothing changed (%d missing files, see "
1711 ui.status(_("nothing changed (%d missing files, see "
1712 "'hg status')\n") % len(stat[3]))
1712 "'hg status')\n") % len(stat[3]))
1713 else:
1713 else:
1714 ui.status(_("nothing changed\n"))
1714 ui.status(_("nothing changed\n"))
1715 return 1
1715 return 1
1716
1716
1717 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1717 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1718
1718
1719 @command('config|showconfig|debugconfig',
1719 @command('config|showconfig|debugconfig',
1720 [('u', 'untrusted', None, _('show untrusted configuration options')),
1720 [('u', 'untrusted', None, _('show untrusted configuration options')),
1721 ('e', 'edit', None, _('edit user config')),
1721 ('e', 'edit', None, _('edit user config')),
1722 ('l', 'local', None, _('edit repository config')),
1722 ('l', 'local', None, _('edit repository config')),
1723 ('g', 'global', None, _('edit global config'))] + formatteropts,
1723 ('g', 'global', None, _('edit global config'))] + formatteropts,
1724 _('[-u] [NAME]...'),
1724 _('[-u] [NAME]...'),
1725 helpcategory=command.CATEGORY_HELP,
1725 helpcategory=command.CATEGORY_HELP,
1726 optionalrepo=True,
1726 optionalrepo=True,
1727 intents={INTENT_READONLY})
1727 intents={INTENT_READONLY})
1728 def config(ui, repo, *values, **opts):
1728 def config(ui, repo, *values, **opts):
1729 """show combined config settings from all hgrc files
1729 """show combined config settings from all hgrc files
1730
1730
1731 With no arguments, print names and values of all config items.
1731 With no arguments, print names and values of all config items.
1732
1732
1733 With one argument of the form section.name, print just the value
1733 With one argument of the form section.name, print just the value
1734 of that config item.
1734 of that config item.
1735
1735
1736 With multiple arguments, print names and values of all config
1736 With multiple arguments, print names and values of all config
1737 items with matching section names or section.names.
1737 items with matching section names or section.names.
1738
1738
1739 With --edit, start an editor on the user-level config file. With
1739 With --edit, start an editor on the user-level config file. With
1740 --global, edit the system-wide config file. With --local, edit the
1740 --global, edit the system-wide config file. With --local, edit the
1741 repository-level config file.
1741 repository-level config file.
1742
1742
1743 With --debug, the source (filename and line number) is printed
1743 With --debug, the source (filename and line number) is printed
1744 for each config item.
1744 for each config item.
1745
1745
1746 See :hg:`help config` for more information about config files.
1746 See :hg:`help config` for more information about config files.
1747
1747
1748 .. container:: verbose
1748 .. container:: verbose
1749
1749
1750 Template:
1750 Template:
1751
1751
1752 The following keywords are supported. See also :hg:`help templates`.
1752 The following keywords are supported. See also :hg:`help templates`.
1753
1753
1754 :name: String. Config name.
1754 :name: String. Config name.
1755 :source: String. Filename and line number where the item is defined.
1755 :source: String. Filename and line number where the item is defined.
1756 :value: String. Config value.
1756 :value: String. Config value.
1757
1757
1758 Returns 0 on success, 1 if NAME does not exist.
1758 Returns 0 on success, 1 if NAME does not exist.
1759
1759
1760 """
1760 """
1761
1761
1762 opts = pycompat.byteskwargs(opts)
1762 opts = pycompat.byteskwargs(opts)
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1765 raise error.Abort(_("can't use --local and --global together"))
1765 raise error.Abort(_("can't use --local and --global together"))
1766
1766
1767 if opts.get('local'):
1767 if opts.get('local'):
1768 if not repo:
1768 if not repo:
1769 raise error.Abort(_("can't use --local outside a repository"))
1769 raise error.Abort(_("can't use --local outside a repository"))
1770 paths = [repo.vfs.join('hgrc')]
1770 paths = [repo.vfs.join('hgrc')]
1771 elif opts.get('global'):
1771 elif opts.get('global'):
1772 paths = rcutil.systemrcpath()
1772 paths = rcutil.systemrcpath()
1773 else:
1773 else:
1774 paths = rcutil.userrcpath()
1774 paths = rcutil.userrcpath()
1775
1775
1776 for f in paths:
1776 for f in paths:
1777 if os.path.exists(f):
1777 if os.path.exists(f):
1778 break
1778 break
1779 else:
1779 else:
1780 if opts.get('global'):
1780 if opts.get('global'):
1781 samplehgrc = uimod.samplehgrcs['global']
1781 samplehgrc = uimod.samplehgrcs['global']
1782 elif opts.get('local'):
1782 elif opts.get('local'):
1783 samplehgrc = uimod.samplehgrcs['local']
1783 samplehgrc = uimod.samplehgrcs['local']
1784 else:
1784 else:
1785 samplehgrc = uimod.samplehgrcs['user']
1785 samplehgrc = uimod.samplehgrcs['user']
1786
1786
1787 f = paths[0]
1787 f = paths[0]
1788 fp = open(f, "wb")
1788 fp = open(f, "wb")
1789 fp.write(util.tonativeeol(samplehgrc))
1789 fp.write(util.tonativeeol(samplehgrc))
1790 fp.close()
1790 fp.close()
1791
1791
1792 editor = ui.geteditor()
1792 editor = ui.geteditor()
1793 ui.system("%s \"%s\"" % (editor, f),
1793 ui.system("%s \"%s\"" % (editor, f),
1794 onerr=error.Abort, errprefix=_("edit failed"),
1794 onerr=error.Abort, errprefix=_("edit failed"),
1795 blockedtag='config_edit')
1795 blockedtag='config_edit')
1796 return
1796 return
1797 ui.pager('config')
1797 ui.pager('config')
1798 fm = ui.formatter('config', opts)
1798 fm = ui.formatter('config', opts)
1799 for t, f in rcutil.rccomponents():
1799 for t, f in rcutil.rccomponents():
1800 if t == 'path':
1800 if t == 'path':
1801 ui.debug('read config from: %s\n' % f)
1801 ui.debug('read config from: %s\n' % f)
1802 elif t == 'items':
1802 elif t == 'items':
1803 for section, name, value, source in f:
1803 for section, name, value, source in f:
1804 ui.debug('set config by: %s\n' % source)
1804 ui.debug('set config by: %s\n' % source)
1805 else:
1805 else:
1806 raise error.ProgrammingError('unknown rctype: %s' % t)
1806 raise error.ProgrammingError('unknown rctype: %s' % t)
1807 untrusted = bool(opts.get('untrusted'))
1807 untrusted = bool(opts.get('untrusted'))
1808
1808
1809 selsections = selentries = []
1809 selsections = selentries = []
1810 if values:
1810 if values:
1811 selsections = [v for v in values if '.' not in v]
1811 selsections = [v for v in values if '.' not in v]
1812 selentries = [v for v in values if '.' in v]
1812 selentries = [v for v in values if '.' in v]
1813 uniquesel = (len(selentries) == 1 and not selsections)
1813 uniquesel = (len(selentries) == 1 and not selsections)
1814 selsections = set(selsections)
1814 selsections = set(selsections)
1815 selentries = set(selentries)
1815 selentries = set(selentries)
1816
1816
1817 matched = False
1817 matched = False
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1819 source = ui.configsource(section, name, untrusted)
1819 source = ui.configsource(section, name, untrusted)
1820 value = pycompat.bytestr(value)
1820 value = pycompat.bytestr(value)
1821 if fm.isplain():
1821 if fm.isplain():
1822 source = source or 'none'
1822 source = source or 'none'
1823 value = value.replace('\n', '\\n')
1823 value = value.replace('\n', '\\n')
1824 entryname = section + '.' + name
1824 entryname = section + '.' + name
1825 if values and not (section in selsections or entryname in selentries):
1825 if values and not (section in selsections or entryname in selentries):
1826 continue
1826 continue
1827 fm.startitem()
1827 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 if uniquesel:
1829 if uniquesel:
1830 fm.data(name=entryname)
1830 fm.data(name=entryname)
1831 fm.write('value', '%s\n', value)
1831 fm.write('value', '%s\n', value)
1832 else:
1832 else:
1833 fm.write('name value', '%s=%s\n', entryname, value)
1833 fm.write('name value', '%s=%s\n', entryname, value)
1834 matched = True
1834 matched = True
1835 fm.end()
1835 fm.end()
1836 if matched:
1836 if matched:
1837 return 0
1837 return 0
1838 return 1
1838 return 1
1839
1839
1840 @command('copy|cp',
1840 @command('copy|cp',
1841 [('A', 'after', None, _('record a copy that has already occurred')),
1841 [('A', 'after', None, _('record a copy that has already occurred')),
1842 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1842 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1843 ] + walkopts + dryrunopts,
1843 ] + walkopts + dryrunopts,
1844 _('[OPTION]... [SOURCE]... DEST'),
1844 _('[OPTION]... [SOURCE]... DEST'),
1845 helpcategory=command.CATEGORY_FILE_CONTENTS)
1845 helpcategory=command.CATEGORY_FILE_CONTENTS)
1846 def copy(ui, repo, *pats, **opts):
1846 def copy(ui, repo, *pats, **opts):
1847 """mark files as copied for the next commit
1847 """mark files as copied for the next commit
1848
1848
1849 Mark dest as having copies of source files. If dest is a
1849 Mark dest as having copies of source files. If dest is a
1850 directory, copies are put in that directory. If dest is a file,
1850 directory, copies are put in that directory. If dest is a file,
1851 the source must be a single file.
1851 the source must be a single file.
1852
1852
1853 By default, this command copies the contents of files as they
1853 By default, this command copies the contents of files as they
1854 exist in the working directory. If invoked with -A/--after, the
1854 exist in the working directory. If invoked with -A/--after, the
1855 operation is recorded, but no copying is performed.
1855 operation is recorded, but no copying is performed.
1856
1856
1857 This command takes effect with the next commit. To undo a copy
1857 This command takes effect with the next commit. To undo a copy
1858 before that, see :hg:`revert`.
1858 before that, see :hg:`revert`.
1859
1859
1860 Returns 0 on success, 1 if errors are encountered.
1860 Returns 0 on success, 1 if errors are encountered.
1861 """
1861 """
1862 opts = pycompat.byteskwargs(opts)
1862 opts = pycompat.byteskwargs(opts)
1863 with repo.wlock(False):
1863 with repo.wlock(False):
1864 return cmdutil.copy(ui, repo, pats, opts)
1864 return cmdutil.copy(ui, repo, pats, opts)
1865
1865
1866 @command(
1866 @command(
1867 'debugcommands', [], _('[COMMAND]'),
1867 'debugcommands', [], _('[COMMAND]'),
1868 helpcategory=command.CATEGORY_HELP,
1868 helpcategory=command.CATEGORY_HELP,
1869 norepo=True)
1869 norepo=True)
1870 def debugcommands(ui, cmd='', *args):
1870 def debugcommands(ui, cmd='', *args):
1871 """list all available commands and options"""
1871 """list all available commands and options"""
1872 for cmd, vals in sorted(table.iteritems()):
1872 for cmd, vals in sorted(table.iteritems()):
1873 cmd = cmd.split('|')[0]
1873 cmd = cmd.split('|')[0]
1874 opts = ', '.join([i[1] for i in vals[1]])
1874 opts = ', '.join([i[1] for i in vals[1]])
1875 ui.write('%s: %s\n' % (cmd, opts))
1875 ui.write('%s: %s\n' % (cmd, opts))
1876
1876
1877 @command('debugcomplete',
1877 @command('debugcomplete',
1878 [('o', 'options', None, _('show the command options'))],
1878 [('o', 'options', None, _('show the command options'))],
1879 _('[-o] CMD'),
1879 _('[-o] CMD'),
1880 helpcategory=command.CATEGORY_HELP,
1880 helpcategory=command.CATEGORY_HELP,
1881 norepo=True)
1881 norepo=True)
1882 def debugcomplete(ui, cmd='', **opts):
1882 def debugcomplete(ui, cmd='', **opts):
1883 """returns the completion list associated with the given command"""
1883 """returns the completion list associated with the given command"""
1884
1884
1885 if opts.get(r'options'):
1885 if opts.get(r'options'):
1886 options = []
1886 options = []
1887 otables = [globalopts]
1887 otables = [globalopts]
1888 if cmd:
1888 if cmd:
1889 aliases, entry = cmdutil.findcmd(cmd, table, False)
1889 aliases, entry = cmdutil.findcmd(cmd, table, False)
1890 otables.append(entry[1])
1890 otables.append(entry[1])
1891 for t in otables:
1891 for t in otables:
1892 for o in t:
1892 for o in t:
1893 if "(DEPRECATED)" in o[3]:
1893 if "(DEPRECATED)" in o[3]:
1894 continue
1894 continue
1895 if o[0]:
1895 if o[0]:
1896 options.append('-%s' % o[0])
1896 options.append('-%s' % o[0])
1897 options.append('--%s' % o[1])
1897 options.append('--%s' % o[1])
1898 ui.write("%s\n" % "\n".join(options))
1898 ui.write("%s\n" % "\n".join(options))
1899 return
1899 return
1900
1900
1901 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1901 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1902 if ui.verbose:
1902 if ui.verbose:
1903 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1903 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1904 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1904 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1905
1905
1906 @command('diff',
1906 @command('diff',
1907 [('r', 'rev', [], _('revision'), _('REV')),
1907 [('r', 'rev', [], _('revision'), _('REV')),
1908 ('c', 'change', '', _('change made by revision'), _('REV'))
1908 ('c', 'change', '', _('change made by revision'), _('REV'))
1909 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1909 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1910 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1910 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1911 helpcategory=command.CATEGORY_FILE_CONTENTS,
1911 helpcategory=command.CATEGORY_FILE_CONTENTS,
1912 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1912 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1913 def diff(ui, repo, *pats, **opts):
1913 def diff(ui, repo, *pats, **opts):
1914 """diff repository (or selected files)
1914 """diff repository (or selected files)
1915
1915
1916 Show differences between revisions for the specified files.
1916 Show differences between revisions for the specified files.
1917
1917
1918 Differences between files are shown using the unified diff format.
1918 Differences between files are shown using the unified diff format.
1919
1919
1920 .. note::
1920 .. note::
1921
1921
1922 :hg:`diff` may generate unexpected results for merges, as it will
1922 :hg:`diff` may generate unexpected results for merges, as it will
1923 default to comparing against the working directory's first
1923 default to comparing against the working directory's first
1924 parent changeset if no revisions are specified.
1924 parent changeset if no revisions are specified.
1925
1925
1926 When two revision arguments are given, then changes are shown
1926 When two revision arguments are given, then changes are shown
1927 between those revisions. If only one revision is specified then
1927 between those revisions. If only one revision is specified then
1928 that revision is compared to the working directory, and, when no
1928 that revision is compared to the working directory, and, when no
1929 revisions are specified, the working directory files are compared
1929 revisions are specified, the working directory files are compared
1930 to its first parent.
1930 to its first parent.
1931
1931
1932 Alternatively you can specify -c/--change with a revision to see
1932 Alternatively you can specify -c/--change with a revision to see
1933 the changes in that changeset relative to its first parent.
1933 the changes in that changeset relative to its first parent.
1934
1934
1935 Without the -a/--text option, diff will avoid generating diffs of
1935 Without the -a/--text option, diff will avoid generating diffs of
1936 files it detects as binary. With -a, diff will generate a diff
1936 files it detects as binary. With -a, diff will generate a diff
1937 anyway, probably with undesirable results.
1937 anyway, probably with undesirable results.
1938
1938
1939 Use the -g/--git option to generate diffs in the git extended diff
1939 Use the -g/--git option to generate diffs in the git extended diff
1940 format. For more information, read :hg:`help diffs`.
1940 format. For more information, read :hg:`help diffs`.
1941
1941
1942 .. container:: verbose
1942 .. container:: verbose
1943
1943
1944 Examples:
1944 Examples:
1945
1945
1946 - compare a file in the current working directory to its parent::
1946 - compare a file in the current working directory to its parent::
1947
1947
1948 hg diff foo.c
1948 hg diff foo.c
1949
1949
1950 - compare two historical versions of a directory, with rename info::
1950 - compare two historical versions of a directory, with rename info::
1951
1951
1952 hg diff --git -r 1.0:1.2 lib/
1952 hg diff --git -r 1.0:1.2 lib/
1953
1953
1954 - get change stats relative to the last change on some date::
1954 - get change stats relative to the last change on some date::
1955
1955
1956 hg diff --stat -r "date('may 2')"
1956 hg diff --stat -r "date('may 2')"
1957
1957
1958 - diff all newly-added files that contain a keyword::
1958 - diff all newly-added files that contain a keyword::
1959
1959
1960 hg diff "set:added() and grep(GNU)"
1960 hg diff "set:added() and grep(GNU)"
1961
1961
1962 - compare a revision and its parents::
1962 - compare a revision and its parents::
1963
1963
1964 hg diff -c 9353 # compare against first parent
1964 hg diff -c 9353 # compare against first parent
1965 hg diff -r 9353^:9353 # same using revset syntax
1965 hg diff -r 9353^:9353 # same using revset syntax
1966 hg diff -r 9353^2:9353 # compare against the second parent
1966 hg diff -r 9353^2:9353 # compare against the second parent
1967
1967
1968 Returns 0 on success.
1968 Returns 0 on success.
1969 """
1969 """
1970
1970
1971 opts = pycompat.byteskwargs(opts)
1971 opts = pycompat.byteskwargs(opts)
1972 revs = opts.get('rev')
1972 revs = opts.get('rev')
1973 change = opts.get('change')
1973 change = opts.get('change')
1974 stat = opts.get('stat')
1974 stat = opts.get('stat')
1975 reverse = opts.get('reverse')
1975 reverse = opts.get('reverse')
1976
1976
1977 if revs and change:
1977 if revs and change:
1978 msg = _('cannot specify --rev and --change at the same time')
1978 msg = _('cannot specify --rev and --change at the same time')
1979 raise error.Abort(msg)
1979 raise error.Abort(msg)
1980 elif change:
1980 elif change:
1981 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1981 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1982 ctx2 = scmutil.revsingle(repo, change, None)
1982 ctx2 = scmutil.revsingle(repo, change, None)
1983 ctx1 = ctx2.p1()
1983 ctx1 = ctx2.p1()
1984 else:
1984 else:
1985 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1985 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1986 ctx1, ctx2 = scmutil.revpair(repo, revs)
1986 ctx1, ctx2 = scmutil.revpair(repo, revs)
1987 node1, node2 = ctx1.node(), ctx2.node()
1987 node1, node2 = ctx1.node(), ctx2.node()
1988
1988
1989 if reverse:
1989 if reverse:
1990 node1, node2 = node2, node1
1990 node1, node2 = node2, node1
1991
1991
1992 diffopts = patch.diffallopts(ui, opts)
1992 diffopts = patch.diffallopts(ui, opts)
1993 m = scmutil.match(ctx2, pats, opts)
1993 m = scmutil.match(ctx2, pats, opts)
1994 m = repo.narrowmatch(m)
1994 m = repo.narrowmatch(m)
1995 ui.pager('diff')
1995 ui.pager('diff')
1996 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1996 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1997 listsubrepos=opts.get('subrepos'),
1997 listsubrepos=opts.get('subrepos'),
1998 root=opts.get('root'))
1998 root=opts.get('root'))
1999
1999
2000 @command('export',
2000 @command('export',
2001 [('B', 'bookmark', '',
2001 [('B', 'bookmark', '',
2002 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2002 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2003 ('o', 'output', '',
2003 ('o', 'output', '',
2004 _('print output to file with formatted name'), _('FORMAT')),
2004 _('print output to file with formatted name'), _('FORMAT')),
2005 ('', 'switch-parent', None, _('diff against the second parent')),
2005 ('', 'switch-parent', None, _('diff against the second parent')),
2006 ('r', 'rev', [], _('revisions to export'), _('REV')),
2006 ('r', 'rev', [], _('revisions to export'), _('REV')),
2007 ] + diffopts + formatteropts,
2007 ] + diffopts + formatteropts,
2008 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2008 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2009 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2009 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2010 helpbasic=True, intents={INTENT_READONLY})
2010 helpbasic=True, intents={INTENT_READONLY})
2011 def export(ui, repo, *changesets, **opts):
2011 def export(ui, repo, *changesets, **opts):
2012 """dump the header and diffs for one or more changesets
2012 """dump the header and diffs for one or more changesets
2013
2013
2014 Print the changeset header and diffs for one or more revisions.
2014 Print the changeset header and diffs for one or more revisions.
2015 If no revision is given, the parent of the working directory is used.
2015 If no revision is given, the parent of the working directory is used.
2016
2016
2017 The information shown in the changeset header is: author, date,
2017 The information shown in the changeset header is: author, date,
2018 branch name (if non-default), changeset hash, parent(s) and commit
2018 branch name (if non-default), changeset hash, parent(s) and commit
2019 comment.
2019 comment.
2020
2020
2021 .. note::
2021 .. note::
2022
2022
2023 :hg:`export` may generate unexpected diff output for merge
2023 :hg:`export` may generate unexpected diff output for merge
2024 changesets, as it will compare the merge changeset against its
2024 changesets, as it will compare the merge changeset against its
2025 first parent only.
2025 first parent only.
2026
2026
2027 Output may be to a file, in which case the name of the file is
2027 Output may be to a file, in which case the name of the file is
2028 given using a template string. See :hg:`help templates`. In addition
2028 given using a template string. See :hg:`help templates`. In addition
2029 to the common template keywords, the following formatting rules are
2029 to the common template keywords, the following formatting rules are
2030 supported:
2030 supported:
2031
2031
2032 :``%%``: literal "%" character
2032 :``%%``: literal "%" character
2033 :``%H``: changeset hash (40 hexadecimal digits)
2033 :``%H``: changeset hash (40 hexadecimal digits)
2034 :``%N``: number of patches being generated
2034 :``%N``: number of patches being generated
2035 :``%R``: changeset revision number
2035 :``%R``: changeset revision number
2036 :``%b``: basename of the exporting repository
2036 :``%b``: basename of the exporting repository
2037 :``%h``: short-form changeset hash (12 hexadecimal digits)
2037 :``%h``: short-form changeset hash (12 hexadecimal digits)
2038 :``%m``: first line of the commit message (only alphanumeric characters)
2038 :``%m``: first line of the commit message (only alphanumeric characters)
2039 :``%n``: zero-padded sequence number, starting at 1
2039 :``%n``: zero-padded sequence number, starting at 1
2040 :``%r``: zero-padded changeset revision number
2040 :``%r``: zero-padded changeset revision number
2041 :``\\``: literal "\\" character
2041 :``\\``: literal "\\" character
2042
2042
2043 Without the -a/--text option, export will avoid generating diffs
2043 Without the -a/--text option, export will avoid generating diffs
2044 of files it detects as binary. With -a, export will generate a
2044 of files it detects as binary. With -a, export will generate a
2045 diff anyway, probably with undesirable results.
2045 diff anyway, probably with undesirable results.
2046
2046
2047 With -B/--bookmark changesets reachable by the given bookmark are
2047 With -B/--bookmark changesets reachable by the given bookmark are
2048 selected.
2048 selected.
2049
2049
2050 Use the -g/--git option to generate diffs in the git extended diff
2050 Use the -g/--git option to generate diffs in the git extended diff
2051 format. See :hg:`help diffs` for more information.
2051 format. See :hg:`help diffs` for more information.
2052
2052
2053 With the --switch-parent option, the diff will be against the
2053 With the --switch-parent option, the diff will be against the
2054 second parent. It can be useful to review a merge.
2054 second parent. It can be useful to review a merge.
2055
2055
2056 .. container:: verbose
2056 .. container:: verbose
2057
2057
2058 Template:
2058 Template:
2059
2059
2060 The following keywords are supported in addition to the common template
2060 The following keywords are supported in addition to the common template
2061 keywords and functions. See also :hg:`help templates`.
2061 keywords and functions. See also :hg:`help templates`.
2062
2062
2063 :diff: String. Diff content.
2063 :diff: String. Diff content.
2064 :parents: List of strings. Parent nodes of the changeset.
2064 :parents: List of strings. Parent nodes of the changeset.
2065
2065
2066 Examples:
2066 Examples:
2067
2067
2068 - use export and import to transplant a bugfix to the current
2068 - use export and import to transplant a bugfix to the current
2069 branch::
2069 branch::
2070
2070
2071 hg export -r 9353 | hg import -
2071 hg export -r 9353 | hg import -
2072
2072
2073 - export all the changesets between two revisions to a file with
2073 - export all the changesets between two revisions to a file with
2074 rename information::
2074 rename information::
2075
2075
2076 hg export --git -r 123:150 > changes.txt
2076 hg export --git -r 123:150 > changes.txt
2077
2077
2078 - split outgoing changes into a series of patches with
2078 - split outgoing changes into a series of patches with
2079 descriptive names::
2079 descriptive names::
2080
2080
2081 hg export -r "outgoing()" -o "%n-%m.patch"
2081 hg export -r "outgoing()" -o "%n-%m.patch"
2082
2082
2083 Returns 0 on success.
2083 Returns 0 on success.
2084 """
2084 """
2085 opts = pycompat.byteskwargs(opts)
2085 opts = pycompat.byteskwargs(opts)
2086 bookmark = opts.get('bookmark')
2086 bookmark = opts.get('bookmark')
2087 changesets += tuple(opts.get('rev', []))
2087 changesets += tuple(opts.get('rev', []))
2088
2088
2089 if bookmark and changesets:
2089 if bookmark and changesets:
2090 raise error.Abort(_("-r and -B are mutually exclusive"))
2090 raise error.Abort(_("-r and -B are mutually exclusive"))
2091
2091
2092 if bookmark:
2092 if bookmark:
2093 if bookmark not in repo._bookmarks:
2093 if bookmark not in repo._bookmarks:
2094 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2094 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2095
2095
2096 revs = scmutil.bookmarkrevs(repo, bookmark)
2096 revs = scmutil.bookmarkrevs(repo, bookmark)
2097 else:
2097 else:
2098 if not changesets:
2098 if not changesets:
2099 changesets = ['.']
2099 changesets = ['.']
2100
2100
2101 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2101 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2102 revs = scmutil.revrange(repo, changesets)
2102 revs = scmutil.revrange(repo, changesets)
2103
2103
2104 if not revs:
2104 if not revs:
2105 raise error.Abort(_("export requires at least one changeset"))
2105 raise error.Abort(_("export requires at least one changeset"))
2106 if len(revs) > 1:
2106 if len(revs) > 1:
2107 ui.note(_('exporting patches:\n'))
2107 ui.note(_('exporting patches:\n'))
2108 else:
2108 else:
2109 ui.note(_('exporting patch:\n'))
2109 ui.note(_('exporting patch:\n'))
2110
2110
2111 fntemplate = opts.get('output')
2111 fntemplate = opts.get('output')
2112 if cmdutil.isstdiofilename(fntemplate):
2112 if cmdutil.isstdiofilename(fntemplate):
2113 fntemplate = ''
2113 fntemplate = ''
2114
2114
2115 if fntemplate:
2115 if fntemplate:
2116 fm = formatter.nullformatter(ui, 'export', opts)
2116 fm = formatter.nullformatter(ui, 'export', opts)
2117 else:
2117 else:
2118 ui.pager('export')
2118 ui.pager('export')
2119 fm = ui.formatter('export', opts)
2119 fm = ui.formatter('export', opts)
2120 with fm:
2120 with fm:
2121 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2121 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2122 switch_parent=opts.get('switch_parent'),
2122 switch_parent=opts.get('switch_parent'),
2123 opts=patch.diffallopts(ui, opts))
2123 opts=patch.diffallopts(ui, opts))
2124
2124
2125 @command('files',
2125 @command('files',
2126 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2126 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2127 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2127 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2128 ] + walkopts + formatteropts + subrepoopts,
2128 ] + walkopts + formatteropts + subrepoopts,
2129 _('[OPTION]... [FILE]...'),
2129 _('[OPTION]... [FILE]...'),
2130 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2130 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2131 intents={INTENT_READONLY})
2131 intents={INTENT_READONLY})
2132 def files(ui, repo, *pats, **opts):
2132 def files(ui, repo, *pats, **opts):
2133 """list tracked files
2133 """list tracked files
2134
2134
2135 Print files under Mercurial control in the working directory or
2135 Print files under Mercurial control in the working directory or
2136 specified revision for given files (excluding removed files).
2136 specified revision for given files (excluding removed files).
2137 Files can be specified as filenames or filesets.
2137 Files can be specified as filenames or filesets.
2138
2138
2139 If no files are given to match, this command prints the names
2139 If no files are given to match, this command prints the names
2140 of all files under Mercurial control.
2140 of all files under Mercurial control.
2141
2141
2142 .. container:: verbose
2142 .. container:: verbose
2143
2143
2144 Template:
2144 Template:
2145
2145
2146 The following keywords are supported in addition to the common template
2146 The following keywords are supported in addition to the common template
2147 keywords and functions. See also :hg:`help templates`.
2147 keywords and functions. See also :hg:`help templates`.
2148
2148
2149 :flags: String. Character denoting file's symlink and executable bits.
2149 :flags: String. Character denoting file's symlink and executable bits.
2150 :path: String. Repository-absolute path of the file.
2150 :path: String. Repository-absolute path of the file.
2151 :size: Integer. Size of the file in bytes.
2151 :size: Integer. Size of the file in bytes.
2152
2152
2153 Examples:
2153 Examples:
2154
2154
2155 - list all files under the current directory::
2155 - list all files under the current directory::
2156
2156
2157 hg files .
2157 hg files .
2158
2158
2159 - shows sizes and flags for current revision::
2159 - shows sizes and flags for current revision::
2160
2160
2161 hg files -vr .
2161 hg files -vr .
2162
2162
2163 - list all files named README::
2163 - list all files named README::
2164
2164
2165 hg files -I "**/README"
2165 hg files -I "**/README"
2166
2166
2167 - list all binary files::
2167 - list all binary files::
2168
2168
2169 hg files "set:binary()"
2169 hg files "set:binary()"
2170
2170
2171 - find files containing a regular expression::
2171 - find files containing a regular expression::
2172
2172
2173 hg files "set:grep('bob')"
2173 hg files "set:grep('bob')"
2174
2174
2175 - search tracked file contents with xargs and grep::
2175 - search tracked file contents with xargs and grep::
2176
2176
2177 hg files -0 | xargs -0 grep foo
2177 hg files -0 | xargs -0 grep foo
2178
2178
2179 See :hg:`help patterns` and :hg:`help filesets` for more information
2179 See :hg:`help patterns` and :hg:`help filesets` for more information
2180 on specifying file patterns.
2180 on specifying file patterns.
2181
2181
2182 Returns 0 if a match is found, 1 otherwise.
2182 Returns 0 if a match is found, 1 otherwise.
2183
2183
2184 """
2184 """
2185
2185
2186 opts = pycompat.byteskwargs(opts)
2186 opts = pycompat.byteskwargs(opts)
2187 rev = opts.get('rev')
2187 rev = opts.get('rev')
2188 if rev:
2188 if rev:
2189 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2189 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2190 ctx = scmutil.revsingle(repo, rev, None)
2190 ctx = scmutil.revsingle(repo, rev, None)
2191
2191
2192 end = '\n'
2192 end = '\n'
2193 if opts.get('print0'):
2193 if opts.get('print0'):
2194 end = '\0'
2194 end = '\0'
2195 fmt = '%s' + end
2195 fmt = '%s' + end
2196
2196
2197 m = scmutil.match(ctx, pats, opts)
2197 m = scmutil.match(ctx, pats, opts)
2198 ui.pager('files')
2198 ui.pager('files')
2199 with ui.formatter('files', opts) as fm:
2199 with ui.formatter('files', opts) as fm:
2200 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2200 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2201
2201
2202 @command(
2202 @command(
2203 'forget',
2203 'forget',
2204 [('i', 'interactive', None, _('use interactive mode')),
2204 [('i', 'interactive', None, _('use interactive mode')),
2205 ] + walkopts + dryrunopts,
2205 ] + walkopts + dryrunopts,
2206 _('[OPTION]... FILE...'),
2206 _('[OPTION]... FILE...'),
2207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2208 helpbasic=True, inferrepo=True)
2208 helpbasic=True, inferrepo=True)
2209 def forget(ui, repo, *pats, **opts):
2209 def forget(ui, repo, *pats, **opts):
2210 """forget the specified files on the next commit
2210 """forget the specified files on the next commit
2211
2211
2212 Mark the specified files so they will no longer be tracked
2212 Mark the specified files so they will no longer be tracked
2213 after the next commit.
2213 after the next commit.
2214
2214
2215 This only removes files from the current branch, not from the
2215 This only removes files from the current branch, not from the
2216 entire project history, and it does not delete them from the
2216 entire project history, and it does not delete them from the
2217 working directory.
2217 working directory.
2218
2218
2219 To delete the file from the working directory, see :hg:`remove`.
2219 To delete the file from the working directory, see :hg:`remove`.
2220
2220
2221 To undo a forget before the next commit, see :hg:`add`.
2221 To undo a forget before the next commit, see :hg:`add`.
2222
2222
2223 .. container:: verbose
2223 .. container:: verbose
2224
2224
2225 Examples:
2225 Examples:
2226
2226
2227 - forget newly-added binary files::
2227 - forget newly-added binary files::
2228
2228
2229 hg forget "set:added() and binary()"
2229 hg forget "set:added() and binary()"
2230
2230
2231 - forget files that would be excluded by .hgignore::
2231 - forget files that would be excluded by .hgignore::
2232
2232
2233 hg forget "set:hgignore()"
2233 hg forget "set:hgignore()"
2234
2234
2235 Returns 0 on success.
2235 Returns 0 on success.
2236 """
2236 """
2237
2237
2238 opts = pycompat.byteskwargs(opts)
2238 opts = pycompat.byteskwargs(opts)
2239 if not pats:
2239 if not pats:
2240 raise error.Abort(_('no files specified'))
2240 raise error.Abort(_('no files specified'))
2241
2241
2242 m = scmutil.match(repo[None], pats, opts)
2242 m = scmutil.match(repo[None], pats, opts)
2243 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2243 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2244 rejected = cmdutil.forget(ui, repo, m, prefix="",
2244 rejected = cmdutil.forget(ui, repo, m, prefix="",
2245 explicitonly=False, dryrun=dryrun,
2245 explicitonly=False, dryrun=dryrun,
2246 interactive=interactive)[0]
2246 interactive=interactive)[0]
2247 return rejected and 1 or 0
2247 return rejected and 1 or 0
2248
2248
2249 @command(
2249 @command(
2250 'graft',
2250 'graft',
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2252 ('c', 'continue', False, _('resume interrupted graft')),
2252 ('c', 'continue', False, _('resume interrupted graft')),
2253 ('', 'stop', False, _('stop interrupted graft')),
2253 ('', 'stop', False, _('stop interrupted graft')),
2254 ('', 'abort', False, _('abort interrupted graft')),
2254 ('', 'abort', False, _('abort interrupted graft')),
2255 ('e', 'edit', False, _('invoke editor on commit messages')),
2255 ('e', 'edit', False, _('invoke editor on commit messages')),
2256 ('', 'log', None, _('append graft info to log message')),
2256 ('', 'log', None, _('append graft info to log message')),
2257 ('', 'no-commit', None,
2257 ('', 'no-commit', None,
2258 _("don't commit, just apply the changes in working directory")),
2258 _("don't commit, just apply the changes in working directory")),
2259 ('f', 'force', False, _('force graft')),
2259 ('f', 'force', False, _('force graft')),
2260 ('D', 'currentdate', False,
2260 ('D', 'currentdate', False,
2261 _('record the current date as commit date')),
2261 _('record the current date as commit date')),
2262 ('U', 'currentuser', False,
2262 ('U', 'currentuser', False,
2263 _('record the current user as committer'))]
2263 _('record the current user as committer'))]
2264 + commitopts2 + mergetoolopts + dryrunopts,
2264 + commitopts2 + mergetoolopts + dryrunopts,
2265 _('[OPTION]... [-r REV]... REV...'),
2265 _('[OPTION]... [-r REV]... REV...'),
2266 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2266 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2267 def graft(ui, repo, *revs, **opts):
2267 def graft(ui, repo, *revs, **opts):
2268 '''copy changes from other branches onto the current branch
2268 '''copy changes from other branches onto the current branch
2269
2269
2270 This command uses Mercurial's merge logic to copy individual
2270 This command uses Mercurial's merge logic to copy individual
2271 changes from other branches without merging branches in the
2271 changes from other branches without merging branches in the
2272 history graph. This is sometimes known as 'backporting' or
2272 history graph. This is sometimes known as 'backporting' or
2273 'cherry-picking'. By default, graft will copy user, date, and
2273 'cherry-picking'. By default, graft will copy user, date, and
2274 description from the source changesets.
2274 description from the source changesets.
2275
2275
2276 Changesets that are ancestors of the current revision, that have
2276 Changesets that are ancestors of the current revision, that have
2277 already been grafted, or that are merges will be skipped.
2277 already been grafted, or that are merges will be skipped.
2278
2278
2279 If --log is specified, log messages will have a comment appended
2279 If --log is specified, log messages will have a comment appended
2280 of the form::
2280 of the form::
2281
2281
2282 (grafted from CHANGESETHASH)
2282 (grafted from CHANGESETHASH)
2283
2283
2284 If --force is specified, revisions will be grafted even if they
2284 If --force is specified, revisions will be grafted even if they
2285 are already ancestors of, or have been grafted to, the destination.
2285 are already ancestors of, or have been grafted to, the destination.
2286 This is useful when the revisions have since been backed out.
2286 This is useful when the revisions have since been backed out.
2287
2287
2288 If a graft merge results in conflicts, the graft process is
2288 If a graft merge results in conflicts, the graft process is
2289 interrupted so that the current merge can be manually resolved.
2289 interrupted so that the current merge can be manually resolved.
2290 Once all conflicts are addressed, the graft process can be
2290 Once all conflicts are addressed, the graft process can be
2291 continued with the -c/--continue option.
2291 continued with the -c/--continue option.
2292
2292
2293 The -c/--continue option reapplies all the earlier options.
2293 The -c/--continue option reapplies all the earlier options.
2294
2294
2295 .. container:: verbose
2295 .. container:: verbose
2296
2296
2297 Examples:
2297 Examples:
2298
2298
2299 - copy a single change to the stable branch and edit its description::
2299 - copy a single change to the stable branch and edit its description::
2300
2300
2301 hg update stable
2301 hg update stable
2302 hg graft --edit 9393
2302 hg graft --edit 9393
2303
2303
2304 - graft a range of changesets with one exception, updating dates::
2304 - graft a range of changesets with one exception, updating dates::
2305
2305
2306 hg graft -D "2085::2093 and not 2091"
2306 hg graft -D "2085::2093 and not 2091"
2307
2307
2308 - continue a graft after resolving conflicts::
2308 - continue a graft after resolving conflicts::
2309
2309
2310 hg graft -c
2310 hg graft -c
2311
2311
2312 - show the source of a grafted changeset::
2312 - show the source of a grafted changeset::
2313
2313
2314 hg log --debug -r .
2314 hg log --debug -r .
2315
2315
2316 - show revisions sorted by date::
2316 - show revisions sorted by date::
2317
2317
2318 hg log -r "sort(all(), date)"
2318 hg log -r "sort(all(), date)"
2319
2319
2320 See :hg:`help revisions` for more about specifying revisions.
2320 See :hg:`help revisions` for more about specifying revisions.
2321
2321
2322 Returns 0 on successful completion.
2322 Returns 0 on successful completion.
2323 '''
2323 '''
2324 with repo.wlock():
2324 with repo.wlock():
2325 return _dograft(ui, repo, *revs, **opts)
2325 return _dograft(ui, repo, *revs, **opts)
2326
2326
2327 def _dograft(ui, repo, *revs, **opts):
2327 def _dograft(ui, repo, *revs, **opts):
2328 opts = pycompat.byteskwargs(opts)
2328 opts = pycompat.byteskwargs(opts)
2329 if revs and opts.get('rev'):
2329 if revs and opts.get('rev'):
2330 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2330 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2331 'revision ordering!\n'))
2331 'revision ordering!\n'))
2332
2332
2333 revs = list(revs)
2333 revs = list(revs)
2334 revs.extend(opts.get('rev'))
2334 revs.extend(opts.get('rev'))
2335 # a dict of data to be stored in state file
2335 # a dict of data to be stored in state file
2336 statedata = {}
2336 statedata = {}
2337 # list of new nodes created by ongoing graft
2337 # list of new nodes created by ongoing graft
2338 statedata['newnodes'] = []
2338 statedata['newnodes'] = []
2339
2339
2340 if not opts.get('user') and opts.get('currentuser'):
2340 if not opts.get('user') and opts.get('currentuser'):
2341 opts['user'] = ui.username()
2341 opts['user'] = ui.username()
2342 if not opts.get('date') and opts.get('currentdate'):
2342 if not opts.get('date') and opts.get('currentdate'):
2343 opts['date'] = "%d %d" % dateutil.makedate()
2343 opts['date'] = "%d %d" % dateutil.makedate()
2344
2344
2345 editor = cmdutil.getcommiteditor(editform='graft',
2345 editor = cmdutil.getcommiteditor(editform='graft',
2346 **pycompat.strkwargs(opts))
2346 **pycompat.strkwargs(opts))
2347
2347
2348 cont = False
2348 cont = False
2349 if opts.get('no_commit'):
2349 if opts.get('no_commit'):
2350 if opts.get('edit'):
2350 if opts.get('edit'):
2351 raise error.Abort(_("cannot specify --no-commit and "
2351 raise error.Abort(_("cannot specify --no-commit and "
2352 "--edit together"))
2352 "--edit together"))
2353 if opts.get('currentuser'):
2353 if opts.get('currentuser'):
2354 raise error.Abort(_("cannot specify --no-commit and "
2354 raise error.Abort(_("cannot specify --no-commit and "
2355 "--currentuser together"))
2355 "--currentuser together"))
2356 if opts.get('currentdate'):
2356 if opts.get('currentdate'):
2357 raise error.Abort(_("cannot specify --no-commit and "
2357 raise error.Abort(_("cannot specify --no-commit and "
2358 "--currentdate together"))
2358 "--currentdate together"))
2359 if opts.get('log'):
2359 if opts.get('log'):
2360 raise error.Abort(_("cannot specify --no-commit and "
2360 raise error.Abort(_("cannot specify --no-commit and "
2361 "--log together"))
2361 "--log together"))
2362
2362
2363 graftstate = statemod.cmdstate(repo, 'graftstate')
2363 graftstate = statemod.cmdstate(repo, 'graftstate')
2364
2364
2365 if opts.get('stop'):
2365 if opts.get('stop'):
2366 if opts.get('continue'):
2366 if opts.get('continue'):
2367 raise error.Abort(_("cannot use '--continue' and "
2367 raise error.Abort(_("cannot use '--continue' and "
2368 "'--stop' together"))
2368 "'--stop' together"))
2369 if opts.get('abort'):
2369 if opts.get('abort'):
2370 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2370 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2371
2371
2372 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2372 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2373 opts.get('date'), opts.get('currentdate'),
2373 opts.get('date'), opts.get('currentdate'),
2374 opts.get('currentuser'), opts.get('rev'))):
2374 opts.get('currentuser'), opts.get('rev'))):
2375 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2375 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2376 return _stopgraft(ui, repo, graftstate)
2376 return _stopgraft(ui, repo, graftstate)
2377 elif opts.get('abort'):
2377 elif opts.get('abort'):
2378 if opts.get('continue'):
2378 if opts.get('continue'):
2379 raise error.Abort(_("cannot use '--continue' and "
2379 raise error.Abort(_("cannot use '--continue' and "
2380 "'--abort' together"))
2380 "'--abort' together"))
2381 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2381 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2382 opts.get('date'), opts.get('currentdate'),
2382 opts.get('date'), opts.get('currentdate'),
2383 opts.get('currentuser'), opts.get('rev'))):
2383 opts.get('currentuser'), opts.get('rev'))):
2384 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2384 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2385
2385
2386 return _abortgraft(ui, repo, graftstate)
2386 return _abortgraft(ui, repo, graftstate)
2387 elif opts.get('continue'):
2387 elif opts.get('continue'):
2388 cont = True
2388 cont = True
2389 if revs:
2389 if revs:
2390 raise error.Abort(_("can't specify --continue and revisions"))
2390 raise error.Abort(_("can't specify --continue and revisions"))
2391 # read in unfinished revisions
2391 # read in unfinished revisions
2392 if graftstate.exists():
2392 if graftstate.exists():
2393 statedata = _readgraftstate(repo, graftstate)
2393 statedata = _readgraftstate(repo, graftstate)
2394 if statedata.get('date'):
2394 if statedata.get('date'):
2395 opts['date'] = statedata['date']
2395 opts['date'] = statedata['date']
2396 if statedata.get('user'):
2396 if statedata.get('user'):
2397 opts['user'] = statedata['user']
2397 opts['user'] = statedata['user']
2398 if statedata.get('log'):
2398 if statedata.get('log'):
2399 opts['log'] = True
2399 opts['log'] = True
2400 if statedata.get('no_commit'):
2400 if statedata.get('no_commit'):
2401 opts['no_commit'] = statedata.get('no_commit')
2401 opts['no_commit'] = statedata.get('no_commit')
2402 nodes = statedata['nodes']
2402 nodes = statedata['nodes']
2403 revs = [repo[node].rev() for node in nodes]
2403 revs = [repo[node].rev() for node in nodes]
2404 else:
2404 else:
2405 cmdutil.wrongtooltocontinue(repo, _('graft'))
2405 cmdutil.wrongtooltocontinue(repo, _('graft'))
2406 else:
2406 else:
2407 if not revs:
2407 if not revs:
2408 raise error.Abort(_('no revisions specified'))
2408 raise error.Abort(_('no revisions specified'))
2409 cmdutil.checkunfinished(repo)
2409 cmdutil.checkunfinished(repo)
2410 cmdutil.bailifchanged(repo)
2410 cmdutil.bailifchanged(repo)
2411 revs = scmutil.revrange(repo, revs)
2411 revs = scmutil.revrange(repo, revs)
2412
2412
2413 skipped = set()
2413 skipped = set()
2414 # check for merges
2414 # check for merges
2415 for rev in repo.revs('%ld and merge()', revs):
2415 for rev in repo.revs('%ld and merge()', revs):
2416 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2416 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2417 skipped.add(rev)
2417 skipped.add(rev)
2418 revs = [r for r in revs if r not in skipped]
2418 revs = [r for r in revs if r not in skipped]
2419 if not revs:
2419 if not revs:
2420 return -1
2420 return -1
2421
2421
2422 # Don't check in the --continue case, in effect retaining --force across
2422 # Don't check in the --continue case, in effect retaining --force across
2423 # --continues. That's because without --force, any revisions we decided to
2423 # --continues. That's because without --force, any revisions we decided to
2424 # skip would have been filtered out here, so they wouldn't have made their
2424 # skip would have been filtered out here, so they wouldn't have made their
2425 # way to the graftstate. With --force, any revisions we would have otherwise
2425 # way to the graftstate. With --force, any revisions we would have otherwise
2426 # skipped would not have been filtered out, and if they hadn't been applied
2426 # skipped would not have been filtered out, and if they hadn't been applied
2427 # already, they'd have been in the graftstate.
2427 # already, they'd have been in the graftstate.
2428 if not (cont or opts.get('force')):
2428 if not (cont or opts.get('force')):
2429 # check for ancestors of dest branch
2429 # check for ancestors of dest branch
2430 crev = repo['.'].rev()
2430 crev = repo['.'].rev()
2431 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2431 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2432 # XXX make this lazy in the future
2432 # XXX make this lazy in the future
2433 # don't mutate while iterating, create a copy
2433 # don't mutate while iterating, create a copy
2434 for rev in list(revs):
2434 for rev in list(revs):
2435 if rev in ancestors:
2435 if rev in ancestors:
2436 ui.warn(_('skipping ancestor revision %d:%s\n') %
2436 ui.warn(_('skipping ancestor revision %d:%s\n') %
2437 (rev, repo[rev]))
2437 (rev, repo[rev]))
2438 # XXX remove on list is slow
2438 # XXX remove on list is slow
2439 revs.remove(rev)
2439 revs.remove(rev)
2440 if not revs:
2440 if not revs:
2441 return -1
2441 return -1
2442
2442
2443 # analyze revs for earlier grafts
2443 # analyze revs for earlier grafts
2444 ids = {}
2444 ids = {}
2445 for ctx in repo.set("%ld", revs):
2445 for ctx in repo.set("%ld", revs):
2446 ids[ctx.hex()] = ctx.rev()
2446 ids[ctx.hex()] = ctx.rev()
2447 n = ctx.extra().get('source')
2447 n = ctx.extra().get('source')
2448 if n:
2448 if n:
2449 ids[n] = ctx.rev()
2449 ids[n] = ctx.rev()
2450
2450
2451 # check ancestors for earlier grafts
2451 # check ancestors for earlier grafts
2452 ui.debug('scanning for duplicate grafts\n')
2452 ui.debug('scanning for duplicate grafts\n')
2453
2453
2454 # The only changesets we can be sure doesn't contain grafts of any
2454 # The only changesets we can be sure doesn't contain grafts of any
2455 # revs, are the ones that are common ancestors of *all* revs:
2455 # revs, are the ones that are common ancestors of *all* revs:
2456 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2456 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2457 ctx = repo[rev]
2457 ctx = repo[rev]
2458 n = ctx.extra().get('source')
2458 n = ctx.extra().get('source')
2459 if n in ids:
2459 if n in ids:
2460 try:
2460 try:
2461 r = repo[n].rev()
2461 r = repo[n].rev()
2462 except error.RepoLookupError:
2462 except error.RepoLookupError:
2463 r = None
2463 r = None
2464 if r in revs:
2464 if r in revs:
2465 ui.warn(_('skipping revision %d:%s '
2465 ui.warn(_('skipping revision %d:%s '
2466 '(already grafted to %d:%s)\n')
2466 '(already grafted to %d:%s)\n')
2467 % (r, repo[r], rev, ctx))
2467 % (r, repo[r], rev, ctx))
2468 revs.remove(r)
2468 revs.remove(r)
2469 elif ids[n] in revs:
2469 elif ids[n] in revs:
2470 if r is None:
2470 if r is None:
2471 ui.warn(_('skipping already grafted revision %d:%s '
2471 ui.warn(_('skipping already grafted revision %d:%s '
2472 '(%d:%s also has unknown origin %s)\n')
2472 '(%d:%s also has unknown origin %s)\n')
2473 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2473 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2474 else:
2474 else:
2475 ui.warn(_('skipping already grafted revision %d:%s '
2475 ui.warn(_('skipping already grafted revision %d:%s '
2476 '(%d:%s also has origin %d:%s)\n')
2476 '(%d:%s also has origin %d:%s)\n')
2477 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2477 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2478 revs.remove(ids[n])
2478 revs.remove(ids[n])
2479 elif ctx.hex() in ids:
2479 elif ctx.hex() in ids:
2480 r = ids[ctx.hex()]
2480 r = ids[ctx.hex()]
2481 if r in revs:
2481 if r in revs:
2482 ui.warn(_('skipping already grafted revision %d:%s '
2482 ui.warn(_('skipping already grafted revision %d:%s '
2483 '(was grafted from %d:%s)\n') %
2483 '(was grafted from %d:%s)\n') %
2484 (r, repo[r], rev, ctx))
2484 (r, repo[r], rev, ctx))
2485 revs.remove(r)
2485 revs.remove(r)
2486 if not revs:
2486 if not revs:
2487 return -1
2487 return -1
2488
2488
2489 if opts.get('no_commit'):
2489 if opts.get('no_commit'):
2490 statedata['no_commit'] = True
2490 statedata['no_commit'] = True
2491 for pos, ctx in enumerate(repo.set("%ld", revs)):
2491 for pos, ctx in enumerate(repo.set("%ld", revs)):
2492 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2492 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2493 ctx.description().split('\n', 1)[0])
2493 ctx.description().split('\n', 1)[0])
2494 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2494 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2495 if names:
2495 if names:
2496 desc += ' (%s)' % ' '.join(names)
2496 desc += ' (%s)' % ' '.join(names)
2497 ui.status(_('grafting %s\n') % desc)
2497 ui.status(_('grafting %s\n') % desc)
2498 if opts.get('dry_run'):
2498 if opts.get('dry_run'):
2499 continue
2499 continue
2500
2500
2501 source = ctx.extra().get('source')
2501 source = ctx.extra().get('source')
2502 extra = {}
2502 extra = {}
2503 if source:
2503 if source:
2504 extra['source'] = source
2504 extra['source'] = source
2505 extra['intermediate-source'] = ctx.hex()
2505 extra['intermediate-source'] = ctx.hex()
2506 else:
2506 else:
2507 extra['source'] = ctx.hex()
2507 extra['source'] = ctx.hex()
2508 user = ctx.user()
2508 user = ctx.user()
2509 if opts.get('user'):
2509 if opts.get('user'):
2510 user = opts['user']
2510 user = opts['user']
2511 statedata['user'] = user
2511 statedata['user'] = user
2512 date = ctx.date()
2512 date = ctx.date()
2513 if opts.get('date'):
2513 if opts.get('date'):
2514 date = opts['date']
2514 date = opts['date']
2515 statedata['date'] = date
2515 statedata['date'] = date
2516 message = ctx.description()
2516 message = ctx.description()
2517 if opts.get('log'):
2517 if opts.get('log'):
2518 message += '\n(grafted from %s)' % ctx.hex()
2518 message += '\n(grafted from %s)' % ctx.hex()
2519 statedata['log'] = True
2519 statedata['log'] = True
2520
2520
2521 # we don't merge the first commit when continuing
2521 # we don't merge the first commit when continuing
2522 if not cont:
2522 if not cont:
2523 # perform the graft merge with p1(rev) as 'ancestor'
2523 # perform the graft merge with p1(rev) as 'ancestor'
2524 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2524 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2525 with ui.configoverride(overrides, 'graft'):
2525 with ui.configoverride(overrides, 'graft'):
2526 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2526 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2527 # report any conflicts
2527 # report any conflicts
2528 if stats.unresolvedcount > 0:
2528 if stats.unresolvedcount > 0:
2529 # write out state for --continue
2529 # write out state for --continue
2530 nodes = [repo[rev].hex() for rev in revs[pos:]]
2530 nodes = [repo[rev].hex() for rev in revs[pos:]]
2531 statedata['nodes'] = nodes
2531 statedata['nodes'] = nodes
2532 stateversion = 1
2532 stateversion = 1
2533 graftstate.save(stateversion, statedata)
2533 graftstate.save(stateversion, statedata)
2534 hint = _("use 'hg resolve' and 'hg graft --continue'")
2534 hint = _("use 'hg resolve' and 'hg graft --continue'")
2535 raise error.Abort(
2535 raise error.Abort(
2536 _("unresolved conflicts, can't continue"),
2536 _("unresolved conflicts, can't continue"),
2537 hint=hint)
2537 hint=hint)
2538 else:
2538 else:
2539 cont = False
2539 cont = False
2540
2540
2541 # commit if --no-commit is false
2541 # commit if --no-commit is false
2542 if not opts.get('no_commit'):
2542 if not opts.get('no_commit'):
2543 node = repo.commit(text=message, user=user, date=date, extra=extra,
2543 node = repo.commit(text=message, user=user, date=date, extra=extra,
2544 editor=editor)
2544 editor=editor)
2545 if node is None:
2545 if node is None:
2546 ui.warn(
2546 ui.warn(
2547 _('note: graft of %d:%s created no changes to commit\n') %
2547 _('note: graft of %d:%s created no changes to commit\n') %
2548 (ctx.rev(), ctx))
2548 (ctx.rev(), ctx))
2549 # checking that newnodes exist because old state files won't have it
2549 # checking that newnodes exist because old state files won't have it
2550 elif statedata.get('newnodes') is not None:
2550 elif statedata.get('newnodes') is not None:
2551 statedata['newnodes'].append(node)
2551 statedata['newnodes'].append(node)
2552
2552
2553 # remove state when we complete successfully
2553 # remove state when we complete successfully
2554 if not opts.get('dry_run'):
2554 if not opts.get('dry_run'):
2555 graftstate.delete()
2555 graftstate.delete()
2556
2556
2557 return 0
2557 return 0
2558
2558
2559 def _abortgraft(ui, repo, graftstate):
2559 def _abortgraft(ui, repo, graftstate):
2560 """abort the interrupted graft and rollbacks to the state before interrupted
2560 """abort the interrupted graft and rollbacks to the state before interrupted
2561 graft"""
2561 graft"""
2562 if not graftstate.exists():
2562 if not graftstate.exists():
2563 raise error.Abort(_("no interrupted graft to abort"))
2563 raise error.Abort(_("no interrupted graft to abort"))
2564 statedata = _readgraftstate(repo, graftstate)
2564 statedata = _readgraftstate(repo, graftstate)
2565 newnodes = statedata.get('newnodes')
2565 newnodes = statedata.get('newnodes')
2566 if newnodes is None:
2566 if newnodes is None:
2567 # and old graft state which does not have all the data required to abort
2567 # and old graft state which does not have all the data required to abort
2568 # the graft
2568 # the graft
2569 raise error.Abort(_("cannot abort using an old graftstate"))
2569 raise error.Abort(_("cannot abort using an old graftstate"))
2570
2570
2571 # changeset from which graft operation was started
2571 # changeset from which graft operation was started
2572 startctx = None
2572 startctx = None
2573 if len(newnodes) > 0:
2573 if len(newnodes) > 0:
2574 startctx = repo[newnodes[0]].p1()
2574 startctx = repo[newnodes[0]].p1()
2575 else:
2575 else:
2576 startctx = repo['.']
2576 startctx = repo['.']
2577 # whether to strip or not
2577 # whether to strip or not
2578 cleanup = False
2578 cleanup = False
2579 if newnodes:
2579 if newnodes:
2580 newnodes = [repo[r].rev() for r in newnodes]
2580 newnodes = [repo[r].rev() for r in newnodes]
2581 cleanup = True
2581 cleanup = True
2582 # checking that none of the newnodes turned public or is public
2582 # checking that none of the newnodes turned public or is public
2583 immutable = [c for c in newnodes if not repo[c].mutable()]
2583 immutable = [c for c in newnodes if not repo[c].mutable()]
2584 if immutable:
2584 if immutable:
2585 repo.ui.warn(_("cannot clean up public changesets %s\n")
2585 repo.ui.warn(_("cannot clean up public changesets %s\n")
2586 % ', '.join(bytes(repo[r]) for r in immutable),
2586 % ', '.join(bytes(repo[r]) for r in immutable),
2587 hint=_("see 'hg help phases' for details"))
2587 hint=_("see 'hg help phases' for details"))
2588 cleanup = False
2588 cleanup = False
2589
2589
2590 # checking that no new nodes are created on top of grafted revs
2590 # checking that no new nodes are created on top of grafted revs
2591 desc = set(repo.changelog.descendants(newnodes))
2591 desc = set(repo.changelog.descendants(newnodes))
2592 if desc - set(newnodes):
2592 if desc - set(newnodes):
2593 repo.ui.warn(_("new changesets detected on destination "
2593 repo.ui.warn(_("new changesets detected on destination "
2594 "branch, can't strip\n"))
2594 "branch, can't strip\n"))
2595 cleanup = False
2595 cleanup = False
2596
2596
2597 if cleanup:
2597 if cleanup:
2598 with repo.wlock(), repo.lock():
2598 with repo.wlock(), repo.lock():
2599 hg.updaterepo(repo, startctx.node(), overwrite=True)
2599 hg.updaterepo(repo, startctx.node(), overwrite=True)
2600 # stripping the new nodes created
2600 # stripping the new nodes created
2601 strippoints = [c.node() for c in repo.set("roots(%ld)",
2601 strippoints = [c.node() for c in repo.set("roots(%ld)",
2602 newnodes)]
2602 newnodes)]
2603 repair.strip(repo.ui, repo, strippoints, backup=False)
2603 repair.strip(repo.ui, repo, strippoints, backup=False)
2604
2604
2605 if not cleanup:
2605 if not cleanup:
2606 # we don't update to the startnode if we can't strip
2606 # we don't update to the startnode if we can't strip
2607 startctx = repo['.']
2607 startctx = repo['.']
2608 hg.updaterepo(repo, startctx.node(), overwrite=True)
2608 hg.updaterepo(repo, startctx.node(), overwrite=True)
2609
2609
2610 ui.status(_("graft aborted\n"))
2610 ui.status(_("graft aborted\n"))
2611 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2611 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2612 graftstate.delete()
2612 graftstate.delete()
2613 return 0
2613 return 0
2614
2614
2615 def _readgraftstate(repo, graftstate):
2615 def _readgraftstate(repo, graftstate):
2616 """read the graft state file and return a dict of the data stored in it"""
2616 """read the graft state file and return a dict of the data stored in it"""
2617 try:
2617 try:
2618 return graftstate.read()
2618 return graftstate.read()
2619 except error.CorruptedState:
2619 except error.CorruptedState:
2620 nodes = repo.vfs.read('graftstate').splitlines()
2620 nodes = repo.vfs.read('graftstate').splitlines()
2621 return {'nodes': nodes}
2621 return {'nodes': nodes}
2622
2622
2623 def _stopgraft(ui, repo, graftstate):
2623 def _stopgraft(ui, repo, graftstate):
2624 """stop the interrupted graft"""
2624 """stop the interrupted graft"""
2625 if not graftstate.exists():
2625 if not graftstate.exists():
2626 raise error.Abort(_("no interrupted graft found"))
2626 raise error.Abort(_("no interrupted graft found"))
2627 pctx = repo['.']
2627 pctx = repo['.']
2628 hg.updaterepo(repo, pctx.node(), overwrite=True)
2628 hg.updaterepo(repo, pctx.node(), overwrite=True)
2629 graftstate.delete()
2629 graftstate.delete()
2630 ui.status(_("stopped the interrupted graft\n"))
2630 ui.status(_("stopped the interrupted graft\n"))
2631 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2631 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2632 return 0
2632 return 0
2633
2633
2634 @command('grep',
2634 @command('grep',
2635 [('0', 'print0', None, _('end fields with NUL')),
2635 [('0', 'print0', None, _('end fields with NUL')),
2636 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2636 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2637 ('', 'diff', None, _('print all revisions when the term was introduced '
2637 ('', 'diff', None, _('print all revisions when the term was introduced '
2638 'or removed')),
2638 'or removed')),
2639 ('a', 'text', None, _('treat all files as text')),
2639 ('a', 'text', None, _('treat all files as text')),
2640 ('f', 'follow', None,
2640 ('f', 'follow', None,
2641 _('follow changeset history,'
2641 _('follow changeset history,'
2642 ' or file history across copies and renames')),
2642 ' or file history across copies and renames')),
2643 ('i', 'ignore-case', None, _('ignore case when matching')),
2643 ('i', 'ignore-case', None, _('ignore case when matching')),
2644 ('l', 'files-with-matches', None,
2644 ('l', 'files-with-matches', None,
2645 _('print only filenames and revisions that match')),
2645 _('print only filenames and revisions that match')),
2646 ('n', 'line-number', None, _('print matching line numbers')),
2646 ('n', 'line-number', None, _('print matching line numbers')),
2647 ('r', 'rev', [],
2647 ('r', 'rev', [],
2648 _('only search files changed within revision range'), _('REV')),
2648 _('only search files changed within revision range'), _('REV')),
2649 ('', 'all-files', None,
2649 ('', 'all-files', None,
2650 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2650 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2651 ('u', 'user', None, _('list the author (long with -v)')),
2651 ('u', 'user', None, _('list the author (long with -v)')),
2652 ('d', 'date', None, _('list the date (short with -q)')),
2652 ('d', 'date', None, _('list the date (short with -q)')),
2653 ] + formatteropts + walkopts,
2653 ] + formatteropts + walkopts,
2654 _('[OPTION]... PATTERN [FILE]...'),
2654 _('[OPTION]... PATTERN [FILE]...'),
2655 helpcategory=command.CATEGORY_FILE_CONTENTS,
2655 helpcategory=command.CATEGORY_FILE_CONTENTS,
2656 inferrepo=True,
2656 inferrepo=True,
2657 intents={INTENT_READONLY})
2657 intents={INTENT_READONLY})
2658 def grep(ui, repo, pattern, *pats, **opts):
2658 def grep(ui, repo, pattern, *pats, **opts):
2659 """search revision history for a pattern in specified files
2659 """search revision history for a pattern in specified files
2660
2660
2661 Search revision history for a regular expression in the specified
2661 Search revision history for a regular expression in the specified
2662 files or the entire project.
2662 files or the entire project.
2663
2663
2664 By default, grep prints the most recent revision number for each
2664 By default, grep prints the most recent revision number for each
2665 file in which it finds a match. To get it to print every revision
2665 file in which it finds a match. To get it to print every revision
2666 that contains a change in match status ("-" for a match that becomes
2666 that contains a change in match status ("-" for a match that becomes
2667 a non-match, or "+" for a non-match that becomes a match), use the
2667 a non-match, or "+" for a non-match that becomes a match), use the
2668 --diff flag.
2668 --diff flag.
2669
2669
2670 PATTERN can be any Python (roughly Perl-compatible) regular
2670 PATTERN can be any Python (roughly Perl-compatible) regular
2671 expression.
2671 expression.
2672
2672
2673 If no FILEs are specified (and -f/--follow isn't set), all files in
2673 If no FILEs are specified (and -f/--follow isn't set), all files in
2674 the repository are searched, including those that don't exist in the
2674 the repository are searched, including those that don't exist in the
2675 current branch or have been deleted in a prior changeset.
2675 current branch or have been deleted in a prior changeset.
2676
2676
2677 .. container:: verbose
2677 .. container:: verbose
2678
2678
2679 Template:
2679 Template:
2680
2680
2681 The following keywords are supported in addition to the common template
2681 The following keywords are supported in addition to the common template
2682 keywords and functions. See also :hg:`help templates`.
2682 keywords and functions. See also :hg:`help templates`.
2683
2683
2684 :change: String. Character denoting insertion ``+`` or removal ``-``.
2684 :change: String. Character denoting insertion ``+`` or removal ``-``.
2685 Available if ``--diff`` is specified.
2685 Available if ``--diff`` is specified.
2686 :lineno: Integer. Line number of the match.
2686 :lineno: Integer. Line number of the match.
2687 :path: String. Repository-absolute path of the file.
2687 :path: String. Repository-absolute path of the file.
2688 :texts: List of text chunks.
2688 :texts: List of text chunks.
2689
2689
2690 And each entry of ``{texts}`` provides the following sub-keywords.
2690 And each entry of ``{texts}`` provides the following sub-keywords.
2691
2691
2692 :matched: Boolean. True if the chunk matches the specified pattern.
2692 :matched: Boolean. True if the chunk matches the specified pattern.
2693 :text: String. Chunk content.
2693 :text: String. Chunk content.
2694
2694
2695 See :hg:`help templates.operators` for the list expansion syntax.
2695 See :hg:`help templates.operators` for the list expansion syntax.
2696
2696
2697 Returns 0 if a match is found, 1 otherwise.
2697 Returns 0 if a match is found, 1 otherwise.
2698 """
2698 """
2699 opts = pycompat.byteskwargs(opts)
2699 opts = pycompat.byteskwargs(opts)
2700 diff = opts.get('all') or opts.get('diff')
2700 diff = opts.get('all') or opts.get('diff')
2701 all_files = opts.get('all_files')
2701 all_files = opts.get('all_files')
2702 if diff and opts.get('all_files'):
2702 if diff and opts.get('all_files'):
2703 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2703 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2704 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2704 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2705 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2705 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2706 # experimental config: commands.grep.all-files
2706 # experimental config: commands.grep.all-files
2707 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2707 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2708 plaingrep = opts.get('all_files') and not opts.get('rev')
2708 plaingrep = opts.get('all_files') and not opts.get('rev')
2709 if plaingrep:
2709 if plaingrep:
2710 opts['rev'] = ['wdir()']
2710 opts['rev'] = ['wdir()']
2711
2711
2712 reflags = re.M
2712 reflags = re.M
2713 if opts.get('ignore_case'):
2713 if opts.get('ignore_case'):
2714 reflags |= re.I
2714 reflags |= re.I
2715 try:
2715 try:
2716 regexp = util.re.compile(pattern, reflags)
2716 regexp = util.re.compile(pattern, reflags)
2717 except re.error as inst:
2717 except re.error as inst:
2718 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2718 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2719 return 1
2719 return 1
2720 sep, eol = ':', '\n'
2720 sep, eol = ':', '\n'
2721 if opts.get('print0'):
2721 if opts.get('print0'):
2722 sep = eol = '\0'
2722 sep = eol = '\0'
2723
2723
2724 getfile = util.lrucachefunc(repo.file)
2724 getfile = util.lrucachefunc(repo.file)
2725
2725
2726 def matchlines(body):
2726 def matchlines(body):
2727 begin = 0
2727 begin = 0
2728 linenum = 0
2728 linenum = 0
2729 while begin < len(body):
2729 while begin < len(body):
2730 match = regexp.search(body, begin)
2730 match = regexp.search(body, begin)
2731 if not match:
2731 if not match:
2732 break
2732 break
2733 mstart, mend = match.span()
2733 mstart, mend = match.span()
2734 linenum += body.count('\n', begin, mstart) + 1
2734 linenum += body.count('\n', begin, mstart) + 1
2735 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2735 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2736 begin = body.find('\n', mend) + 1 or len(body) + 1
2736 begin = body.find('\n', mend) + 1 or len(body) + 1
2737 lend = begin - 1
2737 lend = begin - 1
2738 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2738 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2739
2739
2740 class linestate(object):
2740 class linestate(object):
2741 def __init__(self, line, linenum, colstart, colend):
2741 def __init__(self, line, linenum, colstart, colend):
2742 self.line = line
2742 self.line = line
2743 self.linenum = linenum
2743 self.linenum = linenum
2744 self.colstart = colstart
2744 self.colstart = colstart
2745 self.colend = colend
2745 self.colend = colend
2746
2746
2747 def __hash__(self):
2747 def __hash__(self):
2748 return hash((self.linenum, self.line))
2748 return hash((self.linenum, self.line))
2749
2749
2750 def __eq__(self, other):
2750 def __eq__(self, other):
2751 return self.line == other.line
2751 return self.line == other.line
2752
2752
2753 def findpos(self):
2753 def findpos(self):
2754 """Iterate all (start, end) indices of matches"""
2754 """Iterate all (start, end) indices of matches"""
2755 yield self.colstart, self.colend
2755 yield self.colstart, self.colend
2756 p = self.colend
2756 p = self.colend
2757 while p < len(self.line):
2757 while p < len(self.line):
2758 m = regexp.search(self.line, p)
2758 m = regexp.search(self.line, p)
2759 if not m:
2759 if not m:
2760 break
2760 break
2761 yield m.span()
2761 yield m.span()
2762 p = m.end()
2762 p = m.end()
2763
2763
2764 matches = {}
2764 matches = {}
2765 copies = {}
2765 copies = {}
2766 def grepbody(fn, rev, body):
2766 def grepbody(fn, rev, body):
2767 matches[rev].setdefault(fn, [])
2767 matches[rev].setdefault(fn, [])
2768 m = matches[rev][fn]
2768 m = matches[rev][fn]
2769 for lnum, cstart, cend, line in matchlines(body):
2769 for lnum, cstart, cend, line in matchlines(body):
2770 s = linestate(line, lnum, cstart, cend)
2770 s = linestate(line, lnum, cstart, cend)
2771 m.append(s)
2771 m.append(s)
2772
2772
2773 def difflinestates(a, b):
2773 def difflinestates(a, b):
2774 sm = difflib.SequenceMatcher(None, a, b)
2774 sm = difflib.SequenceMatcher(None, a, b)
2775 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2775 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2776 if tag == r'insert':
2776 if tag == r'insert':
2777 for i in pycompat.xrange(blo, bhi):
2777 for i in pycompat.xrange(blo, bhi):
2778 yield ('+', b[i])
2778 yield ('+', b[i])
2779 elif tag == r'delete':
2779 elif tag == r'delete':
2780 for i in pycompat.xrange(alo, ahi):
2780 for i in pycompat.xrange(alo, ahi):
2781 yield ('-', a[i])
2781 yield ('-', a[i])
2782 elif tag == r'replace':
2782 elif tag == r'replace':
2783 for i in pycompat.xrange(alo, ahi):
2783 for i in pycompat.xrange(alo, ahi):
2784 yield ('-', a[i])
2784 yield ('-', a[i])
2785 for i in pycompat.xrange(blo, bhi):
2785 for i in pycompat.xrange(blo, bhi):
2786 yield ('+', b[i])
2786 yield ('+', b[i])
2787
2787
2788 def display(fm, fn, ctx, pstates, states):
2788 def display(fm, fn, ctx, pstates, states):
2789 rev = scmutil.intrev(ctx)
2789 rev = scmutil.intrev(ctx)
2790 if fm.isplain():
2790 if fm.isplain():
2791 formatuser = ui.shortuser
2791 formatuser = ui.shortuser
2792 else:
2792 else:
2793 formatuser = pycompat.bytestr
2793 formatuser = pycompat.bytestr
2794 if ui.quiet:
2794 if ui.quiet:
2795 datefmt = '%Y-%m-%d'
2795 datefmt = '%Y-%m-%d'
2796 else:
2796 else:
2797 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2797 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2798 found = False
2798 found = False
2799 @util.cachefunc
2799 @util.cachefunc
2800 def binary():
2800 def binary():
2801 flog = getfile(fn)
2801 flog = getfile(fn)
2802 try:
2802 try:
2803 return stringutil.binary(flog.read(ctx.filenode(fn)))
2803 return stringutil.binary(flog.read(ctx.filenode(fn)))
2804 except error.WdirUnsupported:
2804 except error.WdirUnsupported:
2805 return ctx[fn].isbinary()
2805 return ctx[fn].isbinary()
2806
2806
2807 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2807 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2808 if diff:
2808 if diff:
2809 iter = difflinestates(pstates, states)
2809 iter = difflinestates(pstates, states)
2810 else:
2810 else:
2811 iter = [('', l) for l in states]
2811 iter = [('', l) for l in states]
2812 for change, l in iter:
2812 for change, l in iter:
2813 fm.startitem()
2813 fm.startitem()
2814 fm.context(ctx=ctx)
2814 fm.context(ctx=ctx)
2815 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2815 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2816
2816
2817 cols = [
2817 cols = [
2818 ('filename', '%s', fn, True),
2818 ('filename', '%s', fn, True),
2819 ('rev', '%d', rev, not plaingrep),
2819 ('rev', '%d', rev, not plaingrep),
2820 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2820 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2821 ]
2821 ]
2822 if diff:
2822 if diff:
2823 cols.append(('change', '%s', change, True))
2823 cols.append(('change', '%s', change, True))
2824 cols.extend([
2824 cols.extend([
2825 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2825 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2826 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2826 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2827 opts.get('date')),
2827 opts.get('date')),
2828 ])
2828 ])
2829 lastcol = next(
2829 lastcol = next(
2830 name for name, fmt, data, cond in reversed(cols) if cond)
2830 name for name, fmt, data, cond in reversed(cols) if cond)
2831 for name, fmt, data, cond in cols:
2831 for name, fmt, data, cond in cols:
2832 field = fieldnamemap.get(name, name)
2832 field = fieldnamemap.get(name, name)
2833 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2833 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2834 if cond and name != lastcol:
2834 if cond and name != lastcol:
2835 fm.plain(sep, label='grep.sep')
2835 fm.plain(sep, label='grep.sep')
2836 if not opts.get('files_with_matches'):
2836 if not opts.get('files_with_matches'):
2837 fm.plain(sep, label='grep.sep')
2837 fm.plain(sep, label='grep.sep')
2838 if not opts.get('text') and binary():
2838 if not opts.get('text') and binary():
2839 fm.plain(_(" Binary file matches"))
2839 fm.plain(_(" Binary file matches"))
2840 else:
2840 else:
2841 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2841 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2842 fm.plain(eol)
2842 fm.plain(eol)
2843 found = True
2843 found = True
2844 if opts.get('files_with_matches'):
2844 if opts.get('files_with_matches'):
2845 break
2845 break
2846 return found
2846 return found
2847
2847
2848 def displaymatches(fm, l):
2848 def displaymatches(fm, l):
2849 p = 0
2849 p = 0
2850 for s, e in l.findpos():
2850 for s, e in l.findpos():
2851 if p < s:
2851 if p < s:
2852 fm.startitem()
2852 fm.startitem()
2853 fm.write('text', '%s', l.line[p:s])
2853 fm.write('text', '%s', l.line[p:s])
2854 fm.data(matched=False)
2854 fm.data(matched=False)
2855 fm.startitem()
2855 fm.startitem()
2856 fm.write('text', '%s', l.line[s:e], label='grep.match')
2856 fm.write('text', '%s', l.line[s:e], label='grep.match')
2857 fm.data(matched=True)
2857 fm.data(matched=True)
2858 p = e
2858 p = e
2859 if p < len(l.line):
2859 if p < len(l.line):
2860 fm.startitem()
2860 fm.startitem()
2861 fm.write('text', '%s', l.line[p:])
2861 fm.write('text', '%s', l.line[p:])
2862 fm.data(matched=False)
2862 fm.data(matched=False)
2863 fm.end()
2863 fm.end()
2864
2864
2865 skip = {}
2865 skip = {}
2866 revfiles = {}
2866 revfiles = {}
2867 match = scmutil.match(repo[None], pats, opts)
2867 match = scmutil.match(repo[None], pats, opts)
2868 found = False
2868 found = False
2869 follow = opts.get('follow')
2869 follow = opts.get('follow')
2870
2870
2871 def prep(ctx, fns):
2871 def prep(ctx, fns):
2872 rev = ctx.rev()
2872 rev = ctx.rev()
2873 pctx = ctx.p1()
2873 pctx = ctx.p1()
2874 parent = pctx.rev()
2874 parent = pctx.rev()
2875 matches.setdefault(rev, {})
2875 matches.setdefault(rev, {})
2876 matches.setdefault(parent, {})
2876 matches.setdefault(parent, {})
2877 files = revfiles.setdefault(rev, [])
2877 files = revfiles.setdefault(rev, [])
2878 for fn in fns:
2878 for fn in fns:
2879 flog = getfile(fn)
2879 flog = getfile(fn)
2880 try:
2880 try:
2881 fnode = ctx.filenode(fn)
2881 fnode = ctx.filenode(fn)
2882 except error.LookupError:
2882 except error.LookupError:
2883 continue
2883 continue
2884 try:
2884 try:
2885 copied = flog.renamed(fnode)
2885 copied = flog.renamed(fnode)
2886 except error.WdirUnsupported:
2886 except error.WdirUnsupported:
2887 copied = ctx[fn].renamed()
2887 copied = ctx[fn].renamed()
2888 copy = follow and copied and copied[0]
2888 copy = follow and copied and copied[0]
2889 if copy:
2889 if copy:
2890 copies.setdefault(rev, {})[fn] = copy
2890 copies.setdefault(rev, {})[fn] = copy
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 files.append(fn)
2895 files.append(fn)
2896
2896
2897 if fn not in matches[rev]:
2897 if fn not in matches[rev]:
2898 try:
2898 try:
2899 content = flog.read(fnode)
2899 content = flog.read(fnode)
2900 except error.WdirUnsupported:
2900 except error.WdirUnsupported:
2901 content = ctx[fn].data()
2901 content = ctx[fn].data()
2902 grepbody(fn, rev, content)
2902 grepbody(fn, rev, content)
2903
2903
2904 pfn = copy or fn
2904 pfn = copy or fn
2905 if pfn not in matches[parent]:
2905 if pfn not in matches[parent]:
2906 try:
2906 try:
2907 fnode = pctx.filenode(pfn)
2907 fnode = pctx.filenode(pfn)
2908 grepbody(pfn, parent, flog.read(fnode))
2908 grepbody(pfn, parent, flog.read(fnode))
2909 except error.LookupError:
2909 except error.LookupError:
2910 pass
2910 pass
2911
2911
2912 ui.pager('grep')
2912 ui.pager('grep')
2913 fm = ui.formatter('grep', opts)
2913 fm = ui.formatter('grep', opts)
2914 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2914 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2915 rev = ctx.rev()
2915 rev = ctx.rev()
2916 parent = ctx.p1().rev()
2916 parent = ctx.p1().rev()
2917 for fn in sorted(revfiles.get(rev, [])):
2917 for fn in sorted(revfiles.get(rev, [])):
2918 states = matches[rev][fn]
2918 states = matches[rev][fn]
2919 copy = copies.get(rev, {}).get(fn)
2919 copy = copies.get(rev, {}).get(fn)
2920 if fn in skip:
2920 if fn in skip:
2921 if copy:
2921 if copy:
2922 skip[copy] = True
2922 skip[copy] = True
2923 continue
2923 continue
2924 pstates = matches.get(parent, {}).get(copy or fn, [])
2924 pstates = matches.get(parent, {}).get(copy or fn, [])
2925 if pstates or states:
2925 if pstates or states:
2926 r = display(fm, fn, ctx, pstates, states)
2926 r = display(fm, fn, ctx, pstates, states)
2927 found = found or r
2927 found = found or r
2928 if r and not diff and not all_files:
2928 if r and not diff and not all_files:
2929 skip[fn] = True
2929 skip[fn] = True
2930 if copy:
2930 if copy:
2931 skip[copy] = True
2931 skip[copy] = True
2932 del revfiles[rev]
2932 del revfiles[rev]
2933 # We will keep the matches dict for the duration of the window
2933 # We will keep the matches dict for the duration of the window
2934 # clear the matches dict once the window is over
2934 # clear the matches dict once the window is over
2935 if not revfiles:
2935 if not revfiles:
2936 matches.clear()
2936 matches.clear()
2937 fm.end()
2937 fm.end()
2938
2938
2939 return not found
2939 return not found
2940
2940
2941 @command('heads',
2941 @command('heads',
2942 [('r', 'rev', '',
2942 [('r', 'rev', '',
2943 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2943 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2944 ('t', 'topo', False, _('show topological heads only')),
2944 ('t', 'topo', False, _('show topological heads only')),
2945 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2945 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2946 ('c', 'closed', False, _('show normal and closed branch heads')),
2946 ('c', 'closed', False, _('show normal and closed branch heads')),
2947 ] + templateopts,
2947 ] + templateopts,
2948 _('[-ct] [-r STARTREV] [REV]...'),
2948 _('[-ct] [-r STARTREV] [REV]...'),
2949 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
2949 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
2950 intents={INTENT_READONLY})
2950 intents={INTENT_READONLY})
2951 def heads(ui, repo, *branchrevs, **opts):
2951 def heads(ui, repo, *branchrevs, **opts):
2952 """show branch heads
2952 """show branch heads
2953
2953
2954 With no arguments, show all open branch heads in the repository.
2954 With no arguments, show all open branch heads in the repository.
2955 Branch heads are changesets that have no descendants on the
2955 Branch heads are changesets that have no descendants on the
2956 same branch. They are where development generally takes place and
2956 same branch. They are where development generally takes place and
2957 are the usual targets for update and merge operations.
2957 are the usual targets for update and merge operations.
2958
2958
2959 If one or more REVs are given, only open branch heads on the
2959 If one or more REVs are given, only open branch heads on the
2960 branches associated with the specified changesets are shown. This
2960 branches associated with the specified changesets are shown. This
2961 means that you can use :hg:`heads .` to see the heads on the
2961 means that you can use :hg:`heads .` to see the heads on the
2962 currently checked-out branch.
2962 currently checked-out branch.
2963
2963
2964 If -c/--closed is specified, also show branch heads marked closed
2964 If -c/--closed is specified, also show branch heads marked closed
2965 (see :hg:`commit --close-branch`).
2965 (see :hg:`commit --close-branch`).
2966
2966
2967 If STARTREV is specified, only those heads that are descendants of
2967 If STARTREV is specified, only those heads that are descendants of
2968 STARTREV will be displayed.
2968 STARTREV will be displayed.
2969
2969
2970 If -t/--topo is specified, named branch mechanics will be ignored and only
2970 If -t/--topo is specified, named branch mechanics will be ignored and only
2971 topological heads (changesets with no children) will be shown.
2971 topological heads (changesets with no children) will be shown.
2972
2972
2973 Returns 0 if matching heads are found, 1 if not.
2973 Returns 0 if matching heads are found, 1 if not.
2974 """
2974 """
2975
2975
2976 opts = pycompat.byteskwargs(opts)
2976 opts = pycompat.byteskwargs(opts)
2977 start = None
2977 start = None
2978 rev = opts.get('rev')
2978 rev = opts.get('rev')
2979 if rev:
2979 if rev:
2980 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2980 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2981 start = scmutil.revsingle(repo, rev, None).node()
2981 start = scmutil.revsingle(repo, rev, None).node()
2982
2982
2983 if opts.get('topo'):
2983 if opts.get('topo'):
2984 heads = [repo[h] for h in repo.heads(start)]
2984 heads = [repo[h] for h in repo.heads(start)]
2985 else:
2985 else:
2986 heads = []
2986 heads = []
2987 for branch in repo.branchmap():
2987 for branch in repo.branchmap():
2988 heads += repo.branchheads(branch, start, opts.get('closed'))
2988 heads += repo.branchheads(branch, start, opts.get('closed'))
2989 heads = [repo[h] for h in heads]
2989 heads = [repo[h] for h in heads]
2990
2990
2991 if branchrevs:
2991 if branchrevs:
2992 branches = set(repo[r].branch()
2992 branches = set(repo[r].branch()
2993 for r in scmutil.revrange(repo, branchrevs))
2993 for r in scmutil.revrange(repo, branchrevs))
2994 heads = [h for h in heads if h.branch() in branches]
2994 heads = [h for h in heads if h.branch() in branches]
2995
2995
2996 if opts.get('active') and branchrevs:
2996 if opts.get('active') and branchrevs:
2997 dagheads = repo.heads(start)
2997 dagheads = repo.heads(start)
2998 heads = [h for h in heads if h.node() in dagheads]
2998 heads = [h for h in heads if h.node() in dagheads]
2999
2999
3000 if branchrevs:
3000 if branchrevs:
3001 haveheads = set(h.branch() for h in heads)
3001 haveheads = set(h.branch() for h in heads)
3002 if branches - haveheads:
3002 if branches - haveheads:
3003 headless = ', '.join(b for b in branches - haveheads)
3003 headless = ', '.join(b for b in branches - haveheads)
3004 msg = _('no open branch heads found on branches %s')
3004 msg = _('no open branch heads found on branches %s')
3005 if opts.get('rev'):
3005 if opts.get('rev'):
3006 msg += _(' (started at %s)') % opts['rev']
3006 msg += _(' (started at %s)') % opts['rev']
3007 ui.warn((msg + '\n') % headless)
3007 ui.warn((msg + '\n') % headless)
3008
3008
3009 if not heads:
3009 if not heads:
3010 return 1
3010 return 1
3011
3011
3012 ui.pager('heads')
3012 ui.pager('heads')
3013 heads = sorted(heads, key=lambda x: -x.rev())
3013 heads = sorted(heads, key=lambda x: -x.rev())
3014 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3014 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3015 for ctx in heads:
3015 for ctx in heads:
3016 displayer.show(ctx)
3016 displayer.show(ctx)
3017 displayer.close()
3017 displayer.close()
3018
3018
3019 @command('help',
3019 @command('help',
3020 [('e', 'extension', None, _('show only help for extensions')),
3020 [('e', 'extension', None, _('show only help for extensions')),
3021 ('c', 'command', None, _('show only help for commands')),
3021 ('c', 'command', None, _('show only help for commands')),
3022 ('k', 'keyword', None, _('show topics matching keyword')),
3022 ('k', 'keyword', None, _('show topics matching keyword')),
3023 ('s', 'system', [],
3023 ('s', 'system', [],
3024 _('show help for specific platform(s)'), _('PLATFORM')),
3024 _('show help for specific platform(s)'), _('PLATFORM')),
3025 ],
3025 ],
3026 _('[-eck] [-s PLATFORM] [TOPIC]'),
3026 _('[-eck] [-s PLATFORM] [TOPIC]'),
3027 helpcategory=command.CATEGORY_HELP,
3027 helpcategory=command.CATEGORY_HELP,
3028 norepo=True,
3028 norepo=True,
3029 intents={INTENT_READONLY})
3029 intents={INTENT_READONLY})
3030 def help_(ui, name=None, **opts):
3030 def help_(ui, name=None, **opts):
3031 """show help for a given topic or a help overview
3031 """show help for a given topic or a help overview
3032
3032
3033 With no arguments, print a list of commands with short help messages.
3033 With no arguments, print a list of commands with short help messages.
3034
3034
3035 Given a topic, extension, or command name, print help for that
3035 Given a topic, extension, or command name, print help for that
3036 topic.
3036 topic.
3037
3037
3038 Returns 0 if successful.
3038 Returns 0 if successful.
3039 """
3039 """
3040
3040
3041 keep = opts.get(r'system') or []
3041 keep = opts.get(r'system') or []
3042 if len(keep) == 0:
3042 if len(keep) == 0:
3043 if pycompat.sysplatform.startswith('win'):
3043 if pycompat.sysplatform.startswith('win'):
3044 keep.append('windows')
3044 keep.append('windows')
3045 elif pycompat.sysplatform == 'OpenVMS':
3045 elif pycompat.sysplatform == 'OpenVMS':
3046 keep.append('vms')
3046 keep.append('vms')
3047 elif pycompat.sysplatform == 'plan9':
3047 elif pycompat.sysplatform == 'plan9':
3048 keep.append('plan9')
3048 keep.append('plan9')
3049 else:
3049 else:
3050 keep.append('unix')
3050 keep.append('unix')
3051 keep.append(pycompat.sysplatform.lower())
3051 keep.append(pycompat.sysplatform.lower())
3052 if ui.verbose:
3052 if ui.verbose:
3053 keep.append('verbose')
3053 keep.append('verbose')
3054
3054
3055 commands = sys.modules[__name__]
3055 commands = sys.modules[__name__]
3056 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3056 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3057 ui.pager('help')
3057 ui.pager('help')
3058 ui.write(formatted)
3058 ui.write(formatted)
3059
3059
3060
3060
3061 @command('identify|id',
3061 @command('identify|id',
3062 [('r', 'rev', '',
3062 [('r', 'rev', '',
3063 _('identify the specified revision'), _('REV')),
3063 _('identify the specified revision'), _('REV')),
3064 ('n', 'num', None, _('show local revision number')),
3064 ('n', 'num', None, _('show local revision number')),
3065 ('i', 'id', None, _('show global revision id')),
3065 ('i', 'id', None, _('show global revision id')),
3066 ('b', 'branch', None, _('show branch')),
3066 ('b', 'branch', None, _('show branch')),
3067 ('t', 'tags', None, _('show tags')),
3067 ('t', 'tags', None, _('show tags')),
3068 ('B', 'bookmarks', None, _('show bookmarks')),
3068 ('B', 'bookmarks', None, _('show bookmarks')),
3069 ] + remoteopts + formatteropts,
3069 ] + remoteopts + formatteropts,
3070 _('[-nibtB] [-r REV] [SOURCE]'),
3070 _('[-nibtB] [-r REV] [SOURCE]'),
3071 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3071 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3072 optionalrepo=True,
3072 optionalrepo=True,
3073 intents={INTENT_READONLY})
3073 intents={INTENT_READONLY})
3074 def identify(ui, repo, source=None, rev=None,
3074 def identify(ui, repo, source=None, rev=None,
3075 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3075 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3076 """identify the working directory or specified revision
3076 """identify the working directory or specified revision
3077
3077
3078 Print a summary identifying the repository state at REV using one or
3078 Print a summary identifying the repository state at REV using one or
3079 two parent hash identifiers, followed by a "+" if the working
3079 two parent hash identifiers, followed by a "+" if the working
3080 directory has uncommitted changes, the branch name (if not default),
3080 directory has uncommitted changes, the branch name (if not default),
3081 a list of tags, and a list of bookmarks.
3081 a list of tags, and a list of bookmarks.
3082
3082
3083 When REV is not given, print a summary of the current state of the
3083 When REV is not given, print a summary of the current state of the
3084 repository including the working directory. Specify -r. to get information
3084 repository including the working directory. Specify -r. to get information
3085 of the working directory parent without scanning uncommitted changes.
3085 of the working directory parent without scanning uncommitted changes.
3086
3086
3087 Specifying a path to a repository root or Mercurial bundle will
3087 Specifying a path to a repository root or Mercurial bundle will
3088 cause lookup to operate on that repository/bundle.
3088 cause lookup to operate on that repository/bundle.
3089
3089
3090 .. container:: verbose
3090 .. container:: verbose
3091
3091
3092 Template:
3092 Template:
3093
3093
3094 The following keywords are supported in addition to the common template
3094 The following keywords are supported in addition to the common template
3095 keywords and functions. See also :hg:`help templates`.
3095 keywords and functions. See also :hg:`help templates`.
3096
3096
3097 :dirty: String. Character ``+`` denoting if the working directory has
3097 :dirty: String. Character ``+`` denoting if the working directory has
3098 uncommitted changes.
3098 uncommitted changes.
3099 :id: String. One or two nodes, optionally followed by ``+``.
3099 :id: String. One or two nodes, optionally followed by ``+``.
3100 :parents: List of strings. Parent nodes of the changeset.
3100 :parents: List of strings. Parent nodes of the changeset.
3101
3101
3102 Examples:
3102 Examples:
3103
3103
3104 - generate a build identifier for the working directory::
3104 - generate a build identifier for the working directory::
3105
3105
3106 hg id --id > build-id.dat
3106 hg id --id > build-id.dat
3107
3107
3108 - find the revision corresponding to a tag::
3108 - find the revision corresponding to a tag::
3109
3109
3110 hg id -n -r 1.3
3110 hg id -n -r 1.3
3111
3111
3112 - check the most recent revision of a remote repository::
3112 - check the most recent revision of a remote repository::
3113
3113
3114 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3114 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3115
3115
3116 See :hg:`log` for generating more information about specific revisions,
3116 See :hg:`log` for generating more information about specific revisions,
3117 including full hash identifiers.
3117 including full hash identifiers.
3118
3118
3119 Returns 0 if successful.
3119 Returns 0 if successful.
3120 """
3120 """
3121
3121
3122 opts = pycompat.byteskwargs(opts)
3122 opts = pycompat.byteskwargs(opts)
3123 if not repo and not source:
3123 if not repo and not source:
3124 raise error.Abort(_("there is no Mercurial repository here "
3124 raise error.Abort(_("there is no Mercurial repository here "
3125 "(.hg not found)"))
3125 "(.hg not found)"))
3126
3126
3127 default = not (num or id or branch or tags or bookmarks)
3127 default = not (num or id or branch or tags or bookmarks)
3128 output = []
3128 output = []
3129 revs = []
3129 revs = []
3130
3130
3131 if source:
3131 if source:
3132 source, branches = hg.parseurl(ui.expandpath(source))
3132 source, branches = hg.parseurl(ui.expandpath(source))
3133 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3133 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3134 repo = peer.local()
3134 repo = peer.local()
3135 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3135 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3136
3136
3137 fm = ui.formatter('identify', opts)
3137 fm = ui.formatter('identify', opts)
3138 fm.startitem()
3138 fm.startitem()
3139
3139
3140 if not repo:
3140 if not repo:
3141 if num or branch or tags:
3141 if num or branch or tags:
3142 raise error.Abort(
3142 raise error.Abort(
3143 _("can't query remote revision number, branch, or tags"))
3143 _("can't query remote revision number, branch, or tags"))
3144 if not rev and revs:
3144 if not rev and revs:
3145 rev = revs[0]
3145 rev = revs[0]
3146 if not rev:
3146 if not rev:
3147 rev = "tip"
3147 rev = "tip"
3148
3148
3149 remoterev = peer.lookup(rev)
3149 remoterev = peer.lookup(rev)
3150 hexrev = fm.hexfunc(remoterev)
3150 hexrev = fm.hexfunc(remoterev)
3151 if default or id:
3151 if default or id:
3152 output = [hexrev]
3152 output = [hexrev]
3153 fm.data(id=hexrev)
3153 fm.data(id=hexrev)
3154
3154
3155 @util.cachefunc
3155 @util.cachefunc
3156 def getbms():
3156 def getbms():
3157 bms = []
3157 bms = []
3158
3158
3159 if 'bookmarks' in peer.listkeys('namespaces'):
3159 if 'bookmarks' in peer.listkeys('namespaces'):
3160 hexremoterev = hex(remoterev)
3160 hexremoterev = hex(remoterev)
3161 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3161 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3162 if bmr == hexremoterev]
3162 if bmr == hexremoterev]
3163
3163
3164 return sorted(bms)
3164 return sorted(bms)
3165
3165
3166 if fm.isplain():
3166 if fm.isplain():
3167 if bookmarks:
3167 if bookmarks:
3168 output.extend(getbms())
3168 output.extend(getbms())
3169 elif default and not ui.quiet:
3169 elif default and not ui.quiet:
3170 # multiple bookmarks for a single parent separated by '/'
3170 # multiple bookmarks for a single parent separated by '/'
3171 bm = '/'.join(getbms())
3171 bm = '/'.join(getbms())
3172 if bm:
3172 if bm:
3173 output.append(bm)
3173 output.append(bm)
3174 else:
3174 else:
3175 fm.data(node=hex(remoterev))
3175 fm.data(node=hex(remoterev))
3176 if bookmarks or 'bookmarks' in fm.datahint():
3176 if bookmarks or 'bookmarks' in fm.datahint():
3177 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3177 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3178 else:
3178 else:
3179 if rev:
3179 if rev:
3180 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3180 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3181 ctx = scmutil.revsingle(repo, rev, None)
3181 ctx = scmutil.revsingle(repo, rev, None)
3182
3182
3183 if ctx.rev() is None:
3183 if ctx.rev() is None:
3184 ctx = repo[None]
3184 ctx = repo[None]
3185 parents = ctx.parents()
3185 parents = ctx.parents()
3186 taglist = []
3186 taglist = []
3187 for p in parents:
3187 for p in parents:
3188 taglist.extend(p.tags())
3188 taglist.extend(p.tags())
3189
3189
3190 dirty = ""
3190 dirty = ""
3191 if ctx.dirty(missing=True, merge=False, branch=False):
3191 if ctx.dirty(missing=True, merge=False, branch=False):
3192 dirty = '+'
3192 dirty = '+'
3193 fm.data(dirty=dirty)
3193 fm.data(dirty=dirty)
3194
3194
3195 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3195 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3196 if default or id:
3196 if default or id:
3197 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3197 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3198 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3198 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3199
3199
3200 if num:
3200 if num:
3201 numoutput = ["%d" % p.rev() for p in parents]
3201 numoutput = ["%d" % p.rev() for p in parents]
3202 output.append("%s%s" % ('+'.join(numoutput), dirty))
3202 output.append("%s%s" % ('+'.join(numoutput), dirty))
3203
3203
3204 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3204 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3205 for p in parents], name='node'))
3205 for p in parents], name='node'))
3206 else:
3206 else:
3207 hexoutput = fm.hexfunc(ctx.node())
3207 hexoutput = fm.hexfunc(ctx.node())
3208 if default or id:
3208 if default or id:
3209 output = [hexoutput]
3209 output = [hexoutput]
3210 fm.data(id=hexoutput)
3210 fm.data(id=hexoutput)
3211
3211
3212 if num:
3212 if num:
3213 output.append(pycompat.bytestr(ctx.rev()))
3213 output.append(pycompat.bytestr(ctx.rev()))
3214 taglist = ctx.tags()
3214 taglist = ctx.tags()
3215
3215
3216 if default and not ui.quiet:
3216 if default and not ui.quiet:
3217 b = ctx.branch()
3217 b = ctx.branch()
3218 if b != 'default':
3218 if b != 'default':
3219 output.append("(%s)" % b)
3219 output.append("(%s)" % b)
3220
3220
3221 # multiple tags for a single parent separated by '/'
3221 # multiple tags for a single parent separated by '/'
3222 t = '/'.join(taglist)
3222 t = '/'.join(taglist)
3223 if t:
3223 if t:
3224 output.append(t)
3224 output.append(t)
3225
3225
3226 # multiple bookmarks for a single parent separated by '/'
3226 # multiple bookmarks for a single parent separated by '/'
3227 bm = '/'.join(ctx.bookmarks())
3227 bm = '/'.join(ctx.bookmarks())
3228 if bm:
3228 if bm:
3229 output.append(bm)
3229 output.append(bm)
3230 else:
3230 else:
3231 if branch:
3231 if branch:
3232 output.append(ctx.branch())
3232 output.append(ctx.branch())
3233
3233
3234 if tags:
3234 if tags:
3235 output.extend(taglist)
3235 output.extend(taglist)
3236
3236
3237 if bookmarks:
3237 if bookmarks:
3238 output.extend(ctx.bookmarks())
3238 output.extend(ctx.bookmarks())
3239
3239
3240 fm.data(node=ctx.hex())
3240 fm.data(node=ctx.hex())
3241 fm.data(branch=ctx.branch())
3241 fm.data(branch=ctx.branch())
3242 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3242 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3243 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3243 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3244 fm.context(ctx=ctx)
3244 fm.context(ctx=ctx)
3245
3245
3246 fm.plain("%s\n" % ' '.join(output))
3246 fm.plain("%s\n" % ' '.join(output))
3247 fm.end()
3247 fm.end()
3248
3248
3249 @command('import|patch',
3249 @command('import|patch',
3250 [('p', 'strip', 1,
3250 [('p', 'strip', 1,
3251 _('directory strip option for patch. This has the same '
3251 _('directory strip option for patch. This has the same '
3252 'meaning as the corresponding patch option'), _('NUM')),
3252 'meaning as the corresponding patch option'), _('NUM')),
3253 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3253 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3254 ('e', 'edit', False, _('invoke editor on commit messages')),
3254 ('e', 'edit', False, _('invoke editor on commit messages')),
3255 ('f', 'force', None,
3255 ('f', 'force', None,
3256 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3256 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3257 ('', 'no-commit', None,
3257 ('', 'no-commit', None,
3258 _("don't commit, just update the working directory")),
3258 _("don't commit, just update the working directory")),
3259 ('', 'bypass', None,
3259 ('', 'bypass', None,
3260 _("apply patch without touching the working directory")),
3260 _("apply patch without touching the working directory")),
3261 ('', 'partial', None,
3261 ('', 'partial', None,
3262 _('commit even if some hunks fail')),
3262 _('commit even if some hunks fail')),
3263 ('', 'exact', None,
3263 ('', 'exact', None,
3264 _('abort if patch would apply lossily')),
3264 _('abort if patch would apply lossily')),
3265 ('', 'prefix', '',
3265 ('', 'prefix', '',
3266 _('apply patch to subdirectory'), _('DIR')),
3266 _('apply patch to subdirectory'), _('DIR')),
3267 ('', 'import-branch', None,
3267 ('', 'import-branch', None,
3268 _('use any branch information in patch (implied by --exact)'))] +
3268 _('use any branch information in patch (implied by --exact)'))] +
3269 commitopts + commitopts2 + similarityopts,
3269 commitopts + commitopts2 + similarityopts,
3270 _('[OPTION]... PATCH...'),
3270 _('[OPTION]... PATCH...'),
3271 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3271 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3272 def import_(ui, repo, patch1=None, *patches, **opts):
3272 def import_(ui, repo, patch1=None, *patches, **opts):
3273 """import an ordered set of patches
3273 """import an ordered set of patches
3274
3274
3275 Import a list of patches and commit them individually (unless
3275 Import a list of patches and commit them individually (unless
3276 --no-commit is specified).
3276 --no-commit is specified).
3277
3277
3278 To read a patch from standard input (stdin), use "-" as the patch
3278 To read a patch from standard input (stdin), use "-" as the patch
3279 name. If a URL is specified, the patch will be downloaded from
3279 name. If a URL is specified, the patch will be downloaded from
3280 there.
3280 there.
3281
3281
3282 Import first applies changes to the working directory (unless
3282 Import first applies changes to the working directory (unless
3283 --bypass is specified), import will abort if there are outstanding
3283 --bypass is specified), import will abort if there are outstanding
3284 changes.
3284 changes.
3285
3285
3286 Use --bypass to apply and commit patches directly to the
3286 Use --bypass to apply and commit patches directly to the
3287 repository, without affecting the working directory. Without
3287 repository, without affecting the working directory. Without
3288 --exact, patches will be applied on top of the working directory
3288 --exact, patches will be applied on top of the working directory
3289 parent revision.
3289 parent revision.
3290
3290
3291 You can import a patch straight from a mail message. Even patches
3291 You can import a patch straight from a mail message. Even patches
3292 as attachments work (to use the body part, it must have type
3292 as attachments work (to use the body part, it must have type
3293 text/plain or text/x-patch). From and Subject headers of email
3293 text/plain or text/x-patch). From and Subject headers of email
3294 message are used as default committer and commit message. All
3294 message are used as default committer and commit message. All
3295 text/plain body parts before first diff are added to the commit
3295 text/plain body parts before first diff are added to the commit
3296 message.
3296 message.
3297
3297
3298 If the imported patch was generated by :hg:`export`, user and
3298 If the imported patch was generated by :hg:`export`, user and
3299 description from patch override values from message headers and
3299 description from patch override values from message headers and
3300 body. Values given on command line with -m/--message and -u/--user
3300 body. Values given on command line with -m/--message and -u/--user
3301 override these.
3301 override these.
3302
3302
3303 If --exact is specified, import will set the working directory to
3303 If --exact is specified, import will set the working directory to
3304 the parent of each patch before applying it, and will abort if the
3304 the parent of each patch before applying it, and will abort if the
3305 resulting changeset has a different ID than the one recorded in
3305 resulting changeset has a different ID than the one recorded in
3306 the patch. This will guard against various ways that portable
3306 the patch. This will guard against various ways that portable
3307 patch formats and mail systems might fail to transfer Mercurial
3307 patch formats and mail systems might fail to transfer Mercurial
3308 data or metadata. See :hg:`bundle` for lossless transmission.
3308 data or metadata. See :hg:`bundle` for lossless transmission.
3309
3309
3310 Use --partial to ensure a changeset will be created from the patch
3310 Use --partial to ensure a changeset will be created from the patch
3311 even if some hunks fail to apply. Hunks that fail to apply will be
3311 even if some hunks fail to apply. Hunks that fail to apply will be
3312 written to a <target-file>.rej file. Conflicts can then be resolved
3312 written to a <target-file>.rej file. Conflicts can then be resolved
3313 by hand before :hg:`commit --amend` is run to update the created
3313 by hand before :hg:`commit --amend` is run to update the created
3314 changeset. This flag exists to let people import patches that
3314 changeset. This flag exists to let people import patches that
3315 partially apply without losing the associated metadata (author,
3315 partially apply without losing the associated metadata (author,
3316 date, description, ...).
3316 date, description, ...).
3317
3317
3318 .. note::
3318 .. note::
3319
3319
3320 When no hunks apply cleanly, :hg:`import --partial` will create
3320 When no hunks apply cleanly, :hg:`import --partial` will create
3321 an empty changeset, importing only the patch metadata.
3321 an empty changeset, importing only the patch metadata.
3322
3322
3323 With -s/--similarity, hg will attempt to discover renames and
3323 With -s/--similarity, hg will attempt to discover renames and
3324 copies in the patch in the same way as :hg:`addremove`.
3324 copies in the patch in the same way as :hg:`addremove`.
3325
3325
3326 It is possible to use external patch programs to perform the patch
3326 It is possible to use external patch programs to perform the patch
3327 by setting the ``ui.patch`` configuration option. For the default
3327 by setting the ``ui.patch`` configuration option. For the default
3328 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3328 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3329 See :hg:`help config` for more information about configuration
3329 See :hg:`help config` for more information about configuration
3330 files and how to use these options.
3330 files and how to use these options.
3331
3331
3332 See :hg:`help dates` for a list of formats valid for -d/--date.
3332 See :hg:`help dates` for a list of formats valid for -d/--date.
3333
3333
3334 .. container:: verbose
3334 .. container:: verbose
3335
3335
3336 Examples:
3336 Examples:
3337
3337
3338 - import a traditional patch from a website and detect renames::
3338 - import a traditional patch from a website and detect renames::
3339
3339
3340 hg import -s 80 http://example.com/bugfix.patch
3340 hg import -s 80 http://example.com/bugfix.patch
3341
3341
3342 - import a changeset from an hgweb server::
3342 - import a changeset from an hgweb server::
3343
3343
3344 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3344 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3345
3345
3346 - import all the patches in an Unix-style mbox::
3346 - import all the patches in an Unix-style mbox::
3347
3347
3348 hg import incoming-patches.mbox
3348 hg import incoming-patches.mbox
3349
3349
3350 - import patches from stdin::
3350 - import patches from stdin::
3351
3351
3352 hg import -
3352 hg import -
3353
3353
3354 - attempt to exactly restore an exported changeset (not always
3354 - attempt to exactly restore an exported changeset (not always
3355 possible)::
3355 possible)::
3356
3356
3357 hg import --exact proposed-fix.patch
3357 hg import --exact proposed-fix.patch
3358
3358
3359 - use an external tool to apply a patch which is too fuzzy for
3359 - use an external tool to apply a patch which is too fuzzy for
3360 the default internal tool.
3360 the default internal tool.
3361
3361
3362 hg import --config ui.patch="patch --merge" fuzzy.patch
3362 hg import --config ui.patch="patch --merge" fuzzy.patch
3363
3363
3364 - change the default fuzzing from 2 to a less strict 7
3364 - change the default fuzzing from 2 to a less strict 7
3365
3365
3366 hg import --config ui.fuzz=7 fuzz.patch
3366 hg import --config ui.fuzz=7 fuzz.patch
3367
3367
3368 Returns 0 on success, 1 on partial success (see --partial).
3368 Returns 0 on success, 1 on partial success (see --partial).
3369 """
3369 """
3370
3370
3371 opts = pycompat.byteskwargs(opts)
3371 opts = pycompat.byteskwargs(opts)
3372 if not patch1:
3372 if not patch1:
3373 raise error.Abort(_('need at least one patch to import'))
3373 raise error.Abort(_('need at least one patch to import'))
3374
3374
3375 patches = (patch1,) + patches
3375 patches = (patch1,) + patches
3376
3376
3377 date = opts.get('date')
3377 date = opts.get('date')
3378 if date:
3378 if date:
3379 opts['date'] = dateutil.parsedate(date)
3379 opts['date'] = dateutil.parsedate(date)
3380
3380
3381 exact = opts.get('exact')
3381 exact = opts.get('exact')
3382 update = not opts.get('bypass')
3382 update = not opts.get('bypass')
3383 if not update and opts.get('no_commit'):
3383 if not update and opts.get('no_commit'):
3384 raise error.Abort(_('cannot use --no-commit with --bypass'))
3384 raise error.Abort(_('cannot use --no-commit with --bypass'))
3385 try:
3385 try:
3386 sim = float(opts.get('similarity') or 0)
3386 sim = float(opts.get('similarity') or 0)
3387 except ValueError:
3387 except ValueError:
3388 raise error.Abort(_('similarity must be a number'))
3388 raise error.Abort(_('similarity must be a number'))
3389 if sim < 0 or sim > 100:
3389 if sim < 0 or sim > 100:
3390 raise error.Abort(_('similarity must be between 0 and 100'))
3390 raise error.Abort(_('similarity must be between 0 and 100'))
3391 if sim and not update:
3391 if sim and not update:
3392 raise error.Abort(_('cannot use --similarity with --bypass'))
3392 raise error.Abort(_('cannot use --similarity with --bypass'))
3393 if exact:
3393 if exact:
3394 if opts.get('edit'):
3394 if opts.get('edit'):
3395 raise error.Abort(_('cannot use --exact with --edit'))
3395 raise error.Abort(_('cannot use --exact with --edit'))
3396 if opts.get('prefix'):
3396 if opts.get('prefix'):
3397 raise error.Abort(_('cannot use --exact with --prefix'))
3397 raise error.Abort(_('cannot use --exact with --prefix'))
3398
3398
3399 base = opts["base"]
3399 base = opts["base"]
3400 msgs = []
3400 msgs = []
3401 ret = 0
3401 ret = 0
3402
3402
3403 with repo.wlock():
3403 with repo.wlock():
3404 if update:
3404 if update:
3405 cmdutil.checkunfinished(repo)
3405 cmdutil.checkunfinished(repo)
3406 if (exact or not opts.get('force')):
3406 if (exact or not opts.get('force')):
3407 cmdutil.bailifchanged(repo)
3407 cmdutil.bailifchanged(repo)
3408
3408
3409 if not opts.get('no_commit'):
3409 if not opts.get('no_commit'):
3410 lock = repo.lock
3410 lock = repo.lock
3411 tr = lambda: repo.transaction('import')
3411 tr = lambda: repo.transaction('import')
3412 dsguard = util.nullcontextmanager
3412 dsguard = util.nullcontextmanager
3413 else:
3413 else:
3414 lock = util.nullcontextmanager
3414 lock = util.nullcontextmanager
3415 tr = util.nullcontextmanager
3415 tr = util.nullcontextmanager
3416 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3416 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3417 with lock(), tr(), dsguard():
3417 with lock(), tr(), dsguard():
3418 parents = repo[None].parents()
3418 parents = repo[None].parents()
3419 for patchurl in patches:
3419 for patchurl in patches:
3420 if patchurl == '-':
3420 if patchurl == '-':
3421 ui.status(_('applying patch from stdin\n'))
3421 ui.status(_('applying patch from stdin\n'))
3422 patchfile = ui.fin
3422 patchfile = ui.fin
3423 patchurl = 'stdin' # for error message
3423 patchurl = 'stdin' # for error message
3424 else:
3424 else:
3425 patchurl = os.path.join(base, patchurl)
3425 patchurl = os.path.join(base, patchurl)
3426 ui.status(_('applying %s\n') % patchurl)
3426 ui.status(_('applying %s\n') % patchurl)
3427 patchfile = hg.openpath(ui, patchurl)
3427 patchfile = hg.openpath(ui, patchurl)
3428
3428
3429 haspatch = False
3429 haspatch = False
3430 for hunk in patch.split(patchfile):
3430 for hunk in patch.split(patchfile):
3431 with patch.extract(ui, hunk) as patchdata:
3431 with patch.extract(ui, hunk) as patchdata:
3432 msg, node, rej = cmdutil.tryimportone(ui, repo,
3432 msg, node, rej = cmdutil.tryimportone(ui, repo,
3433 patchdata,
3433 patchdata,
3434 parents, opts,
3434 parents, opts,
3435 msgs, hg.clean)
3435 msgs, hg.clean)
3436 if msg:
3436 if msg:
3437 haspatch = True
3437 haspatch = True
3438 ui.note(msg + '\n')
3438 ui.note(msg + '\n')
3439 if update or exact:
3439 if update or exact:
3440 parents = repo[None].parents()
3440 parents = repo[None].parents()
3441 else:
3441 else:
3442 parents = [repo[node]]
3442 parents = [repo[node]]
3443 if rej:
3443 if rej:
3444 ui.write_err(_("patch applied partially\n"))
3444 ui.write_err(_("patch applied partially\n"))
3445 ui.write_err(_("(fix the .rej files and run "
3445 ui.write_err(_("(fix the .rej files and run "
3446 "`hg commit --amend`)\n"))
3446 "`hg commit --amend`)\n"))
3447 ret = 1
3447 ret = 1
3448 break
3448 break
3449
3449
3450 if not haspatch:
3450 if not haspatch:
3451 raise error.Abort(_('%s: no diffs found') % patchurl)
3451 raise error.Abort(_('%s: no diffs found') % patchurl)
3452
3452
3453 if msgs:
3453 if msgs:
3454 repo.savecommitmessage('\n* * *\n'.join(msgs))
3454 repo.savecommitmessage('\n* * *\n'.join(msgs))
3455 return ret
3455 return ret
3456
3456
3457 @command('incoming|in',
3457 @command('incoming|in',
3458 [('f', 'force', None,
3458 [('f', 'force', None,
3459 _('run even if remote repository is unrelated')),
3459 _('run even if remote repository is unrelated')),
3460 ('n', 'newest-first', None, _('show newest record first')),
3460 ('n', 'newest-first', None, _('show newest record first')),
3461 ('', 'bundle', '',
3461 ('', 'bundle', '',
3462 _('file to store the bundles into'), _('FILE')),
3462 _('file to store the bundles into'), _('FILE')),
3463 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3463 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3464 ('B', 'bookmarks', False, _("compare bookmarks")),
3464 ('B', 'bookmarks', False, _("compare bookmarks")),
3465 ('b', 'branch', [],
3465 ('b', 'branch', [],
3466 _('a specific branch you would like to pull'), _('BRANCH')),
3466 _('a specific branch you would like to pull'), _('BRANCH')),
3467 ] + logopts + remoteopts + subrepoopts,
3467 ] + logopts + remoteopts + subrepoopts,
3468 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3468 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3469 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3469 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3470 def incoming(ui, repo, source="default", **opts):
3470 def incoming(ui, repo, source="default", **opts):
3471 """show new changesets found in source
3471 """show new changesets found in source
3472
3472
3473 Show new changesets found in the specified path/URL or the default
3473 Show new changesets found in the specified path/URL or the default
3474 pull location. These are the changesets that would have been pulled
3474 pull location. These are the changesets that would have been pulled
3475 by :hg:`pull` at the time you issued this command.
3475 by :hg:`pull` at the time you issued this command.
3476
3476
3477 See pull for valid source format details.
3477 See pull for valid source format details.
3478
3478
3479 .. container:: verbose
3479 .. container:: verbose
3480
3480
3481 With -B/--bookmarks, the result of bookmark comparison between
3481 With -B/--bookmarks, the result of bookmark comparison between
3482 local and remote repositories is displayed. With -v/--verbose,
3482 local and remote repositories is displayed. With -v/--verbose,
3483 status is also displayed for each bookmark like below::
3483 status is also displayed for each bookmark like below::
3484
3484
3485 BM1 01234567890a added
3485 BM1 01234567890a added
3486 BM2 1234567890ab advanced
3486 BM2 1234567890ab advanced
3487 BM3 234567890abc diverged
3487 BM3 234567890abc diverged
3488 BM4 34567890abcd changed
3488 BM4 34567890abcd changed
3489
3489
3490 The action taken locally when pulling depends on the
3490 The action taken locally when pulling depends on the
3491 status of each bookmark:
3491 status of each bookmark:
3492
3492
3493 :``added``: pull will create it
3493 :``added``: pull will create it
3494 :``advanced``: pull will update it
3494 :``advanced``: pull will update it
3495 :``diverged``: pull will create a divergent bookmark
3495 :``diverged``: pull will create a divergent bookmark
3496 :``changed``: result depends on remote changesets
3496 :``changed``: result depends on remote changesets
3497
3497
3498 From the point of view of pulling behavior, bookmark
3498 From the point of view of pulling behavior, bookmark
3499 existing only in the remote repository are treated as ``added``,
3499 existing only in the remote repository are treated as ``added``,
3500 even if it is in fact locally deleted.
3500 even if it is in fact locally deleted.
3501
3501
3502 .. container:: verbose
3502 .. container:: verbose
3503
3503
3504 For remote repository, using --bundle avoids downloading the
3504 For remote repository, using --bundle avoids downloading the
3505 changesets twice if the incoming is followed by a pull.
3505 changesets twice if the incoming is followed by a pull.
3506
3506
3507 Examples:
3507 Examples:
3508
3508
3509 - show incoming changes with patches and full description::
3509 - show incoming changes with patches and full description::
3510
3510
3511 hg incoming -vp
3511 hg incoming -vp
3512
3512
3513 - show incoming changes excluding merges, store a bundle::
3513 - show incoming changes excluding merges, store a bundle::
3514
3514
3515 hg in -vpM --bundle incoming.hg
3515 hg in -vpM --bundle incoming.hg
3516 hg pull incoming.hg
3516 hg pull incoming.hg
3517
3517
3518 - briefly list changes inside a bundle::
3518 - briefly list changes inside a bundle::
3519
3519
3520 hg in changes.hg -T "{desc|firstline}\\n"
3520 hg in changes.hg -T "{desc|firstline}\\n"
3521
3521
3522 Returns 0 if there are incoming changes, 1 otherwise.
3522 Returns 0 if there are incoming changes, 1 otherwise.
3523 """
3523 """
3524 opts = pycompat.byteskwargs(opts)
3524 opts = pycompat.byteskwargs(opts)
3525 if opts.get('graph'):
3525 if opts.get('graph'):
3526 logcmdutil.checkunsupportedgraphflags([], opts)
3526 logcmdutil.checkunsupportedgraphflags([], opts)
3527 def display(other, chlist, displayer):
3527 def display(other, chlist, displayer):
3528 revdag = logcmdutil.graphrevs(other, chlist, opts)
3528 revdag = logcmdutil.graphrevs(other, chlist, opts)
3529 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3529 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3530 graphmod.asciiedges)
3530 graphmod.asciiedges)
3531
3531
3532 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3532 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3533 return 0
3533 return 0
3534
3534
3535 if opts.get('bundle') and opts.get('subrepos'):
3535 if opts.get('bundle') and opts.get('subrepos'):
3536 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3536 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3537
3537
3538 if opts.get('bookmarks'):
3538 if opts.get('bookmarks'):
3539 source, branches = hg.parseurl(ui.expandpath(source),
3539 source, branches = hg.parseurl(ui.expandpath(source),
3540 opts.get('branch'))
3540 opts.get('branch'))
3541 other = hg.peer(repo, opts, source)
3541 other = hg.peer(repo, opts, source)
3542 if 'bookmarks' not in other.listkeys('namespaces'):
3542 if 'bookmarks' not in other.listkeys('namespaces'):
3543 ui.warn(_("remote doesn't support bookmarks\n"))
3543 ui.warn(_("remote doesn't support bookmarks\n"))
3544 return 0
3544 return 0
3545 ui.pager('incoming')
3545 ui.pager('incoming')
3546 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3546 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3547 return bookmarks.incoming(ui, repo, other)
3547 return bookmarks.incoming(ui, repo, other)
3548
3548
3549 repo._subtoppath = ui.expandpath(source)
3549 repo._subtoppath = ui.expandpath(source)
3550 try:
3550 try:
3551 return hg.incoming(ui, repo, source, opts)
3551 return hg.incoming(ui, repo, source, opts)
3552 finally:
3552 finally:
3553 del repo._subtoppath
3553 del repo._subtoppath
3554
3554
3555
3555
3556 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3556 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3557 helpcategory=command.CATEGORY_REPO_CREATION,
3557 helpcategory=command.CATEGORY_REPO_CREATION,
3558 helpbasic=True, norepo=True)
3558 helpbasic=True, norepo=True)
3559 def init(ui, dest=".", **opts):
3559 def init(ui, dest=".", **opts):
3560 """create a new repository in the given directory
3560 """create a new repository in the given directory
3561
3561
3562 Initialize a new repository in the given directory. If the given
3562 Initialize a new repository in the given directory. If the given
3563 directory does not exist, it will be created.
3563 directory does not exist, it will be created.
3564
3564
3565 If no directory is given, the current directory is used.
3565 If no directory is given, the current directory is used.
3566
3566
3567 It is possible to specify an ``ssh://`` URL as the destination.
3567 It is possible to specify an ``ssh://`` URL as the destination.
3568 See :hg:`help urls` for more information.
3568 See :hg:`help urls` for more information.
3569
3569
3570 Returns 0 on success.
3570 Returns 0 on success.
3571 """
3571 """
3572 opts = pycompat.byteskwargs(opts)
3572 opts = pycompat.byteskwargs(opts)
3573 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3573 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3574
3574
3575 @command('locate',
3575 @command('locate',
3576 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3576 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3577 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3577 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3578 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3578 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3579 ] + walkopts,
3579 ] + walkopts,
3580 _('[OPTION]... [PATTERN]...'),
3580 _('[OPTION]... [PATTERN]...'),
3581 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3581 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3582 def locate(ui, repo, *pats, **opts):
3582 def locate(ui, repo, *pats, **opts):
3583 """locate files matching specific patterns (DEPRECATED)
3583 """locate files matching specific patterns (DEPRECATED)
3584
3584
3585 Print files under Mercurial control in the working directory whose
3585 Print files under Mercurial control in the working directory whose
3586 names match the given patterns.
3586 names match the given patterns.
3587
3587
3588 By default, this command searches all directories in the working
3588 By default, this command searches all directories in the working
3589 directory. To search just the current directory and its
3589 directory. To search just the current directory and its
3590 subdirectories, use "--include .".
3590 subdirectories, use "--include .".
3591
3591
3592 If no patterns are given to match, this command prints the names
3592 If no patterns are given to match, this command prints the names
3593 of all files under Mercurial control in the working directory.
3593 of all files under Mercurial control in the working directory.
3594
3594
3595 If you want to feed the output of this command into the "xargs"
3595 If you want to feed the output of this command into the "xargs"
3596 command, use the -0 option to both this command and "xargs". This
3596 command, use the -0 option to both this command and "xargs". This
3597 will avoid the problem of "xargs" treating single filenames that
3597 will avoid the problem of "xargs" treating single filenames that
3598 contain whitespace as multiple filenames.
3598 contain whitespace as multiple filenames.
3599
3599
3600 See :hg:`help files` for a more versatile command.
3600 See :hg:`help files` for a more versatile command.
3601
3601
3602 Returns 0 if a match is found, 1 otherwise.
3602 Returns 0 if a match is found, 1 otherwise.
3603 """
3603 """
3604 opts = pycompat.byteskwargs(opts)
3604 opts = pycompat.byteskwargs(opts)
3605 if opts.get('print0'):
3605 if opts.get('print0'):
3606 end = '\0'
3606 end = '\0'
3607 else:
3607 else:
3608 end = '\n'
3608 end = '\n'
3609 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3609 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3610
3610
3611 ret = 1
3611 ret = 1
3612 m = scmutil.match(ctx, pats, opts, default='relglob',
3612 m = scmutil.match(ctx, pats, opts, default='relglob',
3613 badfn=lambda x, y: False)
3613 badfn=lambda x, y: False)
3614
3614
3615 ui.pager('locate')
3615 ui.pager('locate')
3616 if ctx.rev() is None:
3616 if ctx.rev() is None:
3617 # When run on the working copy, "locate" includes removed files, so
3617 # When run on the working copy, "locate" includes removed files, so
3618 # we get the list of files from the dirstate.
3618 # we get the list of files from the dirstate.
3619 filesgen = sorted(repo.dirstate.matches(m))
3619 filesgen = sorted(repo.dirstate.matches(m))
3620 else:
3620 else:
3621 filesgen = ctx.matches(m)
3621 filesgen = ctx.matches(m)
3622 for abs in filesgen:
3622 for abs in filesgen:
3623 if opts.get('fullpath'):
3623 if opts.get('fullpath'):
3624 ui.write(repo.wjoin(abs), end)
3624 ui.write(repo.wjoin(abs), end)
3625 else:
3625 else:
3626 ui.write(((pats and m.rel(abs)) or abs), end)
3626 ui.write(((pats and m.rel(abs)) or abs), end)
3627 ret = 0
3627 ret = 0
3628
3628
3629 return ret
3629 return ret
3630
3630
3631 @command('log|history',
3631 @command('log|history',
3632 [('f', 'follow', None,
3632 [('f', 'follow', None,
3633 _('follow changeset history, or file history across copies and renames')),
3633 _('follow changeset history, or file history across copies and renames')),
3634 ('', 'follow-first', None,
3634 ('', 'follow-first', None,
3635 _('only follow the first parent of merge changesets (DEPRECATED)')),
3635 _('only follow the first parent of merge changesets (DEPRECATED)')),
3636 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3636 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3637 ('C', 'copies', None, _('show copied files')),
3637 ('C', 'copies', None, _('show copied files')),
3638 ('k', 'keyword', [],
3638 ('k', 'keyword', [],
3639 _('do case-insensitive search for a given text'), _('TEXT')),
3639 _('do case-insensitive search for a given text'), _('TEXT')),
3640 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3640 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3641 ('L', 'line-range', [],
3641 ('L', 'line-range', [],
3642 _('follow line range of specified file (EXPERIMENTAL)'),
3642 _('follow line range of specified file (EXPERIMENTAL)'),
3643 _('FILE,RANGE')),
3643 _('FILE,RANGE')),
3644 ('', 'removed', None, _('include revisions where files were removed')),
3644 ('', 'removed', None, _('include revisions where files were removed')),
3645 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3645 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3646 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3646 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3647 ('', 'only-branch', [],
3647 ('', 'only-branch', [],
3648 _('show only changesets within the given named branch (DEPRECATED)'),
3648 _('show only changesets within the given named branch (DEPRECATED)'),
3649 _('BRANCH')),
3649 _('BRANCH')),
3650 ('b', 'branch', [],
3650 ('b', 'branch', [],
3651 _('show changesets within the given named branch'), _('BRANCH')),
3651 _('show changesets within the given named branch'), _('BRANCH')),
3652 ('P', 'prune', [],
3652 ('P', 'prune', [],
3653 _('do not display revision or any of its ancestors'), _('REV')),
3653 _('do not display revision or any of its ancestors'), _('REV')),
3654 ] + logopts + walkopts,
3654 ] + logopts + walkopts,
3655 _('[OPTION]... [FILE]'),
3655 _('[OPTION]... [FILE]'),
3656 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3656 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3657 helpbasic=True, inferrepo=True,
3657 helpbasic=True, inferrepo=True,
3658 intents={INTENT_READONLY})
3658 intents={INTENT_READONLY})
3659 def log(ui, repo, *pats, **opts):
3659 def log(ui, repo, *pats, **opts):
3660 """show revision history of entire repository or files
3660 """show revision history of entire repository or files
3661
3661
3662 Print the revision history of the specified files or the entire
3662 Print the revision history of the specified files or the entire
3663 project.
3663 project.
3664
3664
3665 If no revision range is specified, the default is ``tip:0`` unless
3665 If no revision range is specified, the default is ``tip:0`` unless
3666 --follow is set, in which case the working directory parent is
3666 --follow is set, in which case the working directory parent is
3667 used as the starting revision.
3667 used as the starting revision.
3668
3668
3669 File history is shown without following rename or copy history of
3669 File history is shown without following rename or copy history of
3670 files. Use -f/--follow with a filename to follow history across
3670 files. Use -f/--follow with a filename to follow history across
3671 renames and copies. --follow without a filename will only show
3671 renames and copies. --follow without a filename will only show
3672 ancestors of the starting revision.
3672 ancestors of the starting revision.
3673
3673
3674 By default this command prints revision number and changeset id,
3674 By default this command prints revision number and changeset id,
3675 tags, non-trivial parents, user, date and time, and a summary for
3675 tags, non-trivial parents, user, date and time, and a summary for
3676 each commit. When the -v/--verbose switch is used, the list of
3676 each commit. When the -v/--verbose switch is used, the list of
3677 changed files and full commit message are shown.
3677 changed files and full commit message are shown.
3678
3678
3679 With --graph the revisions are shown as an ASCII art DAG with the most
3679 With --graph the revisions are shown as an ASCII art DAG with the most
3680 recent changeset at the top.
3680 recent changeset at the top.
3681 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3681 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3682 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3682 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3683 changeset from the lines below is a parent of the 'o' merge on the same
3683 changeset from the lines below is a parent of the 'o' merge on the same
3684 line.
3684 line.
3685 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3685 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3686 of a '|' indicates one or more revisions in a path are omitted.
3686 of a '|' indicates one or more revisions in a path are omitted.
3687
3687
3688 .. container:: verbose
3688 .. container:: verbose
3689
3689
3690 Use -L/--line-range FILE,M:N options to follow the history of lines
3690 Use -L/--line-range FILE,M:N options to follow the history of lines
3691 from M to N in FILE. With -p/--patch only diff hunks affecting
3691 from M to N in FILE. With -p/--patch only diff hunks affecting
3692 specified line range will be shown. This option requires --follow;
3692 specified line range will be shown. This option requires --follow;
3693 it can be specified multiple times. Currently, this option is not
3693 it can be specified multiple times. Currently, this option is not
3694 compatible with --graph. This option is experimental.
3694 compatible with --graph. This option is experimental.
3695
3695
3696 .. note::
3696 .. note::
3697
3697
3698 :hg:`log --patch` may generate unexpected diff output for merge
3698 :hg:`log --patch` may generate unexpected diff output for merge
3699 changesets, as it will only compare the merge changeset against
3699 changesets, as it will only compare the merge changeset against
3700 its first parent. Also, only files different from BOTH parents
3700 its first parent. Also, only files different from BOTH parents
3701 will appear in files:.
3701 will appear in files:.
3702
3702
3703 .. note::
3703 .. note::
3704
3704
3705 For performance reasons, :hg:`log FILE` may omit duplicate changes
3705 For performance reasons, :hg:`log FILE` may omit duplicate changes
3706 made on branches and will not show removals or mode changes. To
3706 made on branches and will not show removals or mode changes. To
3707 see all such changes, use the --removed switch.
3707 see all such changes, use the --removed switch.
3708
3708
3709 .. container:: verbose
3709 .. container:: verbose
3710
3710
3711 .. note::
3711 .. note::
3712
3712
3713 The history resulting from -L/--line-range options depends on diff
3713 The history resulting from -L/--line-range options depends on diff
3714 options; for instance if white-spaces are ignored, respective changes
3714 options; for instance if white-spaces are ignored, respective changes
3715 with only white-spaces in specified line range will not be listed.
3715 with only white-spaces in specified line range will not be listed.
3716
3716
3717 .. container:: verbose
3717 .. container:: verbose
3718
3718
3719 Some examples:
3719 Some examples:
3720
3720
3721 - changesets with full descriptions and file lists::
3721 - changesets with full descriptions and file lists::
3722
3722
3723 hg log -v
3723 hg log -v
3724
3724
3725 - changesets ancestral to the working directory::
3725 - changesets ancestral to the working directory::
3726
3726
3727 hg log -f
3727 hg log -f
3728
3728
3729 - last 10 commits on the current branch::
3729 - last 10 commits on the current branch::
3730
3730
3731 hg log -l 10 -b .
3731 hg log -l 10 -b .
3732
3732
3733 - changesets showing all modifications of a file, including removals::
3733 - changesets showing all modifications of a file, including removals::
3734
3734
3735 hg log --removed file.c
3735 hg log --removed file.c
3736
3736
3737 - all changesets that touch a directory, with diffs, excluding merges::
3737 - all changesets that touch a directory, with diffs, excluding merges::
3738
3738
3739 hg log -Mp lib/
3739 hg log -Mp lib/
3740
3740
3741 - all revision numbers that match a keyword::
3741 - all revision numbers that match a keyword::
3742
3742
3743 hg log -k bug --template "{rev}\\n"
3743 hg log -k bug --template "{rev}\\n"
3744
3744
3745 - the full hash identifier of the working directory parent::
3745 - the full hash identifier of the working directory parent::
3746
3746
3747 hg log -r . --template "{node}\\n"
3747 hg log -r . --template "{node}\\n"
3748
3748
3749 - list available log templates::
3749 - list available log templates::
3750
3750
3751 hg log -T list
3751 hg log -T list
3752
3752
3753 - check if a given changeset is included in a tagged release::
3753 - check if a given changeset is included in a tagged release::
3754
3754
3755 hg log -r "a21ccf and ancestor(1.9)"
3755 hg log -r "a21ccf and ancestor(1.9)"
3756
3756
3757 - find all changesets by some user in a date range::
3757 - find all changesets by some user in a date range::
3758
3758
3759 hg log -k alice -d "may 2008 to jul 2008"
3759 hg log -k alice -d "may 2008 to jul 2008"
3760
3760
3761 - summary of all changesets after the last tag::
3761 - summary of all changesets after the last tag::
3762
3762
3763 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3763 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3764
3764
3765 - changesets touching lines 13 to 23 for file.c::
3765 - changesets touching lines 13 to 23 for file.c::
3766
3766
3767 hg log -L file.c,13:23
3767 hg log -L file.c,13:23
3768
3768
3769 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3769 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3770 main.c with patch::
3770 main.c with patch::
3771
3771
3772 hg log -L file.c,13:23 -L main.c,2:6 -p
3772 hg log -L file.c,13:23 -L main.c,2:6 -p
3773
3773
3774 See :hg:`help dates` for a list of formats valid for -d/--date.
3774 See :hg:`help dates` for a list of formats valid for -d/--date.
3775
3775
3776 See :hg:`help revisions` for more about specifying and ordering
3776 See :hg:`help revisions` for more about specifying and ordering
3777 revisions.
3777 revisions.
3778
3778
3779 See :hg:`help templates` for more about pre-packaged styles and
3779 See :hg:`help templates` for more about pre-packaged styles and
3780 specifying custom templates. The default template used by the log
3780 specifying custom templates. The default template used by the log
3781 command can be customized via the ``ui.logtemplate`` configuration
3781 command can be customized via the ``ui.logtemplate`` configuration
3782 setting.
3782 setting.
3783
3783
3784 Returns 0 on success.
3784 Returns 0 on success.
3785
3785
3786 """
3786 """
3787 opts = pycompat.byteskwargs(opts)
3787 opts = pycompat.byteskwargs(opts)
3788 linerange = opts.get('line_range')
3788 linerange = opts.get('line_range')
3789
3789
3790 if linerange and not opts.get('follow'):
3790 if linerange and not opts.get('follow'):
3791 raise error.Abort(_('--line-range requires --follow'))
3791 raise error.Abort(_('--line-range requires --follow'))
3792
3792
3793 if linerange and pats:
3793 if linerange and pats:
3794 # TODO: take pats as patterns with no line-range filter
3794 # TODO: take pats as patterns with no line-range filter
3795 raise error.Abort(
3795 raise error.Abort(
3796 _('FILE arguments are not compatible with --line-range option')
3796 _('FILE arguments are not compatible with --line-range option')
3797 )
3797 )
3798
3798
3799 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3799 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3800 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3800 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3801 if linerange:
3801 if linerange:
3802 # TODO: should follow file history from logcmdutil._initialrevs(),
3802 # TODO: should follow file history from logcmdutil._initialrevs(),
3803 # then filter the result by logcmdutil._makerevset() and --limit
3803 # then filter the result by logcmdutil._makerevset() and --limit
3804 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3804 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3805
3805
3806 getrenamed = None
3806 getrenamed = None
3807 if opts.get('copies'):
3807 if opts.get('copies'):
3808 endrev = None
3808 endrev = None
3809 if revs:
3809 if revs:
3810 endrev = revs.max() + 1
3810 endrev = revs.max() + 1
3811 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3811 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3812
3812
3813 ui.pager('log')
3813 ui.pager('log')
3814 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3814 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3815 buffered=True)
3815 buffered=True)
3816 if opts.get('graph'):
3816 if opts.get('graph'):
3817 displayfn = logcmdutil.displaygraphrevs
3817 displayfn = logcmdutil.displaygraphrevs
3818 else:
3818 else:
3819 displayfn = logcmdutil.displayrevs
3819 displayfn = logcmdutil.displayrevs
3820 displayfn(ui, repo, revs, displayer, getrenamed)
3820 displayfn(ui, repo, revs, displayer, getrenamed)
3821
3821
3822 @command('manifest',
3822 @command('manifest',
3823 [('r', 'rev', '', _('revision to display'), _('REV')),
3823 [('r', 'rev', '', _('revision to display'), _('REV')),
3824 ('', 'all', False, _("list files from all revisions"))]
3824 ('', 'all', False, _("list files from all revisions"))]
3825 + formatteropts,
3825 + formatteropts,
3826 _('[-r REV]'),
3826 _('[-r REV]'),
3827 helpcategory=command.CATEGORY_MAINTENANCE,
3827 helpcategory=command.CATEGORY_MAINTENANCE,
3828 intents={INTENT_READONLY})
3828 intents={INTENT_READONLY})
3829 def manifest(ui, repo, node=None, rev=None, **opts):
3829 def manifest(ui, repo, node=None, rev=None, **opts):
3830 """output the current or given revision of the project manifest
3830 """output the current or given revision of the project manifest
3831
3831
3832 Print a list of version controlled files for the given revision.
3832 Print a list of version controlled files for the given revision.
3833 If no revision is given, the first parent of the working directory
3833 If no revision is given, the first parent of the working directory
3834 is used, or the null revision if no revision is checked out.
3834 is used, or the null revision if no revision is checked out.
3835
3835
3836 With -v, print file permissions, symlink and executable bits.
3836 With -v, print file permissions, symlink and executable bits.
3837 With --debug, print file revision hashes.
3837 With --debug, print file revision hashes.
3838
3838
3839 If option --all is specified, the list of all files from all revisions
3839 If option --all is specified, the list of all files from all revisions
3840 is printed. This includes deleted and renamed files.
3840 is printed. This includes deleted and renamed files.
3841
3841
3842 Returns 0 on success.
3842 Returns 0 on success.
3843 """
3843 """
3844 opts = pycompat.byteskwargs(opts)
3844 opts = pycompat.byteskwargs(opts)
3845 fm = ui.formatter('manifest', opts)
3845 fm = ui.formatter('manifest', opts)
3846
3846
3847 if opts.get('all'):
3847 if opts.get('all'):
3848 if rev or node:
3848 if rev or node:
3849 raise error.Abort(_("can't specify a revision with --all"))
3849 raise error.Abort(_("can't specify a revision with --all"))
3850
3850
3851 res = set()
3851 res = set()
3852 for rev in repo:
3852 for rev in repo:
3853 ctx = repo[rev]
3853 ctx = repo[rev]
3854 res |= set(ctx.files())
3854 res |= set(ctx.files())
3855
3855
3856 ui.pager('manifest')
3856 ui.pager('manifest')
3857 for f in sorted(res):
3857 for f in sorted(res):
3858 fm.startitem()
3858 fm.startitem()
3859 fm.write("path", '%s\n', f)
3859 fm.write("path", '%s\n', f)
3860 fm.end()
3860 fm.end()
3861 return
3861 return
3862
3862
3863 if rev and node:
3863 if rev and node:
3864 raise error.Abort(_("please specify just one revision"))
3864 raise error.Abort(_("please specify just one revision"))
3865
3865
3866 if not node:
3866 if not node:
3867 node = rev
3867 node = rev
3868
3868
3869 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3869 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3870 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3870 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3871 if node:
3871 if node:
3872 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3872 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3873 ctx = scmutil.revsingle(repo, node)
3873 ctx = scmutil.revsingle(repo, node)
3874 mf = ctx.manifest()
3874 mf = ctx.manifest()
3875 ui.pager('manifest')
3875 ui.pager('manifest')
3876 for f in ctx:
3876 for f in ctx:
3877 fm.startitem()
3877 fm.startitem()
3878 fm.context(ctx=ctx)
3878 fm.context(ctx=ctx)
3879 fl = ctx[f].flags()
3879 fl = ctx[f].flags()
3880 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3880 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3881 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3881 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3882 fm.write('path', '%s\n', f)
3882 fm.write('path', '%s\n', f)
3883 fm.end()
3883 fm.end()
3884
3884
3885 @command('merge',
3885 @command('merge',
3886 [('f', 'force', None,
3886 [('f', 'force', None,
3887 _('force a merge including outstanding changes (DEPRECATED)')),
3887 _('force a merge including outstanding changes (DEPRECATED)')),
3888 ('r', 'rev', '', _('revision to merge'), _('REV')),
3888 ('r', 'rev', '', _('revision to merge'), _('REV')),
3889 ('P', 'preview', None,
3889 ('P', 'preview', None,
3890 _('review revisions to merge (no merge is performed)')),
3890 _('review revisions to merge (no merge is performed)')),
3891 ('', 'abort', None, _('abort the ongoing merge')),
3891 ('', 'abort', None, _('abort the ongoing merge')),
3892 ] + mergetoolopts,
3892 ] + mergetoolopts,
3893 _('[-P] [[-r] REV]'),
3893 _('[-P] [[-r] REV]'),
3894 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3894 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3895 def merge(ui, repo, node=None, **opts):
3895 def merge(ui, repo, node=None, **opts):
3896 """merge another revision into working directory
3896 """merge another revision into working directory
3897
3897
3898 The current working directory is updated with all changes made in
3898 The current working directory is updated with all changes made in
3899 the requested revision since the last common predecessor revision.
3899 the requested revision since the last common predecessor revision.
3900
3900
3901 Files that changed between either parent are marked as changed for
3901 Files that changed between either parent are marked as changed for
3902 the next commit and a commit must be performed before any further
3902 the next commit and a commit must be performed before any further
3903 updates to the repository are allowed. The next commit will have
3903 updates to the repository are allowed. The next commit will have
3904 two parents.
3904 two parents.
3905
3905
3906 ``--tool`` can be used to specify the merge tool used for file
3906 ``--tool`` can be used to specify the merge tool used for file
3907 merges. It overrides the HGMERGE environment variable and your
3907 merges. It overrides the HGMERGE environment variable and your
3908 configuration files. See :hg:`help merge-tools` for options.
3908 configuration files. See :hg:`help merge-tools` for options.
3909
3909
3910 If no revision is specified, the working directory's parent is a
3910 If no revision is specified, the working directory's parent is a
3911 head revision, and the current branch contains exactly one other
3911 head revision, and the current branch contains exactly one other
3912 head, the other head is merged with by default. Otherwise, an
3912 head, the other head is merged with by default. Otherwise, an
3913 explicit revision with which to merge with must be provided.
3913 explicit revision with which to merge with must be provided.
3914
3914
3915 See :hg:`help resolve` for information on handling file conflicts.
3915 See :hg:`help resolve` for information on handling file conflicts.
3916
3916
3917 To undo an uncommitted merge, use :hg:`merge --abort` which
3917 To undo an uncommitted merge, use :hg:`merge --abort` which
3918 will check out a clean copy of the original merge parent, losing
3918 will check out a clean copy of the original merge parent, losing
3919 all changes.
3919 all changes.
3920
3920
3921 Returns 0 on success, 1 if there are unresolved files.
3921 Returns 0 on success, 1 if there are unresolved files.
3922 """
3922 """
3923
3923
3924 opts = pycompat.byteskwargs(opts)
3924 opts = pycompat.byteskwargs(opts)
3925 abort = opts.get('abort')
3925 abort = opts.get('abort')
3926 if abort and repo.dirstate.p2() == nullid:
3926 if abort and repo.dirstate.p2() == nullid:
3927 cmdutil.wrongtooltocontinue(repo, _('merge'))
3927 cmdutil.wrongtooltocontinue(repo, _('merge'))
3928 if abort:
3928 if abort:
3929 if node:
3929 if node:
3930 raise error.Abort(_("cannot specify a node with --abort"))
3930 raise error.Abort(_("cannot specify a node with --abort"))
3931 if opts.get('rev'):
3931 if opts.get('rev'):
3932 raise error.Abort(_("cannot specify both --rev and --abort"))
3932 raise error.Abort(_("cannot specify both --rev and --abort"))
3933 if opts.get('preview'):
3933 if opts.get('preview'):
3934 raise error.Abort(_("cannot specify --preview with --abort"))
3934 raise error.Abort(_("cannot specify --preview with --abort"))
3935 if opts.get('rev') and node:
3935 if opts.get('rev') and node:
3936 raise error.Abort(_("please specify just one revision"))
3936 raise error.Abort(_("please specify just one revision"))
3937 if not node:
3937 if not node:
3938 node = opts.get('rev')
3938 node = opts.get('rev')
3939
3939
3940 if node:
3940 if node:
3941 node = scmutil.revsingle(repo, node).node()
3941 node = scmutil.revsingle(repo, node).node()
3942
3942
3943 if not node and not abort:
3943 if not node and not abort:
3944 node = repo[destutil.destmerge(repo)].node()
3944 node = repo[destutil.destmerge(repo)].node()
3945
3945
3946 if opts.get('preview'):
3946 if opts.get('preview'):
3947 # find nodes that are ancestors of p2 but not of p1
3947 # find nodes that are ancestors of p2 but not of p1
3948 p1 = repo.lookup('.')
3948 p1 = repo.lookup('.')
3949 p2 = node
3949 p2 = node
3950 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3950 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3951
3951
3952 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3952 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3953 for node in nodes:
3953 for node in nodes:
3954 displayer.show(repo[node])
3954 displayer.show(repo[node])
3955 displayer.close()
3955 displayer.close()
3956 return 0
3956 return 0
3957
3957
3958 # ui.forcemerge is an internal variable, do not document
3958 # ui.forcemerge is an internal variable, do not document
3959 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3959 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3960 with ui.configoverride(overrides, 'merge'):
3960 with ui.configoverride(overrides, 'merge'):
3961 force = opts.get('force')
3961 force = opts.get('force')
3962 labels = ['working copy', 'merge rev']
3962 labels = ['working copy', 'merge rev']
3963 return hg.merge(repo, node, force=force, mergeforce=force,
3963 return hg.merge(repo, node, force=force, mergeforce=force,
3964 labels=labels, abort=abort)
3964 labels=labels, abort=abort)
3965
3965
3966 @command('outgoing|out',
3966 @command('outgoing|out',
3967 [('f', 'force', None, _('run even when the destination is unrelated')),
3967 [('f', 'force', None, _('run even when the destination is unrelated')),
3968 ('r', 'rev', [],
3968 ('r', 'rev', [],
3969 _('a changeset intended to be included in the destination'), _('REV')),
3969 _('a changeset intended to be included in the destination'), _('REV')),
3970 ('n', 'newest-first', None, _('show newest record first')),
3970 ('n', 'newest-first', None, _('show newest record first')),
3971 ('B', 'bookmarks', False, _('compare bookmarks')),
3971 ('B', 'bookmarks', False, _('compare bookmarks')),
3972 ('b', 'branch', [], _('a specific branch you would like to push'),
3972 ('b', 'branch', [], _('a specific branch you would like to push'),
3973 _('BRANCH')),
3973 _('BRANCH')),
3974 ] + logopts + remoteopts + subrepoopts,
3974 ] + logopts + remoteopts + subrepoopts,
3975 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
3975 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
3976 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3976 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3977 def outgoing(ui, repo, dest=None, **opts):
3977 def outgoing(ui, repo, dest=None, **opts):
3978 """show changesets not found in the destination
3978 """show changesets not found in the destination
3979
3979
3980 Show changesets not found in the specified destination repository
3980 Show changesets not found in the specified destination repository
3981 or the default push location. These are the changesets that would
3981 or the default push location. These are the changesets that would
3982 be pushed if a push was requested.
3982 be pushed if a push was requested.
3983
3983
3984 See pull for details of valid destination formats.
3984 See pull for details of valid destination formats.
3985
3985
3986 .. container:: verbose
3986 .. container:: verbose
3987
3987
3988 With -B/--bookmarks, the result of bookmark comparison between
3988 With -B/--bookmarks, the result of bookmark comparison between
3989 local and remote repositories is displayed. With -v/--verbose,
3989 local and remote repositories is displayed. With -v/--verbose,
3990 status is also displayed for each bookmark like below::
3990 status is also displayed for each bookmark like below::
3991
3991
3992 BM1 01234567890a added
3992 BM1 01234567890a added
3993 BM2 deleted
3993 BM2 deleted
3994 BM3 234567890abc advanced
3994 BM3 234567890abc advanced
3995 BM4 34567890abcd diverged
3995 BM4 34567890abcd diverged
3996 BM5 4567890abcde changed
3996 BM5 4567890abcde changed
3997
3997
3998 The action taken when pushing depends on the
3998 The action taken when pushing depends on the
3999 status of each bookmark:
3999 status of each bookmark:
4000
4000
4001 :``added``: push with ``-B`` will create it
4001 :``added``: push with ``-B`` will create it
4002 :``deleted``: push with ``-B`` will delete it
4002 :``deleted``: push with ``-B`` will delete it
4003 :``advanced``: push will update it
4003 :``advanced``: push will update it
4004 :``diverged``: push with ``-B`` will update it
4004 :``diverged``: push with ``-B`` will update it
4005 :``changed``: push with ``-B`` will update it
4005 :``changed``: push with ``-B`` will update it
4006
4006
4007 From the point of view of pushing behavior, bookmarks
4007 From the point of view of pushing behavior, bookmarks
4008 existing only in the remote repository are treated as
4008 existing only in the remote repository are treated as
4009 ``deleted``, even if it is in fact added remotely.
4009 ``deleted``, even if it is in fact added remotely.
4010
4010
4011 Returns 0 if there are outgoing changes, 1 otherwise.
4011 Returns 0 if there are outgoing changes, 1 otherwise.
4012 """
4012 """
4013 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4013 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4014 # style URLs, so don't overwrite dest.
4014 # style URLs, so don't overwrite dest.
4015 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4015 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4016 if not path:
4016 if not path:
4017 raise error.Abort(_('default repository not configured!'),
4017 raise error.Abort(_('default repository not configured!'),
4018 hint=_("see 'hg help config.paths'"))
4018 hint=_("see 'hg help config.paths'"))
4019
4019
4020 opts = pycompat.byteskwargs(opts)
4020 opts = pycompat.byteskwargs(opts)
4021 if opts.get('graph'):
4021 if opts.get('graph'):
4022 logcmdutil.checkunsupportedgraphflags([], opts)
4022 logcmdutil.checkunsupportedgraphflags([], opts)
4023 o, other = hg._outgoing(ui, repo, dest, opts)
4023 o, other = hg._outgoing(ui, repo, dest, opts)
4024 if not o:
4024 if not o:
4025 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4025 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4026 return
4026 return
4027
4027
4028 revdag = logcmdutil.graphrevs(repo, o, opts)
4028 revdag = logcmdutil.graphrevs(repo, o, opts)
4029 ui.pager('outgoing')
4029 ui.pager('outgoing')
4030 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4030 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4031 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4031 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4032 graphmod.asciiedges)
4032 graphmod.asciiedges)
4033 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4033 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4034 return 0
4034 return 0
4035
4035
4036 if opts.get('bookmarks'):
4036 if opts.get('bookmarks'):
4037 dest = path.pushloc or path.loc
4037 dest = path.pushloc or path.loc
4038 other = hg.peer(repo, opts, dest)
4038 other = hg.peer(repo, opts, dest)
4039 if 'bookmarks' not in other.listkeys('namespaces'):
4039 if 'bookmarks' not in other.listkeys('namespaces'):
4040 ui.warn(_("remote doesn't support bookmarks\n"))
4040 ui.warn(_("remote doesn't support bookmarks\n"))
4041 return 0
4041 return 0
4042 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4042 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4043 ui.pager('outgoing')
4043 ui.pager('outgoing')
4044 return bookmarks.outgoing(ui, repo, other)
4044 return bookmarks.outgoing(ui, repo, other)
4045
4045
4046 repo._subtoppath = path.pushloc or path.loc
4046 repo._subtoppath = path.pushloc or path.loc
4047 try:
4047 try:
4048 return hg.outgoing(ui, repo, dest, opts)
4048 return hg.outgoing(ui, repo, dest, opts)
4049 finally:
4049 finally:
4050 del repo._subtoppath
4050 del repo._subtoppath
4051
4051
4052 @command('parents',
4052 @command('parents',
4053 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4053 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4054 ] + templateopts,
4054 ] + templateopts,
4055 _('[-r REV] [FILE]'),
4055 _('[-r REV] [FILE]'),
4056 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4056 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4057 inferrepo=True)
4057 inferrepo=True)
4058 def parents(ui, repo, file_=None, **opts):
4058 def parents(ui, repo, file_=None, **opts):
4059 """show the parents of the working directory or revision (DEPRECATED)
4059 """show the parents of the working directory or revision (DEPRECATED)
4060
4060
4061 Print the working directory's parent revisions. If a revision is
4061 Print the working directory's parent revisions. If a revision is
4062 given via -r/--rev, the parent of that revision will be printed.
4062 given via -r/--rev, the parent of that revision will be printed.
4063 If a file argument is given, the revision in which the file was
4063 If a file argument is given, the revision in which the file was
4064 last changed (before the working directory revision or the
4064 last changed (before the working directory revision or the
4065 argument to --rev if given) is printed.
4065 argument to --rev if given) is printed.
4066
4066
4067 This command is equivalent to::
4067 This command is equivalent to::
4068
4068
4069 hg log -r "p1()+p2()" or
4069 hg log -r "p1()+p2()" or
4070 hg log -r "p1(REV)+p2(REV)" or
4070 hg log -r "p1(REV)+p2(REV)" or
4071 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4071 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4072 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4072 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4073
4073
4074 See :hg:`summary` and :hg:`help revsets` for related information.
4074 See :hg:`summary` and :hg:`help revsets` for related information.
4075
4075
4076 Returns 0 on success.
4076 Returns 0 on success.
4077 """
4077 """
4078
4078
4079 opts = pycompat.byteskwargs(opts)
4079 opts = pycompat.byteskwargs(opts)
4080 rev = opts.get('rev')
4080 rev = opts.get('rev')
4081 if rev:
4081 if rev:
4082 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4082 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4083 ctx = scmutil.revsingle(repo, rev, None)
4083 ctx = scmutil.revsingle(repo, rev, None)
4084
4084
4085 if file_:
4085 if file_:
4086 m = scmutil.match(ctx, (file_,), opts)
4086 m = scmutil.match(ctx, (file_,), opts)
4087 if m.anypats() or len(m.files()) != 1:
4087 if m.anypats() or len(m.files()) != 1:
4088 raise error.Abort(_('can only specify an explicit filename'))
4088 raise error.Abort(_('can only specify an explicit filename'))
4089 file_ = m.files()[0]
4089 file_ = m.files()[0]
4090 filenodes = []
4090 filenodes = []
4091 for cp in ctx.parents():
4091 for cp in ctx.parents():
4092 if not cp:
4092 if not cp:
4093 continue
4093 continue
4094 try:
4094 try:
4095 filenodes.append(cp.filenode(file_))
4095 filenodes.append(cp.filenode(file_))
4096 except error.LookupError:
4096 except error.LookupError:
4097 pass
4097 pass
4098 if not filenodes:
4098 if not filenodes:
4099 raise error.Abort(_("'%s' not found in manifest!") % file_)
4099 raise error.Abort(_("'%s' not found in manifest!") % file_)
4100 p = []
4100 p = []
4101 for fn in filenodes:
4101 for fn in filenodes:
4102 fctx = repo.filectx(file_, fileid=fn)
4102 fctx = repo.filectx(file_, fileid=fn)
4103 p.append(fctx.node())
4103 p.append(fctx.node())
4104 else:
4104 else:
4105 p = [cp.node() for cp in ctx.parents()]
4105 p = [cp.node() for cp in ctx.parents()]
4106
4106
4107 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4107 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4108 for n in p:
4108 for n in p:
4109 if n != nullid:
4109 if n != nullid:
4110 displayer.show(repo[n])
4110 displayer.show(repo[n])
4111 displayer.close()
4111 displayer.close()
4112
4112
4113 @command('paths', formatteropts, _('[NAME]'),
4113 @command('paths', formatteropts, _('[NAME]'),
4114 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4114 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4115 optionalrepo=True, intents={INTENT_READONLY})
4115 optionalrepo=True, intents={INTENT_READONLY})
4116 def paths(ui, repo, search=None, **opts):
4116 def paths(ui, repo, search=None, **opts):
4117 """show aliases for remote repositories
4117 """show aliases for remote repositories
4118
4118
4119 Show definition of symbolic path name NAME. If no name is given,
4119 Show definition of symbolic path name NAME. If no name is given,
4120 show definition of all available names.
4120 show definition of all available names.
4121
4121
4122 Option -q/--quiet suppresses all output when searching for NAME
4122 Option -q/--quiet suppresses all output when searching for NAME
4123 and shows only the path names when listing all definitions.
4123 and shows only the path names when listing all definitions.
4124
4124
4125 Path names are defined in the [paths] section of your
4125 Path names are defined in the [paths] section of your
4126 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4126 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4127 repository, ``.hg/hgrc`` is used, too.
4127 repository, ``.hg/hgrc`` is used, too.
4128
4128
4129 The path names ``default`` and ``default-push`` have a special
4129 The path names ``default`` and ``default-push`` have a special
4130 meaning. When performing a push or pull operation, they are used
4130 meaning. When performing a push or pull operation, they are used
4131 as fallbacks if no location is specified on the command-line.
4131 as fallbacks if no location is specified on the command-line.
4132 When ``default-push`` is set, it will be used for push and
4132 When ``default-push`` is set, it will be used for push and
4133 ``default`` will be used for pull; otherwise ``default`` is used
4133 ``default`` will be used for pull; otherwise ``default`` is used
4134 as the fallback for both. When cloning a repository, the clone
4134 as the fallback for both. When cloning a repository, the clone
4135 source is written as ``default`` in ``.hg/hgrc``.
4135 source is written as ``default`` in ``.hg/hgrc``.
4136
4136
4137 .. note::
4137 .. note::
4138
4138
4139 ``default`` and ``default-push`` apply to all inbound (e.g.
4139 ``default`` and ``default-push`` apply to all inbound (e.g.
4140 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4140 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4141 and :hg:`bundle`) operations.
4141 and :hg:`bundle`) operations.
4142
4142
4143 See :hg:`help urls` for more information.
4143 See :hg:`help urls` for more information.
4144
4144
4145 .. container:: verbose
4145 .. container:: verbose
4146
4146
4147 Template:
4147 Template:
4148
4148
4149 The following keywords are supported. See also :hg:`help templates`.
4149 The following keywords are supported. See also :hg:`help templates`.
4150
4150
4151 :name: String. Symbolic name of the path alias.
4151 :name: String. Symbolic name of the path alias.
4152 :pushurl: String. URL for push operations.
4152 :pushurl: String. URL for push operations.
4153 :url: String. URL or directory path for the other operations.
4153 :url: String. URL or directory path for the other operations.
4154
4154
4155 Returns 0 on success.
4155 Returns 0 on success.
4156 """
4156 """
4157
4157
4158 opts = pycompat.byteskwargs(opts)
4158 opts = pycompat.byteskwargs(opts)
4159 ui.pager('paths')
4159 ui.pager('paths')
4160 if search:
4160 if search:
4161 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4161 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4162 if name == search]
4162 if name == search]
4163 else:
4163 else:
4164 pathitems = sorted(ui.paths.iteritems())
4164 pathitems = sorted(ui.paths.iteritems())
4165
4165
4166 fm = ui.formatter('paths', opts)
4166 fm = ui.formatter('paths', opts)
4167 if fm.isplain():
4167 if fm.isplain():
4168 hidepassword = util.hidepassword
4168 hidepassword = util.hidepassword
4169 else:
4169 else:
4170 hidepassword = bytes
4170 hidepassword = bytes
4171 if ui.quiet:
4171 if ui.quiet:
4172 namefmt = '%s\n'
4172 namefmt = '%s\n'
4173 else:
4173 else:
4174 namefmt = '%s = '
4174 namefmt = '%s = '
4175 showsubopts = not search and not ui.quiet
4175 showsubopts = not search and not ui.quiet
4176
4176
4177 for name, path in pathitems:
4177 for name, path in pathitems:
4178 fm.startitem()
4178 fm.startitem()
4179 fm.condwrite(not search, 'name', namefmt, name)
4179 fm.condwrite(not search, 'name', namefmt, name)
4180 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4180 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4181 for subopt, value in sorted(path.suboptions.items()):
4181 for subopt, value in sorted(path.suboptions.items()):
4182 assert subopt not in ('name', 'url')
4182 assert subopt not in ('name', 'url')
4183 if showsubopts:
4183 if showsubopts:
4184 fm.plain('%s:%s = ' % (name, subopt))
4184 fm.plain('%s:%s = ' % (name, subopt))
4185 fm.condwrite(showsubopts, subopt, '%s\n', value)
4185 fm.condwrite(showsubopts, subopt, '%s\n', value)
4186
4186
4187 fm.end()
4187 fm.end()
4188
4188
4189 if search and not pathitems:
4189 if search and not pathitems:
4190 if not ui.quiet:
4190 if not ui.quiet:
4191 ui.warn(_("not found!\n"))
4191 ui.warn(_("not found!\n"))
4192 return 1
4192 return 1
4193 else:
4193 else:
4194 return 0
4194 return 0
4195
4195
4196 @command('phase',
4196 @command('phase',
4197 [('p', 'public', False, _('set changeset phase to public')),
4197 [('p', 'public', False, _('set changeset phase to public')),
4198 ('d', 'draft', False, _('set changeset phase to draft')),
4198 ('d', 'draft', False, _('set changeset phase to draft')),
4199 ('s', 'secret', False, _('set changeset phase to secret')),
4199 ('s', 'secret', False, _('set changeset phase to secret')),
4200 ('f', 'force', False, _('allow to move boundary backward')),
4200 ('f', 'force', False, _('allow to move boundary backward')),
4201 ('r', 'rev', [], _('target revision'), _('REV')),
4201 ('r', 'rev', [], _('target revision'), _('REV')),
4202 ],
4202 ],
4203 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4203 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4204 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4204 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4205 def phase(ui, repo, *revs, **opts):
4205 def phase(ui, repo, *revs, **opts):
4206 """set or show the current phase name
4206 """set or show the current phase name
4207
4207
4208 With no argument, show the phase name of the current revision(s).
4208 With no argument, show the phase name of the current revision(s).
4209
4209
4210 With one of -p/--public, -d/--draft or -s/--secret, change the
4210 With one of -p/--public, -d/--draft or -s/--secret, change the
4211 phase value of the specified revisions.
4211 phase value of the specified revisions.
4212
4212
4213 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4213 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4214 lower phase to a higher phase. Phases are ordered as follows::
4214 lower phase to a higher phase. Phases are ordered as follows::
4215
4215
4216 public < draft < secret
4216 public < draft < secret
4217
4217
4218 Returns 0 on success, 1 if some phases could not be changed.
4218 Returns 0 on success, 1 if some phases could not be changed.
4219
4219
4220 (For more information about the phases concept, see :hg:`help phases`.)
4220 (For more information about the phases concept, see :hg:`help phases`.)
4221 """
4221 """
4222 opts = pycompat.byteskwargs(opts)
4222 opts = pycompat.byteskwargs(opts)
4223 # search for a unique phase argument
4223 # search for a unique phase argument
4224 targetphase = None
4224 targetphase = None
4225 for idx, name in enumerate(phases.phasenames):
4225 for idx, name in enumerate(phases.phasenames):
4226 if opts.get(name, False):
4226 if opts.get(name, False):
4227 if targetphase is not None:
4227 if targetphase is not None:
4228 raise error.Abort(_('only one phase can be specified'))
4228 raise error.Abort(_('only one phase can be specified'))
4229 targetphase = idx
4229 targetphase = idx
4230
4230
4231 # look for specified revision
4231 # look for specified revision
4232 revs = list(revs)
4232 revs = list(revs)
4233 revs.extend(opts['rev'])
4233 revs.extend(opts['rev'])
4234 if not revs:
4234 if not revs:
4235 # display both parents as the second parent phase can influence
4235 # display both parents as the second parent phase can influence
4236 # the phase of a merge commit
4236 # the phase of a merge commit
4237 revs = [c.rev() for c in repo[None].parents()]
4237 revs = [c.rev() for c in repo[None].parents()]
4238
4238
4239 revs = scmutil.revrange(repo, revs)
4239 revs = scmutil.revrange(repo, revs)
4240
4240
4241 ret = 0
4241 ret = 0
4242 if targetphase is None:
4242 if targetphase is None:
4243 # display
4243 # display
4244 for r in revs:
4244 for r in revs:
4245 ctx = repo[r]
4245 ctx = repo[r]
4246 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4246 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4247 else:
4247 else:
4248 with repo.lock(), repo.transaction("phase") as tr:
4248 with repo.lock(), repo.transaction("phase") as tr:
4249 # set phase
4249 # set phase
4250 if not revs:
4250 if not revs:
4251 raise error.Abort(_('empty revision set'))
4251 raise error.Abort(_('empty revision set'))
4252 nodes = [repo[r].node() for r in revs]
4252 nodes = [repo[r].node() for r in revs]
4253 # moving revision from public to draft may hide them
4253 # moving revision from public to draft may hide them
4254 # We have to check result on an unfiltered repository
4254 # We have to check result on an unfiltered repository
4255 unfi = repo.unfiltered()
4255 unfi = repo.unfiltered()
4256 getphase = unfi._phasecache.phase
4256 getphase = unfi._phasecache.phase
4257 olddata = [getphase(unfi, r) for r in unfi]
4257 olddata = [getphase(unfi, r) for r in unfi]
4258 phases.advanceboundary(repo, tr, targetphase, nodes)
4258 phases.advanceboundary(repo, tr, targetphase, nodes)
4259 if opts['force']:
4259 if opts['force']:
4260 phases.retractboundary(repo, tr, targetphase, nodes)
4260 phases.retractboundary(repo, tr, targetphase, nodes)
4261 getphase = unfi._phasecache.phase
4261 getphase = unfi._phasecache.phase
4262 newdata = [getphase(unfi, r) for r in unfi]
4262 newdata = [getphase(unfi, r) for r in unfi]
4263 changes = sum(newdata[r] != olddata[r] for r in unfi)
4263 changes = sum(newdata[r] != olddata[r] for r in unfi)
4264 cl = unfi.changelog
4264 cl = unfi.changelog
4265 rejected = [n for n in nodes
4265 rejected = [n for n in nodes
4266 if newdata[cl.rev(n)] < targetphase]
4266 if newdata[cl.rev(n)] < targetphase]
4267 if rejected:
4267 if rejected:
4268 ui.warn(_('cannot move %i changesets to a higher '
4268 ui.warn(_('cannot move %i changesets to a higher '
4269 'phase, use --force\n') % len(rejected))
4269 'phase, use --force\n') % len(rejected))
4270 ret = 1
4270 ret = 1
4271 if changes:
4271 if changes:
4272 msg = _('phase changed for %i changesets\n') % changes
4272 msg = _('phase changed for %i changesets\n') % changes
4273 if ret:
4273 if ret:
4274 ui.status(msg)
4274 ui.status(msg)
4275 else:
4275 else:
4276 ui.note(msg)
4276 ui.note(msg)
4277 else:
4277 else:
4278 ui.warn(_('no phases changed\n'))
4278 ui.warn(_('no phases changed\n'))
4279 return ret
4279 return ret
4280
4280
4281 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4281 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4282 """Run after a changegroup has been added via pull/unbundle
4282 """Run after a changegroup has been added via pull/unbundle
4283
4283
4284 This takes arguments below:
4284 This takes arguments below:
4285
4285
4286 :modheads: change of heads by pull/unbundle
4286 :modheads: change of heads by pull/unbundle
4287 :optupdate: updating working directory is needed or not
4287 :optupdate: updating working directory is needed or not
4288 :checkout: update destination revision (or None to default destination)
4288 :checkout: update destination revision (or None to default destination)
4289 :brev: a name, which might be a bookmark to be activated after updating
4289 :brev: a name, which might be a bookmark to be activated after updating
4290 """
4290 """
4291 if modheads == 0:
4291 if modheads == 0:
4292 return
4292 return
4293 if optupdate:
4293 if optupdate:
4294 try:
4294 try:
4295 return hg.updatetotally(ui, repo, checkout, brev)
4295 return hg.updatetotally(ui, repo, checkout, brev)
4296 except error.UpdateAbort as inst:
4296 except error.UpdateAbort as inst:
4297 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4297 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4298 hint = inst.hint
4298 hint = inst.hint
4299 raise error.UpdateAbort(msg, hint=hint)
4299 raise error.UpdateAbort(msg, hint=hint)
4300 if modheads > 1:
4300 if modheads > 1:
4301 currentbranchheads = len(repo.branchheads())
4301 currentbranchheads = len(repo.branchheads())
4302 if currentbranchheads == modheads:
4302 if currentbranchheads == modheads:
4303 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4303 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4304 elif currentbranchheads > 1:
4304 elif currentbranchheads > 1:
4305 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4305 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4306 "merge)\n"))
4306 "merge)\n"))
4307 else:
4307 else:
4308 ui.status(_("(run 'hg heads' to see heads)\n"))
4308 ui.status(_("(run 'hg heads' to see heads)\n"))
4309 elif not ui.configbool('commands', 'update.requiredest'):
4309 elif not ui.configbool('commands', 'update.requiredest'):
4310 ui.status(_("(run 'hg update' to get a working copy)\n"))
4310 ui.status(_("(run 'hg update' to get a working copy)\n"))
4311
4311
4312 @command('pull',
4312 @command('pull',
4313 [('u', 'update', None,
4313 [('u', 'update', None,
4314 _('update to new branch head if new descendants were pulled')),
4314 _('update to new branch head if new descendants were pulled')),
4315 ('f', 'force', None, _('run even when remote repository is unrelated')),
4315 ('f', 'force', None, _('run even when remote repository is unrelated')),
4316 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4316 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4317 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4317 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4318 ('b', 'branch', [], _('a specific branch you would like to pull'),
4318 ('b', 'branch', [], _('a specific branch you would like to pull'),
4319 _('BRANCH')),
4319 _('BRANCH')),
4320 ] + remoteopts,
4320 ] + remoteopts,
4321 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4321 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4322 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4322 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4323 helpbasic=True)
4323 helpbasic=True)
4324 def pull(ui, repo, source="default", **opts):
4324 def pull(ui, repo, source="default", **opts):
4325 """pull changes from the specified source
4325 """pull changes from the specified source
4326
4326
4327 Pull changes from a remote repository to a local one.
4327 Pull changes from a remote repository to a local one.
4328
4328
4329 This finds all changes from the repository at the specified path
4329 This finds all changes from the repository at the specified path
4330 or URL and adds them to a local repository (the current one unless
4330 or URL and adds them to a local repository (the current one unless
4331 -R is specified). By default, this does not update the copy of the
4331 -R is specified). By default, this does not update the copy of the
4332 project in the working directory.
4332 project in the working directory.
4333
4333
4334 When cloning from servers that support it, Mercurial may fetch
4334 When cloning from servers that support it, Mercurial may fetch
4335 pre-generated data. When this is done, hooks operating on incoming
4335 pre-generated data. When this is done, hooks operating on incoming
4336 changesets and changegroups may fire more than once, once for each
4336 changesets and changegroups may fire more than once, once for each
4337 pre-generated bundle and as well as for any additional remaining
4337 pre-generated bundle and as well as for any additional remaining
4338 data. See :hg:`help -e clonebundles` for more.
4338 data. See :hg:`help -e clonebundles` for more.
4339
4339
4340 Use :hg:`incoming` if you want to see what would have been added
4340 Use :hg:`incoming` if you want to see what would have been added
4341 by a pull at the time you issued this command. If you then decide
4341 by a pull at the time you issued this command. If you then decide
4342 to add those changes to the repository, you should use :hg:`pull
4342 to add those changes to the repository, you should use :hg:`pull
4343 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4343 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4344
4344
4345 If SOURCE is omitted, the 'default' path will be used.
4345 If SOURCE is omitted, the 'default' path will be used.
4346 See :hg:`help urls` for more information.
4346 See :hg:`help urls` for more information.
4347
4347
4348 Specifying bookmark as ``.`` is equivalent to specifying the active
4348 Specifying bookmark as ``.`` is equivalent to specifying the active
4349 bookmark's name.
4349 bookmark's name.
4350
4350
4351 Returns 0 on success, 1 if an update had unresolved files.
4351 Returns 0 on success, 1 if an update had unresolved files.
4352 """
4352 """
4353
4353
4354 opts = pycompat.byteskwargs(opts)
4354 opts = pycompat.byteskwargs(opts)
4355 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4355 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4356 msg = _('update destination required by configuration')
4356 msg = _('update destination required by configuration')
4357 hint = _('use hg pull followed by hg update DEST')
4357 hint = _('use hg pull followed by hg update DEST')
4358 raise error.Abort(msg, hint=hint)
4358 raise error.Abort(msg, hint=hint)
4359
4359
4360 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4360 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4361 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4361 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4362 other = hg.peer(repo, opts, source)
4362 other = hg.peer(repo, opts, source)
4363 try:
4363 try:
4364 revs, checkout = hg.addbranchrevs(repo, other, branches,
4364 revs, checkout = hg.addbranchrevs(repo, other, branches,
4365 opts.get('rev'))
4365 opts.get('rev'))
4366
4366
4367
4367
4368 pullopargs = {}
4368 pullopargs = {}
4369 if opts.get('bookmark'):
4369 if opts.get('bookmark'):
4370 if not revs:
4370 if not revs:
4371 revs = []
4371 revs = []
4372 # The list of bookmark used here is not the one used to actually
4372 # The list of bookmark used here is not the one used to actually
4373 # update the bookmark name. This can result in the revision pulled
4373 # update the bookmark name. This can result in the revision pulled
4374 # not ending up with the name of the bookmark because of a race
4374 # not ending up with the name of the bookmark because of a race
4375 # condition on the server. (See issue 4689 for details)
4375 # condition on the server. (See issue 4689 for details)
4376 remotebookmarks = other.listkeys('bookmarks')
4376 remotebookmarks = other.listkeys('bookmarks')
4377 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4377 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4378 pullopargs['remotebookmarks'] = remotebookmarks
4378 pullopargs['remotebookmarks'] = remotebookmarks
4379 for b in opts['bookmark']:
4379 for b in opts['bookmark']:
4380 b = repo._bookmarks.expandname(b)
4380 b = repo._bookmarks.expandname(b)
4381 if b not in remotebookmarks:
4381 if b not in remotebookmarks:
4382 raise error.Abort(_('remote bookmark %s not found!') % b)
4382 raise error.Abort(_('remote bookmark %s not found!') % b)
4383 revs.append(hex(remotebookmarks[b]))
4383 revs.append(hex(remotebookmarks[b]))
4384
4384
4385 if revs:
4385 if revs:
4386 try:
4386 try:
4387 # When 'rev' is a bookmark name, we cannot guarantee that it
4387 # When 'rev' is a bookmark name, we cannot guarantee that it
4388 # will be updated with that name because of a race condition
4388 # will be updated with that name because of a race condition
4389 # server side. (See issue 4689 for details)
4389 # server side. (See issue 4689 for details)
4390 oldrevs = revs
4390 oldrevs = revs
4391 revs = [] # actually, nodes
4391 revs = [] # actually, nodes
4392 for r in oldrevs:
4392 for r in oldrevs:
4393 with other.commandexecutor() as e:
4393 with other.commandexecutor() as e:
4394 node = e.callcommand('lookup', {'key': r}).result()
4394 node = e.callcommand('lookup', {'key': r}).result()
4395
4395
4396 revs.append(node)
4396 revs.append(node)
4397 if r == checkout:
4397 if r == checkout:
4398 checkout = node
4398 checkout = node
4399 except error.CapabilityError:
4399 except error.CapabilityError:
4400 err = _("other repository doesn't support revision lookup, "
4400 err = _("other repository doesn't support revision lookup, "
4401 "so a rev cannot be specified.")
4401 "so a rev cannot be specified.")
4402 raise error.Abort(err)
4402 raise error.Abort(err)
4403
4403
4404 wlock = util.nullcontextmanager()
4404 wlock = util.nullcontextmanager()
4405 if opts.get('update'):
4405 if opts.get('update'):
4406 wlock = repo.wlock()
4406 wlock = repo.wlock()
4407 with wlock:
4407 with wlock:
4408 pullopargs.update(opts.get('opargs', {}))
4408 pullopargs.update(opts.get('opargs', {}))
4409 modheads = exchange.pull(repo, other, heads=revs,
4409 modheads = exchange.pull(repo, other, heads=revs,
4410 force=opts.get('force'),
4410 force=opts.get('force'),
4411 bookmarks=opts.get('bookmark', ()),
4411 bookmarks=opts.get('bookmark', ()),
4412 opargs=pullopargs).cgresult
4412 opargs=pullopargs).cgresult
4413
4413
4414 # brev is a name, which might be a bookmark to be activated at
4414 # brev is a name, which might be a bookmark to be activated at
4415 # the end of the update. In other words, it is an explicit
4415 # the end of the update. In other words, it is an explicit
4416 # destination of the update
4416 # destination of the update
4417 brev = None
4417 brev = None
4418
4418
4419 if checkout:
4419 if checkout:
4420 checkout = repo.changelog.rev(checkout)
4420 checkout = repo.changelog.rev(checkout)
4421
4421
4422 # order below depends on implementation of
4422 # order below depends on implementation of
4423 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4423 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4424 # because 'checkout' is determined without it.
4424 # because 'checkout' is determined without it.
4425 if opts.get('rev'):
4425 if opts.get('rev'):
4426 brev = opts['rev'][0]
4426 brev = opts['rev'][0]
4427 elif opts.get('branch'):
4427 elif opts.get('branch'):
4428 brev = opts['branch'][0]
4428 brev = opts['branch'][0]
4429 else:
4429 else:
4430 brev = branches[0]
4430 brev = branches[0]
4431 repo._subtoppath = source
4431 repo._subtoppath = source
4432 try:
4432 try:
4433 ret = postincoming(ui, repo, modheads, opts.get('update'),
4433 ret = postincoming(ui, repo, modheads, opts.get('update'),
4434 checkout, brev)
4434 checkout, brev)
4435
4435
4436 finally:
4436 finally:
4437 del repo._subtoppath
4437 del repo._subtoppath
4438
4438
4439 finally:
4439 finally:
4440 other.close()
4440 other.close()
4441 return ret
4441 return ret
4442
4442
4443 @command('push',
4443 @command('push',
4444 [('f', 'force', None, _('force push')),
4444 [('f', 'force', None, _('force push')),
4445 ('r', 'rev', [],
4445 ('r', 'rev', [],
4446 _('a changeset intended to be included in the destination'),
4446 _('a changeset intended to be included in the destination'),
4447 _('REV')),
4447 _('REV')),
4448 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4448 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4449 ('b', 'branch', [],
4449 ('b', 'branch', [],
4450 _('a specific branch you would like to push'), _('BRANCH')),
4450 _('a specific branch you would like to push'), _('BRANCH')),
4451 ('', 'new-branch', False, _('allow pushing a new branch')),
4451 ('', 'new-branch', False, _('allow pushing a new branch')),
4452 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4452 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4453 ] + remoteopts,
4453 ] + remoteopts,
4454 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4454 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4455 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4455 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4456 helpbasic=True)
4456 helpbasic=True)
4457 def push(ui, repo, dest=None, **opts):
4457 def push(ui, repo, dest=None, **opts):
4458 """push changes to the specified destination
4458 """push changes to the specified destination
4459
4459
4460 Push changesets from the local repository to the specified
4460 Push changesets from the local repository to the specified
4461 destination.
4461 destination.
4462
4462
4463 This operation is symmetrical to pull: it is identical to a pull
4463 This operation is symmetrical to pull: it is identical to a pull
4464 in the destination repository from the current one.
4464 in the destination repository from the current one.
4465
4465
4466 By default, push will not allow creation of new heads at the
4466 By default, push will not allow creation of new heads at the
4467 destination, since multiple heads would make it unclear which head
4467 destination, since multiple heads would make it unclear which head
4468 to use. In this situation, it is recommended to pull and merge
4468 to use. In this situation, it is recommended to pull and merge
4469 before pushing.
4469 before pushing.
4470
4470
4471 Use --new-branch if you want to allow push to create a new named
4471 Use --new-branch if you want to allow push to create a new named
4472 branch that is not present at the destination. This allows you to
4472 branch that is not present at the destination. This allows you to
4473 only create a new branch without forcing other changes.
4473 only create a new branch without forcing other changes.
4474
4474
4475 .. note::
4475 .. note::
4476
4476
4477 Extra care should be taken with the -f/--force option,
4477 Extra care should be taken with the -f/--force option,
4478 which will push all new heads on all branches, an action which will
4478 which will push all new heads on all branches, an action which will
4479 almost always cause confusion for collaborators.
4479 almost always cause confusion for collaborators.
4480
4480
4481 If -r/--rev is used, the specified revision and all its ancestors
4481 If -r/--rev is used, the specified revision and all its ancestors
4482 will be pushed to the remote repository.
4482 will be pushed to the remote repository.
4483
4483
4484 If -B/--bookmark is used, the specified bookmarked revision, its
4484 If -B/--bookmark is used, the specified bookmarked revision, its
4485 ancestors, and the bookmark will be pushed to the remote
4485 ancestors, and the bookmark will be pushed to the remote
4486 repository. Specifying ``.`` is equivalent to specifying the active
4486 repository. Specifying ``.`` is equivalent to specifying the active
4487 bookmark's name.
4487 bookmark's name.
4488
4488
4489 Please see :hg:`help urls` for important details about ``ssh://``
4489 Please see :hg:`help urls` for important details about ``ssh://``
4490 URLs. If DESTINATION is omitted, a default path will be used.
4490 URLs. If DESTINATION is omitted, a default path will be used.
4491
4491
4492 .. container:: verbose
4492 .. container:: verbose
4493
4493
4494 The --pushvars option sends strings to the server that become
4494 The --pushvars option sends strings to the server that become
4495 environment variables prepended with ``HG_USERVAR_``. For example,
4495 environment variables prepended with ``HG_USERVAR_``. For example,
4496 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4496 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4497 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4497 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4498
4498
4499 pushvars can provide for user-overridable hooks as well as set debug
4499 pushvars can provide for user-overridable hooks as well as set debug
4500 levels. One example is having a hook that blocks commits containing
4500 levels. One example is having a hook that blocks commits containing
4501 conflict markers, but enables the user to override the hook if the file
4501 conflict markers, but enables the user to override the hook if the file
4502 is using conflict markers for testing purposes or the file format has
4502 is using conflict markers for testing purposes or the file format has
4503 strings that look like conflict markers.
4503 strings that look like conflict markers.
4504
4504
4505 By default, servers will ignore `--pushvars`. To enable it add the
4505 By default, servers will ignore `--pushvars`. To enable it add the
4506 following to your configuration file::
4506 following to your configuration file::
4507
4507
4508 [push]
4508 [push]
4509 pushvars.server = true
4509 pushvars.server = true
4510
4510
4511 Returns 0 if push was successful, 1 if nothing to push.
4511 Returns 0 if push was successful, 1 if nothing to push.
4512 """
4512 """
4513
4513
4514 opts = pycompat.byteskwargs(opts)
4514 opts = pycompat.byteskwargs(opts)
4515 if opts.get('bookmark'):
4515 if opts.get('bookmark'):
4516 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4516 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4517 for b in opts['bookmark']:
4517 for b in opts['bookmark']:
4518 # translate -B options to -r so changesets get pushed
4518 # translate -B options to -r so changesets get pushed
4519 b = repo._bookmarks.expandname(b)
4519 b = repo._bookmarks.expandname(b)
4520 if b in repo._bookmarks:
4520 if b in repo._bookmarks:
4521 opts.setdefault('rev', []).append(b)
4521 opts.setdefault('rev', []).append(b)
4522 else:
4522 else:
4523 # if we try to push a deleted bookmark, translate it to null
4523 # if we try to push a deleted bookmark, translate it to null
4524 # this lets simultaneous -r, -b options continue working
4524 # this lets simultaneous -r, -b options continue working
4525 opts.setdefault('rev', []).append("null")
4525 opts.setdefault('rev', []).append("null")
4526
4526
4527 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4527 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4528 if not path:
4528 if not path:
4529 raise error.Abort(_('default repository not configured!'),
4529 raise error.Abort(_('default repository not configured!'),
4530 hint=_("see 'hg help config.paths'"))
4530 hint=_("see 'hg help config.paths'"))
4531 dest = path.pushloc or path.loc
4531 dest = path.pushloc or path.loc
4532 branches = (path.branch, opts.get('branch') or [])
4532 branches = (path.branch, opts.get('branch') or [])
4533 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4533 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4534 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4534 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4535 other = hg.peer(repo, opts, dest)
4535 other = hg.peer(repo, opts, dest)
4536
4536
4537 if revs:
4537 if revs:
4538 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4538 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4539 if not revs:
4539 if not revs:
4540 raise error.Abort(_("specified revisions evaluate to an empty set"),
4540 raise error.Abort(_("specified revisions evaluate to an empty set"),
4541 hint=_("use different revision arguments"))
4541 hint=_("use different revision arguments"))
4542 elif path.pushrev:
4542 elif path.pushrev:
4543 # It doesn't make any sense to specify ancestor revisions. So limit
4543 # It doesn't make any sense to specify ancestor revisions. So limit
4544 # to DAG heads to make discovery simpler.
4544 # to DAG heads to make discovery simpler.
4545 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4545 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4546 revs = scmutil.revrange(repo, [expr])
4546 revs = scmutil.revrange(repo, [expr])
4547 revs = [repo[rev].node() for rev in revs]
4547 revs = [repo[rev].node() for rev in revs]
4548 if not revs:
4548 if not revs:
4549 raise error.Abort(_('default push revset for path evaluates to an '
4549 raise error.Abort(_('default push revset for path evaluates to an '
4550 'empty set'))
4550 'empty set'))
4551
4551
4552 repo._subtoppath = dest
4552 repo._subtoppath = dest
4553 try:
4553 try:
4554 # push subrepos depth-first for coherent ordering
4554 # push subrepos depth-first for coherent ordering
4555 c = repo['.']
4555 c = repo['.']
4556 subs = c.substate # only repos that are committed
4556 subs = c.substate # only repos that are committed
4557 for s in sorted(subs):
4557 for s in sorted(subs):
4558 result = c.sub(s).push(opts)
4558 result = c.sub(s).push(opts)
4559 if result == 0:
4559 if result == 0:
4560 return not result
4560 return not result
4561 finally:
4561 finally:
4562 del repo._subtoppath
4562 del repo._subtoppath
4563
4563
4564 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4564 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4565 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4565 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4566
4566
4567 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4567 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4568 newbranch=opts.get('new_branch'),
4568 newbranch=opts.get('new_branch'),
4569 bookmarks=opts.get('bookmark', ()),
4569 bookmarks=opts.get('bookmark', ()),
4570 opargs=opargs)
4570 opargs=opargs)
4571
4571
4572 result = not pushop.cgresult
4572 result = not pushop.cgresult
4573
4573
4574 if pushop.bkresult is not None:
4574 if pushop.bkresult is not None:
4575 if pushop.bkresult == 2:
4575 if pushop.bkresult == 2:
4576 result = 2
4576 result = 2
4577 elif not result and pushop.bkresult:
4577 elif not result and pushop.bkresult:
4578 result = 2
4578 result = 2
4579
4579
4580 return result
4580 return result
4581
4581
4582 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4582 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4583 def recover(ui, repo):
4583 def recover(ui, repo):
4584 """roll back an interrupted transaction
4584 """roll back an interrupted transaction
4585
4585
4586 Recover from an interrupted commit or pull.
4586 Recover from an interrupted commit or pull.
4587
4587
4588 This command tries to fix the repository status after an
4588 This command tries to fix the repository status after an
4589 interrupted operation. It should only be necessary when Mercurial
4589 interrupted operation. It should only be necessary when Mercurial
4590 suggests it.
4590 suggests it.
4591
4591
4592 Returns 0 if successful, 1 if nothing to recover or verify fails.
4592 Returns 0 if successful, 1 if nothing to recover or verify fails.
4593 """
4593 """
4594 if repo.recover():
4594 if repo.recover():
4595 return hg.verify(repo)
4595 return hg.verify(repo)
4596 return 1
4596 return 1
4597
4597
4598 @command('remove|rm',
4598 @command('remove|rm',
4599 [('A', 'after', None, _('record delete for missing files')),
4599 [('A', 'after', None, _('record delete for missing files')),
4600 ('f', 'force', None,
4600 ('f', 'force', None,
4601 _('forget added files, delete modified files')),
4601 _('forget added files, delete modified files')),
4602 ] + subrepoopts + walkopts + dryrunopts,
4602 ] + subrepoopts + walkopts + dryrunopts,
4603 _('[OPTION]... FILE...'),
4603 _('[OPTION]... FILE...'),
4604 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4604 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4605 helpbasic=True, inferrepo=True)
4605 helpbasic=True, inferrepo=True)
4606 def remove(ui, repo, *pats, **opts):
4606 def remove(ui, repo, *pats, **opts):
4607 """remove the specified files on the next commit
4607 """remove the specified files on the next commit
4608
4608
4609 Schedule the indicated files for removal from the current branch.
4609 Schedule the indicated files for removal from the current branch.
4610
4610
4611 This command schedules the files to be removed at the next commit.
4611 This command schedules the files to be removed at the next commit.
4612 To undo a remove before that, see :hg:`revert`. To undo added
4612 To undo a remove before that, see :hg:`revert`. To undo added
4613 files, see :hg:`forget`.
4613 files, see :hg:`forget`.
4614
4614
4615 .. container:: verbose
4615 .. container:: verbose
4616
4616
4617 -A/--after can be used to remove only files that have already
4617 -A/--after can be used to remove only files that have already
4618 been deleted, -f/--force can be used to force deletion, and -Af
4618 been deleted, -f/--force can be used to force deletion, and -Af
4619 can be used to remove files from the next revision without
4619 can be used to remove files from the next revision without
4620 deleting them from the working directory.
4620 deleting them from the working directory.
4621
4621
4622 The following table details the behavior of remove for different
4622 The following table details the behavior of remove for different
4623 file states (columns) and option combinations (rows). The file
4623 file states (columns) and option combinations (rows). The file
4624 states are Added [A], Clean [C], Modified [M] and Missing [!]
4624 states are Added [A], Clean [C], Modified [M] and Missing [!]
4625 (as reported by :hg:`status`). The actions are Warn, Remove
4625 (as reported by :hg:`status`). The actions are Warn, Remove
4626 (from branch) and Delete (from disk):
4626 (from branch) and Delete (from disk):
4627
4627
4628 ========= == == == ==
4628 ========= == == == ==
4629 opt/state A C M !
4629 opt/state A C M !
4630 ========= == == == ==
4630 ========= == == == ==
4631 none W RD W R
4631 none W RD W R
4632 -f R RD RD R
4632 -f R RD RD R
4633 -A W W W R
4633 -A W W W R
4634 -Af R R R R
4634 -Af R R R R
4635 ========= == == == ==
4635 ========= == == == ==
4636
4636
4637 .. note::
4637 .. note::
4638
4638
4639 :hg:`remove` never deletes files in Added [A] state from the
4639 :hg:`remove` never deletes files in Added [A] state from the
4640 working directory, not even if ``--force`` is specified.
4640 working directory, not even if ``--force`` is specified.
4641
4641
4642 Returns 0 on success, 1 if any warnings encountered.
4642 Returns 0 on success, 1 if any warnings encountered.
4643 """
4643 """
4644
4644
4645 opts = pycompat.byteskwargs(opts)
4645 opts = pycompat.byteskwargs(opts)
4646 after, force = opts.get('after'), opts.get('force')
4646 after, force = opts.get('after'), opts.get('force')
4647 dryrun = opts.get('dry_run')
4647 dryrun = opts.get('dry_run')
4648 if not pats and not after:
4648 if not pats and not after:
4649 raise error.Abort(_('no files specified'))
4649 raise error.Abort(_('no files specified'))
4650
4650
4651 m = scmutil.match(repo[None], pats, opts)
4651 m = scmutil.match(repo[None], pats, opts)
4652 subrepos = opts.get('subrepos')
4652 subrepos = opts.get('subrepos')
4653 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4653 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4654 dryrun=dryrun)
4654 dryrun=dryrun)
4655
4655
4656 @command('rename|move|mv',
4656 @command('rename|move|mv',
4657 [('A', 'after', None, _('record a rename that has already occurred')),
4657 [('A', 'after', None, _('record a rename that has already occurred')),
4658 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4658 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4659 ] + walkopts + dryrunopts,
4659 ] + walkopts + dryrunopts,
4660 _('[OPTION]... SOURCE... DEST'),
4660 _('[OPTION]... SOURCE... DEST'),
4661 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4661 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4662 def rename(ui, repo, *pats, **opts):
4662 def rename(ui, repo, *pats, **opts):
4663 """rename files; equivalent of copy + remove
4663 """rename files; equivalent of copy + remove
4664
4664
4665 Mark dest as copies of sources; mark sources for deletion. If dest
4665 Mark dest as copies of sources; mark sources for deletion. If dest
4666 is a directory, copies are put in that directory. If dest is a
4666 is a directory, copies are put in that directory. If dest is a
4667 file, there can only be one source.
4667 file, there can only be one source.
4668
4668
4669 By default, this command copies the contents of files as they
4669 By default, this command copies the contents of files as they
4670 exist in the working directory. If invoked with -A/--after, the
4670 exist in the working directory. If invoked with -A/--after, the
4671 operation is recorded, but no copying is performed.
4671 operation is recorded, but no copying is performed.
4672
4672
4673 This command takes effect at the next commit. To undo a rename
4673 This command takes effect at the next commit. To undo a rename
4674 before that, see :hg:`revert`.
4674 before that, see :hg:`revert`.
4675
4675
4676 Returns 0 on success, 1 if errors are encountered.
4676 Returns 0 on success, 1 if errors are encountered.
4677 """
4677 """
4678 opts = pycompat.byteskwargs(opts)
4678 opts = pycompat.byteskwargs(opts)
4679 with repo.wlock(False):
4679 with repo.wlock(False):
4680 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4680 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4681
4681
4682 @command('resolve',
4682 @command('resolve',
4683 [('a', 'all', None, _('select all unresolved files')),
4683 [('a', 'all', None, _('select all unresolved files')),
4684 ('l', 'list', None, _('list state of files needing merge')),
4684 ('l', 'list', None, _('list state of files needing merge')),
4685 ('m', 'mark', None, _('mark files as resolved')),
4685 ('m', 'mark', None, _('mark files as resolved')),
4686 ('u', 'unmark', None, _('mark files as unresolved')),
4686 ('u', 'unmark', None, _('mark files as unresolved')),
4687 ('n', 'no-status', None, _('hide status prefix')),
4687 ('n', 'no-status', None, _('hide status prefix')),
4688 ('', 're-merge', None, _('re-merge files'))]
4688 ('', 're-merge', None, _('re-merge files'))]
4689 + mergetoolopts + walkopts + formatteropts,
4689 + mergetoolopts + walkopts + formatteropts,
4690 _('[OPTION]... [FILE]...'),
4690 _('[OPTION]... [FILE]...'),
4691 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4691 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4692 inferrepo=True)
4692 inferrepo=True)
4693 def resolve(ui, repo, *pats, **opts):
4693 def resolve(ui, repo, *pats, **opts):
4694 """redo merges or set/view the merge status of files
4694 """redo merges or set/view the merge status of files
4695
4695
4696 Merges with unresolved conflicts are often the result of
4696 Merges with unresolved conflicts are often the result of
4697 non-interactive merging using the ``internal:merge`` configuration
4697 non-interactive merging using the ``internal:merge`` configuration
4698 setting, or a command-line merge tool like ``diff3``. The resolve
4698 setting, or a command-line merge tool like ``diff3``. The resolve
4699 command is used to manage the files involved in a merge, after
4699 command is used to manage the files involved in a merge, after
4700 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4700 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4701 working directory must have two parents). See :hg:`help
4701 working directory must have two parents). See :hg:`help
4702 merge-tools` for information on configuring merge tools.
4702 merge-tools` for information on configuring merge tools.
4703
4703
4704 The resolve command can be used in the following ways:
4704 The resolve command can be used in the following ways:
4705
4705
4706 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4706 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4707 the specified files, discarding any previous merge attempts. Re-merging
4707 the specified files, discarding any previous merge attempts. Re-merging
4708 is not performed for files already marked as resolved. Use ``--all/-a``
4708 is not performed for files already marked as resolved. Use ``--all/-a``
4709 to select all unresolved files. ``--tool`` can be used to specify
4709 to select all unresolved files. ``--tool`` can be used to specify
4710 the merge tool used for the given files. It overrides the HGMERGE
4710 the merge tool used for the given files. It overrides the HGMERGE
4711 environment variable and your configuration files. Previous file
4711 environment variable and your configuration files. Previous file
4712 contents are saved with a ``.orig`` suffix.
4712 contents are saved with a ``.orig`` suffix.
4713
4713
4714 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4714 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4715 (e.g. after having manually fixed-up the files). The default is
4715 (e.g. after having manually fixed-up the files). The default is
4716 to mark all unresolved files.
4716 to mark all unresolved files.
4717
4717
4718 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4718 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4719 default is to mark all resolved files.
4719 default is to mark all resolved files.
4720
4720
4721 - :hg:`resolve -l`: list files which had or still have conflicts.
4721 - :hg:`resolve -l`: list files which had or still have conflicts.
4722 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4722 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4723 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4723 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4724 the list. See :hg:`help filesets` for details.
4724 the list. See :hg:`help filesets` for details.
4725
4725
4726 .. note::
4726 .. note::
4727
4727
4728 Mercurial will not let you commit files with unresolved merge
4728 Mercurial will not let you commit files with unresolved merge
4729 conflicts. You must use :hg:`resolve -m ...` before you can
4729 conflicts. You must use :hg:`resolve -m ...` before you can
4730 commit after a conflicting merge.
4730 commit after a conflicting merge.
4731
4731
4732 .. container:: verbose
4732 .. container:: verbose
4733
4733
4734 Template:
4734 Template:
4735
4735
4736 The following keywords are supported in addition to the common template
4736 The following keywords are supported in addition to the common template
4737 keywords and functions. See also :hg:`help templates`.
4737 keywords and functions. See also :hg:`help templates`.
4738
4738
4739 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4739 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4740 :path: String. Repository-absolute path of the file.
4740 :path: String. Repository-absolute path of the file.
4741
4741
4742 Returns 0 on success, 1 if any files fail a resolve attempt.
4742 Returns 0 on success, 1 if any files fail a resolve attempt.
4743 """
4743 """
4744
4744
4745 opts = pycompat.byteskwargs(opts)
4745 opts = pycompat.byteskwargs(opts)
4746 confirm = ui.configbool('commands', 'resolve.confirm')
4746 confirm = ui.configbool('commands', 'resolve.confirm')
4747 flaglist = 'all mark unmark list no_status re_merge'.split()
4747 flaglist = 'all mark unmark list no_status re_merge'.split()
4748 all, mark, unmark, show, nostatus, remerge = \
4748 all, mark, unmark, show, nostatus, remerge = \
4749 [opts.get(o) for o in flaglist]
4749 [opts.get(o) for o in flaglist]
4750
4750
4751 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4751 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4752 if actioncount > 1:
4752 if actioncount > 1:
4753 raise error.Abort(_("too many actions specified"))
4753 raise error.Abort(_("too many actions specified"))
4754 elif (actioncount == 0
4754 elif (actioncount == 0
4755 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4755 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4756 hint = _('use --mark, --unmark, --list or --re-merge')
4756 hint = _('use --mark, --unmark, --list or --re-merge')
4757 raise error.Abort(_('no action specified'), hint=hint)
4757 raise error.Abort(_('no action specified'), hint=hint)
4758 if pats and all:
4758 if pats and all:
4759 raise error.Abort(_("can't specify --all and patterns"))
4759 raise error.Abort(_("can't specify --all and patterns"))
4760 if not (all or pats or show or mark or unmark):
4760 if not (all or pats or show or mark or unmark):
4761 raise error.Abort(_('no files or directories specified'),
4761 raise error.Abort(_('no files or directories specified'),
4762 hint=('use --all to re-merge all unresolved files'))
4762 hint=('use --all to re-merge all unresolved files'))
4763
4763
4764 if confirm:
4764 if confirm:
4765 if all:
4765 if all:
4766 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4766 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4767 b'$$ &Yes $$ &No')):
4767 b'$$ &Yes $$ &No')):
4768 raise error.Abort(_('user quit'))
4768 raise error.Abort(_('user quit'))
4769 if mark and not pats:
4769 if mark and not pats:
4770 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4770 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4771 b'$$ &Yes $$ &No')):
4771 b'$$ &Yes $$ &No')):
4772 raise error.Abort(_('user quit'))
4772 raise error.Abort(_('user quit'))
4773 if unmark and not pats:
4773 if unmark and not pats:
4774 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4774 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4775 b'$$ &Yes $$ &No')):
4775 b'$$ &Yes $$ &No')):
4776 raise error.Abort(_('user quit'))
4776 raise error.Abort(_('user quit'))
4777
4777
4778 if show:
4778 if show:
4779 ui.pager('resolve')
4779 ui.pager('resolve')
4780 fm = ui.formatter('resolve', opts)
4780 fm = ui.formatter('resolve', opts)
4781 ms = mergemod.mergestate.read(repo)
4781 ms = mergemod.mergestate.read(repo)
4782 wctx = repo[None]
4782 wctx = repo[None]
4783 m = scmutil.match(wctx, pats, opts)
4783 m = scmutil.match(wctx, pats, opts)
4784
4784
4785 # Labels and keys based on merge state. Unresolved path conflicts show
4785 # Labels and keys based on merge state. Unresolved path conflicts show
4786 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4786 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4787 # resolved conflicts.
4787 # resolved conflicts.
4788 mergestateinfo = {
4788 mergestateinfo = {
4789 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4789 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4790 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4790 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4791 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4791 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4792 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4792 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4793 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4793 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4794 'D'),
4794 'D'),
4795 }
4795 }
4796
4796
4797 for f in ms:
4797 for f in ms:
4798 if not m(f):
4798 if not m(f):
4799 continue
4799 continue
4800
4800
4801 label, key = mergestateinfo[ms[f]]
4801 label, key = mergestateinfo[ms[f]]
4802 fm.startitem()
4802 fm.startitem()
4803 fm.context(ctx=wctx)
4803 fm.context(ctx=wctx)
4804 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4804 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4805 fm.write('path', '%s\n', f, label=label)
4805 fm.write('path', '%s\n', f, label=label)
4806 fm.end()
4806 fm.end()
4807 return 0
4807 return 0
4808
4808
4809 with repo.wlock():
4809 with repo.wlock():
4810 ms = mergemod.mergestate.read(repo)
4810 ms = mergemod.mergestate.read(repo)
4811
4811
4812 if not (ms.active() or repo.dirstate.p2() != nullid):
4812 if not (ms.active() or repo.dirstate.p2() != nullid):
4813 raise error.Abort(
4813 raise error.Abort(
4814 _('resolve command not applicable when not merging'))
4814 _('resolve command not applicable when not merging'))
4815
4815
4816 wctx = repo[None]
4816 wctx = repo[None]
4817
4817
4818 if (ms.mergedriver
4818 if (ms.mergedriver
4819 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4819 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4820 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4820 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4821 ms.commit()
4821 ms.commit()
4822 # allow mark and unmark to go through
4822 # allow mark and unmark to go through
4823 if not mark and not unmark and not proceed:
4823 if not mark and not unmark and not proceed:
4824 return 1
4824 return 1
4825
4825
4826 m = scmutil.match(wctx, pats, opts)
4826 m = scmutil.match(wctx, pats, opts)
4827 ret = 0
4827 ret = 0
4828 didwork = False
4828 didwork = False
4829 runconclude = False
4829 runconclude = False
4830
4830
4831 tocomplete = []
4831 tocomplete = []
4832 hasconflictmarkers = []
4832 hasconflictmarkers = []
4833 if mark:
4833 if mark:
4834 markcheck = ui.config('commands', 'resolve.mark-check')
4834 markcheck = ui.config('commands', 'resolve.mark-check')
4835 if markcheck not in ['warn', 'abort']:
4835 if markcheck not in ['warn', 'abort']:
4836 # Treat all invalid / unrecognized values as 'none'.
4836 # Treat all invalid / unrecognized values as 'none'.
4837 markcheck = False
4837 markcheck = False
4838 for f in ms:
4838 for f in ms:
4839 if not m(f):
4839 if not m(f):
4840 continue
4840 continue
4841
4841
4842 didwork = True
4842 didwork = True
4843
4843
4844 # don't let driver-resolved files be marked, and run the conclude
4844 # don't let driver-resolved files be marked, and run the conclude
4845 # step if asked to resolve
4845 # step if asked to resolve
4846 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4846 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4847 exact = m.exact(f)
4847 exact = m.exact(f)
4848 if mark:
4848 if mark:
4849 if exact:
4849 if exact:
4850 ui.warn(_('not marking %s as it is driver-resolved\n')
4850 ui.warn(_('not marking %s as it is driver-resolved\n')
4851 % f)
4851 % f)
4852 elif unmark:
4852 elif unmark:
4853 if exact:
4853 if exact:
4854 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4854 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4855 % f)
4855 % f)
4856 else:
4856 else:
4857 runconclude = True
4857 runconclude = True
4858 continue
4858 continue
4859
4859
4860 # path conflicts must be resolved manually
4860 # path conflicts must be resolved manually
4861 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4861 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4862 mergemod.MERGE_RECORD_RESOLVED_PATH):
4862 mergemod.MERGE_RECORD_RESOLVED_PATH):
4863 if mark:
4863 if mark:
4864 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4864 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4865 elif unmark:
4865 elif unmark:
4866 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4866 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4867 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4867 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4868 ui.warn(_('%s: path conflict must be resolved manually\n')
4868 ui.warn(_('%s: path conflict must be resolved manually\n')
4869 % f)
4869 % f)
4870 continue
4870 continue
4871
4871
4872 if mark:
4872 if mark:
4873 if markcheck:
4873 if markcheck:
4874 with repo.wvfs(f) as fobj:
4874 with repo.wvfs(f) as fobj:
4875 fdata = fobj.read()
4875 fdata = fobj.read()
4876 if filemerge.hasconflictmarkers(fdata) and \
4876 if filemerge.hasconflictmarkers(fdata) and \
4877 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4877 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4878 hasconflictmarkers.append(f)
4878 hasconflictmarkers.append(f)
4879 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4879 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4880 elif unmark:
4880 elif unmark:
4881 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4881 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4882 else:
4882 else:
4883 # backup pre-resolve (merge uses .orig for its own purposes)
4883 # backup pre-resolve (merge uses .orig for its own purposes)
4884 a = repo.wjoin(f)
4884 a = repo.wjoin(f)
4885 try:
4885 try:
4886 util.copyfile(a, a + ".resolve")
4886 util.copyfile(a, a + ".resolve")
4887 except (IOError, OSError) as inst:
4887 except (IOError, OSError) as inst:
4888 if inst.errno != errno.ENOENT:
4888 if inst.errno != errno.ENOENT:
4889 raise
4889 raise
4890
4890
4891 try:
4891 try:
4892 # preresolve file
4892 # preresolve file
4893 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4893 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4894 with ui.configoverride(overrides, 'resolve'):
4894 with ui.configoverride(overrides, 'resolve'):
4895 complete, r = ms.preresolve(f, wctx)
4895 complete, r = ms.preresolve(f, wctx)
4896 if not complete:
4896 if not complete:
4897 tocomplete.append(f)
4897 tocomplete.append(f)
4898 elif r:
4898 elif r:
4899 ret = 1
4899 ret = 1
4900 finally:
4900 finally:
4901 ms.commit()
4901 ms.commit()
4902
4902
4903 # replace filemerge's .orig file with our resolve file, but only
4903 # replace filemerge's .orig file with our resolve file, but only
4904 # for merges that are complete
4904 # for merges that are complete
4905 if complete:
4905 if complete:
4906 try:
4906 try:
4907 util.rename(a + ".resolve",
4907 util.rename(a + ".resolve",
4908 scmutil.origpath(ui, repo, a))
4908 scmutil.origpath(ui, repo, a))
4909 except OSError as inst:
4909 except OSError as inst:
4910 if inst.errno != errno.ENOENT:
4910 if inst.errno != errno.ENOENT:
4911 raise
4911 raise
4912
4912
4913 if hasconflictmarkers:
4913 if hasconflictmarkers:
4914 ui.warn(_('warning: the following files still have conflict '
4914 ui.warn(_('warning: the following files still have conflict '
4915 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4915 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4916 if markcheck == 'abort' and not all and not pats:
4916 if markcheck == 'abort' and not all and not pats:
4917 raise error.Abort(_('conflict markers detected'),
4917 raise error.Abort(_('conflict markers detected'),
4918 hint=_('use --all to mark anyway'))
4918 hint=_('use --all to mark anyway'))
4919
4919
4920 for f in tocomplete:
4920 for f in tocomplete:
4921 try:
4921 try:
4922 # resolve file
4922 # resolve file
4923 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4923 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4924 with ui.configoverride(overrides, 'resolve'):
4924 with ui.configoverride(overrides, 'resolve'):
4925 r = ms.resolve(f, wctx)
4925 r = ms.resolve(f, wctx)
4926 if r:
4926 if r:
4927 ret = 1
4927 ret = 1
4928 finally:
4928 finally:
4929 ms.commit()
4929 ms.commit()
4930
4930
4931 # replace filemerge's .orig file with our resolve file
4931 # replace filemerge's .orig file with our resolve file
4932 a = repo.wjoin(f)
4932 a = repo.wjoin(f)
4933 try:
4933 try:
4934 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4934 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4935 except OSError as inst:
4935 except OSError as inst:
4936 if inst.errno != errno.ENOENT:
4936 if inst.errno != errno.ENOENT:
4937 raise
4937 raise
4938
4938
4939 ms.commit()
4939 ms.commit()
4940 ms.recordactions()
4940 ms.recordactions()
4941
4941
4942 if not didwork and pats:
4942 if not didwork and pats:
4943 hint = None
4943 hint = None
4944 if not any([p for p in pats if p.find(':') >= 0]):
4944 if not any([p for p in pats if p.find(':') >= 0]):
4945 pats = ['path:%s' % p for p in pats]
4945 pats = ['path:%s' % p for p in pats]
4946 m = scmutil.match(wctx, pats, opts)
4946 m = scmutil.match(wctx, pats, opts)
4947 for f in ms:
4947 for f in ms:
4948 if not m(f):
4948 if not m(f):
4949 continue
4949 continue
4950 def flag(o):
4950 def flag(o):
4951 if o == 're_merge':
4951 if o == 're_merge':
4952 return '--re-merge '
4952 return '--re-merge '
4953 return '-%s ' % o[0:1]
4953 return '-%s ' % o[0:1]
4954 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4954 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4955 hint = _("(try: hg resolve %s%s)\n") % (
4955 hint = _("(try: hg resolve %s%s)\n") % (
4956 flags,
4956 flags,
4957 ' '.join(pats))
4957 ' '.join(pats))
4958 break
4958 break
4959 ui.warn(_("arguments do not match paths that need resolving\n"))
4959 ui.warn(_("arguments do not match paths that need resolving\n"))
4960 if hint:
4960 if hint:
4961 ui.warn(hint)
4961 ui.warn(hint)
4962 elif ms.mergedriver and ms.mdstate() != 's':
4962 elif ms.mergedriver and ms.mdstate() != 's':
4963 # run conclude step when either a driver-resolved file is requested
4963 # run conclude step when either a driver-resolved file is requested
4964 # or there are no driver-resolved files
4964 # or there are no driver-resolved files
4965 # we can't use 'ret' to determine whether any files are unresolved
4965 # we can't use 'ret' to determine whether any files are unresolved
4966 # because we might not have tried to resolve some
4966 # because we might not have tried to resolve some
4967 if ((runconclude or not list(ms.driverresolved()))
4967 if ((runconclude or not list(ms.driverresolved()))
4968 and not list(ms.unresolved())):
4968 and not list(ms.unresolved())):
4969 proceed = mergemod.driverconclude(repo, ms, wctx)
4969 proceed = mergemod.driverconclude(repo, ms, wctx)
4970 ms.commit()
4970 ms.commit()
4971 if not proceed:
4971 if not proceed:
4972 return 1
4972 return 1
4973
4973
4974 # Nudge users into finishing an unfinished operation
4974 # Nudge users into finishing an unfinished operation
4975 unresolvedf = list(ms.unresolved())
4975 unresolvedf = list(ms.unresolved())
4976 driverresolvedf = list(ms.driverresolved())
4976 driverresolvedf = list(ms.driverresolved())
4977 if not unresolvedf and not driverresolvedf:
4977 if not unresolvedf and not driverresolvedf:
4978 ui.status(_('(no more unresolved files)\n'))
4978 ui.status(_('(no more unresolved files)\n'))
4979 cmdutil.checkafterresolved(repo)
4979 cmdutil.checkafterresolved(repo)
4980 elif not unresolvedf:
4980 elif not unresolvedf:
4981 ui.status(_('(no more unresolved files -- '
4981 ui.status(_('(no more unresolved files -- '
4982 'run "hg resolve --all" to conclude)\n'))
4982 'run "hg resolve --all" to conclude)\n'))
4983
4983
4984 return ret
4984 return ret
4985
4985
4986 @command('revert',
4986 @command('revert',
4987 [('a', 'all', None, _('revert all changes when no arguments given')),
4987 [('a', 'all', None, _('revert all changes when no arguments given')),
4988 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4988 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4989 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4989 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4990 ('C', 'no-backup', None, _('do not save backup copies of files')),
4990 ('C', 'no-backup', None, _('do not save backup copies of files')),
4991 ('i', 'interactive', None, _('interactively select the changes')),
4991 ('i', 'interactive', None, _('interactively select the changes')),
4992 ] + walkopts + dryrunopts,
4992 ] + walkopts + dryrunopts,
4993 _('[OPTION]... [-r REV] [NAME]...'),
4993 _('[OPTION]... [-r REV] [NAME]...'),
4994 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4994 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4995 def revert(ui, repo, *pats, **opts):
4995 def revert(ui, repo, *pats, **opts):
4996 """restore files to their checkout state
4996 """restore files to their checkout state
4997
4997
4998 .. note::
4998 .. note::
4999
4999
5000 To check out earlier revisions, you should use :hg:`update REV`.
5000 To check out earlier revisions, you should use :hg:`update REV`.
5001 To cancel an uncommitted merge (and lose your changes),
5001 To cancel an uncommitted merge (and lose your changes),
5002 use :hg:`merge --abort`.
5002 use :hg:`merge --abort`.
5003
5003
5004 With no revision specified, revert the specified files or directories
5004 With no revision specified, revert the specified files or directories
5005 to the contents they had in the parent of the working directory.
5005 to the contents they had in the parent of the working directory.
5006 This restores the contents of files to an unmodified
5006 This restores the contents of files to an unmodified
5007 state and unschedules adds, removes, copies, and renames. If the
5007 state and unschedules adds, removes, copies, and renames. If the
5008 working directory has two parents, you must explicitly specify a
5008 working directory has two parents, you must explicitly specify a
5009 revision.
5009 revision.
5010
5010
5011 Using the -r/--rev or -d/--date options, revert the given files or
5011 Using the -r/--rev or -d/--date options, revert the given files or
5012 directories to their states as of a specific revision. Because
5012 directories to their states as of a specific revision. Because
5013 revert does not change the working directory parents, this will
5013 revert does not change the working directory parents, this will
5014 cause these files to appear modified. This can be helpful to "back
5014 cause these files to appear modified. This can be helpful to "back
5015 out" some or all of an earlier change. See :hg:`backout` for a
5015 out" some or all of an earlier change. See :hg:`backout` for a
5016 related method.
5016 related method.
5017
5017
5018 Modified files are saved with a .orig suffix before reverting.
5018 Modified files are saved with a .orig suffix before reverting.
5019 To disable these backups, use --no-backup. It is possible to store
5019 To disable these backups, use --no-backup. It is possible to store
5020 the backup files in a custom directory relative to the root of the
5020 the backup files in a custom directory relative to the root of the
5021 repository by setting the ``ui.origbackuppath`` configuration
5021 repository by setting the ``ui.origbackuppath`` configuration
5022 option.
5022 option.
5023
5023
5024 See :hg:`help dates` for a list of formats valid for -d/--date.
5024 See :hg:`help dates` for a list of formats valid for -d/--date.
5025
5025
5026 See :hg:`help backout` for a way to reverse the effect of an
5026 See :hg:`help backout` for a way to reverse the effect of an
5027 earlier changeset.
5027 earlier changeset.
5028
5028
5029 Returns 0 on success.
5029 Returns 0 on success.
5030 """
5030 """
5031
5031
5032 opts = pycompat.byteskwargs(opts)
5032 opts = pycompat.byteskwargs(opts)
5033 if opts.get("date"):
5033 if opts.get("date"):
5034 if opts.get("rev"):
5034 if opts.get("rev"):
5035 raise error.Abort(_("you can't specify a revision and a date"))
5035 raise error.Abort(_("you can't specify a revision and a date"))
5036 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5036 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5037
5037
5038 parent, p2 = repo.dirstate.parents()
5038 parent, p2 = repo.dirstate.parents()
5039 if not opts.get('rev') and p2 != nullid:
5039 if not opts.get('rev') and p2 != nullid:
5040 # revert after merge is a trap for new users (issue2915)
5040 # revert after merge is a trap for new users (issue2915)
5041 raise error.Abort(_('uncommitted merge with no revision specified'),
5041 raise error.Abort(_('uncommitted merge with no revision specified'),
5042 hint=_("use 'hg update' or see 'hg help revert'"))
5042 hint=_("use 'hg update' or see 'hg help revert'"))
5043
5043
5044 rev = opts.get('rev')
5044 rev = opts.get('rev')
5045 if rev:
5045 if rev:
5046 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5046 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5047 ctx = scmutil.revsingle(repo, rev)
5047 ctx = scmutil.revsingle(repo, rev)
5048
5048
5049 if (not (pats or opts.get('include') or opts.get('exclude') or
5049 if (not (pats or opts.get('include') or opts.get('exclude') or
5050 opts.get('all') or opts.get('interactive'))):
5050 opts.get('all') or opts.get('interactive'))):
5051 msg = _("no files or directories specified")
5051 msg = _("no files or directories specified")
5052 if p2 != nullid:
5052 if p2 != nullid:
5053 hint = _("uncommitted merge, use --all to discard all changes,"
5053 hint = _("uncommitted merge, use --all to discard all changes,"
5054 " or 'hg update -C .' to abort the merge")
5054 " or 'hg update -C .' to abort the merge")
5055 raise error.Abort(msg, hint=hint)
5055 raise error.Abort(msg, hint=hint)
5056 dirty = any(repo.status())
5056 dirty = any(repo.status())
5057 node = ctx.node()
5057 node = ctx.node()
5058 if node != parent:
5058 if node != parent:
5059 if dirty:
5059 if dirty:
5060 hint = _("uncommitted changes, use --all to discard all"
5060 hint = _("uncommitted changes, use --all to discard all"
5061 " changes, or 'hg update %d' to update") % ctx.rev()
5061 " changes, or 'hg update %d' to update") % ctx.rev()
5062 else:
5062 else:
5063 hint = _("use --all to revert all files,"
5063 hint = _("use --all to revert all files,"
5064 " or 'hg update %d' to update") % ctx.rev()
5064 " or 'hg update %d' to update") % ctx.rev()
5065 elif dirty:
5065 elif dirty:
5066 hint = _("uncommitted changes, use --all to discard all changes")
5066 hint = _("uncommitted changes, use --all to discard all changes")
5067 else:
5067 else:
5068 hint = _("use --all to revert all files")
5068 hint = _("use --all to revert all files")
5069 raise error.Abort(msg, hint=hint)
5069 raise error.Abort(msg, hint=hint)
5070
5070
5071 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5071 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5072 **pycompat.strkwargs(opts))
5072 **pycompat.strkwargs(opts))
5073
5073
5074 @command(
5074 @command(
5075 'rollback',
5075 'rollback',
5076 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5076 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5077 helpcategory=command.CATEGORY_MAINTENANCE)
5077 helpcategory=command.CATEGORY_MAINTENANCE)
5078 def rollback(ui, repo, **opts):
5078 def rollback(ui, repo, **opts):
5079 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5079 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5080
5080
5081 Please use :hg:`commit --amend` instead of rollback to correct
5081 Please use :hg:`commit --amend` instead of rollback to correct
5082 mistakes in the last commit.
5082 mistakes in the last commit.
5083
5083
5084 This command should be used with care. There is only one level of
5084 This command should be used with care. There is only one level of
5085 rollback, and there is no way to undo a rollback. It will also
5085 rollback, and there is no way to undo a rollback. It will also
5086 restore the dirstate at the time of the last transaction, losing
5086 restore the dirstate at the time of the last transaction, losing
5087 any dirstate changes since that time. This command does not alter
5087 any dirstate changes since that time. This command does not alter
5088 the working directory.
5088 the working directory.
5089
5089
5090 Transactions are used to encapsulate the effects of all commands
5090 Transactions are used to encapsulate the effects of all commands
5091 that create new changesets or propagate existing changesets into a
5091 that create new changesets or propagate existing changesets into a
5092 repository.
5092 repository.
5093
5093
5094 .. container:: verbose
5094 .. container:: verbose
5095
5095
5096 For example, the following commands are transactional, and their
5096 For example, the following commands are transactional, and their
5097 effects can be rolled back:
5097 effects can be rolled back:
5098
5098
5099 - commit
5099 - commit
5100 - import
5100 - import
5101 - pull
5101 - pull
5102 - push (with this repository as the destination)
5102 - push (with this repository as the destination)
5103 - unbundle
5103 - unbundle
5104
5104
5105 To avoid permanent data loss, rollback will refuse to rollback a
5105 To avoid permanent data loss, rollback will refuse to rollback a
5106 commit transaction if it isn't checked out. Use --force to
5106 commit transaction if it isn't checked out. Use --force to
5107 override this protection.
5107 override this protection.
5108
5108
5109 The rollback command can be entirely disabled by setting the
5109 The rollback command can be entirely disabled by setting the
5110 ``ui.rollback`` configuration setting to false. If you're here
5110 ``ui.rollback`` configuration setting to false. If you're here
5111 because you want to use rollback and it's disabled, you can
5111 because you want to use rollback and it's disabled, you can
5112 re-enable the command by setting ``ui.rollback`` to true.
5112 re-enable the command by setting ``ui.rollback`` to true.
5113
5113
5114 This command is not intended for use on public repositories. Once
5114 This command is not intended for use on public repositories. Once
5115 changes are visible for pull by other users, rolling a transaction
5115 changes are visible for pull by other users, rolling a transaction
5116 back locally is ineffective (someone else may already have pulled
5116 back locally is ineffective (someone else may already have pulled
5117 the changes). Furthermore, a race is possible with readers of the
5117 the changes). Furthermore, a race is possible with readers of the
5118 repository; for example an in-progress pull from the repository
5118 repository; for example an in-progress pull from the repository
5119 may fail if a rollback is performed.
5119 may fail if a rollback is performed.
5120
5120
5121 Returns 0 on success, 1 if no rollback data is available.
5121 Returns 0 on success, 1 if no rollback data is available.
5122 """
5122 """
5123 if not ui.configbool('ui', 'rollback'):
5123 if not ui.configbool('ui', 'rollback'):
5124 raise error.Abort(_('rollback is disabled because it is unsafe'),
5124 raise error.Abort(_('rollback is disabled because it is unsafe'),
5125 hint=('see `hg help -v rollback` for information'))
5125 hint=('see `hg help -v rollback` for information'))
5126 return repo.rollback(dryrun=opts.get(r'dry_run'),
5126 return repo.rollback(dryrun=opts.get(r'dry_run'),
5127 force=opts.get(r'force'))
5127 force=opts.get(r'force'))
5128
5128
5129 @command(
5129 @command(
5130 'root', [], intents={INTENT_READONLY},
5130 'root', [], intents={INTENT_READONLY},
5131 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5131 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5132 def root(ui, repo):
5132 def root(ui, repo):
5133 """print the root (top) of the current working directory
5133 """print the root (top) of the current working directory
5134
5134
5135 Print the root directory of the current repository.
5135 Print the root directory of the current repository.
5136
5136
5137 Returns 0 on success.
5137 Returns 0 on success.
5138 """
5138 """
5139 ui.write(repo.root + "\n")
5139 ui.write(repo.root + "\n")
5140
5140
5141 @command('serve',
5141 @command('serve',
5142 [('A', 'accesslog', '', _('name of access log file to write to'),
5142 [('A', 'accesslog', '', _('name of access log file to write to'),
5143 _('FILE')),
5143 _('FILE')),
5144 ('d', 'daemon', None, _('run server in background')),
5144 ('d', 'daemon', None, _('run server in background')),
5145 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5145 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5146 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5146 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5147 # use string type, then we can check if something was passed
5147 # use string type, then we can check if something was passed
5148 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5148 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5149 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5149 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5150 _('ADDR')),
5150 _('ADDR')),
5151 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5151 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5152 _('PREFIX')),
5152 _('PREFIX')),
5153 ('n', 'name', '',
5153 ('n', 'name', '',
5154 _('name to show in web pages (default: working directory)'), _('NAME')),
5154 _('name to show in web pages (default: working directory)'), _('NAME')),
5155 ('', 'web-conf', '',
5155 ('', 'web-conf', '',
5156 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5156 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5157 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5157 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5158 _('FILE')),
5158 _('FILE')),
5159 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5159 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5160 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5160 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5161 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5161 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5162 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5162 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5163 ('', 'style', '', _('template style to use'), _('STYLE')),
5163 ('', 'style', '', _('template style to use'), _('STYLE')),
5164 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5164 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5165 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5165 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5166 ('', 'print-url', None, _('start and print only the URL'))]
5166 ('', 'print-url', None, _('start and print only the URL'))]
5167 + subrepoopts,
5167 + subrepoopts,
5168 _('[OPTION]...'),
5168 _('[OPTION]...'),
5169 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5169 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5170 helpbasic=True, optionalrepo=True)
5170 helpbasic=True, optionalrepo=True)
5171 def serve(ui, repo, **opts):
5171 def serve(ui, repo, **opts):
5172 """start stand-alone webserver
5172 """start stand-alone webserver
5173
5173
5174 Start a local HTTP repository browser and pull server. You can use
5174 Start a local HTTP repository browser and pull server. You can use
5175 this for ad-hoc sharing and browsing of repositories. It is
5175 this for ad-hoc sharing and browsing of repositories. It is
5176 recommended to use a real web server to serve a repository for
5176 recommended to use a real web server to serve a repository for
5177 longer periods of time.
5177 longer periods of time.
5178
5178
5179 Please note that the server does not implement access control.
5179 Please note that the server does not implement access control.
5180 This means that, by default, anybody can read from the server and
5180 This means that, by default, anybody can read from the server and
5181 nobody can write to it by default. Set the ``web.allow-push``
5181 nobody can write to it by default. Set the ``web.allow-push``
5182 option to ``*`` to allow everybody to push to the server. You
5182 option to ``*`` to allow everybody to push to the server. You
5183 should use a real web server if you need to authenticate users.
5183 should use a real web server if you need to authenticate users.
5184
5184
5185 By default, the server logs accesses to stdout and errors to
5185 By default, the server logs accesses to stdout and errors to
5186 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5186 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5187 files.
5187 files.
5188
5188
5189 To have the server choose a free port number to listen on, specify
5189 To have the server choose a free port number to listen on, specify
5190 a port number of 0; in this case, the server will print the port
5190 a port number of 0; in this case, the server will print the port
5191 number it uses.
5191 number it uses.
5192
5192
5193 Returns 0 on success.
5193 Returns 0 on success.
5194 """
5194 """
5195
5195
5196 opts = pycompat.byteskwargs(opts)
5196 opts = pycompat.byteskwargs(opts)
5197 if opts["stdio"] and opts["cmdserver"]:
5197 if opts["stdio"] and opts["cmdserver"]:
5198 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5198 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5199 if opts["print_url"] and ui.verbose:
5199 if opts["print_url"] and ui.verbose:
5200 raise error.Abort(_("cannot use --print-url with --verbose"))
5200 raise error.Abort(_("cannot use --print-url with --verbose"))
5201
5201
5202 if opts["stdio"]:
5202 if opts["stdio"]:
5203 if repo is None:
5203 if repo is None:
5204 raise error.RepoError(_("there is no Mercurial repository here"
5204 raise error.RepoError(_("there is no Mercurial repository here"
5205 " (.hg not found)"))
5205 " (.hg not found)"))
5206 s = wireprotoserver.sshserver(ui, repo)
5206 s = wireprotoserver.sshserver(ui, repo)
5207 s.serve_forever()
5207 s.serve_forever()
5208
5208
5209 service = server.createservice(ui, repo, opts)
5209 service = server.createservice(ui, repo, opts)
5210 return server.runservice(opts, initfn=service.init, runfn=service.run)
5210 return server.runservice(opts, initfn=service.init, runfn=service.run)
5211
5211
5212 _NOTTERSE = 'nothing'
5212 _NOTTERSE = 'nothing'
5213
5213
5214 @command('status|st',
5214 @command('status|st',
5215 [('A', 'all', None, _('show status of all files')),
5215 [('A', 'all', None, _('show status of all files')),
5216 ('m', 'modified', None, _('show only modified files')),
5216 ('m', 'modified', None, _('show only modified files')),
5217 ('a', 'added', None, _('show only added files')),
5217 ('a', 'added', None, _('show only added files')),
5218 ('r', 'removed', None, _('show only removed files')),
5218 ('r', 'removed', None, _('show only removed files')),
5219 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5219 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5220 ('c', 'clean', None, _('show only files without changes')),
5220 ('c', 'clean', None, _('show only files without changes')),
5221 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5221 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5222 ('i', 'ignored', None, _('show only ignored files')),
5222 ('i', 'ignored', None, _('show only ignored files')),
5223 ('n', 'no-status', None, _('hide status prefix')),
5223 ('n', 'no-status', None, _('hide status prefix')),
5224 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5224 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5225 ('C', 'copies', None, _('show source of copied files')),
5225 ('C', 'copies', None, _('show source of copied files')),
5226 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5226 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5227 ('', 'rev', [], _('show difference from revision'), _('REV')),
5227 ('', 'rev', [], _('show difference from revision'), _('REV')),
5228 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5228 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5229 ] + walkopts + subrepoopts + formatteropts,
5229 ] + walkopts + subrepoopts + formatteropts,
5230 _('[OPTION]... [FILE]...'),
5230 _('[OPTION]... [FILE]...'),
5231 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5231 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5232 helpbasic=True, inferrepo=True,
5232 helpbasic=True, inferrepo=True,
5233 intents={INTENT_READONLY})
5233 intents={INTENT_READONLY})
5234 def status(ui, repo, *pats, **opts):
5234 def status(ui, repo, *pats, **opts):
5235 """show changed files in the working directory
5235 """show changed files in the working directory
5236
5236
5237 Show status of files in the repository. If names are given, only
5237 Show status of files in the repository. If names are given, only
5238 files that match are shown. Files that are clean or ignored or
5238 files that match are shown. Files that are clean or ignored or
5239 the source of a copy/move operation, are not listed unless
5239 the source of a copy/move operation, are not listed unless
5240 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5240 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5241 Unless options described with "show only ..." are given, the
5241 Unless options described with "show only ..." are given, the
5242 options -mardu are used.
5242 options -mardu are used.
5243
5243
5244 Option -q/--quiet hides untracked (unknown and ignored) files
5244 Option -q/--quiet hides untracked (unknown and ignored) files
5245 unless explicitly requested with -u/--unknown or -i/--ignored.
5245 unless explicitly requested with -u/--unknown or -i/--ignored.
5246
5246
5247 .. note::
5247 .. note::
5248
5248
5249 :hg:`status` may appear to disagree with diff if permissions have
5249 :hg:`status` may appear to disagree with diff if permissions have
5250 changed or a merge has occurred. The standard diff format does
5250 changed or a merge has occurred. The standard diff format does
5251 not report permission changes and diff only reports changes
5251 not report permission changes and diff only reports changes
5252 relative to one merge parent.
5252 relative to one merge parent.
5253
5253
5254 If one revision is given, it is used as the base revision.
5254 If one revision is given, it is used as the base revision.
5255 If two revisions are given, the differences between them are
5255 If two revisions are given, the differences between them are
5256 shown. The --change option can also be used as a shortcut to list
5256 shown. The --change option can also be used as a shortcut to list
5257 the changed files of a revision from its first parent.
5257 the changed files of a revision from its first parent.
5258
5258
5259 The codes used to show the status of files are::
5259 The codes used to show the status of files are::
5260
5260
5261 M = modified
5261 M = modified
5262 A = added
5262 A = added
5263 R = removed
5263 R = removed
5264 C = clean
5264 C = clean
5265 ! = missing (deleted by non-hg command, but still tracked)
5265 ! = missing (deleted by non-hg command, but still tracked)
5266 ? = not tracked
5266 ? = not tracked
5267 I = ignored
5267 I = ignored
5268 = origin of the previous file (with --copies)
5268 = origin of the previous file (with --copies)
5269
5269
5270 .. container:: verbose
5270 .. container:: verbose
5271
5271
5272 The -t/--terse option abbreviates the output by showing only the directory
5272 The -t/--terse option abbreviates the output by showing only the directory
5273 name if all the files in it share the same status. The option takes an
5273 name if all the files in it share the same status. The option takes an
5274 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5274 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5275 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5275 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5276 for 'ignored' and 'c' for clean.
5276 for 'ignored' and 'c' for clean.
5277
5277
5278 It abbreviates only those statuses which are passed. Note that clean and
5278 It abbreviates only those statuses which are passed. Note that clean and
5279 ignored files are not displayed with '--terse ic' unless the -c/--clean
5279 ignored files are not displayed with '--terse ic' unless the -c/--clean
5280 and -i/--ignored options are also used.
5280 and -i/--ignored options are also used.
5281
5281
5282 The -v/--verbose option shows information when the repository is in an
5282 The -v/--verbose option shows information when the repository is in an
5283 unfinished merge, shelve, rebase state etc. You can have this behavior
5283 unfinished merge, shelve, rebase state etc. You can have this behavior
5284 turned on by default by enabling the ``commands.status.verbose`` option.
5284 turned on by default by enabling the ``commands.status.verbose`` option.
5285
5285
5286 You can skip displaying some of these states by setting
5286 You can skip displaying some of these states by setting
5287 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5287 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5288 'histedit', 'merge', 'rebase', or 'unshelve'.
5288 'histedit', 'merge', 'rebase', or 'unshelve'.
5289
5289
5290 Template:
5290 Template:
5291
5291
5292 The following keywords are supported in addition to the common template
5292 The following keywords are supported in addition to the common template
5293 keywords and functions. See also :hg:`help templates`.
5293 keywords and functions. See also :hg:`help templates`.
5294
5294
5295 :path: String. Repository-absolute path of the file.
5295 :path: String. Repository-absolute path of the file.
5296 :source: String. Repository-absolute path of the file originated from.
5296 :source: String. Repository-absolute path of the file originated from.
5297 Available if ``--copies`` is specified.
5297 Available if ``--copies`` is specified.
5298 :status: String. Character denoting file's status.
5298 :status: String. Character denoting file's status.
5299
5299
5300 Examples:
5300 Examples:
5301
5301
5302 - show changes in the working directory relative to a
5302 - show changes in the working directory relative to a
5303 changeset::
5303 changeset::
5304
5304
5305 hg status --rev 9353
5305 hg status --rev 9353
5306
5306
5307 - show changes in the working directory relative to the
5307 - show changes in the working directory relative to the
5308 current directory (see :hg:`help patterns` for more information)::
5308 current directory (see :hg:`help patterns` for more information)::
5309
5309
5310 hg status re:
5310 hg status re:
5311
5311
5312 - show all changes including copies in an existing changeset::
5312 - show all changes including copies in an existing changeset::
5313
5313
5314 hg status --copies --change 9353
5314 hg status --copies --change 9353
5315
5315
5316 - get a NUL separated list of added files, suitable for xargs::
5316 - get a NUL separated list of added files, suitable for xargs::
5317
5317
5318 hg status -an0
5318 hg status -an0
5319
5319
5320 - show more information about the repository status, abbreviating
5320 - show more information about the repository status, abbreviating
5321 added, removed, modified, deleted, and untracked paths::
5321 added, removed, modified, deleted, and untracked paths::
5322
5322
5323 hg status -v -t mardu
5323 hg status -v -t mardu
5324
5324
5325 Returns 0 on success.
5325 Returns 0 on success.
5326
5326
5327 """
5327 """
5328
5328
5329 opts = pycompat.byteskwargs(opts)
5329 opts = pycompat.byteskwargs(opts)
5330 revs = opts.get('rev')
5330 revs = opts.get('rev')
5331 change = opts.get('change')
5331 change = opts.get('change')
5332 terse = opts.get('terse')
5332 terse = opts.get('terse')
5333 if terse is _NOTTERSE:
5333 if terse is _NOTTERSE:
5334 if revs:
5334 if revs:
5335 terse = ''
5335 terse = ''
5336 else:
5336 else:
5337 terse = ui.config('commands', 'status.terse')
5337 terse = ui.config('commands', 'status.terse')
5338
5338
5339 if revs and change:
5339 if revs and change:
5340 msg = _('cannot specify --rev and --change at the same time')
5340 msg = _('cannot specify --rev and --change at the same time')
5341 raise error.Abort(msg)
5341 raise error.Abort(msg)
5342 elif revs and terse:
5342 elif revs and terse:
5343 msg = _('cannot use --terse with --rev')
5343 msg = _('cannot use --terse with --rev')
5344 raise error.Abort(msg)
5344 raise error.Abort(msg)
5345 elif change:
5345 elif change:
5346 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5346 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5347 ctx2 = scmutil.revsingle(repo, change, None)
5347 ctx2 = scmutil.revsingle(repo, change, None)
5348 ctx1 = ctx2.p1()
5348 ctx1 = ctx2.p1()
5349 else:
5349 else:
5350 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5350 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5351 ctx1, ctx2 = scmutil.revpair(repo, revs)
5351 ctx1, ctx2 = scmutil.revpair(repo, revs)
5352
5352
5353 if pats or ui.configbool('commands', 'status.relative'):
5353 if pats or ui.configbool('commands', 'status.relative'):
5354 cwd = repo.getcwd()
5354 cwd = repo.getcwd()
5355 else:
5355 else:
5356 cwd = ''
5356 cwd = ''
5357
5357
5358 if opts.get('print0'):
5358 if opts.get('print0'):
5359 end = '\0'
5359 end = '\0'
5360 else:
5360 else:
5361 end = '\n'
5361 end = '\n'
5362 copy = {}
5362 copy = {}
5363 states = 'modified added removed deleted unknown ignored clean'.split()
5363 states = 'modified added removed deleted unknown ignored clean'.split()
5364 show = [k for k in states if opts.get(k)]
5364 show = [k for k in states if opts.get(k)]
5365 if opts.get('all'):
5365 if opts.get('all'):
5366 show += ui.quiet and (states[:4] + ['clean']) or states
5366 show += ui.quiet and (states[:4] + ['clean']) or states
5367
5367
5368 if not show:
5368 if not show:
5369 if ui.quiet:
5369 if ui.quiet:
5370 show = states[:4]
5370 show = states[:4]
5371 else:
5371 else:
5372 show = states[:5]
5372 show = states[:5]
5373
5373
5374 m = scmutil.match(ctx2, pats, opts)
5374 m = scmutil.match(ctx2, pats, opts)
5375 if terse:
5375 if terse:
5376 # we need to compute clean and unknown to terse
5376 # we need to compute clean and unknown to terse
5377 stat = repo.status(ctx1.node(), ctx2.node(), m,
5377 stat = repo.status(ctx1.node(), ctx2.node(), m,
5378 'ignored' in show or 'i' in terse,
5378 'ignored' in show or 'i' in terse,
5379 clean=True, unknown=True,
5379 clean=True, unknown=True,
5380 listsubrepos=opts.get('subrepos'))
5380 listsubrepos=opts.get('subrepos'))
5381
5381
5382 stat = cmdutil.tersedir(stat, terse)
5382 stat = cmdutil.tersedir(stat, terse)
5383 else:
5383 else:
5384 stat = repo.status(ctx1.node(), ctx2.node(), m,
5384 stat = repo.status(ctx1.node(), ctx2.node(), m,
5385 'ignored' in show, 'clean' in show,
5385 'ignored' in show, 'clean' in show,
5386 'unknown' in show, opts.get('subrepos'))
5386 'unknown' in show, opts.get('subrepos'))
5387
5387
5388 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5388 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5389
5389
5390 if (opts.get('all') or opts.get('copies')
5390 if (opts.get('all') or opts.get('copies')
5391 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5391 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5392 copy = copies.pathcopies(ctx1, ctx2, m)
5392 copy = copies.pathcopies(ctx1, ctx2, m)
5393
5393
5394 ui.pager('status')
5394 ui.pager('status')
5395 fm = ui.formatter('status', opts)
5395 fm = ui.formatter('status', opts)
5396 fmt = '%s' + end
5396 fmt = '%s' + end
5397 showchar = not opts.get('no_status')
5397 showchar = not opts.get('no_status')
5398
5398
5399 for state, char, files in changestates:
5399 for state, char, files in changestates:
5400 if state in show:
5400 if state in show:
5401 label = 'status.' + state
5401 label = 'status.' + state
5402 for f in files:
5402 for f in files:
5403 fm.startitem()
5403 fm.startitem()
5404 fm.context(ctx=ctx2)
5404 fm.context(ctx=ctx2)
5405 fm.data(path=f)
5405 fm.data(path=f)
5406 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5406 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5407 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5407 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5408 if f in copy:
5408 if f in copy:
5409 fm.data(source=copy[f])
5409 fm.data(source=copy[f])
5410 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5410 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5411 label='status.copied')
5411 label='status.copied')
5412
5412
5413 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5413 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5414 and not ui.plain()):
5414 and not ui.plain()):
5415 cmdutil.morestatus(repo, fm)
5415 cmdutil.morestatus(repo, fm)
5416 fm.end()
5416 fm.end()
5417
5417
5418 @command('summary|sum',
5418 @command('summary|sum',
5419 [('', 'remote', None, _('check for push and pull'))],
5419 [('', 'remote', None, _('check for push and pull'))],
5420 '[--remote]',
5420 '[--remote]',
5421 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5421 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5422 helpbasic=True,
5422 helpbasic=True,
5423 intents={INTENT_READONLY})
5423 intents={INTENT_READONLY})
5424 def summary(ui, repo, **opts):
5424 def summary(ui, repo, **opts):
5425 """summarize working directory state
5425 """summarize working directory state
5426
5426
5427 This generates a brief summary of the working directory state,
5427 This generates a brief summary of the working directory state,
5428 including parents, branch, commit status, phase and available updates.
5428 including parents, branch, commit status, phase and available updates.
5429
5429
5430 With the --remote option, this will check the default paths for
5430 With the --remote option, this will check the default paths for
5431 incoming and outgoing changes. This can be time-consuming.
5431 incoming and outgoing changes. This can be time-consuming.
5432
5432
5433 Returns 0 on success.
5433 Returns 0 on success.
5434 """
5434 """
5435
5435
5436 opts = pycompat.byteskwargs(opts)
5436 opts = pycompat.byteskwargs(opts)
5437 ui.pager('summary')
5437 ui.pager('summary')
5438 ctx = repo[None]
5438 ctx = repo[None]
5439 parents = ctx.parents()
5439 parents = ctx.parents()
5440 pnode = parents[0].node()
5440 pnode = parents[0].node()
5441 marks = []
5441 marks = []
5442
5442
5443 ms = None
5443 ms = None
5444 try:
5444 try:
5445 ms = mergemod.mergestate.read(repo)
5445 ms = mergemod.mergestate.read(repo)
5446 except error.UnsupportedMergeRecords as e:
5446 except error.UnsupportedMergeRecords as e:
5447 s = ' '.join(e.recordtypes)
5447 s = ' '.join(e.recordtypes)
5448 ui.warn(
5448 ui.warn(
5449 _('warning: merge state has unsupported record types: %s\n') % s)
5449 _('warning: merge state has unsupported record types: %s\n') % s)
5450 unresolved = []
5450 unresolved = []
5451 else:
5451 else:
5452 unresolved = list(ms.unresolved())
5452 unresolved = list(ms.unresolved())
5453
5453
5454 for p in parents:
5454 for p in parents:
5455 # label with log.changeset (instead of log.parent) since this
5455 # label with log.changeset (instead of log.parent) since this
5456 # shows a working directory parent *changeset*:
5456 # shows a working directory parent *changeset*:
5457 # i18n: column positioning for "hg summary"
5457 # i18n: column positioning for "hg summary"
5458 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5458 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5459 label=logcmdutil.changesetlabels(p))
5459 label=logcmdutil.changesetlabels(p))
5460 ui.write(' '.join(p.tags()), label='log.tag')
5460 ui.write(' '.join(p.tags()), label='log.tag')
5461 if p.bookmarks():
5461 if p.bookmarks():
5462 marks.extend(p.bookmarks())
5462 marks.extend(p.bookmarks())
5463 if p.rev() == -1:
5463 if p.rev() == -1:
5464 if not len(repo):
5464 if not len(repo):
5465 ui.write(_(' (empty repository)'))
5465 ui.write(_(' (empty repository)'))
5466 else:
5466 else:
5467 ui.write(_(' (no revision checked out)'))
5467 ui.write(_(' (no revision checked out)'))
5468 if p.obsolete():
5468 if p.obsolete():
5469 ui.write(_(' (obsolete)'))
5469 ui.write(_(' (obsolete)'))
5470 if p.isunstable():
5470 if p.isunstable():
5471 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5471 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5472 for instability in p.instabilities())
5472 for instability in p.instabilities())
5473 ui.write(' ('
5473 ui.write(' ('
5474 + ', '.join(instabilities)
5474 + ', '.join(instabilities)
5475 + ')')
5475 + ')')
5476 ui.write('\n')
5476 ui.write('\n')
5477 if p.description():
5477 if p.description():
5478 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5478 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5479 label='log.summary')
5479 label='log.summary')
5480
5480
5481 branch = ctx.branch()
5481 branch = ctx.branch()
5482 bheads = repo.branchheads(branch)
5482 bheads = repo.branchheads(branch)
5483 # i18n: column positioning for "hg summary"
5483 # i18n: column positioning for "hg summary"
5484 m = _('branch: %s\n') % branch
5484 m = _('branch: %s\n') % branch
5485 if branch != 'default':
5485 if branch != 'default':
5486 ui.write(m, label='log.branch')
5486 ui.write(m, label='log.branch')
5487 else:
5487 else:
5488 ui.status(m, label='log.branch')
5488 ui.status(m, label='log.branch')
5489
5489
5490 if marks:
5490 if marks:
5491 active = repo._activebookmark
5491 active = repo._activebookmark
5492 # i18n: column positioning for "hg summary"
5492 # i18n: column positioning for "hg summary"
5493 ui.write(_('bookmarks:'), label='log.bookmark')
5493 ui.write(_('bookmarks:'), label='log.bookmark')
5494 if active is not None:
5494 if active is not None:
5495 if active in marks:
5495 if active in marks:
5496 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5496 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5497 marks.remove(active)
5497 marks.remove(active)
5498 else:
5498 else:
5499 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5499 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5500 for m in marks:
5500 for m in marks:
5501 ui.write(' ' + m, label='log.bookmark')
5501 ui.write(' ' + m, label='log.bookmark')
5502 ui.write('\n', label='log.bookmark')
5502 ui.write('\n', label='log.bookmark')
5503
5503
5504 status = repo.status(unknown=True)
5504 status = repo.status(unknown=True)
5505
5505
5506 c = repo.dirstate.copies()
5506 c = repo.dirstate.copies()
5507 copied, renamed = [], []
5507 copied, renamed = [], []
5508 for d, s in c.iteritems():
5508 for d, s in c.iteritems():
5509 if s in status.removed:
5509 if s in status.removed:
5510 status.removed.remove(s)
5510 status.removed.remove(s)
5511 renamed.append(d)
5511 renamed.append(d)
5512 else:
5512 else:
5513 copied.append(d)
5513 copied.append(d)
5514 if d in status.added:
5514 if d in status.added:
5515 status.added.remove(d)
5515 status.added.remove(d)
5516
5516
5517 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5517 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5518
5518
5519 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5519 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5520 (ui.label(_('%d added'), 'status.added'), status.added),
5520 (ui.label(_('%d added'), 'status.added'), status.added),
5521 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5521 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5522 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5522 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5523 (ui.label(_('%d copied'), 'status.copied'), copied),
5523 (ui.label(_('%d copied'), 'status.copied'), copied),
5524 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5524 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5525 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5525 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5526 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5526 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5527 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5527 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5528 t = []
5528 t = []
5529 for l, s in labels:
5529 for l, s in labels:
5530 if s:
5530 if s:
5531 t.append(l % len(s))
5531 t.append(l % len(s))
5532
5532
5533 t = ', '.join(t)
5533 t = ', '.join(t)
5534 cleanworkdir = False
5534 cleanworkdir = False
5535
5535
5536 if repo.vfs.exists('graftstate'):
5536 if repo.vfs.exists('graftstate'):
5537 t += _(' (graft in progress)')
5537 t += _(' (graft in progress)')
5538 if repo.vfs.exists('updatestate'):
5538 if repo.vfs.exists('updatestate'):
5539 t += _(' (interrupted update)')
5539 t += _(' (interrupted update)')
5540 elif len(parents) > 1:
5540 elif len(parents) > 1:
5541 t += _(' (merge)')
5541 t += _(' (merge)')
5542 elif branch != parents[0].branch():
5542 elif branch != parents[0].branch():
5543 t += _(' (new branch)')
5543 t += _(' (new branch)')
5544 elif (parents[0].closesbranch() and
5544 elif (parents[0].closesbranch() and
5545 pnode in repo.branchheads(branch, closed=True)):
5545 pnode in repo.branchheads(branch, closed=True)):
5546 t += _(' (head closed)')
5546 t += _(' (head closed)')
5547 elif not (status.modified or status.added or status.removed or renamed or
5547 elif not (status.modified or status.added or status.removed or renamed or
5548 copied or subs):
5548 copied or subs):
5549 t += _(' (clean)')
5549 t += _(' (clean)')
5550 cleanworkdir = True
5550 cleanworkdir = True
5551 elif pnode not in bheads:
5551 elif pnode not in bheads:
5552 t += _(' (new branch head)')
5552 t += _(' (new branch head)')
5553
5553
5554 if parents:
5554 if parents:
5555 pendingphase = max(p.phase() for p in parents)
5555 pendingphase = max(p.phase() for p in parents)
5556 else:
5556 else:
5557 pendingphase = phases.public
5557 pendingphase = phases.public
5558
5558
5559 if pendingphase > phases.newcommitphase(ui):
5559 if pendingphase > phases.newcommitphase(ui):
5560 t += ' (%s)' % phases.phasenames[pendingphase]
5560 t += ' (%s)' % phases.phasenames[pendingphase]
5561
5561
5562 if cleanworkdir:
5562 if cleanworkdir:
5563 # i18n: column positioning for "hg summary"
5563 # i18n: column positioning for "hg summary"
5564 ui.status(_('commit: %s\n') % t.strip())
5564 ui.status(_('commit: %s\n') % t.strip())
5565 else:
5565 else:
5566 # i18n: column positioning for "hg summary"
5566 # i18n: column positioning for "hg summary"
5567 ui.write(_('commit: %s\n') % t.strip())
5567 ui.write(_('commit: %s\n') % t.strip())
5568
5568
5569 # all ancestors of branch heads - all ancestors of parent = new csets
5569 # all ancestors of branch heads - all ancestors of parent = new csets
5570 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5570 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5571 bheads))
5571 bheads))
5572
5572
5573 if new == 0:
5573 if new == 0:
5574 # i18n: column positioning for "hg summary"
5574 # i18n: column positioning for "hg summary"
5575 ui.status(_('update: (current)\n'))
5575 ui.status(_('update: (current)\n'))
5576 elif pnode not in bheads:
5576 elif pnode not in bheads:
5577 # i18n: column positioning for "hg summary"
5577 # i18n: column positioning for "hg summary"
5578 ui.write(_('update: %d new changesets (update)\n') % new)
5578 ui.write(_('update: %d new changesets (update)\n') % new)
5579 else:
5579 else:
5580 # i18n: column positioning for "hg summary"
5580 # i18n: column positioning for "hg summary"
5581 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5581 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5582 (new, len(bheads)))
5582 (new, len(bheads)))
5583
5583
5584 t = []
5584 t = []
5585 draft = len(repo.revs('draft()'))
5585 draft = len(repo.revs('draft()'))
5586 if draft:
5586 if draft:
5587 t.append(_('%d draft') % draft)
5587 t.append(_('%d draft') % draft)
5588 secret = len(repo.revs('secret()'))
5588 secret = len(repo.revs('secret()'))
5589 if secret:
5589 if secret:
5590 t.append(_('%d secret') % secret)
5590 t.append(_('%d secret') % secret)
5591
5591
5592 if draft or secret:
5592 if draft or secret:
5593 ui.status(_('phases: %s\n') % ', '.join(t))
5593 ui.status(_('phases: %s\n') % ', '.join(t))
5594
5594
5595 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5595 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5596 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5596 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5597 numtrouble = len(repo.revs(trouble + "()"))
5597 numtrouble = len(repo.revs(trouble + "()"))
5598 # We write all the possibilities to ease translation
5598 # We write all the possibilities to ease translation
5599 troublemsg = {
5599 troublemsg = {
5600 "orphan": _("orphan: %d changesets"),
5600 "orphan": _("orphan: %d changesets"),
5601 "contentdivergent": _("content-divergent: %d changesets"),
5601 "contentdivergent": _("content-divergent: %d changesets"),
5602 "phasedivergent": _("phase-divergent: %d changesets"),
5602 "phasedivergent": _("phase-divergent: %d changesets"),
5603 }
5603 }
5604 if numtrouble > 0:
5604 if numtrouble > 0:
5605 ui.status(troublemsg[trouble] % numtrouble + "\n")
5605 ui.status(troublemsg[trouble] % numtrouble + "\n")
5606
5606
5607 cmdutil.summaryhooks(ui, repo)
5607 cmdutil.summaryhooks(ui, repo)
5608
5608
5609 if opts.get('remote'):
5609 if opts.get('remote'):
5610 needsincoming, needsoutgoing = True, True
5610 needsincoming, needsoutgoing = True, True
5611 else:
5611 else:
5612 needsincoming, needsoutgoing = False, False
5612 needsincoming, needsoutgoing = False, False
5613 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5613 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5614 if i:
5614 if i:
5615 needsincoming = True
5615 needsincoming = True
5616 if o:
5616 if o:
5617 needsoutgoing = True
5617 needsoutgoing = True
5618 if not needsincoming and not needsoutgoing:
5618 if not needsincoming and not needsoutgoing:
5619 return
5619 return
5620
5620
5621 def getincoming():
5621 def getincoming():
5622 source, branches = hg.parseurl(ui.expandpath('default'))
5622 source, branches = hg.parseurl(ui.expandpath('default'))
5623 sbranch = branches[0]
5623 sbranch = branches[0]
5624 try:
5624 try:
5625 other = hg.peer(repo, {}, source)
5625 other = hg.peer(repo, {}, source)
5626 except error.RepoError:
5626 except error.RepoError:
5627 if opts.get('remote'):
5627 if opts.get('remote'):
5628 raise
5628 raise
5629 return source, sbranch, None, None, None
5629 return source, sbranch, None, None, None
5630 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5630 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5631 if revs:
5631 if revs:
5632 revs = [other.lookup(rev) for rev in revs]
5632 revs = [other.lookup(rev) for rev in revs]
5633 ui.debug('comparing with %s\n' % util.hidepassword(source))
5633 ui.debug('comparing with %s\n' % util.hidepassword(source))
5634 repo.ui.pushbuffer()
5634 repo.ui.pushbuffer()
5635 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5635 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5636 repo.ui.popbuffer()
5636 repo.ui.popbuffer()
5637 return source, sbranch, other, commoninc, commoninc[1]
5637 return source, sbranch, other, commoninc, commoninc[1]
5638
5638
5639 if needsincoming:
5639 if needsincoming:
5640 source, sbranch, sother, commoninc, incoming = getincoming()
5640 source, sbranch, sother, commoninc, incoming = getincoming()
5641 else:
5641 else:
5642 source = sbranch = sother = commoninc = incoming = None
5642 source = sbranch = sother = commoninc = incoming = None
5643
5643
5644 def getoutgoing():
5644 def getoutgoing():
5645 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5645 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5646 dbranch = branches[0]
5646 dbranch = branches[0]
5647 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5647 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5648 if source != dest:
5648 if source != dest:
5649 try:
5649 try:
5650 dother = hg.peer(repo, {}, dest)
5650 dother = hg.peer(repo, {}, dest)
5651 except error.RepoError:
5651 except error.RepoError:
5652 if opts.get('remote'):
5652 if opts.get('remote'):
5653 raise
5653 raise
5654 return dest, dbranch, None, None
5654 return dest, dbranch, None, None
5655 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5655 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5656 elif sother is None:
5656 elif sother is None:
5657 # there is no explicit destination peer, but source one is invalid
5657 # there is no explicit destination peer, but source one is invalid
5658 return dest, dbranch, None, None
5658 return dest, dbranch, None, None
5659 else:
5659 else:
5660 dother = sother
5660 dother = sother
5661 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5661 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5662 common = None
5662 common = None
5663 else:
5663 else:
5664 common = commoninc
5664 common = commoninc
5665 if revs:
5665 if revs:
5666 revs = [repo.lookup(rev) for rev in revs]
5666 revs = [repo.lookup(rev) for rev in revs]
5667 repo.ui.pushbuffer()
5667 repo.ui.pushbuffer()
5668 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5668 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5669 commoninc=common)
5669 commoninc=common)
5670 repo.ui.popbuffer()
5670 repo.ui.popbuffer()
5671 return dest, dbranch, dother, outgoing
5671 return dest, dbranch, dother, outgoing
5672
5672
5673 if needsoutgoing:
5673 if needsoutgoing:
5674 dest, dbranch, dother, outgoing = getoutgoing()
5674 dest, dbranch, dother, outgoing = getoutgoing()
5675 else:
5675 else:
5676 dest = dbranch = dother = outgoing = None
5676 dest = dbranch = dother = outgoing = None
5677
5677
5678 if opts.get('remote'):
5678 if opts.get('remote'):
5679 t = []
5679 t = []
5680 if incoming:
5680 if incoming:
5681 t.append(_('1 or more incoming'))
5681 t.append(_('1 or more incoming'))
5682 o = outgoing.missing
5682 o = outgoing.missing
5683 if o:
5683 if o:
5684 t.append(_('%d outgoing') % len(o))
5684 t.append(_('%d outgoing') % len(o))
5685 other = dother or sother
5685 other = dother or sother
5686 if 'bookmarks' in other.listkeys('namespaces'):
5686 if 'bookmarks' in other.listkeys('namespaces'):
5687 counts = bookmarks.summary(repo, other)
5687 counts = bookmarks.summary(repo, other)
5688 if counts[0] > 0:
5688 if counts[0] > 0:
5689 t.append(_('%d incoming bookmarks') % counts[0])
5689 t.append(_('%d incoming bookmarks') % counts[0])
5690 if counts[1] > 0:
5690 if counts[1] > 0:
5691 t.append(_('%d outgoing bookmarks') % counts[1])
5691 t.append(_('%d outgoing bookmarks') % counts[1])
5692
5692
5693 if t:
5693 if t:
5694 # i18n: column positioning for "hg summary"
5694 # i18n: column positioning for "hg summary"
5695 ui.write(_('remote: %s\n') % (', '.join(t)))
5695 ui.write(_('remote: %s\n') % (', '.join(t)))
5696 else:
5696 else:
5697 # i18n: column positioning for "hg summary"
5697 # i18n: column positioning for "hg summary"
5698 ui.status(_('remote: (synced)\n'))
5698 ui.status(_('remote: (synced)\n'))
5699
5699
5700 cmdutil.summaryremotehooks(ui, repo, opts,
5700 cmdutil.summaryremotehooks(ui, repo, opts,
5701 ((source, sbranch, sother, commoninc),
5701 ((source, sbranch, sother, commoninc),
5702 (dest, dbranch, dother, outgoing)))
5702 (dest, dbranch, dother, outgoing)))
5703
5703
5704 @command('tag',
5704 @command('tag',
5705 [('f', 'force', None, _('force tag')),
5705 [('f', 'force', None, _('force tag')),
5706 ('l', 'local', None, _('make the tag local')),
5706 ('l', 'local', None, _('make the tag local')),
5707 ('r', 'rev', '', _('revision to tag'), _('REV')),
5707 ('r', 'rev', '', _('revision to tag'), _('REV')),
5708 ('', 'remove', None, _('remove a tag')),
5708 ('', 'remove', None, _('remove a tag')),
5709 # -l/--local is already there, commitopts cannot be used
5709 # -l/--local is already there, commitopts cannot be used
5710 ('e', 'edit', None, _('invoke editor on commit messages')),
5710 ('e', 'edit', None, _('invoke editor on commit messages')),
5711 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5711 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5712 ] + commitopts2,
5712 ] + commitopts2,
5713 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5713 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5714 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5714 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5715 def tag(ui, repo, name1, *names, **opts):
5715 def tag(ui, repo, name1, *names, **opts):
5716 """add one or more tags for the current or given revision
5716 """add one or more tags for the current or given revision
5717
5717
5718 Name a particular revision using <name>.
5718 Name a particular revision using <name>.
5719
5719
5720 Tags are used to name particular revisions of the repository and are
5720 Tags are used to name particular revisions of the repository and are
5721 very useful to compare different revisions, to go back to significant
5721 very useful to compare different revisions, to go back to significant
5722 earlier versions or to mark branch points as releases, etc. Changing
5722 earlier versions or to mark branch points as releases, etc. Changing
5723 an existing tag is normally disallowed; use -f/--force to override.
5723 an existing tag is normally disallowed; use -f/--force to override.
5724
5724
5725 If no revision is given, the parent of the working directory is
5725 If no revision is given, the parent of the working directory is
5726 used.
5726 used.
5727
5727
5728 To facilitate version control, distribution, and merging of tags,
5728 To facilitate version control, distribution, and merging of tags,
5729 they are stored as a file named ".hgtags" which is managed similarly
5729 they are stored as a file named ".hgtags" which is managed similarly
5730 to other project files and can be hand-edited if necessary. This
5730 to other project files and can be hand-edited if necessary. This
5731 also means that tagging creates a new commit. The file
5731 also means that tagging creates a new commit. The file
5732 ".hg/localtags" is used for local tags (not shared among
5732 ".hg/localtags" is used for local tags (not shared among
5733 repositories).
5733 repositories).
5734
5734
5735 Tag commits are usually made at the head of a branch. If the parent
5735 Tag commits are usually made at the head of a branch. If the parent
5736 of the working directory is not a branch head, :hg:`tag` aborts; use
5736 of the working directory is not a branch head, :hg:`tag` aborts; use
5737 -f/--force to force the tag commit to be based on a non-head
5737 -f/--force to force the tag commit to be based on a non-head
5738 changeset.
5738 changeset.
5739
5739
5740 See :hg:`help dates` for a list of formats valid for -d/--date.
5740 See :hg:`help dates` for a list of formats valid for -d/--date.
5741
5741
5742 Since tag names have priority over branch names during revision
5742 Since tag names have priority over branch names during revision
5743 lookup, using an existing branch name as a tag name is discouraged.
5743 lookup, using an existing branch name as a tag name is discouraged.
5744
5744
5745 Returns 0 on success.
5745 Returns 0 on success.
5746 """
5746 """
5747 opts = pycompat.byteskwargs(opts)
5747 opts = pycompat.byteskwargs(opts)
5748 with repo.wlock(), repo.lock():
5748 with repo.wlock(), repo.lock():
5749 rev_ = "."
5749 rev_ = "."
5750 names = [t.strip() for t in (name1,) + names]
5750 names = [t.strip() for t in (name1,) + names]
5751 if len(names) != len(set(names)):
5751 if len(names) != len(set(names)):
5752 raise error.Abort(_('tag names must be unique'))
5752 raise error.Abort(_('tag names must be unique'))
5753 for n in names:
5753 for n in names:
5754 scmutil.checknewlabel(repo, n, 'tag')
5754 scmutil.checknewlabel(repo, n, 'tag')
5755 if not n:
5755 if not n:
5756 raise error.Abort(_('tag names cannot consist entirely of '
5756 raise error.Abort(_('tag names cannot consist entirely of '
5757 'whitespace'))
5757 'whitespace'))
5758 if opts.get('rev') and opts.get('remove'):
5758 if opts.get('rev') and opts.get('remove'):
5759 raise error.Abort(_("--rev and --remove are incompatible"))
5759 raise error.Abort(_("--rev and --remove are incompatible"))
5760 if opts.get('rev'):
5760 if opts.get('rev'):
5761 rev_ = opts['rev']
5761 rev_ = opts['rev']
5762 message = opts.get('message')
5762 message = opts.get('message')
5763 if opts.get('remove'):
5763 if opts.get('remove'):
5764 if opts.get('local'):
5764 if opts.get('local'):
5765 expectedtype = 'local'
5765 expectedtype = 'local'
5766 else:
5766 else:
5767 expectedtype = 'global'
5767 expectedtype = 'global'
5768
5768
5769 for n in names:
5769 for n in names:
5770 if not repo.tagtype(n):
5770 if not repo.tagtype(n):
5771 raise error.Abort(_("tag '%s' does not exist") % n)
5771 raise error.Abort(_("tag '%s' does not exist") % n)
5772 if repo.tagtype(n) != expectedtype:
5772 if repo.tagtype(n) != expectedtype:
5773 if expectedtype == 'global':
5773 if expectedtype == 'global':
5774 raise error.Abort(_("tag '%s' is not a global tag") % n)
5774 raise error.Abort(_("tag '%s' is not a global tag") % n)
5775 else:
5775 else:
5776 raise error.Abort(_("tag '%s' is not a local tag") % n)
5776 raise error.Abort(_("tag '%s' is not a local tag") % n)
5777 rev_ = 'null'
5777 rev_ = 'null'
5778 if not message:
5778 if not message:
5779 # we don't translate commit messages
5779 # we don't translate commit messages
5780 message = 'Removed tag %s' % ', '.join(names)
5780 message = 'Removed tag %s' % ', '.join(names)
5781 elif not opts.get('force'):
5781 elif not opts.get('force'):
5782 for n in names:
5782 for n in names:
5783 if n in repo.tags():
5783 if n in repo.tags():
5784 raise error.Abort(_("tag '%s' already exists "
5784 raise error.Abort(_("tag '%s' already exists "
5785 "(use -f to force)") % n)
5785 "(use -f to force)") % n)
5786 if not opts.get('local'):
5786 if not opts.get('local'):
5787 p1, p2 = repo.dirstate.parents()
5787 p1, p2 = repo.dirstate.parents()
5788 if p2 != nullid:
5788 if p2 != nullid:
5789 raise error.Abort(_('uncommitted merge'))
5789 raise error.Abort(_('uncommitted merge'))
5790 bheads = repo.branchheads()
5790 bheads = repo.branchheads()
5791 if not opts.get('force') and bheads and p1 not in bheads:
5791 if not opts.get('force') and bheads and p1 not in bheads:
5792 raise error.Abort(_('working directory is not at a branch head '
5792 raise error.Abort(_('working directory is not at a branch head '
5793 '(use -f to force)'))
5793 '(use -f to force)'))
5794 node = scmutil.revsingle(repo, rev_).node()
5794 node = scmutil.revsingle(repo, rev_).node()
5795
5795
5796 if not message:
5796 if not message:
5797 # we don't translate commit messages
5797 # we don't translate commit messages
5798 message = ('Added tag %s for changeset %s' %
5798 message = ('Added tag %s for changeset %s' %
5799 (', '.join(names), short(node)))
5799 (', '.join(names), short(node)))
5800
5800
5801 date = opts.get('date')
5801 date = opts.get('date')
5802 if date:
5802 if date:
5803 date = dateutil.parsedate(date)
5803 date = dateutil.parsedate(date)
5804
5804
5805 if opts.get('remove'):
5805 if opts.get('remove'):
5806 editform = 'tag.remove'
5806 editform = 'tag.remove'
5807 else:
5807 else:
5808 editform = 'tag.add'
5808 editform = 'tag.add'
5809 editor = cmdutil.getcommiteditor(editform=editform,
5809 editor = cmdutil.getcommiteditor(editform=editform,
5810 **pycompat.strkwargs(opts))
5810 **pycompat.strkwargs(opts))
5811
5811
5812 # don't allow tagging the null rev
5812 # don't allow tagging the null rev
5813 if (not opts.get('remove') and
5813 if (not opts.get('remove') and
5814 scmutil.revsingle(repo, rev_).rev() == nullrev):
5814 scmutil.revsingle(repo, rev_).rev() == nullrev):
5815 raise error.Abort(_("cannot tag null revision"))
5815 raise error.Abort(_("cannot tag null revision"))
5816
5816
5817 tagsmod.tag(repo, names, node, message, opts.get('local'),
5817 tagsmod.tag(repo, names, node, message, opts.get('local'),
5818 opts.get('user'), date, editor=editor)
5818 opts.get('user'), date, editor=editor)
5819
5819
5820 @command(
5820 @command(
5821 'tags', formatteropts, '',
5821 'tags', formatteropts, '',
5822 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5822 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5823 intents={INTENT_READONLY})
5823 intents={INTENT_READONLY})
5824 def tags(ui, repo, **opts):
5824 def tags(ui, repo, **opts):
5825 """list repository tags
5825 """list repository tags
5826
5826
5827 This lists both regular and local tags. When the -v/--verbose
5827 This lists both regular and local tags. When the -v/--verbose
5828 switch is used, a third column "local" is printed for local tags.
5828 switch is used, a third column "local" is printed for local tags.
5829 When the -q/--quiet switch is used, only the tag name is printed.
5829 When the -q/--quiet switch is used, only the tag name is printed.
5830
5830
5831 .. container:: verbose
5831 .. container:: verbose
5832
5832
5833 Template:
5833 Template:
5834
5834
5835 The following keywords are supported in addition to the common template
5835 The following keywords are supported in addition to the common template
5836 keywords and functions such as ``{tag}``. See also
5836 keywords and functions such as ``{tag}``. See also
5837 :hg:`help templates`.
5837 :hg:`help templates`.
5838
5838
5839 :type: String. ``local`` for local tags.
5839 :type: String. ``local`` for local tags.
5840
5840
5841 Returns 0 on success.
5841 Returns 0 on success.
5842 """
5842 """
5843
5843
5844 opts = pycompat.byteskwargs(opts)
5844 opts = pycompat.byteskwargs(opts)
5845 ui.pager('tags')
5845 ui.pager('tags')
5846 fm = ui.formatter('tags', opts)
5846 fm = ui.formatter('tags', opts)
5847 hexfunc = fm.hexfunc
5847 hexfunc = fm.hexfunc
5848 tagtype = ""
5848 tagtype = ""
5849
5849
5850 for t, n in reversed(repo.tagslist()):
5850 for t, n in reversed(repo.tagslist()):
5851 hn = hexfunc(n)
5851 hn = hexfunc(n)
5852 label = 'tags.normal'
5852 label = 'tags.normal'
5853 tagtype = ''
5853 tagtype = ''
5854 if repo.tagtype(t) == 'local':
5854 if repo.tagtype(t) == 'local':
5855 label = 'tags.local'
5855 label = 'tags.local'
5856 tagtype = 'local'
5856 tagtype = 'local'
5857
5857
5858 fm.startitem()
5858 fm.startitem()
5859 fm.context(repo=repo)
5859 fm.context(repo=repo)
5860 fm.write('tag', '%s', t, label=label)
5860 fm.write('tag', '%s', t, label=label)
5861 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5861 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5862 fm.condwrite(not ui.quiet, 'rev node', fmt,
5862 fm.condwrite(not ui.quiet, 'rev node', fmt,
5863 repo.changelog.rev(n), hn, label=label)
5863 repo.changelog.rev(n), hn, label=label)
5864 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5864 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5865 tagtype, label=label)
5865 tagtype, label=label)
5866 fm.plain('\n')
5866 fm.plain('\n')
5867 fm.end()
5867 fm.end()
5868
5868
5869 @command('tip',
5869 @command('tip',
5870 [('p', 'patch', None, _('show patch')),
5870 [('p', 'patch', None, _('show patch')),
5871 ('g', 'git', None, _('use git extended diff format')),
5871 ('g', 'git', None, _('use git extended diff format')),
5872 ] + templateopts,
5872 ] + templateopts,
5873 _('[-p] [-g]'),
5873 _('[-p] [-g]'),
5874 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5874 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5875 def tip(ui, repo, **opts):
5875 def tip(ui, repo, **opts):
5876 """show the tip revision (DEPRECATED)
5876 """show the tip revision (DEPRECATED)
5877
5877
5878 The tip revision (usually just called the tip) is the changeset
5878 The tip revision (usually just called the tip) is the changeset
5879 most recently added to the repository (and therefore the most
5879 most recently added to the repository (and therefore the most
5880 recently changed head).
5880 recently changed head).
5881
5881
5882 If you have just made a commit, that commit will be the tip. If
5882 If you have just made a commit, that commit will be the tip. If
5883 you have just pulled changes from another repository, the tip of
5883 you have just pulled changes from another repository, the tip of
5884 that repository becomes the current tip. The "tip" tag is special
5884 that repository becomes the current tip. The "tip" tag is special
5885 and cannot be renamed or assigned to a different changeset.
5885 and cannot be renamed or assigned to a different changeset.
5886
5886
5887 This command is deprecated, please use :hg:`heads` instead.
5887 This command is deprecated, please use :hg:`heads` instead.
5888
5888
5889 Returns 0 on success.
5889 Returns 0 on success.
5890 """
5890 """
5891 opts = pycompat.byteskwargs(opts)
5891 opts = pycompat.byteskwargs(opts)
5892 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5892 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5893 displayer.show(repo['tip'])
5893 displayer.show(repo['tip'])
5894 displayer.close()
5894 displayer.close()
5895
5895
5896 @command('unbundle',
5896 @command('unbundle',
5897 [('u', 'update', None,
5897 [('u', 'update', None,
5898 _('update to new branch head if changesets were unbundled'))],
5898 _('update to new branch head if changesets were unbundled'))],
5899 _('[-u] FILE...'),
5899 _('[-u] FILE...'),
5900 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5900 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5901 def unbundle(ui, repo, fname1, *fnames, **opts):
5901 def unbundle(ui, repo, fname1, *fnames, **opts):
5902 """apply one or more bundle files
5902 """apply one or more bundle files
5903
5903
5904 Apply one or more bundle files generated by :hg:`bundle`.
5904 Apply one or more bundle files generated by :hg:`bundle`.
5905
5905
5906 Returns 0 on success, 1 if an update has unresolved files.
5906 Returns 0 on success, 1 if an update has unresolved files.
5907 """
5907 """
5908 fnames = (fname1,) + fnames
5908 fnames = (fname1,) + fnames
5909
5909
5910 with repo.lock():
5910 with repo.lock():
5911 for fname in fnames:
5911 for fname in fnames:
5912 f = hg.openpath(ui, fname)
5912 f = hg.openpath(ui, fname)
5913 gen = exchange.readbundle(ui, f, fname)
5913 gen = exchange.readbundle(ui, f, fname)
5914 if isinstance(gen, streamclone.streamcloneapplier):
5914 if isinstance(gen, streamclone.streamcloneapplier):
5915 raise error.Abort(
5915 raise error.Abort(
5916 _('packed bundles cannot be applied with '
5916 _('packed bundles cannot be applied with '
5917 '"hg unbundle"'),
5917 '"hg unbundle"'),
5918 hint=_('use "hg debugapplystreamclonebundle"'))
5918 hint=_('use "hg debugapplystreamclonebundle"'))
5919 url = 'bundle:' + fname
5919 url = 'bundle:' + fname
5920 try:
5920 try:
5921 txnname = 'unbundle'
5921 txnname = 'unbundle'
5922 if not isinstance(gen, bundle2.unbundle20):
5922 if not isinstance(gen, bundle2.unbundle20):
5923 txnname = 'unbundle\n%s' % util.hidepassword(url)
5923 txnname = 'unbundle\n%s' % util.hidepassword(url)
5924 with repo.transaction(txnname) as tr:
5924 with repo.transaction(txnname) as tr:
5925 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5925 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5926 url=url)
5926 url=url)
5927 except error.BundleUnknownFeatureError as exc:
5927 except error.BundleUnknownFeatureError as exc:
5928 raise error.Abort(
5928 raise error.Abort(
5929 _('%s: unknown bundle feature, %s') % (fname, exc),
5929 _('%s: unknown bundle feature, %s') % (fname, exc),
5930 hint=_("see https://mercurial-scm.org/"
5930 hint=_("see https://mercurial-scm.org/"
5931 "wiki/BundleFeature for more "
5931 "wiki/BundleFeature for more "
5932 "information"))
5932 "information"))
5933 modheads = bundle2.combinechangegroupresults(op)
5933 modheads = bundle2.combinechangegroupresults(op)
5934
5934
5935 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5935 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5936
5936
5937 @command('update|up|checkout|co',
5937 @command('update|up|checkout|co',
5938 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5938 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5939 ('c', 'check', None, _('require clean working directory')),
5939 ('c', 'check', None, _('require clean working directory')),
5940 ('m', 'merge', None, _('merge uncommitted changes')),
5940 ('m', 'merge', None, _('merge uncommitted changes')),
5941 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5941 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5942 ('r', 'rev', '', _('revision'), _('REV'))
5942 ('r', 'rev', '', _('revision'), _('REV'))
5943 ] + mergetoolopts,
5943 ] + mergetoolopts,
5944 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5944 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5945 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5945 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5946 helpbasic=True)
5946 helpbasic=True)
5947 def update(ui, repo, node=None, **opts):
5947 def update(ui, repo, node=None, **opts):
5948 """update working directory (or switch revisions)
5948 """update working directory (or switch revisions)
5949
5949
5950 Update the repository's working directory to the specified
5950 Update the repository's working directory to the specified
5951 changeset. If no changeset is specified, update to the tip of the
5951 changeset. If no changeset is specified, update to the tip of the
5952 current named branch and move the active bookmark (see :hg:`help
5952 current named branch and move the active bookmark (see :hg:`help
5953 bookmarks`).
5953 bookmarks`).
5954
5954
5955 Update sets the working directory's parent revision to the specified
5955 Update sets the working directory's parent revision to the specified
5956 changeset (see :hg:`help parents`).
5956 changeset (see :hg:`help parents`).
5957
5957
5958 If the changeset is not a descendant or ancestor of the working
5958 If the changeset is not a descendant or ancestor of the working
5959 directory's parent and there are uncommitted changes, the update is
5959 directory's parent and there are uncommitted changes, the update is
5960 aborted. With the -c/--check option, the working directory is checked
5960 aborted. With the -c/--check option, the working directory is checked
5961 for uncommitted changes; if none are found, the working directory is
5961 for uncommitted changes; if none are found, the working directory is
5962 updated to the specified changeset.
5962 updated to the specified changeset.
5963
5963
5964 .. container:: verbose
5964 .. container:: verbose
5965
5965
5966 The -C/--clean, -c/--check, and -m/--merge options control what
5966 The -C/--clean, -c/--check, and -m/--merge options control what
5967 happens if the working directory contains uncommitted changes.
5967 happens if the working directory contains uncommitted changes.
5968 At most of one of them can be specified.
5968 At most of one of them can be specified.
5969
5969
5970 1. If no option is specified, and if
5970 1. If no option is specified, and if
5971 the requested changeset is an ancestor or descendant of
5971 the requested changeset is an ancestor or descendant of
5972 the working directory's parent, the uncommitted changes
5972 the working directory's parent, the uncommitted changes
5973 are merged into the requested changeset and the merged
5973 are merged into the requested changeset and the merged
5974 result is left uncommitted. If the requested changeset is
5974 result is left uncommitted. If the requested changeset is
5975 not an ancestor or descendant (that is, it is on another
5975 not an ancestor or descendant (that is, it is on another
5976 branch), the update is aborted and the uncommitted changes
5976 branch), the update is aborted and the uncommitted changes
5977 are preserved.
5977 are preserved.
5978
5978
5979 2. With the -m/--merge option, the update is allowed even if the
5979 2. With the -m/--merge option, the update is allowed even if the
5980 requested changeset is not an ancestor or descendant of
5980 requested changeset is not an ancestor or descendant of
5981 the working directory's parent.
5981 the working directory's parent.
5982
5982
5983 3. With the -c/--check option, the update is aborted and the
5983 3. With the -c/--check option, the update is aborted and the
5984 uncommitted changes are preserved.
5984 uncommitted changes are preserved.
5985
5985
5986 4. With the -C/--clean option, uncommitted changes are discarded and
5986 4. With the -C/--clean option, uncommitted changes are discarded and
5987 the working directory is updated to the requested changeset.
5987 the working directory is updated to the requested changeset.
5988
5988
5989 To cancel an uncommitted merge (and lose your changes), use
5989 To cancel an uncommitted merge (and lose your changes), use
5990 :hg:`merge --abort`.
5990 :hg:`merge --abort`.
5991
5991
5992 Use null as the changeset to remove the working directory (like
5992 Use null as the changeset to remove the working directory (like
5993 :hg:`clone -U`).
5993 :hg:`clone -U`).
5994
5994
5995 If you want to revert just one file to an older revision, use
5995 If you want to revert just one file to an older revision, use
5996 :hg:`revert [-r REV] NAME`.
5996 :hg:`revert [-r REV] NAME`.
5997
5997
5998 See :hg:`help dates` for a list of formats valid for -d/--date.
5998 See :hg:`help dates` for a list of formats valid for -d/--date.
5999
5999
6000 Returns 0 on success, 1 if there are unresolved files.
6000 Returns 0 on success, 1 if there are unresolved files.
6001 """
6001 """
6002 rev = opts.get(r'rev')
6002 rev = opts.get(r'rev')
6003 date = opts.get(r'date')
6003 date = opts.get(r'date')
6004 clean = opts.get(r'clean')
6004 clean = opts.get(r'clean')
6005 check = opts.get(r'check')
6005 check = opts.get(r'check')
6006 merge = opts.get(r'merge')
6006 merge = opts.get(r'merge')
6007 if rev and node:
6007 if rev and node:
6008 raise error.Abort(_("please specify just one revision"))
6008 raise error.Abort(_("please specify just one revision"))
6009
6009
6010 if ui.configbool('commands', 'update.requiredest'):
6010 if ui.configbool('commands', 'update.requiredest'):
6011 if not node and not rev and not date:
6011 if not node and not rev and not date:
6012 raise error.Abort(_('you must specify a destination'),
6012 raise error.Abort(_('you must specify a destination'),
6013 hint=_('for example: hg update ".::"'))
6013 hint=_('for example: hg update ".::"'))
6014
6014
6015 if rev is None or rev == '':
6015 if rev is None or rev == '':
6016 rev = node
6016 rev = node
6017
6017
6018 if date and rev is not None:
6018 if date and rev is not None:
6019 raise error.Abort(_("you can't specify a revision and a date"))
6019 raise error.Abort(_("you can't specify a revision and a date"))
6020
6020
6021 if len([x for x in (clean, check, merge) if x]) > 1:
6021 if len([x for x in (clean, check, merge) if x]) > 1:
6022 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6022 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6023 "or -m/--merge"))
6023 "or -m/--merge"))
6024
6024
6025 updatecheck = None
6025 updatecheck = None
6026 if check:
6026 if check:
6027 updatecheck = 'abort'
6027 updatecheck = 'abort'
6028 elif merge:
6028 elif merge:
6029 updatecheck = 'none'
6029 updatecheck = 'none'
6030
6030
6031 with repo.wlock():
6031 with repo.wlock():
6032 cmdutil.clearunfinished(repo)
6032 cmdutil.clearunfinished(repo)
6033
6033
6034 if date:
6034 if date:
6035 rev = cmdutil.finddate(ui, repo, date)
6035 rev = cmdutil.finddate(ui, repo, date)
6036
6036
6037 # if we defined a bookmark, we have to remember the original name
6037 # if we defined a bookmark, we have to remember the original name
6038 brev = rev
6038 brev = rev
6039 if rev:
6039 if rev:
6040 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6040 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6041 ctx = scmutil.revsingle(repo, rev, rev)
6041 ctx = scmutil.revsingle(repo, rev, default=None)
6042 rev = ctx.rev()
6042 rev = ctx.rev()
6043 hidden = ctx.hidden()
6043 hidden = ctx.hidden()
6044 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6044 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6045 with ui.configoverride(overrides, 'update'):
6045 with ui.configoverride(overrides, 'update'):
6046 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6046 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6047 updatecheck=updatecheck)
6047 updatecheck=updatecheck)
6048 if hidden:
6048 if hidden:
6049 ctxstr = ctx.hex()[:12]
6049 ctxstr = ctx.hex()[:12]
6050 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6050 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6051
6051
6052 if ctx.obsolete():
6052 if ctx.obsolete():
6053 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6053 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6054 ui.warn("(%s)\n" % obsfatemsg)
6054 ui.warn("(%s)\n" % obsfatemsg)
6055 return ret
6055 return ret
6056
6056
6057 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6057 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6058 def verify(ui, repo):
6058 def verify(ui, repo):
6059 """verify the integrity of the repository
6059 """verify the integrity of the repository
6060
6060
6061 Verify the integrity of the current repository.
6061 Verify the integrity of the current repository.
6062
6062
6063 This will perform an extensive check of the repository's
6063 This will perform an extensive check of the repository's
6064 integrity, validating the hashes and checksums of each entry in
6064 integrity, validating the hashes and checksums of each entry in
6065 the changelog, manifest, and tracked files, as well as the
6065 the changelog, manifest, and tracked files, as well as the
6066 integrity of their crosslinks and indices.
6066 integrity of their crosslinks and indices.
6067
6067
6068 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6068 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6069 for more information about recovery from corruption of the
6069 for more information about recovery from corruption of the
6070 repository.
6070 repository.
6071
6071
6072 Returns 0 on success, 1 if errors are encountered.
6072 Returns 0 on success, 1 if errors are encountered.
6073 """
6073 """
6074 return hg.verify(repo)
6074 return hg.verify(repo)
6075
6075
6076 @command(
6076 @command(
6077 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6077 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6078 norepo=True, intents={INTENT_READONLY})
6078 norepo=True, intents={INTENT_READONLY})
6079 def version_(ui, **opts):
6079 def version_(ui, **opts):
6080 """output version and copyright information
6080 """output version and copyright information
6081
6081
6082 .. container:: verbose
6082 .. container:: verbose
6083
6083
6084 Template:
6084 Template:
6085
6085
6086 The following keywords are supported. See also :hg:`help templates`.
6086 The following keywords are supported. See also :hg:`help templates`.
6087
6087
6088 :extensions: List of extensions.
6088 :extensions: List of extensions.
6089 :ver: String. Version number.
6089 :ver: String. Version number.
6090
6090
6091 And each entry of ``{extensions}`` provides the following sub-keywords
6091 And each entry of ``{extensions}`` provides the following sub-keywords
6092 in addition to ``{ver}``.
6092 in addition to ``{ver}``.
6093
6093
6094 :bundled: Boolean. True if included in the release.
6094 :bundled: Boolean. True if included in the release.
6095 :name: String. Extension name.
6095 :name: String. Extension name.
6096 """
6096 """
6097 opts = pycompat.byteskwargs(opts)
6097 opts = pycompat.byteskwargs(opts)
6098 if ui.verbose:
6098 if ui.verbose:
6099 ui.pager('version')
6099 ui.pager('version')
6100 fm = ui.formatter("version", opts)
6100 fm = ui.formatter("version", opts)
6101 fm.startitem()
6101 fm.startitem()
6102 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6102 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6103 util.version())
6103 util.version())
6104 license = _(
6104 license = _(
6105 "(see https://mercurial-scm.org for more information)\n"
6105 "(see https://mercurial-scm.org for more information)\n"
6106 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6106 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6107 "This is free software; see the source for copying conditions. "
6107 "This is free software; see the source for copying conditions. "
6108 "There is NO\nwarranty; "
6108 "There is NO\nwarranty; "
6109 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6109 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6110 )
6110 )
6111 if not ui.quiet:
6111 if not ui.quiet:
6112 fm.plain(license)
6112 fm.plain(license)
6113
6113
6114 if ui.verbose:
6114 if ui.verbose:
6115 fm.plain(_("\nEnabled extensions:\n\n"))
6115 fm.plain(_("\nEnabled extensions:\n\n"))
6116 # format names and versions into columns
6116 # format names and versions into columns
6117 names = []
6117 names = []
6118 vers = []
6118 vers = []
6119 isinternals = []
6119 isinternals = []
6120 for name, module in extensions.extensions():
6120 for name, module in extensions.extensions():
6121 names.append(name)
6121 names.append(name)
6122 vers.append(extensions.moduleversion(module) or None)
6122 vers.append(extensions.moduleversion(module) or None)
6123 isinternals.append(extensions.ismoduleinternal(module))
6123 isinternals.append(extensions.ismoduleinternal(module))
6124 fn = fm.nested("extensions", tmpl='{name}\n')
6124 fn = fm.nested("extensions", tmpl='{name}\n')
6125 if names:
6125 if names:
6126 namefmt = " %%-%ds " % max(len(n) for n in names)
6126 namefmt = " %%-%ds " % max(len(n) for n in names)
6127 places = [_("external"), _("internal")]
6127 places = [_("external"), _("internal")]
6128 for n, v, p in zip(names, vers, isinternals):
6128 for n, v, p in zip(names, vers, isinternals):
6129 fn.startitem()
6129 fn.startitem()
6130 fn.condwrite(ui.verbose, "name", namefmt, n)
6130 fn.condwrite(ui.verbose, "name", namefmt, n)
6131 if ui.verbose:
6131 if ui.verbose:
6132 fn.plain("%s " % places[p])
6132 fn.plain("%s " % places[p])
6133 fn.data(bundled=p)
6133 fn.data(bundled=p)
6134 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6134 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6135 if ui.verbose:
6135 if ui.verbose:
6136 fn.plain("\n")
6136 fn.plain("\n")
6137 fn.end()
6137 fn.end()
6138 fm.end()
6138 fm.end()
6139
6139
6140 def loadcmdtable(ui, name, cmdtable):
6140 def loadcmdtable(ui, name, cmdtable):
6141 """Load command functions from specified cmdtable
6141 """Load command functions from specified cmdtable
6142 """
6142 """
6143 cmdtable = cmdtable.copy()
6143 cmdtable = cmdtable.copy()
6144 for cmd in list(cmdtable):
6144 for cmd in list(cmdtable):
6145 if not cmd.startswith('^'):
6145 if not cmd.startswith('^'):
6146 continue
6146 continue
6147 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6147 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6148 % (cmd, name), '4.8')
6148 % (cmd, name), '4.8')
6149 entry = cmdtable.pop(cmd)
6149 entry = cmdtable.pop(cmd)
6150 entry[0].helpbasic = True
6150 entry[0].helpbasic = True
6151 cmdtable[cmd[1:]] = entry
6151 cmdtable[cmd[1:]] = entry
6152
6152
6153 overrides = [cmd for cmd in cmdtable if cmd in table]
6153 overrides = [cmd for cmd in cmdtable if cmd in table]
6154 if overrides:
6154 if overrides:
6155 ui.warn(_("extension '%s' overrides commands: %s\n")
6155 ui.warn(_("extension '%s' overrides commands: %s\n")
6156 % (name, " ".join(overrides)))
6156 % (name, " ".join(overrides)))
6157 table.update(cmdtable)
6157 table.update(cmdtable)
@@ -1,95 +1,115 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3 $ echo foo>foo
3 $ echo foo>foo
4 $ hg addremove
4 $ hg addremove
5 adding foo
5 adding foo
6 $ hg commit -m "1"
6 $ hg commit -m "1"
7
7
8 $ hg verify
8 $ hg verify
9 checking changesets
9 checking changesets
10 checking manifests
10 checking manifests
11 crosschecking files in changesets and manifests
11 crosschecking files in changesets and manifests
12 checking files
12 checking files
13 checked 1 changesets with 1 changes to 1 files
13 checked 1 changesets with 1 changes to 1 files
14
14
15 $ hg clone . ../branch
15 $ hg clone . ../branch
16 updating to branch default
16 updating to branch default
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 $ cd ../branch
18 $ cd ../branch
19 $ hg co
19 $ hg co
20 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 $ echo bar>>foo
21 $ echo bar>>foo
22 $ hg commit -m "2"
22 $ hg commit -m "2"
23
23
24 $ cd ../test
24 $ cd ../test
25
25
26 $ hg pull ../branch
26 $ hg pull ../branch
27 pulling from ../branch
27 pulling from ../branch
28 searching for changes
28 searching for changes
29 adding changesets
29 adding changesets
30 adding manifests
30 adding manifests
31 adding file changes
31 adding file changes
32 added 1 changesets with 1 changes to 1 files
32 added 1 changesets with 1 changes to 1 files
33 new changesets 30aff43faee1
33 new changesets 30aff43faee1
34 1 local changesets published
34 1 local changesets published
35 (run 'hg update' to get a working copy)
35 (run 'hg update' to get a working copy)
36
36
37 $ hg verify
37 $ hg verify
38 checking changesets
38 checking changesets
39 checking manifests
39 checking manifests
40 crosschecking files in changesets and manifests
40 crosschecking files in changesets and manifests
41 checking files
41 checking files
42 checked 2 changesets with 2 changes to 1 files
42 checked 2 changesets with 2 changes to 1 files
43
43
44 $ hg co
44 $ hg co
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46
46
47 $ cat foo
47 $ cat foo
48 foo
48 foo
49 bar
49 bar
50
50
51 $ hg manifest --debug
51 $ hg manifest --debug
52 6f4310b00b9a147241b071a60c28a650827fb03d 644 foo
52 6f4310b00b9a147241b071a60c28a650827fb03d 644 foo
53
53
54 update to rev 0 with a date
54 update to rev 0 with a date
55
55
56 $ hg upd -d foo 0
56 $ hg upd -d foo 0
57 abort: you can't specify a revision and a date
57 abort: you can't specify a revision and a date
58 [255]
58 [255]
59
59
60 update to default destination (with empty revspec)
61
62 $ hg update -q null
63 $ hg update
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ hg id
66 30aff43faee1 tip
67
68 $ hg update -q null
69 $ hg update -r ''
70 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 $ hg id
72 30aff43faee1 tip
73
74 $ hg update -q null
75 $ hg update ''
76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 $ hg id
78 30aff43faee1 tip
79
60 $ cd ..
80 $ cd ..
61
81
62 update with worker processes
82 update with worker processes
63
83
64 #if no-windows
84 #if no-windows
65
85
66 $ cat <<EOF > forceworker.py
86 $ cat <<EOF > forceworker.py
67 > from mercurial import extensions, worker
87 > from mercurial import extensions, worker
68 > def nocost(orig, ui, costperop, nops, threadsafe=True):
88 > def nocost(orig, ui, costperop, nops, threadsafe=True):
69 > return worker._numworkers(ui) > 1
89 > return worker._numworkers(ui) > 1
70 > def uisetup(ui):
90 > def uisetup(ui):
71 > extensions.wrapfunction(worker, 'worthwhile', nocost)
91 > extensions.wrapfunction(worker, 'worthwhile', nocost)
72 > EOF
92 > EOF
73
93
74 $ hg init worker
94 $ hg init worker
75 $ cd worker
95 $ cd worker
76 $ cat <<EOF >> .hg/hgrc
96 $ cat <<EOF >> .hg/hgrc
77 > [extensions]
97 > [extensions]
78 > forceworker = $TESTTMP/forceworker.py
98 > forceworker = $TESTTMP/forceworker.py
79 > [worker]
99 > [worker]
80 > numcpus = 4
100 > numcpus = 4
81 > EOF
101 > EOF
82 $ for i in `"$PYTHON" $TESTDIR/seq.py 1 100`; do
102 $ for i in `"$PYTHON" $TESTDIR/seq.py 1 100`; do
83 > echo $i > $i
103 > echo $i > $i
84 > done
104 > done
85 $ hg ci -qAm 'add 100 files'
105 $ hg ci -qAm 'add 100 files'
86
106
87 $ hg update null
107 $ hg update null
88 0 files updated, 0 files merged, 100 files removed, 0 files unresolved
108 0 files updated, 0 files merged, 100 files removed, 0 files unresolved
89 $ hg update -v | grep 100
109 $ hg update -v | grep 100
90 getting 100
110 getting 100
91 100 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 100 files updated, 0 files merged, 0 files removed, 0 files unresolved
92
112
93 $ cd ..
113 $ cd ..
94
114
95 #endif
115 #endif
General Comments 0
You need to be logged in to leave comments. Login now