##// END OF EJS Templates
grep: give different labels to + and - symbols...
Jordi Gutiérrez Hermoso -
r41886:8ab42ccb default
parent child Browse files
Show More
@@ -1,6234 +1,6238 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 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
183 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
184 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
184 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
185 return rejected and 1 or 0
185 return rejected and 1 or 0
186
186
187 @command('addremove',
187 @command('addremove',
188 similarityopts + subrepoopts + walkopts + dryrunopts,
188 similarityopts + subrepoopts + walkopts + dryrunopts,
189 _('[OPTION]... [FILE]...'),
189 _('[OPTION]... [FILE]...'),
190 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
190 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
191 inferrepo=True)
191 inferrepo=True)
192 def addremove(ui, repo, *pats, **opts):
192 def addremove(ui, repo, *pats, **opts):
193 """add all new files, delete all missing files
193 """add all new files, delete all missing files
194
194
195 Add all new files and remove all missing files from the
195 Add all new files and remove all missing files from the
196 repository.
196 repository.
197
197
198 Unless names are given, new files are ignored if they match any of
198 Unless names are given, new files are ignored if they match any of
199 the patterns in ``.hgignore``. As with add, these changes take
199 the patterns in ``.hgignore``. As with add, these changes take
200 effect at the next commit.
200 effect at the next commit.
201
201
202 Use the -s/--similarity option to detect renamed files. This
202 Use the -s/--similarity option to detect renamed files. This
203 option takes a percentage between 0 (disabled) and 100 (files must
203 option takes a percentage between 0 (disabled) and 100 (files must
204 be identical) as its parameter. With a parameter greater than 0,
204 be identical) as its parameter. With a parameter greater than 0,
205 this compares every removed file with every added file and records
205 this compares every removed file with every added file and records
206 those similar enough as renames. Detecting renamed files this way
206 those similar enough as renames. Detecting renamed files this way
207 can be expensive. After using this option, :hg:`status -C` can be
207 can be expensive. After using this option, :hg:`status -C` can be
208 used to check which files were identified as moved or renamed. If
208 used to check which files were identified as moved or renamed. If
209 not specified, -s/--similarity defaults to 100 and only renames of
209 not specified, -s/--similarity defaults to 100 and only renames of
210 identical files are detected.
210 identical files are detected.
211
211
212 .. container:: verbose
212 .. container:: verbose
213
213
214 Examples:
214 Examples:
215
215
216 - A number of files (bar.c and foo.c) are new,
216 - A number of files (bar.c and foo.c) are new,
217 while foobar.c has been removed (without using :hg:`remove`)
217 while foobar.c has been removed (without using :hg:`remove`)
218 from the repository::
218 from the repository::
219
219
220 $ ls
220 $ ls
221 bar.c foo.c
221 bar.c foo.c
222 $ hg status
222 $ hg status
223 ! foobar.c
223 ! foobar.c
224 ? bar.c
224 ? bar.c
225 ? foo.c
225 ? foo.c
226 $ hg addremove
226 $ hg addremove
227 adding bar.c
227 adding bar.c
228 adding foo.c
228 adding foo.c
229 removing foobar.c
229 removing foobar.c
230 $ hg status
230 $ hg status
231 A bar.c
231 A bar.c
232 A foo.c
232 A foo.c
233 R foobar.c
233 R foobar.c
234
234
235 - A file foobar.c was moved to foo.c without using :hg:`rename`.
235 - A file foobar.c was moved to foo.c without using :hg:`rename`.
236 Afterwards, it was edited slightly::
236 Afterwards, it was edited slightly::
237
237
238 $ ls
238 $ ls
239 foo.c
239 foo.c
240 $ hg status
240 $ hg status
241 ! foobar.c
241 ! foobar.c
242 ? foo.c
242 ? foo.c
243 $ hg addremove --similarity 90
243 $ hg addremove --similarity 90
244 removing foobar.c
244 removing foobar.c
245 adding foo.c
245 adding foo.c
246 recording removal of foobar.c as rename to foo.c (94% similar)
246 recording removal of foobar.c as rename to foo.c (94% similar)
247 $ hg status -C
247 $ hg status -C
248 A foo.c
248 A foo.c
249 foobar.c
249 foobar.c
250 R foobar.c
250 R foobar.c
251
251
252 Returns 0 if all files are successfully added.
252 Returns 0 if all files are successfully added.
253 """
253 """
254 opts = pycompat.byteskwargs(opts)
254 opts = pycompat.byteskwargs(opts)
255 if not opts.get('similarity'):
255 if not opts.get('similarity'):
256 opts['similarity'] = '100'
256 opts['similarity'] = '100'
257 matcher = scmutil.match(repo[None], pats, opts)
257 matcher = scmutil.match(repo[None], pats, opts)
258 relative = scmutil.anypats(pats, opts)
258 relative = scmutil.anypats(pats, opts)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
260 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
260 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
261
261
262 @command('annotate|blame',
262 @command('annotate|blame',
263 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
263 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
264 ('', 'follow', None,
264 ('', 'follow', None,
265 _('follow copies/renames and list the filename (DEPRECATED)')),
265 _('follow copies/renames and list the filename (DEPRECATED)')),
266 ('', 'no-follow', None, _("don't follow copies and renames")),
266 ('', 'no-follow', None, _("don't follow copies and renames")),
267 ('a', 'text', None, _('treat all files as text')),
267 ('a', 'text', None, _('treat all files as text')),
268 ('u', 'user', None, _('list the author (long with -v)')),
268 ('u', 'user', None, _('list the author (long with -v)')),
269 ('f', 'file', None, _('list the filename')),
269 ('f', 'file', None, _('list the filename')),
270 ('d', 'date', None, _('list the date (short with -q)')),
270 ('d', 'date', None, _('list the date (short with -q)')),
271 ('n', 'number', None, _('list the revision number (default)')),
271 ('n', 'number', None, _('list the revision number (default)')),
272 ('c', 'changeset', None, _('list the changeset')),
272 ('c', 'changeset', None, _('list the changeset')),
273 ('l', 'line-number', None, _('show line number at the first appearance')),
273 ('l', 'line-number', None, _('show line number at the first appearance')),
274 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
274 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
275 ] + diffwsopts + walkopts + formatteropts,
275 ] + diffwsopts + walkopts + formatteropts,
276 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
276 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
277 helpcategory=command.CATEGORY_FILE_CONTENTS,
277 helpcategory=command.CATEGORY_FILE_CONTENTS,
278 helpbasic=True, inferrepo=True)
278 helpbasic=True, inferrepo=True)
279 def annotate(ui, repo, *pats, **opts):
279 def annotate(ui, repo, *pats, **opts):
280 """show changeset information by line for each file
280 """show changeset information by line for each file
281
281
282 List changes in files, showing the revision id responsible for
282 List changes in files, showing the revision id responsible for
283 each line.
283 each line.
284
284
285 This command is useful for discovering when a change was made and
285 This command is useful for discovering when a change was made and
286 by whom.
286 by whom.
287
287
288 If you include --file, --user, or --date, the revision number is
288 If you include --file, --user, or --date, the revision number is
289 suppressed unless you also include --number.
289 suppressed unless you also include --number.
290
290
291 Without the -a/--text option, annotate will avoid processing files
291 Without the -a/--text option, annotate will avoid processing files
292 it detects as binary. With -a, annotate will annotate the file
292 it detects as binary. With -a, annotate will annotate the file
293 anyway, although the results will probably be neither useful
293 anyway, although the results will probably be neither useful
294 nor desirable.
294 nor desirable.
295
295
296 .. container:: verbose
296 .. container:: verbose
297
297
298 Template:
298 Template:
299
299
300 The following keywords are supported in addition to the common template
300 The following keywords are supported in addition to the common template
301 keywords and functions. See also :hg:`help templates`.
301 keywords and functions. See also :hg:`help templates`.
302
302
303 :lines: List of lines with annotation data.
303 :lines: List of lines with annotation data.
304 :path: String. Repository-absolute path of the specified file.
304 :path: String. Repository-absolute path of the specified file.
305
305
306 And each entry of ``{lines}`` provides the following sub-keywords in
306 And each entry of ``{lines}`` provides the following sub-keywords in
307 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
307 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
308
308
309 :line: String. Line content.
309 :line: String. Line content.
310 :lineno: Integer. Line number at that revision.
310 :lineno: Integer. Line number at that revision.
311 :path: String. Repository-absolute path of the file at that revision.
311 :path: String. Repository-absolute path of the file at that revision.
312
312
313 See :hg:`help templates.operators` for the list expansion syntax.
313 See :hg:`help templates.operators` for the list expansion syntax.
314
314
315 Returns 0 on success.
315 Returns 0 on success.
316 """
316 """
317 opts = pycompat.byteskwargs(opts)
317 opts = pycompat.byteskwargs(opts)
318 if not pats:
318 if not pats:
319 raise error.Abort(_('at least one filename or pattern is required'))
319 raise error.Abort(_('at least one filename or pattern is required'))
320
320
321 if opts.get('follow'):
321 if opts.get('follow'):
322 # --follow is deprecated and now just an alias for -f/--file
322 # --follow is deprecated and now just an alias for -f/--file
323 # to mimic the behavior of Mercurial before version 1.5
323 # to mimic the behavior of Mercurial before version 1.5
324 opts['file'] = True
324 opts['file'] = True
325
325
326 if (not opts.get('user') and not opts.get('changeset')
326 if (not opts.get('user') and not opts.get('changeset')
327 and not opts.get('date') and not opts.get('file')):
327 and not opts.get('date') and not opts.get('file')):
328 opts['number'] = True
328 opts['number'] = True
329
329
330 linenumber = opts.get('line_number') is not None
330 linenumber = opts.get('line_number') is not None
331 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
331 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
332 raise error.Abort(_('at least one of -n/-c is required for -l'))
332 raise error.Abort(_('at least one of -n/-c is required for -l'))
333
333
334 rev = opts.get('rev')
334 rev = opts.get('rev')
335 if rev:
335 if rev:
336 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
336 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
337 ctx = scmutil.revsingle(repo, rev)
337 ctx = scmutil.revsingle(repo, rev)
338
338
339 ui.pager('annotate')
339 ui.pager('annotate')
340 rootfm = ui.formatter('annotate', opts)
340 rootfm = ui.formatter('annotate', opts)
341 if ui.debugflag:
341 if ui.debugflag:
342 shorthex = pycompat.identity
342 shorthex = pycompat.identity
343 else:
343 else:
344 def shorthex(h):
344 def shorthex(h):
345 return h[:12]
345 return h[:12]
346 if ui.quiet:
346 if ui.quiet:
347 datefunc = dateutil.shortdate
347 datefunc = dateutil.shortdate
348 else:
348 else:
349 datefunc = dateutil.datestr
349 datefunc = dateutil.datestr
350 if ctx.rev() is None:
350 if ctx.rev() is None:
351 if opts.get('changeset'):
351 if opts.get('changeset'):
352 # omit "+" suffix which is appended to node hex
352 # omit "+" suffix which is appended to node hex
353 def formatrev(rev):
353 def formatrev(rev):
354 if rev == wdirrev:
354 if rev == wdirrev:
355 return '%d' % ctx.p1().rev()
355 return '%d' % ctx.p1().rev()
356 else:
356 else:
357 return '%d' % rev
357 return '%d' % rev
358 else:
358 else:
359 def formatrev(rev):
359 def formatrev(rev):
360 if rev == wdirrev:
360 if rev == wdirrev:
361 return '%d+' % ctx.p1().rev()
361 return '%d+' % ctx.p1().rev()
362 else:
362 else:
363 return '%d ' % rev
363 return '%d ' % rev
364 def formathex(h):
364 def formathex(h):
365 if h == wdirhex:
365 if h == wdirhex:
366 return '%s+' % shorthex(hex(ctx.p1().node()))
366 return '%s+' % shorthex(hex(ctx.p1().node()))
367 else:
367 else:
368 return '%s ' % shorthex(h)
368 return '%s ' % shorthex(h)
369 else:
369 else:
370 formatrev = b'%d'.__mod__
370 formatrev = b'%d'.__mod__
371 formathex = shorthex
371 formathex = shorthex
372
372
373 opmap = [
373 opmap = [
374 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
374 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
375 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
375 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
376 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
376 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
377 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
377 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
378 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
378 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
379 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
379 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
380 ]
380 ]
381 opnamemap = {
381 opnamemap = {
382 'rev': 'number',
382 'rev': 'number',
383 'node': 'changeset',
383 'node': 'changeset',
384 'path': 'file',
384 'path': 'file',
385 'lineno': 'line_number',
385 'lineno': 'line_number',
386 }
386 }
387
387
388 if rootfm.isplain():
388 if rootfm.isplain():
389 def makefunc(get, fmt):
389 def makefunc(get, fmt):
390 return lambda x: fmt(get(x))
390 return lambda x: fmt(get(x))
391 else:
391 else:
392 def makefunc(get, fmt):
392 def makefunc(get, fmt):
393 return get
393 return get
394 datahint = rootfm.datahint()
394 datahint = rootfm.datahint()
395 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
395 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
397 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
397 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
398 fields = ' '.join(fn for fn, sep, get, fmt in opmap
398 fields = ' '.join(fn for fn, sep, get, fmt in opmap
399 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
399 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
400
400
401 def bad(x, y):
401 def bad(x, y):
402 raise error.Abort("%s: %s" % (x, y))
402 raise error.Abort("%s: %s" % (x, y))
403
403
404 m = scmutil.match(ctx, pats, opts, badfn=bad)
404 m = scmutil.match(ctx, pats, opts, badfn=bad)
405
405
406 follow = not opts.get('no_follow')
406 follow = not opts.get('no_follow')
407 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
407 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
408 whitespace=True)
408 whitespace=True)
409 skiprevs = opts.get('skip')
409 skiprevs = opts.get('skip')
410 if skiprevs:
410 if skiprevs:
411 skiprevs = scmutil.revrange(repo, skiprevs)
411 skiprevs = scmutil.revrange(repo, skiprevs)
412
412
413 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
413 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
414 for abs in ctx.walk(m):
414 for abs in ctx.walk(m):
415 fctx = ctx[abs]
415 fctx = ctx[abs]
416 rootfm.startitem()
416 rootfm.startitem()
417 rootfm.data(path=abs)
417 rootfm.data(path=abs)
418 if not opts.get('text') and fctx.isbinary():
418 if not opts.get('text') and fctx.isbinary():
419 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
419 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
420 continue
420 continue
421
421
422 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
422 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
423 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
423 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
424 diffopts=diffopts)
424 diffopts=diffopts)
425 if not lines:
425 if not lines:
426 fm.end()
426 fm.end()
427 continue
427 continue
428 formats = []
428 formats = []
429 pieces = []
429 pieces = []
430
430
431 for f, sep in funcmap:
431 for f, sep in funcmap:
432 l = [f(n) for n in lines]
432 l = [f(n) for n in lines]
433 if fm.isplain():
433 if fm.isplain():
434 sizes = [encoding.colwidth(x) for x in l]
434 sizes = [encoding.colwidth(x) for x in l]
435 ml = max(sizes)
435 ml = max(sizes)
436 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
436 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
437 else:
437 else:
438 formats.append(['%s' for x in l])
438 formats.append(['%s' for x in l])
439 pieces.append(l)
439 pieces.append(l)
440
440
441 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
441 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
442 fm.startitem()
442 fm.startitem()
443 fm.context(fctx=n.fctx)
443 fm.context(fctx=n.fctx)
444 fm.write(fields, "".join(f), *p)
444 fm.write(fields, "".join(f), *p)
445 if n.skip:
445 if n.skip:
446 fmt = "* %s"
446 fmt = "* %s"
447 else:
447 else:
448 fmt = ": %s"
448 fmt = ": %s"
449 fm.write('line', fmt, n.text)
449 fm.write('line', fmt, n.text)
450
450
451 if not lines[-1].text.endswith('\n'):
451 if not lines[-1].text.endswith('\n'):
452 fm.plain('\n')
452 fm.plain('\n')
453 fm.end()
453 fm.end()
454
454
455 rootfm.end()
455 rootfm.end()
456
456
457 @command('archive',
457 @command('archive',
458 [('', 'no-decode', None, _('do not pass files through decoders')),
458 [('', 'no-decode', None, _('do not pass files through decoders')),
459 ('p', 'prefix', '', _('directory prefix for files in archive'),
459 ('p', 'prefix', '', _('directory prefix for files in archive'),
460 _('PREFIX')),
460 _('PREFIX')),
461 ('r', 'rev', '', _('revision to distribute'), _('REV')),
461 ('r', 'rev', '', _('revision to distribute'), _('REV')),
462 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
462 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
463 ] + subrepoopts + walkopts,
463 ] + subrepoopts + walkopts,
464 _('[OPTION]... DEST'),
464 _('[OPTION]... DEST'),
465 helpcategory=command.CATEGORY_IMPORT_EXPORT)
465 helpcategory=command.CATEGORY_IMPORT_EXPORT)
466 def archive(ui, repo, dest, **opts):
466 def archive(ui, repo, dest, **opts):
467 '''create an unversioned archive of a repository revision
467 '''create an unversioned archive of a repository revision
468
468
469 By default, the revision used is the parent of the working
469 By default, the revision used is the parent of the working
470 directory; use -r/--rev to specify a different revision.
470 directory; use -r/--rev to specify a different revision.
471
471
472 The archive type is automatically detected based on file
472 The archive type is automatically detected based on file
473 extension (to override, use -t/--type).
473 extension (to override, use -t/--type).
474
474
475 .. container:: verbose
475 .. container:: verbose
476
476
477 Examples:
477 Examples:
478
478
479 - create a zip file containing the 1.0 release::
479 - create a zip file containing the 1.0 release::
480
480
481 hg archive -r 1.0 project-1.0.zip
481 hg archive -r 1.0 project-1.0.zip
482
482
483 - create a tarball excluding .hg files::
483 - create a tarball excluding .hg files::
484
484
485 hg archive project.tar.gz -X ".hg*"
485 hg archive project.tar.gz -X ".hg*"
486
486
487 Valid types are:
487 Valid types are:
488
488
489 :``files``: a directory full of files (default)
489 :``files``: a directory full of files (default)
490 :``tar``: tar archive, uncompressed
490 :``tar``: tar archive, uncompressed
491 :``tbz2``: tar archive, compressed using bzip2
491 :``tbz2``: tar archive, compressed using bzip2
492 :``tgz``: tar archive, compressed using gzip
492 :``tgz``: tar archive, compressed using gzip
493 :``uzip``: zip archive, uncompressed
493 :``uzip``: zip archive, uncompressed
494 :``zip``: zip archive, compressed using deflate
494 :``zip``: zip archive, compressed using deflate
495
495
496 The exact name of the destination archive or directory is given
496 The exact name of the destination archive or directory is given
497 using a format string; see :hg:`help export` for details.
497 using a format string; see :hg:`help export` for details.
498
498
499 Each member added to an archive file has a directory prefix
499 Each member added to an archive file has a directory prefix
500 prepended. Use -p/--prefix to specify a format string for the
500 prepended. Use -p/--prefix to specify a format string for the
501 prefix. The default is the basename of the archive, with suffixes
501 prefix. The default is the basename of the archive, with suffixes
502 removed.
502 removed.
503
503
504 Returns 0 on success.
504 Returns 0 on success.
505 '''
505 '''
506
506
507 opts = pycompat.byteskwargs(opts)
507 opts = pycompat.byteskwargs(opts)
508 rev = opts.get('rev')
508 rev = opts.get('rev')
509 if rev:
509 if rev:
510 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
510 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
511 ctx = scmutil.revsingle(repo, rev)
511 ctx = scmutil.revsingle(repo, rev)
512 if not ctx:
512 if not ctx:
513 raise error.Abort(_('no working directory: please specify a revision'))
513 raise error.Abort(_('no working directory: please specify a revision'))
514 node = ctx.node()
514 node = ctx.node()
515 dest = cmdutil.makefilename(ctx, dest)
515 dest = cmdutil.makefilename(ctx, dest)
516 if os.path.realpath(dest) == repo.root:
516 if os.path.realpath(dest) == repo.root:
517 raise error.Abort(_('repository root cannot be destination'))
517 raise error.Abort(_('repository root cannot be destination'))
518
518
519 kind = opts.get('type') or archival.guesskind(dest) or 'files'
519 kind = opts.get('type') or archival.guesskind(dest) or 'files'
520 prefix = opts.get('prefix')
520 prefix = opts.get('prefix')
521
521
522 if dest == '-':
522 if dest == '-':
523 if kind == 'files':
523 if kind == 'files':
524 raise error.Abort(_('cannot archive plain files to stdout'))
524 raise error.Abort(_('cannot archive plain files to stdout'))
525 dest = cmdutil.makefileobj(ctx, dest)
525 dest = cmdutil.makefileobj(ctx, dest)
526 if not prefix:
526 if not prefix:
527 prefix = os.path.basename(repo.root) + '-%h'
527 prefix = os.path.basename(repo.root) + '-%h'
528
528
529 prefix = cmdutil.makefilename(ctx, prefix)
529 prefix = cmdutil.makefilename(ctx, prefix)
530 match = scmutil.match(ctx, [], opts)
530 match = scmutil.match(ctx, [], opts)
531 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
531 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
532 match, prefix, subrepos=opts.get('subrepos'))
532 match, prefix, subrepos=opts.get('subrepos'))
533
533
534 @command('backout',
534 @command('backout',
535 [('', 'merge', None, _('merge with old dirstate parent after backout')),
535 [('', 'merge', None, _('merge with old dirstate parent after backout')),
536 ('', 'commit', None,
536 ('', 'commit', None,
537 _('commit if no conflicts were encountered (DEPRECATED)')),
537 _('commit if no conflicts were encountered (DEPRECATED)')),
538 ('', 'no-commit', None, _('do not commit')),
538 ('', 'no-commit', None, _('do not commit')),
539 ('', 'parent', '',
539 ('', 'parent', '',
540 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
540 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
541 ('r', 'rev', '', _('revision to backout'), _('REV')),
541 ('r', 'rev', '', _('revision to backout'), _('REV')),
542 ('e', 'edit', False, _('invoke editor on commit messages')),
542 ('e', 'edit', False, _('invoke editor on commit messages')),
543 ] + mergetoolopts + walkopts + commitopts + commitopts2,
543 ] + mergetoolopts + walkopts + commitopts + commitopts2,
544 _('[OPTION]... [-r] REV'),
544 _('[OPTION]... [-r] REV'),
545 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
545 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
546 def backout(ui, repo, node=None, rev=None, **opts):
546 def backout(ui, repo, node=None, rev=None, **opts):
547 '''reverse effect of earlier changeset
547 '''reverse effect of earlier changeset
548
548
549 Prepare a new changeset with the effect of REV undone in the
549 Prepare a new changeset with the effect of REV undone in the
550 current working directory. If no conflicts were encountered,
550 current working directory. If no conflicts were encountered,
551 it will be committed immediately.
551 it will be committed immediately.
552
552
553 If REV is the parent of the working directory, then this new changeset
553 If REV is the parent of the working directory, then this new changeset
554 is committed automatically (unless --no-commit is specified).
554 is committed automatically (unless --no-commit is specified).
555
555
556 .. note::
556 .. note::
557
557
558 :hg:`backout` cannot be used to fix either an unwanted or
558 :hg:`backout` cannot be used to fix either an unwanted or
559 incorrect merge.
559 incorrect merge.
560
560
561 .. container:: verbose
561 .. container:: verbose
562
562
563 Examples:
563 Examples:
564
564
565 - Reverse the effect of the parent of the working directory.
565 - Reverse the effect of the parent of the working directory.
566 This backout will be committed immediately::
566 This backout will be committed immediately::
567
567
568 hg backout -r .
568 hg backout -r .
569
569
570 - Reverse the effect of previous bad revision 23::
570 - Reverse the effect of previous bad revision 23::
571
571
572 hg backout -r 23
572 hg backout -r 23
573
573
574 - Reverse the effect of previous bad revision 23 and
574 - Reverse the effect of previous bad revision 23 and
575 leave changes uncommitted::
575 leave changes uncommitted::
576
576
577 hg backout -r 23 --no-commit
577 hg backout -r 23 --no-commit
578 hg commit -m "Backout revision 23"
578 hg commit -m "Backout revision 23"
579
579
580 By default, the pending changeset will have one parent,
580 By default, the pending changeset will have one parent,
581 maintaining a linear history. With --merge, the pending
581 maintaining a linear history. With --merge, the pending
582 changeset will instead have two parents: the old parent of the
582 changeset will instead have two parents: the old parent of the
583 working directory and a new child of REV that simply undoes REV.
583 working directory and a new child of REV that simply undoes REV.
584
584
585 Before version 1.7, the behavior without --merge was equivalent
585 Before version 1.7, the behavior without --merge was equivalent
586 to specifying --merge followed by :hg:`update --clean .` to
586 to specifying --merge followed by :hg:`update --clean .` to
587 cancel the merge and leave the child of REV as a head to be
587 cancel the merge and leave the child of REV as a head to be
588 merged separately.
588 merged separately.
589
589
590 See :hg:`help dates` for a list of formats valid for -d/--date.
590 See :hg:`help dates` for a list of formats valid for -d/--date.
591
591
592 See :hg:`help revert` for a way to restore files to the state
592 See :hg:`help revert` for a way to restore files to the state
593 of another revision.
593 of another revision.
594
594
595 Returns 0 on success, 1 if nothing to backout or there are unresolved
595 Returns 0 on success, 1 if nothing to backout or there are unresolved
596 files.
596 files.
597 '''
597 '''
598 with repo.wlock(), repo.lock():
598 with repo.wlock(), repo.lock():
599 return _dobackout(ui, repo, node, rev, **opts)
599 return _dobackout(ui, repo, node, rev, **opts)
600
600
601 def _dobackout(ui, repo, node=None, rev=None, **opts):
601 def _dobackout(ui, repo, node=None, rev=None, **opts):
602 opts = pycompat.byteskwargs(opts)
602 opts = pycompat.byteskwargs(opts)
603 if opts.get('commit') and opts.get('no_commit'):
603 if opts.get('commit') and opts.get('no_commit'):
604 raise error.Abort(_("cannot use --commit with --no-commit"))
604 raise error.Abort(_("cannot use --commit with --no-commit"))
605 if opts.get('merge') and opts.get('no_commit'):
605 if opts.get('merge') and opts.get('no_commit'):
606 raise error.Abort(_("cannot use --merge with --no-commit"))
606 raise error.Abort(_("cannot use --merge with --no-commit"))
607
607
608 if rev and node:
608 if rev and node:
609 raise error.Abort(_("please specify just one revision"))
609 raise error.Abort(_("please specify just one revision"))
610
610
611 if not rev:
611 if not rev:
612 rev = node
612 rev = node
613
613
614 if not rev:
614 if not rev:
615 raise error.Abort(_("please specify a revision to backout"))
615 raise error.Abort(_("please specify a revision to backout"))
616
616
617 date = opts.get('date')
617 date = opts.get('date')
618 if date:
618 if date:
619 opts['date'] = dateutil.parsedate(date)
619 opts['date'] = dateutil.parsedate(date)
620
620
621 cmdutil.checkunfinished(repo)
621 cmdutil.checkunfinished(repo)
622 cmdutil.bailifchanged(repo)
622 cmdutil.bailifchanged(repo)
623 node = scmutil.revsingle(repo, rev).node()
623 node = scmutil.revsingle(repo, rev).node()
624
624
625 op1, op2 = repo.dirstate.parents()
625 op1, op2 = repo.dirstate.parents()
626 if not repo.changelog.isancestor(node, op1):
626 if not repo.changelog.isancestor(node, op1):
627 raise error.Abort(_('cannot backout change that is not an ancestor'))
627 raise error.Abort(_('cannot backout change that is not an ancestor'))
628
628
629 p1, p2 = repo.changelog.parents(node)
629 p1, p2 = repo.changelog.parents(node)
630 if p1 == nullid:
630 if p1 == nullid:
631 raise error.Abort(_('cannot backout a change with no parents'))
631 raise error.Abort(_('cannot backout a change with no parents'))
632 if p2 != nullid:
632 if p2 != nullid:
633 if not opts.get('parent'):
633 if not opts.get('parent'):
634 raise error.Abort(_('cannot backout a merge changeset'))
634 raise error.Abort(_('cannot backout a merge changeset'))
635 p = repo.lookup(opts['parent'])
635 p = repo.lookup(opts['parent'])
636 if p not in (p1, p2):
636 if p not in (p1, p2):
637 raise error.Abort(_('%s is not a parent of %s') %
637 raise error.Abort(_('%s is not a parent of %s') %
638 (short(p), short(node)))
638 (short(p), short(node)))
639 parent = p
639 parent = p
640 else:
640 else:
641 if opts.get('parent'):
641 if opts.get('parent'):
642 raise error.Abort(_('cannot use --parent on non-merge changeset'))
642 raise error.Abort(_('cannot use --parent on non-merge changeset'))
643 parent = p1
643 parent = p1
644
644
645 # the backout should appear on the same branch
645 # the backout should appear on the same branch
646 branch = repo.dirstate.branch()
646 branch = repo.dirstate.branch()
647 bheads = repo.branchheads(branch)
647 bheads = repo.branchheads(branch)
648 rctx = scmutil.revsingle(repo, hex(parent))
648 rctx = scmutil.revsingle(repo, hex(parent))
649 if not opts.get('merge') and op1 != node:
649 if not opts.get('merge') and op1 != node:
650 with dirstateguard.dirstateguard(repo, 'backout'):
650 with dirstateguard.dirstateguard(repo, 'backout'):
651 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
651 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
652 with ui.configoverride(overrides, 'backout'):
652 with ui.configoverride(overrides, 'backout'):
653 stats = mergemod.update(repo, parent, branchmerge=True,
653 stats = mergemod.update(repo, parent, branchmerge=True,
654 force=True, ancestor=node,
654 force=True, ancestor=node,
655 mergeancestor=False)
655 mergeancestor=False)
656 repo.setparents(op1, op2)
656 repo.setparents(op1, op2)
657 hg._showstats(repo, stats)
657 hg._showstats(repo, stats)
658 if stats.unresolvedcount:
658 if stats.unresolvedcount:
659 repo.ui.status(_("use 'hg resolve' to retry unresolved "
659 repo.ui.status(_("use 'hg resolve' to retry unresolved "
660 "file merges\n"))
660 "file merges\n"))
661 return 1
661 return 1
662 else:
662 else:
663 hg.clean(repo, node, show_stats=False)
663 hg.clean(repo, node, show_stats=False)
664 repo.dirstate.setbranch(branch)
664 repo.dirstate.setbranch(branch)
665 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
665 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
666
666
667 if opts.get('no_commit'):
667 if opts.get('no_commit'):
668 msg = _("changeset %s backed out, "
668 msg = _("changeset %s backed out, "
669 "don't forget to commit.\n")
669 "don't forget to commit.\n")
670 ui.status(msg % short(node))
670 ui.status(msg % short(node))
671 return 0
671 return 0
672
672
673 def commitfunc(ui, repo, message, match, opts):
673 def commitfunc(ui, repo, message, match, opts):
674 editform = 'backout'
674 editform = 'backout'
675 e = cmdutil.getcommiteditor(editform=editform,
675 e = cmdutil.getcommiteditor(editform=editform,
676 **pycompat.strkwargs(opts))
676 **pycompat.strkwargs(opts))
677 if not message:
677 if not message:
678 # we don't translate commit messages
678 # we don't translate commit messages
679 message = "Backed out changeset %s" % short(node)
679 message = "Backed out changeset %s" % short(node)
680 e = cmdutil.getcommiteditor(edit=True, editform=editform)
680 e = cmdutil.getcommiteditor(edit=True, editform=editform)
681 return repo.commit(message, opts.get('user'), opts.get('date'),
681 return repo.commit(message, opts.get('user'), opts.get('date'),
682 match, editor=e)
682 match, editor=e)
683 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
683 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
684 if not newnode:
684 if not newnode:
685 ui.status(_("nothing changed\n"))
685 ui.status(_("nothing changed\n"))
686 return 1
686 return 1
687 cmdutil.commitstatus(repo, newnode, branch, bheads)
687 cmdutil.commitstatus(repo, newnode, branch, bheads)
688
688
689 def nice(node):
689 def nice(node):
690 return '%d:%s' % (repo.changelog.rev(node), short(node))
690 return '%d:%s' % (repo.changelog.rev(node), short(node))
691 ui.status(_('changeset %s backs out changeset %s\n') %
691 ui.status(_('changeset %s backs out changeset %s\n') %
692 (nice(repo.changelog.tip()), nice(node)))
692 (nice(repo.changelog.tip()), nice(node)))
693 if opts.get('merge') and op1 != node:
693 if opts.get('merge') and op1 != node:
694 hg.clean(repo, op1, show_stats=False)
694 hg.clean(repo, op1, show_stats=False)
695 ui.status(_('merging with changeset %s\n')
695 ui.status(_('merging with changeset %s\n')
696 % nice(repo.changelog.tip()))
696 % nice(repo.changelog.tip()))
697 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
697 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
698 with ui.configoverride(overrides, 'backout'):
698 with ui.configoverride(overrides, 'backout'):
699 return hg.merge(repo, hex(repo.changelog.tip()))
699 return hg.merge(repo, hex(repo.changelog.tip()))
700 return 0
700 return 0
701
701
702 @command('bisect',
702 @command('bisect',
703 [('r', 'reset', False, _('reset bisect state')),
703 [('r', 'reset', False, _('reset bisect state')),
704 ('g', 'good', False, _('mark changeset good')),
704 ('g', 'good', False, _('mark changeset good')),
705 ('b', 'bad', False, _('mark changeset bad')),
705 ('b', 'bad', False, _('mark changeset bad')),
706 ('s', 'skip', False, _('skip testing changeset')),
706 ('s', 'skip', False, _('skip testing changeset')),
707 ('e', 'extend', False, _('extend the bisect range')),
707 ('e', 'extend', False, _('extend the bisect range')),
708 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
708 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
709 ('U', 'noupdate', False, _('do not update to target'))],
709 ('U', 'noupdate', False, _('do not update to target'))],
710 _("[-gbsr] [-U] [-c CMD] [REV]"),
710 _("[-gbsr] [-U] [-c CMD] [REV]"),
711 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
711 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
712 def bisect(ui, repo, rev=None, extra=None, command=None,
712 def bisect(ui, repo, rev=None, extra=None, command=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
714 noupdate=None):
714 noupdate=None):
715 """subdivision search of changesets
715 """subdivision search of changesets
716
716
717 This command helps to find changesets which introduce problems. To
717 This command helps to find changesets which introduce problems. To
718 use, mark the earliest changeset you know exhibits the problem as
718 use, mark the earliest changeset you know exhibits the problem as
719 bad, then mark the latest changeset which is free from the problem
719 bad, then mark the latest changeset which is free from the problem
720 as good. Bisect will update your working directory to a revision
720 as good. Bisect will update your working directory to a revision
721 for testing (unless the -U/--noupdate option is specified). Once
721 for testing (unless the -U/--noupdate option is specified). Once
722 you have performed tests, mark the working directory as good or
722 you have performed tests, mark the working directory as good or
723 bad, and bisect will either update to another candidate changeset
723 bad, and bisect will either update to another candidate changeset
724 or announce that it has found the bad revision.
724 or announce that it has found the bad revision.
725
725
726 As a shortcut, you can also use the revision argument to mark a
726 As a shortcut, you can also use the revision argument to mark a
727 revision as good or bad without checking it out first.
727 revision as good or bad without checking it out first.
728
728
729 If you supply a command, it will be used for automatic bisection.
729 If you supply a command, it will be used for automatic bisection.
730 The environment variable HG_NODE will contain the ID of the
730 The environment variable HG_NODE will contain the ID of the
731 changeset being tested. The exit status of the command will be
731 changeset being tested. The exit status of the command will be
732 used to mark revisions as good or bad: status 0 means good, 125
732 used to mark revisions as good or bad: status 0 means good, 125
733 means to skip the revision, 127 (command not found) will abort the
733 means to skip the revision, 127 (command not found) will abort the
734 bisection, and any other non-zero exit status means the revision
734 bisection, and any other non-zero exit status means the revision
735 is bad.
735 is bad.
736
736
737 .. container:: verbose
737 .. container:: verbose
738
738
739 Some examples:
739 Some examples:
740
740
741 - start a bisection with known bad revision 34, and good revision 12::
741 - start a bisection with known bad revision 34, and good revision 12::
742
742
743 hg bisect --bad 34
743 hg bisect --bad 34
744 hg bisect --good 12
744 hg bisect --good 12
745
745
746 - advance the current bisection by marking current revision as good or
746 - advance the current bisection by marking current revision as good or
747 bad::
747 bad::
748
748
749 hg bisect --good
749 hg bisect --good
750 hg bisect --bad
750 hg bisect --bad
751
751
752 - mark the current revision, or a known revision, to be skipped (e.g. if
752 - mark the current revision, or a known revision, to be skipped (e.g. if
753 that revision is not usable because of another issue)::
753 that revision is not usable because of another issue)::
754
754
755 hg bisect --skip
755 hg bisect --skip
756 hg bisect --skip 23
756 hg bisect --skip 23
757
757
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
759
759
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
761
761
762 - forget the current bisection::
762 - forget the current bisection::
763
763
764 hg bisect --reset
764 hg bisect --reset
765
765
766 - use 'make && make tests' to automatically find the first broken
766 - use 'make && make tests' to automatically find the first broken
767 revision::
767 revision::
768
768
769 hg bisect --reset
769 hg bisect --reset
770 hg bisect --bad 34
770 hg bisect --bad 34
771 hg bisect --good 12
771 hg bisect --good 12
772 hg bisect --command "make && make tests"
772 hg bisect --command "make && make tests"
773
773
774 - see all changesets whose states are already known in the current
774 - see all changesets whose states are already known in the current
775 bisection::
775 bisection::
776
776
777 hg log -r "bisect(pruned)"
777 hg log -r "bisect(pruned)"
778
778
779 - see the changeset currently being bisected (especially useful
779 - see the changeset currently being bisected (especially useful
780 if running with -U/--noupdate)::
780 if running with -U/--noupdate)::
781
781
782 hg log -r "bisect(current)"
782 hg log -r "bisect(current)"
783
783
784 - see all changesets that took part in the current bisection::
784 - see all changesets that took part in the current bisection::
785
785
786 hg log -r "bisect(range)"
786 hg log -r "bisect(range)"
787
787
788 - you can even get a nice graph::
788 - you can even get a nice graph::
789
789
790 hg log --graph -r "bisect(range)"
790 hg log --graph -r "bisect(range)"
791
791
792 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
792 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
793
793
794 Returns 0 on success.
794 Returns 0 on success.
795 """
795 """
796 # backward compatibility
796 # backward compatibility
797 if rev in "good bad reset init".split():
797 if rev in "good bad reset init".split():
798 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
798 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
799 cmd, rev, extra = rev, extra, None
799 cmd, rev, extra = rev, extra, None
800 if cmd == "good":
800 if cmd == "good":
801 good = True
801 good = True
802 elif cmd == "bad":
802 elif cmd == "bad":
803 bad = True
803 bad = True
804 else:
804 else:
805 reset = True
805 reset = True
806 elif extra:
806 elif extra:
807 raise error.Abort(_('incompatible arguments'))
807 raise error.Abort(_('incompatible arguments'))
808
808
809 incompatibles = {
809 incompatibles = {
810 '--bad': bad,
810 '--bad': bad,
811 '--command': bool(command),
811 '--command': bool(command),
812 '--extend': extend,
812 '--extend': extend,
813 '--good': good,
813 '--good': good,
814 '--reset': reset,
814 '--reset': reset,
815 '--skip': skip,
815 '--skip': skip,
816 }
816 }
817
817
818 enabled = [x for x in incompatibles if incompatibles[x]]
818 enabled = [x for x in incompatibles if incompatibles[x]]
819
819
820 if len(enabled) > 1:
820 if len(enabled) > 1:
821 raise error.Abort(_('%s and %s are incompatible') %
821 raise error.Abort(_('%s and %s are incompatible') %
822 tuple(sorted(enabled)[0:2]))
822 tuple(sorted(enabled)[0:2]))
823
823
824 if reset:
824 if reset:
825 hbisect.resetstate(repo)
825 hbisect.resetstate(repo)
826 return
826 return
827
827
828 state = hbisect.load_state(repo)
828 state = hbisect.load_state(repo)
829
829
830 # update state
830 # update state
831 if good or bad or skip:
831 if good or bad or skip:
832 if rev:
832 if rev:
833 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
833 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
834 else:
834 else:
835 nodes = [repo.lookup('.')]
835 nodes = [repo.lookup('.')]
836 if good:
836 if good:
837 state['good'] += nodes
837 state['good'] += nodes
838 elif bad:
838 elif bad:
839 state['bad'] += nodes
839 state['bad'] += nodes
840 elif skip:
840 elif skip:
841 state['skip'] += nodes
841 state['skip'] += nodes
842 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
843 if not (state['good'] and state['bad']):
843 if not (state['good'] and state['bad']):
844 return
844 return
845
845
846 def mayupdate(repo, node, show_stats=True):
846 def mayupdate(repo, node, show_stats=True):
847 """common used update sequence"""
847 """common used update sequence"""
848 if noupdate:
848 if noupdate:
849 return
849 return
850 cmdutil.checkunfinished(repo)
850 cmdutil.checkunfinished(repo)
851 cmdutil.bailifchanged(repo)
851 cmdutil.bailifchanged(repo)
852 return hg.clean(repo, node, show_stats=show_stats)
852 return hg.clean(repo, node, show_stats=show_stats)
853
853
854 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
854 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
855
855
856 if command:
856 if command:
857 changesets = 1
857 changesets = 1
858 if noupdate:
858 if noupdate:
859 try:
859 try:
860 node = state['current'][0]
860 node = state['current'][0]
861 except LookupError:
861 except LookupError:
862 raise error.Abort(_('current bisect revision is unknown - '
862 raise error.Abort(_('current bisect revision is unknown - '
863 'start a new bisect to fix'))
863 'start a new bisect to fix'))
864 else:
864 else:
865 node, p2 = repo.dirstate.parents()
865 node, p2 = repo.dirstate.parents()
866 if p2 != nullid:
866 if p2 != nullid:
867 raise error.Abort(_('current bisect revision is a merge'))
867 raise error.Abort(_('current bisect revision is a merge'))
868 if rev:
868 if rev:
869 node = repo[scmutil.revsingle(repo, rev, node)].node()
869 node = repo[scmutil.revsingle(repo, rev, node)].node()
870 try:
870 try:
871 while changesets:
871 while changesets:
872 # update state
872 # update state
873 state['current'] = [node]
873 state['current'] = [node]
874 hbisect.save_state(repo, state)
874 hbisect.save_state(repo, state)
875 status = ui.system(command, environ={'HG_NODE': hex(node)},
875 status = ui.system(command, environ={'HG_NODE': hex(node)},
876 blockedtag='bisect_check')
876 blockedtag='bisect_check')
877 if status == 125:
877 if status == 125:
878 transition = "skip"
878 transition = "skip"
879 elif status == 0:
879 elif status == 0:
880 transition = "good"
880 transition = "good"
881 # status < 0 means process was killed
881 # status < 0 means process was killed
882 elif status == 127:
882 elif status == 127:
883 raise error.Abort(_("failed to execute %s") % command)
883 raise error.Abort(_("failed to execute %s") % command)
884 elif status < 0:
884 elif status < 0:
885 raise error.Abort(_("%s killed") % command)
885 raise error.Abort(_("%s killed") % command)
886 else:
886 else:
887 transition = "bad"
887 transition = "bad"
888 state[transition].append(node)
888 state[transition].append(node)
889 ctx = repo[node]
889 ctx = repo[node]
890 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
890 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
891 transition))
891 transition))
892 hbisect.checkstate(state)
892 hbisect.checkstate(state)
893 # bisect
893 # bisect
894 nodes, changesets, bgood = hbisect.bisect(repo, state)
894 nodes, changesets, bgood = hbisect.bisect(repo, state)
895 # update to next check
895 # update to next check
896 node = nodes[0]
896 node = nodes[0]
897 mayupdate(repo, node, show_stats=False)
897 mayupdate(repo, node, show_stats=False)
898 finally:
898 finally:
899 state['current'] = [node]
899 state['current'] = [node]
900 hbisect.save_state(repo, state)
900 hbisect.save_state(repo, state)
901 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
901 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
902 return
902 return
903
903
904 hbisect.checkstate(state)
904 hbisect.checkstate(state)
905
905
906 # actually bisect
906 # actually bisect
907 nodes, changesets, good = hbisect.bisect(repo, state)
907 nodes, changesets, good = hbisect.bisect(repo, state)
908 if extend:
908 if extend:
909 if not changesets:
909 if not changesets:
910 extendnode = hbisect.extendrange(repo, state, nodes, good)
910 extendnode = hbisect.extendrange(repo, state, nodes, good)
911 if extendnode is not None:
911 if extendnode is not None:
912 ui.write(_("Extending search to changeset %d:%s\n")
912 ui.write(_("Extending search to changeset %d:%s\n")
913 % (extendnode.rev(), extendnode))
913 % (extendnode.rev(), extendnode))
914 state['current'] = [extendnode.node()]
914 state['current'] = [extendnode.node()]
915 hbisect.save_state(repo, state)
915 hbisect.save_state(repo, state)
916 return mayupdate(repo, extendnode.node())
916 return mayupdate(repo, extendnode.node())
917 raise error.Abort(_("nothing to extend"))
917 raise error.Abort(_("nothing to extend"))
918
918
919 if changesets == 0:
919 if changesets == 0:
920 hbisect.printresult(ui, repo, state, displayer, nodes, good)
920 hbisect.printresult(ui, repo, state, displayer, nodes, good)
921 else:
921 else:
922 assert len(nodes) == 1 # only a single node can be tested next
922 assert len(nodes) == 1 # only a single node can be tested next
923 node = nodes[0]
923 node = nodes[0]
924 # compute the approximate number of remaining tests
924 # compute the approximate number of remaining tests
925 tests, size = 0, 2
925 tests, size = 0, 2
926 while size <= changesets:
926 while size <= changesets:
927 tests, size = tests + 1, size * 2
927 tests, size = tests + 1, size * 2
928 rev = repo.changelog.rev(node)
928 rev = repo.changelog.rev(node)
929 ui.write(_("Testing changeset %d:%s "
929 ui.write(_("Testing changeset %d:%s "
930 "(%d changesets remaining, ~%d tests)\n")
930 "(%d changesets remaining, ~%d tests)\n")
931 % (rev, short(node), changesets, tests))
931 % (rev, short(node), changesets, tests))
932 state['current'] = [node]
932 state['current'] = [node]
933 hbisect.save_state(repo, state)
933 hbisect.save_state(repo, state)
934 return mayupdate(repo, node)
934 return mayupdate(repo, node)
935
935
936 @command('bookmarks|bookmark',
936 @command('bookmarks|bookmark',
937 [('f', 'force', False, _('force')),
937 [('f', 'force', False, _('force')),
938 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
938 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
939 ('d', 'delete', False, _('delete a given bookmark')),
939 ('d', 'delete', False, _('delete a given bookmark')),
940 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
940 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
941 ('i', 'inactive', False, _('mark a bookmark inactive')),
941 ('i', 'inactive', False, _('mark a bookmark inactive')),
942 ('l', 'list', False, _('list existing bookmarks')),
942 ('l', 'list', False, _('list existing bookmarks')),
943 ] + formatteropts,
943 ] + formatteropts,
944 _('hg bookmarks [OPTIONS]... [NAME]...'),
944 _('hg bookmarks [OPTIONS]... [NAME]...'),
945 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
945 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
946 def bookmark(ui, repo, *names, **opts):
946 def bookmark(ui, repo, *names, **opts):
947 '''create a new bookmark or list existing bookmarks
947 '''create a new bookmark or list existing bookmarks
948
948
949 Bookmarks are labels on changesets to help track lines of development.
949 Bookmarks are labels on changesets to help track lines of development.
950 Bookmarks are unversioned and can be moved, renamed and deleted.
950 Bookmarks are unversioned and can be moved, renamed and deleted.
951 Deleting or moving a bookmark has no effect on the associated changesets.
951 Deleting or moving a bookmark has no effect on the associated changesets.
952
952
953 Creating or updating to a bookmark causes it to be marked as 'active'.
953 Creating or updating to a bookmark causes it to be marked as 'active'.
954 The active bookmark is indicated with a '*'.
954 The active bookmark is indicated with a '*'.
955 When a commit is made, the active bookmark will advance to the new commit.
955 When a commit is made, the active bookmark will advance to the new commit.
956 A plain :hg:`update` will also advance an active bookmark, if possible.
956 A plain :hg:`update` will also advance an active bookmark, if possible.
957 Updating away from a bookmark will cause it to be deactivated.
957 Updating away from a bookmark will cause it to be deactivated.
958
958
959 Bookmarks can be pushed and pulled between repositories (see
959 Bookmarks can be pushed and pulled between repositories (see
960 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
960 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
961 diverged, a new 'divergent bookmark' of the form 'name@path' will
961 diverged, a new 'divergent bookmark' of the form 'name@path' will
962 be created. Using :hg:`merge` will resolve the divergence.
962 be created. Using :hg:`merge` will resolve the divergence.
963
963
964 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
964 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
965 the active bookmark's name.
965 the active bookmark's name.
966
966
967 A bookmark named '@' has the special property that :hg:`clone` will
967 A bookmark named '@' has the special property that :hg:`clone` will
968 check it out by default if it exists.
968 check it out by default if it exists.
969
969
970 .. container:: verbose
970 .. container:: verbose
971
971
972 Template:
972 Template:
973
973
974 The following keywords are supported in addition to the common template
974 The following keywords are supported in addition to the common template
975 keywords and functions such as ``{bookmark}``. See also
975 keywords and functions such as ``{bookmark}``. See also
976 :hg:`help templates`.
976 :hg:`help templates`.
977
977
978 :active: Boolean. True if the bookmark is active.
978 :active: Boolean. True if the bookmark is active.
979
979
980 Examples:
980 Examples:
981
981
982 - create an active bookmark for a new line of development::
982 - create an active bookmark for a new line of development::
983
983
984 hg book new-feature
984 hg book new-feature
985
985
986 - create an inactive bookmark as a place marker::
986 - create an inactive bookmark as a place marker::
987
987
988 hg book -i reviewed
988 hg book -i reviewed
989
989
990 - create an inactive bookmark on another changeset::
990 - create an inactive bookmark on another changeset::
991
991
992 hg book -r .^ tested
992 hg book -r .^ tested
993
993
994 - rename bookmark turkey to dinner::
994 - rename bookmark turkey to dinner::
995
995
996 hg book -m turkey dinner
996 hg book -m turkey dinner
997
997
998 - move the '@' bookmark from another branch::
998 - move the '@' bookmark from another branch::
999
999
1000 hg book -f @
1000 hg book -f @
1001
1001
1002 - print only the active bookmark name::
1002 - print only the active bookmark name::
1003
1003
1004 hg book -ql .
1004 hg book -ql .
1005 '''
1005 '''
1006 opts = pycompat.byteskwargs(opts)
1006 opts = pycompat.byteskwargs(opts)
1007 force = opts.get('force')
1007 force = opts.get('force')
1008 rev = opts.get('rev')
1008 rev = opts.get('rev')
1009 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1009 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1010
1010
1011 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1011 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1012 if len(selactions) > 1:
1012 if len(selactions) > 1:
1013 raise error.Abort(_('--%s and --%s are incompatible')
1013 raise error.Abort(_('--%s and --%s are incompatible')
1014 % tuple(selactions[:2]))
1014 % tuple(selactions[:2]))
1015 if selactions:
1015 if selactions:
1016 action = selactions[0]
1016 action = selactions[0]
1017 elif names or rev:
1017 elif names or rev:
1018 action = 'add'
1018 action = 'add'
1019 elif inactive:
1019 elif inactive:
1020 action = 'inactive' # meaning deactivate
1020 action = 'inactive' # meaning deactivate
1021 else:
1021 else:
1022 action = 'list'
1022 action = 'list'
1023
1023
1024 if rev and action in {'delete', 'rename', 'list'}:
1024 if rev and action in {'delete', 'rename', 'list'}:
1025 raise error.Abort(_("--rev is incompatible with --%s") % action)
1025 raise error.Abort(_("--rev is incompatible with --%s") % action)
1026 if inactive and action in {'delete', 'list'}:
1026 if inactive and action in {'delete', 'list'}:
1027 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1027 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1028 if not names and action in {'add', 'delete'}:
1028 if not names and action in {'add', 'delete'}:
1029 raise error.Abort(_("bookmark name required"))
1029 raise error.Abort(_("bookmark name required"))
1030
1030
1031 if action in {'add', 'delete', 'rename', 'inactive'}:
1031 if action in {'add', 'delete', 'rename', 'inactive'}:
1032 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1032 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1033 if action == 'delete':
1033 if action == 'delete':
1034 names = pycompat.maplist(repo._bookmarks.expandname, names)
1034 names = pycompat.maplist(repo._bookmarks.expandname, names)
1035 bookmarks.delete(repo, tr, names)
1035 bookmarks.delete(repo, tr, names)
1036 elif action == 'rename':
1036 elif action == 'rename':
1037 if not names:
1037 if not names:
1038 raise error.Abort(_("new bookmark name required"))
1038 raise error.Abort(_("new bookmark name required"))
1039 elif len(names) > 1:
1039 elif len(names) > 1:
1040 raise error.Abort(_("only one new bookmark name allowed"))
1040 raise error.Abort(_("only one new bookmark name allowed"))
1041 oldname = repo._bookmarks.expandname(opts['rename'])
1041 oldname = repo._bookmarks.expandname(opts['rename'])
1042 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1042 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1043 elif action == 'add':
1043 elif action == 'add':
1044 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1044 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1045 elif action == 'inactive':
1045 elif action == 'inactive':
1046 if len(repo._bookmarks) == 0:
1046 if len(repo._bookmarks) == 0:
1047 ui.status(_("no bookmarks set\n"))
1047 ui.status(_("no bookmarks set\n"))
1048 elif not repo._activebookmark:
1048 elif not repo._activebookmark:
1049 ui.status(_("no active bookmark\n"))
1049 ui.status(_("no active bookmark\n"))
1050 else:
1050 else:
1051 bookmarks.deactivate(repo)
1051 bookmarks.deactivate(repo)
1052 elif action == 'list':
1052 elif action == 'list':
1053 names = pycompat.maplist(repo._bookmarks.expandname, names)
1053 names = pycompat.maplist(repo._bookmarks.expandname, names)
1054 with ui.formatter('bookmarks', opts) as fm:
1054 with ui.formatter('bookmarks', opts) as fm:
1055 bookmarks.printbookmarks(ui, repo, fm, names)
1055 bookmarks.printbookmarks(ui, repo, fm, names)
1056 else:
1056 else:
1057 raise error.ProgrammingError('invalid action: %s' % action)
1057 raise error.ProgrammingError('invalid action: %s' % action)
1058
1058
1059 @command('branch',
1059 @command('branch',
1060 [('f', 'force', None,
1060 [('f', 'force', None,
1061 _('set branch name even if it shadows an existing branch')),
1061 _('set branch name even if it shadows an existing branch')),
1062 ('C', 'clean', None, _('reset branch name to parent branch name')),
1062 ('C', 'clean', None, _('reset branch name to parent branch name')),
1063 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1063 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1064 ],
1064 ],
1065 _('[-fC] [NAME]'),
1065 _('[-fC] [NAME]'),
1066 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1066 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1067 def branch(ui, repo, label=None, **opts):
1067 def branch(ui, repo, label=None, **opts):
1068 """set or show the current branch name
1068 """set or show the current branch name
1069
1069
1070 .. note::
1070 .. note::
1071
1071
1072 Branch names are permanent and global. Use :hg:`bookmark` to create a
1072 Branch names are permanent and global. Use :hg:`bookmark` to create a
1073 light-weight bookmark instead. See :hg:`help glossary` for more
1073 light-weight bookmark instead. See :hg:`help glossary` for more
1074 information about named branches and bookmarks.
1074 information about named branches and bookmarks.
1075
1075
1076 With no argument, show the current branch name. With one argument,
1076 With no argument, show the current branch name. With one argument,
1077 set the working directory branch name (the branch will not exist
1077 set the working directory branch name (the branch will not exist
1078 in the repository until the next commit). Standard practice
1078 in the repository until the next commit). Standard practice
1079 recommends that primary development take place on the 'default'
1079 recommends that primary development take place on the 'default'
1080 branch.
1080 branch.
1081
1081
1082 Unless -f/--force is specified, branch will not let you set a
1082 Unless -f/--force is specified, branch will not let you set a
1083 branch name that already exists.
1083 branch name that already exists.
1084
1084
1085 Use -C/--clean to reset the working directory branch to that of
1085 Use -C/--clean to reset the working directory branch to that of
1086 the parent of the working directory, negating a previous branch
1086 the parent of the working directory, negating a previous branch
1087 change.
1087 change.
1088
1088
1089 Use the command :hg:`update` to switch to an existing branch. Use
1089 Use the command :hg:`update` to switch to an existing branch. Use
1090 :hg:`commit --close-branch` to mark this branch head as closed.
1090 :hg:`commit --close-branch` to mark this branch head as closed.
1091 When all heads of a branch are closed, the branch will be
1091 When all heads of a branch are closed, the branch will be
1092 considered closed.
1092 considered closed.
1093
1093
1094 Returns 0 on success.
1094 Returns 0 on success.
1095 """
1095 """
1096 opts = pycompat.byteskwargs(opts)
1096 opts = pycompat.byteskwargs(opts)
1097 revs = opts.get('rev')
1097 revs = opts.get('rev')
1098 if label:
1098 if label:
1099 label = label.strip()
1099 label = label.strip()
1100
1100
1101 if not opts.get('clean') and not label:
1101 if not opts.get('clean') and not label:
1102 if revs:
1102 if revs:
1103 raise error.Abort(_("no branch name specified for the revisions"))
1103 raise error.Abort(_("no branch name specified for the revisions"))
1104 ui.write("%s\n" % repo.dirstate.branch())
1104 ui.write("%s\n" % repo.dirstate.branch())
1105 return
1105 return
1106
1106
1107 with repo.wlock():
1107 with repo.wlock():
1108 if opts.get('clean'):
1108 if opts.get('clean'):
1109 label = repo['.'].branch()
1109 label = repo['.'].branch()
1110 repo.dirstate.setbranch(label)
1110 repo.dirstate.setbranch(label)
1111 ui.status(_('reset working directory to branch %s\n') % label)
1111 ui.status(_('reset working directory to branch %s\n') % label)
1112 elif label:
1112 elif label:
1113
1113
1114 scmutil.checknewlabel(repo, label, 'branch')
1114 scmutil.checknewlabel(repo, label, 'branch')
1115 if revs:
1115 if revs:
1116 return cmdutil.changebranch(ui, repo, revs, label)
1116 return cmdutil.changebranch(ui, repo, revs, label)
1117
1117
1118 if not opts.get('force') and label in repo.branchmap():
1118 if not opts.get('force') and label in repo.branchmap():
1119 if label not in [p.branch() for p in repo[None].parents()]:
1119 if label not in [p.branch() for p in repo[None].parents()]:
1120 raise error.Abort(_('a branch of the same name already'
1120 raise error.Abort(_('a branch of the same name already'
1121 ' exists'),
1121 ' exists'),
1122 # i18n: "it" refers to an existing branch
1122 # i18n: "it" refers to an existing branch
1123 hint=_("use 'hg update' to switch to it"))
1123 hint=_("use 'hg update' to switch to it"))
1124
1124
1125 repo.dirstate.setbranch(label)
1125 repo.dirstate.setbranch(label)
1126 ui.status(_('marked working directory as branch %s\n') % label)
1126 ui.status(_('marked working directory as branch %s\n') % label)
1127
1127
1128 # find any open named branches aside from default
1128 # find any open named branches aside from default
1129 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1129 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1130 if n != "default" and not c]
1130 if n != "default" and not c]
1131 if not others:
1131 if not others:
1132 ui.status(_('(branches are permanent and global, '
1132 ui.status(_('(branches are permanent and global, '
1133 'did you want a bookmark?)\n'))
1133 'did you want a bookmark?)\n'))
1134
1134
1135 @command('branches',
1135 @command('branches',
1136 [('a', 'active', False,
1136 [('a', 'active', False,
1137 _('show only branches that have unmerged heads (DEPRECATED)')),
1137 _('show only branches that have unmerged heads (DEPRECATED)')),
1138 ('c', 'closed', False, _('show normal and closed branches')),
1138 ('c', 'closed', False, _('show normal and closed branches')),
1139 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1139 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1140 ] + formatteropts,
1140 ] + formatteropts,
1141 _('[-c]'),
1141 _('[-c]'),
1142 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1142 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1143 intents={INTENT_READONLY})
1143 intents={INTENT_READONLY})
1144 def branches(ui, repo, active=False, closed=False, **opts):
1144 def branches(ui, repo, active=False, closed=False, **opts):
1145 """list repository named branches
1145 """list repository named branches
1146
1146
1147 List the repository's named branches, indicating which ones are
1147 List the repository's named branches, indicating which ones are
1148 inactive. If -c/--closed is specified, also list branches which have
1148 inactive. If -c/--closed is specified, also list branches which have
1149 been marked closed (see :hg:`commit --close-branch`).
1149 been marked closed (see :hg:`commit --close-branch`).
1150
1150
1151 Use the command :hg:`update` to switch to an existing branch.
1151 Use the command :hg:`update` to switch to an existing branch.
1152
1152
1153 .. container:: verbose
1153 .. container:: verbose
1154
1154
1155 Template:
1155 Template:
1156
1156
1157 The following keywords are supported in addition to the common template
1157 The following keywords are supported in addition to the common template
1158 keywords and functions such as ``{branch}``. See also
1158 keywords and functions such as ``{branch}``. See also
1159 :hg:`help templates`.
1159 :hg:`help templates`.
1160
1160
1161 :active: Boolean. True if the branch is active.
1161 :active: Boolean. True if the branch is active.
1162 :closed: Boolean. True if the branch is closed.
1162 :closed: Boolean. True if the branch is closed.
1163 :current: Boolean. True if it is the current branch.
1163 :current: Boolean. True if it is the current branch.
1164
1164
1165 Returns 0.
1165 Returns 0.
1166 """
1166 """
1167
1167
1168 opts = pycompat.byteskwargs(opts)
1168 opts = pycompat.byteskwargs(opts)
1169 revs = opts.get('rev')
1169 revs = opts.get('rev')
1170 selectedbranches = None
1170 selectedbranches = None
1171 if revs:
1171 if revs:
1172 revs = scmutil.revrange(repo, revs)
1172 revs = scmutil.revrange(repo, revs)
1173 getbi = repo.revbranchcache().branchinfo
1173 getbi = repo.revbranchcache().branchinfo
1174 selectedbranches = {getbi(r)[0] for r in revs}
1174 selectedbranches = {getbi(r)[0] for r in revs}
1175
1175
1176 ui.pager('branches')
1176 ui.pager('branches')
1177 fm = ui.formatter('branches', opts)
1177 fm = ui.formatter('branches', opts)
1178 hexfunc = fm.hexfunc
1178 hexfunc = fm.hexfunc
1179
1179
1180 allheads = set(repo.heads())
1180 allheads = set(repo.heads())
1181 branches = []
1181 branches = []
1182 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1182 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1183 if selectedbranches is not None and tag not in selectedbranches:
1183 if selectedbranches is not None and tag not in selectedbranches:
1184 continue
1184 continue
1185 isactive = False
1185 isactive = False
1186 if not isclosed:
1186 if not isclosed:
1187 openheads = set(repo.branchmap().iteropen(heads))
1187 openheads = set(repo.branchmap().iteropen(heads))
1188 isactive = bool(openheads & allheads)
1188 isactive = bool(openheads & allheads)
1189 branches.append((tag, repo[tip], isactive, not isclosed))
1189 branches.append((tag, repo[tip], isactive, not isclosed))
1190 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1190 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1191 reverse=True)
1191 reverse=True)
1192
1192
1193 for tag, ctx, isactive, isopen in branches:
1193 for tag, ctx, isactive, isopen in branches:
1194 if active and not isactive:
1194 if active and not isactive:
1195 continue
1195 continue
1196 if isactive:
1196 if isactive:
1197 label = 'branches.active'
1197 label = 'branches.active'
1198 notice = ''
1198 notice = ''
1199 elif not isopen:
1199 elif not isopen:
1200 if not closed:
1200 if not closed:
1201 continue
1201 continue
1202 label = 'branches.closed'
1202 label = 'branches.closed'
1203 notice = _(' (closed)')
1203 notice = _(' (closed)')
1204 else:
1204 else:
1205 label = 'branches.inactive'
1205 label = 'branches.inactive'
1206 notice = _(' (inactive)')
1206 notice = _(' (inactive)')
1207 current = (tag == repo.dirstate.branch())
1207 current = (tag == repo.dirstate.branch())
1208 if current:
1208 if current:
1209 label = 'branches.current'
1209 label = 'branches.current'
1210
1210
1211 fm.startitem()
1211 fm.startitem()
1212 fm.write('branch', '%s', tag, label=label)
1212 fm.write('branch', '%s', tag, label=label)
1213 rev = ctx.rev()
1213 rev = ctx.rev()
1214 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1214 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1215 fmt = ' ' * padsize + ' %d:%s'
1215 fmt = ' ' * padsize + ' %d:%s'
1216 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1216 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1217 label='log.changeset changeset.%s' % ctx.phasestr())
1217 label='log.changeset changeset.%s' % ctx.phasestr())
1218 fm.context(ctx=ctx)
1218 fm.context(ctx=ctx)
1219 fm.data(active=isactive, closed=not isopen, current=current)
1219 fm.data(active=isactive, closed=not isopen, current=current)
1220 if not ui.quiet:
1220 if not ui.quiet:
1221 fm.plain(notice)
1221 fm.plain(notice)
1222 fm.plain('\n')
1222 fm.plain('\n')
1223 fm.end()
1223 fm.end()
1224
1224
1225 @command('bundle',
1225 @command('bundle',
1226 [('f', 'force', None, _('run even when the destination is unrelated')),
1226 [('f', 'force', None, _('run even when the destination is unrelated')),
1227 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1227 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1228 _('REV')),
1228 _('REV')),
1229 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1229 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1230 _('BRANCH')),
1230 _('BRANCH')),
1231 ('', 'base', [],
1231 ('', 'base', [],
1232 _('a base changeset assumed to be available at the destination'),
1232 _('a base changeset assumed to be available at the destination'),
1233 _('REV')),
1233 _('REV')),
1234 ('a', 'all', None, _('bundle all changesets in the repository')),
1234 ('a', 'all', None, _('bundle all changesets in the repository')),
1235 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1235 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1236 ] + remoteopts,
1236 ] + remoteopts,
1237 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1237 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1238 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1238 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1239 def bundle(ui, repo, fname, dest=None, **opts):
1239 def bundle(ui, repo, fname, dest=None, **opts):
1240 """create a bundle file
1240 """create a bundle file
1241
1241
1242 Generate a bundle file containing data to be transferred to another
1242 Generate a bundle file containing data to be transferred to another
1243 repository.
1243 repository.
1244
1244
1245 To create a bundle containing all changesets, use -a/--all
1245 To create a bundle containing all changesets, use -a/--all
1246 (or --base null). Otherwise, hg assumes the destination will have
1246 (or --base null). Otherwise, hg assumes the destination will have
1247 all the nodes you specify with --base parameters. Otherwise, hg
1247 all the nodes you specify with --base parameters. Otherwise, hg
1248 will assume the repository has all the nodes in destination, or
1248 will assume the repository has all the nodes in destination, or
1249 default-push/default if no destination is specified, where destination
1249 default-push/default if no destination is specified, where destination
1250 is the repository you provide through DEST option.
1250 is the repository you provide through DEST option.
1251
1251
1252 You can change bundle format with the -t/--type option. See
1252 You can change bundle format with the -t/--type option. See
1253 :hg:`help bundlespec` for documentation on this format. By default,
1253 :hg:`help bundlespec` for documentation on this format. By default,
1254 the most appropriate format is used and compression defaults to
1254 the most appropriate format is used and compression defaults to
1255 bzip2.
1255 bzip2.
1256
1256
1257 The bundle file can then be transferred using conventional means
1257 The bundle file can then be transferred using conventional means
1258 and applied to another repository with the unbundle or pull
1258 and applied to another repository with the unbundle or pull
1259 command. This is useful when direct push and pull are not
1259 command. This is useful when direct push and pull are not
1260 available or when exporting an entire repository is undesirable.
1260 available or when exporting an entire repository is undesirable.
1261
1261
1262 Applying bundles preserves all changeset contents including
1262 Applying bundles preserves all changeset contents including
1263 permissions, copy/rename information, and revision history.
1263 permissions, copy/rename information, and revision history.
1264
1264
1265 Returns 0 on success, 1 if no changes found.
1265 Returns 0 on success, 1 if no changes found.
1266 """
1266 """
1267 opts = pycompat.byteskwargs(opts)
1267 opts = pycompat.byteskwargs(opts)
1268 revs = None
1268 revs = None
1269 if 'rev' in opts:
1269 if 'rev' in opts:
1270 revstrings = opts['rev']
1270 revstrings = opts['rev']
1271 revs = scmutil.revrange(repo, revstrings)
1271 revs = scmutil.revrange(repo, revstrings)
1272 if revstrings and not revs:
1272 if revstrings and not revs:
1273 raise error.Abort(_('no commits to bundle'))
1273 raise error.Abort(_('no commits to bundle'))
1274
1274
1275 bundletype = opts.get('type', 'bzip2').lower()
1275 bundletype = opts.get('type', 'bzip2').lower()
1276 try:
1276 try:
1277 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1277 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1278 except error.UnsupportedBundleSpecification as e:
1278 except error.UnsupportedBundleSpecification as e:
1279 raise error.Abort(pycompat.bytestr(e),
1279 raise error.Abort(pycompat.bytestr(e),
1280 hint=_("see 'hg help bundlespec' for supported "
1280 hint=_("see 'hg help bundlespec' for supported "
1281 "values for --type"))
1281 "values for --type"))
1282 cgversion = bundlespec.contentopts["cg.version"]
1282 cgversion = bundlespec.contentopts["cg.version"]
1283
1283
1284 # Packed bundles are a pseudo bundle format for now.
1284 # Packed bundles are a pseudo bundle format for now.
1285 if cgversion == 's1':
1285 if cgversion == 's1':
1286 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1286 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1287 hint=_("use 'hg debugcreatestreamclonebundle'"))
1287 hint=_("use 'hg debugcreatestreamclonebundle'"))
1288
1288
1289 if opts.get('all'):
1289 if opts.get('all'):
1290 if dest:
1290 if dest:
1291 raise error.Abort(_("--all is incompatible with specifying "
1291 raise error.Abort(_("--all is incompatible with specifying "
1292 "a destination"))
1292 "a destination"))
1293 if opts.get('base'):
1293 if opts.get('base'):
1294 ui.warn(_("ignoring --base because --all was specified\n"))
1294 ui.warn(_("ignoring --base because --all was specified\n"))
1295 base = [nullrev]
1295 base = [nullrev]
1296 else:
1296 else:
1297 base = scmutil.revrange(repo, opts.get('base'))
1297 base = scmutil.revrange(repo, opts.get('base'))
1298 if cgversion not in changegroup.supportedoutgoingversions(repo):
1298 if cgversion not in changegroup.supportedoutgoingversions(repo):
1299 raise error.Abort(_("repository does not support bundle version %s") %
1299 raise error.Abort(_("repository does not support bundle version %s") %
1300 cgversion)
1300 cgversion)
1301
1301
1302 if base:
1302 if base:
1303 if dest:
1303 if dest:
1304 raise error.Abort(_("--base is incompatible with specifying "
1304 raise error.Abort(_("--base is incompatible with specifying "
1305 "a destination"))
1305 "a destination"))
1306 common = [repo[rev].node() for rev in base]
1306 common = [repo[rev].node() for rev in base]
1307 heads = [repo[r].node() for r in revs] if revs else None
1307 heads = [repo[r].node() for r in revs] if revs else None
1308 outgoing = discovery.outgoing(repo, common, heads)
1308 outgoing = discovery.outgoing(repo, common, heads)
1309 else:
1309 else:
1310 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1310 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1311 dest, branches = hg.parseurl(dest, opts.get('branch'))
1311 dest, branches = hg.parseurl(dest, opts.get('branch'))
1312 other = hg.peer(repo, opts, dest)
1312 other = hg.peer(repo, opts, dest)
1313 revs = [repo[r].hex() for r in revs]
1313 revs = [repo[r].hex() for r in revs]
1314 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1314 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1315 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1315 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1316 outgoing = discovery.findcommonoutgoing(repo, other,
1316 outgoing = discovery.findcommonoutgoing(repo, other,
1317 onlyheads=heads,
1317 onlyheads=heads,
1318 force=opts.get('force'),
1318 force=opts.get('force'),
1319 portable=True)
1319 portable=True)
1320
1320
1321 if not outgoing.missing:
1321 if not outgoing.missing:
1322 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1322 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1323 return 1
1323 return 1
1324
1324
1325 if cgversion == '01': #bundle1
1325 if cgversion == '01': #bundle1
1326 bversion = 'HG10' + bundlespec.wirecompression
1326 bversion = 'HG10' + bundlespec.wirecompression
1327 bcompression = None
1327 bcompression = None
1328 elif cgversion in ('02', '03'):
1328 elif cgversion in ('02', '03'):
1329 bversion = 'HG20'
1329 bversion = 'HG20'
1330 bcompression = bundlespec.wirecompression
1330 bcompression = bundlespec.wirecompression
1331 else:
1331 else:
1332 raise error.ProgrammingError(
1332 raise error.ProgrammingError(
1333 'bundle: unexpected changegroup version %s' % cgversion)
1333 'bundle: unexpected changegroup version %s' % cgversion)
1334
1334
1335 # TODO compression options should be derived from bundlespec parsing.
1335 # TODO compression options should be derived from bundlespec parsing.
1336 # This is a temporary hack to allow adjusting bundle compression
1336 # This is a temporary hack to allow adjusting bundle compression
1337 # level without a) formalizing the bundlespec changes to declare it
1337 # level without a) formalizing the bundlespec changes to declare it
1338 # b) introducing a command flag.
1338 # b) introducing a command flag.
1339 compopts = {}
1339 compopts = {}
1340 complevel = ui.configint('experimental',
1340 complevel = ui.configint('experimental',
1341 'bundlecomplevel.' + bundlespec.compression)
1341 'bundlecomplevel.' + bundlespec.compression)
1342 if complevel is None:
1342 if complevel is None:
1343 complevel = ui.configint('experimental', 'bundlecomplevel')
1343 complevel = ui.configint('experimental', 'bundlecomplevel')
1344 if complevel is not None:
1344 if complevel is not None:
1345 compopts['level'] = complevel
1345 compopts['level'] = complevel
1346
1346
1347 # Allow overriding the bundling of obsmarker in phases through
1347 # Allow overriding the bundling of obsmarker in phases through
1348 # configuration while we don't have a bundle version that include them
1348 # configuration while we don't have a bundle version that include them
1349 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1349 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1350 bundlespec.contentopts['obsolescence'] = True
1350 bundlespec.contentopts['obsolescence'] = True
1351 if repo.ui.configbool('experimental', 'bundle-phases'):
1351 if repo.ui.configbool('experimental', 'bundle-phases'):
1352 bundlespec.contentopts['phases'] = True
1352 bundlespec.contentopts['phases'] = True
1353
1353
1354 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1354 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1355 bundlespec.contentopts, compression=bcompression,
1355 bundlespec.contentopts, compression=bcompression,
1356 compopts=compopts)
1356 compopts=compopts)
1357
1357
1358 @command('cat',
1358 @command('cat',
1359 [('o', 'output', '',
1359 [('o', 'output', '',
1360 _('print output to file with formatted name'), _('FORMAT')),
1360 _('print output to file with formatted name'), _('FORMAT')),
1361 ('r', 'rev', '', _('print the given revision'), _('REV')),
1361 ('r', 'rev', '', _('print the given revision'), _('REV')),
1362 ('', 'decode', None, _('apply any matching decode filter')),
1362 ('', 'decode', None, _('apply any matching decode filter')),
1363 ] + walkopts + formatteropts,
1363 ] + walkopts + formatteropts,
1364 _('[OPTION]... FILE...'),
1364 _('[OPTION]... FILE...'),
1365 helpcategory=command.CATEGORY_FILE_CONTENTS,
1365 helpcategory=command.CATEGORY_FILE_CONTENTS,
1366 inferrepo=True,
1366 inferrepo=True,
1367 intents={INTENT_READONLY})
1367 intents={INTENT_READONLY})
1368 def cat(ui, repo, file1, *pats, **opts):
1368 def cat(ui, repo, file1, *pats, **opts):
1369 """output the current or given revision of files
1369 """output the current or given revision of files
1370
1370
1371 Print the specified files as they were at the given revision. If
1371 Print the specified files as they were at the given revision. If
1372 no revision is given, the parent of the working directory is used.
1372 no revision is given, the parent of the working directory is used.
1373
1373
1374 Output may be to a file, in which case the name of the file is
1374 Output may be to a file, in which case the name of the file is
1375 given using a template string. See :hg:`help templates`. In addition
1375 given using a template string. See :hg:`help templates`. In addition
1376 to the common template keywords, the following formatting rules are
1376 to the common template keywords, the following formatting rules are
1377 supported:
1377 supported:
1378
1378
1379 :``%%``: literal "%" character
1379 :``%%``: literal "%" character
1380 :``%s``: basename of file being printed
1380 :``%s``: basename of file being printed
1381 :``%d``: dirname of file being printed, or '.' if in repository root
1381 :``%d``: dirname of file being printed, or '.' if in repository root
1382 :``%p``: root-relative path name of file being printed
1382 :``%p``: root-relative path name of file being printed
1383 :``%H``: changeset hash (40 hexadecimal digits)
1383 :``%H``: changeset hash (40 hexadecimal digits)
1384 :``%R``: changeset revision number
1384 :``%R``: changeset revision number
1385 :``%h``: short-form changeset hash (12 hexadecimal digits)
1385 :``%h``: short-form changeset hash (12 hexadecimal digits)
1386 :``%r``: zero-padded changeset revision number
1386 :``%r``: zero-padded changeset revision number
1387 :``%b``: basename of the exporting repository
1387 :``%b``: basename of the exporting repository
1388 :``\\``: literal "\\" character
1388 :``\\``: literal "\\" character
1389
1389
1390 .. container:: verbose
1390 .. container:: verbose
1391
1391
1392 Template:
1392 Template:
1393
1393
1394 The following keywords are supported in addition to the common template
1394 The following keywords are supported in addition to the common template
1395 keywords and functions. See also :hg:`help templates`.
1395 keywords and functions. See also :hg:`help templates`.
1396
1396
1397 :data: String. File content.
1397 :data: String. File content.
1398 :path: String. Repository-absolute path of the file.
1398 :path: String. Repository-absolute path of the file.
1399
1399
1400 Returns 0 on success.
1400 Returns 0 on success.
1401 """
1401 """
1402 opts = pycompat.byteskwargs(opts)
1402 opts = pycompat.byteskwargs(opts)
1403 rev = opts.get('rev')
1403 rev = opts.get('rev')
1404 if rev:
1404 if rev:
1405 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1405 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1406 ctx = scmutil.revsingle(repo, rev)
1406 ctx = scmutil.revsingle(repo, rev)
1407 m = scmutil.match(ctx, (file1,) + pats, opts)
1407 m = scmutil.match(ctx, (file1,) + pats, opts)
1408 fntemplate = opts.pop('output', '')
1408 fntemplate = opts.pop('output', '')
1409 if cmdutil.isstdiofilename(fntemplate):
1409 if cmdutil.isstdiofilename(fntemplate):
1410 fntemplate = ''
1410 fntemplate = ''
1411
1411
1412 if fntemplate:
1412 if fntemplate:
1413 fm = formatter.nullformatter(ui, 'cat', opts)
1413 fm = formatter.nullformatter(ui, 'cat', opts)
1414 else:
1414 else:
1415 ui.pager('cat')
1415 ui.pager('cat')
1416 fm = ui.formatter('cat', opts)
1416 fm = ui.formatter('cat', opts)
1417 with fm:
1417 with fm:
1418 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1418 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1419 **pycompat.strkwargs(opts))
1419 **pycompat.strkwargs(opts))
1420
1420
1421 @command('clone',
1421 @command('clone',
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1423 'directory (only a repository)')),
1423 'directory (only a repository)')),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1425 _('REV')),
1425 _('REV')),
1426 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1426 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1427 ' and its ancestors'), _('REV')),
1427 ' and its ancestors'), _('REV')),
1428 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1428 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1429 ' changesets and their ancestors'), _('BRANCH')),
1429 ' changesets and their ancestors'), _('BRANCH')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1431 ('', 'uncompressed', None,
1431 ('', 'uncompressed', None,
1432 _('an alias to --stream (DEPRECATED)')),
1432 _('an alias to --stream (DEPRECATED)')),
1433 ('', 'stream', None,
1433 ('', 'stream', None,
1434 _('clone with minimal data processing')),
1434 _('clone with minimal data processing')),
1435 ] + remoteopts,
1435 ] + remoteopts,
1436 _('[OPTION]... SOURCE [DEST]'),
1436 _('[OPTION]... SOURCE [DEST]'),
1437 helpcategory=command.CATEGORY_REPO_CREATION,
1437 helpcategory=command.CATEGORY_REPO_CREATION,
1438 helpbasic=True, norepo=True)
1438 helpbasic=True, norepo=True)
1439 def clone(ui, source, dest=None, **opts):
1439 def clone(ui, source, dest=None, **opts):
1440 """make a copy of an existing repository
1440 """make a copy of an existing repository
1441
1441
1442 Create a copy of an existing repository in a new directory.
1442 Create a copy of an existing repository in a new directory.
1443
1443
1444 If no destination directory name is specified, it defaults to the
1444 If no destination directory name is specified, it defaults to the
1445 basename of the source.
1445 basename of the source.
1446
1446
1447 The location of the source is added to the new repository's
1447 The location of the source is added to the new repository's
1448 ``.hg/hgrc`` file, as the default to be used for future pulls.
1448 ``.hg/hgrc`` file, as the default to be used for future pulls.
1449
1449
1450 Only local paths and ``ssh://`` URLs are supported as
1450 Only local paths and ``ssh://`` URLs are supported as
1451 destinations. For ``ssh://`` destinations, no working directory or
1451 destinations. For ``ssh://`` destinations, no working directory or
1452 ``.hg/hgrc`` will be created on the remote side.
1452 ``.hg/hgrc`` will be created on the remote side.
1453
1453
1454 If the source repository has a bookmark called '@' set, that
1454 If the source repository has a bookmark called '@' set, that
1455 revision will be checked out in the new repository by default.
1455 revision will be checked out in the new repository by default.
1456
1456
1457 To check out a particular version, use -u/--update, or
1457 To check out a particular version, use -u/--update, or
1458 -U/--noupdate to create a clone with no working directory.
1458 -U/--noupdate to create a clone with no working directory.
1459
1459
1460 To pull only a subset of changesets, specify one or more revisions
1460 To pull only a subset of changesets, specify one or more revisions
1461 identifiers with -r/--rev or branches with -b/--branch. The
1461 identifiers with -r/--rev or branches with -b/--branch. The
1462 resulting clone will contain only the specified changesets and
1462 resulting clone will contain only the specified changesets and
1463 their ancestors. These options (or 'clone src#rev dest') imply
1463 their ancestors. These options (or 'clone src#rev dest') imply
1464 --pull, even for local source repositories.
1464 --pull, even for local source repositories.
1465
1465
1466 In normal clone mode, the remote normalizes repository data into a common
1466 In normal clone mode, the remote normalizes repository data into a common
1467 exchange format and the receiving end translates this data into its local
1467 exchange format and the receiving end translates this data into its local
1468 storage format. --stream activates a different clone mode that essentially
1468 storage format. --stream activates a different clone mode that essentially
1469 copies repository files from the remote with minimal data processing. This
1469 copies repository files from the remote with minimal data processing. This
1470 significantly reduces the CPU cost of a clone both remotely and locally.
1470 significantly reduces the CPU cost of a clone both remotely and locally.
1471 However, it often increases the transferred data size by 30-40%. This can
1471 However, it often increases the transferred data size by 30-40%. This can
1472 result in substantially faster clones where I/O throughput is plentiful,
1472 result in substantially faster clones where I/O throughput is plentiful,
1473 especially for larger repositories. A side-effect of --stream clones is
1473 especially for larger repositories. A side-effect of --stream clones is
1474 that storage settings and requirements on the remote are applied locally:
1474 that storage settings and requirements on the remote are applied locally:
1475 a modern client may inherit legacy or inefficient storage used by the
1475 a modern client may inherit legacy or inefficient storage used by the
1476 remote or a legacy Mercurial client may not be able to clone from a
1476 remote or a legacy Mercurial client may not be able to clone from a
1477 modern Mercurial remote.
1477 modern Mercurial remote.
1478
1478
1479 .. note::
1479 .. note::
1480
1480
1481 Specifying a tag will include the tagged changeset but not the
1481 Specifying a tag will include the tagged changeset but not the
1482 changeset containing the tag.
1482 changeset containing the tag.
1483
1483
1484 .. container:: verbose
1484 .. container:: verbose
1485
1485
1486 For efficiency, hardlinks are used for cloning whenever the
1486 For efficiency, hardlinks are used for cloning whenever the
1487 source and destination are on the same filesystem (note this
1487 source and destination are on the same filesystem (note this
1488 applies only to the repository data, not to the working
1488 applies only to the repository data, not to the working
1489 directory). Some filesystems, such as AFS, implement hardlinking
1489 directory). Some filesystems, such as AFS, implement hardlinking
1490 incorrectly, but do not report errors. In these cases, use the
1490 incorrectly, but do not report errors. In these cases, use the
1491 --pull option to avoid hardlinking.
1491 --pull option to avoid hardlinking.
1492
1492
1493 Mercurial will update the working directory to the first applicable
1493 Mercurial will update the working directory to the first applicable
1494 revision from this list:
1494 revision from this list:
1495
1495
1496 a) null if -U or the source repository has no changesets
1496 a) null if -U or the source repository has no changesets
1497 b) if -u . and the source repository is local, the first parent of
1497 b) if -u . and the source repository is local, the first parent of
1498 the source repository's working directory
1498 the source repository's working directory
1499 c) the changeset specified with -u (if a branch name, this means the
1499 c) the changeset specified with -u (if a branch name, this means the
1500 latest head of that branch)
1500 latest head of that branch)
1501 d) the changeset specified with -r
1501 d) the changeset specified with -r
1502 e) the tipmost head specified with -b
1502 e) the tipmost head specified with -b
1503 f) the tipmost head specified with the url#branch source syntax
1503 f) the tipmost head specified with the url#branch source syntax
1504 g) the revision marked with the '@' bookmark, if present
1504 g) the revision marked with the '@' bookmark, if present
1505 h) the tipmost head of the default branch
1505 h) the tipmost head of the default branch
1506 i) tip
1506 i) tip
1507
1507
1508 When cloning from servers that support it, Mercurial may fetch
1508 When cloning from servers that support it, Mercurial may fetch
1509 pre-generated data from a server-advertised URL or inline from the
1509 pre-generated data from a server-advertised URL or inline from the
1510 same stream. When this is done, hooks operating on incoming changesets
1510 same stream. When this is done, hooks operating on incoming changesets
1511 and changegroups may fire more than once, once for each pre-generated
1511 and changegroups may fire more than once, once for each pre-generated
1512 bundle and as well as for any additional remaining data. In addition,
1512 bundle and as well as for any additional remaining data. In addition,
1513 if an error occurs, the repository may be rolled back to a partial
1513 if an error occurs, the repository may be rolled back to a partial
1514 clone. This behavior may change in future releases.
1514 clone. This behavior may change in future releases.
1515 See :hg:`help -e clonebundles` for more.
1515 See :hg:`help -e clonebundles` for more.
1516
1516
1517 Examples:
1517 Examples:
1518
1518
1519 - clone a remote repository to a new directory named hg/::
1519 - clone a remote repository to a new directory named hg/::
1520
1520
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1522
1522
1523 - create a lightweight local clone::
1523 - create a lightweight local clone::
1524
1524
1525 hg clone project/ project-feature/
1525 hg clone project/ project-feature/
1526
1526
1527 - clone from an absolute path on an ssh server (note double-slash)::
1527 - clone from an absolute path on an ssh server (note double-slash)::
1528
1528
1529 hg clone ssh://user@server//home/projects/alpha/
1529 hg clone ssh://user@server//home/projects/alpha/
1530
1530
1531 - do a streaming clone while checking out a specified version::
1531 - do a streaming clone while checking out a specified version::
1532
1532
1533 hg clone --stream http://server/repo -u 1.5
1533 hg clone --stream http://server/repo -u 1.5
1534
1534
1535 - create a repository without changesets after a particular revision::
1535 - create a repository without changesets after a particular revision::
1536
1536
1537 hg clone -r 04e544 experimental/ good/
1537 hg clone -r 04e544 experimental/ good/
1538
1538
1539 - clone (and track) a particular named branch::
1539 - clone (and track) a particular named branch::
1540
1540
1541 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1541 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1542
1542
1543 See :hg:`help urls` for details on specifying URLs.
1543 See :hg:`help urls` for details on specifying URLs.
1544
1544
1545 Returns 0 on success.
1545 Returns 0 on success.
1546 """
1546 """
1547 opts = pycompat.byteskwargs(opts)
1547 opts = pycompat.byteskwargs(opts)
1548 if opts.get('noupdate') and opts.get('updaterev'):
1548 if opts.get('noupdate') and opts.get('updaterev'):
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1550
1550
1551 # --include/--exclude can come from narrow or sparse.
1551 # --include/--exclude can come from narrow or sparse.
1552 includepats, excludepats = None, None
1552 includepats, excludepats = None, None
1553
1553
1554 # hg.clone() differentiates between None and an empty set. So make sure
1554 # hg.clone() differentiates between None and an empty set. So make sure
1555 # patterns are sets if narrow is requested without patterns.
1555 # patterns are sets if narrow is requested without patterns.
1556 if opts.get('narrow'):
1556 if opts.get('narrow'):
1557 includepats = set()
1557 includepats = set()
1558 excludepats = set()
1558 excludepats = set()
1559
1559
1560 if opts.get('include'):
1560 if opts.get('include'):
1561 includepats = narrowspec.parsepatterns(opts.get('include'))
1561 includepats = narrowspec.parsepatterns(opts.get('include'))
1562 if opts.get('exclude'):
1562 if opts.get('exclude'):
1563 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1563 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1564
1564
1565 r = hg.clone(ui, opts, source, dest,
1565 r = hg.clone(ui, opts, source, dest,
1566 pull=opts.get('pull'),
1566 pull=opts.get('pull'),
1567 stream=opts.get('stream') or opts.get('uncompressed'),
1567 stream=opts.get('stream') or opts.get('uncompressed'),
1568 revs=opts.get('rev'),
1568 revs=opts.get('rev'),
1569 update=opts.get('updaterev') or not opts.get('noupdate'),
1569 update=opts.get('updaterev') or not opts.get('noupdate'),
1570 branch=opts.get('branch'),
1570 branch=opts.get('branch'),
1571 shareopts=opts.get('shareopts'),
1571 shareopts=opts.get('shareopts'),
1572 storeincludepats=includepats,
1572 storeincludepats=includepats,
1573 storeexcludepats=excludepats,
1573 storeexcludepats=excludepats,
1574 depth=opts.get('depth') or None)
1574 depth=opts.get('depth') or None)
1575
1575
1576 return r is None
1576 return r is None
1577
1577
1578 @command('commit|ci',
1578 @command('commit|ci',
1579 [('A', 'addremove', None,
1579 [('A', 'addremove', None,
1580 _('mark new/missing files as added/removed before committing')),
1580 _('mark new/missing files as added/removed before committing')),
1581 ('', 'close-branch', None,
1581 ('', 'close-branch', None,
1582 _('mark a branch head as closed')),
1582 _('mark a branch head as closed')),
1583 ('', 'amend', None, _('amend the parent of the working directory')),
1583 ('', 'amend', None, _('amend the parent of the working directory')),
1584 ('s', 'secret', None, _('use the secret phase for committing')),
1584 ('s', 'secret', None, _('use the secret phase for committing')),
1585 ('e', 'edit', None, _('invoke editor on commit messages')),
1585 ('e', 'edit', None, _('invoke editor on commit messages')),
1586 ('i', 'interactive', None, _('use interactive mode')),
1586 ('i', 'interactive', None, _('use interactive mode')),
1587 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1587 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1588 _('[OPTION]... [FILE]...'),
1588 _('[OPTION]... [FILE]...'),
1589 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1589 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1590 inferrepo=True)
1590 inferrepo=True)
1591 def commit(ui, repo, *pats, **opts):
1591 def commit(ui, repo, *pats, **opts):
1592 """commit the specified files or all outstanding changes
1592 """commit the specified files or all outstanding changes
1593
1593
1594 Commit changes to the given files into the repository. Unlike a
1594 Commit changes to the given files into the repository. Unlike a
1595 centralized SCM, this operation is a local operation. See
1595 centralized SCM, this operation is a local operation. See
1596 :hg:`push` for a way to actively distribute your changes.
1596 :hg:`push` for a way to actively distribute your changes.
1597
1597
1598 If a list of files is omitted, all changes reported by :hg:`status`
1598 If a list of files is omitted, all changes reported by :hg:`status`
1599 will be committed.
1599 will be committed.
1600
1600
1601 If you are committing the result of a merge, do not provide any
1601 If you are committing the result of a merge, do not provide any
1602 filenames or -I/-X filters.
1602 filenames or -I/-X filters.
1603
1603
1604 If no commit message is specified, Mercurial starts your
1604 If no commit message is specified, Mercurial starts your
1605 configured editor where you can enter a message. In case your
1605 configured editor where you can enter a message. In case your
1606 commit fails, you will find a backup of your message in
1606 commit fails, you will find a backup of your message in
1607 ``.hg/last-message.txt``.
1607 ``.hg/last-message.txt``.
1608
1608
1609 The --close-branch flag can be used to mark the current branch
1609 The --close-branch flag can be used to mark the current branch
1610 head closed. When all heads of a branch are closed, the branch
1610 head closed. When all heads of a branch are closed, the branch
1611 will be considered closed and no longer listed.
1611 will be considered closed and no longer listed.
1612
1612
1613 The --amend flag can be used to amend the parent of the
1613 The --amend flag can be used to amend the parent of the
1614 working directory with a new commit that contains the changes
1614 working directory with a new commit that contains the changes
1615 in the parent in addition to those currently reported by :hg:`status`,
1615 in the parent in addition to those currently reported by :hg:`status`,
1616 if there are any. The old commit is stored in a backup bundle in
1616 if there are any. The old commit is stored in a backup bundle in
1617 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1617 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1618 on how to restore it).
1618 on how to restore it).
1619
1619
1620 Message, user and date are taken from the amended commit unless
1620 Message, user and date are taken from the amended commit unless
1621 specified. When a message isn't specified on the command line,
1621 specified. When a message isn't specified on the command line,
1622 the editor will open with the message of the amended commit.
1622 the editor will open with the message of the amended commit.
1623
1623
1624 It is not possible to amend public changesets (see :hg:`help phases`)
1624 It is not possible to amend public changesets (see :hg:`help phases`)
1625 or changesets that have children.
1625 or changesets that have children.
1626
1626
1627 See :hg:`help dates` for a list of formats valid for -d/--date.
1627 See :hg:`help dates` for a list of formats valid for -d/--date.
1628
1628
1629 Returns 0 on success, 1 if nothing changed.
1629 Returns 0 on success, 1 if nothing changed.
1630
1630
1631 .. container:: verbose
1631 .. container:: verbose
1632
1632
1633 Examples:
1633 Examples:
1634
1634
1635 - commit all files ending in .py::
1635 - commit all files ending in .py::
1636
1636
1637 hg commit --include "set:**.py"
1637 hg commit --include "set:**.py"
1638
1638
1639 - commit all non-binary files::
1639 - commit all non-binary files::
1640
1640
1641 hg commit --exclude "set:binary()"
1641 hg commit --exclude "set:binary()"
1642
1642
1643 - amend the current commit and set the date to now::
1643 - amend the current commit and set the date to now::
1644
1644
1645 hg commit --amend --date now
1645 hg commit --amend --date now
1646 """
1646 """
1647 with repo.wlock(), repo.lock():
1647 with repo.wlock(), repo.lock():
1648 return _docommit(ui, repo, *pats, **opts)
1648 return _docommit(ui, repo, *pats, **opts)
1649
1649
1650 def _docommit(ui, repo, *pats, **opts):
1650 def _docommit(ui, repo, *pats, **opts):
1651 if opts.get(r'interactive'):
1651 if opts.get(r'interactive'):
1652 opts.pop(r'interactive')
1652 opts.pop(r'interactive')
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1654 cmdutil.recordfilter, *pats,
1654 cmdutil.recordfilter, *pats,
1655 **opts)
1655 **opts)
1656 # ret can be 0 (no changes to record) or the value returned by
1656 # ret can be 0 (no changes to record) or the value returned by
1657 # commit(), 1 if nothing changed or None on success.
1657 # commit(), 1 if nothing changed or None on success.
1658 return 1 if ret == 0 else ret
1658 return 1 if ret == 0 else ret
1659
1659
1660 opts = pycompat.byteskwargs(opts)
1660 opts = pycompat.byteskwargs(opts)
1661 if opts.get('subrepos'):
1661 if opts.get('subrepos'):
1662 if opts.get('amend'):
1662 if opts.get('amend'):
1663 raise error.Abort(_('cannot amend with --subrepos'))
1663 raise error.Abort(_('cannot amend with --subrepos'))
1664 # Let --subrepos on the command line override config setting.
1664 # Let --subrepos on the command line override config setting.
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1666
1666
1667 cmdutil.checkunfinished(repo, commit=True)
1667 cmdutil.checkunfinished(repo, commit=True)
1668
1668
1669 branch = repo[None].branch()
1669 branch = repo[None].branch()
1670 bheads = repo.branchheads(branch)
1670 bheads = repo.branchheads(branch)
1671
1671
1672 extra = {}
1672 extra = {}
1673 if opts.get('close_branch'):
1673 if opts.get('close_branch'):
1674 extra['close'] = '1'
1674 extra['close'] = '1'
1675
1675
1676 if not bheads:
1676 if not bheads:
1677 raise error.Abort(_('can only close branch heads'))
1677 raise error.Abort(_('can only close branch heads'))
1678 elif opts.get('amend'):
1678 elif opts.get('amend'):
1679 if repo['.'].p1().branch() != branch and \
1679 if repo['.'].p1().branch() != branch and \
1680 repo['.'].p2().branch() != branch:
1680 repo['.'].p2().branch() != branch:
1681 raise error.Abort(_('can only close branch heads'))
1681 raise error.Abort(_('can only close branch heads'))
1682
1682
1683 if opts.get('amend'):
1683 if opts.get('amend'):
1684 if ui.configbool('ui', 'commitsubrepos'):
1684 if ui.configbool('ui', 'commitsubrepos'):
1685 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1685 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1686
1686
1687 old = repo['.']
1687 old = repo['.']
1688 rewriteutil.precheck(repo, [old.rev()], 'amend')
1688 rewriteutil.precheck(repo, [old.rev()], 'amend')
1689
1689
1690 # Currently histedit gets confused if an amend happens while histedit
1690 # Currently histedit gets confused if an amend happens while histedit
1691 # is in progress. Since we have a checkunfinished command, we are
1691 # is in progress. Since we have a checkunfinished command, we are
1692 # temporarily honoring it.
1692 # temporarily honoring it.
1693 #
1693 #
1694 # Note: eventually this guard will be removed. Please do not expect
1694 # Note: eventually this guard will be removed. Please do not expect
1695 # this behavior to remain.
1695 # this behavior to remain.
1696 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1696 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1697 cmdutil.checkunfinished(repo)
1697 cmdutil.checkunfinished(repo)
1698
1698
1699 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1699 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1700 if node == old.node():
1700 if node == old.node():
1701 ui.status(_("nothing changed\n"))
1701 ui.status(_("nothing changed\n"))
1702 return 1
1702 return 1
1703 else:
1703 else:
1704 def commitfunc(ui, repo, message, match, opts):
1704 def commitfunc(ui, repo, message, match, opts):
1705 overrides = {}
1705 overrides = {}
1706 if opts.get('secret'):
1706 if opts.get('secret'):
1707 overrides[('phases', 'new-commit')] = 'secret'
1707 overrides[('phases', 'new-commit')] = 'secret'
1708
1708
1709 baseui = repo.baseui
1709 baseui = repo.baseui
1710 with baseui.configoverride(overrides, 'commit'):
1710 with baseui.configoverride(overrides, 'commit'):
1711 with ui.configoverride(overrides, 'commit'):
1711 with ui.configoverride(overrides, 'commit'):
1712 editform = cmdutil.mergeeditform(repo[None],
1712 editform = cmdutil.mergeeditform(repo[None],
1713 'commit.normal')
1713 'commit.normal')
1714 editor = cmdutil.getcommiteditor(
1714 editor = cmdutil.getcommiteditor(
1715 editform=editform, **pycompat.strkwargs(opts))
1715 editform=editform, **pycompat.strkwargs(opts))
1716 return repo.commit(message,
1716 return repo.commit(message,
1717 opts.get('user'),
1717 opts.get('user'),
1718 opts.get('date'),
1718 opts.get('date'),
1719 match,
1719 match,
1720 editor=editor,
1720 editor=editor,
1721 extra=extra)
1721 extra=extra)
1722
1722
1723 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1723 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1724
1724
1725 if not node:
1725 if not node:
1726 stat = cmdutil.postcommitstatus(repo, pats, opts)
1726 stat = cmdutil.postcommitstatus(repo, pats, opts)
1727 if stat[3]:
1727 if stat[3]:
1728 ui.status(_("nothing changed (%d missing files, see "
1728 ui.status(_("nothing changed (%d missing files, see "
1729 "'hg status')\n") % len(stat[3]))
1729 "'hg status')\n") % len(stat[3]))
1730 else:
1730 else:
1731 ui.status(_("nothing changed\n"))
1731 ui.status(_("nothing changed\n"))
1732 return 1
1732 return 1
1733
1733
1734 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1734 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1735
1735
1736 @command('config|showconfig|debugconfig',
1736 @command('config|showconfig|debugconfig',
1737 [('u', 'untrusted', None, _('show untrusted configuration options')),
1737 [('u', 'untrusted', None, _('show untrusted configuration options')),
1738 ('e', 'edit', None, _('edit user config')),
1738 ('e', 'edit', None, _('edit user config')),
1739 ('l', 'local', None, _('edit repository config')),
1739 ('l', 'local', None, _('edit repository config')),
1740 ('g', 'global', None, _('edit global config'))] + formatteropts,
1740 ('g', 'global', None, _('edit global config'))] + formatteropts,
1741 _('[-u] [NAME]...'),
1741 _('[-u] [NAME]...'),
1742 helpcategory=command.CATEGORY_HELP,
1742 helpcategory=command.CATEGORY_HELP,
1743 optionalrepo=True,
1743 optionalrepo=True,
1744 intents={INTENT_READONLY})
1744 intents={INTENT_READONLY})
1745 def config(ui, repo, *values, **opts):
1745 def config(ui, repo, *values, **opts):
1746 """show combined config settings from all hgrc files
1746 """show combined config settings from all hgrc files
1747
1747
1748 With no arguments, print names and values of all config items.
1748 With no arguments, print names and values of all config items.
1749
1749
1750 With one argument of the form section.name, print just the value
1750 With one argument of the form section.name, print just the value
1751 of that config item.
1751 of that config item.
1752
1752
1753 With multiple arguments, print names and values of all config
1753 With multiple arguments, print names and values of all config
1754 items with matching section names or section.names.
1754 items with matching section names or section.names.
1755
1755
1756 With --edit, start an editor on the user-level config file. With
1756 With --edit, start an editor on the user-level config file. With
1757 --global, edit the system-wide config file. With --local, edit the
1757 --global, edit the system-wide config file. With --local, edit the
1758 repository-level config file.
1758 repository-level config file.
1759
1759
1760 With --debug, the source (filename and line number) is printed
1760 With --debug, the source (filename and line number) is printed
1761 for each config item.
1761 for each config item.
1762
1762
1763 See :hg:`help config` for more information about config files.
1763 See :hg:`help config` for more information about config files.
1764
1764
1765 .. container:: verbose
1765 .. container:: verbose
1766
1766
1767 Template:
1767 Template:
1768
1768
1769 The following keywords are supported. See also :hg:`help templates`.
1769 The following keywords are supported. See also :hg:`help templates`.
1770
1770
1771 :name: String. Config name.
1771 :name: String. Config name.
1772 :source: String. Filename and line number where the item is defined.
1772 :source: String. Filename and line number where the item is defined.
1773 :value: String. Config value.
1773 :value: String. Config value.
1774
1774
1775 Returns 0 on success, 1 if NAME does not exist.
1775 Returns 0 on success, 1 if NAME does not exist.
1776
1776
1777 """
1777 """
1778
1778
1779 opts = pycompat.byteskwargs(opts)
1779 opts = pycompat.byteskwargs(opts)
1780 if opts.get('edit') or opts.get('local') or opts.get('global'):
1780 if opts.get('edit') or opts.get('local') or opts.get('global'):
1781 if opts.get('local') and opts.get('global'):
1781 if opts.get('local') and opts.get('global'):
1782 raise error.Abort(_("can't use --local and --global together"))
1782 raise error.Abort(_("can't use --local and --global together"))
1783
1783
1784 if opts.get('local'):
1784 if opts.get('local'):
1785 if not repo:
1785 if not repo:
1786 raise error.Abort(_("can't use --local outside a repository"))
1786 raise error.Abort(_("can't use --local outside a repository"))
1787 paths = [repo.vfs.join('hgrc')]
1787 paths = [repo.vfs.join('hgrc')]
1788 elif opts.get('global'):
1788 elif opts.get('global'):
1789 paths = rcutil.systemrcpath()
1789 paths = rcutil.systemrcpath()
1790 else:
1790 else:
1791 paths = rcutil.userrcpath()
1791 paths = rcutil.userrcpath()
1792
1792
1793 for f in paths:
1793 for f in paths:
1794 if os.path.exists(f):
1794 if os.path.exists(f):
1795 break
1795 break
1796 else:
1796 else:
1797 if opts.get('global'):
1797 if opts.get('global'):
1798 samplehgrc = uimod.samplehgrcs['global']
1798 samplehgrc = uimod.samplehgrcs['global']
1799 elif opts.get('local'):
1799 elif opts.get('local'):
1800 samplehgrc = uimod.samplehgrcs['local']
1800 samplehgrc = uimod.samplehgrcs['local']
1801 else:
1801 else:
1802 samplehgrc = uimod.samplehgrcs['user']
1802 samplehgrc = uimod.samplehgrcs['user']
1803
1803
1804 f = paths[0]
1804 f = paths[0]
1805 fp = open(f, "wb")
1805 fp = open(f, "wb")
1806 fp.write(util.tonativeeol(samplehgrc))
1806 fp.write(util.tonativeeol(samplehgrc))
1807 fp.close()
1807 fp.close()
1808
1808
1809 editor = ui.geteditor()
1809 editor = ui.geteditor()
1810 ui.system("%s \"%s\"" % (editor, f),
1810 ui.system("%s \"%s\"" % (editor, f),
1811 onerr=error.Abort, errprefix=_("edit failed"),
1811 onerr=error.Abort, errprefix=_("edit failed"),
1812 blockedtag='config_edit')
1812 blockedtag='config_edit')
1813 return
1813 return
1814 ui.pager('config')
1814 ui.pager('config')
1815 fm = ui.formatter('config', opts)
1815 fm = ui.formatter('config', opts)
1816 for t, f in rcutil.rccomponents():
1816 for t, f in rcutil.rccomponents():
1817 if t == 'path':
1817 if t == 'path':
1818 ui.debug('read config from: %s\n' % f)
1818 ui.debug('read config from: %s\n' % f)
1819 elif t == 'items':
1819 elif t == 'items':
1820 for section, name, value, source in f:
1820 for section, name, value, source in f:
1821 ui.debug('set config by: %s\n' % source)
1821 ui.debug('set config by: %s\n' % source)
1822 else:
1822 else:
1823 raise error.ProgrammingError('unknown rctype: %s' % t)
1823 raise error.ProgrammingError('unknown rctype: %s' % t)
1824 untrusted = bool(opts.get('untrusted'))
1824 untrusted = bool(opts.get('untrusted'))
1825
1825
1826 selsections = selentries = []
1826 selsections = selentries = []
1827 if values:
1827 if values:
1828 selsections = [v for v in values if '.' not in v]
1828 selsections = [v for v in values if '.' not in v]
1829 selentries = [v for v in values if '.' in v]
1829 selentries = [v for v in values if '.' in v]
1830 uniquesel = (len(selentries) == 1 and not selsections)
1830 uniquesel = (len(selentries) == 1 and not selsections)
1831 selsections = set(selsections)
1831 selsections = set(selsections)
1832 selentries = set(selentries)
1832 selentries = set(selentries)
1833
1833
1834 matched = False
1834 matched = False
1835 for section, name, value in ui.walkconfig(untrusted=untrusted):
1835 for section, name, value in ui.walkconfig(untrusted=untrusted):
1836 source = ui.configsource(section, name, untrusted)
1836 source = ui.configsource(section, name, untrusted)
1837 value = pycompat.bytestr(value)
1837 value = pycompat.bytestr(value)
1838 if fm.isplain():
1838 if fm.isplain():
1839 source = source or 'none'
1839 source = source or 'none'
1840 value = value.replace('\n', '\\n')
1840 value = value.replace('\n', '\\n')
1841 entryname = section + '.' + name
1841 entryname = section + '.' + name
1842 if values and not (section in selsections or entryname in selentries):
1842 if values and not (section in selsections or entryname in selentries):
1843 continue
1843 continue
1844 fm.startitem()
1844 fm.startitem()
1845 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1845 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1846 if uniquesel:
1846 if uniquesel:
1847 fm.data(name=entryname)
1847 fm.data(name=entryname)
1848 fm.write('value', '%s\n', value)
1848 fm.write('value', '%s\n', value)
1849 else:
1849 else:
1850 fm.write('name value', '%s=%s\n', entryname, value)
1850 fm.write('name value', '%s=%s\n', entryname, value)
1851 matched = True
1851 matched = True
1852 fm.end()
1852 fm.end()
1853 if matched:
1853 if matched:
1854 return 0
1854 return 0
1855 return 1
1855 return 1
1856
1856
1857 @command('copy|cp',
1857 @command('copy|cp',
1858 [('A', 'after', None, _('record a copy that has already occurred')),
1858 [('A', 'after', None, _('record a copy that has already occurred')),
1859 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1859 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1860 ] + walkopts + dryrunopts,
1860 ] + walkopts + dryrunopts,
1861 _('[OPTION]... [SOURCE]... DEST'),
1861 _('[OPTION]... [SOURCE]... DEST'),
1862 helpcategory=command.CATEGORY_FILE_CONTENTS)
1862 helpcategory=command.CATEGORY_FILE_CONTENTS)
1863 def copy(ui, repo, *pats, **opts):
1863 def copy(ui, repo, *pats, **opts):
1864 """mark files as copied for the next commit
1864 """mark files as copied for the next commit
1865
1865
1866 Mark dest as having copies of source files. If dest is a
1866 Mark dest as having copies of source files. If dest is a
1867 directory, copies are put in that directory. If dest is a file,
1867 directory, copies are put in that directory. If dest is a file,
1868 the source must be a single file.
1868 the source must be a single file.
1869
1869
1870 By default, this command copies the contents of files as they
1870 By default, this command copies the contents of files as they
1871 exist in the working directory. If invoked with -A/--after, the
1871 exist in the working directory. If invoked with -A/--after, the
1872 operation is recorded, but no copying is performed.
1872 operation is recorded, but no copying is performed.
1873
1873
1874 This command takes effect with the next commit. To undo a copy
1874 This command takes effect with the next commit. To undo a copy
1875 before that, see :hg:`revert`.
1875 before that, see :hg:`revert`.
1876
1876
1877 Returns 0 on success, 1 if errors are encountered.
1877 Returns 0 on success, 1 if errors are encountered.
1878 """
1878 """
1879 opts = pycompat.byteskwargs(opts)
1879 opts = pycompat.byteskwargs(opts)
1880 with repo.wlock(False):
1880 with repo.wlock(False):
1881 return cmdutil.copy(ui, repo, pats, opts)
1881 return cmdutil.copy(ui, repo, pats, opts)
1882
1882
1883 @command(
1883 @command(
1884 'debugcommands', [], _('[COMMAND]'),
1884 'debugcommands', [], _('[COMMAND]'),
1885 helpcategory=command.CATEGORY_HELP,
1885 helpcategory=command.CATEGORY_HELP,
1886 norepo=True)
1886 norepo=True)
1887 def debugcommands(ui, cmd='', *args):
1887 def debugcommands(ui, cmd='', *args):
1888 """list all available commands and options"""
1888 """list all available commands and options"""
1889 for cmd, vals in sorted(table.iteritems()):
1889 for cmd, vals in sorted(table.iteritems()):
1890 cmd = cmd.split('|')[0]
1890 cmd = cmd.split('|')[0]
1891 opts = ', '.join([i[1] for i in vals[1]])
1891 opts = ', '.join([i[1] for i in vals[1]])
1892 ui.write('%s: %s\n' % (cmd, opts))
1892 ui.write('%s: %s\n' % (cmd, opts))
1893
1893
1894 @command('debugcomplete',
1894 @command('debugcomplete',
1895 [('o', 'options', None, _('show the command options'))],
1895 [('o', 'options', None, _('show the command options'))],
1896 _('[-o] CMD'),
1896 _('[-o] CMD'),
1897 helpcategory=command.CATEGORY_HELP,
1897 helpcategory=command.CATEGORY_HELP,
1898 norepo=True)
1898 norepo=True)
1899 def debugcomplete(ui, cmd='', **opts):
1899 def debugcomplete(ui, cmd='', **opts):
1900 """returns the completion list associated with the given command"""
1900 """returns the completion list associated with the given command"""
1901
1901
1902 if opts.get(r'options'):
1902 if opts.get(r'options'):
1903 options = []
1903 options = []
1904 otables = [globalopts]
1904 otables = [globalopts]
1905 if cmd:
1905 if cmd:
1906 aliases, entry = cmdutil.findcmd(cmd, table, False)
1906 aliases, entry = cmdutil.findcmd(cmd, table, False)
1907 otables.append(entry[1])
1907 otables.append(entry[1])
1908 for t in otables:
1908 for t in otables:
1909 for o in t:
1909 for o in t:
1910 if "(DEPRECATED)" in o[3]:
1910 if "(DEPRECATED)" in o[3]:
1911 continue
1911 continue
1912 if o[0]:
1912 if o[0]:
1913 options.append('-%s' % o[0])
1913 options.append('-%s' % o[0])
1914 options.append('--%s' % o[1])
1914 options.append('--%s' % o[1])
1915 ui.write("%s\n" % "\n".join(options))
1915 ui.write("%s\n" % "\n".join(options))
1916 return
1916 return
1917
1917
1918 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1918 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1919 if ui.verbose:
1919 if ui.verbose:
1920 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1920 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1921 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1921 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1922
1922
1923 @command('diff',
1923 @command('diff',
1924 [('r', 'rev', [], _('revision'), _('REV')),
1924 [('r', 'rev', [], _('revision'), _('REV')),
1925 ('c', 'change', '', _('change made by revision'), _('REV'))
1925 ('c', 'change', '', _('change made by revision'), _('REV'))
1926 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1926 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1927 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1927 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1928 helpcategory=command.CATEGORY_FILE_CONTENTS,
1928 helpcategory=command.CATEGORY_FILE_CONTENTS,
1929 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1929 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1930 def diff(ui, repo, *pats, **opts):
1930 def diff(ui, repo, *pats, **opts):
1931 """diff repository (or selected files)
1931 """diff repository (or selected files)
1932
1932
1933 Show differences between revisions for the specified files.
1933 Show differences between revisions for the specified files.
1934
1934
1935 Differences between files are shown using the unified diff format.
1935 Differences between files are shown using the unified diff format.
1936
1936
1937 .. note::
1937 .. note::
1938
1938
1939 :hg:`diff` may generate unexpected results for merges, as it will
1939 :hg:`diff` may generate unexpected results for merges, as it will
1940 default to comparing against the working directory's first
1940 default to comparing against the working directory's first
1941 parent changeset if no revisions are specified.
1941 parent changeset if no revisions are specified.
1942
1942
1943 When two revision arguments are given, then changes are shown
1943 When two revision arguments are given, then changes are shown
1944 between those revisions. If only one revision is specified then
1944 between those revisions. If only one revision is specified then
1945 that revision is compared to the working directory, and, when no
1945 that revision is compared to the working directory, and, when no
1946 revisions are specified, the working directory files are compared
1946 revisions are specified, the working directory files are compared
1947 to its first parent.
1947 to its first parent.
1948
1948
1949 Alternatively you can specify -c/--change with a revision to see
1949 Alternatively you can specify -c/--change with a revision to see
1950 the changes in that changeset relative to its first parent.
1950 the changes in that changeset relative to its first parent.
1951
1951
1952 Without the -a/--text option, diff will avoid generating diffs of
1952 Without the -a/--text option, diff will avoid generating diffs of
1953 files it detects as binary. With -a, diff will generate a diff
1953 files it detects as binary. With -a, diff will generate a diff
1954 anyway, probably with undesirable results.
1954 anyway, probably with undesirable results.
1955
1955
1956 Use the -g/--git option to generate diffs in the git extended diff
1956 Use the -g/--git option to generate diffs in the git extended diff
1957 format. For more information, read :hg:`help diffs`.
1957 format. For more information, read :hg:`help diffs`.
1958
1958
1959 .. container:: verbose
1959 .. container:: verbose
1960
1960
1961 Examples:
1961 Examples:
1962
1962
1963 - compare a file in the current working directory to its parent::
1963 - compare a file in the current working directory to its parent::
1964
1964
1965 hg diff foo.c
1965 hg diff foo.c
1966
1966
1967 - compare two historical versions of a directory, with rename info::
1967 - compare two historical versions of a directory, with rename info::
1968
1968
1969 hg diff --git -r 1.0:1.2 lib/
1969 hg diff --git -r 1.0:1.2 lib/
1970
1970
1971 - get change stats relative to the last change on some date::
1971 - get change stats relative to the last change on some date::
1972
1972
1973 hg diff --stat -r "date('may 2')"
1973 hg diff --stat -r "date('may 2')"
1974
1974
1975 - diff all newly-added files that contain a keyword::
1975 - diff all newly-added files that contain a keyword::
1976
1976
1977 hg diff "set:added() and grep(GNU)"
1977 hg diff "set:added() and grep(GNU)"
1978
1978
1979 - compare a revision and its parents::
1979 - compare a revision and its parents::
1980
1980
1981 hg diff -c 9353 # compare against first parent
1981 hg diff -c 9353 # compare against first parent
1982 hg diff -r 9353^:9353 # same using revset syntax
1982 hg diff -r 9353^:9353 # same using revset syntax
1983 hg diff -r 9353^2:9353 # compare against the second parent
1983 hg diff -r 9353^2:9353 # compare against the second parent
1984
1984
1985 Returns 0 on success.
1985 Returns 0 on success.
1986 """
1986 """
1987
1987
1988 opts = pycompat.byteskwargs(opts)
1988 opts = pycompat.byteskwargs(opts)
1989 revs = opts.get('rev')
1989 revs = opts.get('rev')
1990 change = opts.get('change')
1990 change = opts.get('change')
1991 stat = opts.get('stat')
1991 stat = opts.get('stat')
1992 reverse = opts.get('reverse')
1992 reverse = opts.get('reverse')
1993
1993
1994 if revs and change:
1994 if revs and change:
1995 msg = _('cannot specify --rev and --change at the same time')
1995 msg = _('cannot specify --rev and --change at the same time')
1996 raise error.Abort(msg)
1996 raise error.Abort(msg)
1997 elif change:
1997 elif change:
1998 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1998 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1999 ctx2 = scmutil.revsingle(repo, change, None)
1999 ctx2 = scmutil.revsingle(repo, change, None)
2000 ctx1 = ctx2.p1()
2000 ctx1 = ctx2.p1()
2001 else:
2001 else:
2002 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2002 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2003 ctx1, ctx2 = scmutil.revpair(repo, revs)
2003 ctx1, ctx2 = scmutil.revpair(repo, revs)
2004 node1, node2 = ctx1.node(), ctx2.node()
2004 node1, node2 = ctx1.node(), ctx2.node()
2005
2005
2006 if reverse:
2006 if reverse:
2007 node1, node2 = node2, node1
2007 node1, node2 = node2, node1
2008
2008
2009 diffopts = patch.diffallopts(ui, opts)
2009 diffopts = patch.diffallopts(ui, opts)
2010 m = scmutil.match(ctx2, pats, opts)
2010 m = scmutil.match(ctx2, pats, opts)
2011 m = repo.narrowmatch(m)
2011 m = repo.narrowmatch(m)
2012 ui.pager('diff')
2012 ui.pager('diff')
2013 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2013 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2014 listsubrepos=opts.get('subrepos'),
2014 listsubrepos=opts.get('subrepos'),
2015 root=opts.get('root'))
2015 root=opts.get('root'))
2016
2016
2017 @command('export',
2017 @command('export',
2018 [('B', 'bookmark', '',
2018 [('B', 'bookmark', '',
2019 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2019 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2020 ('o', 'output', '',
2020 ('o', 'output', '',
2021 _('print output to file with formatted name'), _('FORMAT')),
2021 _('print output to file with formatted name'), _('FORMAT')),
2022 ('', 'switch-parent', None, _('diff against the second parent')),
2022 ('', 'switch-parent', None, _('diff against the second parent')),
2023 ('r', 'rev', [], _('revisions to export'), _('REV')),
2023 ('r', 'rev', [], _('revisions to export'), _('REV')),
2024 ] + diffopts + formatteropts,
2024 ] + diffopts + formatteropts,
2025 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2025 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2026 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2026 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2027 helpbasic=True, intents={INTENT_READONLY})
2027 helpbasic=True, intents={INTENT_READONLY})
2028 def export(ui, repo, *changesets, **opts):
2028 def export(ui, repo, *changesets, **opts):
2029 """dump the header and diffs for one or more changesets
2029 """dump the header and diffs for one or more changesets
2030
2030
2031 Print the changeset header and diffs for one or more revisions.
2031 Print the changeset header and diffs for one or more revisions.
2032 If no revision is given, the parent of the working directory is used.
2032 If no revision is given, the parent of the working directory is used.
2033
2033
2034 The information shown in the changeset header is: author, date,
2034 The information shown in the changeset header is: author, date,
2035 branch name (if non-default), changeset hash, parent(s) and commit
2035 branch name (if non-default), changeset hash, parent(s) and commit
2036 comment.
2036 comment.
2037
2037
2038 .. note::
2038 .. note::
2039
2039
2040 :hg:`export` may generate unexpected diff output for merge
2040 :hg:`export` may generate unexpected diff output for merge
2041 changesets, as it will compare the merge changeset against its
2041 changesets, as it will compare the merge changeset against its
2042 first parent only.
2042 first parent only.
2043
2043
2044 Output may be to a file, in which case the name of the file is
2044 Output may be to a file, in which case the name of the file is
2045 given using a template string. See :hg:`help templates`. In addition
2045 given using a template string. See :hg:`help templates`. In addition
2046 to the common template keywords, the following formatting rules are
2046 to the common template keywords, the following formatting rules are
2047 supported:
2047 supported:
2048
2048
2049 :``%%``: literal "%" character
2049 :``%%``: literal "%" character
2050 :``%H``: changeset hash (40 hexadecimal digits)
2050 :``%H``: changeset hash (40 hexadecimal digits)
2051 :``%N``: number of patches being generated
2051 :``%N``: number of patches being generated
2052 :``%R``: changeset revision number
2052 :``%R``: changeset revision number
2053 :``%b``: basename of the exporting repository
2053 :``%b``: basename of the exporting repository
2054 :``%h``: short-form changeset hash (12 hexadecimal digits)
2054 :``%h``: short-form changeset hash (12 hexadecimal digits)
2055 :``%m``: first line of the commit message (only alphanumeric characters)
2055 :``%m``: first line of the commit message (only alphanumeric characters)
2056 :``%n``: zero-padded sequence number, starting at 1
2056 :``%n``: zero-padded sequence number, starting at 1
2057 :``%r``: zero-padded changeset revision number
2057 :``%r``: zero-padded changeset revision number
2058 :``\\``: literal "\\" character
2058 :``\\``: literal "\\" character
2059
2059
2060 Without the -a/--text option, export will avoid generating diffs
2060 Without the -a/--text option, export will avoid generating diffs
2061 of files it detects as binary. With -a, export will generate a
2061 of files it detects as binary. With -a, export will generate a
2062 diff anyway, probably with undesirable results.
2062 diff anyway, probably with undesirable results.
2063
2063
2064 With -B/--bookmark changesets reachable by the given bookmark are
2064 With -B/--bookmark changesets reachable by the given bookmark are
2065 selected.
2065 selected.
2066
2066
2067 Use the -g/--git option to generate diffs in the git extended diff
2067 Use the -g/--git option to generate diffs in the git extended diff
2068 format. See :hg:`help diffs` for more information.
2068 format. See :hg:`help diffs` for more information.
2069
2069
2070 With the --switch-parent option, the diff will be against the
2070 With the --switch-parent option, the diff will be against the
2071 second parent. It can be useful to review a merge.
2071 second parent. It can be useful to review a merge.
2072
2072
2073 .. container:: verbose
2073 .. container:: verbose
2074
2074
2075 Template:
2075 Template:
2076
2076
2077 The following keywords are supported in addition to the common template
2077 The following keywords are supported in addition to the common template
2078 keywords and functions. See also :hg:`help templates`.
2078 keywords and functions. See also :hg:`help templates`.
2079
2079
2080 :diff: String. Diff content.
2080 :diff: String. Diff content.
2081 :parents: List of strings. Parent nodes of the changeset.
2081 :parents: List of strings. Parent nodes of the changeset.
2082
2082
2083 Examples:
2083 Examples:
2084
2084
2085 - use export and import to transplant a bugfix to the current
2085 - use export and import to transplant a bugfix to the current
2086 branch::
2086 branch::
2087
2087
2088 hg export -r 9353 | hg import -
2088 hg export -r 9353 | hg import -
2089
2089
2090 - export all the changesets between two revisions to a file with
2090 - export all the changesets between two revisions to a file with
2091 rename information::
2091 rename information::
2092
2092
2093 hg export --git -r 123:150 > changes.txt
2093 hg export --git -r 123:150 > changes.txt
2094
2094
2095 - split outgoing changes into a series of patches with
2095 - split outgoing changes into a series of patches with
2096 descriptive names::
2096 descriptive names::
2097
2097
2098 hg export -r "outgoing()" -o "%n-%m.patch"
2098 hg export -r "outgoing()" -o "%n-%m.patch"
2099
2099
2100 Returns 0 on success.
2100 Returns 0 on success.
2101 """
2101 """
2102 opts = pycompat.byteskwargs(opts)
2102 opts = pycompat.byteskwargs(opts)
2103 bookmark = opts.get('bookmark')
2103 bookmark = opts.get('bookmark')
2104 changesets += tuple(opts.get('rev', []))
2104 changesets += tuple(opts.get('rev', []))
2105
2105
2106 if bookmark and changesets:
2106 if bookmark and changesets:
2107 raise error.Abort(_("-r and -B are mutually exclusive"))
2107 raise error.Abort(_("-r and -B are mutually exclusive"))
2108
2108
2109 if bookmark:
2109 if bookmark:
2110 if bookmark not in repo._bookmarks:
2110 if bookmark not in repo._bookmarks:
2111 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2111 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2112
2112
2113 revs = scmutil.bookmarkrevs(repo, bookmark)
2113 revs = scmutil.bookmarkrevs(repo, bookmark)
2114 else:
2114 else:
2115 if not changesets:
2115 if not changesets:
2116 changesets = ['.']
2116 changesets = ['.']
2117
2117
2118 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2118 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2119 revs = scmutil.revrange(repo, changesets)
2119 revs = scmutil.revrange(repo, changesets)
2120
2120
2121 if not revs:
2121 if not revs:
2122 raise error.Abort(_("export requires at least one changeset"))
2122 raise error.Abort(_("export requires at least one changeset"))
2123 if len(revs) > 1:
2123 if len(revs) > 1:
2124 ui.note(_('exporting patches:\n'))
2124 ui.note(_('exporting patches:\n'))
2125 else:
2125 else:
2126 ui.note(_('exporting patch:\n'))
2126 ui.note(_('exporting patch:\n'))
2127
2127
2128 fntemplate = opts.get('output')
2128 fntemplate = opts.get('output')
2129 if cmdutil.isstdiofilename(fntemplate):
2129 if cmdutil.isstdiofilename(fntemplate):
2130 fntemplate = ''
2130 fntemplate = ''
2131
2131
2132 if fntemplate:
2132 if fntemplate:
2133 fm = formatter.nullformatter(ui, 'export', opts)
2133 fm = formatter.nullformatter(ui, 'export', opts)
2134 else:
2134 else:
2135 ui.pager('export')
2135 ui.pager('export')
2136 fm = ui.formatter('export', opts)
2136 fm = ui.formatter('export', opts)
2137 with fm:
2137 with fm:
2138 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2138 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2139 switch_parent=opts.get('switch_parent'),
2139 switch_parent=opts.get('switch_parent'),
2140 opts=patch.diffallopts(ui, opts))
2140 opts=patch.diffallopts(ui, opts))
2141
2141
2142 @command('files',
2142 @command('files',
2143 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2143 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2144 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2144 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2145 ] + walkopts + formatteropts + subrepoopts,
2145 ] + walkopts + formatteropts + subrepoopts,
2146 _('[OPTION]... [FILE]...'),
2146 _('[OPTION]... [FILE]...'),
2147 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2147 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2148 intents={INTENT_READONLY})
2148 intents={INTENT_READONLY})
2149 def files(ui, repo, *pats, **opts):
2149 def files(ui, repo, *pats, **opts):
2150 """list tracked files
2150 """list tracked files
2151
2151
2152 Print files under Mercurial control in the working directory or
2152 Print files under Mercurial control in the working directory or
2153 specified revision for given files (excluding removed files).
2153 specified revision for given files (excluding removed files).
2154 Files can be specified as filenames or filesets.
2154 Files can be specified as filenames or filesets.
2155
2155
2156 If no files are given to match, this command prints the names
2156 If no files are given to match, this command prints the names
2157 of all files under Mercurial control.
2157 of all files under Mercurial control.
2158
2158
2159 .. container:: verbose
2159 .. container:: verbose
2160
2160
2161 Template:
2161 Template:
2162
2162
2163 The following keywords are supported in addition to the common template
2163 The following keywords are supported in addition to the common template
2164 keywords and functions. See also :hg:`help templates`.
2164 keywords and functions. See also :hg:`help templates`.
2165
2165
2166 :flags: String. Character denoting file's symlink and executable bits.
2166 :flags: String. Character denoting file's symlink and executable bits.
2167 :path: String. Repository-absolute path of the file.
2167 :path: String. Repository-absolute path of the file.
2168 :size: Integer. Size of the file in bytes.
2168 :size: Integer. Size of the file in bytes.
2169
2169
2170 Examples:
2170 Examples:
2171
2171
2172 - list all files under the current directory::
2172 - list all files under the current directory::
2173
2173
2174 hg files .
2174 hg files .
2175
2175
2176 - shows sizes and flags for current revision::
2176 - shows sizes and flags for current revision::
2177
2177
2178 hg files -vr .
2178 hg files -vr .
2179
2179
2180 - list all files named README::
2180 - list all files named README::
2181
2181
2182 hg files -I "**/README"
2182 hg files -I "**/README"
2183
2183
2184 - list all binary files::
2184 - list all binary files::
2185
2185
2186 hg files "set:binary()"
2186 hg files "set:binary()"
2187
2187
2188 - find files containing a regular expression::
2188 - find files containing a regular expression::
2189
2189
2190 hg files "set:grep('bob')"
2190 hg files "set:grep('bob')"
2191
2191
2192 - search tracked file contents with xargs and grep::
2192 - search tracked file contents with xargs and grep::
2193
2193
2194 hg files -0 | xargs -0 grep foo
2194 hg files -0 | xargs -0 grep foo
2195
2195
2196 See :hg:`help patterns` and :hg:`help filesets` for more information
2196 See :hg:`help patterns` and :hg:`help filesets` for more information
2197 on specifying file patterns.
2197 on specifying file patterns.
2198
2198
2199 Returns 0 if a match is found, 1 otherwise.
2199 Returns 0 if a match is found, 1 otherwise.
2200
2200
2201 """
2201 """
2202
2202
2203 opts = pycompat.byteskwargs(opts)
2203 opts = pycompat.byteskwargs(opts)
2204 rev = opts.get('rev')
2204 rev = opts.get('rev')
2205 if rev:
2205 if rev:
2206 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2206 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2207 ctx = scmutil.revsingle(repo, rev, None)
2207 ctx = scmutil.revsingle(repo, rev, None)
2208
2208
2209 end = '\n'
2209 end = '\n'
2210 if opts.get('print0'):
2210 if opts.get('print0'):
2211 end = '\0'
2211 end = '\0'
2212 fmt = '%s' + end
2212 fmt = '%s' + end
2213
2213
2214 m = scmutil.match(ctx, pats, opts)
2214 m = scmutil.match(ctx, pats, opts)
2215 ui.pager('files')
2215 ui.pager('files')
2216 with ui.formatter('files', opts) as fm:
2216 with ui.formatter('files', opts) as fm:
2217 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2217 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2218
2218
2219 @command(
2219 @command(
2220 'forget',
2220 'forget',
2221 [('i', 'interactive', None, _('use interactive mode')),
2221 [('i', 'interactive', None, _('use interactive mode')),
2222 ] + walkopts + dryrunopts,
2222 ] + walkopts + dryrunopts,
2223 _('[OPTION]... FILE...'),
2223 _('[OPTION]... FILE...'),
2224 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2224 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2225 helpbasic=True, inferrepo=True)
2225 helpbasic=True, inferrepo=True)
2226 def forget(ui, repo, *pats, **opts):
2226 def forget(ui, repo, *pats, **opts):
2227 """forget the specified files on the next commit
2227 """forget the specified files on the next commit
2228
2228
2229 Mark the specified files so they will no longer be tracked
2229 Mark the specified files so they will no longer be tracked
2230 after the next commit.
2230 after the next commit.
2231
2231
2232 This only removes files from the current branch, not from the
2232 This only removes files from the current branch, not from the
2233 entire project history, and it does not delete them from the
2233 entire project history, and it does not delete them from the
2234 working directory.
2234 working directory.
2235
2235
2236 To delete the file from the working directory, see :hg:`remove`.
2236 To delete the file from the working directory, see :hg:`remove`.
2237
2237
2238 To undo a forget before the next commit, see :hg:`add`.
2238 To undo a forget before the next commit, see :hg:`add`.
2239
2239
2240 .. container:: verbose
2240 .. container:: verbose
2241
2241
2242 Examples:
2242 Examples:
2243
2243
2244 - forget newly-added binary files::
2244 - forget newly-added binary files::
2245
2245
2246 hg forget "set:added() and binary()"
2246 hg forget "set:added() and binary()"
2247
2247
2248 - forget files that would be excluded by .hgignore::
2248 - forget files that would be excluded by .hgignore::
2249
2249
2250 hg forget "set:hgignore()"
2250 hg forget "set:hgignore()"
2251
2251
2252 Returns 0 on success.
2252 Returns 0 on success.
2253 """
2253 """
2254
2254
2255 opts = pycompat.byteskwargs(opts)
2255 opts = pycompat.byteskwargs(opts)
2256 if not pats:
2256 if not pats:
2257 raise error.Abort(_('no files specified'))
2257 raise error.Abort(_('no files specified'))
2258
2258
2259 m = scmutil.match(repo[None], pats, opts)
2259 m = scmutil.match(repo[None], pats, opts)
2260 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2260 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2261 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2261 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2262 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2262 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2263 explicitonly=False, dryrun=dryrun,
2263 explicitonly=False, dryrun=dryrun,
2264 interactive=interactive)[0]
2264 interactive=interactive)[0]
2265 return rejected and 1 or 0
2265 return rejected and 1 or 0
2266
2266
2267 @command(
2267 @command(
2268 'graft',
2268 'graft',
2269 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2269 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2270 ('', 'base', '',
2270 ('', 'base', '',
2271 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2271 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2272 ('c', 'continue', False, _('resume interrupted graft')),
2272 ('c', 'continue', False, _('resume interrupted graft')),
2273 ('', 'stop', False, _('stop interrupted graft')),
2273 ('', 'stop', False, _('stop interrupted graft')),
2274 ('', 'abort', False, _('abort interrupted graft')),
2274 ('', 'abort', False, _('abort interrupted graft')),
2275 ('e', 'edit', False, _('invoke editor on commit messages')),
2275 ('e', 'edit', False, _('invoke editor on commit messages')),
2276 ('', 'log', None, _('append graft info to log message')),
2276 ('', 'log', None, _('append graft info to log message')),
2277 ('', 'no-commit', None,
2277 ('', 'no-commit', None,
2278 _("don't commit, just apply the changes in working directory")),
2278 _("don't commit, just apply the changes in working directory")),
2279 ('f', 'force', False, _('force graft')),
2279 ('f', 'force', False, _('force graft')),
2280 ('D', 'currentdate', False,
2280 ('D', 'currentdate', False,
2281 _('record the current date as commit date')),
2281 _('record the current date as commit date')),
2282 ('U', 'currentuser', False,
2282 ('U', 'currentuser', False,
2283 _('record the current user as committer'))]
2283 _('record the current user as committer'))]
2284 + commitopts2 + mergetoolopts + dryrunopts,
2284 + commitopts2 + mergetoolopts + dryrunopts,
2285 _('[OPTION]... [-r REV]... REV...'),
2285 _('[OPTION]... [-r REV]... REV...'),
2286 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2286 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2287 def graft(ui, repo, *revs, **opts):
2287 def graft(ui, repo, *revs, **opts):
2288 '''copy changes from other branches onto the current branch
2288 '''copy changes from other branches onto the current branch
2289
2289
2290 This command uses Mercurial's merge logic to copy individual
2290 This command uses Mercurial's merge logic to copy individual
2291 changes from other branches without merging branches in the
2291 changes from other branches without merging branches in the
2292 history graph. This is sometimes known as 'backporting' or
2292 history graph. This is sometimes known as 'backporting' or
2293 'cherry-picking'. By default, graft will copy user, date, and
2293 'cherry-picking'. By default, graft will copy user, date, and
2294 description from the source changesets.
2294 description from the source changesets.
2295
2295
2296 Changesets that are ancestors of the current revision, that have
2296 Changesets that are ancestors of the current revision, that have
2297 already been grafted, or that are merges will be skipped.
2297 already been grafted, or that are merges will be skipped.
2298
2298
2299 If --log is specified, log messages will have a comment appended
2299 If --log is specified, log messages will have a comment appended
2300 of the form::
2300 of the form::
2301
2301
2302 (grafted from CHANGESETHASH)
2302 (grafted from CHANGESETHASH)
2303
2303
2304 If --force is specified, revisions will be grafted even if they
2304 If --force is specified, revisions will be grafted even if they
2305 are already ancestors of, or have been grafted to, the destination.
2305 are already ancestors of, or have been grafted to, the destination.
2306 This is useful when the revisions have since been backed out.
2306 This is useful when the revisions have since been backed out.
2307
2307
2308 If a graft merge results in conflicts, the graft process is
2308 If a graft merge results in conflicts, the graft process is
2309 interrupted so that the current merge can be manually resolved.
2309 interrupted so that the current merge can be manually resolved.
2310 Once all conflicts are addressed, the graft process can be
2310 Once all conflicts are addressed, the graft process can be
2311 continued with the -c/--continue option.
2311 continued with the -c/--continue option.
2312
2312
2313 The -c/--continue option reapplies all the earlier options.
2313 The -c/--continue option reapplies all the earlier options.
2314
2314
2315 .. container:: verbose
2315 .. container:: verbose
2316
2316
2317 The --base option exposes more of how graft internally uses merge with a
2317 The --base option exposes more of how graft internally uses merge with a
2318 custom base revision. --base can be used to specify another ancestor than
2318 custom base revision. --base can be used to specify another ancestor than
2319 the first and only parent.
2319 the first and only parent.
2320
2320
2321 The command::
2321 The command::
2322
2322
2323 hg graft -r 345 --base 234
2323 hg graft -r 345 --base 234
2324
2324
2325 is thus pretty much the same as::
2325 is thus pretty much the same as::
2326
2326
2327 hg diff -r 234 -r 345 | hg import
2327 hg diff -r 234 -r 345 | hg import
2328
2328
2329 but using merge to resolve conflicts and track moved files.
2329 but using merge to resolve conflicts and track moved files.
2330
2330
2331 The result of a merge can thus be backported as a single commit by
2331 The result of a merge can thus be backported as a single commit by
2332 specifying one of the merge parents as base, and thus effectively
2332 specifying one of the merge parents as base, and thus effectively
2333 grafting the changes from the other side.
2333 grafting the changes from the other side.
2334
2334
2335 It is also possible to collapse multiple changesets and clean up history
2335 It is also possible to collapse multiple changesets and clean up history
2336 by specifying another ancestor as base, much like rebase --collapse
2336 by specifying another ancestor as base, much like rebase --collapse
2337 --keep.
2337 --keep.
2338
2338
2339 The commit message can be tweaked after the fact using commit --amend .
2339 The commit message can be tweaked after the fact using commit --amend .
2340
2340
2341 For using non-ancestors as the base to backout changes, see the backout
2341 For using non-ancestors as the base to backout changes, see the backout
2342 command and the hidden --parent option.
2342 command and the hidden --parent option.
2343
2343
2344 .. container:: verbose
2344 .. container:: verbose
2345
2345
2346 Examples:
2346 Examples:
2347
2347
2348 - copy a single change to the stable branch and edit its description::
2348 - copy a single change to the stable branch and edit its description::
2349
2349
2350 hg update stable
2350 hg update stable
2351 hg graft --edit 9393
2351 hg graft --edit 9393
2352
2352
2353 - graft a range of changesets with one exception, updating dates::
2353 - graft a range of changesets with one exception, updating dates::
2354
2354
2355 hg graft -D "2085::2093 and not 2091"
2355 hg graft -D "2085::2093 and not 2091"
2356
2356
2357 - continue a graft after resolving conflicts::
2357 - continue a graft after resolving conflicts::
2358
2358
2359 hg graft -c
2359 hg graft -c
2360
2360
2361 - show the source of a grafted changeset::
2361 - show the source of a grafted changeset::
2362
2362
2363 hg log --debug -r .
2363 hg log --debug -r .
2364
2364
2365 - show revisions sorted by date::
2365 - show revisions sorted by date::
2366
2366
2367 hg log -r "sort(all(), date)"
2367 hg log -r "sort(all(), date)"
2368
2368
2369 - backport the result of a merge as a single commit::
2369 - backport the result of a merge as a single commit::
2370
2370
2371 hg graft -r 123 --base 123^
2371 hg graft -r 123 --base 123^
2372
2372
2373 - land a feature branch as one changeset::
2373 - land a feature branch as one changeset::
2374
2374
2375 hg up -cr default
2375 hg up -cr default
2376 hg graft -r featureX --base "ancestor('featureX', 'default')"
2376 hg graft -r featureX --base "ancestor('featureX', 'default')"
2377
2377
2378 See :hg:`help revisions` for more about specifying revisions.
2378 See :hg:`help revisions` for more about specifying revisions.
2379
2379
2380 Returns 0 on successful completion.
2380 Returns 0 on successful completion.
2381 '''
2381 '''
2382 with repo.wlock():
2382 with repo.wlock():
2383 return _dograft(ui, repo, *revs, **opts)
2383 return _dograft(ui, repo, *revs, **opts)
2384
2384
2385 def _dograft(ui, repo, *revs, **opts):
2385 def _dograft(ui, repo, *revs, **opts):
2386 opts = pycompat.byteskwargs(opts)
2386 opts = pycompat.byteskwargs(opts)
2387 if revs and opts.get('rev'):
2387 if revs and opts.get('rev'):
2388 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2388 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2389 'revision ordering!\n'))
2389 'revision ordering!\n'))
2390
2390
2391 revs = list(revs)
2391 revs = list(revs)
2392 revs.extend(opts.get('rev'))
2392 revs.extend(opts.get('rev'))
2393 basectx = None
2393 basectx = None
2394 if opts.get('base'):
2394 if opts.get('base'):
2395 basectx = scmutil.revsingle(repo, opts['base'], None)
2395 basectx = scmutil.revsingle(repo, opts['base'], None)
2396 # a dict of data to be stored in state file
2396 # a dict of data to be stored in state file
2397 statedata = {}
2397 statedata = {}
2398 # list of new nodes created by ongoing graft
2398 # list of new nodes created by ongoing graft
2399 statedata['newnodes'] = []
2399 statedata['newnodes'] = []
2400
2400
2401 if opts.get('user') and opts.get('currentuser'):
2401 if opts.get('user') and opts.get('currentuser'):
2402 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2402 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2403 if opts.get('date') and opts.get('currentdate'):
2403 if opts.get('date') and opts.get('currentdate'):
2404 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2404 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2405 if not opts.get('user') and opts.get('currentuser'):
2405 if not opts.get('user') and opts.get('currentuser'):
2406 opts['user'] = ui.username()
2406 opts['user'] = ui.username()
2407 if not opts.get('date') and opts.get('currentdate'):
2407 if not opts.get('date') and opts.get('currentdate'):
2408 opts['date'] = "%d %d" % dateutil.makedate()
2408 opts['date'] = "%d %d" % dateutil.makedate()
2409
2409
2410 editor = cmdutil.getcommiteditor(editform='graft',
2410 editor = cmdutil.getcommiteditor(editform='graft',
2411 **pycompat.strkwargs(opts))
2411 **pycompat.strkwargs(opts))
2412
2412
2413 cont = False
2413 cont = False
2414 if opts.get('no_commit'):
2414 if opts.get('no_commit'):
2415 if opts.get('edit'):
2415 if opts.get('edit'):
2416 raise error.Abort(_("cannot specify --no-commit and "
2416 raise error.Abort(_("cannot specify --no-commit and "
2417 "--edit together"))
2417 "--edit together"))
2418 if opts.get('currentuser'):
2418 if opts.get('currentuser'):
2419 raise error.Abort(_("cannot specify --no-commit and "
2419 raise error.Abort(_("cannot specify --no-commit and "
2420 "--currentuser together"))
2420 "--currentuser together"))
2421 if opts.get('currentdate'):
2421 if opts.get('currentdate'):
2422 raise error.Abort(_("cannot specify --no-commit and "
2422 raise error.Abort(_("cannot specify --no-commit and "
2423 "--currentdate together"))
2423 "--currentdate together"))
2424 if opts.get('log'):
2424 if opts.get('log'):
2425 raise error.Abort(_("cannot specify --no-commit and "
2425 raise error.Abort(_("cannot specify --no-commit and "
2426 "--log together"))
2426 "--log together"))
2427
2427
2428 graftstate = statemod.cmdstate(repo, 'graftstate')
2428 graftstate = statemod.cmdstate(repo, 'graftstate')
2429
2429
2430 if opts.get('stop'):
2430 if opts.get('stop'):
2431 if opts.get('continue'):
2431 if opts.get('continue'):
2432 raise error.Abort(_("cannot use '--continue' and "
2432 raise error.Abort(_("cannot use '--continue' and "
2433 "'--stop' together"))
2433 "'--stop' together"))
2434 if opts.get('abort'):
2434 if opts.get('abort'):
2435 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2435 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2436
2436
2437 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2437 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2438 opts.get('date'), opts.get('currentdate'),
2438 opts.get('date'), opts.get('currentdate'),
2439 opts.get('currentuser'), opts.get('rev'))):
2439 opts.get('currentuser'), opts.get('rev'))):
2440 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2440 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2441 return _stopgraft(ui, repo, graftstate)
2441 return _stopgraft(ui, repo, graftstate)
2442 elif opts.get('abort'):
2442 elif opts.get('abort'):
2443 if opts.get('continue'):
2443 if opts.get('continue'):
2444 raise error.Abort(_("cannot use '--continue' and "
2444 raise error.Abort(_("cannot use '--continue' and "
2445 "'--abort' together"))
2445 "'--abort' together"))
2446 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2446 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2447 opts.get('date'), opts.get('currentdate'),
2447 opts.get('date'), opts.get('currentdate'),
2448 opts.get('currentuser'), opts.get('rev'))):
2448 opts.get('currentuser'), opts.get('rev'))):
2449 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2449 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2450
2450
2451 return _abortgraft(ui, repo, graftstate)
2451 return _abortgraft(ui, repo, graftstate)
2452 elif opts.get('continue'):
2452 elif opts.get('continue'):
2453 cont = True
2453 cont = True
2454 if revs:
2454 if revs:
2455 raise error.Abort(_("can't specify --continue and revisions"))
2455 raise error.Abort(_("can't specify --continue and revisions"))
2456 # read in unfinished revisions
2456 # read in unfinished revisions
2457 if graftstate.exists():
2457 if graftstate.exists():
2458 statedata = _readgraftstate(repo, graftstate)
2458 statedata = _readgraftstate(repo, graftstate)
2459 if statedata.get('date'):
2459 if statedata.get('date'):
2460 opts['date'] = statedata['date']
2460 opts['date'] = statedata['date']
2461 if statedata.get('user'):
2461 if statedata.get('user'):
2462 opts['user'] = statedata['user']
2462 opts['user'] = statedata['user']
2463 if statedata.get('log'):
2463 if statedata.get('log'):
2464 opts['log'] = True
2464 opts['log'] = True
2465 if statedata.get('no_commit'):
2465 if statedata.get('no_commit'):
2466 opts['no_commit'] = statedata.get('no_commit')
2466 opts['no_commit'] = statedata.get('no_commit')
2467 nodes = statedata['nodes']
2467 nodes = statedata['nodes']
2468 revs = [repo[node].rev() for node in nodes]
2468 revs = [repo[node].rev() for node in nodes]
2469 else:
2469 else:
2470 cmdutil.wrongtooltocontinue(repo, _('graft'))
2470 cmdutil.wrongtooltocontinue(repo, _('graft'))
2471 else:
2471 else:
2472 if not revs:
2472 if not revs:
2473 raise error.Abort(_('no revisions specified'))
2473 raise error.Abort(_('no revisions specified'))
2474 cmdutil.checkunfinished(repo)
2474 cmdutil.checkunfinished(repo)
2475 cmdutil.bailifchanged(repo)
2475 cmdutil.bailifchanged(repo)
2476 revs = scmutil.revrange(repo, revs)
2476 revs = scmutil.revrange(repo, revs)
2477
2477
2478 skipped = set()
2478 skipped = set()
2479 if basectx is None:
2479 if basectx is None:
2480 # check for merges
2480 # check for merges
2481 for rev in repo.revs('%ld and merge()', revs):
2481 for rev in repo.revs('%ld and merge()', revs):
2482 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2482 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2483 skipped.add(rev)
2483 skipped.add(rev)
2484 revs = [r for r in revs if r not in skipped]
2484 revs = [r for r in revs if r not in skipped]
2485 if not revs:
2485 if not revs:
2486 return -1
2486 return -1
2487 if basectx is not None and len(revs) != 1:
2487 if basectx is not None and len(revs) != 1:
2488 raise error.Abort(_('only one revision allowed with --base '))
2488 raise error.Abort(_('only one revision allowed with --base '))
2489
2489
2490 # Don't check in the --continue case, in effect retaining --force across
2490 # Don't check in the --continue case, in effect retaining --force across
2491 # --continues. That's because without --force, any revisions we decided to
2491 # --continues. That's because without --force, any revisions we decided to
2492 # skip would have been filtered out here, so they wouldn't have made their
2492 # skip would have been filtered out here, so they wouldn't have made their
2493 # way to the graftstate. With --force, any revisions we would have otherwise
2493 # way to the graftstate. With --force, any revisions we would have otherwise
2494 # skipped would not have been filtered out, and if they hadn't been applied
2494 # skipped would not have been filtered out, and if they hadn't been applied
2495 # already, they'd have been in the graftstate.
2495 # already, they'd have been in the graftstate.
2496 if not (cont or opts.get('force')) and basectx is None:
2496 if not (cont or opts.get('force')) and basectx is None:
2497 # check for ancestors of dest branch
2497 # check for ancestors of dest branch
2498 crev = repo['.'].rev()
2498 crev = repo['.'].rev()
2499 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2499 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2500 # XXX make this lazy in the future
2500 # XXX make this lazy in the future
2501 # don't mutate while iterating, create a copy
2501 # don't mutate while iterating, create a copy
2502 for rev in list(revs):
2502 for rev in list(revs):
2503 if rev in ancestors:
2503 if rev in ancestors:
2504 ui.warn(_('skipping ancestor revision %d:%s\n') %
2504 ui.warn(_('skipping ancestor revision %d:%s\n') %
2505 (rev, repo[rev]))
2505 (rev, repo[rev]))
2506 # XXX remove on list is slow
2506 # XXX remove on list is slow
2507 revs.remove(rev)
2507 revs.remove(rev)
2508 if not revs:
2508 if not revs:
2509 return -1
2509 return -1
2510
2510
2511 # analyze revs for earlier grafts
2511 # analyze revs for earlier grafts
2512 ids = {}
2512 ids = {}
2513 for ctx in repo.set("%ld", revs):
2513 for ctx in repo.set("%ld", revs):
2514 ids[ctx.hex()] = ctx.rev()
2514 ids[ctx.hex()] = ctx.rev()
2515 n = ctx.extra().get('source')
2515 n = ctx.extra().get('source')
2516 if n:
2516 if n:
2517 ids[n] = ctx.rev()
2517 ids[n] = ctx.rev()
2518
2518
2519 # check ancestors for earlier grafts
2519 # check ancestors for earlier grafts
2520 ui.debug('scanning for duplicate grafts\n')
2520 ui.debug('scanning for duplicate grafts\n')
2521
2521
2522 # The only changesets we can be sure doesn't contain grafts of any
2522 # The only changesets we can be sure doesn't contain grafts of any
2523 # revs, are the ones that are common ancestors of *all* revs:
2523 # revs, are the ones that are common ancestors of *all* revs:
2524 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2524 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2525 ctx = repo[rev]
2525 ctx = repo[rev]
2526 n = ctx.extra().get('source')
2526 n = ctx.extra().get('source')
2527 if n in ids:
2527 if n in ids:
2528 try:
2528 try:
2529 r = repo[n].rev()
2529 r = repo[n].rev()
2530 except error.RepoLookupError:
2530 except error.RepoLookupError:
2531 r = None
2531 r = None
2532 if r in revs:
2532 if r in revs:
2533 ui.warn(_('skipping revision %d:%s '
2533 ui.warn(_('skipping revision %d:%s '
2534 '(already grafted to %d:%s)\n')
2534 '(already grafted to %d:%s)\n')
2535 % (r, repo[r], rev, ctx))
2535 % (r, repo[r], rev, ctx))
2536 revs.remove(r)
2536 revs.remove(r)
2537 elif ids[n] in revs:
2537 elif ids[n] in revs:
2538 if r is None:
2538 if r is None:
2539 ui.warn(_('skipping already grafted revision %d:%s '
2539 ui.warn(_('skipping already grafted revision %d:%s '
2540 '(%d:%s also has unknown origin %s)\n')
2540 '(%d:%s also has unknown origin %s)\n')
2541 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2541 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2542 else:
2542 else:
2543 ui.warn(_('skipping already grafted revision %d:%s '
2543 ui.warn(_('skipping already grafted revision %d:%s '
2544 '(%d:%s also has origin %d:%s)\n')
2544 '(%d:%s also has origin %d:%s)\n')
2545 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2545 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2546 revs.remove(ids[n])
2546 revs.remove(ids[n])
2547 elif ctx.hex() in ids:
2547 elif ctx.hex() in ids:
2548 r = ids[ctx.hex()]
2548 r = ids[ctx.hex()]
2549 if r in revs:
2549 if r in revs:
2550 ui.warn(_('skipping already grafted revision %d:%s '
2550 ui.warn(_('skipping already grafted revision %d:%s '
2551 '(was grafted from %d:%s)\n') %
2551 '(was grafted from %d:%s)\n') %
2552 (r, repo[r], rev, ctx))
2552 (r, repo[r], rev, ctx))
2553 revs.remove(r)
2553 revs.remove(r)
2554 if not revs:
2554 if not revs:
2555 return -1
2555 return -1
2556
2556
2557 if opts.get('no_commit'):
2557 if opts.get('no_commit'):
2558 statedata['no_commit'] = True
2558 statedata['no_commit'] = True
2559 for pos, ctx in enumerate(repo.set("%ld", revs)):
2559 for pos, ctx in enumerate(repo.set("%ld", revs)):
2560 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2560 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2561 ctx.description().split('\n', 1)[0])
2561 ctx.description().split('\n', 1)[0])
2562 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2562 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2563 if names:
2563 if names:
2564 desc += ' (%s)' % ' '.join(names)
2564 desc += ' (%s)' % ' '.join(names)
2565 ui.status(_('grafting %s\n') % desc)
2565 ui.status(_('grafting %s\n') % desc)
2566 if opts.get('dry_run'):
2566 if opts.get('dry_run'):
2567 continue
2567 continue
2568
2568
2569 source = ctx.extra().get('source')
2569 source = ctx.extra().get('source')
2570 extra = {}
2570 extra = {}
2571 if source:
2571 if source:
2572 extra['source'] = source
2572 extra['source'] = source
2573 extra['intermediate-source'] = ctx.hex()
2573 extra['intermediate-source'] = ctx.hex()
2574 else:
2574 else:
2575 extra['source'] = ctx.hex()
2575 extra['source'] = ctx.hex()
2576 user = ctx.user()
2576 user = ctx.user()
2577 if opts.get('user'):
2577 if opts.get('user'):
2578 user = opts['user']
2578 user = opts['user']
2579 statedata['user'] = user
2579 statedata['user'] = user
2580 date = ctx.date()
2580 date = ctx.date()
2581 if opts.get('date'):
2581 if opts.get('date'):
2582 date = opts['date']
2582 date = opts['date']
2583 statedata['date'] = date
2583 statedata['date'] = date
2584 message = ctx.description()
2584 message = ctx.description()
2585 if opts.get('log'):
2585 if opts.get('log'):
2586 message += '\n(grafted from %s)' % ctx.hex()
2586 message += '\n(grafted from %s)' % ctx.hex()
2587 statedata['log'] = True
2587 statedata['log'] = True
2588
2588
2589 # we don't merge the first commit when continuing
2589 # we don't merge the first commit when continuing
2590 if not cont:
2590 if not cont:
2591 # perform the graft merge with p1(rev) as 'ancestor'
2591 # perform the graft merge with p1(rev) as 'ancestor'
2592 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2592 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2593 base = ctx.p1() if basectx is None else basectx
2593 base = ctx.p1() if basectx is None else basectx
2594 with ui.configoverride(overrides, 'graft'):
2594 with ui.configoverride(overrides, 'graft'):
2595 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2595 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2596 # report any conflicts
2596 # report any conflicts
2597 if stats.unresolvedcount > 0:
2597 if stats.unresolvedcount > 0:
2598 # write out state for --continue
2598 # write out state for --continue
2599 nodes = [repo[rev].hex() for rev in revs[pos:]]
2599 nodes = [repo[rev].hex() for rev in revs[pos:]]
2600 statedata['nodes'] = nodes
2600 statedata['nodes'] = nodes
2601 stateversion = 1
2601 stateversion = 1
2602 graftstate.save(stateversion, statedata)
2602 graftstate.save(stateversion, statedata)
2603 hint = _("use 'hg resolve' and 'hg graft --continue'")
2603 hint = _("use 'hg resolve' and 'hg graft --continue'")
2604 raise error.Abort(
2604 raise error.Abort(
2605 _("unresolved conflicts, can't continue"),
2605 _("unresolved conflicts, can't continue"),
2606 hint=hint)
2606 hint=hint)
2607 else:
2607 else:
2608 cont = False
2608 cont = False
2609
2609
2610 # commit if --no-commit is false
2610 # commit if --no-commit is false
2611 if not opts.get('no_commit'):
2611 if not opts.get('no_commit'):
2612 node = repo.commit(text=message, user=user, date=date, extra=extra,
2612 node = repo.commit(text=message, user=user, date=date, extra=extra,
2613 editor=editor)
2613 editor=editor)
2614 if node is None:
2614 if node is None:
2615 ui.warn(
2615 ui.warn(
2616 _('note: graft of %d:%s created no changes to commit\n') %
2616 _('note: graft of %d:%s created no changes to commit\n') %
2617 (ctx.rev(), ctx))
2617 (ctx.rev(), ctx))
2618 # checking that newnodes exist because old state files won't have it
2618 # checking that newnodes exist because old state files won't have it
2619 elif statedata.get('newnodes') is not None:
2619 elif statedata.get('newnodes') is not None:
2620 statedata['newnodes'].append(node)
2620 statedata['newnodes'].append(node)
2621
2621
2622 # remove state when we complete successfully
2622 # remove state when we complete successfully
2623 if not opts.get('dry_run'):
2623 if not opts.get('dry_run'):
2624 graftstate.delete()
2624 graftstate.delete()
2625
2625
2626 return 0
2626 return 0
2627
2627
2628 def _abortgraft(ui, repo, graftstate):
2628 def _abortgraft(ui, repo, graftstate):
2629 """abort the interrupted graft and rollbacks to the state before interrupted
2629 """abort the interrupted graft and rollbacks to the state before interrupted
2630 graft"""
2630 graft"""
2631 if not graftstate.exists():
2631 if not graftstate.exists():
2632 raise error.Abort(_("no interrupted graft to abort"))
2632 raise error.Abort(_("no interrupted graft to abort"))
2633 statedata = _readgraftstate(repo, graftstate)
2633 statedata = _readgraftstate(repo, graftstate)
2634 newnodes = statedata.get('newnodes')
2634 newnodes = statedata.get('newnodes')
2635 if newnodes is None:
2635 if newnodes is None:
2636 # and old graft state which does not have all the data required to abort
2636 # and old graft state which does not have all the data required to abort
2637 # the graft
2637 # the graft
2638 raise error.Abort(_("cannot abort using an old graftstate"))
2638 raise error.Abort(_("cannot abort using an old graftstate"))
2639
2639
2640 # changeset from which graft operation was started
2640 # changeset from which graft operation was started
2641 if len(newnodes) > 0:
2641 if len(newnodes) > 0:
2642 startctx = repo[newnodes[0]].p1()
2642 startctx = repo[newnodes[0]].p1()
2643 else:
2643 else:
2644 startctx = repo['.']
2644 startctx = repo['.']
2645 # whether to strip or not
2645 # whether to strip or not
2646 cleanup = False
2646 cleanup = False
2647 if newnodes:
2647 if newnodes:
2648 newnodes = [repo[r].rev() for r in newnodes]
2648 newnodes = [repo[r].rev() for r in newnodes]
2649 cleanup = True
2649 cleanup = True
2650 # checking that none of the newnodes turned public or is public
2650 # checking that none of the newnodes turned public or is public
2651 immutable = [c for c in newnodes if not repo[c].mutable()]
2651 immutable = [c for c in newnodes if not repo[c].mutable()]
2652 if immutable:
2652 if immutable:
2653 repo.ui.warn(_("cannot clean up public changesets %s\n")
2653 repo.ui.warn(_("cannot clean up public changesets %s\n")
2654 % ', '.join(bytes(repo[r]) for r in immutable),
2654 % ', '.join(bytes(repo[r]) for r in immutable),
2655 hint=_("see 'hg help phases' for details"))
2655 hint=_("see 'hg help phases' for details"))
2656 cleanup = False
2656 cleanup = False
2657
2657
2658 # checking that no new nodes are created on top of grafted revs
2658 # checking that no new nodes are created on top of grafted revs
2659 desc = set(repo.changelog.descendants(newnodes))
2659 desc = set(repo.changelog.descendants(newnodes))
2660 if desc - set(newnodes):
2660 if desc - set(newnodes):
2661 repo.ui.warn(_("new changesets detected on destination "
2661 repo.ui.warn(_("new changesets detected on destination "
2662 "branch, can't strip\n"))
2662 "branch, can't strip\n"))
2663 cleanup = False
2663 cleanup = False
2664
2664
2665 if cleanup:
2665 if cleanup:
2666 with repo.wlock(), repo.lock():
2666 with repo.wlock(), repo.lock():
2667 hg.updaterepo(repo, startctx.node(), overwrite=True)
2667 hg.updaterepo(repo, startctx.node(), overwrite=True)
2668 # stripping the new nodes created
2668 # stripping the new nodes created
2669 strippoints = [c.node() for c in repo.set("roots(%ld)",
2669 strippoints = [c.node() for c in repo.set("roots(%ld)",
2670 newnodes)]
2670 newnodes)]
2671 repair.strip(repo.ui, repo, strippoints, backup=False)
2671 repair.strip(repo.ui, repo, strippoints, backup=False)
2672
2672
2673 if not cleanup:
2673 if not cleanup:
2674 # we don't update to the startnode if we can't strip
2674 # we don't update to the startnode if we can't strip
2675 startctx = repo['.']
2675 startctx = repo['.']
2676 hg.updaterepo(repo, startctx.node(), overwrite=True)
2676 hg.updaterepo(repo, startctx.node(), overwrite=True)
2677
2677
2678 ui.status(_("graft aborted\n"))
2678 ui.status(_("graft aborted\n"))
2679 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2679 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2680 graftstate.delete()
2680 graftstate.delete()
2681 return 0
2681 return 0
2682
2682
2683 def _readgraftstate(repo, graftstate):
2683 def _readgraftstate(repo, graftstate):
2684 """read the graft state file and return a dict of the data stored in it"""
2684 """read the graft state file and return a dict of the data stored in it"""
2685 try:
2685 try:
2686 return graftstate.read()
2686 return graftstate.read()
2687 except error.CorruptedState:
2687 except error.CorruptedState:
2688 nodes = repo.vfs.read('graftstate').splitlines()
2688 nodes = repo.vfs.read('graftstate').splitlines()
2689 return {'nodes': nodes}
2689 return {'nodes': nodes}
2690
2690
2691 def _stopgraft(ui, repo, graftstate):
2691 def _stopgraft(ui, repo, graftstate):
2692 """stop the interrupted graft"""
2692 """stop the interrupted graft"""
2693 if not graftstate.exists():
2693 if not graftstate.exists():
2694 raise error.Abort(_("no interrupted graft found"))
2694 raise error.Abort(_("no interrupted graft found"))
2695 pctx = repo['.']
2695 pctx = repo['.']
2696 hg.updaterepo(repo, pctx.node(), overwrite=True)
2696 hg.updaterepo(repo, pctx.node(), overwrite=True)
2697 graftstate.delete()
2697 graftstate.delete()
2698 ui.status(_("stopped the interrupted graft\n"))
2698 ui.status(_("stopped the interrupted graft\n"))
2699 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2699 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2700 return 0
2700 return 0
2701
2701
2702 @command('grep',
2702 @command('grep',
2703 [('0', 'print0', None, _('end fields with NUL')),
2703 [('0', 'print0', None, _('end fields with NUL')),
2704 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2704 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2705 ('', 'diff', None, _('print all revisions when the term was introduced '
2705 ('', 'diff', None, _('print all revisions when the term was introduced '
2706 'or removed')),
2706 'or removed')),
2707 ('a', 'text', None, _('treat all files as text')),
2707 ('a', 'text', None, _('treat all files as text')),
2708 ('f', 'follow', None,
2708 ('f', 'follow', None,
2709 _('follow changeset history,'
2709 _('follow changeset history,'
2710 ' or file history across copies and renames')),
2710 ' or file history across copies and renames')),
2711 ('i', 'ignore-case', None, _('ignore case when matching')),
2711 ('i', 'ignore-case', None, _('ignore case when matching')),
2712 ('l', 'files-with-matches', None,
2712 ('l', 'files-with-matches', None,
2713 _('print only filenames and revisions that match')),
2713 _('print only filenames and revisions that match')),
2714 ('n', 'line-number', None, _('print matching line numbers')),
2714 ('n', 'line-number', None, _('print matching line numbers')),
2715 ('r', 'rev', [],
2715 ('r', 'rev', [],
2716 _('only search files changed within revision range'), _('REV')),
2716 _('only search files changed within revision range'), _('REV')),
2717 ('', 'all-files', None,
2717 ('', 'all-files', None,
2718 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2718 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2719 ('u', 'user', None, _('list the author (long with -v)')),
2719 ('u', 'user', None, _('list the author (long with -v)')),
2720 ('d', 'date', None, _('list the date (short with -q)')),
2720 ('d', 'date', None, _('list the date (short with -q)')),
2721 ] + formatteropts + walkopts,
2721 ] + formatteropts + walkopts,
2722 _('[OPTION]... PATTERN [FILE]...'),
2722 _('[OPTION]... PATTERN [FILE]...'),
2723 helpcategory=command.CATEGORY_FILE_CONTENTS,
2723 helpcategory=command.CATEGORY_FILE_CONTENTS,
2724 inferrepo=True,
2724 inferrepo=True,
2725 intents={INTENT_READONLY})
2725 intents={INTENT_READONLY})
2726 def grep(ui, repo, pattern, *pats, **opts):
2726 def grep(ui, repo, pattern, *pats, **opts):
2727 """search revision history for a pattern in specified files
2727 """search revision history for a pattern in specified files
2728
2728
2729 Search revision history for a regular expression in the specified
2729 Search revision history for a regular expression in the specified
2730 files or the entire project.
2730 files or the entire project.
2731
2731
2732 By default, grep prints the most recent revision number for each
2732 By default, grep prints the most recent revision number for each
2733 file in which it finds a match. To get it to print every revision
2733 file in which it finds a match. To get it to print every revision
2734 that contains a change in match status ("-" for a match that becomes
2734 that contains a change in match status ("-" for a match that becomes
2735 a non-match, or "+" for a non-match that becomes a match), use the
2735 a non-match, or "+" for a non-match that becomes a match), use the
2736 --diff flag.
2736 --diff flag.
2737
2737
2738 PATTERN can be any Python (roughly Perl-compatible) regular
2738 PATTERN can be any Python (roughly Perl-compatible) regular
2739 expression.
2739 expression.
2740
2740
2741 If no FILEs are specified (and -f/--follow isn't set), all files in
2741 If no FILEs are specified (and -f/--follow isn't set), all files in
2742 the repository are searched, including those that don't exist in the
2742 the repository are searched, including those that don't exist in the
2743 current branch or have been deleted in a prior changeset.
2743 current branch or have been deleted in a prior changeset.
2744
2744
2745 .. container:: verbose
2745 .. container:: verbose
2746
2746
2747 Template:
2747 Template:
2748
2748
2749 The following keywords are supported in addition to the common template
2749 The following keywords are supported in addition to the common template
2750 keywords and functions. See also :hg:`help templates`.
2750 keywords and functions. See also :hg:`help templates`.
2751
2751
2752 :change: String. Character denoting insertion ``+`` or removal ``-``.
2752 :change: String. Character denoting insertion ``+`` or removal ``-``.
2753 Available if ``--diff`` is specified.
2753 Available if ``--diff`` is specified.
2754 :lineno: Integer. Line number of the match.
2754 :lineno: Integer. Line number of the match.
2755 :path: String. Repository-absolute path of the file.
2755 :path: String. Repository-absolute path of the file.
2756 :texts: List of text chunks.
2756 :texts: List of text chunks.
2757
2757
2758 And each entry of ``{texts}`` provides the following sub-keywords.
2758 And each entry of ``{texts}`` provides the following sub-keywords.
2759
2759
2760 :matched: Boolean. True if the chunk matches the specified pattern.
2760 :matched: Boolean. True if the chunk matches the specified pattern.
2761 :text: String. Chunk content.
2761 :text: String. Chunk content.
2762
2762
2763 See :hg:`help templates.operators` for the list expansion syntax.
2763 See :hg:`help templates.operators` for the list expansion syntax.
2764
2764
2765 Returns 0 if a match is found, 1 otherwise.
2765 Returns 0 if a match is found, 1 otherwise.
2766 """
2766 """
2767 opts = pycompat.byteskwargs(opts)
2767 opts = pycompat.byteskwargs(opts)
2768 diff = opts.get('all') or opts.get('diff')
2768 diff = opts.get('all') or opts.get('diff')
2769 all_files = opts.get('all_files')
2769 all_files = opts.get('all_files')
2770 if diff and opts.get('all_files'):
2770 if diff and opts.get('all_files'):
2771 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2771 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2772 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2772 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2773 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2773 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2774 # experimental config: commands.grep.all-files
2774 # experimental config: commands.grep.all-files
2775 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2775 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2776 plaingrep = opts.get('all_files') and not opts.get('rev')
2776 plaingrep = opts.get('all_files') and not opts.get('rev')
2777 if plaingrep:
2777 if plaingrep:
2778 opts['rev'] = ['wdir()']
2778 opts['rev'] = ['wdir()']
2779
2779
2780 reflags = re.M
2780 reflags = re.M
2781 if opts.get('ignore_case'):
2781 if opts.get('ignore_case'):
2782 reflags |= re.I
2782 reflags |= re.I
2783 try:
2783 try:
2784 regexp = util.re.compile(pattern, reflags)
2784 regexp = util.re.compile(pattern, reflags)
2785 except re.error as inst:
2785 except re.error as inst:
2786 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2786 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2787 return 1
2787 return 1
2788 sep, eol = ':', '\n'
2788 sep, eol = ':', '\n'
2789 if opts.get('print0'):
2789 if opts.get('print0'):
2790 sep = eol = '\0'
2790 sep = eol = '\0'
2791
2791
2792 getfile = util.lrucachefunc(repo.file)
2792 getfile = util.lrucachefunc(repo.file)
2793
2793
2794 def matchlines(body):
2794 def matchlines(body):
2795 begin = 0
2795 begin = 0
2796 linenum = 0
2796 linenum = 0
2797 while begin < len(body):
2797 while begin < len(body):
2798 match = regexp.search(body, begin)
2798 match = regexp.search(body, begin)
2799 if not match:
2799 if not match:
2800 break
2800 break
2801 mstart, mend = match.span()
2801 mstart, mend = match.span()
2802 linenum += body.count('\n', begin, mstart) + 1
2802 linenum += body.count('\n', begin, mstart) + 1
2803 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2803 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2804 begin = body.find('\n', mend) + 1 or len(body) + 1
2804 begin = body.find('\n', mend) + 1 or len(body) + 1
2805 lend = begin - 1
2805 lend = begin - 1
2806 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2806 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2807
2807
2808 class linestate(object):
2808 class linestate(object):
2809 def __init__(self, line, linenum, colstart, colend):
2809 def __init__(self, line, linenum, colstart, colend):
2810 self.line = line
2810 self.line = line
2811 self.linenum = linenum
2811 self.linenum = linenum
2812 self.colstart = colstart
2812 self.colstart = colstart
2813 self.colend = colend
2813 self.colend = colend
2814
2814
2815 def __hash__(self):
2815 def __hash__(self):
2816 return hash((self.linenum, self.line))
2816 return hash((self.linenum, self.line))
2817
2817
2818 def __eq__(self, other):
2818 def __eq__(self, other):
2819 return self.line == other.line
2819 return self.line == other.line
2820
2820
2821 def findpos(self):
2821 def findpos(self):
2822 """Iterate all (start, end) indices of matches"""
2822 """Iterate all (start, end) indices of matches"""
2823 yield self.colstart, self.colend
2823 yield self.colstart, self.colend
2824 p = self.colend
2824 p = self.colend
2825 while p < len(self.line):
2825 while p < len(self.line):
2826 m = regexp.search(self.line, p)
2826 m = regexp.search(self.line, p)
2827 if not m:
2827 if not m:
2828 break
2828 break
2829 yield m.span()
2829 yield m.span()
2830 p = m.end()
2830 p = m.end()
2831
2831
2832 matches = {}
2832 matches = {}
2833 copies = {}
2833 copies = {}
2834 def grepbody(fn, rev, body):
2834 def grepbody(fn, rev, body):
2835 matches[rev].setdefault(fn, [])
2835 matches[rev].setdefault(fn, [])
2836 m = matches[rev][fn]
2836 m = matches[rev][fn]
2837 for lnum, cstart, cend, line in matchlines(body):
2837 for lnum, cstart, cend, line in matchlines(body):
2838 s = linestate(line, lnum, cstart, cend)
2838 s = linestate(line, lnum, cstart, cend)
2839 m.append(s)
2839 m.append(s)
2840
2840
2841 def difflinestates(a, b):
2841 def difflinestates(a, b):
2842 sm = difflib.SequenceMatcher(None, a, b)
2842 sm = difflib.SequenceMatcher(None, a, b)
2843 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2843 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2844 if tag == r'insert':
2844 if tag == r'insert':
2845 for i in pycompat.xrange(blo, bhi):
2845 for i in pycompat.xrange(blo, bhi):
2846 yield ('+', b[i])
2846 yield ('+', b[i])
2847 elif tag == r'delete':
2847 elif tag == r'delete':
2848 for i in pycompat.xrange(alo, ahi):
2848 for i in pycompat.xrange(alo, ahi):
2849 yield ('-', a[i])
2849 yield ('-', a[i])
2850 elif tag == r'replace':
2850 elif tag == r'replace':
2851 for i in pycompat.xrange(alo, ahi):
2851 for i in pycompat.xrange(alo, ahi):
2852 yield ('-', a[i])
2852 yield ('-', a[i])
2853 for i in pycompat.xrange(blo, bhi):
2853 for i in pycompat.xrange(blo, bhi):
2854 yield ('+', b[i])
2854 yield ('+', b[i])
2855
2855
2856 uipathfn = scmutil.getuipathfn(repo)
2856 uipathfn = scmutil.getuipathfn(repo)
2857 def display(fm, fn, ctx, pstates, states):
2857 def display(fm, fn, ctx, pstates, states):
2858 rev = scmutil.intrev(ctx)
2858 rev = scmutil.intrev(ctx)
2859 if fm.isplain():
2859 if fm.isplain():
2860 formatuser = ui.shortuser
2860 formatuser = ui.shortuser
2861 else:
2861 else:
2862 formatuser = pycompat.bytestr
2862 formatuser = pycompat.bytestr
2863 if ui.quiet:
2863 if ui.quiet:
2864 datefmt = '%Y-%m-%d'
2864 datefmt = '%Y-%m-%d'
2865 else:
2865 else:
2866 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2866 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2867 found = False
2867 found = False
2868 @util.cachefunc
2868 @util.cachefunc
2869 def binary():
2869 def binary():
2870 flog = getfile(fn)
2870 flog = getfile(fn)
2871 try:
2871 try:
2872 return stringutil.binary(flog.read(ctx.filenode(fn)))
2872 return stringutil.binary(flog.read(ctx.filenode(fn)))
2873 except error.WdirUnsupported:
2873 except error.WdirUnsupported:
2874 return ctx[fn].isbinary()
2874 return ctx[fn].isbinary()
2875
2875
2876 fieldnamemap = {'linenumber': 'lineno'}
2876 fieldnamemap = {'linenumber': 'lineno'}
2877 if diff:
2877 if diff:
2878 iter = difflinestates(pstates, states)
2878 iter = difflinestates(pstates, states)
2879 else:
2879 else:
2880 iter = [('', l) for l in states]
2880 iter = [('', l) for l in states]
2881 for change, l in iter:
2881 for change, l in iter:
2882 fm.startitem()
2882 fm.startitem()
2883 fm.context(ctx=ctx)
2883 fm.context(ctx=ctx)
2884 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2884 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2885 fm.plain(uipathfn(fn), label='grep.filename')
2885 fm.plain(uipathfn(fn), label='grep.filename')
2886
2886
2887 cols = [
2887 cols = [
2888 ('rev', '%d', rev, not plaingrep),
2888 ('rev', '%d', rev, not plaingrep, ''),
2889 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2889 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2890 ]
2890 ]
2891 if diff:
2891 if diff:
2892 cols.append(('change', '%s', change, True))
2892 cols.append(
2893 ('change', '%s', change, True,
2894 'grep.inserted ' if change == '+' else 'grep.deleted ')
2895 )
2893 cols.extend([
2896 cols.extend([
2894 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2897 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2895 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2898 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2896 opts.get('date')),
2899 opts.get('date'), ''),
2897 ])
2900 ])
2898 for name, fmt, data, cond in cols:
2901 for name, fmt, data, cond, extra_label in cols:
2899 if cond:
2902 if cond:
2900 fm.plain(sep, label='grep.sep')
2903 fm.plain(sep, label='grep.sep')
2901 field = fieldnamemap.get(name, name)
2904 field = fieldnamemap.get(name, name)
2902 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2905 label = extra_label + ('grep.%s' % name)
2906 fm.condwrite(cond, field, fmt, data, label=label)
2903 if not opts.get('files_with_matches'):
2907 if not opts.get('files_with_matches'):
2904 fm.plain(sep, label='grep.sep')
2908 fm.plain(sep, label='grep.sep')
2905 if not opts.get('text') and binary():
2909 if not opts.get('text') and binary():
2906 fm.plain(_(" Binary file matches"))
2910 fm.plain(_(" Binary file matches"))
2907 else:
2911 else:
2908 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2912 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2909 fm.plain(eol)
2913 fm.plain(eol)
2910 found = True
2914 found = True
2911 if opts.get('files_with_matches'):
2915 if opts.get('files_with_matches'):
2912 break
2916 break
2913 return found
2917 return found
2914
2918
2915 def displaymatches(fm, l):
2919 def displaymatches(fm, l):
2916 p = 0
2920 p = 0
2917 for s, e in l.findpos():
2921 for s, e in l.findpos():
2918 if p < s:
2922 if p < s:
2919 fm.startitem()
2923 fm.startitem()
2920 fm.write('text', '%s', l.line[p:s])
2924 fm.write('text', '%s', l.line[p:s])
2921 fm.data(matched=False)
2925 fm.data(matched=False)
2922 fm.startitem()
2926 fm.startitem()
2923 fm.write('text', '%s', l.line[s:e], label='grep.match')
2927 fm.write('text', '%s', l.line[s:e], label='grep.match')
2924 fm.data(matched=True)
2928 fm.data(matched=True)
2925 p = e
2929 p = e
2926 if p < len(l.line):
2930 if p < len(l.line):
2927 fm.startitem()
2931 fm.startitem()
2928 fm.write('text', '%s', l.line[p:])
2932 fm.write('text', '%s', l.line[p:])
2929 fm.data(matched=False)
2933 fm.data(matched=False)
2930 fm.end()
2934 fm.end()
2931
2935
2932 skip = set()
2936 skip = set()
2933 revfiles = {}
2937 revfiles = {}
2934 match = scmutil.match(repo[None], pats, opts)
2938 match = scmutil.match(repo[None], pats, opts)
2935 found = False
2939 found = False
2936 follow = opts.get('follow')
2940 follow = opts.get('follow')
2937
2941
2938 def prep(ctx, fns):
2942 def prep(ctx, fns):
2939 rev = ctx.rev()
2943 rev = ctx.rev()
2940 pctx = ctx.p1()
2944 pctx = ctx.p1()
2941 parent = pctx.rev()
2945 parent = pctx.rev()
2942 matches.setdefault(rev, {})
2946 matches.setdefault(rev, {})
2943 matches.setdefault(parent, {})
2947 matches.setdefault(parent, {})
2944 files = revfiles.setdefault(rev, [])
2948 files = revfiles.setdefault(rev, [])
2945 for fn in fns:
2949 for fn in fns:
2946 flog = getfile(fn)
2950 flog = getfile(fn)
2947 try:
2951 try:
2948 fnode = ctx.filenode(fn)
2952 fnode = ctx.filenode(fn)
2949 except error.LookupError:
2953 except error.LookupError:
2950 continue
2954 continue
2951 copy = None
2955 copy = None
2952 if follow:
2956 if follow:
2953 try:
2957 try:
2954 copied = flog.renamed(fnode)
2958 copied = flog.renamed(fnode)
2955 except error.WdirUnsupported:
2959 except error.WdirUnsupported:
2956 copied = ctx[fn].renamed()
2960 copied = ctx[fn].renamed()
2957 copy = copied and copied[0]
2961 copy = copied and copied[0]
2958 if copy:
2962 if copy:
2959 copies.setdefault(rev, {})[fn] = copy
2963 copies.setdefault(rev, {})[fn] = copy
2960 if fn in skip:
2964 if fn in skip:
2961 skip.add(copy)
2965 skip.add(copy)
2962 if fn in skip:
2966 if fn in skip:
2963 continue
2967 continue
2964 files.append(fn)
2968 files.append(fn)
2965
2969
2966 if fn not in matches[rev]:
2970 if fn not in matches[rev]:
2967 try:
2971 try:
2968 content = flog.read(fnode)
2972 content = flog.read(fnode)
2969 except error.WdirUnsupported:
2973 except error.WdirUnsupported:
2970 content = ctx[fn].data()
2974 content = ctx[fn].data()
2971 grepbody(fn, rev, content)
2975 grepbody(fn, rev, content)
2972
2976
2973 pfn = copy or fn
2977 pfn = copy or fn
2974 if pfn not in matches[parent]:
2978 if pfn not in matches[parent]:
2975 try:
2979 try:
2976 fnode = pctx.filenode(pfn)
2980 fnode = pctx.filenode(pfn)
2977 grepbody(pfn, parent, flog.read(fnode))
2981 grepbody(pfn, parent, flog.read(fnode))
2978 except error.LookupError:
2982 except error.LookupError:
2979 pass
2983 pass
2980
2984
2981 ui.pager('grep')
2985 ui.pager('grep')
2982 fm = ui.formatter('grep', opts)
2986 fm = ui.formatter('grep', opts)
2983 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2987 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2984 rev = ctx.rev()
2988 rev = ctx.rev()
2985 parent = ctx.p1().rev()
2989 parent = ctx.p1().rev()
2986 for fn in sorted(revfiles.get(rev, [])):
2990 for fn in sorted(revfiles.get(rev, [])):
2987 states = matches[rev][fn]
2991 states = matches[rev][fn]
2988 copy = copies.get(rev, {}).get(fn)
2992 copy = copies.get(rev, {}).get(fn)
2989 if fn in skip:
2993 if fn in skip:
2990 if copy:
2994 if copy:
2991 skip.add(copy)
2995 skip.add(copy)
2992 continue
2996 continue
2993 pstates = matches.get(parent, {}).get(copy or fn, [])
2997 pstates = matches.get(parent, {}).get(copy or fn, [])
2994 if pstates or states:
2998 if pstates or states:
2995 r = display(fm, fn, ctx, pstates, states)
2999 r = display(fm, fn, ctx, pstates, states)
2996 found = found or r
3000 found = found or r
2997 if r and not diff and not all_files:
3001 if r and not diff and not all_files:
2998 skip.add(fn)
3002 skip.add(fn)
2999 if copy:
3003 if copy:
3000 skip.add(copy)
3004 skip.add(copy)
3001 del revfiles[rev]
3005 del revfiles[rev]
3002 # We will keep the matches dict for the duration of the window
3006 # We will keep the matches dict for the duration of the window
3003 # clear the matches dict once the window is over
3007 # clear the matches dict once the window is over
3004 if not revfiles:
3008 if not revfiles:
3005 matches.clear()
3009 matches.clear()
3006 fm.end()
3010 fm.end()
3007
3011
3008 return not found
3012 return not found
3009
3013
3010 @command('heads',
3014 @command('heads',
3011 [('r', 'rev', '',
3015 [('r', 'rev', '',
3012 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3016 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3013 ('t', 'topo', False, _('show topological heads only')),
3017 ('t', 'topo', False, _('show topological heads only')),
3014 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3018 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3015 ('c', 'closed', False, _('show normal and closed branch heads')),
3019 ('c', 'closed', False, _('show normal and closed branch heads')),
3016 ] + templateopts,
3020 ] + templateopts,
3017 _('[-ct] [-r STARTREV] [REV]...'),
3021 _('[-ct] [-r STARTREV] [REV]...'),
3018 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3022 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3019 intents={INTENT_READONLY})
3023 intents={INTENT_READONLY})
3020 def heads(ui, repo, *branchrevs, **opts):
3024 def heads(ui, repo, *branchrevs, **opts):
3021 """show branch heads
3025 """show branch heads
3022
3026
3023 With no arguments, show all open branch heads in the repository.
3027 With no arguments, show all open branch heads in the repository.
3024 Branch heads are changesets that have no descendants on the
3028 Branch heads are changesets that have no descendants on the
3025 same branch. They are where development generally takes place and
3029 same branch. They are where development generally takes place and
3026 are the usual targets for update and merge operations.
3030 are the usual targets for update and merge operations.
3027
3031
3028 If one or more REVs are given, only open branch heads on the
3032 If one or more REVs are given, only open branch heads on the
3029 branches associated with the specified changesets are shown. This
3033 branches associated with the specified changesets are shown. This
3030 means that you can use :hg:`heads .` to see the heads on the
3034 means that you can use :hg:`heads .` to see the heads on the
3031 currently checked-out branch.
3035 currently checked-out branch.
3032
3036
3033 If -c/--closed is specified, also show branch heads marked closed
3037 If -c/--closed is specified, also show branch heads marked closed
3034 (see :hg:`commit --close-branch`).
3038 (see :hg:`commit --close-branch`).
3035
3039
3036 If STARTREV is specified, only those heads that are descendants of
3040 If STARTREV is specified, only those heads that are descendants of
3037 STARTREV will be displayed.
3041 STARTREV will be displayed.
3038
3042
3039 If -t/--topo is specified, named branch mechanics will be ignored and only
3043 If -t/--topo is specified, named branch mechanics will be ignored and only
3040 topological heads (changesets with no children) will be shown.
3044 topological heads (changesets with no children) will be shown.
3041
3045
3042 Returns 0 if matching heads are found, 1 if not.
3046 Returns 0 if matching heads are found, 1 if not.
3043 """
3047 """
3044
3048
3045 opts = pycompat.byteskwargs(opts)
3049 opts = pycompat.byteskwargs(opts)
3046 start = None
3050 start = None
3047 rev = opts.get('rev')
3051 rev = opts.get('rev')
3048 if rev:
3052 if rev:
3049 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3053 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3050 start = scmutil.revsingle(repo, rev, None).node()
3054 start = scmutil.revsingle(repo, rev, None).node()
3051
3055
3052 if opts.get('topo'):
3056 if opts.get('topo'):
3053 heads = [repo[h] for h in repo.heads(start)]
3057 heads = [repo[h] for h in repo.heads(start)]
3054 else:
3058 else:
3055 heads = []
3059 heads = []
3056 for branch in repo.branchmap():
3060 for branch in repo.branchmap():
3057 heads += repo.branchheads(branch, start, opts.get('closed'))
3061 heads += repo.branchheads(branch, start, opts.get('closed'))
3058 heads = [repo[h] for h in heads]
3062 heads = [repo[h] for h in heads]
3059
3063
3060 if branchrevs:
3064 if branchrevs:
3061 branches = set(repo[r].branch()
3065 branches = set(repo[r].branch()
3062 for r in scmutil.revrange(repo, branchrevs))
3066 for r in scmutil.revrange(repo, branchrevs))
3063 heads = [h for h in heads if h.branch() in branches]
3067 heads = [h for h in heads if h.branch() in branches]
3064
3068
3065 if opts.get('active') and branchrevs:
3069 if opts.get('active') and branchrevs:
3066 dagheads = repo.heads(start)
3070 dagheads = repo.heads(start)
3067 heads = [h for h in heads if h.node() in dagheads]
3071 heads = [h for h in heads if h.node() in dagheads]
3068
3072
3069 if branchrevs:
3073 if branchrevs:
3070 haveheads = set(h.branch() for h in heads)
3074 haveheads = set(h.branch() for h in heads)
3071 if branches - haveheads:
3075 if branches - haveheads:
3072 headless = ', '.join(b for b in branches - haveheads)
3076 headless = ', '.join(b for b in branches - haveheads)
3073 msg = _('no open branch heads found on branches %s')
3077 msg = _('no open branch heads found on branches %s')
3074 if opts.get('rev'):
3078 if opts.get('rev'):
3075 msg += _(' (started at %s)') % opts['rev']
3079 msg += _(' (started at %s)') % opts['rev']
3076 ui.warn((msg + '\n') % headless)
3080 ui.warn((msg + '\n') % headless)
3077
3081
3078 if not heads:
3082 if not heads:
3079 return 1
3083 return 1
3080
3084
3081 ui.pager('heads')
3085 ui.pager('heads')
3082 heads = sorted(heads, key=lambda x: -x.rev())
3086 heads = sorted(heads, key=lambda x: -x.rev())
3083 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3087 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3084 for ctx in heads:
3088 for ctx in heads:
3085 displayer.show(ctx)
3089 displayer.show(ctx)
3086 displayer.close()
3090 displayer.close()
3087
3091
3088 @command('help',
3092 @command('help',
3089 [('e', 'extension', None, _('show only help for extensions')),
3093 [('e', 'extension', None, _('show only help for extensions')),
3090 ('c', 'command', None, _('show only help for commands')),
3094 ('c', 'command', None, _('show only help for commands')),
3091 ('k', 'keyword', None, _('show topics matching keyword')),
3095 ('k', 'keyword', None, _('show topics matching keyword')),
3092 ('s', 'system', [],
3096 ('s', 'system', [],
3093 _('show help for specific platform(s)'), _('PLATFORM')),
3097 _('show help for specific platform(s)'), _('PLATFORM')),
3094 ],
3098 ],
3095 _('[-eck] [-s PLATFORM] [TOPIC]'),
3099 _('[-eck] [-s PLATFORM] [TOPIC]'),
3096 helpcategory=command.CATEGORY_HELP,
3100 helpcategory=command.CATEGORY_HELP,
3097 norepo=True,
3101 norepo=True,
3098 intents={INTENT_READONLY})
3102 intents={INTENT_READONLY})
3099 def help_(ui, name=None, **opts):
3103 def help_(ui, name=None, **opts):
3100 """show help for a given topic or a help overview
3104 """show help for a given topic or a help overview
3101
3105
3102 With no arguments, print a list of commands with short help messages.
3106 With no arguments, print a list of commands with short help messages.
3103
3107
3104 Given a topic, extension, or command name, print help for that
3108 Given a topic, extension, or command name, print help for that
3105 topic.
3109 topic.
3106
3110
3107 Returns 0 if successful.
3111 Returns 0 if successful.
3108 """
3112 """
3109
3113
3110 keep = opts.get(r'system') or []
3114 keep = opts.get(r'system') or []
3111 if len(keep) == 0:
3115 if len(keep) == 0:
3112 if pycompat.sysplatform.startswith('win'):
3116 if pycompat.sysplatform.startswith('win'):
3113 keep.append('windows')
3117 keep.append('windows')
3114 elif pycompat.sysplatform == 'OpenVMS':
3118 elif pycompat.sysplatform == 'OpenVMS':
3115 keep.append('vms')
3119 keep.append('vms')
3116 elif pycompat.sysplatform == 'plan9':
3120 elif pycompat.sysplatform == 'plan9':
3117 keep.append('plan9')
3121 keep.append('plan9')
3118 else:
3122 else:
3119 keep.append('unix')
3123 keep.append('unix')
3120 keep.append(pycompat.sysplatform.lower())
3124 keep.append(pycompat.sysplatform.lower())
3121 if ui.verbose:
3125 if ui.verbose:
3122 keep.append('verbose')
3126 keep.append('verbose')
3123
3127
3124 commands = sys.modules[__name__]
3128 commands = sys.modules[__name__]
3125 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3129 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3126 ui.pager('help')
3130 ui.pager('help')
3127 ui.write(formatted)
3131 ui.write(formatted)
3128
3132
3129
3133
3130 @command('identify|id',
3134 @command('identify|id',
3131 [('r', 'rev', '',
3135 [('r', 'rev', '',
3132 _('identify the specified revision'), _('REV')),
3136 _('identify the specified revision'), _('REV')),
3133 ('n', 'num', None, _('show local revision number')),
3137 ('n', 'num', None, _('show local revision number')),
3134 ('i', 'id', None, _('show global revision id')),
3138 ('i', 'id', None, _('show global revision id')),
3135 ('b', 'branch', None, _('show branch')),
3139 ('b', 'branch', None, _('show branch')),
3136 ('t', 'tags', None, _('show tags')),
3140 ('t', 'tags', None, _('show tags')),
3137 ('B', 'bookmarks', None, _('show bookmarks')),
3141 ('B', 'bookmarks', None, _('show bookmarks')),
3138 ] + remoteopts + formatteropts,
3142 ] + remoteopts + formatteropts,
3139 _('[-nibtB] [-r REV] [SOURCE]'),
3143 _('[-nibtB] [-r REV] [SOURCE]'),
3140 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3144 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3141 optionalrepo=True,
3145 optionalrepo=True,
3142 intents={INTENT_READONLY})
3146 intents={INTENT_READONLY})
3143 def identify(ui, repo, source=None, rev=None,
3147 def identify(ui, repo, source=None, rev=None,
3144 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3148 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3145 """identify the working directory or specified revision
3149 """identify the working directory or specified revision
3146
3150
3147 Print a summary identifying the repository state at REV using one or
3151 Print a summary identifying the repository state at REV using one or
3148 two parent hash identifiers, followed by a "+" if the working
3152 two parent hash identifiers, followed by a "+" if the working
3149 directory has uncommitted changes, the branch name (if not default),
3153 directory has uncommitted changes, the branch name (if not default),
3150 a list of tags, and a list of bookmarks.
3154 a list of tags, and a list of bookmarks.
3151
3155
3152 When REV is not given, print a summary of the current state of the
3156 When REV is not given, print a summary of the current state of the
3153 repository including the working directory. Specify -r. to get information
3157 repository including the working directory. Specify -r. to get information
3154 of the working directory parent without scanning uncommitted changes.
3158 of the working directory parent without scanning uncommitted changes.
3155
3159
3156 Specifying a path to a repository root or Mercurial bundle will
3160 Specifying a path to a repository root or Mercurial bundle will
3157 cause lookup to operate on that repository/bundle.
3161 cause lookup to operate on that repository/bundle.
3158
3162
3159 .. container:: verbose
3163 .. container:: verbose
3160
3164
3161 Template:
3165 Template:
3162
3166
3163 The following keywords are supported in addition to the common template
3167 The following keywords are supported in addition to the common template
3164 keywords and functions. See also :hg:`help templates`.
3168 keywords and functions. See also :hg:`help templates`.
3165
3169
3166 :dirty: String. Character ``+`` denoting if the working directory has
3170 :dirty: String. Character ``+`` denoting if the working directory has
3167 uncommitted changes.
3171 uncommitted changes.
3168 :id: String. One or two nodes, optionally followed by ``+``.
3172 :id: String. One or two nodes, optionally followed by ``+``.
3169 :parents: List of strings. Parent nodes of the changeset.
3173 :parents: List of strings. Parent nodes of the changeset.
3170
3174
3171 Examples:
3175 Examples:
3172
3176
3173 - generate a build identifier for the working directory::
3177 - generate a build identifier for the working directory::
3174
3178
3175 hg id --id > build-id.dat
3179 hg id --id > build-id.dat
3176
3180
3177 - find the revision corresponding to a tag::
3181 - find the revision corresponding to a tag::
3178
3182
3179 hg id -n -r 1.3
3183 hg id -n -r 1.3
3180
3184
3181 - check the most recent revision of a remote repository::
3185 - check the most recent revision of a remote repository::
3182
3186
3183 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3187 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3184
3188
3185 See :hg:`log` for generating more information about specific revisions,
3189 See :hg:`log` for generating more information about specific revisions,
3186 including full hash identifiers.
3190 including full hash identifiers.
3187
3191
3188 Returns 0 if successful.
3192 Returns 0 if successful.
3189 """
3193 """
3190
3194
3191 opts = pycompat.byteskwargs(opts)
3195 opts = pycompat.byteskwargs(opts)
3192 if not repo and not source:
3196 if not repo and not source:
3193 raise error.Abort(_("there is no Mercurial repository here "
3197 raise error.Abort(_("there is no Mercurial repository here "
3194 "(.hg not found)"))
3198 "(.hg not found)"))
3195
3199
3196 default = not (num or id or branch or tags or bookmarks)
3200 default = not (num or id or branch or tags or bookmarks)
3197 output = []
3201 output = []
3198 revs = []
3202 revs = []
3199
3203
3200 if source:
3204 if source:
3201 source, branches = hg.parseurl(ui.expandpath(source))
3205 source, branches = hg.parseurl(ui.expandpath(source))
3202 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3206 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3203 repo = peer.local()
3207 repo = peer.local()
3204 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3208 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3205
3209
3206 fm = ui.formatter('identify', opts)
3210 fm = ui.formatter('identify', opts)
3207 fm.startitem()
3211 fm.startitem()
3208
3212
3209 if not repo:
3213 if not repo:
3210 if num or branch or tags:
3214 if num or branch or tags:
3211 raise error.Abort(
3215 raise error.Abort(
3212 _("can't query remote revision number, branch, or tags"))
3216 _("can't query remote revision number, branch, or tags"))
3213 if not rev and revs:
3217 if not rev and revs:
3214 rev = revs[0]
3218 rev = revs[0]
3215 if not rev:
3219 if not rev:
3216 rev = "tip"
3220 rev = "tip"
3217
3221
3218 remoterev = peer.lookup(rev)
3222 remoterev = peer.lookup(rev)
3219 hexrev = fm.hexfunc(remoterev)
3223 hexrev = fm.hexfunc(remoterev)
3220 if default or id:
3224 if default or id:
3221 output = [hexrev]
3225 output = [hexrev]
3222 fm.data(id=hexrev)
3226 fm.data(id=hexrev)
3223
3227
3224 @util.cachefunc
3228 @util.cachefunc
3225 def getbms():
3229 def getbms():
3226 bms = []
3230 bms = []
3227
3231
3228 if 'bookmarks' in peer.listkeys('namespaces'):
3232 if 'bookmarks' in peer.listkeys('namespaces'):
3229 hexremoterev = hex(remoterev)
3233 hexremoterev = hex(remoterev)
3230 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3234 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3231 if bmr == hexremoterev]
3235 if bmr == hexremoterev]
3232
3236
3233 return sorted(bms)
3237 return sorted(bms)
3234
3238
3235 if fm.isplain():
3239 if fm.isplain():
3236 if bookmarks:
3240 if bookmarks:
3237 output.extend(getbms())
3241 output.extend(getbms())
3238 elif default and not ui.quiet:
3242 elif default and not ui.quiet:
3239 # multiple bookmarks for a single parent separated by '/'
3243 # multiple bookmarks for a single parent separated by '/'
3240 bm = '/'.join(getbms())
3244 bm = '/'.join(getbms())
3241 if bm:
3245 if bm:
3242 output.append(bm)
3246 output.append(bm)
3243 else:
3247 else:
3244 fm.data(node=hex(remoterev))
3248 fm.data(node=hex(remoterev))
3245 if bookmarks or 'bookmarks' in fm.datahint():
3249 if bookmarks or 'bookmarks' in fm.datahint():
3246 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3250 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3247 else:
3251 else:
3248 if rev:
3252 if rev:
3249 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3253 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3250 ctx = scmutil.revsingle(repo, rev, None)
3254 ctx = scmutil.revsingle(repo, rev, None)
3251
3255
3252 if ctx.rev() is None:
3256 if ctx.rev() is None:
3253 ctx = repo[None]
3257 ctx = repo[None]
3254 parents = ctx.parents()
3258 parents = ctx.parents()
3255 taglist = []
3259 taglist = []
3256 for p in parents:
3260 for p in parents:
3257 taglist.extend(p.tags())
3261 taglist.extend(p.tags())
3258
3262
3259 dirty = ""
3263 dirty = ""
3260 if ctx.dirty(missing=True, merge=False, branch=False):
3264 if ctx.dirty(missing=True, merge=False, branch=False):
3261 dirty = '+'
3265 dirty = '+'
3262 fm.data(dirty=dirty)
3266 fm.data(dirty=dirty)
3263
3267
3264 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3268 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3265 if default or id:
3269 if default or id:
3266 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3270 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3267 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3271 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3268
3272
3269 if num:
3273 if num:
3270 numoutput = ["%d" % p.rev() for p in parents]
3274 numoutput = ["%d" % p.rev() for p in parents]
3271 output.append("%s%s" % ('+'.join(numoutput), dirty))
3275 output.append("%s%s" % ('+'.join(numoutput), dirty))
3272
3276
3273 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3277 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3274 for p in parents], name='node'))
3278 for p in parents], name='node'))
3275 else:
3279 else:
3276 hexoutput = fm.hexfunc(ctx.node())
3280 hexoutput = fm.hexfunc(ctx.node())
3277 if default or id:
3281 if default or id:
3278 output = [hexoutput]
3282 output = [hexoutput]
3279 fm.data(id=hexoutput)
3283 fm.data(id=hexoutput)
3280
3284
3281 if num:
3285 if num:
3282 output.append(pycompat.bytestr(ctx.rev()))
3286 output.append(pycompat.bytestr(ctx.rev()))
3283 taglist = ctx.tags()
3287 taglist = ctx.tags()
3284
3288
3285 if default and not ui.quiet:
3289 if default and not ui.quiet:
3286 b = ctx.branch()
3290 b = ctx.branch()
3287 if b != 'default':
3291 if b != 'default':
3288 output.append("(%s)" % b)
3292 output.append("(%s)" % b)
3289
3293
3290 # multiple tags for a single parent separated by '/'
3294 # multiple tags for a single parent separated by '/'
3291 t = '/'.join(taglist)
3295 t = '/'.join(taglist)
3292 if t:
3296 if t:
3293 output.append(t)
3297 output.append(t)
3294
3298
3295 # multiple bookmarks for a single parent separated by '/'
3299 # multiple bookmarks for a single parent separated by '/'
3296 bm = '/'.join(ctx.bookmarks())
3300 bm = '/'.join(ctx.bookmarks())
3297 if bm:
3301 if bm:
3298 output.append(bm)
3302 output.append(bm)
3299 else:
3303 else:
3300 if branch:
3304 if branch:
3301 output.append(ctx.branch())
3305 output.append(ctx.branch())
3302
3306
3303 if tags:
3307 if tags:
3304 output.extend(taglist)
3308 output.extend(taglist)
3305
3309
3306 if bookmarks:
3310 if bookmarks:
3307 output.extend(ctx.bookmarks())
3311 output.extend(ctx.bookmarks())
3308
3312
3309 fm.data(node=ctx.hex())
3313 fm.data(node=ctx.hex())
3310 fm.data(branch=ctx.branch())
3314 fm.data(branch=ctx.branch())
3311 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3315 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3312 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3316 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3313 fm.context(ctx=ctx)
3317 fm.context(ctx=ctx)
3314
3318
3315 fm.plain("%s\n" % ' '.join(output))
3319 fm.plain("%s\n" % ' '.join(output))
3316 fm.end()
3320 fm.end()
3317
3321
3318 @command('import|patch',
3322 @command('import|patch',
3319 [('p', 'strip', 1,
3323 [('p', 'strip', 1,
3320 _('directory strip option for patch. This has the same '
3324 _('directory strip option for patch. This has the same '
3321 'meaning as the corresponding patch option'), _('NUM')),
3325 'meaning as the corresponding patch option'), _('NUM')),
3322 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3326 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3323 ('e', 'edit', False, _('invoke editor on commit messages')),
3327 ('e', 'edit', False, _('invoke editor on commit messages')),
3324 ('f', 'force', None,
3328 ('f', 'force', None,
3325 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3329 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3326 ('', 'no-commit', None,
3330 ('', 'no-commit', None,
3327 _("don't commit, just update the working directory")),
3331 _("don't commit, just update the working directory")),
3328 ('', 'bypass', None,
3332 ('', 'bypass', None,
3329 _("apply patch without touching the working directory")),
3333 _("apply patch without touching the working directory")),
3330 ('', 'partial', None,
3334 ('', 'partial', None,
3331 _('commit even if some hunks fail')),
3335 _('commit even if some hunks fail')),
3332 ('', 'exact', None,
3336 ('', 'exact', None,
3333 _('abort if patch would apply lossily')),
3337 _('abort if patch would apply lossily')),
3334 ('', 'prefix', '',
3338 ('', 'prefix', '',
3335 _('apply patch to subdirectory'), _('DIR')),
3339 _('apply patch to subdirectory'), _('DIR')),
3336 ('', 'import-branch', None,
3340 ('', 'import-branch', None,
3337 _('use any branch information in patch (implied by --exact)'))] +
3341 _('use any branch information in patch (implied by --exact)'))] +
3338 commitopts + commitopts2 + similarityopts,
3342 commitopts + commitopts2 + similarityopts,
3339 _('[OPTION]... PATCH...'),
3343 _('[OPTION]... PATCH...'),
3340 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3344 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3341 def import_(ui, repo, patch1=None, *patches, **opts):
3345 def import_(ui, repo, patch1=None, *patches, **opts):
3342 """import an ordered set of patches
3346 """import an ordered set of patches
3343
3347
3344 Import a list of patches and commit them individually (unless
3348 Import a list of patches and commit them individually (unless
3345 --no-commit is specified).
3349 --no-commit is specified).
3346
3350
3347 To read a patch from standard input (stdin), use "-" as the patch
3351 To read a patch from standard input (stdin), use "-" as the patch
3348 name. If a URL is specified, the patch will be downloaded from
3352 name. If a URL is specified, the patch will be downloaded from
3349 there.
3353 there.
3350
3354
3351 Import first applies changes to the working directory (unless
3355 Import first applies changes to the working directory (unless
3352 --bypass is specified), import will abort if there are outstanding
3356 --bypass is specified), import will abort if there are outstanding
3353 changes.
3357 changes.
3354
3358
3355 Use --bypass to apply and commit patches directly to the
3359 Use --bypass to apply and commit patches directly to the
3356 repository, without affecting the working directory. Without
3360 repository, without affecting the working directory. Without
3357 --exact, patches will be applied on top of the working directory
3361 --exact, patches will be applied on top of the working directory
3358 parent revision.
3362 parent revision.
3359
3363
3360 You can import a patch straight from a mail message. Even patches
3364 You can import a patch straight from a mail message. Even patches
3361 as attachments work (to use the body part, it must have type
3365 as attachments work (to use the body part, it must have type
3362 text/plain or text/x-patch). From and Subject headers of email
3366 text/plain or text/x-patch). From and Subject headers of email
3363 message are used as default committer and commit message. All
3367 message are used as default committer and commit message. All
3364 text/plain body parts before first diff are added to the commit
3368 text/plain body parts before first diff are added to the commit
3365 message.
3369 message.
3366
3370
3367 If the imported patch was generated by :hg:`export`, user and
3371 If the imported patch was generated by :hg:`export`, user and
3368 description from patch override values from message headers and
3372 description from patch override values from message headers and
3369 body. Values given on command line with -m/--message and -u/--user
3373 body. Values given on command line with -m/--message and -u/--user
3370 override these.
3374 override these.
3371
3375
3372 If --exact is specified, import will set the working directory to
3376 If --exact is specified, import will set the working directory to
3373 the parent of each patch before applying it, and will abort if the
3377 the parent of each patch before applying it, and will abort if the
3374 resulting changeset has a different ID than the one recorded in
3378 resulting changeset has a different ID than the one recorded in
3375 the patch. This will guard against various ways that portable
3379 the patch. This will guard against various ways that portable
3376 patch formats and mail systems might fail to transfer Mercurial
3380 patch formats and mail systems might fail to transfer Mercurial
3377 data or metadata. See :hg:`bundle` for lossless transmission.
3381 data or metadata. See :hg:`bundle` for lossless transmission.
3378
3382
3379 Use --partial to ensure a changeset will be created from the patch
3383 Use --partial to ensure a changeset will be created from the patch
3380 even if some hunks fail to apply. Hunks that fail to apply will be
3384 even if some hunks fail to apply. Hunks that fail to apply will be
3381 written to a <target-file>.rej file. Conflicts can then be resolved
3385 written to a <target-file>.rej file. Conflicts can then be resolved
3382 by hand before :hg:`commit --amend` is run to update the created
3386 by hand before :hg:`commit --amend` is run to update the created
3383 changeset. This flag exists to let people import patches that
3387 changeset. This flag exists to let people import patches that
3384 partially apply without losing the associated metadata (author,
3388 partially apply without losing the associated metadata (author,
3385 date, description, ...).
3389 date, description, ...).
3386
3390
3387 .. note::
3391 .. note::
3388
3392
3389 When no hunks apply cleanly, :hg:`import --partial` will create
3393 When no hunks apply cleanly, :hg:`import --partial` will create
3390 an empty changeset, importing only the patch metadata.
3394 an empty changeset, importing only the patch metadata.
3391
3395
3392 With -s/--similarity, hg will attempt to discover renames and
3396 With -s/--similarity, hg will attempt to discover renames and
3393 copies in the patch in the same way as :hg:`addremove`.
3397 copies in the patch in the same way as :hg:`addremove`.
3394
3398
3395 It is possible to use external patch programs to perform the patch
3399 It is possible to use external patch programs to perform the patch
3396 by setting the ``ui.patch`` configuration option. For the default
3400 by setting the ``ui.patch`` configuration option. For the default
3397 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3401 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3398 See :hg:`help config` for more information about configuration
3402 See :hg:`help config` for more information about configuration
3399 files and how to use these options.
3403 files and how to use these options.
3400
3404
3401 See :hg:`help dates` for a list of formats valid for -d/--date.
3405 See :hg:`help dates` for a list of formats valid for -d/--date.
3402
3406
3403 .. container:: verbose
3407 .. container:: verbose
3404
3408
3405 Examples:
3409 Examples:
3406
3410
3407 - import a traditional patch from a website and detect renames::
3411 - import a traditional patch from a website and detect renames::
3408
3412
3409 hg import -s 80 http://example.com/bugfix.patch
3413 hg import -s 80 http://example.com/bugfix.patch
3410
3414
3411 - import a changeset from an hgweb server::
3415 - import a changeset from an hgweb server::
3412
3416
3413 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3417 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3414
3418
3415 - import all the patches in an Unix-style mbox::
3419 - import all the patches in an Unix-style mbox::
3416
3420
3417 hg import incoming-patches.mbox
3421 hg import incoming-patches.mbox
3418
3422
3419 - import patches from stdin::
3423 - import patches from stdin::
3420
3424
3421 hg import -
3425 hg import -
3422
3426
3423 - attempt to exactly restore an exported changeset (not always
3427 - attempt to exactly restore an exported changeset (not always
3424 possible)::
3428 possible)::
3425
3429
3426 hg import --exact proposed-fix.patch
3430 hg import --exact proposed-fix.patch
3427
3431
3428 - use an external tool to apply a patch which is too fuzzy for
3432 - use an external tool to apply a patch which is too fuzzy for
3429 the default internal tool.
3433 the default internal tool.
3430
3434
3431 hg import --config ui.patch="patch --merge" fuzzy.patch
3435 hg import --config ui.patch="patch --merge" fuzzy.patch
3432
3436
3433 - change the default fuzzing from 2 to a less strict 7
3437 - change the default fuzzing from 2 to a less strict 7
3434
3438
3435 hg import --config ui.fuzz=7 fuzz.patch
3439 hg import --config ui.fuzz=7 fuzz.patch
3436
3440
3437 Returns 0 on success, 1 on partial success (see --partial).
3441 Returns 0 on success, 1 on partial success (see --partial).
3438 """
3442 """
3439
3443
3440 opts = pycompat.byteskwargs(opts)
3444 opts = pycompat.byteskwargs(opts)
3441 if not patch1:
3445 if not patch1:
3442 raise error.Abort(_('need at least one patch to import'))
3446 raise error.Abort(_('need at least one patch to import'))
3443
3447
3444 patches = (patch1,) + patches
3448 patches = (patch1,) + patches
3445
3449
3446 date = opts.get('date')
3450 date = opts.get('date')
3447 if date:
3451 if date:
3448 opts['date'] = dateutil.parsedate(date)
3452 opts['date'] = dateutil.parsedate(date)
3449
3453
3450 exact = opts.get('exact')
3454 exact = opts.get('exact')
3451 update = not opts.get('bypass')
3455 update = not opts.get('bypass')
3452 if not update and opts.get('no_commit'):
3456 if not update and opts.get('no_commit'):
3453 raise error.Abort(_('cannot use --no-commit with --bypass'))
3457 raise error.Abort(_('cannot use --no-commit with --bypass'))
3454 try:
3458 try:
3455 sim = float(opts.get('similarity') or 0)
3459 sim = float(opts.get('similarity') or 0)
3456 except ValueError:
3460 except ValueError:
3457 raise error.Abort(_('similarity must be a number'))
3461 raise error.Abort(_('similarity must be a number'))
3458 if sim < 0 or sim > 100:
3462 if sim < 0 or sim > 100:
3459 raise error.Abort(_('similarity must be between 0 and 100'))
3463 raise error.Abort(_('similarity must be between 0 and 100'))
3460 if sim and not update:
3464 if sim and not update:
3461 raise error.Abort(_('cannot use --similarity with --bypass'))
3465 raise error.Abort(_('cannot use --similarity with --bypass'))
3462 if exact:
3466 if exact:
3463 if opts.get('edit'):
3467 if opts.get('edit'):
3464 raise error.Abort(_('cannot use --exact with --edit'))
3468 raise error.Abort(_('cannot use --exact with --edit'))
3465 if opts.get('prefix'):
3469 if opts.get('prefix'):
3466 raise error.Abort(_('cannot use --exact with --prefix'))
3470 raise error.Abort(_('cannot use --exact with --prefix'))
3467
3471
3468 base = opts["base"]
3472 base = opts["base"]
3469 msgs = []
3473 msgs = []
3470 ret = 0
3474 ret = 0
3471
3475
3472 with repo.wlock():
3476 with repo.wlock():
3473 if update:
3477 if update:
3474 cmdutil.checkunfinished(repo)
3478 cmdutil.checkunfinished(repo)
3475 if (exact or not opts.get('force')):
3479 if (exact or not opts.get('force')):
3476 cmdutil.bailifchanged(repo)
3480 cmdutil.bailifchanged(repo)
3477
3481
3478 if not opts.get('no_commit'):
3482 if not opts.get('no_commit'):
3479 lock = repo.lock
3483 lock = repo.lock
3480 tr = lambda: repo.transaction('import')
3484 tr = lambda: repo.transaction('import')
3481 dsguard = util.nullcontextmanager
3485 dsguard = util.nullcontextmanager
3482 else:
3486 else:
3483 lock = util.nullcontextmanager
3487 lock = util.nullcontextmanager
3484 tr = util.nullcontextmanager
3488 tr = util.nullcontextmanager
3485 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3489 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3486 with lock(), tr(), dsguard():
3490 with lock(), tr(), dsguard():
3487 parents = repo[None].parents()
3491 parents = repo[None].parents()
3488 for patchurl in patches:
3492 for patchurl in patches:
3489 if patchurl == '-':
3493 if patchurl == '-':
3490 ui.status(_('applying patch from stdin\n'))
3494 ui.status(_('applying patch from stdin\n'))
3491 patchfile = ui.fin
3495 patchfile = ui.fin
3492 patchurl = 'stdin' # for error message
3496 patchurl = 'stdin' # for error message
3493 else:
3497 else:
3494 patchurl = os.path.join(base, patchurl)
3498 patchurl = os.path.join(base, patchurl)
3495 ui.status(_('applying %s\n') % patchurl)
3499 ui.status(_('applying %s\n') % patchurl)
3496 patchfile = hg.openpath(ui, patchurl)
3500 patchfile = hg.openpath(ui, patchurl)
3497
3501
3498 haspatch = False
3502 haspatch = False
3499 for hunk in patch.split(patchfile):
3503 for hunk in patch.split(patchfile):
3500 with patch.extract(ui, hunk) as patchdata:
3504 with patch.extract(ui, hunk) as patchdata:
3501 msg, node, rej = cmdutil.tryimportone(ui, repo,
3505 msg, node, rej = cmdutil.tryimportone(ui, repo,
3502 patchdata,
3506 patchdata,
3503 parents, opts,
3507 parents, opts,
3504 msgs, hg.clean)
3508 msgs, hg.clean)
3505 if msg:
3509 if msg:
3506 haspatch = True
3510 haspatch = True
3507 ui.note(msg + '\n')
3511 ui.note(msg + '\n')
3508 if update or exact:
3512 if update or exact:
3509 parents = repo[None].parents()
3513 parents = repo[None].parents()
3510 else:
3514 else:
3511 parents = [repo[node]]
3515 parents = [repo[node]]
3512 if rej:
3516 if rej:
3513 ui.write_err(_("patch applied partially\n"))
3517 ui.write_err(_("patch applied partially\n"))
3514 ui.write_err(_("(fix the .rej files and run "
3518 ui.write_err(_("(fix the .rej files and run "
3515 "`hg commit --amend`)\n"))
3519 "`hg commit --amend`)\n"))
3516 ret = 1
3520 ret = 1
3517 break
3521 break
3518
3522
3519 if not haspatch:
3523 if not haspatch:
3520 raise error.Abort(_('%s: no diffs found') % patchurl)
3524 raise error.Abort(_('%s: no diffs found') % patchurl)
3521
3525
3522 if msgs:
3526 if msgs:
3523 repo.savecommitmessage('\n* * *\n'.join(msgs))
3527 repo.savecommitmessage('\n* * *\n'.join(msgs))
3524 return ret
3528 return ret
3525
3529
3526 @command('incoming|in',
3530 @command('incoming|in',
3527 [('f', 'force', None,
3531 [('f', 'force', None,
3528 _('run even if remote repository is unrelated')),
3532 _('run even if remote repository is unrelated')),
3529 ('n', 'newest-first', None, _('show newest record first')),
3533 ('n', 'newest-first', None, _('show newest record first')),
3530 ('', 'bundle', '',
3534 ('', 'bundle', '',
3531 _('file to store the bundles into'), _('FILE')),
3535 _('file to store the bundles into'), _('FILE')),
3532 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3536 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3533 ('B', 'bookmarks', False, _("compare bookmarks")),
3537 ('B', 'bookmarks', False, _("compare bookmarks")),
3534 ('b', 'branch', [],
3538 ('b', 'branch', [],
3535 _('a specific branch you would like to pull'), _('BRANCH')),
3539 _('a specific branch you would like to pull'), _('BRANCH')),
3536 ] + logopts + remoteopts + subrepoopts,
3540 ] + logopts + remoteopts + subrepoopts,
3537 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3541 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3538 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3542 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3539 def incoming(ui, repo, source="default", **opts):
3543 def incoming(ui, repo, source="default", **opts):
3540 """show new changesets found in source
3544 """show new changesets found in source
3541
3545
3542 Show new changesets found in the specified path/URL or the default
3546 Show new changesets found in the specified path/URL or the default
3543 pull location. These are the changesets that would have been pulled
3547 pull location. These are the changesets that would have been pulled
3544 by :hg:`pull` at the time you issued this command.
3548 by :hg:`pull` at the time you issued this command.
3545
3549
3546 See pull for valid source format details.
3550 See pull for valid source format details.
3547
3551
3548 .. container:: verbose
3552 .. container:: verbose
3549
3553
3550 With -B/--bookmarks, the result of bookmark comparison between
3554 With -B/--bookmarks, the result of bookmark comparison between
3551 local and remote repositories is displayed. With -v/--verbose,
3555 local and remote repositories is displayed. With -v/--verbose,
3552 status is also displayed for each bookmark like below::
3556 status is also displayed for each bookmark like below::
3553
3557
3554 BM1 01234567890a added
3558 BM1 01234567890a added
3555 BM2 1234567890ab advanced
3559 BM2 1234567890ab advanced
3556 BM3 234567890abc diverged
3560 BM3 234567890abc diverged
3557 BM4 34567890abcd changed
3561 BM4 34567890abcd changed
3558
3562
3559 The action taken locally when pulling depends on the
3563 The action taken locally when pulling depends on the
3560 status of each bookmark:
3564 status of each bookmark:
3561
3565
3562 :``added``: pull will create it
3566 :``added``: pull will create it
3563 :``advanced``: pull will update it
3567 :``advanced``: pull will update it
3564 :``diverged``: pull will create a divergent bookmark
3568 :``diverged``: pull will create a divergent bookmark
3565 :``changed``: result depends on remote changesets
3569 :``changed``: result depends on remote changesets
3566
3570
3567 From the point of view of pulling behavior, bookmark
3571 From the point of view of pulling behavior, bookmark
3568 existing only in the remote repository are treated as ``added``,
3572 existing only in the remote repository are treated as ``added``,
3569 even if it is in fact locally deleted.
3573 even if it is in fact locally deleted.
3570
3574
3571 .. container:: verbose
3575 .. container:: verbose
3572
3576
3573 For remote repository, using --bundle avoids downloading the
3577 For remote repository, using --bundle avoids downloading the
3574 changesets twice if the incoming is followed by a pull.
3578 changesets twice if the incoming is followed by a pull.
3575
3579
3576 Examples:
3580 Examples:
3577
3581
3578 - show incoming changes with patches and full description::
3582 - show incoming changes with patches and full description::
3579
3583
3580 hg incoming -vp
3584 hg incoming -vp
3581
3585
3582 - show incoming changes excluding merges, store a bundle::
3586 - show incoming changes excluding merges, store a bundle::
3583
3587
3584 hg in -vpM --bundle incoming.hg
3588 hg in -vpM --bundle incoming.hg
3585 hg pull incoming.hg
3589 hg pull incoming.hg
3586
3590
3587 - briefly list changes inside a bundle::
3591 - briefly list changes inside a bundle::
3588
3592
3589 hg in changes.hg -T "{desc|firstline}\\n"
3593 hg in changes.hg -T "{desc|firstline}\\n"
3590
3594
3591 Returns 0 if there are incoming changes, 1 otherwise.
3595 Returns 0 if there are incoming changes, 1 otherwise.
3592 """
3596 """
3593 opts = pycompat.byteskwargs(opts)
3597 opts = pycompat.byteskwargs(opts)
3594 if opts.get('graph'):
3598 if opts.get('graph'):
3595 logcmdutil.checkunsupportedgraphflags([], opts)
3599 logcmdutil.checkunsupportedgraphflags([], opts)
3596 def display(other, chlist, displayer):
3600 def display(other, chlist, displayer):
3597 revdag = logcmdutil.graphrevs(other, chlist, opts)
3601 revdag = logcmdutil.graphrevs(other, chlist, opts)
3598 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3602 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3599 graphmod.asciiedges)
3603 graphmod.asciiedges)
3600
3604
3601 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3605 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3602 return 0
3606 return 0
3603
3607
3604 if opts.get('bundle') and opts.get('subrepos'):
3608 if opts.get('bundle') and opts.get('subrepos'):
3605 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3609 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3606
3610
3607 if opts.get('bookmarks'):
3611 if opts.get('bookmarks'):
3608 source, branches = hg.parseurl(ui.expandpath(source),
3612 source, branches = hg.parseurl(ui.expandpath(source),
3609 opts.get('branch'))
3613 opts.get('branch'))
3610 other = hg.peer(repo, opts, source)
3614 other = hg.peer(repo, opts, source)
3611 if 'bookmarks' not in other.listkeys('namespaces'):
3615 if 'bookmarks' not in other.listkeys('namespaces'):
3612 ui.warn(_("remote doesn't support bookmarks\n"))
3616 ui.warn(_("remote doesn't support bookmarks\n"))
3613 return 0
3617 return 0
3614 ui.pager('incoming')
3618 ui.pager('incoming')
3615 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3619 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3616 return bookmarks.incoming(ui, repo, other)
3620 return bookmarks.incoming(ui, repo, other)
3617
3621
3618 repo._subtoppath = ui.expandpath(source)
3622 repo._subtoppath = ui.expandpath(source)
3619 try:
3623 try:
3620 return hg.incoming(ui, repo, source, opts)
3624 return hg.incoming(ui, repo, source, opts)
3621 finally:
3625 finally:
3622 del repo._subtoppath
3626 del repo._subtoppath
3623
3627
3624
3628
3625 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3629 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3626 helpcategory=command.CATEGORY_REPO_CREATION,
3630 helpcategory=command.CATEGORY_REPO_CREATION,
3627 helpbasic=True, norepo=True)
3631 helpbasic=True, norepo=True)
3628 def init(ui, dest=".", **opts):
3632 def init(ui, dest=".", **opts):
3629 """create a new repository in the given directory
3633 """create a new repository in the given directory
3630
3634
3631 Initialize a new repository in the given directory. If the given
3635 Initialize a new repository in the given directory. If the given
3632 directory does not exist, it will be created.
3636 directory does not exist, it will be created.
3633
3637
3634 If no directory is given, the current directory is used.
3638 If no directory is given, the current directory is used.
3635
3639
3636 It is possible to specify an ``ssh://`` URL as the destination.
3640 It is possible to specify an ``ssh://`` URL as the destination.
3637 See :hg:`help urls` for more information.
3641 See :hg:`help urls` for more information.
3638
3642
3639 Returns 0 on success.
3643 Returns 0 on success.
3640 """
3644 """
3641 opts = pycompat.byteskwargs(opts)
3645 opts = pycompat.byteskwargs(opts)
3642 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3646 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3643
3647
3644 @command('locate',
3648 @command('locate',
3645 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3649 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3646 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3650 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3647 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3651 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3648 ] + walkopts,
3652 ] + walkopts,
3649 _('[OPTION]... [PATTERN]...'),
3653 _('[OPTION]... [PATTERN]...'),
3650 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3654 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3651 def locate(ui, repo, *pats, **opts):
3655 def locate(ui, repo, *pats, **opts):
3652 """locate files matching specific patterns (DEPRECATED)
3656 """locate files matching specific patterns (DEPRECATED)
3653
3657
3654 Print files under Mercurial control in the working directory whose
3658 Print files under Mercurial control in the working directory whose
3655 names match the given patterns.
3659 names match the given patterns.
3656
3660
3657 By default, this command searches all directories in the working
3661 By default, this command searches all directories in the working
3658 directory. To search just the current directory and its
3662 directory. To search just the current directory and its
3659 subdirectories, use "--include .".
3663 subdirectories, use "--include .".
3660
3664
3661 If no patterns are given to match, this command prints the names
3665 If no patterns are given to match, this command prints the names
3662 of all files under Mercurial control in the working directory.
3666 of all files under Mercurial control in the working directory.
3663
3667
3664 If you want to feed the output of this command into the "xargs"
3668 If you want to feed the output of this command into the "xargs"
3665 command, use the -0 option to both this command and "xargs". This
3669 command, use the -0 option to both this command and "xargs". This
3666 will avoid the problem of "xargs" treating single filenames that
3670 will avoid the problem of "xargs" treating single filenames that
3667 contain whitespace as multiple filenames.
3671 contain whitespace as multiple filenames.
3668
3672
3669 See :hg:`help files` for a more versatile command.
3673 See :hg:`help files` for a more versatile command.
3670
3674
3671 Returns 0 if a match is found, 1 otherwise.
3675 Returns 0 if a match is found, 1 otherwise.
3672 """
3676 """
3673 opts = pycompat.byteskwargs(opts)
3677 opts = pycompat.byteskwargs(opts)
3674 if opts.get('print0'):
3678 if opts.get('print0'):
3675 end = '\0'
3679 end = '\0'
3676 else:
3680 else:
3677 end = '\n'
3681 end = '\n'
3678 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3682 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3679
3683
3680 ret = 1
3684 ret = 1
3681 m = scmutil.match(ctx, pats, opts, default='relglob',
3685 m = scmutil.match(ctx, pats, opts, default='relglob',
3682 badfn=lambda x, y: False)
3686 badfn=lambda x, y: False)
3683
3687
3684 ui.pager('locate')
3688 ui.pager('locate')
3685 if ctx.rev() is None:
3689 if ctx.rev() is None:
3686 # When run on the working copy, "locate" includes removed files, so
3690 # When run on the working copy, "locate" includes removed files, so
3687 # we get the list of files from the dirstate.
3691 # we get the list of files from the dirstate.
3688 filesgen = sorted(repo.dirstate.matches(m))
3692 filesgen = sorted(repo.dirstate.matches(m))
3689 else:
3693 else:
3690 filesgen = ctx.matches(m)
3694 filesgen = ctx.matches(m)
3691 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3695 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3692 for abs in filesgen:
3696 for abs in filesgen:
3693 if opts.get('fullpath'):
3697 if opts.get('fullpath'):
3694 ui.write(repo.wjoin(abs), end)
3698 ui.write(repo.wjoin(abs), end)
3695 else:
3699 else:
3696 ui.write(uipathfn(abs), end)
3700 ui.write(uipathfn(abs), end)
3697 ret = 0
3701 ret = 0
3698
3702
3699 return ret
3703 return ret
3700
3704
3701 @command('log|history',
3705 @command('log|history',
3702 [('f', 'follow', None,
3706 [('f', 'follow', None,
3703 _('follow changeset history, or file history across copies and renames')),
3707 _('follow changeset history, or file history across copies and renames')),
3704 ('', 'follow-first', None,
3708 ('', 'follow-first', None,
3705 _('only follow the first parent of merge changesets (DEPRECATED)')),
3709 _('only follow the first parent of merge changesets (DEPRECATED)')),
3706 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3710 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3707 ('C', 'copies', None, _('show copied files')),
3711 ('C', 'copies', None, _('show copied files')),
3708 ('k', 'keyword', [],
3712 ('k', 'keyword', [],
3709 _('do case-insensitive search for a given text'), _('TEXT')),
3713 _('do case-insensitive search for a given text'), _('TEXT')),
3710 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3714 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3711 ('L', 'line-range', [],
3715 ('L', 'line-range', [],
3712 _('follow line range of specified file (EXPERIMENTAL)'),
3716 _('follow line range of specified file (EXPERIMENTAL)'),
3713 _('FILE,RANGE')),
3717 _('FILE,RANGE')),
3714 ('', 'removed', None, _('include revisions where files were removed')),
3718 ('', 'removed', None, _('include revisions where files were removed')),
3715 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3719 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3716 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3720 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3717 ('', 'only-branch', [],
3721 ('', 'only-branch', [],
3718 _('show only changesets within the given named branch (DEPRECATED)'),
3722 _('show only changesets within the given named branch (DEPRECATED)'),
3719 _('BRANCH')),
3723 _('BRANCH')),
3720 ('b', 'branch', [],
3724 ('b', 'branch', [],
3721 _('show changesets within the given named branch'), _('BRANCH')),
3725 _('show changesets within the given named branch'), _('BRANCH')),
3722 ('P', 'prune', [],
3726 ('P', 'prune', [],
3723 _('do not display revision or any of its ancestors'), _('REV')),
3727 _('do not display revision or any of its ancestors'), _('REV')),
3724 ] + logopts + walkopts,
3728 ] + logopts + walkopts,
3725 _('[OPTION]... [FILE]'),
3729 _('[OPTION]... [FILE]'),
3726 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3730 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3727 helpbasic=True, inferrepo=True,
3731 helpbasic=True, inferrepo=True,
3728 intents={INTENT_READONLY})
3732 intents={INTENT_READONLY})
3729 def log(ui, repo, *pats, **opts):
3733 def log(ui, repo, *pats, **opts):
3730 """show revision history of entire repository or files
3734 """show revision history of entire repository or files
3731
3735
3732 Print the revision history of the specified files or the entire
3736 Print the revision history of the specified files or the entire
3733 project.
3737 project.
3734
3738
3735 If no revision range is specified, the default is ``tip:0`` unless
3739 If no revision range is specified, the default is ``tip:0`` unless
3736 --follow is set, in which case the working directory parent is
3740 --follow is set, in which case the working directory parent is
3737 used as the starting revision.
3741 used as the starting revision.
3738
3742
3739 File history is shown without following rename or copy history of
3743 File history is shown without following rename or copy history of
3740 files. Use -f/--follow with a filename to follow history across
3744 files. Use -f/--follow with a filename to follow history across
3741 renames and copies. --follow without a filename will only show
3745 renames and copies. --follow without a filename will only show
3742 ancestors of the starting revision.
3746 ancestors of the starting revision.
3743
3747
3744 By default this command prints revision number and changeset id,
3748 By default this command prints revision number and changeset id,
3745 tags, non-trivial parents, user, date and time, and a summary for
3749 tags, non-trivial parents, user, date and time, and a summary for
3746 each commit. When the -v/--verbose switch is used, the list of
3750 each commit. When the -v/--verbose switch is used, the list of
3747 changed files and full commit message are shown.
3751 changed files and full commit message are shown.
3748
3752
3749 With --graph the revisions are shown as an ASCII art DAG with the most
3753 With --graph the revisions are shown as an ASCII art DAG with the most
3750 recent changeset at the top.
3754 recent changeset at the top.
3751 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3755 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3752 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3756 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3753 changeset from the lines below is a parent of the 'o' merge on the same
3757 changeset from the lines below is a parent of the 'o' merge on the same
3754 line.
3758 line.
3755 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3759 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3756 of a '|' indicates one or more revisions in a path are omitted.
3760 of a '|' indicates one or more revisions in a path are omitted.
3757
3761
3758 .. container:: verbose
3762 .. container:: verbose
3759
3763
3760 Use -L/--line-range FILE,M:N options to follow the history of lines
3764 Use -L/--line-range FILE,M:N options to follow the history of lines
3761 from M to N in FILE. With -p/--patch only diff hunks affecting
3765 from M to N in FILE. With -p/--patch only diff hunks affecting
3762 specified line range will be shown. This option requires --follow;
3766 specified line range will be shown. This option requires --follow;
3763 it can be specified multiple times. Currently, this option is not
3767 it can be specified multiple times. Currently, this option is not
3764 compatible with --graph. This option is experimental.
3768 compatible with --graph. This option is experimental.
3765
3769
3766 .. note::
3770 .. note::
3767
3771
3768 :hg:`log --patch` may generate unexpected diff output for merge
3772 :hg:`log --patch` may generate unexpected diff output for merge
3769 changesets, as it will only compare the merge changeset against
3773 changesets, as it will only compare the merge changeset against
3770 its first parent. Also, only files different from BOTH parents
3774 its first parent. Also, only files different from BOTH parents
3771 will appear in files:.
3775 will appear in files:.
3772
3776
3773 .. note::
3777 .. note::
3774
3778
3775 For performance reasons, :hg:`log FILE` may omit duplicate changes
3779 For performance reasons, :hg:`log FILE` may omit duplicate changes
3776 made on branches and will not show removals or mode changes. To
3780 made on branches and will not show removals or mode changes. To
3777 see all such changes, use the --removed switch.
3781 see all such changes, use the --removed switch.
3778
3782
3779 .. container:: verbose
3783 .. container:: verbose
3780
3784
3781 .. note::
3785 .. note::
3782
3786
3783 The history resulting from -L/--line-range options depends on diff
3787 The history resulting from -L/--line-range options depends on diff
3784 options; for instance if white-spaces are ignored, respective changes
3788 options; for instance if white-spaces are ignored, respective changes
3785 with only white-spaces in specified line range will not be listed.
3789 with only white-spaces in specified line range will not be listed.
3786
3790
3787 .. container:: verbose
3791 .. container:: verbose
3788
3792
3789 Some examples:
3793 Some examples:
3790
3794
3791 - changesets with full descriptions and file lists::
3795 - changesets with full descriptions and file lists::
3792
3796
3793 hg log -v
3797 hg log -v
3794
3798
3795 - changesets ancestral to the working directory::
3799 - changesets ancestral to the working directory::
3796
3800
3797 hg log -f
3801 hg log -f
3798
3802
3799 - last 10 commits on the current branch::
3803 - last 10 commits on the current branch::
3800
3804
3801 hg log -l 10 -b .
3805 hg log -l 10 -b .
3802
3806
3803 - changesets showing all modifications of a file, including removals::
3807 - changesets showing all modifications of a file, including removals::
3804
3808
3805 hg log --removed file.c
3809 hg log --removed file.c
3806
3810
3807 - all changesets that touch a directory, with diffs, excluding merges::
3811 - all changesets that touch a directory, with diffs, excluding merges::
3808
3812
3809 hg log -Mp lib/
3813 hg log -Mp lib/
3810
3814
3811 - all revision numbers that match a keyword::
3815 - all revision numbers that match a keyword::
3812
3816
3813 hg log -k bug --template "{rev}\\n"
3817 hg log -k bug --template "{rev}\\n"
3814
3818
3815 - the full hash identifier of the working directory parent::
3819 - the full hash identifier of the working directory parent::
3816
3820
3817 hg log -r . --template "{node}\\n"
3821 hg log -r . --template "{node}\\n"
3818
3822
3819 - list available log templates::
3823 - list available log templates::
3820
3824
3821 hg log -T list
3825 hg log -T list
3822
3826
3823 - check if a given changeset is included in a tagged release::
3827 - check if a given changeset is included in a tagged release::
3824
3828
3825 hg log -r "a21ccf and ancestor(1.9)"
3829 hg log -r "a21ccf and ancestor(1.9)"
3826
3830
3827 - find all changesets by some user in a date range::
3831 - find all changesets by some user in a date range::
3828
3832
3829 hg log -k alice -d "may 2008 to jul 2008"
3833 hg log -k alice -d "may 2008 to jul 2008"
3830
3834
3831 - summary of all changesets after the last tag::
3835 - summary of all changesets after the last tag::
3832
3836
3833 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3837 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3834
3838
3835 - changesets touching lines 13 to 23 for file.c::
3839 - changesets touching lines 13 to 23 for file.c::
3836
3840
3837 hg log -L file.c,13:23
3841 hg log -L file.c,13:23
3838
3842
3839 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3843 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3840 main.c with patch::
3844 main.c with patch::
3841
3845
3842 hg log -L file.c,13:23 -L main.c,2:6 -p
3846 hg log -L file.c,13:23 -L main.c,2:6 -p
3843
3847
3844 See :hg:`help dates` for a list of formats valid for -d/--date.
3848 See :hg:`help dates` for a list of formats valid for -d/--date.
3845
3849
3846 See :hg:`help revisions` for more about specifying and ordering
3850 See :hg:`help revisions` for more about specifying and ordering
3847 revisions.
3851 revisions.
3848
3852
3849 See :hg:`help templates` for more about pre-packaged styles and
3853 See :hg:`help templates` for more about pre-packaged styles and
3850 specifying custom templates. The default template used by the log
3854 specifying custom templates. The default template used by the log
3851 command can be customized via the ``ui.logtemplate`` configuration
3855 command can be customized via the ``ui.logtemplate`` configuration
3852 setting.
3856 setting.
3853
3857
3854 Returns 0 on success.
3858 Returns 0 on success.
3855
3859
3856 """
3860 """
3857 opts = pycompat.byteskwargs(opts)
3861 opts = pycompat.byteskwargs(opts)
3858 linerange = opts.get('line_range')
3862 linerange = opts.get('line_range')
3859
3863
3860 if linerange and not opts.get('follow'):
3864 if linerange and not opts.get('follow'):
3861 raise error.Abort(_('--line-range requires --follow'))
3865 raise error.Abort(_('--line-range requires --follow'))
3862
3866
3863 if linerange and pats:
3867 if linerange and pats:
3864 # TODO: take pats as patterns with no line-range filter
3868 # TODO: take pats as patterns with no line-range filter
3865 raise error.Abort(
3869 raise error.Abort(
3866 _('FILE arguments are not compatible with --line-range option')
3870 _('FILE arguments are not compatible with --line-range option')
3867 )
3871 )
3868
3872
3869 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3873 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3870 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3874 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3871 if linerange:
3875 if linerange:
3872 # TODO: should follow file history from logcmdutil._initialrevs(),
3876 # TODO: should follow file history from logcmdutil._initialrevs(),
3873 # then filter the result by logcmdutil._makerevset() and --limit
3877 # then filter the result by logcmdutil._makerevset() and --limit
3874 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3878 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3875
3879
3876 getrenamed = None
3880 getrenamed = None
3877 if opts.get('copies'):
3881 if opts.get('copies'):
3878 endrev = None
3882 endrev = None
3879 if revs:
3883 if revs:
3880 endrev = revs.max() + 1
3884 endrev = revs.max() + 1
3881 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3885 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3882
3886
3883 ui.pager('log')
3887 ui.pager('log')
3884 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3885 buffered=True)
3889 buffered=True)
3886 if opts.get('graph'):
3890 if opts.get('graph'):
3887 displayfn = logcmdutil.displaygraphrevs
3891 displayfn = logcmdutil.displaygraphrevs
3888 else:
3892 else:
3889 displayfn = logcmdutil.displayrevs
3893 displayfn = logcmdutil.displayrevs
3890 displayfn(ui, repo, revs, displayer, getrenamed)
3894 displayfn(ui, repo, revs, displayer, getrenamed)
3891
3895
3892 @command('manifest',
3896 @command('manifest',
3893 [('r', 'rev', '', _('revision to display'), _('REV')),
3897 [('r', 'rev', '', _('revision to display'), _('REV')),
3894 ('', 'all', False, _("list files from all revisions"))]
3898 ('', 'all', False, _("list files from all revisions"))]
3895 + formatteropts,
3899 + formatteropts,
3896 _('[-r REV]'),
3900 _('[-r REV]'),
3897 helpcategory=command.CATEGORY_MAINTENANCE,
3901 helpcategory=command.CATEGORY_MAINTENANCE,
3898 intents={INTENT_READONLY})
3902 intents={INTENT_READONLY})
3899 def manifest(ui, repo, node=None, rev=None, **opts):
3903 def manifest(ui, repo, node=None, rev=None, **opts):
3900 """output the current or given revision of the project manifest
3904 """output the current or given revision of the project manifest
3901
3905
3902 Print a list of version controlled files for the given revision.
3906 Print a list of version controlled files for the given revision.
3903 If no revision is given, the first parent of the working directory
3907 If no revision is given, the first parent of the working directory
3904 is used, or the null revision if no revision is checked out.
3908 is used, or the null revision if no revision is checked out.
3905
3909
3906 With -v, print file permissions, symlink and executable bits.
3910 With -v, print file permissions, symlink and executable bits.
3907 With --debug, print file revision hashes.
3911 With --debug, print file revision hashes.
3908
3912
3909 If option --all is specified, the list of all files from all revisions
3913 If option --all is specified, the list of all files from all revisions
3910 is printed. This includes deleted and renamed files.
3914 is printed. This includes deleted and renamed files.
3911
3915
3912 Returns 0 on success.
3916 Returns 0 on success.
3913 """
3917 """
3914 opts = pycompat.byteskwargs(opts)
3918 opts = pycompat.byteskwargs(opts)
3915 fm = ui.formatter('manifest', opts)
3919 fm = ui.formatter('manifest', opts)
3916
3920
3917 if opts.get('all'):
3921 if opts.get('all'):
3918 if rev or node:
3922 if rev or node:
3919 raise error.Abort(_("can't specify a revision with --all"))
3923 raise error.Abort(_("can't specify a revision with --all"))
3920
3924
3921 res = set()
3925 res = set()
3922 for rev in repo:
3926 for rev in repo:
3923 ctx = repo[rev]
3927 ctx = repo[rev]
3924 res |= set(ctx.files())
3928 res |= set(ctx.files())
3925
3929
3926 ui.pager('manifest')
3930 ui.pager('manifest')
3927 for f in sorted(res):
3931 for f in sorted(res):
3928 fm.startitem()
3932 fm.startitem()
3929 fm.write("path", '%s\n', f)
3933 fm.write("path", '%s\n', f)
3930 fm.end()
3934 fm.end()
3931 return
3935 return
3932
3936
3933 if rev and node:
3937 if rev and node:
3934 raise error.Abort(_("please specify just one revision"))
3938 raise error.Abort(_("please specify just one revision"))
3935
3939
3936 if not node:
3940 if not node:
3937 node = rev
3941 node = rev
3938
3942
3939 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3943 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3940 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3944 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3941 if node:
3945 if node:
3942 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3946 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3943 ctx = scmutil.revsingle(repo, node)
3947 ctx = scmutil.revsingle(repo, node)
3944 mf = ctx.manifest()
3948 mf = ctx.manifest()
3945 ui.pager('manifest')
3949 ui.pager('manifest')
3946 for f in ctx:
3950 for f in ctx:
3947 fm.startitem()
3951 fm.startitem()
3948 fm.context(ctx=ctx)
3952 fm.context(ctx=ctx)
3949 fl = ctx[f].flags()
3953 fl = ctx[f].flags()
3950 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3954 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3951 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3955 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3952 fm.write('path', '%s\n', f)
3956 fm.write('path', '%s\n', f)
3953 fm.end()
3957 fm.end()
3954
3958
3955 @command('merge',
3959 @command('merge',
3956 [('f', 'force', None,
3960 [('f', 'force', None,
3957 _('force a merge including outstanding changes (DEPRECATED)')),
3961 _('force a merge including outstanding changes (DEPRECATED)')),
3958 ('r', 'rev', '', _('revision to merge'), _('REV')),
3962 ('r', 'rev', '', _('revision to merge'), _('REV')),
3959 ('P', 'preview', None,
3963 ('P', 'preview', None,
3960 _('review revisions to merge (no merge is performed)')),
3964 _('review revisions to merge (no merge is performed)')),
3961 ('', 'abort', None, _('abort the ongoing merge')),
3965 ('', 'abort', None, _('abort the ongoing merge')),
3962 ] + mergetoolopts,
3966 ] + mergetoolopts,
3963 _('[-P] [[-r] REV]'),
3967 _('[-P] [[-r] REV]'),
3964 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3968 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3965 def merge(ui, repo, node=None, **opts):
3969 def merge(ui, repo, node=None, **opts):
3966 """merge another revision into working directory
3970 """merge another revision into working directory
3967
3971
3968 The current working directory is updated with all changes made in
3972 The current working directory is updated with all changes made in
3969 the requested revision since the last common predecessor revision.
3973 the requested revision since the last common predecessor revision.
3970
3974
3971 Files that changed between either parent are marked as changed for
3975 Files that changed between either parent are marked as changed for
3972 the next commit and a commit must be performed before any further
3976 the next commit and a commit must be performed before any further
3973 updates to the repository are allowed. The next commit will have
3977 updates to the repository are allowed. The next commit will have
3974 two parents.
3978 two parents.
3975
3979
3976 ``--tool`` can be used to specify the merge tool used for file
3980 ``--tool`` can be used to specify the merge tool used for file
3977 merges. It overrides the HGMERGE environment variable and your
3981 merges. It overrides the HGMERGE environment variable and your
3978 configuration files. See :hg:`help merge-tools` for options.
3982 configuration files. See :hg:`help merge-tools` for options.
3979
3983
3980 If no revision is specified, the working directory's parent is a
3984 If no revision is specified, the working directory's parent is a
3981 head revision, and the current branch contains exactly one other
3985 head revision, and the current branch contains exactly one other
3982 head, the other head is merged with by default. Otherwise, an
3986 head, the other head is merged with by default. Otherwise, an
3983 explicit revision with which to merge with must be provided.
3987 explicit revision with which to merge with must be provided.
3984
3988
3985 See :hg:`help resolve` for information on handling file conflicts.
3989 See :hg:`help resolve` for information on handling file conflicts.
3986
3990
3987 To undo an uncommitted merge, use :hg:`merge --abort` which
3991 To undo an uncommitted merge, use :hg:`merge --abort` which
3988 will check out a clean copy of the original merge parent, losing
3992 will check out a clean copy of the original merge parent, losing
3989 all changes.
3993 all changes.
3990
3994
3991 Returns 0 on success, 1 if there are unresolved files.
3995 Returns 0 on success, 1 if there are unresolved files.
3992 """
3996 """
3993
3997
3994 opts = pycompat.byteskwargs(opts)
3998 opts = pycompat.byteskwargs(opts)
3995 abort = opts.get('abort')
3999 abort = opts.get('abort')
3996 if abort and repo.dirstate.p2() == nullid:
4000 if abort and repo.dirstate.p2() == nullid:
3997 cmdutil.wrongtooltocontinue(repo, _('merge'))
4001 cmdutil.wrongtooltocontinue(repo, _('merge'))
3998 if abort:
4002 if abort:
3999 if node:
4003 if node:
4000 raise error.Abort(_("cannot specify a node with --abort"))
4004 raise error.Abort(_("cannot specify a node with --abort"))
4001 if opts.get('rev'):
4005 if opts.get('rev'):
4002 raise error.Abort(_("cannot specify both --rev and --abort"))
4006 raise error.Abort(_("cannot specify both --rev and --abort"))
4003 if opts.get('preview'):
4007 if opts.get('preview'):
4004 raise error.Abort(_("cannot specify --preview with --abort"))
4008 raise error.Abort(_("cannot specify --preview with --abort"))
4005 if opts.get('rev') and node:
4009 if opts.get('rev') and node:
4006 raise error.Abort(_("please specify just one revision"))
4010 raise error.Abort(_("please specify just one revision"))
4007 if not node:
4011 if not node:
4008 node = opts.get('rev')
4012 node = opts.get('rev')
4009
4013
4010 if node:
4014 if node:
4011 node = scmutil.revsingle(repo, node).node()
4015 node = scmutil.revsingle(repo, node).node()
4012
4016
4013 if not node and not abort:
4017 if not node and not abort:
4014 node = repo[destutil.destmerge(repo)].node()
4018 node = repo[destutil.destmerge(repo)].node()
4015
4019
4016 if opts.get('preview'):
4020 if opts.get('preview'):
4017 # find nodes that are ancestors of p2 but not of p1
4021 # find nodes that are ancestors of p2 but not of p1
4018 p1 = repo.lookup('.')
4022 p1 = repo.lookup('.')
4019 p2 = node
4023 p2 = node
4020 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4024 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4021
4025
4022 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4026 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4023 for node in nodes:
4027 for node in nodes:
4024 displayer.show(repo[node])
4028 displayer.show(repo[node])
4025 displayer.close()
4029 displayer.close()
4026 return 0
4030 return 0
4027
4031
4028 # ui.forcemerge is an internal variable, do not document
4032 # ui.forcemerge is an internal variable, do not document
4029 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4033 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4030 with ui.configoverride(overrides, 'merge'):
4034 with ui.configoverride(overrides, 'merge'):
4031 force = opts.get('force')
4035 force = opts.get('force')
4032 labels = ['working copy', 'merge rev']
4036 labels = ['working copy', 'merge rev']
4033 return hg.merge(repo, node, force=force, mergeforce=force,
4037 return hg.merge(repo, node, force=force, mergeforce=force,
4034 labels=labels, abort=abort)
4038 labels=labels, abort=abort)
4035
4039
4036 @command('outgoing|out',
4040 @command('outgoing|out',
4037 [('f', 'force', None, _('run even when the destination is unrelated')),
4041 [('f', 'force', None, _('run even when the destination is unrelated')),
4038 ('r', 'rev', [],
4042 ('r', 'rev', [],
4039 _('a changeset intended to be included in the destination'), _('REV')),
4043 _('a changeset intended to be included in the destination'), _('REV')),
4040 ('n', 'newest-first', None, _('show newest record first')),
4044 ('n', 'newest-first', None, _('show newest record first')),
4041 ('B', 'bookmarks', False, _('compare bookmarks')),
4045 ('B', 'bookmarks', False, _('compare bookmarks')),
4042 ('b', 'branch', [], _('a specific branch you would like to push'),
4046 ('b', 'branch', [], _('a specific branch you would like to push'),
4043 _('BRANCH')),
4047 _('BRANCH')),
4044 ] + logopts + remoteopts + subrepoopts,
4048 ] + logopts + remoteopts + subrepoopts,
4045 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4049 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4046 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4050 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4047 def outgoing(ui, repo, dest=None, **opts):
4051 def outgoing(ui, repo, dest=None, **opts):
4048 """show changesets not found in the destination
4052 """show changesets not found in the destination
4049
4053
4050 Show changesets not found in the specified destination repository
4054 Show changesets not found in the specified destination repository
4051 or the default push location. These are the changesets that would
4055 or the default push location. These are the changesets that would
4052 be pushed if a push was requested.
4056 be pushed if a push was requested.
4053
4057
4054 See pull for details of valid destination formats.
4058 See pull for details of valid destination formats.
4055
4059
4056 .. container:: verbose
4060 .. container:: verbose
4057
4061
4058 With -B/--bookmarks, the result of bookmark comparison between
4062 With -B/--bookmarks, the result of bookmark comparison between
4059 local and remote repositories is displayed. With -v/--verbose,
4063 local and remote repositories is displayed. With -v/--verbose,
4060 status is also displayed for each bookmark like below::
4064 status is also displayed for each bookmark like below::
4061
4065
4062 BM1 01234567890a added
4066 BM1 01234567890a added
4063 BM2 deleted
4067 BM2 deleted
4064 BM3 234567890abc advanced
4068 BM3 234567890abc advanced
4065 BM4 34567890abcd diverged
4069 BM4 34567890abcd diverged
4066 BM5 4567890abcde changed
4070 BM5 4567890abcde changed
4067
4071
4068 The action taken when pushing depends on the
4072 The action taken when pushing depends on the
4069 status of each bookmark:
4073 status of each bookmark:
4070
4074
4071 :``added``: push with ``-B`` will create it
4075 :``added``: push with ``-B`` will create it
4072 :``deleted``: push with ``-B`` will delete it
4076 :``deleted``: push with ``-B`` will delete it
4073 :``advanced``: push will update it
4077 :``advanced``: push will update it
4074 :``diverged``: push with ``-B`` will update it
4078 :``diverged``: push with ``-B`` will update it
4075 :``changed``: push with ``-B`` will update it
4079 :``changed``: push with ``-B`` will update it
4076
4080
4077 From the point of view of pushing behavior, bookmarks
4081 From the point of view of pushing behavior, bookmarks
4078 existing only in the remote repository are treated as
4082 existing only in the remote repository are treated as
4079 ``deleted``, even if it is in fact added remotely.
4083 ``deleted``, even if it is in fact added remotely.
4080
4084
4081 Returns 0 if there are outgoing changes, 1 otherwise.
4085 Returns 0 if there are outgoing changes, 1 otherwise.
4082 """
4086 """
4083 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4087 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4084 # style URLs, so don't overwrite dest.
4088 # style URLs, so don't overwrite dest.
4085 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4089 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4086 if not path:
4090 if not path:
4087 raise error.Abort(_('default repository not configured!'),
4091 raise error.Abort(_('default repository not configured!'),
4088 hint=_("see 'hg help config.paths'"))
4092 hint=_("see 'hg help config.paths'"))
4089
4093
4090 opts = pycompat.byteskwargs(opts)
4094 opts = pycompat.byteskwargs(opts)
4091 if opts.get('graph'):
4095 if opts.get('graph'):
4092 logcmdutil.checkunsupportedgraphflags([], opts)
4096 logcmdutil.checkunsupportedgraphflags([], opts)
4093 o, other = hg._outgoing(ui, repo, dest, opts)
4097 o, other = hg._outgoing(ui, repo, dest, opts)
4094 if not o:
4098 if not o:
4095 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4099 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4096 return
4100 return
4097
4101
4098 revdag = logcmdutil.graphrevs(repo, o, opts)
4102 revdag = logcmdutil.graphrevs(repo, o, opts)
4099 ui.pager('outgoing')
4103 ui.pager('outgoing')
4100 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4104 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4101 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4105 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4102 graphmod.asciiedges)
4106 graphmod.asciiedges)
4103 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4107 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4104 return 0
4108 return 0
4105
4109
4106 if opts.get('bookmarks'):
4110 if opts.get('bookmarks'):
4107 dest = path.pushloc or path.loc
4111 dest = path.pushloc or path.loc
4108 other = hg.peer(repo, opts, dest)
4112 other = hg.peer(repo, opts, dest)
4109 if 'bookmarks' not in other.listkeys('namespaces'):
4113 if 'bookmarks' not in other.listkeys('namespaces'):
4110 ui.warn(_("remote doesn't support bookmarks\n"))
4114 ui.warn(_("remote doesn't support bookmarks\n"))
4111 return 0
4115 return 0
4112 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4116 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4113 ui.pager('outgoing')
4117 ui.pager('outgoing')
4114 return bookmarks.outgoing(ui, repo, other)
4118 return bookmarks.outgoing(ui, repo, other)
4115
4119
4116 repo._subtoppath = path.pushloc or path.loc
4120 repo._subtoppath = path.pushloc or path.loc
4117 try:
4121 try:
4118 return hg.outgoing(ui, repo, dest, opts)
4122 return hg.outgoing(ui, repo, dest, opts)
4119 finally:
4123 finally:
4120 del repo._subtoppath
4124 del repo._subtoppath
4121
4125
4122 @command('parents',
4126 @command('parents',
4123 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4127 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4124 ] + templateopts,
4128 ] + templateopts,
4125 _('[-r REV] [FILE]'),
4129 _('[-r REV] [FILE]'),
4126 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4130 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4127 inferrepo=True)
4131 inferrepo=True)
4128 def parents(ui, repo, file_=None, **opts):
4132 def parents(ui, repo, file_=None, **opts):
4129 """show the parents of the working directory or revision (DEPRECATED)
4133 """show the parents of the working directory or revision (DEPRECATED)
4130
4134
4131 Print the working directory's parent revisions. If a revision is
4135 Print the working directory's parent revisions. If a revision is
4132 given via -r/--rev, the parent of that revision will be printed.
4136 given via -r/--rev, the parent of that revision will be printed.
4133 If a file argument is given, the revision in which the file was
4137 If a file argument is given, the revision in which the file was
4134 last changed (before the working directory revision or the
4138 last changed (before the working directory revision or the
4135 argument to --rev if given) is printed.
4139 argument to --rev if given) is printed.
4136
4140
4137 This command is equivalent to::
4141 This command is equivalent to::
4138
4142
4139 hg log -r "p1()+p2()" or
4143 hg log -r "p1()+p2()" or
4140 hg log -r "p1(REV)+p2(REV)" or
4144 hg log -r "p1(REV)+p2(REV)" or
4141 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4145 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4142 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4146 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4143
4147
4144 See :hg:`summary` and :hg:`help revsets` for related information.
4148 See :hg:`summary` and :hg:`help revsets` for related information.
4145
4149
4146 Returns 0 on success.
4150 Returns 0 on success.
4147 """
4151 """
4148
4152
4149 opts = pycompat.byteskwargs(opts)
4153 opts = pycompat.byteskwargs(opts)
4150 rev = opts.get('rev')
4154 rev = opts.get('rev')
4151 if rev:
4155 if rev:
4152 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4156 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4153 ctx = scmutil.revsingle(repo, rev, None)
4157 ctx = scmutil.revsingle(repo, rev, None)
4154
4158
4155 if file_:
4159 if file_:
4156 m = scmutil.match(ctx, (file_,), opts)
4160 m = scmutil.match(ctx, (file_,), opts)
4157 if m.anypats() or len(m.files()) != 1:
4161 if m.anypats() or len(m.files()) != 1:
4158 raise error.Abort(_('can only specify an explicit filename'))
4162 raise error.Abort(_('can only specify an explicit filename'))
4159 file_ = m.files()[0]
4163 file_ = m.files()[0]
4160 filenodes = []
4164 filenodes = []
4161 for cp in ctx.parents():
4165 for cp in ctx.parents():
4162 if not cp:
4166 if not cp:
4163 continue
4167 continue
4164 try:
4168 try:
4165 filenodes.append(cp.filenode(file_))
4169 filenodes.append(cp.filenode(file_))
4166 except error.LookupError:
4170 except error.LookupError:
4167 pass
4171 pass
4168 if not filenodes:
4172 if not filenodes:
4169 raise error.Abort(_("'%s' not found in manifest!") % file_)
4173 raise error.Abort(_("'%s' not found in manifest!") % file_)
4170 p = []
4174 p = []
4171 for fn in filenodes:
4175 for fn in filenodes:
4172 fctx = repo.filectx(file_, fileid=fn)
4176 fctx = repo.filectx(file_, fileid=fn)
4173 p.append(fctx.node())
4177 p.append(fctx.node())
4174 else:
4178 else:
4175 p = [cp.node() for cp in ctx.parents()]
4179 p = [cp.node() for cp in ctx.parents()]
4176
4180
4177 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4181 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4178 for n in p:
4182 for n in p:
4179 if n != nullid:
4183 if n != nullid:
4180 displayer.show(repo[n])
4184 displayer.show(repo[n])
4181 displayer.close()
4185 displayer.close()
4182
4186
4183 @command('paths', formatteropts, _('[NAME]'),
4187 @command('paths', formatteropts, _('[NAME]'),
4184 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4188 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4185 optionalrepo=True, intents={INTENT_READONLY})
4189 optionalrepo=True, intents={INTENT_READONLY})
4186 def paths(ui, repo, search=None, **opts):
4190 def paths(ui, repo, search=None, **opts):
4187 """show aliases for remote repositories
4191 """show aliases for remote repositories
4188
4192
4189 Show definition of symbolic path name NAME. If no name is given,
4193 Show definition of symbolic path name NAME. If no name is given,
4190 show definition of all available names.
4194 show definition of all available names.
4191
4195
4192 Option -q/--quiet suppresses all output when searching for NAME
4196 Option -q/--quiet suppresses all output when searching for NAME
4193 and shows only the path names when listing all definitions.
4197 and shows only the path names when listing all definitions.
4194
4198
4195 Path names are defined in the [paths] section of your
4199 Path names are defined in the [paths] section of your
4196 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4200 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4197 repository, ``.hg/hgrc`` is used, too.
4201 repository, ``.hg/hgrc`` is used, too.
4198
4202
4199 The path names ``default`` and ``default-push`` have a special
4203 The path names ``default`` and ``default-push`` have a special
4200 meaning. When performing a push or pull operation, they are used
4204 meaning. When performing a push or pull operation, they are used
4201 as fallbacks if no location is specified on the command-line.
4205 as fallbacks if no location is specified on the command-line.
4202 When ``default-push`` is set, it will be used for push and
4206 When ``default-push`` is set, it will be used for push and
4203 ``default`` will be used for pull; otherwise ``default`` is used
4207 ``default`` will be used for pull; otherwise ``default`` is used
4204 as the fallback for both. When cloning a repository, the clone
4208 as the fallback for both. When cloning a repository, the clone
4205 source is written as ``default`` in ``.hg/hgrc``.
4209 source is written as ``default`` in ``.hg/hgrc``.
4206
4210
4207 .. note::
4211 .. note::
4208
4212
4209 ``default`` and ``default-push`` apply to all inbound (e.g.
4213 ``default`` and ``default-push`` apply to all inbound (e.g.
4210 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4214 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4211 and :hg:`bundle`) operations.
4215 and :hg:`bundle`) operations.
4212
4216
4213 See :hg:`help urls` for more information.
4217 See :hg:`help urls` for more information.
4214
4218
4215 .. container:: verbose
4219 .. container:: verbose
4216
4220
4217 Template:
4221 Template:
4218
4222
4219 The following keywords are supported. See also :hg:`help templates`.
4223 The following keywords are supported. See also :hg:`help templates`.
4220
4224
4221 :name: String. Symbolic name of the path alias.
4225 :name: String. Symbolic name of the path alias.
4222 :pushurl: String. URL for push operations.
4226 :pushurl: String. URL for push operations.
4223 :url: String. URL or directory path for the other operations.
4227 :url: String. URL or directory path for the other operations.
4224
4228
4225 Returns 0 on success.
4229 Returns 0 on success.
4226 """
4230 """
4227
4231
4228 opts = pycompat.byteskwargs(opts)
4232 opts = pycompat.byteskwargs(opts)
4229 ui.pager('paths')
4233 ui.pager('paths')
4230 if search:
4234 if search:
4231 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4235 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4232 if name == search]
4236 if name == search]
4233 else:
4237 else:
4234 pathitems = sorted(ui.paths.iteritems())
4238 pathitems = sorted(ui.paths.iteritems())
4235
4239
4236 fm = ui.formatter('paths', opts)
4240 fm = ui.formatter('paths', opts)
4237 if fm.isplain():
4241 if fm.isplain():
4238 hidepassword = util.hidepassword
4242 hidepassword = util.hidepassword
4239 else:
4243 else:
4240 hidepassword = bytes
4244 hidepassword = bytes
4241 if ui.quiet:
4245 if ui.quiet:
4242 namefmt = '%s\n'
4246 namefmt = '%s\n'
4243 else:
4247 else:
4244 namefmt = '%s = '
4248 namefmt = '%s = '
4245 showsubopts = not search and not ui.quiet
4249 showsubopts = not search and not ui.quiet
4246
4250
4247 for name, path in pathitems:
4251 for name, path in pathitems:
4248 fm.startitem()
4252 fm.startitem()
4249 fm.condwrite(not search, 'name', namefmt, name)
4253 fm.condwrite(not search, 'name', namefmt, name)
4250 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4254 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4251 for subopt, value in sorted(path.suboptions.items()):
4255 for subopt, value in sorted(path.suboptions.items()):
4252 assert subopt not in ('name', 'url')
4256 assert subopt not in ('name', 'url')
4253 if showsubopts:
4257 if showsubopts:
4254 fm.plain('%s:%s = ' % (name, subopt))
4258 fm.plain('%s:%s = ' % (name, subopt))
4255 fm.condwrite(showsubopts, subopt, '%s\n', value)
4259 fm.condwrite(showsubopts, subopt, '%s\n', value)
4256
4260
4257 fm.end()
4261 fm.end()
4258
4262
4259 if search and not pathitems:
4263 if search and not pathitems:
4260 if not ui.quiet:
4264 if not ui.quiet:
4261 ui.warn(_("not found!\n"))
4265 ui.warn(_("not found!\n"))
4262 return 1
4266 return 1
4263 else:
4267 else:
4264 return 0
4268 return 0
4265
4269
4266 @command('phase',
4270 @command('phase',
4267 [('p', 'public', False, _('set changeset phase to public')),
4271 [('p', 'public', False, _('set changeset phase to public')),
4268 ('d', 'draft', False, _('set changeset phase to draft')),
4272 ('d', 'draft', False, _('set changeset phase to draft')),
4269 ('s', 'secret', False, _('set changeset phase to secret')),
4273 ('s', 'secret', False, _('set changeset phase to secret')),
4270 ('f', 'force', False, _('allow to move boundary backward')),
4274 ('f', 'force', False, _('allow to move boundary backward')),
4271 ('r', 'rev', [], _('target revision'), _('REV')),
4275 ('r', 'rev', [], _('target revision'), _('REV')),
4272 ],
4276 ],
4273 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4277 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4274 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4278 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4275 def phase(ui, repo, *revs, **opts):
4279 def phase(ui, repo, *revs, **opts):
4276 """set or show the current phase name
4280 """set or show the current phase name
4277
4281
4278 With no argument, show the phase name of the current revision(s).
4282 With no argument, show the phase name of the current revision(s).
4279
4283
4280 With one of -p/--public, -d/--draft or -s/--secret, change the
4284 With one of -p/--public, -d/--draft or -s/--secret, change the
4281 phase value of the specified revisions.
4285 phase value of the specified revisions.
4282
4286
4283 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4287 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4284 lower phase to a higher phase. Phases are ordered as follows::
4288 lower phase to a higher phase. Phases are ordered as follows::
4285
4289
4286 public < draft < secret
4290 public < draft < secret
4287
4291
4288 Returns 0 on success, 1 if some phases could not be changed.
4292 Returns 0 on success, 1 if some phases could not be changed.
4289
4293
4290 (For more information about the phases concept, see :hg:`help phases`.)
4294 (For more information about the phases concept, see :hg:`help phases`.)
4291 """
4295 """
4292 opts = pycompat.byteskwargs(opts)
4296 opts = pycompat.byteskwargs(opts)
4293 # search for a unique phase argument
4297 # search for a unique phase argument
4294 targetphase = None
4298 targetphase = None
4295 for idx, name in enumerate(phases.cmdphasenames):
4299 for idx, name in enumerate(phases.cmdphasenames):
4296 if opts[name]:
4300 if opts[name]:
4297 if targetphase is not None:
4301 if targetphase is not None:
4298 raise error.Abort(_('only one phase can be specified'))
4302 raise error.Abort(_('only one phase can be specified'))
4299 targetphase = idx
4303 targetphase = idx
4300
4304
4301 # look for specified revision
4305 # look for specified revision
4302 revs = list(revs)
4306 revs = list(revs)
4303 revs.extend(opts['rev'])
4307 revs.extend(opts['rev'])
4304 if not revs:
4308 if not revs:
4305 # display both parents as the second parent phase can influence
4309 # display both parents as the second parent phase can influence
4306 # the phase of a merge commit
4310 # the phase of a merge commit
4307 revs = [c.rev() for c in repo[None].parents()]
4311 revs = [c.rev() for c in repo[None].parents()]
4308
4312
4309 revs = scmutil.revrange(repo, revs)
4313 revs = scmutil.revrange(repo, revs)
4310
4314
4311 ret = 0
4315 ret = 0
4312 if targetphase is None:
4316 if targetphase is None:
4313 # display
4317 # display
4314 for r in revs:
4318 for r in revs:
4315 ctx = repo[r]
4319 ctx = repo[r]
4316 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4320 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4317 else:
4321 else:
4318 with repo.lock(), repo.transaction("phase") as tr:
4322 with repo.lock(), repo.transaction("phase") as tr:
4319 # set phase
4323 # set phase
4320 if not revs:
4324 if not revs:
4321 raise error.Abort(_('empty revision set'))
4325 raise error.Abort(_('empty revision set'))
4322 nodes = [repo[r].node() for r in revs]
4326 nodes = [repo[r].node() for r in revs]
4323 # moving revision from public to draft may hide them
4327 # moving revision from public to draft may hide them
4324 # We have to check result on an unfiltered repository
4328 # We have to check result on an unfiltered repository
4325 unfi = repo.unfiltered()
4329 unfi = repo.unfiltered()
4326 getphase = unfi._phasecache.phase
4330 getphase = unfi._phasecache.phase
4327 olddata = [getphase(unfi, r) for r in unfi]
4331 olddata = [getphase(unfi, r) for r in unfi]
4328 phases.advanceboundary(repo, tr, targetphase, nodes)
4332 phases.advanceboundary(repo, tr, targetphase, nodes)
4329 if opts['force']:
4333 if opts['force']:
4330 phases.retractboundary(repo, tr, targetphase, nodes)
4334 phases.retractboundary(repo, tr, targetphase, nodes)
4331 getphase = unfi._phasecache.phase
4335 getphase = unfi._phasecache.phase
4332 newdata = [getphase(unfi, r) for r in unfi]
4336 newdata = [getphase(unfi, r) for r in unfi]
4333 changes = sum(newdata[r] != olddata[r] for r in unfi)
4337 changes = sum(newdata[r] != olddata[r] for r in unfi)
4334 cl = unfi.changelog
4338 cl = unfi.changelog
4335 rejected = [n for n in nodes
4339 rejected = [n for n in nodes
4336 if newdata[cl.rev(n)] < targetphase]
4340 if newdata[cl.rev(n)] < targetphase]
4337 if rejected:
4341 if rejected:
4338 ui.warn(_('cannot move %i changesets to a higher '
4342 ui.warn(_('cannot move %i changesets to a higher '
4339 'phase, use --force\n') % len(rejected))
4343 'phase, use --force\n') % len(rejected))
4340 ret = 1
4344 ret = 1
4341 if changes:
4345 if changes:
4342 msg = _('phase changed for %i changesets\n') % changes
4346 msg = _('phase changed for %i changesets\n') % changes
4343 if ret:
4347 if ret:
4344 ui.status(msg)
4348 ui.status(msg)
4345 else:
4349 else:
4346 ui.note(msg)
4350 ui.note(msg)
4347 else:
4351 else:
4348 ui.warn(_('no phases changed\n'))
4352 ui.warn(_('no phases changed\n'))
4349 return ret
4353 return ret
4350
4354
4351 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4355 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4352 """Run after a changegroup has been added via pull/unbundle
4356 """Run after a changegroup has been added via pull/unbundle
4353
4357
4354 This takes arguments below:
4358 This takes arguments below:
4355
4359
4356 :modheads: change of heads by pull/unbundle
4360 :modheads: change of heads by pull/unbundle
4357 :optupdate: updating working directory is needed or not
4361 :optupdate: updating working directory is needed or not
4358 :checkout: update destination revision (or None to default destination)
4362 :checkout: update destination revision (or None to default destination)
4359 :brev: a name, which might be a bookmark to be activated after updating
4363 :brev: a name, which might be a bookmark to be activated after updating
4360 """
4364 """
4361 if modheads == 0:
4365 if modheads == 0:
4362 return
4366 return
4363 if optupdate:
4367 if optupdate:
4364 try:
4368 try:
4365 return hg.updatetotally(ui, repo, checkout, brev)
4369 return hg.updatetotally(ui, repo, checkout, brev)
4366 except error.UpdateAbort as inst:
4370 except error.UpdateAbort as inst:
4367 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4371 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4368 hint = inst.hint
4372 hint = inst.hint
4369 raise error.UpdateAbort(msg, hint=hint)
4373 raise error.UpdateAbort(msg, hint=hint)
4370 if modheads is not None and modheads > 1:
4374 if modheads is not None and modheads > 1:
4371 currentbranchheads = len(repo.branchheads())
4375 currentbranchheads = len(repo.branchheads())
4372 if currentbranchheads == modheads:
4376 if currentbranchheads == modheads:
4373 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4377 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4374 elif currentbranchheads > 1:
4378 elif currentbranchheads > 1:
4375 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4379 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4376 "merge)\n"))
4380 "merge)\n"))
4377 else:
4381 else:
4378 ui.status(_("(run 'hg heads' to see heads)\n"))
4382 ui.status(_("(run 'hg heads' to see heads)\n"))
4379 elif not ui.configbool('commands', 'update.requiredest'):
4383 elif not ui.configbool('commands', 'update.requiredest'):
4380 ui.status(_("(run 'hg update' to get a working copy)\n"))
4384 ui.status(_("(run 'hg update' to get a working copy)\n"))
4381
4385
4382 @command('pull',
4386 @command('pull',
4383 [('u', 'update', None,
4387 [('u', 'update', None,
4384 _('update to new branch head if new descendants were pulled')),
4388 _('update to new branch head if new descendants were pulled')),
4385 ('f', 'force', None, _('run even when remote repository is unrelated')),
4389 ('f', 'force', None, _('run even when remote repository is unrelated')),
4386 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4390 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4387 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4391 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4388 ('b', 'branch', [], _('a specific branch you would like to pull'),
4392 ('b', 'branch', [], _('a specific branch you would like to pull'),
4389 _('BRANCH')),
4393 _('BRANCH')),
4390 ] + remoteopts,
4394 ] + remoteopts,
4391 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4395 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4392 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4396 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4393 helpbasic=True)
4397 helpbasic=True)
4394 def pull(ui, repo, source="default", **opts):
4398 def pull(ui, repo, source="default", **opts):
4395 """pull changes from the specified source
4399 """pull changes from the specified source
4396
4400
4397 Pull changes from a remote repository to a local one.
4401 Pull changes from a remote repository to a local one.
4398
4402
4399 This finds all changes from the repository at the specified path
4403 This finds all changes from the repository at the specified path
4400 or URL and adds them to a local repository (the current one unless
4404 or URL and adds them to a local repository (the current one unless
4401 -R is specified). By default, this does not update the copy of the
4405 -R is specified). By default, this does not update the copy of the
4402 project in the working directory.
4406 project in the working directory.
4403
4407
4404 When cloning from servers that support it, Mercurial may fetch
4408 When cloning from servers that support it, Mercurial may fetch
4405 pre-generated data. When this is done, hooks operating on incoming
4409 pre-generated data. When this is done, hooks operating on incoming
4406 changesets and changegroups may fire more than once, once for each
4410 changesets and changegroups may fire more than once, once for each
4407 pre-generated bundle and as well as for any additional remaining
4411 pre-generated bundle and as well as for any additional remaining
4408 data. See :hg:`help -e clonebundles` for more.
4412 data. See :hg:`help -e clonebundles` for more.
4409
4413
4410 Use :hg:`incoming` if you want to see what would have been added
4414 Use :hg:`incoming` if you want to see what would have been added
4411 by a pull at the time you issued this command. If you then decide
4415 by a pull at the time you issued this command. If you then decide
4412 to add those changes to the repository, you should use :hg:`pull
4416 to add those changes to the repository, you should use :hg:`pull
4413 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4417 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4414
4418
4415 If SOURCE is omitted, the 'default' path will be used.
4419 If SOURCE is omitted, the 'default' path will be used.
4416 See :hg:`help urls` for more information.
4420 See :hg:`help urls` for more information.
4417
4421
4418 Specifying bookmark as ``.`` is equivalent to specifying the active
4422 Specifying bookmark as ``.`` is equivalent to specifying the active
4419 bookmark's name.
4423 bookmark's name.
4420
4424
4421 Returns 0 on success, 1 if an update had unresolved files.
4425 Returns 0 on success, 1 if an update had unresolved files.
4422 """
4426 """
4423
4427
4424 opts = pycompat.byteskwargs(opts)
4428 opts = pycompat.byteskwargs(opts)
4425 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4429 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4426 msg = _('update destination required by configuration')
4430 msg = _('update destination required by configuration')
4427 hint = _('use hg pull followed by hg update DEST')
4431 hint = _('use hg pull followed by hg update DEST')
4428 raise error.Abort(msg, hint=hint)
4432 raise error.Abort(msg, hint=hint)
4429
4433
4430 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4434 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4431 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4435 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4432 other = hg.peer(repo, opts, source)
4436 other = hg.peer(repo, opts, source)
4433 try:
4437 try:
4434 revs, checkout = hg.addbranchrevs(repo, other, branches,
4438 revs, checkout = hg.addbranchrevs(repo, other, branches,
4435 opts.get('rev'))
4439 opts.get('rev'))
4436
4440
4437 pullopargs = {}
4441 pullopargs = {}
4438
4442
4439 nodes = None
4443 nodes = None
4440 if opts.get('bookmark') or revs:
4444 if opts.get('bookmark') or revs:
4441 # The list of bookmark used here is the same used to actually update
4445 # The list of bookmark used here is the same used to actually update
4442 # the bookmark names, to avoid the race from issue 4689 and we do
4446 # the bookmark names, to avoid the race from issue 4689 and we do
4443 # all lookup and bookmark queries in one go so they see the same
4447 # all lookup and bookmark queries in one go so they see the same
4444 # version of the server state (issue 4700).
4448 # version of the server state (issue 4700).
4445 nodes = []
4449 nodes = []
4446 fnodes = []
4450 fnodes = []
4447 revs = revs or []
4451 revs = revs or []
4448 if revs and not other.capable('lookup'):
4452 if revs and not other.capable('lookup'):
4449 err = _("other repository doesn't support revision lookup, "
4453 err = _("other repository doesn't support revision lookup, "
4450 "so a rev cannot be specified.")
4454 "so a rev cannot be specified.")
4451 raise error.Abort(err)
4455 raise error.Abort(err)
4452 with other.commandexecutor() as e:
4456 with other.commandexecutor() as e:
4453 fremotebookmarks = e.callcommand('listkeys', {
4457 fremotebookmarks = e.callcommand('listkeys', {
4454 'namespace': 'bookmarks'
4458 'namespace': 'bookmarks'
4455 })
4459 })
4456 for r in revs:
4460 for r in revs:
4457 fnodes.append(e.callcommand('lookup', {'key': r}))
4461 fnodes.append(e.callcommand('lookup', {'key': r}))
4458 remotebookmarks = fremotebookmarks.result()
4462 remotebookmarks = fremotebookmarks.result()
4459 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4463 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4460 pullopargs['remotebookmarks'] = remotebookmarks
4464 pullopargs['remotebookmarks'] = remotebookmarks
4461 for b in opts.get('bookmark', []):
4465 for b in opts.get('bookmark', []):
4462 b = repo._bookmarks.expandname(b)
4466 b = repo._bookmarks.expandname(b)
4463 if b not in remotebookmarks:
4467 if b not in remotebookmarks:
4464 raise error.Abort(_('remote bookmark %s not found!') % b)
4468 raise error.Abort(_('remote bookmark %s not found!') % b)
4465 nodes.append(remotebookmarks[b])
4469 nodes.append(remotebookmarks[b])
4466 for i, rev in enumerate(revs):
4470 for i, rev in enumerate(revs):
4467 node = fnodes[i].result()
4471 node = fnodes[i].result()
4468 nodes.append(node)
4472 nodes.append(node)
4469 if rev == checkout:
4473 if rev == checkout:
4470 checkout = node
4474 checkout = node
4471
4475
4472 wlock = util.nullcontextmanager()
4476 wlock = util.nullcontextmanager()
4473 if opts.get('update'):
4477 if opts.get('update'):
4474 wlock = repo.wlock()
4478 wlock = repo.wlock()
4475 with wlock:
4479 with wlock:
4476 pullopargs.update(opts.get('opargs', {}))
4480 pullopargs.update(opts.get('opargs', {}))
4477 modheads = exchange.pull(repo, other, heads=nodes,
4481 modheads = exchange.pull(repo, other, heads=nodes,
4478 force=opts.get('force'),
4482 force=opts.get('force'),
4479 bookmarks=opts.get('bookmark', ()),
4483 bookmarks=opts.get('bookmark', ()),
4480 opargs=pullopargs).cgresult
4484 opargs=pullopargs).cgresult
4481
4485
4482 # brev is a name, which might be a bookmark to be activated at
4486 # brev is a name, which might be a bookmark to be activated at
4483 # the end of the update. In other words, it is an explicit
4487 # the end of the update. In other words, it is an explicit
4484 # destination of the update
4488 # destination of the update
4485 brev = None
4489 brev = None
4486
4490
4487 if checkout:
4491 if checkout:
4488 checkout = repo.changelog.rev(checkout)
4492 checkout = repo.changelog.rev(checkout)
4489
4493
4490 # order below depends on implementation of
4494 # order below depends on implementation of
4491 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4495 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4492 # because 'checkout' is determined without it.
4496 # because 'checkout' is determined without it.
4493 if opts.get('rev'):
4497 if opts.get('rev'):
4494 brev = opts['rev'][0]
4498 brev = opts['rev'][0]
4495 elif opts.get('branch'):
4499 elif opts.get('branch'):
4496 brev = opts['branch'][0]
4500 brev = opts['branch'][0]
4497 else:
4501 else:
4498 brev = branches[0]
4502 brev = branches[0]
4499 repo._subtoppath = source
4503 repo._subtoppath = source
4500 try:
4504 try:
4501 ret = postincoming(ui, repo, modheads, opts.get('update'),
4505 ret = postincoming(ui, repo, modheads, opts.get('update'),
4502 checkout, brev)
4506 checkout, brev)
4503
4507
4504 finally:
4508 finally:
4505 del repo._subtoppath
4509 del repo._subtoppath
4506
4510
4507 finally:
4511 finally:
4508 other.close()
4512 other.close()
4509 return ret
4513 return ret
4510
4514
4511 @command('push',
4515 @command('push',
4512 [('f', 'force', None, _('force push')),
4516 [('f', 'force', None, _('force push')),
4513 ('r', 'rev', [],
4517 ('r', 'rev', [],
4514 _('a changeset intended to be included in the destination'),
4518 _('a changeset intended to be included in the destination'),
4515 _('REV')),
4519 _('REV')),
4516 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4520 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4517 ('b', 'branch', [],
4521 ('b', 'branch', [],
4518 _('a specific branch you would like to push'), _('BRANCH')),
4522 _('a specific branch you would like to push'), _('BRANCH')),
4519 ('', 'new-branch', False, _('allow pushing a new branch')),
4523 ('', 'new-branch', False, _('allow pushing a new branch')),
4520 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4524 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4521 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4525 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4522 ] + remoteopts,
4526 ] + remoteopts,
4523 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4527 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4524 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4528 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4525 helpbasic=True)
4529 helpbasic=True)
4526 def push(ui, repo, dest=None, **opts):
4530 def push(ui, repo, dest=None, **opts):
4527 """push changes to the specified destination
4531 """push changes to the specified destination
4528
4532
4529 Push changesets from the local repository to the specified
4533 Push changesets from the local repository to the specified
4530 destination.
4534 destination.
4531
4535
4532 This operation is symmetrical to pull: it is identical to a pull
4536 This operation is symmetrical to pull: it is identical to a pull
4533 in the destination repository from the current one.
4537 in the destination repository from the current one.
4534
4538
4535 By default, push will not allow creation of new heads at the
4539 By default, push will not allow creation of new heads at the
4536 destination, since multiple heads would make it unclear which head
4540 destination, since multiple heads would make it unclear which head
4537 to use. In this situation, it is recommended to pull and merge
4541 to use. In this situation, it is recommended to pull and merge
4538 before pushing.
4542 before pushing.
4539
4543
4540 Use --new-branch if you want to allow push to create a new named
4544 Use --new-branch if you want to allow push to create a new named
4541 branch that is not present at the destination. This allows you to
4545 branch that is not present at the destination. This allows you to
4542 only create a new branch without forcing other changes.
4546 only create a new branch without forcing other changes.
4543
4547
4544 .. note::
4548 .. note::
4545
4549
4546 Extra care should be taken with the -f/--force option,
4550 Extra care should be taken with the -f/--force option,
4547 which will push all new heads on all branches, an action which will
4551 which will push all new heads on all branches, an action which will
4548 almost always cause confusion for collaborators.
4552 almost always cause confusion for collaborators.
4549
4553
4550 If -r/--rev is used, the specified revision and all its ancestors
4554 If -r/--rev is used, the specified revision and all its ancestors
4551 will be pushed to the remote repository.
4555 will be pushed to the remote repository.
4552
4556
4553 If -B/--bookmark is used, the specified bookmarked revision, its
4557 If -B/--bookmark is used, the specified bookmarked revision, its
4554 ancestors, and the bookmark will be pushed to the remote
4558 ancestors, and the bookmark will be pushed to the remote
4555 repository. Specifying ``.`` is equivalent to specifying the active
4559 repository. Specifying ``.`` is equivalent to specifying the active
4556 bookmark's name.
4560 bookmark's name.
4557
4561
4558 Please see :hg:`help urls` for important details about ``ssh://``
4562 Please see :hg:`help urls` for important details about ``ssh://``
4559 URLs. If DESTINATION is omitted, a default path will be used.
4563 URLs. If DESTINATION is omitted, a default path will be used.
4560
4564
4561 .. container:: verbose
4565 .. container:: verbose
4562
4566
4563 The --pushvars option sends strings to the server that become
4567 The --pushvars option sends strings to the server that become
4564 environment variables prepended with ``HG_USERVAR_``. For example,
4568 environment variables prepended with ``HG_USERVAR_``. For example,
4565 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4569 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4566 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4570 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4567
4571
4568 pushvars can provide for user-overridable hooks as well as set debug
4572 pushvars can provide for user-overridable hooks as well as set debug
4569 levels. One example is having a hook that blocks commits containing
4573 levels. One example is having a hook that blocks commits containing
4570 conflict markers, but enables the user to override the hook if the file
4574 conflict markers, but enables the user to override the hook if the file
4571 is using conflict markers for testing purposes or the file format has
4575 is using conflict markers for testing purposes or the file format has
4572 strings that look like conflict markers.
4576 strings that look like conflict markers.
4573
4577
4574 By default, servers will ignore `--pushvars`. To enable it add the
4578 By default, servers will ignore `--pushvars`. To enable it add the
4575 following to your configuration file::
4579 following to your configuration file::
4576
4580
4577 [push]
4581 [push]
4578 pushvars.server = true
4582 pushvars.server = true
4579
4583
4580 Returns 0 if push was successful, 1 if nothing to push.
4584 Returns 0 if push was successful, 1 if nothing to push.
4581 """
4585 """
4582
4586
4583 opts = pycompat.byteskwargs(opts)
4587 opts = pycompat.byteskwargs(opts)
4584 if opts.get('bookmark'):
4588 if opts.get('bookmark'):
4585 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4589 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4586 for b in opts['bookmark']:
4590 for b in opts['bookmark']:
4587 # translate -B options to -r so changesets get pushed
4591 # translate -B options to -r so changesets get pushed
4588 b = repo._bookmarks.expandname(b)
4592 b = repo._bookmarks.expandname(b)
4589 if b in repo._bookmarks:
4593 if b in repo._bookmarks:
4590 opts.setdefault('rev', []).append(b)
4594 opts.setdefault('rev', []).append(b)
4591 else:
4595 else:
4592 # if we try to push a deleted bookmark, translate it to null
4596 # if we try to push a deleted bookmark, translate it to null
4593 # this lets simultaneous -r, -b options continue working
4597 # this lets simultaneous -r, -b options continue working
4594 opts.setdefault('rev', []).append("null")
4598 opts.setdefault('rev', []).append("null")
4595
4599
4596 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4600 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4597 if not path:
4601 if not path:
4598 raise error.Abort(_('default repository not configured!'),
4602 raise error.Abort(_('default repository not configured!'),
4599 hint=_("see 'hg help config.paths'"))
4603 hint=_("see 'hg help config.paths'"))
4600 dest = path.pushloc or path.loc
4604 dest = path.pushloc or path.loc
4601 branches = (path.branch, opts.get('branch') or [])
4605 branches = (path.branch, opts.get('branch') or [])
4602 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4606 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4603 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4607 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4604 other = hg.peer(repo, opts, dest)
4608 other = hg.peer(repo, opts, dest)
4605
4609
4606 if revs:
4610 if revs:
4607 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4611 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4608 if not revs:
4612 if not revs:
4609 raise error.Abort(_("specified revisions evaluate to an empty set"),
4613 raise error.Abort(_("specified revisions evaluate to an empty set"),
4610 hint=_("use different revision arguments"))
4614 hint=_("use different revision arguments"))
4611 elif path.pushrev:
4615 elif path.pushrev:
4612 # It doesn't make any sense to specify ancestor revisions. So limit
4616 # It doesn't make any sense to specify ancestor revisions. So limit
4613 # to DAG heads to make discovery simpler.
4617 # to DAG heads to make discovery simpler.
4614 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4618 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4615 revs = scmutil.revrange(repo, [expr])
4619 revs = scmutil.revrange(repo, [expr])
4616 revs = [repo[rev].node() for rev in revs]
4620 revs = [repo[rev].node() for rev in revs]
4617 if not revs:
4621 if not revs:
4618 raise error.Abort(_('default push revset for path evaluates to an '
4622 raise error.Abort(_('default push revset for path evaluates to an '
4619 'empty set'))
4623 'empty set'))
4620
4624
4621 repo._subtoppath = dest
4625 repo._subtoppath = dest
4622 try:
4626 try:
4623 # push subrepos depth-first for coherent ordering
4627 # push subrepos depth-first for coherent ordering
4624 c = repo['.']
4628 c = repo['.']
4625 subs = c.substate # only repos that are committed
4629 subs = c.substate # only repos that are committed
4626 for s in sorted(subs):
4630 for s in sorted(subs):
4627 result = c.sub(s).push(opts)
4631 result = c.sub(s).push(opts)
4628 if result == 0:
4632 if result == 0:
4629 return not result
4633 return not result
4630 finally:
4634 finally:
4631 del repo._subtoppath
4635 del repo._subtoppath
4632
4636
4633 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4637 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4634 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4638 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4635
4639
4636 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4640 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4637 newbranch=opts.get('new_branch'),
4641 newbranch=opts.get('new_branch'),
4638 bookmarks=opts.get('bookmark', ()),
4642 bookmarks=opts.get('bookmark', ()),
4639 publish=opts.get('publish'),
4643 publish=opts.get('publish'),
4640 opargs=opargs)
4644 opargs=opargs)
4641
4645
4642 result = not pushop.cgresult
4646 result = not pushop.cgresult
4643
4647
4644 if pushop.bkresult is not None:
4648 if pushop.bkresult is not None:
4645 if pushop.bkresult == 2:
4649 if pushop.bkresult == 2:
4646 result = 2
4650 result = 2
4647 elif not result and pushop.bkresult:
4651 elif not result and pushop.bkresult:
4648 result = 2
4652 result = 2
4649
4653
4650 return result
4654 return result
4651
4655
4652 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4656 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4653 def recover(ui, repo):
4657 def recover(ui, repo):
4654 """roll back an interrupted transaction
4658 """roll back an interrupted transaction
4655
4659
4656 Recover from an interrupted commit or pull.
4660 Recover from an interrupted commit or pull.
4657
4661
4658 This command tries to fix the repository status after an
4662 This command tries to fix the repository status after an
4659 interrupted operation. It should only be necessary when Mercurial
4663 interrupted operation. It should only be necessary when Mercurial
4660 suggests it.
4664 suggests it.
4661
4665
4662 Returns 0 if successful, 1 if nothing to recover or verify fails.
4666 Returns 0 if successful, 1 if nothing to recover or verify fails.
4663 """
4667 """
4664 if repo.recover():
4668 if repo.recover():
4665 return hg.verify(repo)
4669 return hg.verify(repo)
4666 return 1
4670 return 1
4667
4671
4668 @command('remove|rm',
4672 @command('remove|rm',
4669 [('A', 'after', None, _('record delete for missing files')),
4673 [('A', 'after', None, _('record delete for missing files')),
4670 ('f', 'force', None,
4674 ('f', 'force', None,
4671 _('forget added files, delete modified files')),
4675 _('forget added files, delete modified files')),
4672 ] + subrepoopts + walkopts + dryrunopts,
4676 ] + subrepoopts + walkopts + dryrunopts,
4673 _('[OPTION]... FILE...'),
4677 _('[OPTION]... FILE...'),
4674 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4678 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4675 helpbasic=True, inferrepo=True)
4679 helpbasic=True, inferrepo=True)
4676 def remove(ui, repo, *pats, **opts):
4680 def remove(ui, repo, *pats, **opts):
4677 """remove the specified files on the next commit
4681 """remove the specified files on the next commit
4678
4682
4679 Schedule the indicated files for removal from the current branch.
4683 Schedule the indicated files for removal from the current branch.
4680
4684
4681 This command schedules the files to be removed at the next commit.
4685 This command schedules the files to be removed at the next commit.
4682 To undo a remove before that, see :hg:`revert`. To undo added
4686 To undo a remove before that, see :hg:`revert`. To undo added
4683 files, see :hg:`forget`.
4687 files, see :hg:`forget`.
4684
4688
4685 .. container:: verbose
4689 .. container:: verbose
4686
4690
4687 -A/--after can be used to remove only files that have already
4691 -A/--after can be used to remove only files that have already
4688 been deleted, -f/--force can be used to force deletion, and -Af
4692 been deleted, -f/--force can be used to force deletion, and -Af
4689 can be used to remove files from the next revision without
4693 can be used to remove files from the next revision without
4690 deleting them from the working directory.
4694 deleting them from the working directory.
4691
4695
4692 The following table details the behavior of remove for different
4696 The following table details the behavior of remove for different
4693 file states (columns) and option combinations (rows). The file
4697 file states (columns) and option combinations (rows). The file
4694 states are Added [A], Clean [C], Modified [M] and Missing [!]
4698 states are Added [A], Clean [C], Modified [M] and Missing [!]
4695 (as reported by :hg:`status`). The actions are Warn, Remove
4699 (as reported by :hg:`status`). The actions are Warn, Remove
4696 (from branch) and Delete (from disk):
4700 (from branch) and Delete (from disk):
4697
4701
4698 ========= == == == ==
4702 ========= == == == ==
4699 opt/state A C M !
4703 opt/state A C M !
4700 ========= == == == ==
4704 ========= == == == ==
4701 none W RD W R
4705 none W RD W R
4702 -f R RD RD R
4706 -f R RD RD R
4703 -A W W W R
4707 -A W W W R
4704 -Af R R R R
4708 -Af R R R R
4705 ========= == == == ==
4709 ========= == == == ==
4706
4710
4707 .. note::
4711 .. note::
4708
4712
4709 :hg:`remove` never deletes files in Added [A] state from the
4713 :hg:`remove` never deletes files in Added [A] state from the
4710 working directory, not even if ``--force`` is specified.
4714 working directory, not even if ``--force`` is specified.
4711
4715
4712 Returns 0 on success, 1 if any warnings encountered.
4716 Returns 0 on success, 1 if any warnings encountered.
4713 """
4717 """
4714
4718
4715 opts = pycompat.byteskwargs(opts)
4719 opts = pycompat.byteskwargs(opts)
4716 after, force = opts.get('after'), opts.get('force')
4720 after, force = opts.get('after'), opts.get('force')
4717 dryrun = opts.get('dry_run')
4721 dryrun = opts.get('dry_run')
4718 if not pats and not after:
4722 if not pats and not after:
4719 raise error.Abort(_('no files specified'))
4723 raise error.Abort(_('no files specified'))
4720
4724
4721 m = scmutil.match(repo[None], pats, opts)
4725 m = scmutil.match(repo[None], pats, opts)
4722 subrepos = opts.get('subrepos')
4726 subrepos = opts.get('subrepos')
4723 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4727 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4724 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4728 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4725 dryrun=dryrun)
4729 dryrun=dryrun)
4726
4730
4727 @command('rename|move|mv',
4731 @command('rename|move|mv',
4728 [('A', 'after', None, _('record a rename that has already occurred')),
4732 [('A', 'after', None, _('record a rename that has already occurred')),
4729 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4733 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4730 ] + walkopts + dryrunopts,
4734 ] + walkopts + dryrunopts,
4731 _('[OPTION]... SOURCE... DEST'),
4735 _('[OPTION]... SOURCE... DEST'),
4732 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4736 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4733 def rename(ui, repo, *pats, **opts):
4737 def rename(ui, repo, *pats, **opts):
4734 """rename files; equivalent of copy + remove
4738 """rename files; equivalent of copy + remove
4735
4739
4736 Mark dest as copies of sources; mark sources for deletion. If dest
4740 Mark dest as copies of sources; mark sources for deletion. If dest
4737 is a directory, copies are put in that directory. If dest is a
4741 is a directory, copies are put in that directory. If dest is a
4738 file, there can only be one source.
4742 file, there can only be one source.
4739
4743
4740 By default, this command copies the contents of files as they
4744 By default, this command copies the contents of files as they
4741 exist in the working directory. If invoked with -A/--after, the
4745 exist in the working directory. If invoked with -A/--after, the
4742 operation is recorded, but no copying is performed.
4746 operation is recorded, but no copying is performed.
4743
4747
4744 This command takes effect at the next commit. To undo a rename
4748 This command takes effect at the next commit. To undo a rename
4745 before that, see :hg:`revert`.
4749 before that, see :hg:`revert`.
4746
4750
4747 Returns 0 on success, 1 if errors are encountered.
4751 Returns 0 on success, 1 if errors are encountered.
4748 """
4752 """
4749 opts = pycompat.byteskwargs(opts)
4753 opts = pycompat.byteskwargs(opts)
4750 with repo.wlock(False):
4754 with repo.wlock(False):
4751 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4755 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4752
4756
4753 @command('resolve',
4757 @command('resolve',
4754 [('a', 'all', None, _('select all unresolved files')),
4758 [('a', 'all', None, _('select all unresolved files')),
4755 ('l', 'list', None, _('list state of files needing merge')),
4759 ('l', 'list', None, _('list state of files needing merge')),
4756 ('m', 'mark', None, _('mark files as resolved')),
4760 ('m', 'mark', None, _('mark files as resolved')),
4757 ('u', 'unmark', None, _('mark files as unresolved')),
4761 ('u', 'unmark', None, _('mark files as unresolved')),
4758 ('n', 'no-status', None, _('hide status prefix')),
4762 ('n', 'no-status', None, _('hide status prefix')),
4759 ('', 're-merge', None, _('re-merge files'))]
4763 ('', 're-merge', None, _('re-merge files'))]
4760 + mergetoolopts + walkopts + formatteropts,
4764 + mergetoolopts + walkopts + formatteropts,
4761 _('[OPTION]... [FILE]...'),
4765 _('[OPTION]... [FILE]...'),
4762 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4766 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4763 inferrepo=True)
4767 inferrepo=True)
4764 def resolve(ui, repo, *pats, **opts):
4768 def resolve(ui, repo, *pats, **opts):
4765 """redo merges or set/view the merge status of files
4769 """redo merges or set/view the merge status of files
4766
4770
4767 Merges with unresolved conflicts are often the result of
4771 Merges with unresolved conflicts are often the result of
4768 non-interactive merging using the ``internal:merge`` configuration
4772 non-interactive merging using the ``internal:merge`` configuration
4769 setting, or a command-line merge tool like ``diff3``. The resolve
4773 setting, or a command-line merge tool like ``diff3``. The resolve
4770 command is used to manage the files involved in a merge, after
4774 command is used to manage the files involved in a merge, after
4771 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4775 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4772 working directory must have two parents). See :hg:`help
4776 working directory must have two parents). See :hg:`help
4773 merge-tools` for information on configuring merge tools.
4777 merge-tools` for information on configuring merge tools.
4774
4778
4775 The resolve command can be used in the following ways:
4779 The resolve command can be used in the following ways:
4776
4780
4777 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4781 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4778 the specified files, discarding any previous merge attempts. Re-merging
4782 the specified files, discarding any previous merge attempts. Re-merging
4779 is not performed for files already marked as resolved. Use ``--all/-a``
4783 is not performed for files already marked as resolved. Use ``--all/-a``
4780 to select all unresolved files. ``--tool`` can be used to specify
4784 to select all unresolved files. ``--tool`` can be used to specify
4781 the merge tool used for the given files. It overrides the HGMERGE
4785 the merge tool used for the given files. It overrides the HGMERGE
4782 environment variable and your configuration files. Previous file
4786 environment variable and your configuration files. Previous file
4783 contents are saved with a ``.orig`` suffix.
4787 contents are saved with a ``.orig`` suffix.
4784
4788
4785 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4789 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4786 (e.g. after having manually fixed-up the files). The default is
4790 (e.g. after having manually fixed-up the files). The default is
4787 to mark all unresolved files.
4791 to mark all unresolved files.
4788
4792
4789 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4793 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4790 default is to mark all resolved files.
4794 default is to mark all resolved files.
4791
4795
4792 - :hg:`resolve -l`: list files which had or still have conflicts.
4796 - :hg:`resolve -l`: list files which had or still have conflicts.
4793 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4797 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4794 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4798 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4795 the list. See :hg:`help filesets` for details.
4799 the list. See :hg:`help filesets` for details.
4796
4800
4797 .. note::
4801 .. note::
4798
4802
4799 Mercurial will not let you commit files with unresolved merge
4803 Mercurial will not let you commit files with unresolved merge
4800 conflicts. You must use :hg:`resolve -m ...` before you can
4804 conflicts. You must use :hg:`resolve -m ...` before you can
4801 commit after a conflicting merge.
4805 commit after a conflicting merge.
4802
4806
4803 .. container:: verbose
4807 .. container:: verbose
4804
4808
4805 Template:
4809 Template:
4806
4810
4807 The following keywords are supported in addition to the common template
4811 The following keywords are supported in addition to the common template
4808 keywords and functions. See also :hg:`help templates`.
4812 keywords and functions. See also :hg:`help templates`.
4809
4813
4810 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4814 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4811 :path: String. Repository-absolute path of the file.
4815 :path: String. Repository-absolute path of the file.
4812
4816
4813 Returns 0 on success, 1 if any files fail a resolve attempt.
4817 Returns 0 on success, 1 if any files fail a resolve attempt.
4814 """
4818 """
4815
4819
4816 opts = pycompat.byteskwargs(opts)
4820 opts = pycompat.byteskwargs(opts)
4817 confirm = ui.configbool('commands', 'resolve.confirm')
4821 confirm = ui.configbool('commands', 'resolve.confirm')
4818 flaglist = 'all mark unmark list no_status re_merge'.split()
4822 flaglist = 'all mark unmark list no_status re_merge'.split()
4819 all, mark, unmark, show, nostatus, remerge = \
4823 all, mark, unmark, show, nostatus, remerge = \
4820 [opts.get(o) for o in flaglist]
4824 [opts.get(o) for o in flaglist]
4821
4825
4822 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4826 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4823 if actioncount > 1:
4827 if actioncount > 1:
4824 raise error.Abort(_("too many actions specified"))
4828 raise error.Abort(_("too many actions specified"))
4825 elif (actioncount == 0
4829 elif (actioncount == 0
4826 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4830 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4827 hint = _('use --mark, --unmark, --list or --re-merge')
4831 hint = _('use --mark, --unmark, --list or --re-merge')
4828 raise error.Abort(_('no action specified'), hint=hint)
4832 raise error.Abort(_('no action specified'), hint=hint)
4829 if pats and all:
4833 if pats and all:
4830 raise error.Abort(_("can't specify --all and patterns"))
4834 raise error.Abort(_("can't specify --all and patterns"))
4831 if not (all or pats or show or mark or unmark):
4835 if not (all or pats or show or mark or unmark):
4832 raise error.Abort(_('no files or directories specified'),
4836 raise error.Abort(_('no files or directories specified'),
4833 hint=('use --all to re-merge all unresolved files'))
4837 hint=('use --all to re-merge all unresolved files'))
4834
4838
4835 if confirm:
4839 if confirm:
4836 if all:
4840 if all:
4837 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4841 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4838 b'$$ &Yes $$ &No')):
4842 b'$$ &Yes $$ &No')):
4839 raise error.Abort(_('user quit'))
4843 raise error.Abort(_('user quit'))
4840 if mark and not pats:
4844 if mark and not pats:
4841 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4845 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4842 b'$$ &Yes $$ &No')):
4846 b'$$ &Yes $$ &No')):
4843 raise error.Abort(_('user quit'))
4847 raise error.Abort(_('user quit'))
4844 if unmark and not pats:
4848 if unmark and not pats:
4845 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4849 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4846 b'$$ &Yes $$ &No')):
4850 b'$$ &Yes $$ &No')):
4847 raise error.Abort(_('user quit'))
4851 raise error.Abort(_('user quit'))
4848
4852
4849 uipathfn = scmutil.getuipathfn(repo)
4853 uipathfn = scmutil.getuipathfn(repo)
4850
4854
4851 if show:
4855 if show:
4852 ui.pager('resolve')
4856 ui.pager('resolve')
4853 fm = ui.formatter('resolve', opts)
4857 fm = ui.formatter('resolve', opts)
4854 ms = mergemod.mergestate.read(repo)
4858 ms = mergemod.mergestate.read(repo)
4855 wctx = repo[None]
4859 wctx = repo[None]
4856 m = scmutil.match(wctx, pats, opts)
4860 m = scmutil.match(wctx, pats, opts)
4857
4861
4858 # Labels and keys based on merge state. Unresolved path conflicts show
4862 # Labels and keys based on merge state. Unresolved path conflicts show
4859 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4863 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4860 # resolved conflicts.
4864 # resolved conflicts.
4861 mergestateinfo = {
4865 mergestateinfo = {
4862 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4866 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4863 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4867 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4864 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4868 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4865 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4869 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4866 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4870 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4867 'D'),
4871 'D'),
4868 }
4872 }
4869
4873
4870 for f in ms:
4874 for f in ms:
4871 if not m(f):
4875 if not m(f):
4872 continue
4876 continue
4873
4877
4874 label, key = mergestateinfo[ms[f]]
4878 label, key = mergestateinfo[ms[f]]
4875 fm.startitem()
4879 fm.startitem()
4876 fm.context(ctx=wctx)
4880 fm.context(ctx=wctx)
4877 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4881 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4878 fm.data(path=f)
4882 fm.data(path=f)
4879 fm.plain('%s\n' % uipathfn(f), label=label)
4883 fm.plain('%s\n' % uipathfn(f), label=label)
4880 fm.end()
4884 fm.end()
4881 return 0
4885 return 0
4882
4886
4883 with repo.wlock():
4887 with repo.wlock():
4884 ms = mergemod.mergestate.read(repo)
4888 ms = mergemod.mergestate.read(repo)
4885
4889
4886 if not (ms.active() or repo.dirstate.p2() != nullid):
4890 if not (ms.active() or repo.dirstate.p2() != nullid):
4887 raise error.Abort(
4891 raise error.Abort(
4888 _('resolve command not applicable when not merging'))
4892 _('resolve command not applicable when not merging'))
4889
4893
4890 wctx = repo[None]
4894 wctx = repo[None]
4891
4895
4892 if (ms.mergedriver
4896 if (ms.mergedriver
4893 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4897 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4894 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4898 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4895 ms.commit()
4899 ms.commit()
4896 # allow mark and unmark to go through
4900 # allow mark and unmark to go through
4897 if not mark and not unmark and not proceed:
4901 if not mark and not unmark and not proceed:
4898 return 1
4902 return 1
4899
4903
4900 m = scmutil.match(wctx, pats, opts)
4904 m = scmutil.match(wctx, pats, opts)
4901 ret = 0
4905 ret = 0
4902 didwork = False
4906 didwork = False
4903 runconclude = False
4907 runconclude = False
4904
4908
4905 tocomplete = []
4909 tocomplete = []
4906 hasconflictmarkers = []
4910 hasconflictmarkers = []
4907 if mark:
4911 if mark:
4908 markcheck = ui.config('commands', 'resolve.mark-check')
4912 markcheck = ui.config('commands', 'resolve.mark-check')
4909 if markcheck not in ['warn', 'abort']:
4913 if markcheck not in ['warn', 'abort']:
4910 # Treat all invalid / unrecognized values as 'none'.
4914 # Treat all invalid / unrecognized values as 'none'.
4911 markcheck = False
4915 markcheck = False
4912 for f in ms:
4916 for f in ms:
4913 if not m(f):
4917 if not m(f):
4914 continue
4918 continue
4915
4919
4916 didwork = True
4920 didwork = True
4917
4921
4918 # don't let driver-resolved files be marked, and run the conclude
4922 # don't let driver-resolved files be marked, and run the conclude
4919 # step if asked to resolve
4923 # step if asked to resolve
4920 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4924 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4921 exact = m.exact(f)
4925 exact = m.exact(f)
4922 if mark:
4926 if mark:
4923 if exact:
4927 if exact:
4924 ui.warn(_('not marking %s as it is driver-resolved\n')
4928 ui.warn(_('not marking %s as it is driver-resolved\n')
4925 % uipathfn(f))
4929 % uipathfn(f))
4926 elif unmark:
4930 elif unmark:
4927 if exact:
4931 if exact:
4928 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4932 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4929 % uipathfn(f))
4933 % uipathfn(f))
4930 else:
4934 else:
4931 runconclude = True
4935 runconclude = True
4932 continue
4936 continue
4933
4937
4934 # path conflicts must be resolved manually
4938 # path conflicts must be resolved manually
4935 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4939 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4936 mergemod.MERGE_RECORD_RESOLVED_PATH):
4940 mergemod.MERGE_RECORD_RESOLVED_PATH):
4937 if mark:
4941 if mark:
4938 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4942 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4939 elif unmark:
4943 elif unmark:
4940 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4944 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4941 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4945 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4942 ui.warn(_('%s: path conflict must be resolved manually\n')
4946 ui.warn(_('%s: path conflict must be resolved manually\n')
4943 % uipathfn(f))
4947 % uipathfn(f))
4944 continue
4948 continue
4945
4949
4946 if mark:
4950 if mark:
4947 if markcheck:
4951 if markcheck:
4948 fdata = repo.wvfs.tryread(f)
4952 fdata = repo.wvfs.tryread(f)
4949 if filemerge.hasconflictmarkers(fdata) and \
4953 if filemerge.hasconflictmarkers(fdata) and \
4950 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4954 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4951 hasconflictmarkers.append(f)
4955 hasconflictmarkers.append(f)
4952 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4956 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4953 elif unmark:
4957 elif unmark:
4954 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4958 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4955 else:
4959 else:
4956 # backup pre-resolve (merge uses .orig for its own purposes)
4960 # backup pre-resolve (merge uses .orig for its own purposes)
4957 a = repo.wjoin(f)
4961 a = repo.wjoin(f)
4958 try:
4962 try:
4959 util.copyfile(a, a + ".resolve")
4963 util.copyfile(a, a + ".resolve")
4960 except (IOError, OSError) as inst:
4964 except (IOError, OSError) as inst:
4961 if inst.errno != errno.ENOENT:
4965 if inst.errno != errno.ENOENT:
4962 raise
4966 raise
4963
4967
4964 try:
4968 try:
4965 # preresolve file
4969 # preresolve file
4966 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4970 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4967 with ui.configoverride(overrides, 'resolve'):
4971 with ui.configoverride(overrides, 'resolve'):
4968 complete, r = ms.preresolve(f, wctx)
4972 complete, r = ms.preresolve(f, wctx)
4969 if not complete:
4973 if not complete:
4970 tocomplete.append(f)
4974 tocomplete.append(f)
4971 elif r:
4975 elif r:
4972 ret = 1
4976 ret = 1
4973 finally:
4977 finally:
4974 ms.commit()
4978 ms.commit()
4975
4979
4976 # replace filemerge's .orig file with our resolve file, but only
4980 # replace filemerge's .orig file with our resolve file, but only
4977 # for merges that are complete
4981 # for merges that are complete
4978 if complete:
4982 if complete:
4979 try:
4983 try:
4980 util.rename(a + ".resolve",
4984 util.rename(a + ".resolve",
4981 scmutil.backuppath(ui, repo, f))
4985 scmutil.backuppath(ui, repo, f))
4982 except OSError as inst:
4986 except OSError as inst:
4983 if inst.errno != errno.ENOENT:
4987 if inst.errno != errno.ENOENT:
4984 raise
4988 raise
4985
4989
4986 if hasconflictmarkers:
4990 if hasconflictmarkers:
4987 ui.warn(_('warning: the following files still have conflict '
4991 ui.warn(_('warning: the following files still have conflict '
4988 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
4992 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
4989 for f in hasconflictmarkers))
4993 for f in hasconflictmarkers))
4990 if markcheck == 'abort' and not all and not pats:
4994 if markcheck == 'abort' and not all and not pats:
4991 raise error.Abort(_('conflict markers detected'),
4995 raise error.Abort(_('conflict markers detected'),
4992 hint=_('use --all to mark anyway'))
4996 hint=_('use --all to mark anyway'))
4993
4997
4994 for f in tocomplete:
4998 for f in tocomplete:
4995 try:
4999 try:
4996 # resolve file
5000 # resolve file
4997 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5001 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4998 with ui.configoverride(overrides, 'resolve'):
5002 with ui.configoverride(overrides, 'resolve'):
4999 r = ms.resolve(f, wctx)
5003 r = ms.resolve(f, wctx)
5000 if r:
5004 if r:
5001 ret = 1
5005 ret = 1
5002 finally:
5006 finally:
5003 ms.commit()
5007 ms.commit()
5004
5008
5005 # replace filemerge's .orig file with our resolve file
5009 # replace filemerge's .orig file with our resolve file
5006 a = repo.wjoin(f)
5010 a = repo.wjoin(f)
5007 try:
5011 try:
5008 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5012 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5009 except OSError as inst:
5013 except OSError as inst:
5010 if inst.errno != errno.ENOENT:
5014 if inst.errno != errno.ENOENT:
5011 raise
5015 raise
5012
5016
5013 ms.commit()
5017 ms.commit()
5014 ms.recordactions()
5018 ms.recordactions()
5015
5019
5016 if not didwork and pats:
5020 if not didwork and pats:
5017 hint = None
5021 hint = None
5018 if not any([p for p in pats if p.find(':') >= 0]):
5022 if not any([p for p in pats if p.find(':') >= 0]):
5019 pats = ['path:%s' % p for p in pats]
5023 pats = ['path:%s' % p for p in pats]
5020 m = scmutil.match(wctx, pats, opts)
5024 m = scmutil.match(wctx, pats, opts)
5021 for f in ms:
5025 for f in ms:
5022 if not m(f):
5026 if not m(f):
5023 continue
5027 continue
5024 def flag(o):
5028 def flag(o):
5025 if o == 're_merge':
5029 if o == 're_merge':
5026 return '--re-merge '
5030 return '--re-merge '
5027 return '-%s ' % o[0:1]
5031 return '-%s ' % o[0:1]
5028 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5032 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5029 hint = _("(try: hg resolve %s%s)\n") % (
5033 hint = _("(try: hg resolve %s%s)\n") % (
5030 flags,
5034 flags,
5031 ' '.join(pats))
5035 ' '.join(pats))
5032 break
5036 break
5033 ui.warn(_("arguments do not match paths that need resolving\n"))
5037 ui.warn(_("arguments do not match paths that need resolving\n"))
5034 if hint:
5038 if hint:
5035 ui.warn(hint)
5039 ui.warn(hint)
5036 elif ms.mergedriver and ms.mdstate() != 's':
5040 elif ms.mergedriver and ms.mdstate() != 's':
5037 # run conclude step when either a driver-resolved file is requested
5041 # run conclude step when either a driver-resolved file is requested
5038 # or there are no driver-resolved files
5042 # or there are no driver-resolved files
5039 # we can't use 'ret' to determine whether any files are unresolved
5043 # we can't use 'ret' to determine whether any files are unresolved
5040 # because we might not have tried to resolve some
5044 # because we might not have tried to resolve some
5041 if ((runconclude or not list(ms.driverresolved()))
5045 if ((runconclude or not list(ms.driverresolved()))
5042 and not list(ms.unresolved())):
5046 and not list(ms.unresolved())):
5043 proceed = mergemod.driverconclude(repo, ms, wctx)
5047 proceed = mergemod.driverconclude(repo, ms, wctx)
5044 ms.commit()
5048 ms.commit()
5045 if not proceed:
5049 if not proceed:
5046 return 1
5050 return 1
5047
5051
5048 # Nudge users into finishing an unfinished operation
5052 # Nudge users into finishing an unfinished operation
5049 unresolvedf = list(ms.unresolved())
5053 unresolvedf = list(ms.unresolved())
5050 driverresolvedf = list(ms.driverresolved())
5054 driverresolvedf = list(ms.driverresolved())
5051 if not unresolvedf and not driverresolvedf:
5055 if not unresolvedf and not driverresolvedf:
5052 ui.status(_('(no more unresolved files)\n'))
5056 ui.status(_('(no more unresolved files)\n'))
5053 cmdutil.checkafterresolved(repo)
5057 cmdutil.checkafterresolved(repo)
5054 elif not unresolvedf:
5058 elif not unresolvedf:
5055 ui.status(_('(no more unresolved files -- '
5059 ui.status(_('(no more unresolved files -- '
5056 'run "hg resolve --all" to conclude)\n'))
5060 'run "hg resolve --all" to conclude)\n'))
5057
5061
5058 return ret
5062 return ret
5059
5063
5060 @command('revert',
5064 @command('revert',
5061 [('a', 'all', None, _('revert all changes when no arguments given')),
5065 [('a', 'all', None, _('revert all changes when no arguments given')),
5062 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5066 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5063 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5067 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5064 ('C', 'no-backup', None, _('do not save backup copies of files')),
5068 ('C', 'no-backup', None, _('do not save backup copies of files')),
5065 ('i', 'interactive', None, _('interactively select the changes')),
5069 ('i', 'interactive', None, _('interactively select the changes')),
5066 ] + walkopts + dryrunopts,
5070 ] + walkopts + dryrunopts,
5067 _('[OPTION]... [-r REV] [NAME]...'),
5071 _('[OPTION]... [-r REV] [NAME]...'),
5068 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5072 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5069 def revert(ui, repo, *pats, **opts):
5073 def revert(ui, repo, *pats, **opts):
5070 """restore files to their checkout state
5074 """restore files to their checkout state
5071
5075
5072 .. note::
5076 .. note::
5073
5077
5074 To check out earlier revisions, you should use :hg:`update REV`.
5078 To check out earlier revisions, you should use :hg:`update REV`.
5075 To cancel an uncommitted merge (and lose your changes),
5079 To cancel an uncommitted merge (and lose your changes),
5076 use :hg:`merge --abort`.
5080 use :hg:`merge --abort`.
5077
5081
5078 With no revision specified, revert the specified files or directories
5082 With no revision specified, revert the specified files or directories
5079 to the contents they had in the parent of the working directory.
5083 to the contents they had in the parent of the working directory.
5080 This restores the contents of files to an unmodified
5084 This restores the contents of files to an unmodified
5081 state and unschedules adds, removes, copies, and renames. If the
5085 state and unschedules adds, removes, copies, and renames. If the
5082 working directory has two parents, you must explicitly specify a
5086 working directory has two parents, you must explicitly specify a
5083 revision.
5087 revision.
5084
5088
5085 Using the -r/--rev or -d/--date options, revert the given files or
5089 Using the -r/--rev or -d/--date options, revert the given files or
5086 directories to their states as of a specific revision. Because
5090 directories to their states as of a specific revision. Because
5087 revert does not change the working directory parents, this will
5091 revert does not change the working directory parents, this will
5088 cause these files to appear modified. This can be helpful to "back
5092 cause these files to appear modified. This can be helpful to "back
5089 out" some or all of an earlier change. See :hg:`backout` for a
5093 out" some or all of an earlier change. See :hg:`backout` for a
5090 related method.
5094 related method.
5091
5095
5092 Modified files are saved with a .orig suffix before reverting.
5096 Modified files are saved with a .orig suffix before reverting.
5093 To disable these backups, use --no-backup. It is possible to store
5097 To disable these backups, use --no-backup. It is possible to store
5094 the backup files in a custom directory relative to the root of the
5098 the backup files in a custom directory relative to the root of the
5095 repository by setting the ``ui.origbackuppath`` configuration
5099 repository by setting the ``ui.origbackuppath`` configuration
5096 option.
5100 option.
5097
5101
5098 See :hg:`help dates` for a list of formats valid for -d/--date.
5102 See :hg:`help dates` for a list of formats valid for -d/--date.
5099
5103
5100 See :hg:`help backout` for a way to reverse the effect of an
5104 See :hg:`help backout` for a way to reverse the effect of an
5101 earlier changeset.
5105 earlier changeset.
5102
5106
5103 Returns 0 on success.
5107 Returns 0 on success.
5104 """
5108 """
5105
5109
5106 opts = pycompat.byteskwargs(opts)
5110 opts = pycompat.byteskwargs(opts)
5107 if opts.get("date"):
5111 if opts.get("date"):
5108 if opts.get("rev"):
5112 if opts.get("rev"):
5109 raise error.Abort(_("you can't specify a revision and a date"))
5113 raise error.Abort(_("you can't specify a revision and a date"))
5110 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5114 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5111
5115
5112 parent, p2 = repo.dirstate.parents()
5116 parent, p2 = repo.dirstate.parents()
5113 if not opts.get('rev') and p2 != nullid:
5117 if not opts.get('rev') and p2 != nullid:
5114 # revert after merge is a trap for new users (issue2915)
5118 # revert after merge is a trap for new users (issue2915)
5115 raise error.Abort(_('uncommitted merge with no revision specified'),
5119 raise error.Abort(_('uncommitted merge with no revision specified'),
5116 hint=_("use 'hg update' or see 'hg help revert'"))
5120 hint=_("use 'hg update' or see 'hg help revert'"))
5117
5121
5118 rev = opts.get('rev')
5122 rev = opts.get('rev')
5119 if rev:
5123 if rev:
5120 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5124 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5121 ctx = scmutil.revsingle(repo, rev)
5125 ctx = scmutil.revsingle(repo, rev)
5122
5126
5123 if (not (pats or opts.get('include') or opts.get('exclude') or
5127 if (not (pats or opts.get('include') or opts.get('exclude') or
5124 opts.get('all') or opts.get('interactive'))):
5128 opts.get('all') or opts.get('interactive'))):
5125 msg = _("no files or directories specified")
5129 msg = _("no files or directories specified")
5126 if p2 != nullid:
5130 if p2 != nullid:
5127 hint = _("uncommitted merge, use --all to discard all changes,"
5131 hint = _("uncommitted merge, use --all to discard all changes,"
5128 " or 'hg update -C .' to abort the merge")
5132 " or 'hg update -C .' to abort the merge")
5129 raise error.Abort(msg, hint=hint)
5133 raise error.Abort(msg, hint=hint)
5130 dirty = any(repo.status())
5134 dirty = any(repo.status())
5131 node = ctx.node()
5135 node = ctx.node()
5132 if node != parent:
5136 if node != parent:
5133 if dirty:
5137 if dirty:
5134 hint = _("uncommitted changes, use --all to discard all"
5138 hint = _("uncommitted changes, use --all to discard all"
5135 " changes, or 'hg update %d' to update") % ctx.rev()
5139 " changes, or 'hg update %d' to update") % ctx.rev()
5136 else:
5140 else:
5137 hint = _("use --all to revert all files,"
5141 hint = _("use --all to revert all files,"
5138 " or 'hg update %d' to update") % ctx.rev()
5142 " or 'hg update %d' to update") % ctx.rev()
5139 elif dirty:
5143 elif dirty:
5140 hint = _("uncommitted changes, use --all to discard all changes")
5144 hint = _("uncommitted changes, use --all to discard all changes")
5141 else:
5145 else:
5142 hint = _("use --all to revert all files")
5146 hint = _("use --all to revert all files")
5143 raise error.Abort(msg, hint=hint)
5147 raise error.Abort(msg, hint=hint)
5144
5148
5145 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5149 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5146 **pycompat.strkwargs(opts))
5150 **pycompat.strkwargs(opts))
5147
5151
5148 @command(
5152 @command(
5149 'rollback',
5153 'rollback',
5150 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5154 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5151 helpcategory=command.CATEGORY_MAINTENANCE)
5155 helpcategory=command.CATEGORY_MAINTENANCE)
5152 def rollback(ui, repo, **opts):
5156 def rollback(ui, repo, **opts):
5153 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5157 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5154
5158
5155 Please use :hg:`commit --amend` instead of rollback to correct
5159 Please use :hg:`commit --amend` instead of rollback to correct
5156 mistakes in the last commit.
5160 mistakes in the last commit.
5157
5161
5158 This command should be used with care. There is only one level of
5162 This command should be used with care. There is only one level of
5159 rollback, and there is no way to undo a rollback. It will also
5163 rollback, and there is no way to undo a rollback. It will also
5160 restore the dirstate at the time of the last transaction, losing
5164 restore the dirstate at the time of the last transaction, losing
5161 any dirstate changes since that time. This command does not alter
5165 any dirstate changes since that time. This command does not alter
5162 the working directory.
5166 the working directory.
5163
5167
5164 Transactions are used to encapsulate the effects of all commands
5168 Transactions are used to encapsulate the effects of all commands
5165 that create new changesets or propagate existing changesets into a
5169 that create new changesets or propagate existing changesets into a
5166 repository.
5170 repository.
5167
5171
5168 .. container:: verbose
5172 .. container:: verbose
5169
5173
5170 For example, the following commands are transactional, and their
5174 For example, the following commands are transactional, and their
5171 effects can be rolled back:
5175 effects can be rolled back:
5172
5176
5173 - commit
5177 - commit
5174 - import
5178 - import
5175 - pull
5179 - pull
5176 - push (with this repository as the destination)
5180 - push (with this repository as the destination)
5177 - unbundle
5181 - unbundle
5178
5182
5179 To avoid permanent data loss, rollback will refuse to rollback a
5183 To avoid permanent data loss, rollback will refuse to rollback a
5180 commit transaction if it isn't checked out. Use --force to
5184 commit transaction if it isn't checked out. Use --force to
5181 override this protection.
5185 override this protection.
5182
5186
5183 The rollback command can be entirely disabled by setting the
5187 The rollback command can be entirely disabled by setting the
5184 ``ui.rollback`` configuration setting to false. If you're here
5188 ``ui.rollback`` configuration setting to false. If you're here
5185 because you want to use rollback and it's disabled, you can
5189 because you want to use rollback and it's disabled, you can
5186 re-enable the command by setting ``ui.rollback`` to true.
5190 re-enable the command by setting ``ui.rollback`` to true.
5187
5191
5188 This command is not intended for use on public repositories. Once
5192 This command is not intended for use on public repositories. Once
5189 changes are visible for pull by other users, rolling a transaction
5193 changes are visible for pull by other users, rolling a transaction
5190 back locally is ineffective (someone else may already have pulled
5194 back locally is ineffective (someone else may already have pulled
5191 the changes). Furthermore, a race is possible with readers of the
5195 the changes). Furthermore, a race is possible with readers of the
5192 repository; for example an in-progress pull from the repository
5196 repository; for example an in-progress pull from the repository
5193 may fail if a rollback is performed.
5197 may fail if a rollback is performed.
5194
5198
5195 Returns 0 on success, 1 if no rollback data is available.
5199 Returns 0 on success, 1 if no rollback data is available.
5196 """
5200 """
5197 if not ui.configbool('ui', 'rollback'):
5201 if not ui.configbool('ui', 'rollback'):
5198 raise error.Abort(_('rollback is disabled because it is unsafe'),
5202 raise error.Abort(_('rollback is disabled because it is unsafe'),
5199 hint=('see `hg help -v rollback` for information'))
5203 hint=('see `hg help -v rollback` for information'))
5200 return repo.rollback(dryrun=opts.get(r'dry_run'),
5204 return repo.rollback(dryrun=opts.get(r'dry_run'),
5201 force=opts.get(r'force'))
5205 force=opts.get(r'force'))
5202
5206
5203 @command(
5207 @command(
5204 'root', [], intents={INTENT_READONLY},
5208 'root', [], intents={INTENT_READONLY},
5205 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5209 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5206 def root(ui, repo):
5210 def root(ui, repo):
5207 """print the root (top) of the current working directory
5211 """print the root (top) of the current working directory
5208
5212
5209 Print the root directory of the current repository.
5213 Print the root directory of the current repository.
5210
5214
5211 Returns 0 on success.
5215 Returns 0 on success.
5212 """
5216 """
5213 ui.write(repo.root + "\n")
5217 ui.write(repo.root + "\n")
5214
5218
5215 @command('serve',
5219 @command('serve',
5216 [('A', 'accesslog', '', _('name of access log file to write to'),
5220 [('A', 'accesslog', '', _('name of access log file to write to'),
5217 _('FILE')),
5221 _('FILE')),
5218 ('d', 'daemon', None, _('run server in background')),
5222 ('d', 'daemon', None, _('run server in background')),
5219 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5223 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5220 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5224 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5221 # use string type, then we can check if something was passed
5225 # use string type, then we can check if something was passed
5222 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5226 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5223 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5227 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5224 _('ADDR')),
5228 _('ADDR')),
5225 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5229 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5226 _('PREFIX')),
5230 _('PREFIX')),
5227 ('n', 'name', '',
5231 ('n', 'name', '',
5228 _('name to show in web pages (default: working directory)'), _('NAME')),
5232 _('name to show in web pages (default: working directory)'), _('NAME')),
5229 ('', 'web-conf', '',
5233 ('', 'web-conf', '',
5230 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5234 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5231 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5235 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5232 _('FILE')),
5236 _('FILE')),
5233 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5237 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5234 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5238 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5235 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5239 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5236 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5240 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5237 ('', 'style', '', _('template style to use'), _('STYLE')),
5241 ('', 'style', '', _('template style to use'), _('STYLE')),
5238 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5242 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5239 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5243 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5240 ('', 'print-url', None, _('start and print only the URL'))]
5244 ('', 'print-url', None, _('start and print only the URL'))]
5241 + subrepoopts,
5245 + subrepoopts,
5242 _('[OPTION]...'),
5246 _('[OPTION]...'),
5243 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5247 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5244 helpbasic=True, optionalrepo=True)
5248 helpbasic=True, optionalrepo=True)
5245 def serve(ui, repo, **opts):
5249 def serve(ui, repo, **opts):
5246 """start stand-alone webserver
5250 """start stand-alone webserver
5247
5251
5248 Start a local HTTP repository browser and pull server. You can use
5252 Start a local HTTP repository browser and pull server. You can use
5249 this for ad-hoc sharing and browsing of repositories. It is
5253 this for ad-hoc sharing and browsing of repositories. It is
5250 recommended to use a real web server to serve a repository for
5254 recommended to use a real web server to serve a repository for
5251 longer periods of time.
5255 longer periods of time.
5252
5256
5253 Please note that the server does not implement access control.
5257 Please note that the server does not implement access control.
5254 This means that, by default, anybody can read from the server and
5258 This means that, by default, anybody can read from the server and
5255 nobody can write to it by default. Set the ``web.allow-push``
5259 nobody can write to it by default. Set the ``web.allow-push``
5256 option to ``*`` to allow everybody to push to the server. You
5260 option to ``*`` to allow everybody to push to the server. You
5257 should use a real web server if you need to authenticate users.
5261 should use a real web server if you need to authenticate users.
5258
5262
5259 By default, the server logs accesses to stdout and errors to
5263 By default, the server logs accesses to stdout and errors to
5260 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5264 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5261 files.
5265 files.
5262
5266
5263 To have the server choose a free port number to listen on, specify
5267 To have the server choose a free port number to listen on, specify
5264 a port number of 0; in this case, the server will print the port
5268 a port number of 0; in this case, the server will print the port
5265 number it uses.
5269 number it uses.
5266
5270
5267 Returns 0 on success.
5271 Returns 0 on success.
5268 """
5272 """
5269
5273
5270 opts = pycompat.byteskwargs(opts)
5274 opts = pycompat.byteskwargs(opts)
5271 if opts["stdio"] and opts["cmdserver"]:
5275 if opts["stdio"] and opts["cmdserver"]:
5272 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5276 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5273 if opts["print_url"] and ui.verbose:
5277 if opts["print_url"] and ui.verbose:
5274 raise error.Abort(_("cannot use --print-url with --verbose"))
5278 raise error.Abort(_("cannot use --print-url with --verbose"))
5275
5279
5276 if opts["stdio"]:
5280 if opts["stdio"]:
5277 if repo is None:
5281 if repo is None:
5278 raise error.RepoError(_("there is no Mercurial repository here"
5282 raise error.RepoError(_("there is no Mercurial repository here"
5279 " (.hg not found)"))
5283 " (.hg not found)"))
5280 s = wireprotoserver.sshserver(ui, repo)
5284 s = wireprotoserver.sshserver(ui, repo)
5281 s.serve_forever()
5285 s.serve_forever()
5282
5286
5283 service = server.createservice(ui, repo, opts)
5287 service = server.createservice(ui, repo, opts)
5284 return server.runservice(opts, initfn=service.init, runfn=service.run)
5288 return server.runservice(opts, initfn=service.init, runfn=service.run)
5285
5289
5286 _NOTTERSE = 'nothing'
5290 _NOTTERSE = 'nothing'
5287
5291
5288 @command('status|st',
5292 @command('status|st',
5289 [('A', 'all', None, _('show status of all files')),
5293 [('A', 'all', None, _('show status of all files')),
5290 ('m', 'modified', None, _('show only modified files')),
5294 ('m', 'modified', None, _('show only modified files')),
5291 ('a', 'added', None, _('show only added files')),
5295 ('a', 'added', None, _('show only added files')),
5292 ('r', 'removed', None, _('show only removed files')),
5296 ('r', 'removed', None, _('show only removed files')),
5293 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5297 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5294 ('c', 'clean', None, _('show only files without changes')),
5298 ('c', 'clean', None, _('show only files without changes')),
5295 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5299 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5296 ('i', 'ignored', None, _('show only ignored files')),
5300 ('i', 'ignored', None, _('show only ignored files')),
5297 ('n', 'no-status', None, _('hide status prefix')),
5301 ('n', 'no-status', None, _('hide status prefix')),
5298 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5302 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5299 ('C', 'copies', None, _('show source of copied files')),
5303 ('C', 'copies', None, _('show source of copied files')),
5300 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5304 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5301 ('', 'rev', [], _('show difference from revision'), _('REV')),
5305 ('', 'rev', [], _('show difference from revision'), _('REV')),
5302 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5306 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5303 ] + walkopts + subrepoopts + formatteropts,
5307 ] + walkopts + subrepoopts + formatteropts,
5304 _('[OPTION]... [FILE]...'),
5308 _('[OPTION]... [FILE]...'),
5305 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5309 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5306 helpbasic=True, inferrepo=True,
5310 helpbasic=True, inferrepo=True,
5307 intents={INTENT_READONLY})
5311 intents={INTENT_READONLY})
5308 def status(ui, repo, *pats, **opts):
5312 def status(ui, repo, *pats, **opts):
5309 """show changed files in the working directory
5313 """show changed files in the working directory
5310
5314
5311 Show status of files in the repository. If names are given, only
5315 Show status of files in the repository. If names are given, only
5312 files that match are shown. Files that are clean or ignored or
5316 files that match are shown. Files that are clean or ignored or
5313 the source of a copy/move operation, are not listed unless
5317 the source of a copy/move operation, are not listed unless
5314 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5318 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5315 Unless options described with "show only ..." are given, the
5319 Unless options described with "show only ..." are given, the
5316 options -mardu are used.
5320 options -mardu are used.
5317
5321
5318 Option -q/--quiet hides untracked (unknown and ignored) files
5322 Option -q/--quiet hides untracked (unknown and ignored) files
5319 unless explicitly requested with -u/--unknown or -i/--ignored.
5323 unless explicitly requested with -u/--unknown or -i/--ignored.
5320
5324
5321 .. note::
5325 .. note::
5322
5326
5323 :hg:`status` may appear to disagree with diff if permissions have
5327 :hg:`status` may appear to disagree with diff if permissions have
5324 changed or a merge has occurred. The standard diff format does
5328 changed or a merge has occurred. The standard diff format does
5325 not report permission changes and diff only reports changes
5329 not report permission changes and diff only reports changes
5326 relative to one merge parent.
5330 relative to one merge parent.
5327
5331
5328 If one revision is given, it is used as the base revision.
5332 If one revision is given, it is used as the base revision.
5329 If two revisions are given, the differences between them are
5333 If two revisions are given, the differences between them are
5330 shown. The --change option can also be used as a shortcut to list
5334 shown. The --change option can also be used as a shortcut to list
5331 the changed files of a revision from its first parent.
5335 the changed files of a revision from its first parent.
5332
5336
5333 The codes used to show the status of files are::
5337 The codes used to show the status of files are::
5334
5338
5335 M = modified
5339 M = modified
5336 A = added
5340 A = added
5337 R = removed
5341 R = removed
5338 C = clean
5342 C = clean
5339 ! = missing (deleted by non-hg command, but still tracked)
5343 ! = missing (deleted by non-hg command, but still tracked)
5340 ? = not tracked
5344 ? = not tracked
5341 I = ignored
5345 I = ignored
5342 = origin of the previous file (with --copies)
5346 = origin of the previous file (with --copies)
5343
5347
5344 .. container:: verbose
5348 .. container:: verbose
5345
5349
5346 The -t/--terse option abbreviates the output by showing only the directory
5350 The -t/--terse option abbreviates the output by showing only the directory
5347 name if all the files in it share the same status. The option takes an
5351 name if all the files in it share the same status. The option takes an
5348 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5352 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5349 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5353 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5350 for 'ignored' and 'c' for clean.
5354 for 'ignored' and 'c' for clean.
5351
5355
5352 It abbreviates only those statuses which are passed. Note that clean and
5356 It abbreviates only those statuses which are passed. Note that clean and
5353 ignored files are not displayed with '--terse ic' unless the -c/--clean
5357 ignored files are not displayed with '--terse ic' unless the -c/--clean
5354 and -i/--ignored options are also used.
5358 and -i/--ignored options are also used.
5355
5359
5356 The -v/--verbose option shows information when the repository is in an
5360 The -v/--verbose option shows information when the repository is in an
5357 unfinished merge, shelve, rebase state etc. You can have this behavior
5361 unfinished merge, shelve, rebase state etc. You can have this behavior
5358 turned on by default by enabling the ``commands.status.verbose`` option.
5362 turned on by default by enabling the ``commands.status.verbose`` option.
5359
5363
5360 You can skip displaying some of these states by setting
5364 You can skip displaying some of these states by setting
5361 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5365 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5362 'histedit', 'merge', 'rebase', or 'unshelve'.
5366 'histedit', 'merge', 'rebase', or 'unshelve'.
5363
5367
5364 Template:
5368 Template:
5365
5369
5366 The following keywords are supported in addition to the common template
5370 The following keywords are supported in addition to the common template
5367 keywords and functions. See also :hg:`help templates`.
5371 keywords and functions. See also :hg:`help templates`.
5368
5372
5369 :path: String. Repository-absolute path of the file.
5373 :path: String. Repository-absolute path of the file.
5370 :source: String. Repository-absolute path of the file originated from.
5374 :source: String. Repository-absolute path of the file originated from.
5371 Available if ``--copies`` is specified.
5375 Available if ``--copies`` is specified.
5372 :status: String. Character denoting file's status.
5376 :status: String. Character denoting file's status.
5373
5377
5374 Examples:
5378 Examples:
5375
5379
5376 - show changes in the working directory relative to a
5380 - show changes in the working directory relative to a
5377 changeset::
5381 changeset::
5378
5382
5379 hg status --rev 9353
5383 hg status --rev 9353
5380
5384
5381 - show changes in the working directory relative to the
5385 - show changes in the working directory relative to the
5382 current directory (see :hg:`help patterns` for more information)::
5386 current directory (see :hg:`help patterns` for more information)::
5383
5387
5384 hg status re:
5388 hg status re:
5385
5389
5386 - show all changes including copies in an existing changeset::
5390 - show all changes including copies in an existing changeset::
5387
5391
5388 hg status --copies --change 9353
5392 hg status --copies --change 9353
5389
5393
5390 - get a NUL separated list of added files, suitable for xargs::
5394 - get a NUL separated list of added files, suitable for xargs::
5391
5395
5392 hg status -an0
5396 hg status -an0
5393
5397
5394 - show more information about the repository status, abbreviating
5398 - show more information about the repository status, abbreviating
5395 added, removed, modified, deleted, and untracked paths::
5399 added, removed, modified, deleted, and untracked paths::
5396
5400
5397 hg status -v -t mardu
5401 hg status -v -t mardu
5398
5402
5399 Returns 0 on success.
5403 Returns 0 on success.
5400
5404
5401 """
5405 """
5402
5406
5403 opts = pycompat.byteskwargs(opts)
5407 opts = pycompat.byteskwargs(opts)
5404 revs = opts.get('rev')
5408 revs = opts.get('rev')
5405 change = opts.get('change')
5409 change = opts.get('change')
5406 terse = opts.get('terse')
5410 terse = opts.get('terse')
5407 if terse is _NOTTERSE:
5411 if terse is _NOTTERSE:
5408 if revs:
5412 if revs:
5409 terse = ''
5413 terse = ''
5410 else:
5414 else:
5411 terse = ui.config('commands', 'status.terse')
5415 terse = ui.config('commands', 'status.terse')
5412
5416
5413 if revs and change:
5417 if revs and change:
5414 msg = _('cannot specify --rev and --change at the same time')
5418 msg = _('cannot specify --rev and --change at the same time')
5415 raise error.Abort(msg)
5419 raise error.Abort(msg)
5416 elif revs and terse:
5420 elif revs and terse:
5417 msg = _('cannot use --terse with --rev')
5421 msg = _('cannot use --terse with --rev')
5418 raise error.Abort(msg)
5422 raise error.Abort(msg)
5419 elif change:
5423 elif change:
5420 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5424 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5421 ctx2 = scmutil.revsingle(repo, change, None)
5425 ctx2 = scmutil.revsingle(repo, change, None)
5422 ctx1 = ctx2.p1()
5426 ctx1 = ctx2.p1()
5423 else:
5427 else:
5424 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5428 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5425 ctx1, ctx2 = scmutil.revpair(repo, revs)
5429 ctx1, ctx2 = scmutil.revpair(repo, revs)
5426
5430
5427 forcerelativevalue = None
5431 forcerelativevalue = None
5428 if ui.hasconfig('commands', 'status.relative'):
5432 if ui.hasconfig('commands', 'status.relative'):
5429 forcerelativevalue = ui.configbool('commands', 'status.relative')
5433 forcerelativevalue = ui.configbool('commands', 'status.relative')
5430 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5434 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5431 forcerelativevalue=forcerelativevalue)
5435 forcerelativevalue=forcerelativevalue)
5432
5436
5433 if opts.get('print0'):
5437 if opts.get('print0'):
5434 end = '\0'
5438 end = '\0'
5435 else:
5439 else:
5436 end = '\n'
5440 end = '\n'
5437 copy = {}
5441 copy = {}
5438 states = 'modified added removed deleted unknown ignored clean'.split()
5442 states = 'modified added removed deleted unknown ignored clean'.split()
5439 show = [k for k in states if opts.get(k)]
5443 show = [k for k in states if opts.get(k)]
5440 if opts.get('all'):
5444 if opts.get('all'):
5441 show += ui.quiet and (states[:4] + ['clean']) or states
5445 show += ui.quiet and (states[:4] + ['clean']) or states
5442
5446
5443 if not show:
5447 if not show:
5444 if ui.quiet:
5448 if ui.quiet:
5445 show = states[:4]
5449 show = states[:4]
5446 else:
5450 else:
5447 show = states[:5]
5451 show = states[:5]
5448
5452
5449 m = scmutil.match(ctx2, pats, opts)
5453 m = scmutil.match(ctx2, pats, opts)
5450 if terse:
5454 if terse:
5451 # we need to compute clean and unknown to terse
5455 # we need to compute clean and unknown to terse
5452 stat = repo.status(ctx1.node(), ctx2.node(), m,
5456 stat = repo.status(ctx1.node(), ctx2.node(), m,
5453 'ignored' in show or 'i' in terse,
5457 'ignored' in show or 'i' in terse,
5454 clean=True, unknown=True,
5458 clean=True, unknown=True,
5455 listsubrepos=opts.get('subrepos'))
5459 listsubrepos=opts.get('subrepos'))
5456
5460
5457 stat = cmdutil.tersedir(stat, terse)
5461 stat = cmdutil.tersedir(stat, terse)
5458 else:
5462 else:
5459 stat = repo.status(ctx1.node(), ctx2.node(), m,
5463 stat = repo.status(ctx1.node(), ctx2.node(), m,
5460 'ignored' in show, 'clean' in show,
5464 'ignored' in show, 'clean' in show,
5461 'unknown' in show, opts.get('subrepos'))
5465 'unknown' in show, opts.get('subrepos'))
5462
5466
5463 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5467 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5464
5468
5465 if (opts.get('all') or opts.get('copies')
5469 if (opts.get('all') or opts.get('copies')
5466 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5470 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5467 copy = copies.pathcopies(ctx1, ctx2, m)
5471 copy = copies.pathcopies(ctx1, ctx2, m)
5468
5472
5469 ui.pager('status')
5473 ui.pager('status')
5470 fm = ui.formatter('status', opts)
5474 fm = ui.formatter('status', opts)
5471 fmt = '%s' + end
5475 fmt = '%s' + end
5472 showchar = not opts.get('no_status')
5476 showchar = not opts.get('no_status')
5473
5477
5474 for state, char, files in changestates:
5478 for state, char, files in changestates:
5475 if state in show:
5479 if state in show:
5476 label = 'status.' + state
5480 label = 'status.' + state
5477 for f in files:
5481 for f in files:
5478 fm.startitem()
5482 fm.startitem()
5479 fm.context(ctx=ctx2)
5483 fm.context(ctx=ctx2)
5480 fm.data(path=f)
5484 fm.data(path=f)
5481 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5485 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5482 fm.plain(fmt % uipathfn(f), label=label)
5486 fm.plain(fmt % uipathfn(f), label=label)
5483 if f in copy:
5487 if f in copy:
5484 fm.data(source=copy[f])
5488 fm.data(source=copy[f])
5485 fm.plain((' %s' + end) % uipathfn(copy[f]),
5489 fm.plain((' %s' + end) % uipathfn(copy[f]),
5486 label='status.copied')
5490 label='status.copied')
5487
5491
5488 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5492 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5489 and not ui.plain()):
5493 and not ui.plain()):
5490 cmdutil.morestatus(repo, fm)
5494 cmdutil.morestatus(repo, fm)
5491 fm.end()
5495 fm.end()
5492
5496
5493 @command('summary|sum',
5497 @command('summary|sum',
5494 [('', 'remote', None, _('check for push and pull'))],
5498 [('', 'remote', None, _('check for push and pull'))],
5495 '[--remote]',
5499 '[--remote]',
5496 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5500 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5497 helpbasic=True,
5501 helpbasic=True,
5498 intents={INTENT_READONLY})
5502 intents={INTENT_READONLY})
5499 def summary(ui, repo, **opts):
5503 def summary(ui, repo, **opts):
5500 """summarize working directory state
5504 """summarize working directory state
5501
5505
5502 This generates a brief summary of the working directory state,
5506 This generates a brief summary of the working directory state,
5503 including parents, branch, commit status, phase and available updates.
5507 including parents, branch, commit status, phase and available updates.
5504
5508
5505 With the --remote option, this will check the default paths for
5509 With the --remote option, this will check the default paths for
5506 incoming and outgoing changes. This can be time-consuming.
5510 incoming and outgoing changes. This can be time-consuming.
5507
5511
5508 Returns 0 on success.
5512 Returns 0 on success.
5509 """
5513 """
5510
5514
5511 opts = pycompat.byteskwargs(opts)
5515 opts = pycompat.byteskwargs(opts)
5512 ui.pager('summary')
5516 ui.pager('summary')
5513 ctx = repo[None]
5517 ctx = repo[None]
5514 parents = ctx.parents()
5518 parents = ctx.parents()
5515 pnode = parents[0].node()
5519 pnode = parents[0].node()
5516 marks = []
5520 marks = []
5517
5521
5518 try:
5522 try:
5519 ms = mergemod.mergestate.read(repo)
5523 ms = mergemod.mergestate.read(repo)
5520 except error.UnsupportedMergeRecords as e:
5524 except error.UnsupportedMergeRecords as e:
5521 s = ' '.join(e.recordtypes)
5525 s = ' '.join(e.recordtypes)
5522 ui.warn(
5526 ui.warn(
5523 _('warning: merge state has unsupported record types: %s\n') % s)
5527 _('warning: merge state has unsupported record types: %s\n') % s)
5524 unresolved = []
5528 unresolved = []
5525 else:
5529 else:
5526 unresolved = list(ms.unresolved())
5530 unresolved = list(ms.unresolved())
5527
5531
5528 for p in parents:
5532 for p in parents:
5529 # label with log.changeset (instead of log.parent) since this
5533 # label with log.changeset (instead of log.parent) since this
5530 # shows a working directory parent *changeset*:
5534 # shows a working directory parent *changeset*:
5531 # i18n: column positioning for "hg summary"
5535 # i18n: column positioning for "hg summary"
5532 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5536 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5533 label=logcmdutil.changesetlabels(p))
5537 label=logcmdutil.changesetlabels(p))
5534 ui.write(' '.join(p.tags()), label='log.tag')
5538 ui.write(' '.join(p.tags()), label='log.tag')
5535 if p.bookmarks():
5539 if p.bookmarks():
5536 marks.extend(p.bookmarks())
5540 marks.extend(p.bookmarks())
5537 if p.rev() == -1:
5541 if p.rev() == -1:
5538 if not len(repo):
5542 if not len(repo):
5539 ui.write(_(' (empty repository)'))
5543 ui.write(_(' (empty repository)'))
5540 else:
5544 else:
5541 ui.write(_(' (no revision checked out)'))
5545 ui.write(_(' (no revision checked out)'))
5542 if p.obsolete():
5546 if p.obsolete():
5543 ui.write(_(' (obsolete)'))
5547 ui.write(_(' (obsolete)'))
5544 if p.isunstable():
5548 if p.isunstable():
5545 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5549 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5546 for instability in p.instabilities())
5550 for instability in p.instabilities())
5547 ui.write(' ('
5551 ui.write(' ('
5548 + ', '.join(instabilities)
5552 + ', '.join(instabilities)
5549 + ')')
5553 + ')')
5550 ui.write('\n')
5554 ui.write('\n')
5551 if p.description():
5555 if p.description():
5552 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5556 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5553 label='log.summary')
5557 label='log.summary')
5554
5558
5555 branch = ctx.branch()
5559 branch = ctx.branch()
5556 bheads = repo.branchheads(branch)
5560 bheads = repo.branchheads(branch)
5557 # i18n: column positioning for "hg summary"
5561 # i18n: column positioning for "hg summary"
5558 m = _('branch: %s\n') % branch
5562 m = _('branch: %s\n') % branch
5559 if branch != 'default':
5563 if branch != 'default':
5560 ui.write(m, label='log.branch')
5564 ui.write(m, label='log.branch')
5561 else:
5565 else:
5562 ui.status(m, label='log.branch')
5566 ui.status(m, label='log.branch')
5563
5567
5564 if marks:
5568 if marks:
5565 active = repo._activebookmark
5569 active = repo._activebookmark
5566 # i18n: column positioning for "hg summary"
5570 # i18n: column positioning for "hg summary"
5567 ui.write(_('bookmarks:'), label='log.bookmark')
5571 ui.write(_('bookmarks:'), label='log.bookmark')
5568 if active is not None:
5572 if active is not None:
5569 if active in marks:
5573 if active in marks:
5570 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5574 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5571 marks.remove(active)
5575 marks.remove(active)
5572 else:
5576 else:
5573 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5577 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5574 for m in marks:
5578 for m in marks:
5575 ui.write(' ' + m, label='log.bookmark')
5579 ui.write(' ' + m, label='log.bookmark')
5576 ui.write('\n', label='log.bookmark')
5580 ui.write('\n', label='log.bookmark')
5577
5581
5578 status = repo.status(unknown=True)
5582 status = repo.status(unknown=True)
5579
5583
5580 c = repo.dirstate.copies()
5584 c = repo.dirstate.copies()
5581 copied, renamed = [], []
5585 copied, renamed = [], []
5582 for d, s in c.iteritems():
5586 for d, s in c.iteritems():
5583 if s in status.removed:
5587 if s in status.removed:
5584 status.removed.remove(s)
5588 status.removed.remove(s)
5585 renamed.append(d)
5589 renamed.append(d)
5586 else:
5590 else:
5587 copied.append(d)
5591 copied.append(d)
5588 if d in status.added:
5592 if d in status.added:
5589 status.added.remove(d)
5593 status.added.remove(d)
5590
5594
5591 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5595 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5592
5596
5593 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5597 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5594 (ui.label(_('%d added'), 'status.added'), status.added),
5598 (ui.label(_('%d added'), 'status.added'), status.added),
5595 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5599 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5596 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5600 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5597 (ui.label(_('%d copied'), 'status.copied'), copied),
5601 (ui.label(_('%d copied'), 'status.copied'), copied),
5598 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5602 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5599 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5603 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5600 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5604 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5601 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5605 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5602 t = []
5606 t = []
5603 for l, s in labels:
5607 for l, s in labels:
5604 if s:
5608 if s:
5605 t.append(l % len(s))
5609 t.append(l % len(s))
5606
5610
5607 t = ', '.join(t)
5611 t = ', '.join(t)
5608 cleanworkdir = False
5612 cleanworkdir = False
5609
5613
5610 if repo.vfs.exists('graftstate'):
5614 if repo.vfs.exists('graftstate'):
5611 t += _(' (graft in progress)')
5615 t += _(' (graft in progress)')
5612 if repo.vfs.exists('updatestate'):
5616 if repo.vfs.exists('updatestate'):
5613 t += _(' (interrupted update)')
5617 t += _(' (interrupted update)')
5614 elif len(parents) > 1:
5618 elif len(parents) > 1:
5615 t += _(' (merge)')
5619 t += _(' (merge)')
5616 elif branch != parents[0].branch():
5620 elif branch != parents[0].branch():
5617 t += _(' (new branch)')
5621 t += _(' (new branch)')
5618 elif (parents[0].closesbranch() and
5622 elif (parents[0].closesbranch() and
5619 pnode in repo.branchheads(branch, closed=True)):
5623 pnode in repo.branchheads(branch, closed=True)):
5620 t += _(' (head closed)')
5624 t += _(' (head closed)')
5621 elif not (status.modified or status.added or status.removed or renamed or
5625 elif not (status.modified or status.added or status.removed or renamed or
5622 copied or subs):
5626 copied or subs):
5623 t += _(' (clean)')
5627 t += _(' (clean)')
5624 cleanworkdir = True
5628 cleanworkdir = True
5625 elif pnode not in bheads:
5629 elif pnode not in bheads:
5626 t += _(' (new branch head)')
5630 t += _(' (new branch head)')
5627
5631
5628 if parents:
5632 if parents:
5629 pendingphase = max(p.phase() for p in parents)
5633 pendingphase = max(p.phase() for p in parents)
5630 else:
5634 else:
5631 pendingphase = phases.public
5635 pendingphase = phases.public
5632
5636
5633 if pendingphase > phases.newcommitphase(ui):
5637 if pendingphase > phases.newcommitphase(ui):
5634 t += ' (%s)' % phases.phasenames[pendingphase]
5638 t += ' (%s)' % phases.phasenames[pendingphase]
5635
5639
5636 if cleanworkdir:
5640 if cleanworkdir:
5637 # i18n: column positioning for "hg summary"
5641 # i18n: column positioning for "hg summary"
5638 ui.status(_('commit: %s\n') % t.strip())
5642 ui.status(_('commit: %s\n') % t.strip())
5639 else:
5643 else:
5640 # i18n: column positioning for "hg summary"
5644 # i18n: column positioning for "hg summary"
5641 ui.write(_('commit: %s\n') % t.strip())
5645 ui.write(_('commit: %s\n') % t.strip())
5642
5646
5643 # all ancestors of branch heads - all ancestors of parent = new csets
5647 # all ancestors of branch heads - all ancestors of parent = new csets
5644 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5648 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5645 bheads))
5649 bheads))
5646
5650
5647 if new == 0:
5651 if new == 0:
5648 # i18n: column positioning for "hg summary"
5652 # i18n: column positioning for "hg summary"
5649 ui.status(_('update: (current)\n'))
5653 ui.status(_('update: (current)\n'))
5650 elif pnode not in bheads:
5654 elif pnode not in bheads:
5651 # i18n: column positioning for "hg summary"
5655 # i18n: column positioning for "hg summary"
5652 ui.write(_('update: %d new changesets (update)\n') % new)
5656 ui.write(_('update: %d new changesets (update)\n') % new)
5653 else:
5657 else:
5654 # i18n: column positioning for "hg summary"
5658 # i18n: column positioning for "hg summary"
5655 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5659 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5656 (new, len(bheads)))
5660 (new, len(bheads)))
5657
5661
5658 t = []
5662 t = []
5659 draft = len(repo.revs('draft()'))
5663 draft = len(repo.revs('draft()'))
5660 if draft:
5664 if draft:
5661 t.append(_('%d draft') % draft)
5665 t.append(_('%d draft') % draft)
5662 secret = len(repo.revs('secret()'))
5666 secret = len(repo.revs('secret()'))
5663 if secret:
5667 if secret:
5664 t.append(_('%d secret') % secret)
5668 t.append(_('%d secret') % secret)
5665
5669
5666 if draft or secret:
5670 if draft or secret:
5667 ui.status(_('phases: %s\n') % ', '.join(t))
5671 ui.status(_('phases: %s\n') % ', '.join(t))
5668
5672
5669 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5673 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5670 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5674 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5671 numtrouble = len(repo.revs(trouble + "()"))
5675 numtrouble = len(repo.revs(trouble + "()"))
5672 # We write all the possibilities to ease translation
5676 # We write all the possibilities to ease translation
5673 troublemsg = {
5677 troublemsg = {
5674 "orphan": _("orphan: %d changesets"),
5678 "orphan": _("orphan: %d changesets"),
5675 "contentdivergent": _("content-divergent: %d changesets"),
5679 "contentdivergent": _("content-divergent: %d changesets"),
5676 "phasedivergent": _("phase-divergent: %d changesets"),
5680 "phasedivergent": _("phase-divergent: %d changesets"),
5677 }
5681 }
5678 if numtrouble > 0:
5682 if numtrouble > 0:
5679 ui.status(troublemsg[trouble] % numtrouble + "\n")
5683 ui.status(troublemsg[trouble] % numtrouble + "\n")
5680
5684
5681 cmdutil.summaryhooks(ui, repo)
5685 cmdutil.summaryhooks(ui, repo)
5682
5686
5683 if opts.get('remote'):
5687 if opts.get('remote'):
5684 needsincoming, needsoutgoing = True, True
5688 needsincoming, needsoutgoing = True, True
5685 else:
5689 else:
5686 needsincoming, needsoutgoing = False, False
5690 needsincoming, needsoutgoing = False, False
5687 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5691 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5688 if i:
5692 if i:
5689 needsincoming = True
5693 needsincoming = True
5690 if o:
5694 if o:
5691 needsoutgoing = True
5695 needsoutgoing = True
5692 if not needsincoming and not needsoutgoing:
5696 if not needsincoming and not needsoutgoing:
5693 return
5697 return
5694
5698
5695 def getincoming():
5699 def getincoming():
5696 source, branches = hg.parseurl(ui.expandpath('default'))
5700 source, branches = hg.parseurl(ui.expandpath('default'))
5697 sbranch = branches[0]
5701 sbranch = branches[0]
5698 try:
5702 try:
5699 other = hg.peer(repo, {}, source)
5703 other = hg.peer(repo, {}, source)
5700 except error.RepoError:
5704 except error.RepoError:
5701 if opts.get('remote'):
5705 if opts.get('remote'):
5702 raise
5706 raise
5703 return source, sbranch, None, None, None
5707 return source, sbranch, None, None, None
5704 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5708 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5705 if revs:
5709 if revs:
5706 revs = [other.lookup(rev) for rev in revs]
5710 revs = [other.lookup(rev) for rev in revs]
5707 ui.debug('comparing with %s\n' % util.hidepassword(source))
5711 ui.debug('comparing with %s\n' % util.hidepassword(source))
5708 repo.ui.pushbuffer()
5712 repo.ui.pushbuffer()
5709 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5713 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5710 repo.ui.popbuffer()
5714 repo.ui.popbuffer()
5711 return source, sbranch, other, commoninc, commoninc[1]
5715 return source, sbranch, other, commoninc, commoninc[1]
5712
5716
5713 if needsincoming:
5717 if needsincoming:
5714 source, sbranch, sother, commoninc, incoming = getincoming()
5718 source, sbranch, sother, commoninc, incoming = getincoming()
5715 else:
5719 else:
5716 source = sbranch = sother = commoninc = incoming = None
5720 source = sbranch = sother = commoninc = incoming = None
5717
5721
5718 def getoutgoing():
5722 def getoutgoing():
5719 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5723 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5720 dbranch = branches[0]
5724 dbranch = branches[0]
5721 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5725 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5722 if source != dest:
5726 if source != dest:
5723 try:
5727 try:
5724 dother = hg.peer(repo, {}, dest)
5728 dother = hg.peer(repo, {}, dest)
5725 except error.RepoError:
5729 except error.RepoError:
5726 if opts.get('remote'):
5730 if opts.get('remote'):
5727 raise
5731 raise
5728 return dest, dbranch, None, None
5732 return dest, dbranch, None, None
5729 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5733 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5730 elif sother is None:
5734 elif sother is None:
5731 # there is no explicit destination peer, but source one is invalid
5735 # there is no explicit destination peer, but source one is invalid
5732 return dest, dbranch, None, None
5736 return dest, dbranch, None, None
5733 else:
5737 else:
5734 dother = sother
5738 dother = sother
5735 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5739 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5736 common = None
5740 common = None
5737 else:
5741 else:
5738 common = commoninc
5742 common = commoninc
5739 if revs:
5743 if revs:
5740 revs = [repo.lookup(rev) for rev in revs]
5744 revs = [repo.lookup(rev) for rev in revs]
5741 repo.ui.pushbuffer()
5745 repo.ui.pushbuffer()
5742 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5746 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5743 commoninc=common)
5747 commoninc=common)
5744 repo.ui.popbuffer()
5748 repo.ui.popbuffer()
5745 return dest, dbranch, dother, outgoing
5749 return dest, dbranch, dother, outgoing
5746
5750
5747 if needsoutgoing:
5751 if needsoutgoing:
5748 dest, dbranch, dother, outgoing = getoutgoing()
5752 dest, dbranch, dother, outgoing = getoutgoing()
5749 else:
5753 else:
5750 dest = dbranch = dother = outgoing = None
5754 dest = dbranch = dother = outgoing = None
5751
5755
5752 if opts.get('remote'):
5756 if opts.get('remote'):
5753 t = []
5757 t = []
5754 if incoming:
5758 if incoming:
5755 t.append(_('1 or more incoming'))
5759 t.append(_('1 or more incoming'))
5756 o = outgoing.missing
5760 o = outgoing.missing
5757 if o:
5761 if o:
5758 t.append(_('%d outgoing') % len(o))
5762 t.append(_('%d outgoing') % len(o))
5759 other = dother or sother
5763 other = dother or sother
5760 if 'bookmarks' in other.listkeys('namespaces'):
5764 if 'bookmarks' in other.listkeys('namespaces'):
5761 counts = bookmarks.summary(repo, other)
5765 counts = bookmarks.summary(repo, other)
5762 if counts[0] > 0:
5766 if counts[0] > 0:
5763 t.append(_('%d incoming bookmarks') % counts[0])
5767 t.append(_('%d incoming bookmarks') % counts[0])
5764 if counts[1] > 0:
5768 if counts[1] > 0:
5765 t.append(_('%d outgoing bookmarks') % counts[1])
5769 t.append(_('%d outgoing bookmarks') % counts[1])
5766
5770
5767 if t:
5771 if t:
5768 # i18n: column positioning for "hg summary"
5772 # i18n: column positioning for "hg summary"
5769 ui.write(_('remote: %s\n') % (', '.join(t)))
5773 ui.write(_('remote: %s\n') % (', '.join(t)))
5770 else:
5774 else:
5771 # i18n: column positioning for "hg summary"
5775 # i18n: column positioning for "hg summary"
5772 ui.status(_('remote: (synced)\n'))
5776 ui.status(_('remote: (synced)\n'))
5773
5777
5774 cmdutil.summaryremotehooks(ui, repo, opts,
5778 cmdutil.summaryremotehooks(ui, repo, opts,
5775 ((source, sbranch, sother, commoninc),
5779 ((source, sbranch, sother, commoninc),
5776 (dest, dbranch, dother, outgoing)))
5780 (dest, dbranch, dother, outgoing)))
5777
5781
5778 @command('tag',
5782 @command('tag',
5779 [('f', 'force', None, _('force tag')),
5783 [('f', 'force', None, _('force tag')),
5780 ('l', 'local', None, _('make the tag local')),
5784 ('l', 'local', None, _('make the tag local')),
5781 ('r', 'rev', '', _('revision to tag'), _('REV')),
5785 ('r', 'rev', '', _('revision to tag'), _('REV')),
5782 ('', 'remove', None, _('remove a tag')),
5786 ('', 'remove', None, _('remove a tag')),
5783 # -l/--local is already there, commitopts cannot be used
5787 # -l/--local is already there, commitopts cannot be used
5784 ('e', 'edit', None, _('invoke editor on commit messages')),
5788 ('e', 'edit', None, _('invoke editor on commit messages')),
5785 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5789 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5786 ] + commitopts2,
5790 ] + commitopts2,
5787 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5791 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5788 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5792 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5789 def tag(ui, repo, name1, *names, **opts):
5793 def tag(ui, repo, name1, *names, **opts):
5790 """add one or more tags for the current or given revision
5794 """add one or more tags for the current or given revision
5791
5795
5792 Name a particular revision using <name>.
5796 Name a particular revision using <name>.
5793
5797
5794 Tags are used to name particular revisions of the repository and are
5798 Tags are used to name particular revisions of the repository and are
5795 very useful to compare different revisions, to go back to significant
5799 very useful to compare different revisions, to go back to significant
5796 earlier versions or to mark branch points as releases, etc. Changing
5800 earlier versions or to mark branch points as releases, etc. Changing
5797 an existing tag is normally disallowed; use -f/--force to override.
5801 an existing tag is normally disallowed; use -f/--force to override.
5798
5802
5799 If no revision is given, the parent of the working directory is
5803 If no revision is given, the parent of the working directory is
5800 used.
5804 used.
5801
5805
5802 To facilitate version control, distribution, and merging of tags,
5806 To facilitate version control, distribution, and merging of tags,
5803 they are stored as a file named ".hgtags" which is managed similarly
5807 they are stored as a file named ".hgtags" which is managed similarly
5804 to other project files and can be hand-edited if necessary. This
5808 to other project files and can be hand-edited if necessary. This
5805 also means that tagging creates a new commit. The file
5809 also means that tagging creates a new commit. The file
5806 ".hg/localtags" is used for local tags (not shared among
5810 ".hg/localtags" is used for local tags (not shared among
5807 repositories).
5811 repositories).
5808
5812
5809 Tag commits are usually made at the head of a branch. If the parent
5813 Tag commits are usually made at the head of a branch. If the parent
5810 of the working directory is not a branch head, :hg:`tag` aborts; use
5814 of the working directory is not a branch head, :hg:`tag` aborts; use
5811 -f/--force to force the tag commit to be based on a non-head
5815 -f/--force to force the tag commit to be based on a non-head
5812 changeset.
5816 changeset.
5813
5817
5814 See :hg:`help dates` for a list of formats valid for -d/--date.
5818 See :hg:`help dates` for a list of formats valid for -d/--date.
5815
5819
5816 Since tag names have priority over branch names during revision
5820 Since tag names have priority over branch names during revision
5817 lookup, using an existing branch name as a tag name is discouraged.
5821 lookup, using an existing branch name as a tag name is discouraged.
5818
5822
5819 Returns 0 on success.
5823 Returns 0 on success.
5820 """
5824 """
5821 opts = pycompat.byteskwargs(opts)
5825 opts = pycompat.byteskwargs(opts)
5822 with repo.wlock(), repo.lock():
5826 with repo.wlock(), repo.lock():
5823 rev_ = "."
5827 rev_ = "."
5824 names = [t.strip() for t in (name1,) + names]
5828 names = [t.strip() for t in (name1,) + names]
5825 if len(names) != len(set(names)):
5829 if len(names) != len(set(names)):
5826 raise error.Abort(_('tag names must be unique'))
5830 raise error.Abort(_('tag names must be unique'))
5827 for n in names:
5831 for n in names:
5828 scmutil.checknewlabel(repo, n, 'tag')
5832 scmutil.checknewlabel(repo, n, 'tag')
5829 if not n:
5833 if not n:
5830 raise error.Abort(_('tag names cannot consist entirely of '
5834 raise error.Abort(_('tag names cannot consist entirely of '
5831 'whitespace'))
5835 'whitespace'))
5832 if opts.get('rev') and opts.get('remove'):
5836 if opts.get('rev') and opts.get('remove'):
5833 raise error.Abort(_("--rev and --remove are incompatible"))
5837 raise error.Abort(_("--rev and --remove are incompatible"))
5834 if opts.get('rev'):
5838 if opts.get('rev'):
5835 rev_ = opts['rev']
5839 rev_ = opts['rev']
5836 message = opts.get('message')
5840 message = opts.get('message')
5837 if opts.get('remove'):
5841 if opts.get('remove'):
5838 if opts.get('local'):
5842 if opts.get('local'):
5839 expectedtype = 'local'
5843 expectedtype = 'local'
5840 else:
5844 else:
5841 expectedtype = 'global'
5845 expectedtype = 'global'
5842
5846
5843 for n in names:
5847 for n in names:
5844 if repo.tagtype(n) == 'global':
5848 if repo.tagtype(n) == 'global':
5845 alltags = tagsmod.findglobaltags(ui, repo)
5849 alltags = tagsmod.findglobaltags(ui, repo)
5846 if alltags[n][0] == nullid:
5850 if alltags[n][0] == nullid:
5847 raise error.Abort(_("tag '%s' is already removed") % n)
5851 raise error.Abort(_("tag '%s' is already removed") % n)
5848 if not repo.tagtype(n):
5852 if not repo.tagtype(n):
5849 raise error.Abort(_("tag '%s' does not exist") % n)
5853 raise error.Abort(_("tag '%s' does not exist") % n)
5850 if repo.tagtype(n) != expectedtype:
5854 if repo.tagtype(n) != expectedtype:
5851 if expectedtype == 'global':
5855 if expectedtype == 'global':
5852 raise error.Abort(_("tag '%s' is not a global tag") % n)
5856 raise error.Abort(_("tag '%s' is not a global tag") % n)
5853 else:
5857 else:
5854 raise error.Abort(_("tag '%s' is not a local tag") % n)
5858 raise error.Abort(_("tag '%s' is not a local tag") % n)
5855 rev_ = 'null'
5859 rev_ = 'null'
5856 if not message:
5860 if not message:
5857 # we don't translate commit messages
5861 # we don't translate commit messages
5858 message = 'Removed tag %s' % ', '.join(names)
5862 message = 'Removed tag %s' % ', '.join(names)
5859 elif not opts.get('force'):
5863 elif not opts.get('force'):
5860 for n in names:
5864 for n in names:
5861 if n in repo.tags():
5865 if n in repo.tags():
5862 raise error.Abort(_("tag '%s' already exists "
5866 raise error.Abort(_("tag '%s' already exists "
5863 "(use -f to force)") % n)
5867 "(use -f to force)") % n)
5864 if not opts.get('local'):
5868 if not opts.get('local'):
5865 p1, p2 = repo.dirstate.parents()
5869 p1, p2 = repo.dirstate.parents()
5866 if p2 != nullid:
5870 if p2 != nullid:
5867 raise error.Abort(_('uncommitted merge'))
5871 raise error.Abort(_('uncommitted merge'))
5868 bheads = repo.branchheads()
5872 bheads = repo.branchheads()
5869 if not opts.get('force') and bheads and p1 not in bheads:
5873 if not opts.get('force') and bheads and p1 not in bheads:
5870 raise error.Abort(_('working directory is not at a branch head '
5874 raise error.Abort(_('working directory is not at a branch head '
5871 '(use -f to force)'))
5875 '(use -f to force)'))
5872 node = scmutil.revsingle(repo, rev_).node()
5876 node = scmutil.revsingle(repo, rev_).node()
5873
5877
5874 if not message:
5878 if not message:
5875 # we don't translate commit messages
5879 # we don't translate commit messages
5876 message = ('Added tag %s for changeset %s' %
5880 message = ('Added tag %s for changeset %s' %
5877 (', '.join(names), short(node)))
5881 (', '.join(names), short(node)))
5878
5882
5879 date = opts.get('date')
5883 date = opts.get('date')
5880 if date:
5884 if date:
5881 date = dateutil.parsedate(date)
5885 date = dateutil.parsedate(date)
5882
5886
5883 if opts.get('remove'):
5887 if opts.get('remove'):
5884 editform = 'tag.remove'
5888 editform = 'tag.remove'
5885 else:
5889 else:
5886 editform = 'tag.add'
5890 editform = 'tag.add'
5887 editor = cmdutil.getcommiteditor(editform=editform,
5891 editor = cmdutil.getcommiteditor(editform=editform,
5888 **pycompat.strkwargs(opts))
5892 **pycompat.strkwargs(opts))
5889
5893
5890 # don't allow tagging the null rev
5894 # don't allow tagging the null rev
5891 if (not opts.get('remove') and
5895 if (not opts.get('remove') and
5892 scmutil.revsingle(repo, rev_).rev() == nullrev):
5896 scmutil.revsingle(repo, rev_).rev() == nullrev):
5893 raise error.Abort(_("cannot tag null revision"))
5897 raise error.Abort(_("cannot tag null revision"))
5894
5898
5895 tagsmod.tag(repo, names, node, message, opts.get('local'),
5899 tagsmod.tag(repo, names, node, message, opts.get('local'),
5896 opts.get('user'), date, editor=editor)
5900 opts.get('user'), date, editor=editor)
5897
5901
5898 @command(
5902 @command(
5899 'tags', formatteropts, '',
5903 'tags', formatteropts, '',
5900 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5904 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5901 intents={INTENT_READONLY})
5905 intents={INTENT_READONLY})
5902 def tags(ui, repo, **opts):
5906 def tags(ui, repo, **opts):
5903 """list repository tags
5907 """list repository tags
5904
5908
5905 This lists both regular and local tags. When the -v/--verbose
5909 This lists both regular and local tags. When the -v/--verbose
5906 switch is used, a third column "local" is printed for local tags.
5910 switch is used, a third column "local" is printed for local tags.
5907 When the -q/--quiet switch is used, only the tag name is printed.
5911 When the -q/--quiet switch is used, only the tag name is printed.
5908
5912
5909 .. container:: verbose
5913 .. container:: verbose
5910
5914
5911 Template:
5915 Template:
5912
5916
5913 The following keywords are supported in addition to the common template
5917 The following keywords are supported in addition to the common template
5914 keywords and functions such as ``{tag}``. See also
5918 keywords and functions such as ``{tag}``. See also
5915 :hg:`help templates`.
5919 :hg:`help templates`.
5916
5920
5917 :type: String. ``local`` for local tags.
5921 :type: String. ``local`` for local tags.
5918
5922
5919 Returns 0 on success.
5923 Returns 0 on success.
5920 """
5924 """
5921
5925
5922 opts = pycompat.byteskwargs(opts)
5926 opts = pycompat.byteskwargs(opts)
5923 ui.pager('tags')
5927 ui.pager('tags')
5924 fm = ui.formatter('tags', opts)
5928 fm = ui.formatter('tags', opts)
5925 hexfunc = fm.hexfunc
5929 hexfunc = fm.hexfunc
5926
5930
5927 for t, n in reversed(repo.tagslist()):
5931 for t, n in reversed(repo.tagslist()):
5928 hn = hexfunc(n)
5932 hn = hexfunc(n)
5929 label = 'tags.normal'
5933 label = 'tags.normal'
5930 tagtype = ''
5934 tagtype = ''
5931 if repo.tagtype(t) == 'local':
5935 if repo.tagtype(t) == 'local':
5932 label = 'tags.local'
5936 label = 'tags.local'
5933 tagtype = 'local'
5937 tagtype = 'local'
5934
5938
5935 fm.startitem()
5939 fm.startitem()
5936 fm.context(repo=repo)
5940 fm.context(repo=repo)
5937 fm.write('tag', '%s', t, label=label)
5941 fm.write('tag', '%s', t, label=label)
5938 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5942 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5939 fm.condwrite(not ui.quiet, 'rev node', fmt,
5943 fm.condwrite(not ui.quiet, 'rev node', fmt,
5940 repo.changelog.rev(n), hn, label=label)
5944 repo.changelog.rev(n), hn, label=label)
5941 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5945 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5942 tagtype, label=label)
5946 tagtype, label=label)
5943 fm.plain('\n')
5947 fm.plain('\n')
5944 fm.end()
5948 fm.end()
5945
5949
5946 @command('tip',
5950 @command('tip',
5947 [('p', 'patch', None, _('show patch')),
5951 [('p', 'patch', None, _('show patch')),
5948 ('g', 'git', None, _('use git extended diff format')),
5952 ('g', 'git', None, _('use git extended diff format')),
5949 ] + templateopts,
5953 ] + templateopts,
5950 _('[-p] [-g]'),
5954 _('[-p] [-g]'),
5951 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5955 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5952 def tip(ui, repo, **opts):
5956 def tip(ui, repo, **opts):
5953 """show the tip revision (DEPRECATED)
5957 """show the tip revision (DEPRECATED)
5954
5958
5955 The tip revision (usually just called the tip) is the changeset
5959 The tip revision (usually just called the tip) is the changeset
5956 most recently added to the repository (and therefore the most
5960 most recently added to the repository (and therefore the most
5957 recently changed head).
5961 recently changed head).
5958
5962
5959 If you have just made a commit, that commit will be the tip. If
5963 If you have just made a commit, that commit will be the tip. If
5960 you have just pulled changes from another repository, the tip of
5964 you have just pulled changes from another repository, the tip of
5961 that repository becomes the current tip. The "tip" tag is special
5965 that repository becomes the current tip. The "tip" tag is special
5962 and cannot be renamed or assigned to a different changeset.
5966 and cannot be renamed or assigned to a different changeset.
5963
5967
5964 This command is deprecated, please use :hg:`heads` instead.
5968 This command is deprecated, please use :hg:`heads` instead.
5965
5969
5966 Returns 0 on success.
5970 Returns 0 on success.
5967 """
5971 """
5968 opts = pycompat.byteskwargs(opts)
5972 opts = pycompat.byteskwargs(opts)
5969 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5973 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5970 displayer.show(repo['tip'])
5974 displayer.show(repo['tip'])
5971 displayer.close()
5975 displayer.close()
5972
5976
5973 @command('unbundle',
5977 @command('unbundle',
5974 [('u', 'update', None,
5978 [('u', 'update', None,
5975 _('update to new branch head if changesets were unbundled'))],
5979 _('update to new branch head if changesets were unbundled'))],
5976 _('[-u] FILE...'),
5980 _('[-u] FILE...'),
5977 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5981 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5978 def unbundle(ui, repo, fname1, *fnames, **opts):
5982 def unbundle(ui, repo, fname1, *fnames, **opts):
5979 """apply one or more bundle files
5983 """apply one or more bundle files
5980
5984
5981 Apply one or more bundle files generated by :hg:`bundle`.
5985 Apply one or more bundle files generated by :hg:`bundle`.
5982
5986
5983 Returns 0 on success, 1 if an update has unresolved files.
5987 Returns 0 on success, 1 if an update has unresolved files.
5984 """
5988 """
5985 fnames = (fname1,) + fnames
5989 fnames = (fname1,) + fnames
5986
5990
5987 with repo.lock():
5991 with repo.lock():
5988 for fname in fnames:
5992 for fname in fnames:
5989 f = hg.openpath(ui, fname)
5993 f = hg.openpath(ui, fname)
5990 gen = exchange.readbundle(ui, f, fname)
5994 gen = exchange.readbundle(ui, f, fname)
5991 if isinstance(gen, streamclone.streamcloneapplier):
5995 if isinstance(gen, streamclone.streamcloneapplier):
5992 raise error.Abort(
5996 raise error.Abort(
5993 _('packed bundles cannot be applied with '
5997 _('packed bundles cannot be applied with '
5994 '"hg unbundle"'),
5998 '"hg unbundle"'),
5995 hint=_('use "hg debugapplystreamclonebundle"'))
5999 hint=_('use "hg debugapplystreamclonebundle"'))
5996 url = 'bundle:' + fname
6000 url = 'bundle:' + fname
5997 try:
6001 try:
5998 txnname = 'unbundle'
6002 txnname = 'unbundle'
5999 if not isinstance(gen, bundle2.unbundle20):
6003 if not isinstance(gen, bundle2.unbundle20):
6000 txnname = 'unbundle\n%s' % util.hidepassword(url)
6004 txnname = 'unbundle\n%s' % util.hidepassword(url)
6001 with repo.transaction(txnname) as tr:
6005 with repo.transaction(txnname) as tr:
6002 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6006 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6003 url=url)
6007 url=url)
6004 except error.BundleUnknownFeatureError as exc:
6008 except error.BundleUnknownFeatureError as exc:
6005 raise error.Abort(
6009 raise error.Abort(
6006 _('%s: unknown bundle feature, %s') % (fname, exc),
6010 _('%s: unknown bundle feature, %s') % (fname, exc),
6007 hint=_("see https://mercurial-scm.org/"
6011 hint=_("see https://mercurial-scm.org/"
6008 "wiki/BundleFeature for more "
6012 "wiki/BundleFeature for more "
6009 "information"))
6013 "information"))
6010 modheads = bundle2.combinechangegroupresults(op)
6014 modheads = bundle2.combinechangegroupresults(op)
6011
6015
6012 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6016 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6013
6017
6014 @command('update|up|checkout|co',
6018 @command('update|up|checkout|co',
6015 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6019 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6016 ('c', 'check', None, _('require clean working directory')),
6020 ('c', 'check', None, _('require clean working directory')),
6017 ('m', 'merge', None, _('merge uncommitted changes')),
6021 ('m', 'merge', None, _('merge uncommitted changes')),
6018 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6022 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6019 ('r', 'rev', '', _('revision'), _('REV'))
6023 ('r', 'rev', '', _('revision'), _('REV'))
6020 ] + mergetoolopts,
6024 ] + mergetoolopts,
6021 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6025 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6022 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6026 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6023 helpbasic=True)
6027 helpbasic=True)
6024 def update(ui, repo, node=None, **opts):
6028 def update(ui, repo, node=None, **opts):
6025 """update working directory (or switch revisions)
6029 """update working directory (or switch revisions)
6026
6030
6027 Update the repository's working directory to the specified
6031 Update the repository's working directory to the specified
6028 changeset. If no changeset is specified, update to the tip of the
6032 changeset. If no changeset is specified, update to the tip of the
6029 current named branch and move the active bookmark (see :hg:`help
6033 current named branch and move the active bookmark (see :hg:`help
6030 bookmarks`).
6034 bookmarks`).
6031
6035
6032 Update sets the working directory's parent revision to the specified
6036 Update sets the working directory's parent revision to the specified
6033 changeset (see :hg:`help parents`).
6037 changeset (see :hg:`help parents`).
6034
6038
6035 If the changeset is not a descendant or ancestor of the working
6039 If the changeset is not a descendant or ancestor of the working
6036 directory's parent and there are uncommitted changes, the update is
6040 directory's parent and there are uncommitted changes, the update is
6037 aborted. With the -c/--check option, the working directory is checked
6041 aborted. With the -c/--check option, the working directory is checked
6038 for uncommitted changes; if none are found, the working directory is
6042 for uncommitted changes; if none are found, the working directory is
6039 updated to the specified changeset.
6043 updated to the specified changeset.
6040
6044
6041 .. container:: verbose
6045 .. container:: verbose
6042
6046
6043 The -C/--clean, -c/--check, and -m/--merge options control what
6047 The -C/--clean, -c/--check, and -m/--merge options control what
6044 happens if the working directory contains uncommitted changes.
6048 happens if the working directory contains uncommitted changes.
6045 At most of one of them can be specified.
6049 At most of one of them can be specified.
6046
6050
6047 1. If no option is specified, and if
6051 1. If no option is specified, and if
6048 the requested changeset is an ancestor or descendant of
6052 the requested changeset is an ancestor or descendant of
6049 the working directory's parent, the uncommitted changes
6053 the working directory's parent, the uncommitted changes
6050 are merged into the requested changeset and the merged
6054 are merged into the requested changeset and the merged
6051 result is left uncommitted. If the requested changeset is
6055 result is left uncommitted. If the requested changeset is
6052 not an ancestor or descendant (that is, it is on another
6056 not an ancestor or descendant (that is, it is on another
6053 branch), the update is aborted and the uncommitted changes
6057 branch), the update is aborted and the uncommitted changes
6054 are preserved.
6058 are preserved.
6055
6059
6056 2. With the -m/--merge option, the update is allowed even if the
6060 2. With the -m/--merge option, the update is allowed even if the
6057 requested changeset is not an ancestor or descendant of
6061 requested changeset is not an ancestor or descendant of
6058 the working directory's parent.
6062 the working directory's parent.
6059
6063
6060 3. With the -c/--check option, the update is aborted and the
6064 3. With the -c/--check option, the update is aborted and the
6061 uncommitted changes are preserved.
6065 uncommitted changes are preserved.
6062
6066
6063 4. With the -C/--clean option, uncommitted changes are discarded and
6067 4. With the -C/--clean option, uncommitted changes are discarded and
6064 the working directory is updated to the requested changeset.
6068 the working directory is updated to the requested changeset.
6065
6069
6066 To cancel an uncommitted merge (and lose your changes), use
6070 To cancel an uncommitted merge (and lose your changes), use
6067 :hg:`merge --abort`.
6071 :hg:`merge --abort`.
6068
6072
6069 Use null as the changeset to remove the working directory (like
6073 Use null as the changeset to remove the working directory (like
6070 :hg:`clone -U`).
6074 :hg:`clone -U`).
6071
6075
6072 If you want to revert just one file to an older revision, use
6076 If you want to revert just one file to an older revision, use
6073 :hg:`revert [-r REV] NAME`.
6077 :hg:`revert [-r REV] NAME`.
6074
6078
6075 See :hg:`help dates` for a list of formats valid for -d/--date.
6079 See :hg:`help dates` for a list of formats valid for -d/--date.
6076
6080
6077 Returns 0 on success, 1 if there are unresolved files.
6081 Returns 0 on success, 1 if there are unresolved files.
6078 """
6082 """
6079 rev = opts.get(r'rev')
6083 rev = opts.get(r'rev')
6080 date = opts.get(r'date')
6084 date = opts.get(r'date')
6081 clean = opts.get(r'clean')
6085 clean = opts.get(r'clean')
6082 check = opts.get(r'check')
6086 check = opts.get(r'check')
6083 merge = opts.get(r'merge')
6087 merge = opts.get(r'merge')
6084 if rev and node:
6088 if rev and node:
6085 raise error.Abort(_("please specify just one revision"))
6089 raise error.Abort(_("please specify just one revision"))
6086
6090
6087 if ui.configbool('commands', 'update.requiredest'):
6091 if ui.configbool('commands', 'update.requiredest'):
6088 if not node and not rev and not date:
6092 if not node and not rev and not date:
6089 raise error.Abort(_('you must specify a destination'),
6093 raise error.Abort(_('you must specify a destination'),
6090 hint=_('for example: hg update ".::"'))
6094 hint=_('for example: hg update ".::"'))
6091
6095
6092 if rev is None or rev == '':
6096 if rev is None or rev == '':
6093 rev = node
6097 rev = node
6094
6098
6095 if date and rev is not None:
6099 if date and rev is not None:
6096 raise error.Abort(_("you can't specify a revision and a date"))
6100 raise error.Abort(_("you can't specify a revision and a date"))
6097
6101
6098 if len([x for x in (clean, check, merge) if x]) > 1:
6102 if len([x for x in (clean, check, merge) if x]) > 1:
6099 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6103 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6100 "or -m/--merge"))
6104 "or -m/--merge"))
6101
6105
6102 updatecheck = None
6106 updatecheck = None
6103 if check:
6107 if check:
6104 updatecheck = 'abort'
6108 updatecheck = 'abort'
6105 elif merge:
6109 elif merge:
6106 updatecheck = 'none'
6110 updatecheck = 'none'
6107
6111
6108 with repo.wlock():
6112 with repo.wlock():
6109 cmdutil.clearunfinished(repo)
6113 cmdutil.clearunfinished(repo)
6110
6114
6111 if date:
6115 if date:
6112 rev = cmdutil.finddate(ui, repo, date)
6116 rev = cmdutil.finddate(ui, repo, date)
6113
6117
6114 # if we defined a bookmark, we have to remember the original name
6118 # if we defined a bookmark, we have to remember the original name
6115 brev = rev
6119 brev = rev
6116 if rev:
6120 if rev:
6117 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6121 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6118 ctx = scmutil.revsingle(repo, rev, default=None)
6122 ctx = scmutil.revsingle(repo, rev, default=None)
6119 rev = ctx.rev()
6123 rev = ctx.rev()
6120 hidden = ctx.hidden()
6124 hidden = ctx.hidden()
6121 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6125 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6122 with ui.configoverride(overrides, 'update'):
6126 with ui.configoverride(overrides, 'update'):
6123 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6127 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6124 updatecheck=updatecheck)
6128 updatecheck=updatecheck)
6125 if hidden:
6129 if hidden:
6126 ctxstr = ctx.hex()[:12]
6130 ctxstr = ctx.hex()[:12]
6127 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6131 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6128
6132
6129 if ctx.obsolete():
6133 if ctx.obsolete():
6130 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6134 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6131 ui.warn("(%s)\n" % obsfatemsg)
6135 ui.warn("(%s)\n" % obsfatemsg)
6132 return ret
6136 return ret
6133
6137
6134 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6138 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6135 def verify(ui, repo):
6139 def verify(ui, repo):
6136 """verify the integrity of the repository
6140 """verify the integrity of the repository
6137
6141
6138 Verify the integrity of the current repository.
6142 Verify the integrity of the current repository.
6139
6143
6140 This will perform an extensive check of the repository's
6144 This will perform an extensive check of the repository's
6141 integrity, validating the hashes and checksums of each entry in
6145 integrity, validating the hashes and checksums of each entry in
6142 the changelog, manifest, and tracked files, as well as the
6146 the changelog, manifest, and tracked files, as well as the
6143 integrity of their crosslinks and indices.
6147 integrity of their crosslinks and indices.
6144
6148
6145 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6149 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6146 for more information about recovery from corruption of the
6150 for more information about recovery from corruption of the
6147 repository.
6151 repository.
6148
6152
6149 Returns 0 on success, 1 if errors are encountered.
6153 Returns 0 on success, 1 if errors are encountered.
6150 """
6154 """
6151 return hg.verify(repo)
6155 return hg.verify(repo)
6152
6156
6153 @command(
6157 @command(
6154 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6158 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6155 norepo=True, intents={INTENT_READONLY})
6159 norepo=True, intents={INTENT_READONLY})
6156 def version_(ui, **opts):
6160 def version_(ui, **opts):
6157 """output version and copyright information
6161 """output version and copyright information
6158
6162
6159 .. container:: verbose
6163 .. container:: verbose
6160
6164
6161 Template:
6165 Template:
6162
6166
6163 The following keywords are supported. See also :hg:`help templates`.
6167 The following keywords are supported. See also :hg:`help templates`.
6164
6168
6165 :extensions: List of extensions.
6169 :extensions: List of extensions.
6166 :ver: String. Version number.
6170 :ver: String. Version number.
6167
6171
6168 And each entry of ``{extensions}`` provides the following sub-keywords
6172 And each entry of ``{extensions}`` provides the following sub-keywords
6169 in addition to ``{ver}``.
6173 in addition to ``{ver}``.
6170
6174
6171 :bundled: Boolean. True if included in the release.
6175 :bundled: Boolean. True if included in the release.
6172 :name: String. Extension name.
6176 :name: String. Extension name.
6173 """
6177 """
6174 opts = pycompat.byteskwargs(opts)
6178 opts = pycompat.byteskwargs(opts)
6175 if ui.verbose:
6179 if ui.verbose:
6176 ui.pager('version')
6180 ui.pager('version')
6177 fm = ui.formatter("version", opts)
6181 fm = ui.formatter("version", opts)
6178 fm.startitem()
6182 fm.startitem()
6179 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6183 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6180 util.version())
6184 util.version())
6181 license = _(
6185 license = _(
6182 "(see https://mercurial-scm.org for more information)\n"
6186 "(see https://mercurial-scm.org for more information)\n"
6183 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6187 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6184 "This is free software; see the source for copying conditions. "
6188 "This is free software; see the source for copying conditions. "
6185 "There is NO\nwarranty; "
6189 "There is NO\nwarranty; "
6186 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6190 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6187 )
6191 )
6188 if not ui.quiet:
6192 if not ui.quiet:
6189 fm.plain(license)
6193 fm.plain(license)
6190
6194
6191 if ui.verbose:
6195 if ui.verbose:
6192 fm.plain(_("\nEnabled extensions:\n\n"))
6196 fm.plain(_("\nEnabled extensions:\n\n"))
6193 # format names and versions into columns
6197 # format names and versions into columns
6194 names = []
6198 names = []
6195 vers = []
6199 vers = []
6196 isinternals = []
6200 isinternals = []
6197 for name, module in extensions.extensions():
6201 for name, module in extensions.extensions():
6198 names.append(name)
6202 names.append(name)
6199 vers.append(extensions.moduleversion(module) or None)
6203 vers.append(extensions.moduleversion(module) or None)
6200 isinternals.append(extensions.ismoduleinternal(module))
6204 isinternals.append(extensions.ismoduleinternal(module))
6201 fn = fm.nested("extensions", tmpl='{name}\n')
6205 fn = fm.nested("extensions", tmpl='{name}\n')
6202 if names:
6206 if names:
6203 namefmt = " %%-%ds " % max(len(n) for n in names)
6207 namefmt = " %%-%ds " % max(len(n) for n in names)
6204 places = [_("external"), _("internal")]
6208 places = [_("external"), _("internal")]
6205 for n, v, p in zip(names, vers, isinternals):
6209 for n, v, p in zip(names, vers, isinternals):
6206 fn.startitem()
6210 fn.startitem()
6207 fn.condwrite(ui.verbose, "name", namefmt, n)
6211 fn.condwrite(ui.verbose, "name", namefmt, n)
6208 if ui.verbose:
6212 if ui.verbose:
6209 fn.plain("%s " % places[p])
6213 fn.plain("%s " % places[p])
6210 fn.data(bundled=p)
6214 fn.data(bundled=p)
6211 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6215 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6212 if ui.verbose:
6216 if ui.verbose:
6213 fn.plain("\n")
6217 fn.plain("\n")
6214 fn.end()
6218 fn.end()
6215 fm.end()
6219 fm.end()
6216
6220
6217 def loadcmdtable(ui, name, cmdtable):
6221 def loadcmdtable(ui, name, cmdtable):
6218 """Load command functions from specified cmdtable
6222 """Load command functions from specified cmdtable
6219 """
6223 """
6220 cmdtable = cmdtable.copy()
6224 cmdtable = cmdtable.copy()
6221 for cmd in list(cmdtable):
6225 for cmd in list(cmdtable):
6222 if not cmd.startswith('^'):
6226 if not cmd.startswith('^'):
6223 continue
6227 continue
6224 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6228 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6225 % (cmd, name), '4.8')
6229 % (cmd, name), '4.8')
6226 entry = cmdtable.pop(cmd)
6230 entry = cmdtable.pop(cmd)
6227 entry[0].helpbasic = True
6231 entry[0].helpbasic = True
6228 cmdtable[cmd[1:]] = entry
6232 cmdtable[cmd[1:]] = entry
6229
6233
6230 overrides = [cmd for cmd in cmdtable if cmd in table]
6234 overrides = [cmd for cmd in cmdtable if cmd in table]
6231 if overrides:
6235 if overrides:
6232 ui.warn(_("extension '%s' overrides commands: %s\n")
6236 ui.warn(_("extension '%s' overrides commands: %s\n")
6233 % (name, " ".join(overrides)))
6237 % (name, " ".join(overrides)))
6234 table.update(cmdtable)
6238 table.update(cmdtable)
@@ -1,524 +1,528 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ echo import > port
3 $ echo import > port
4 $ hg add port
4 $ hg add port
5 $ hg commit -m 0 -u spam -d '0 0'
5 $ hg commit -m 0 -u spam -d '0 0'
6 $ echo export >> port
6 $ echo export >> port
7 $ hg commit -m 1 -u eggs -d '1 0'
7 $ hg commit -m 1 -u eggs -d '1 0'
8 $ echo export > port
8 $ echo export > port
9 $ echo vaportight >> port
9 $ echo vaportight >> port
10 $ echo 'import/export' >> port
10 $ echo 'import/export' >> port
11 $ hg commit -m 2 -u spam -d '2 0'
11 $ hg commit -m 2 -u spam -d '2 0'
12 $ echo 'import/export' >> port
12 $ echo 'import/export' >> port
13 $ hg commit -m 3 -u eggs -d '3 0'
13 $ hg commit -m 3 -u eggs -d '3 0'
14 $ head -n 3 port > port1
14 $ head -n 3 port > port1
15 $ mv port1 port
15 $ mv port1 port
16 $ hg commit -m 4 -u spam -d '4 0'
16 $ hg commit -m 4 -u spam -d '4 0'
17
17
18 pattern error
18 pattern error
19
19
20 $ hg grep '**test**'
20 $ hg grep '**test**'
21 grep: invalid match pattern: nothing to repeat* (glob)
21 grep: invalid match pattern: nothing to repeat* (glob)
22 [1]
22 [1]
23
23
24 simple
24 simple
25
25
26 $ hg grep -r tip:0 '.*'
26 $ hg grep -r tip:0 '.*'
27 port:4:export
27 port:4:export
28 port:4:vaportight
28 port:4:vaportight
29 port:4:import/export
29 port:4:import/export
30 $ hg grep -r tip:0 port port
30 $ hg grep -r tip:0 port port
31 port:4:export
31 port:4:export
32 port:4:vaportight
32 port:4:vaportight
33 port:4:import/export
33 port:4:import/export
34
34
35 simple from subdirectory
35 simple from subdirectory
36
36
37 $ mkdir dir
37 $ mkdir dir
38 $ cd dir
38 $ cd dir
39 $ hg grep -r tip:0 port
39 $ hg grep -r tip:0 port
40 port:4:export
40 port:4:export
41 port:4:vaportight
41 port:4:vaportight
42 port:4:import/export
42 port:4:import/export
43 $ hg grep -r tip:0 port --config ui.relative-paths=yes
43 $ hg grep -r tip:0 port --config ui.relative-paths=yes
44 ../port:4:export
44 ../port:4:export
45 ../port:4:vaportight
45 ../port:4:vaportight
46 ../port:4:import/export
46 ../port:4:import/export
47 $ cd ..
47 $ cd ..
48
48
49 simple with color
49 simple with color
50
50
51 $ hg --config extensions.color= grep --config color.mode=ansi \
51 $ hg --config extensions.color= grep --config color.mode=ansi \
52 > --color=always port port -r tip:0
52 > --color=always port port -r tip:0
53 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
53 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
54 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
54 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
55 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
55 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
56
56
57 simple templated
57 simple templated
58
58
59 $ hg grep port -r tip:0 \
59 $ hg grep port -r tip:0 \
60 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
60 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
61 port:4:914fa752cdea:exPORT
61 port:4:914fa752cdea:exPORT
62 port:4:914fa752cdea:vaPORTight
62 port:4:914fa752cdea:vaPORTight
63 port:4:914fa752cdea:imPORT/exPORT
63 port:4:914fa752cdea:imPORT/exPORT
64
64
65 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
65 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
66 port:4:export
66 port:4:export
67 port:4:vaportight
67 port:4:vaportight
68 port:4:import/export
68 port:4:import/export
69
69
70 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
70 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
71 port:tip:export
71 port:tip:export
72 port:tip:vaportight
72 port:tip:vaportight
73 port:tip:import/export
73 port:tip:import/export
74
74
75 simple JSON (no "change" field)
75 simple JSON (no "change" field)
76
76
77 $ hg grep -r tip:0 -Tjson port
77 $ hg grep -r tip:0 -Tjson port
78 [
78 [
79 {
79 {
80 "date": [4, 0],
80 "date": [4, 0],
81 "lineno": 1,
81 "lineno": 1,
82 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
82 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
83 "path": "port",
83 "path": "port",
84 "rev": 4,
84 "rev": 4,
85 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
85 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
86 "user": "spam"
86 "user": "spam"
87 },
87 },
88 {
88 {
89 "date": [4, 0],
89 "date": [4, 0],
90 "lineno": 2,
90 "lineno": 2,
91 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
91 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
92 "path": "port",
92 "path": "port",
93 "rev": 4,
93 "rev": 4,
94 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
94 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
95 "user": "spam"
95 "user": "spam"
96 },
96 },
97 {
97 {
98 "date": [4, 0],
98 "date": [4, 0],
99 "lineno": 3,
99 "lineno": 3,
100 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
100 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
101 "path": "port",
101 "path": "port",
102 "rev": 4,
102 "rev": 4,
103 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
103 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
104 "user": "spam"
104 "user": "spam"
105 }
105 }
106 ]
106 ]
107
107
108 simple JSON without matching lines
108 simple JSON without matching lines
109
109
110 $ hg grep -r tip:0 -Tjson -l port
110 $ hg grep -r tip:0 -Tjson -l port
111 [
111 [
112 {
112 {
113 "date": [4, 0],
113 "date": [4, 0],
114 "lineno": 1,
114 "lineno": 1,
115 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
115 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
116 "path": "port",
116 "path": "port",
117 "rev": 4,
117 "rev": 4,
118 "user": "spam"
118 "user": "spam"
119 }
119 }
120 ]
120 ]
121
121
122 all
122 all
123
123
124 $ hg grep --traceback --all -nu port port
124 $ hg grep --traceback --all -nu port port
125 port:4:4:-:spam:import/export
125 port:4:4:-:spam:import/export
126 port:3:4:+:eggs:import/export
126 port:3:4:+:eggs:import/export
127 port:2:1:-:spam:import
127 port:2:1:-:spam:import
128 port:2:2:-:spam:export
128 port:2:2:-:spam:export
129 port:2:1:+:spam:export
129 port:2:1:+:spam:export
130 port:2:2:+:spam:vaportight
130 port:2:2:+:spam:vaportight
131 port:2:3:+:spam:import/export
131 port:2:3:+:spam:import/export
132 port:1:2:+:eggs:export
132 port:1:2:+:eggs:export
133 port:0:1:+:spam:import
133 port:0:1:+:spam:import
134
134
135 all JSON
135 all JSON
136
136
137 $ hg grep --all -Tjson port port
137 $ hg grep --all -Tjson port port
138 [
138 [
139 {
139 {
140 "change": "-",
140 "change": "-",
141 "date": [4, 0],
141 "date": [4, 0],
142 "lineno": 4,
142 "lineno": 4,
143 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
143 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
144 "path": "port",
144 "path": "port",
145 "rev": 4,
145 "rev": 4,
146 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
146 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
147 "user": "spam"
147 "user": "spam"
148 },
148 },
149 {
149 {
150 "change": "+",
150 "change": "+",
151 "date": [3, 0],
151 "date": [3, 0],
152 "lineno": 4,
152 "lineno": 4,
153 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
153 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
154 "path": "port",
154 "path": "port",
155 "rev": 3,
155 "rev": 3,
156 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
156 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
157 "user": "eggs"
157 "user": "eggs"
158 },
158 },
159 {
159 {
160 "change": "-",
160 "change": "-",
161 "date": [2, 0],
161 "date": [2, 0],
162 "lineno": 1,
162 "lineno": 1,
163 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
163 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
164 "path": "port",
164 "path": "port",
165 "rev": 2,
165 "rev": 2,
166 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
166 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
167 "user": "spam"
167 "user": "spam"
168 },
168 },
169 {
169 {
170 "change": "-",
170 "change": "-",
171 "date": [2, 0],
171 "date": [2, 0],
172 "lineno": 2,
172 "lineno": 2,
173 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
173 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
174 "path": "port",
174 "path": "port",
175 "rev": 2,
175 "rev": 2,
176 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
176 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
177 "user": "spam"
177 "user": "spam"
178 },
178 },
179 {
179 {
180 "change": "+",
180 "change": "+",
181 "date": [2, 0],
181 "date": [2, 0],
182 "lineno": 1,
182 "lineno": 1,
183 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
183 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
184 "path": "port",
184 "path": "port",
185 "rev": 2,
185 "rev": 2,
186 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
186 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
187 "user": "spam"
187 "user": "spam"
188 },
188 },
189 {
189 {
190 "change": "+",
190 "change": "+",
191 "date": [2, 0],
191 "date": [2, 0],
192 "lineno": 2,
192 "lineno": 2,
193 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
193 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
194 "path": "port",
194 "path": "port",
195 "rev": 2,
195 "rev": 2,
196 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
196 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
197 "user": "spam"
197 "user": "spam"
198 },
198 },
199 {
199 {
200 "change": "+",
200 "change": "+",
201 "date": [2, 0],
201 "date": [2, 0],
202 "lineno": 3,
202 "lineno": 3,
203 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
203 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
204 "path": "port",
204 "path": "port",
205 "rev": 2,
205 "rev": 2,
206 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
206 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
207 "user": "spam"
207 "user": "spam"
208 },
208 },
209 {
209 {
210 "change": "+",
210 "change": "+",
211 "date": [1, 0],
211 "date": [1, 0],
212 "lineno": 2,
212 "lineno": 2,
213 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
213 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
214 "path": "port",
214 "path": "port",
215 "rev": 1,
215 "rev": 1,
216 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
216 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
217 "user": "eggs"
217 "user": "eggs"
218 },
218 },
219 {
219 {
220 "change": "+",
220 "change": "+",
221 "date": [0, 0],
221 "date": [0, 0],
222 "lineno": 1,
222 "lineno": 1,
223 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
223 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
224 "path": "port",
224 "path": "port",
225 "rev": 0,
225 "rev": 0,
226 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
226 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
227 "user": "spam"
227 "user": "spam"
228 }
228 }
229 ]
229 ]
230
230
231 other
231 other
232
232
233 $ hg grep -r tip:0 -l port port
233 $ hg grep -r tip:0 -l port port
234 port:4
234 port:4
235 $ hg grep -r tip:0 import port
235 $ hg grep -r tip:0 import port
236 port:4:import/export
236 port:4:import/export
237
237
238 $ hg cp port port2
238 $ hg cp port port2
239 $ hg commit -m 4 -u spam -d '5 0'
239 $ hg commit -m 4 -u spam -d '5 0'
240
240
241 follow
241 follow
242
242
243 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
243 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
244 port:0:import
244 port:0:import
245
245
246 $ echo deport >> port2
246 $ echo deport >> port2
247 $ hg commit -m 5 -u eggs -d '6 0'
247 $ hg commit -m 5 -u eggs -d '6 0'
248 $ hg grep -f --all -nu port port2
248 $ hg grep -f --all -nu port port2
249 port2:6:4:+:eggs:deport
249 port2:6:4:+:eggs:deport
250 port:4:4:-:spam:import/export
250 port:4:4:-:spam:import/export
251 port:3:4:+:eggs:import/export
251 port:3:4:+:eggs:import/export
252 port:2:1:-:spam:import
252 port:2:1:-:spam:import
253 port:2:2:-:spam:export
253 port:2:2:-:spam:export
254 port:2:1:+:spam:export
254 port:2:1:+:spam:export
255 port:2:2:+:spam:vaportight
255 port:2:2:+:spam:vaportight
256 port:2:3:+:spam:import/export
256 port:2:3:+:spam:import/export
257 port:1:2:+:eggs:export
257 port:1:2:+:eggs:export
258 port:0:1:+:spam:import
258 port:0:1:+:spam:import
259
259
260 $ hg up -q null
260 $ hg up -q null
261 $ hg grep -r 'reverse(:.)' -f port
261 $ hg grep -r 'reverse(:.)' -f port
262 port:0:import
262 port:0:import
263
263
264 Test wdir
264 Test wdir
265 (at least, this shouldn't crash)
265 (at least, this shouldn't crash)
266
266
267 $ hg up -q
267 $ hg up -q
268 $ echo wport >> port2
268 $ echo wport >> port2
269 $ hg stat
269 $ hg stat
270 M port2
270 M port2
271 $ hg grep -r 'wdir()' port
271 $ hg grep -r 'wdir()' port
272 port2:2147483647:export
272 port2:2147483647:export
273 port2:2147483647:vaportight
273 port2:2147483647:vaportight
274 port2:2147483647:import/export
274 port2:2147483647:import/export
275 port2:2147483647:deport
275 port2:2147483647:deport
276 port2:2147483647:wport
276 port2:2147483647:wport
277
277
278 $ cd ..
278 $ cd ..
279 $ hg init t2
279 $ hg init t2
280 $ cd t2
280 $ cd t2
281 $ hg grep -r tip:0 foobar foo
281 $ hg grep -r tip:0 foobar foo
282 [1]
282 [1]
283 $ hg grep -r tip:0 foobar
283 $ hg grep -r tip:0 foobar
284 [1]
284 [1]
285 $ echo blue >> color
285 $ echo blue >> color
286 $ echo black >> color
286 $ echo black >> color
287 $ hg add color
287 $ hg add color
288 $ hg ci -m 0
288 $ hg ci -m 0
289 $ echo orange >> color
289 $ echo orange >> color
290 $ hg ci -m 1
290 $ hg ci -m 1
291 $ echo black > color
291 $ echo black > color
292 $ hg ci -m 2
292 $ hg ci -m 2
293 $ echo orange >> color
293 $ echo orange >> color
294 $ echo blue >> color
294 $ echo blue >> color
295 $ hg ci -m 3
295 $ hg ci -m 3
296 $ hg grep -r tip:0 orange
296 $ hg grep -r tip:0 orange
297 color:3:orange
297 color:3:orange
298 $ hg grep --all orange
298 $ hg grep --all orange
299 color:3:+:orange
299 color:3:+:orange
300 color:2:-:orange
300 color:2:-:orange
301 color:1:+:orange
301 color:1:+:orange
302 $ hg grep --diff orange --color=debug
303 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
304 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
305 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
302
306
303 $ hg grep --diff orange
307 $ hg grep --diff orange
304 color:3:+:orange
308 color:3:+:orange
305 color:2:-:orange
309 color:2:-:orange
306 color:1:+:orange
310 color:1:+:orange
307
311
308 test substring match: '^' should only match at the beginning
312 test substring match: '^' should only match at the beginning
309
313
310 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
314 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
311 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
315 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
312 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
316 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
313 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
317 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
314
318
315 match in last "line" without newline
319 match in last "line" without newline
316
320
317 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
321 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
318 $ hg ci -Amnoeol
322 $ hg ci -Amnoeol
319 adding noeol
323 adding noeol
320 $ hg grep -r tip:0 loop
324 $ hg grep -r tip:0 loop
321 noeol:4:no infinite loop
325 noeol:4:no infinite loop
322
326
323 $ cd ..
327 $ cd ..
324
328
325 Issue685: traceback in grep -r after rename
329 Issue685: traceback in grep -r after rename
326
330
327 Got a traceback when using grep on a single
331 Got a traceback when using grep on a single
328 revision with renamed files.
332 revision with renamed files.
329
333
330 $ hg init issue685
334 $ hg init issue685
331 $ cd issue685
335 $ cd issue685
332 $ echo octarine > color
336 $ echo octarine > color
333 $ hg ci -Amcolor
337 $ hg ci -Amcolor
334 adding color
338 adding color
335 $ hg rename color colour
339 $ hg rename color colour
336 $ hg ci -Am rename
340 $ hg ci -Am rename
337 $ hg grep -r tip:0 octarine
341 $ hg grep -r tip:0 octarine
338 colour:1:octarine
342 colour:1:octarine
339 color:0:octarine
343 color:0:octarine
340
344
341 Used to crash here
345 Used to crash here
342
346
343 $ hg grep -r 1 octarine
347 $ hg grep -r 1 octarine
344 colour:1:octarine
348 colour:1:octarine
345 $ cd ..
349 $ cd ..
346
350
347
351
348 Issue337: test that grep follows parent-child relationships instead
352 Issue337: test that grep follows parent-child relationships instead
349 of just using revision numbers.
353 of just using revision numbers.
350
354
351 $ hg init issue337
355 $ hg init issue337
352 $ cd issue337
356 $ cd issue337
353
357
354 $ echo white > color
358 $ echo white > color
355 $ hg commit -A -m "0 white"
359 $ hg commit -A -m "0 white"
356 adding color
360 adding color
357
361
358 $ echo red > color
362 $ echo red > color
359 $ hg commit -A -m "1 red"
363 $ hg commit -A -m "1 red"
360
364
361 $ hg update 0
365 $ hg update 0
362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 $ echo black > color
367 $ echo black > color
364 $ hg commit -A -m "2 black"
368 $ hg commit -A -m "2 black"
365 created new head
369 created new head
366
370
367 $ hg update --clean 1
371 $ hg update --clean 1
368 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 $ echo blue > color
373 $ echo blue > color
370 $ hg commit -A -m "3 blue"
374 $ hg commit -A -m "3 blue"
371
375
372 $ hg grep --all red
376 $ hg grep --all red
373 color:3:-:red
377 color:3:-:red
374 color:1:+:red
378 color:1:+:red
375
379
376 $ hg grep --diff red
380 $ hg grep --diff red
377 color:3:-:red
381 color:3:-:red
378 color:1:+:red
382 color:1:+:red
379
383
380 Issue3885: test that changing revision order does not alter the
384 Issue3885: test that changing revision order does not alter the
381 revisions printed, just their order.
385 revisions printed, just their order.
382
386
383 $ hg grep --all red -r "all()"
387 $ hg grep --all red -r "all()"
384 color:1:+:red
388 color:1:+:red
385 color:3:-:red
389 color:3:-:red
386
390
387 $ hg grep --all red -r "reverse(all())"
391 $ hg grep --all red -r "reverse(all())"
388 color:3:-:red
392 color:3:-:red
389 color:1:+:red
393 color:1:+:red
390
394
391 $ hg grep --diff red -r "all()"
395 $ hg grep --diff red -r "all()"
392 color:1:+:red
396 color:1:+:red
393 color:3:-:red
397 color:3:-:red
394
398
395 $ hg grep --diff red -r "reverse(all())"
399 $ hg grep --diff red -r "reverse(all())"
396 color:3:-:red
400 color:3:-:red
397 color:1:+:red
401 color:1:+:red
398
402
399 $ cd ..
403 $ cd ..
400
404
401 $ hg init a
405 $ hg init a
402 $ cd a
406 $ cd a
403 $ cp "$TESTDIR/binfile.bin" .
407 $ cp "$TESTDIR/binfile.bin" .
404 $ hg add binfile.bin
408 $ hg add binfile.bin
405 $ hg ci -m 'add binfile.bin'
409 $ hg ci -m 'add binfile.bin'
406 $ hg grep "MaCam" --all
410 $ hg grep "MaCam" --all
407 binfile.bin:0:+: Binary file matches
411 binfile.bin:0:+: Binary file matches
408
412
409 $ hg grep "MaCam" --diff
413 $ hg grep "MaCam" --diff
410 binfile.bin:0:+: Binary file matches
414 binfile.bin:0:+: Binary file matches
411
415
412 $ cd ..
416 $ cd ..
413
417
414 Test for showing working of allfiles flag
418 Test for showing working of allfiles flag
415
419
416 $ hg init sng
420 $ hg init sng
417 $ cd sng
421 $ cd sng
418 $ echo "unmod" >> um
422 $ echo "unmod" >> um
419 $ hg ci -A -m "adds unmod to um"
423 $ hg ci -A -m "adds unmod to um"
420 adding um
424 adding um
421 $ echo "something else" >> new
425 $ echo "something else" >> new
422 $ hg ci -A -m "second commit"
426 $ hg ci -A -m "second commit"
423 adding new
427 adding new
424 $ hg grep -r "." "unmod"
428 $ hg grep -r "." "unmod"
425 [1]
429 [1]
426 $ hg grep -r "." "unmod" --all-files
430 $ hg grep -r "." "unmod" --all-files
427 um:1:unmod
431 um:1:unmod
428
432
429 With --all-files, the working directory is searched by default
433 With --all-files, the working directory is searched by default
430
434
431 $ echo modified >> new
435 $ echo modified >> new
432 $ hg grep --all-files mod
436 $ hg grep --all-files mod
433 new:modified
437 new:modified
434 um:unmod
438 um:unmod
435
439
436 which can be overridden by -rREV
440 which can be overridden by -rREV
437
441
438 $ hg grep --all-files -r. mod
442 $ hg grep --all-files -r. mod
439 um:1:unmod
443 um:1:unmod
440
444
441 commands.all-files can be negated by --no-all-files
445 commands.all-files can be negated by --no-all-files
442
446
443 $ hg grep --config commands.grep.all-files=True mod
447 $ hg grep --config commands.grep.all-files=True mod
444 new:modified
448 new:modified
445 um:unmod
449 um:unmod
446 $ hg grep --config commands.grep.all-files=True --no-all-files mod
450 $ hg grep --config commands.grep.all-files=True --no-all-files mod
447 um:0:unmod
451 um:0:unmod
448
452
449 --diff --all-files makes no sense since --diff is the option to grep history
453 --diff --all-files makes no sense since --diff is the option to grep history
450
454
451 $ hg grep --diff --all-files um
455 $ hg grep --diff --all-files um
452 abort: --diff and --all-files are mutually exclusive
456 abort: --diff and --all-files are mutually exclusive
453 [255]
457 [255]
454
458
455 but --diff should precede the commands.grep.all-files option
459 but --diff should precede the commands.grep.all-files option
456
460
457 $ hg grep --config commands.grep.all-files=True --diff mod
461 $ hg grep --config commands.grep.all-files=True --diff mod
458 um:0:+:unmod
462 um:0:+:unmod
459
463
460 $ cd ..
464 $ cd ..
461
465
462 Fix_Wdir(): test that passing wdir() t -r flag does greps on the
466 Fix_Wdir(): test that passing wdir() t -r flag does greps on the
463 files modified in the working directory
467 files modified in the working directory
464
468
465 $ cd a
469 $ cd a
466 $ echo "abracadara" >> a
470 $ echo "abracadara" >> a
467 $ hg add a
471 $ hg add a
468 $ hg grep -r "wdir()" "abra"
472 $ hg grep -r "wdir()" "abra"
469 a:2147483647:abracadara
473 a:2147483647:abracadara
470
474
471 $ cd ..
475 $ cd ..
472
476
473 Change Default of grep by ui.tweakdefaults, that is, the files not in current
477 Change Default of grep by ui.tweakdefaults, that is, the files not in current
474 working directory should not be grepp-ed on
478 working directory should not be grepp-ed on
475
479
476 $ hg init ab
480 $ hg init ab
477 $ cd ab
481 $ cd ab
478 $ cat <<'EOF' >> .hg/hgrc
482 $ cat <<'EOF' >> .hg/hgrc
479 > [ui]
483 > [ui]
480 > tweakdefaults = True
484 > tweakdefaults = True
481 > EOF
485 > EOF
482 $ echo "some text">>file1
486 $ echo "some text">>file1
483 $ hg add file1
487 $ hg add file1
484 $ hg commit -m "adds file1"
488 $ hg commit -m "adds file1"
485 $ hg mv file1 file2
489 $ hg mv file1 file2
486
490
487 wdir revision is hidden by default:
491 wdir revision is hidden by default:
488
492
489 $ hg grep "some"
493 $ hg grep "some"
490 file2:some text
494 file2:some text
491
495
492 but it should be available in template dict:
496 but it should be available in template dict:
493
497
494 $ hg grep "some" -Tjson
498 $ hg grep "some" -Tjson
495 [
499 [
496 {
500 {
497 "date": [0, 0],
501 "date": [0, 0],
498 "lineno": 1,
502 "lineno": 1,
499 "node": "ffffffffffffffffffffffffffffffffffffffff",
503 "node": "ffffffffffffffffffffffffffffffffffffffff",
500 "path": "file2",
504 "path": "file2",
501 "rev": 2147483647,
505 "rev": 2147483647,
502 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
506 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
503 "user": "test"
507 "user": "test"
504 }
508 }
505 ]
509 ]
506
510
507 $ cd ..
511 $ cd ..
508
512
509 test -rMULTIREV with --all-files
513 test -rMULTIREV with --all-files
510
514
511 $ cd sng
515 $ cd sng
512 $ hg rm um
516 $ hg rm um
513 $ hg commit -m "deletes um"
517 $ hg commit -m "deletes um"
514 $ hg grep -r "0:2" "unmod" --all-files
518 $ hg grep -r "0:2" "unmod" --all-files
515 um:0:unmod
519 um:0:unmod
516 um:1:unmod
520 um:1:unmod
517 $ hg grep -r "0:2" "unmod" --all-files um
521 $ hg grep -r "0:2" "unmod" --all-files um
518 um:0:unmod
522 um:0:unmod
519 um:1:unmod
523 um:1:unmod
520 $ hg grep -r "0:2" "unmod" --all-files "glob:**/um" # Check that patterns also work
524 $ hg grep -r "0:2" "unmod" --all-files "glob:**/um" # Check that patterns also work
521 um:0:unmod
525 um:0:unmod
522 um:1:unmod
526 um:1:unmod
523 $ cd ..
527 $ cd ..
524
528
General Comments 0
You need to be logged in to leave comments. Login now