##// END OF EJS Templates
config: add support for defaultvalue of list of printable elements
Yuya Nishihara -
r43644:a71578ec stable
parent child Browse files
Show More
@@ -1,7810 +1,7814 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 .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 (
84 (
85 b'R',
85 b'R',
86 b'repository',
86 b'repository',
87 b'',
87 b'',
88 _(b'repository root directory or name of overlay bundle file'),
88 _(b'repository root directory or name of overlay bundle file'),
89 _(b'REPO'),
89 _(b'REPO'),
90 ),
90 ),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (
92 (
93 b'y',
93 b'y',
94 b'noninteractive',
94 b'noninteractive',
95 None,
95 None,
96 _(
96 _(
97 b'do not prompt, automatically pick the first choice for all prompts'
97 b'do not prompt, automatically pick the first choice for all prompts'
98 ),
98 ),
99 ),
99 ),
100 (b'q', b'quiet', None, _(b'suppress output')),
100 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
102 (
102 (
103 b'',
103 b'',
104 b'color',
104 b'color',
105 b'',
105 b'',
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # and should not be translated
107 # and should not be translated
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b'TYPE'),
109 _(b'TYPE'),
110 ),
110 ),
111 (
111 (
112 b'',
112 b'',
113 b'config',
113 b'config',
114 [],
114 [],
115 _(b'set/override config option (use \'section.name=value\')'),
115 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'CONFIG'),
116 _(b'CONFIG'),
117 ),
117 ),
118 (b'', b'debug', None, _(b'enable debugging output')),
118 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debugger', None, _(b'start debugger')),
119 (b'', b'debugger', None, _(b'start debugger')),
120 (
120 (
121 b'',
121 b'',
122 b'encoding',
122 b'encoding',
123 encoding.encoding,
123 encoding.encoding,
124 _(b'set the charset encoding'),
124 _(b'set the charset encoding'),
125 _(b'ENCODE'),
125 _(b'ENCODE'),
126 ),
126 ),
127 (
127 (
128 b'',
128 b'',
129 b'encodingmode',
129 b'encodingmode',
130 encoding.encodingmode,
130 encoding.encodingmode,
131 _(b'set the charset encoding mode'),
131 _(b'set the charset encoding mode'),
132 _(b'MODE'),
132 _(b'MODE'),
133 ),
133 ),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'time', None, _(b'time how long the command takes')),
135 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'profile', None, _(b'print command execution profile')),
136 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'version', None, _(b'output version information and exit')),
137 (b'', b'version', None, _(b'output version information and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (
140 (
141 b'',
141 b'',
142 b'pager',
142 b'pager',
143 b'auto',
143 b'auto',
144 _(b"when to paginate (boolean, always, auto, or never)"),
144 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b'TYPE'),
145 _(b'TYPE'),
146 ),
146 ),
147 ]
147 ]
148
148
149 dryrunopts = cmdutil.dryrunopts
149 dryrunopts = cmdutil.dryrunopts
150 remoteopts = cmdutil.remoteopts
150 remoteopts = cmdutil.remoteopts
151 walkopts = cmdutil.walkopts
151 walkopts = cmdutil.walkopts
152 commitopts = cmdutil.commitopts
152 commitopts = cmdutil.commitopts
153 commitopts2 = cmdutil.commitopts2
153 commitopts2 = cmdutil.commitopts2
154 commitopts3 = cmdutil.commitopts3
154 commitopts3 = cmdutil.commitopts3
155 formatteropts = cmdutil.formatteropts
155 formatteropts = cmdutil.formatteropts
156 templateopts = cmdutil.templateopts
156 templateopts = cmdutil.templateopts
157 logopts = cmdutil.logopts
157 logopts = cmdutil.logopts
158 diffopts = cmdutil.diffopts
158 diffopts = cmdutil.diffopts
159 diffwsopts = cmdutil.diffwsopts
159 diffwsopts = cmdutil.diffwsopts
160 diffopts2 = cmdutil.diffopts2
160 diffopts2 = cmdutil.diffopts2
161 mergetoolopts = cmdutil.mergetoolopts
161 mergetoolopts = cmdutil.mergetoolopts
162 similarityopts = cmdutil.similarityopts
162 similarityopts = cmdutil.similarityopts
163 subrepoopts = cmdutil.subrepoopts
163 subrepoopts = cmdutil.subrepoopts
164 debugrevlogopts = cmdutil.debugrevlogopts
164 debugrevlogopts = cmdutil.debugrevlogopts
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168
168
169 @command(
169 @command(
170 b'abort',
170 b'abort',
171 dryrunopts,
171 dryrunopts,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpbasic=True,
173 helpbasic=True,
174 )
174 )
175 def abort(ui, repo, **opts):
175 def abort(ui, repo, **opts):
176 """abort an unfinished operation (EXPERIMENTAL)
176 """abort an unfinished operation (EXPERIMENTAL)
177
177
178 Aborts a multistep operation like graft, histedit, rebase, merge,
178 Aborts a multistep operation like graft, histedit, rebase, merge,
179 and unshelve if they are in an unfinished state.
179 and unshelve if they are in an unfinished state.
180
180
181 use --dry-run/-n to dry run the command.
181 use --dry-run/-n to dry run the command.
182 """
182 """
183 dryrun = opts.get(r'dry_run')
183 dryrun = opts.get(r'dry_run')
184 abortstate = cmdutil.getunfinishedstate(repo)
184 abortstate = cmdutil.getunfinishedstate(repo)
185 if not abortstate:
185 if not abortstate:
186 raise error.Abort(_(b'no operation in progress'))
186 raise error.Abort(_(b'no operation in progress'))
187 if not abortstate.abortfunc:
187 if not abortstate.abortfunc:
188 raise error.Abort(
188 raise error.Abort(
189 (
189 (
190 _(b"%s in progress but does not support 'hg abort'")
190 _(b"%s in progress but does not support 'hg abort'")
191 % (abortstate._opname)
191 % (abortstate._opname)
192 ),
192 ),
193 hint=abortstate.hint(),
193 hint=abortstate.hint(),
194 )
194 )
195 if dryrun:
195 if dryrun:
196 ui.status(
196 ui.status(
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 )
198 )
199 return
199 return
200 return abortstate.abortfunc(ui, repo)
200 return abortstate.abortfunc(ui, repo)
201
201
202
202
203 @command(
203 @command(
204 b'add',
204 b'add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _(b'[OPTION]... [FILE]...'),
206 _(b'[OPTION]... [FILE]...'),
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpbasic=True,
208 helpbasic=True,
209 inferrepo=True,
209 inferrepo=True,
210 )
210 )
211 def add(ui, repo, *pats, **opts):
211 def add(ui, repo, *pats, **opts):
212 """add the specified files on the next commit
212 """add the specified files on the next commit
213
213
214 Schedule files to be version controlled and added to the
214 Schedule files to be version controlled and added to the
215 repository.
215 repository.
216
216
217 The files will be added to the repository at the next commit. To
217 The files will be added to the repository at the next commit. To
218 undo an add before that, see :hg:`forget`.
218 undo an add before that, see :hg:`forget`.
219
219
220 If no names are given, add all files to the repository (except
220 If no names are given, add all files to the repository (except
221 files matching ``.hgignore``).
221 files matching ``.hgignore``).
222
222
223 .. container:: verbose
223 .. container:: verbose
224
224
225 Examples:
225 Examples:
226
226
227 - New (unknown) files are added
227 - New (unknown) files are added
228 automatically by :hg:`add`::
228 automatically by :hg:`add`::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ? foo.c
233 ? foo.c
234 $ hg add
234 $ hg add
235 adding foo.c
235 adding foo.c
236 $ hg status
236 $ hg status
237 A foo.c
237 A foo.c
238
238
239 - Specific files to be added can be specified::
239 - Specific files to be added can be specified::
240
240
241 $ ls
241 $ ls
242 bar.c foo.c
242 bar.c foo.c
243 $ hg status
243 $ hg status
244 ? bar.c
244 ? bar.c
245 ? foo.c
245 ? foo.c
246 $ hg add bar.c
246 $ hg add bar.c
247 $ hg status
247 $ hg status
248 A bar.c
248 A bar.c
249 ? foo.c
249 ? foo.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253
253
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259
259
260 @command(
260 @command(
261 b'addremove',
261 b'addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _(b'[OPTION]... [FILE]...'),
263 _(b'[OPTION]... [FILE]...'),
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 inferrepo=True,
265 inferrepo=True,
266 )
266 )
267 def addremove(ui, repo, *pats, **opts):
267 def addremove(ui, repo, *pats, **opts):
268 """add all new files, delete all missing files
268 """add all new files, delete all missing files
269
269
270 Add all new files and remove all missing files from the
270 Add all new files and remove all missing files from the
271 repository.
271 repository.
272
272
273 Unless names are given, new files are ignored if they match any of
273 Unless names are given, new files are ignored if they match any of
274 the patterns in ``.hgignore``. As with add, these changes take
274 the patterns in ``.hgignore``. As with add, these changes take
275 effect at the next commit.
275 effect at the next commit.
276
276
277 Use the -s/--similarity option to detect renamed files. This
277 Use the -s/--similarity option to detect renamed files. This
278 option takes a percentage between 0 (disabled) and 100 (files must
278 option takes a percentage between 0 (disabled) and 100 (files must
279 be identical) as its parameter. With a parameter greater than 0,
279 be identical) as its parameter. With a parameter greater than 0,
280 this compares every removed file with every added file and records
280 this compares every removed file with every added file and records
281 those similar enough as renames. Detecting renamed files this way
281 those similar enough as renames. Detecting renamed files this way
282 can be expensive. After using this option, :hg:`status -C` can be
282 can be expensive. After using this option, :hg:`status -C` can be
283 used to check which files were identified as moved or renamed. If
283 used to check which files were identified as moved or renamed. If
284 not specified, -s/--similarity defaults to 100 and only renames of
284 not specified, -s/--similarity defaults to 100 and only renames of
285 identical files are detected.
285 identical files are detected.
286
286
287 .. container:: verbose
287 .. container:: verbose
288
288
289 Examples:
289 Examples:
290
290
291 - A number of files (bar.c and foo.c) are new,
291 - A number of files (bar.c and foo.c) are new,
292 while foobar.c has been removed (without using :hg:`remove`)
292 while foobar.c has been removed (without using :hg:`remove`)
293 from the repository::
293 from the repository::
294
294
295 $ ls
295 $ ls
296 bar.c foo.c
296 bar.c foo.c
297 $ hg status
297 $ hg status
298 ! foobar.c
298 ! foobar.c
299 ? bar.c
299 ? bar.c
300 ? foo.c
300 ? foo.c
301 $ hg addremove
301 $ hg addremove
302 adding bar.c
302 adding bar.c
303 adding foo.c
303 adding foo.c
304 removing foobar.c
304 removing foobar.c
305 $ hg status
305 $ hg status
306 A bar.c
306 A bar.c
307 A foo.c
307 A foo.c
308 R foobar.c
308 R foobar.c
309
309
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 Afterwards, it was edited slightly::
311 Afterwards, it was edited slightly::
312
312
313 $ ls
313 $ ls
314 foo.c
314 foo.c
315 $ hg status
315 $ hg status
316 ! foobar.c
316 ! foobar.c
317 ? foo.c
317 ? foo.c
318 $ hg addremove --similarity 90
318 $ hg addremove --similarity 90
319 removing foobar.c
319 removing foobar.c
320 adding foo.c
320 adding foo.c
321 recording removal of foobar.c as rename to foo.c (94% similar)
321 recording removal of foobar.c as rename to foo.c (94% similar)
322 $ hg status -C
322 $ hg status -C
323 A foo.c
323 A foo.c
324 foobar.c
324 foobar.c
325 R foobar.c
325 R foobar.c
326
326
327 Returns 0 if all files are successfully added.
327 Returns 0 if all files are successfully added.
328 """
328 """
329 opts = pycompat.byteskwargs(opts)
329 opts = pycompat.byteskwargs(opts)
330 if not opts.get(b'similarity'):
330 if not opts.get(b'similarity'):
331 opts[b'similarity'] = b'100'
331 opts[b'similarity'] = b'100'
332 matcher = scmutil.match(repo[None], pats, opts)
332 matcher = scmutil.match(repo[None], pats, opts)
333 relative = scmutil.anypats(pats, opts)
333 relative = scmutil.anypats(pats, opts)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336
336
337
337
338 @command(
338 @command(
339 b'annotate|blame',
339 b'annotate|blame',
340 [
340 [
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (
342 (
343 b'',
343 b'',
344 b'follow',
344 b'follow',
345 None,
345 None,
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 ),
347 ),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'a', b'text', None, _(b'treat all files as text')),
349 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'f', b'file', None, _(b'list the filename')),
351 (b'f', b'file', None, _(b'list the filename')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
355 (
355 (
356 b'l',
356 b'l',
357 b'line-number',
357 b'line-number',
358 None,
358 None,
359 _(b'show line number at the first appearance'),
359 _(b'show line number at the first appearance'),
360 ),
360 ),
361 (
361 (
362 b'',
362 b'',
363 b'skip',
363 b'skip',
364 [],
364 [],
365 _(b'revision to not display (EXPERIMENTAL)'),
365 _(b'revision to not display (EXPERIMENTAL)'),
366 _(b'REV'),
366 _(b'REV'),
367 ),
367 ),
368 ]
368 ]
369 + diffwsopts
369 + diffwsopts
370 + walkopts
370 + walkopts
371 + formatteropts,
371 + formatteropts,
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpbasic=True,
374 helpbasic=True,
375 inferrepo=True,
375 inferrepo=True,
376 )
376 )
377 def annotate(ui, repo, *pats, **opts):
377 def annotate(ui, repo, *pats, **opts):
378 """show changeset information by line for each file
378 """show changeset information by line for each file
379
379
380 List changes in files, showing the revision id responsible for
380 List changes in files, showing the revision id responsible for
381 each line.
381 each line.
382
382
383 This command is useful for discovering when a change was made and
383 This command is useful for discovering when a change was made and
384 by whom.
384 by whom.
385
385
386 If you include --file, --user, or --date, the revision number is
386 If you include --file, --user, or --date, the revision number is
387 suppressed unless you also include --number.
387 suppressed unless you also include --number.
388
388
389 Without the -a/--text option, annotate will avoid processing files
389 Without the -a/--text option, annotate will avoid processing files
390 it detects as binary. With -a, annotate will annotate the file
390 it detects as binary. With -a, annotate will annotate the file
391 anyway, although the results will probably be neither useful
391 anyway, although the results will probably be neither useful
392 nor desirable.
392 nor desirable.
393
393
394 .. container:: verbose
394 .. container:: verbose
395
395
396 Template:
396 Template:
397
397
398 The following keywords are supported in addition to the common template
398 The following keywords are supported in addition to the common template
399 keywords and functions. See also :hg:`help templates`.
399 keywords and functions. See also :hg:`help templates`.
400
400
401 :lines: List of lines with annotation data.
401 :lines: List of lines with annotation data.
402 :path: String. Repository-absolute path of the specified file.
402 :path: String. Repository-absolute path of the specified file.
403
403
404 And each entry of ``{lines}`` provides the following sub-keywords in
404 And each entry of ``{lines}`` provides the following sub-keywords in
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406
406
407 :line: String. Line content.
407 :line: String. Line content.
408 :lineno: Integer. Line number at that revision.
408 :lineno: Integer. Line number at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
410
410
411 See :hg:`help templates.operators` for the list expansion syntax.
411 See :hg:`help templates.operators` for the list expansion syntax.
412
412
413 Returns 0 on success.
413 Returns 0 on success.
414 """
414 """
415 opts = pycompat.byteskwargs(opts)
415 opts = pycompat.byteskwargs(opts)
416 if not pats:
416 if not pats:
417 raise error.Abort(_(b'at least one filename or pattern is required'))
417 raise error.Abort(_(b'at least one filename or pattern is required'))
418
418
419 if opts.get(b'follow'):
419 if opts.get(b'follow'):
420 # --follow is deprecated and now just an alias for -f/--file
420 # --follow is deprecated and now just an alias for -f/--file
421 # to mimic the behavior of Mercurial before version 1.5
421 # to mimic the behavior of Mercurial before version 1.5
422 opts[b'file'] = True
422 opts[b'file'] = True
423
423
424 if (
424 if (
425 not opts.get(b'user')
425 not opts.get(b'user')
426 and not opts.get(b'changeset')
426 and not opts.get(b'changeset')
427 and not opts.get(b'date')
427 and not opts.get(b'date')
428 and not opts.get(b'file')
428 and not opts.get(b'file')
429 ):
429 ):
430 opts[b'number'] = True
430 opts[b'number'] = True
431
431
432 linenumber = opts.get(b'line_number') is not None
432 linenumber = opts.get(b'line_number') is not None
433 if (
433 if (
434 linenumber
434 linenumber
435 and (not opts.get(b'changeset'))
435 and (not opts.get(b'changeset'))
436 and (not opts.get(b'number'))
436 and (not opts.get(b'number'))
437 ):
437 ):
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439
439
440 rev = opts.get(b'rev')
440 rev = opts.get(b'rev')
441 if rev:
441 if rev:
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 ctx = scmutil.revsingle(repo, rev)
443 ctx = scmutil.revsingle(repo, rev)
444
444
445 ui.pager(b'annotate')
445 ui.pager(b'annotate')
446 rootfm = ui.formatter(b'annotate', opts)
446 rootfm = ui.formatter(b'annotate', opts)
447 if ui.debugflag:
447 if ui.debugflag:
448 shorthex = pycompat.identity
448 shorthex = pycompat.identity
449 else:
449 else:
450
450
451 def shorthex(h):
451 def shorthex(h):
452 return h[:12]
452 return h[:12]
453
453
454 if ui.quiet:
454 if ui.quiet:
455 datefunc = dateutil.shortdate
455 datefunc = dateutil.shortdate
456 else:
456 else:
457 datefunc = dateutil.datestr
457 datefunc = dateutil.datestr
458 if ctx.rev() is None:
458 if ctx.rev() is None:
459 if opts.get(b'changeset'):
459 if opts.get(b'changeset'):
460 # omit "+" suffix which is appended to node hex
460 # omit "+" suffix which is appended to node hex
461 def formatrev(rev):
461 def formatrev(rev):
462 if rev == wdirrev:
462 if rev == wdirrev:
463 return b'%d' % ctx.p1().rev()
463 return b'%d' % ctx.p1().rev()
464 else:
464 else:
465 return b'%d' % rev
465 return b'%d' % rev
466
466
467 else:
467 else:
468
468
469 def formatrev(rev):
469 def formatrev(rev):
470 if rev == wdirrev:
470 if rev == wdirrev:
471 return b'%d+' % ctx.p1().rev()
471 return b'%d+' % ctx.p1().rev()
472 else:
472 else:
473 return b'%d ' % rev
473 return b'%d ' % rev
474
474
475 def formathex(h):
475 def formathex(h):
476 if h == wdirhex:
476 if h == wdirhex:
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 else:
478 else:
479 return b'%s ' % shorthex(h)
479 return b'%s ' % shorthex(h)
480
480
481 else:
481 else:
482 formatrev = b'%d'.__mod__
482 formatrev = b'%d'.__mod__
483 formathex = shorthex
483 formathex = shorthex
484
484
485 opmap = [
485 opmap = [
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 ]
492 ]
493 opnamemap = {
493 opnamemap = {
494 b'rev': b'number',
494 b'rev': b'number',
495 b'node': b'changeset',
495 b'node': b'changeset',
496 b'path': b'file',
496 b'path': b'file',
497 b'lineno': b'line_number',
497 b'lineno': b'line_number',
498 }
498 }
499
499
500 if rootfm.isplain():
500 if rootfm.isplain():
501
501
502 def makefunc(get, fmt):
502 def makefunc(get, fmt):
503 return lambda x: fmt(get(x))
503 return lambda x: fmt(get(x))
504
504
505 else:
505 else:
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return get
508 return get
509
509
510 datahint = rootfm.datahint()
510 datahint = rootfm.datahint()
511 funcmap = [
511 funcmap = [
512 (makefunc(get, fmt), sep)
512 (makefunc(get, fmt), sep)
513 for fn, sep, get, fmt in opmap
513 for fn, sep, get, fmt in opmap
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 ]
515 ]
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 fields = b' '.join(
517 fields = b' '.join(
518 fn
518 fn
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 )
521 )
522
522
523 def bad(x, y):
523 def bad(x, y):
524 raise error.Abort(b"%s: %s" % (x, y))
524 raise error.Abort(b"%s: %s" % (x, y))
525
525
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
527
527
528 follow = not opts.get(b'no_follow')
528 follow = not opts.get(b'no_follow')
529 diffopts = patch.difffeatureopts(
529 diffopts = patch.difffeatureopts(
530 ui, opts, section=b'annotate', whitespace=True
530 ui, opts, section=b'annotate', whitespace=True
531 )
531 )
532 skiprevs = opts.get(b'skip')
532 skiprevs = opts.get(b'skip')
533 if skiprevs:
533 if skiprevs:
534 skiprevs = scmutil.revrange(repo, skiprevs)
534 skiprevs = scmutil.revrange(repo, skiprevs)
535
535
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fctx = ctx[abs]
538 fctx = ctx[abs]
539 rootfm.startitem()
539 rootfm.startitem()
540 rootfm.data(path=abs)
540 rootfm.data(path=abs)
541 if not opts.get(b'text') and fctx.isbinary():
541 if not opts.get(b'text') and fctx.isbinary():
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 continue
543 continue
544
544
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 lines = fctx.annotate(
546 lines = fctx.annotate(
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 )
548 )
549 if not lines:
549 if not lines:
550 fm.end()
550 fm.end()
551 continue
551 continue
552 formats = []
552 formats = []
553 pieces = []
553 pieces = []
554
554
555 for f, sep in funcmap:
555 for f, sep in funcmap:
556 l = [f(n) for n in lines]
556 l = [f(n) for n in lines]
557 if fm.isplain():
557 if fm.isplain():
558 sizes = [encoding.colwidth(x) for x in l]
558 sizes = [encoding.colwidth(x) for x in l]
559 ml = max(sizes)
559 ml = max(sizes)
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 else:
561 else:
562 formats.append([b'%s' for x in l])
562 formats.append([b'%s' for x in l])
563 pieces.append(l)
563 pieces.append(l)
564
564
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 fm.startitem()
566 fm.startitem()
567 fm.context(fctx=n.fctx)
567 fm.context(fctx=n.fctx)
568 fm.write(fields, b"".join(f), *p)
568 fm.write(fields, b"".join(f), *p)
569 if n.skip:
569 if n.skip:
570 fmt = b"* %s"
570 fmt = b"* %s"
571 else:
571 else:
572 fmt = b": %s"
572 fmt = b": %s"
573 fm.write(b'line', fmt, n.text)
573 fm.write(b'line', fmt, n.text)
574
574
575 if not lines[-1].text.endswith(b'\n'):
575 if not lines[-1].text.endswith(b'\n'):
576 fm.plain(b'\n')
576 fm.plain(b'\n')
577 fm.end()
577 fm.end()
578
578
579 rootfm.end()
579 rootfm.end()
580
580
581
581
582 @command(
582 @command(
583 b'archive',
583 b'archive',
584 [
584 [
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (
586 (
587 b'p',
587 b'p',
588 b'prefix',
588 b'prefix',
589 b'',
589 b'',
590 _(b'directory prefix for files in archive'),
590 _(b'directory prefix for files in archive'),
591 _(b'PREFIX'),
591 _(b'PREFIX'),
592 ),
592 ),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 ]
595 ]
596 + subrepoopts
596 + subrepoopts
597 + walkopts,
597 + walkopts,
598 _(b'[OPTION]... DEST'),
598 _(b'[OPTION]... DEST'),
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 )
600 )
601 def archive(ui, repo, dest, **opts):
601 def archive(ui, repo, dest, **opts):
602 '''create an unversioned archive of a repository revision
602 '''create an unversioned archive of a repository revision
603
603
604 By default, the revision used is the parent of the working
604 By default, the revision used is the parent of the working
605 directory; use -r/--rev to specify a different revision.
605 directory; use -r/--rev to specify a different revision.
606
606
607 The archive type is automatically detected based on file
607 The archive type is automatically detected based on file
608 extension (to override, use -t/--type).
608 extension (to override, use -t/--type).
609
609
610 .. container:: verbose
610 .. container:: verbose
611
611
612 Examples:
612 Examples:
613
613
614 - create a zip file containing the 1.0 release::
614 - create a zip file containing the 1.0 release::
615
615
616 hg archive -r 1.0 project-1.0.zip
616 hg archive -r 1.0 project-1.0.zip
617
617
618 - create a tarball excluding .hg files::
618 - create a tarball excluding .hg files::
619
619
620 hg archive project.tar.gz -X ".hg*"
620 hg archive project.tar.gz -X ".hg*"
621
621
622 Valid types are:
622 Valid types are:
623
623
624 :``files``: a directory full of files (default)
624 :``files``: a directory full of files (default)
625 :``tar``: tar archive, uncompressed
625 :``tar``: tar archive, uncompressed
626 :``tbz2``: tar archive, compressed using bzip2
626 :``tbz2``: tar archive, compressed using bzip2
627 :``tgz``: tar archive, compressed using gzip
627 :``tgz``: tar archive, compressed using gzip
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``uzip``: zip archive, uncompressed
629 :``uzip``: zip archive, uncompressed
630 :``zip``: zip archive, compressed using deflate
630 :``zip``: zip archive, compressed using deflate
631
631
632 The exact name of the destination archive or directory is given
632 The exact name of the destination archive or directory is given
633 using a format string; see :hg:`help export` for details.
633 using a format string; see :hg:`help export` for details.
634
634
635 Each member added to an archive file has a directory prefix
635 Each member added to an archive file has a directory prefix
636 prepended. Use -p/--prefix to specify a format string for the
636 prepended. Use -p/--prefix to specify a format string for the
637 prefix. The default is the basename of the archive, with suffixes
637 prefix. The default is the basename of the archive, with suffixes
638 removed.
638 removed.
639
639
640 Returns 0 on success.
640 Returns 0 on success.
641 '''
641 '''
642
642
643 opts = pycompat.byteskwargs(opts)
643 opts = pycompat.byteskwargs(opts)
644 rev = opts.get(b'rev')
644 rev = opts.get(b'rev')
645 if rev:
645 if rev:
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
648 if not ctx:
648 if not ctx:
649 raise error.Abort(_(b'no working directory: please specify a revision'))
649 raise error.Abort(_(b'no working directory: please specify a revision'))
650 node = ctx.node()
650 node = ctx.node()
651 dest = cmdutil.makefilename(ctx, dest)
651 dest = cmdutil.makefilename(ctx, dest)
652 if os.path.realpath(dest) == repo.root:
652 if os.path.realpath(dest) == repo.root:
653 raise error.Abort(_(b'repository root cannot be destination'))
653 raise error.Abort(_(b'repository root cannot be destination'))
654
654
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 prefix = opts.get(b'prefix')
656 prefix = opts.get(b'prefix')
657
657
658 if dest == b'-':
658 if dest == b'-':
659 if kind == b'files':
659 if kind == b'files':
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 dest = cmdutil.makefileobj(ctx, dest)
661 dest = cmdutil.makefileobj(ctx, dest)
662 if not prefix:
662 if not prefix:
663 prefix = os.path.basename(repo.root) + b'-%h'
663 prefix = os.path.basename(repo.root) + b'-%h'
664
664
665 prefix = cmdutil.makefilename(ctx, prefix)
665 prefix = cmdutil.makefilename(ctx, prefix)
666 match = scmutil.match(ctx, [], opts)
666 match = scmutil.match(ctx, [], opts)
667 archival.archive(
667 archival.archive(
668 repo,
668 repo,
669 dest,
669 dest,
670 node,
670 node,
671 kind,
671 kind,
672 not opts.get(b'no_decode'),
672 not opts.get(b'no_decode'),
673 match,
673 match,
674 prefix,
674 prefix,
675 subrepos=opts.get(b'subrepos'),
675 subrepos=opts.get(b'subrepos'),
676 )
676 )
677
677
678
678
679 @command(
679 @command(
680 b'backout',
680 b'backout',
681 [
681 [
682 (
682 (
683 b'',
683 b'',
684 b'merge',
684 b'merge',
685 None,
685 None,
686 _(b'merge with old dirstate parent after backout'),
686 _(b'merge with old dirstate parent after backout'),
687 ),
687 ),
688 (
688 (
689 b'',
689 b'',
690 b'commit',
690 b'commit',
691 None,
691 None,
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 ),
693 ),
694 (b'', b'no-commit', None, _(b'do not commit')),
694 (b'', b'no-commit', None, _(b'do not commit')),
695 (
695 (
696 b'',
696 b'',
697 b'parent',
697 b'parent',
698 b'',
698 b'',
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'REV'),
700 _(b'REV'),
701 ),
701 ),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 ]
704 ]
705 + mergetoolopts
705 + mergetoolopts
706 + walkopts
706 + walkopts
707 + commitopts
707 + commitopts
708 + commitopts2,
708 + commitopts2,
709 _(b'[OPTION]... [-r] REV'),
709 _(b'[OPTION]... [-r] REV'),
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 )
711 )
712 def backout(ui, repo, node=None, rev=None, **opts):
712 def backout(ui, repo, node=None, rev=None, **opts):
713 '''reverse effect of earlier changeset
713 '''reverse effect of earlier changeset
714
714
715 Prepare a new changeset with the effect of REV undone in the
715 Prepare a new changeset with the effect of REV undone in the
716 current working directory. If no conflicts were encountered,
716 current working directory. If no conflicts were encountered,
717 it will be committed immediately.
717 it will be committed immediately.
718
718
719 If REV is the parent of the working directory, then this new changeset
719 If REV is the parent of the working directory, then this new changeset
720 is committed automatically (unless --no-commit is specified).
720 is committed automatically (unless --no-commit is specified).
721
721
722 .. note::
722 .. note::
723
723
724 :hg:`backout` cannot be used to fix either an unwanted or
724 :hg:`backout` cannot be used to fix either an unwanted or
725 incorrect merge.
725 incorrect merge.
726
726
727 .. container:: verbose
727 .. container:: verbose
728
728
729 Examples:
729 Examples:
730
730
731 - Reverse the effect of the parent of the working directory.
731 - Reverse the effect of the parent of the working directory.
732 This backout will be committed immediately::
732 This backout will be committed immediately::
733
733
734 hg backout -r .
734 hg backout -r .
735
735
736 - Reverse the effect of previous bad revision 23::
736 - Reverse the effect of previous bad revision 23::
737
737
738 hg backout -r 23
738 hg backout -r 23
739
739
740 - Reverse the effect of previous bad revision 23 and
740 - Reverse the effect of previous bad revision 23 and
741 leave changes uncommitted::
741 leave changes uncommitted::
742
742
743 hg backout -r 23 --no-commit
743 hg backout -r 23 --no-commit
744 hg commit -m "Backout revision 23"
744 hg commit -m "Backout revision 23"
745
745
746 By default, the pending changeset will have one parent,
746 By default, the pending changeset will have one parent,
747 maintaining a linear history. With --merge, the pending
747 maintaining a linear history. With --merge, the pending
748 changeset will instead have two parents: the old parent of the
748 changeset will instead have two parents: the old parent of the
749 working directory and a new child of REV that simply undoes REV.
749 working directory and a new child of REV that simply undoes REV.
750
750
751 Before version 1.7, the behavior without --merge was equivalent
751 Before version 1.7, the behavior without --merge was equivalent
752 to specifying --merge followed by :hg:`update --clean .` to
752 to specifying --merge followed by :hg:`update --clean .` to
753 cancel the merge and leave the child of REV as a head to be
753 cancel the merge and leave the child of REV as a head to be
754 merged separately.
754 merged separately.
755
755
756 See :hg:`help dates` for a list of formats valid for -d/--date.
756 See :hg:`help dates` for a list of formats valid for -d/--date.
757
757
758 See :hg:`help revert` for a way to restore files to the state
758 See :hg:`help revert` for a way to restore files to the state
759 of another revision.
759 of another revision.
760
760
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 files.
762 files.
763 '''
763 '''
764 with repo.wlock(), repo.lock():
764 with repo.wlock(), repo.lock():
765 return _dobackout(ui, repo, node, rev, **opts)
765 return _dobackout(ui, repo, node, rev, **opts)
766
766
767
767
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
770 if opts.get(b'commit') and opts.get(b'no_commit'):
770 if opts.get(b'commit') and opts.get(b'no_commit'):
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 if opts.get(b'merge') and opts.get(b'no_commit'):
772 if opts.get(b'merge') and opts.get(b'no_commit'):
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774
774
775 if rev and node:
775 if rev and node:
776 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
777
777
778 if not rev:
778 if not rev:
779 rev = node
779 rev = node
780
780
781 if not rev:
781 if not rev:
782 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
783
783
784 date = opts.get(b'date')
784 date = opts.get(b'date')
785 if date:
785 if date:
786 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
787
787
788 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
789 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
790 node = scmutil.revsingle(repo, rev).node()
790 node = scmutil.revsingle(repo, rev).node()
791
791
792 op1, op2 = repo.dirstate.parents()
792 op1, op2 = repo.dirstate.parents()
793 if not repo.changelog.isancestor(node, op1):
793 if not repo.changelog.isancestor(node, op1):
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795
795
796 p1, p2 = repo.changelog.parents(node)
796 p1, p2 = repo.changelog.parents(node)
797 if p1 == nullid:
797 if p1 == nullid:
798 raise error.Abort(_(b'cannot backout a change with no parents'))
798 raise error.Abort(_(b'cannot backout a change with no parents'))
799 if p2 != nullid:
799 if p2 != nullid:
800 if not opts.get(b'parent'):
800 if not opts.get(b'parent'):
801 raise error.Abort(_(b'cannot backout a merge changeset'))
801 raise error.Abort(_(b'cannot backout a merge changeset'))
802 p = repo.lookup(opts[b'parent'])
802 p = repo.lookup(opts[b'parent'])
803 if p not in (p1, p2):
803 if p not in (p1, p2):
804 raise error.Abort(
804 raise error.Abort(
805 _(b'%s is not a parent of %s') % (short(p), short(node))
805 _(b'%s is not a parent of %s') % (short(p), short(node))
806 )
806 )
807 parent = p
807 parent = p
808 else:
808 else:
809 if opts.get(b'parent'):
809 if opts.get(b'parent'):
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 parent = p1
811 parent = p1
812
812
813 # the backout should appear on the same branch
813 # the backout should appear on the same branch
814 branch = repo.dirstate.branch()
814 branch = repo.dirstate.branch()
815 bheads = repo.branchheads(branch)
815 bheads = repo.branchheads(branch)
816 rctx = scmutil.revsingle(repo, hex(parent))
816 rctx = scmutil.revsingle(repo, hex(parent))
817 if not opts.get(b'merge') and op1 != node:
817 if not opts.get(b'merge') and op1 != node:
818 with dirstateguard.dirstateguard(repo, b'backout'):
818 with dirstateguard.dirstateguard(repo, b'backout'):
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 with ui.configoverride(overrides, b'backout'):
820 with ui.configoverride(overrides, b'backout'):
821 stats = mergemod.update(
821 stats = mergemod.update(
822 repo,
822 repo,
823 parent,
823 parent,
824 branchmerge=True,
824 branchmerge=True,
825 force=True,
825 force=True,
826 ancestor=node,
826 ancestor=node,
827 mergeancestor=False,
827 mergeancestor=False,
828 )
828 )
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 if not newnode:
860 if not newnode:
861 ui.status(_(b"nothing changed\n"))
861 ui.status(_(b"nothing changed\n"))
862 return 1
862 return 1
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
864
864
865 def nice(node):
865 def nice(node):
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867
867
868 ui.status(
868 ui.status(
869 _(b'changeset %s backs out changeset %s\n')
869 _(b'changeset %s backs out changeset %s\n')
870 % (nice(repo.changelog.tip()), nice(node))
870 % (nice(repo.changelog.tip()), nice(node))
871 )
871 )
872 if opts.get(b'merge') and op1 != node:
872 if opts.get(b'merge') and op1 != node:
873 hg.clean(repo, op1, show_stats=False)
873 hg.clean(repo, op1, show_stats=False)
874 ui.status(
874 ui.status(
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 )
876 )
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 with ui.configoverride(overrides, b'backout'):
878 with ui.configoverride(overrides, b'backout'):
879 return hg.merge(repo, hex(repo.changelog.tip()))
879 return hg.merge(repo, hex(repo.changelog.tip()))
880 return 0
880 return 0
881
881
882
882
883 @command(
883 @command(
884 b'bisect',
884 b'bisect',
885 [
885 [
886 (b'r', b'reset', False, _(b'reset bisect state')),
886 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'g', b'good', False, _(b'mark changeset good')),
887 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (
891 (
892 b'c',
892 b'c',
893 b'command',
893 b'command',
894 b'',
894 b'',
895 _(b'use command to check changeset state'),
895 _(b'use command to check changeset state'),
896 _(b'CMD'),
896 _(b'CMD'),
897 ),
897 ),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
899 ],
899 ],
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 )
902 )
903 def bisect(
903 def bisect(
904 ui,
904 ui,
905 repo,
905 repo,
906 rev=None,
906 rev=None,
907 extra=None,
907 extra=None,
908 command=None,
908 command=None,
909 reset=None,
909 reset=None,
910 good=None,
910 good=None,
911 bad=None,
911 bad=None,
912 skip=None,
912 skip=None,
913 extend=None,
913 extend=None,
914 noupdate=None,
914 noupdate=None,
915 ):
915 ):
916 """subdivision search of changesets
916 """subdivision search of changesets
917
917
918 This command helps to find changesets which introduce problems. To
918 This command helps to find changesets which introduce problems. To
919 use, mark the earliest changeset you know exhibits the problem as
919 use, mark the earliest changeset you know exhibits the problem as
920 bad, then mark the latest changeset which is free from the problem
920 bad, then mark the latest changeset which is free from the problem
921 as good. Bisect will update your working directory to a revision
921 as good. Bisect will update your working directory to a revision
922 for testing (unless the -U/--noupdate option is specified). Once
922 for testing (unless the -U/--noupdate option is specified). Once
923 you have performed tests, mark the working directory as good or
923 you have performed tests, mark the working directory as good or
924 bad, and bisect will either update to another candidate changeset
924 bad, and bisect will either update to another candidate changeset
925 or announce that it has found the bad revision.
925 or announce that it has found the bad revision.
926
926
927 As a shortcut, you can also use the revision argument to mark a
927 As a shortcut, you can also use the revision argument to mark a
928 revision as good or bad without checking it out first.
928 revision as good or bad without checking it out first.
929
929
930 If you supply a command, it will be used for automatic bisection.
930 If you supply a command, it will be used for automatic bisection.
931 The environment variable HG_NODE will contain the ID of the
931 The environment variable HG_NODE will contain the ID of the
932 changeset being tested. The exit status of the command will be
932 changeset being tested. The exit status of the command will be
933 used to mark revisions as good or bad: status 0 means good, 125
933 used to mark revisions as good or bad: status 0 means good, 125
934 means to skip the revision, 127 (command not found) will abort the
934 means to skip the revision, 127 (command not found) will abort the
935 bisection, and any other non-zero exit status means the revision
935 bisection, and any other non-zero exit status means the revision
936 is bad.
936 is bad.
937
937
938 .. container:: verbose
938 .. container:: verbose
939
939
940 Some examples:
940 Some examples:
941
941
942 - start a bisection with known bad revision 34, and good revision 12::
942 - start a bisection with known bad revision 34, and good revision 12::
943
943
944 hg bisect --bad 34
944 hg bisect --bad 34
945 hg bisect --good 12
945 hg bisect --good 12
946
946
947 - advance the current bisection by marking current revision as good or
947 - advance the current bisection by marking current revision as good or
948 bad::
948 bad::
949
949
950 hg bisect --good
950 hg bisect --good
951 hg bisect --bad
951 hg bisect --bad
952
952
953 - mark the current revision, or a known revision, to be skipped (e.g. if
953 - mark the current revision, or a known revision, to be skipped (e.g. if
954 that revision is not usable because of another issue)::
954 that revision is not usable because of another issue)::
955
955
956 hg bisect --skip
956 hg bisect --skip
957 hg bisect --skip 23
957 hg bisect --skip 23
958
958
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960
960
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962
962
963 - forget the current bisection::
963 - forget the current bisection::
964
964
965 hg bisect --reset
965 hg bisect --reset
966
966
967 - use 'make && make tests' to automatically find the first broken
967 - use 'make && make tests' to automatically find the first broken
968 revision::
968 revision::
969
969
970 hg bisect --reset
970 hg bisect --reset
971 hg bisect --bad 34
971 hg bisect --bad 34
972 hg bisect --good 12
972 hg bisect --good 12
973 hg bisect --command "make && make tests"
973 hg bisect --command "make && make tests"
974
974
975 - see all changesets whose states are already known in the current
975 - see all changesets whose states are already known in the current
976 bisection::
976 bisection::
977
977
978 hg log -r "bisect(pruned)"
978 hg log -r "bisect(pruned)"
979
979
980 - see the changeset currently being bisected (especially useful
980 - see the changeset currently being bisected (especially useful
981 if running with -U/--noupdate)::
981 if running with -U/--noupdate)::
982
982
983 hg log -r "bisect(current)"
983 hg log -r "bisect(current)"
984
984
985 - see all changesets that took part in the current bisection::
985 - see all changesets that took part in the current bisection::
986
986
987 hg log -r "bisect(range)"
987 hg log -r "bisect(range)"
988
988
989 - you can even get a nice graph::
989 - you can even get a nice graph::
990
990
991 hg log --graph -r "bisect(range)"
991 hg log --graph -r "bisect(range)"
992
992
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994
994
995 Returns 0 on success.
995 Returns 0 on success.
996 """
996 """
997 # backward compatibility
997 # backward compatibility
998 if rev in b"good bad reset init".split():
998 if rev in b"good bad reset init".split():
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 cmd, rev, extra = rev, extra, None
1000 cmd, rev, extra = rev, extra, None
1001 if cmd == b"good":
1001 if cmd == b"good":
1002 good = True
1002 good = True
1003 elif cmd == b"bad":
1003 elif cmd == b"bad":
1004 bad = True
1004 bad = True
1005 else:
1005 else:
1006 reset = True
1006 reset = True
1007 elif extra:
1007 elif extra:
1008 raise error.Abort(_(b'incompatible arguments'))
1008 raise error.Abort(_(b'incompatible arguments'))
1009
1009
1010 incompatibles = {
1010 incompatibles = {
1011 b'--bad': bad,
1011 b'--bad': bad,
1012 b'--command': bool(command),
1012 b'--command': bool(command),
1013 b'--extend': extend,
1013 b'--extend': extend,
1014 b'--good': good,
1014 b'--good': good,
1015 b'--reset': reset,
1015 b'--reset': reset,
1016 b'--skip': skip,
1016 b'--skip': skip,
1017 }
1017 }
1018
1018
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1020
1020
1021 if len(enabled) > 1:
1021 if len(enabled) > 1:
1022 raise error.Abort(
1022 raise error.Abort(
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 )
1024 )
1025
1025
1026 if reset:
1026 if reset:
1027 hbisect.resetstate(repo)
1027 hbisect.resetstate(repo)
1028 return
1028 return
1029
1029
1030 state = hbisect.load_state(repo)
1030 state = hbisect.load_state(repo)
1031
1031
1032 # update state
1032 # update state
1033 if good or bad or skip:
1033 if good or bad or skip:
1034 if rev:
1034 if rev:
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 else:
1036 else:
1037 nodes = [repo.lookup(b'.')]
1037 nodes = [repo.lookup(b'.')]
1038 if good:
1038 if good:
1039 state[b'good'] += nodes
1039 state[b'good'] += nodes
1040 elif bad:
1040 elif bad:
1041 state[b'bad'] += nodes
1041 state[b'bad'] += nodes
1042 elif skip:
1042 elif skip:
1043 state[b'skip'] += nodes
1043 state[b'skip'] += nodes
1044 hbisect.save_state(repo, state)
1044 hbisect.save_state(repo, state)
1045 if not (state[b'good'] and state[b'bad']):
1045 if not (state[b'good'] and state[b'bad']):
1046 return
1046 return
1047
1047
1048 def mayupdate(repo, node, show_stats=True):
1048 def mayupdate(repo, node, show_stats=True):
1049 """common used update sequence"""
1049 """common used update sequence"""
1050 if noupdate:
1050 if noupdate:
1051 return
1051 return
1052 cmdutil.checkunfinished(repo)
1052 cmdutil.checkunfinished(repo)
1053 cmdutil.bailifchanged(repo)
1053 cmdutil.bailifchanged(repo)
1054 return hg.clean(repo, node, show_stats=show_stats)
1054 return hg.clean(repo, node, show_stats=show_stats)
1055
1055
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057
1057
1058 if command:
1058 if command:
1059 changesets = 1
1059 changesets = 1
1060 if noupdate:
1060 if noupdate:
1061 try:
1061 try:
1062 node = state[b'current'][0]
1062 node = state[b'current'][0]
1063 except LookupError:
1063 except LookupError:
1064 raise error.Abort(
1064 raise error.Abort(
1065 _(
1065 _(
1066 b'current bisect revision is unknown - '
1066 b'current bisect revision is unknown - '
1067 b'start a new bisect to fix'
1067 b'start a new bisect to fix'
1068 )
1068 )
1069 )
1069 )
1070 else:
1070 else:
1071 node, p2 = repo.dirstate.parents()
1071 node, p2 = repo.dirstate.parents()
1072 if p2 != nullid:
1072 if p2 != nullid:
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1074 if rev:
1074 if rev:
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 try:
1076 try:
1077 while changesets:
1077 while changesets:
1078 # update state
1078 # update state
1079 state[b'current'] = [node]
1079 state[b'current'] = [node]
1080 hbisect.save_state(repo, state)
1080 hbisect.save_state(repo, state)
1081 status = ui.system(
1081 status = ui.system(
1082 command,
1082 command,
1083 environ={b'HG_NODE': hex(node)},
1083 environ={b'HG_NODE': hex(node)},
1084 blockedtag=b'bisect_check',
1084 blockedtag=b'bisect_check',
1085 )
1085 )
1086 if status == 125:
1086 if status == 125:
1087 transition = b"skip"
1087 transition = b"skip"
1088 elif status == 0:
1088 elif status == 0:
1089 transition = b"good"
1089 transition = b"good"
1090 # status < 0 means process was killed
1090 # status < 0 means process was killed
1091 elif status == 127:
1091 elif status == 127:
1092 raise error.Abort(_(b"failed to execute %s") % command)
1092 raise error.Abort(_(b"failed to execute %s") % command)
1093 elif status < 0:
1093 elif status < 0:
1094 raise error.Abort(_(b"%s killed") % command)
1094 raise error.Abort(_(b"%s killed") % command)
1095 else:
1095 else:
1096 transition = b"bad"
1096 transition = b"bad"
1097 state[transition].append(node)
1097 state[transition].append(node)
1098 ctx = repo[node]
1098 ctx = repo[node]
1099 ui.status(
1099 ui.status(
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 )
1101 )
1102 hbisect.checkstate(state)
1102 hbisect.checkstate(state)
1103 # bisect
1103 # bisect
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 # update to next check
1105 # update to next check
1106 node = nodes[0]
1106 node = nodes[0]
1107 mayupdate(repo, node, show_stats=False)
1107 mayupdate(repo, node, show_stats=False)
1108 finally:
1108 finally:
1109 state[b'current'] = [node]
1109 state[b'current'] = [node]
1110 hbisect.save_state(repo, state)
1110 hbisect.save_state(repo, state)
1111 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1111 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1112 return
1112 return
1113
1113
1114 hbisect.checkstate(state)
1114 hbisect.checkstate(state)
1115
1115
1116 # actually bisect
1116 # actually bisect
1117 nodes, changesets, good = hbisect.bisect(repo, state)
1117 nodes, changesets, good = hbisect.bisect(repo, state)
1118 if extend:
1118 if extend:
1119 if not changesets:
1119 if not changesets:
1120 extendnode = hbisect.extendrange(repo, state, nodes, good)
1120 extendnode = hbisect.extendrange(repo, state, nodes, good)
1121 if extendnode is not None:
1121 if extendnode is not None:
1122 ui.write(
1122 ui.write(
1123 _(b"Extending search to changeset %d:%s\n")
1123 _(b"Extending search to changeset %d:%s\n")
1124 % (extendnode.rev(), extendnode)
1124 % (extendnode.rev(), extendnode)
1125 )
1125 )
1126 state[b'current'] = [extendnode.node()]
1126 state[b'current'] = [extendnode.node()]
1127 hbisect.save_state(repo, state)
1127 hbisect.save_state(repo, state)
1128 return mayupdate(repo, extendnode.node())
1128 return mayupdate(repo, extendnode.node())
1129 raise error.Abort(_(b"nothing to extend"))
1129 raise error.Abort(_(b"nothing to extend"))
1130
1130
1131 if changesets == 0:
1131 if changesets == 0:
1132 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1132 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1133 else:
1133 else:
1134 assert len(nodes) == 1 # only a single node can be tested next
1134 assert len(nodes) == 1 # only a single node can be tested next
1135 node = nodes[0]
1135 node = nodes[0]
1136 # compute the approximate number of remaining tests
1136 # compute the approximate number of remaining tests
1137 tests, size = 0, 2
1137 tests, size = 0, 2
1138 while size <= changesets:
1138 while size <= changesets:
1139 tests, size = tests + 1, size * 2
1139 tests, size = tests + 1, size * 2
1140 rev = repo.changelog.rev(node)
1140 rev = repo.changelog.rev(node)
1141 ui.write(
1141 ui.write(
1142 _(
1142 _(
1143 b"Testing changeset %d:%s "
1143 b"Testing changeset %d:%s "
1144 b"(%d changesets remaining, ~%d tests)\n"
1144 b"(%d changesets remaining, ~%d tests)\n"
1145 )
1145 )
1146 % (rev, short(node), changesets, tests)
1146 % (rev, short(node), changesets, tests)
1147 )
1147 )
1148 state[b'current'] = [node]
1148 state[b'current'] = [node]
1149 hbisect.save_state(repo, state)
1149 hbisect.save_state(repo, state)
1150 return mayupdate(repo, node)
1150 return mayupdate(repo, node)
1151
1151
1152
1152
1153 @command(
1153 @command(
1154 b'bookmarks|bookmark',
1154 b'bookmarks|bookmark',
1155 [
1155 [
1156 (b'f', b'force', False, _(b'force')),
1156 (b'f', b'force', False, _(b'force')),
1157 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1157 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1158 (b'd', b'delete', False, _(b'delete a given bookmark')),
1158 (b'd', b'delete', False, _(b'delete a given bookmark')),
1159 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1159 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1160 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1160 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1161 (b'l', b'list', False, _(b'list existing bookmarks')),
1161 (b'l', b'list', False, _(b'list existing bookmarks')),
1162 ]
1162 ]
1163 + formatteropts,
1163 + formatteropts,
1164 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1164 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1166 )
1166 )
1167 def bookmark(ui, repo, *names, **opts):
1167 def bookmark(ui, repo, *names, **opts):
1168 '''create a new bookmark or list existing bookmarks
1168 '''create a new bookmark or list existing bookmarks
1169
1169
1170 Bookmarks are labels on changesets to help track lines of development.
1170 Bookmarks are labels on changesets to help track lines of development.
1171 Bookmarks are unversioned and can be moved, renamed and deleted.
1171 Bookmarks are unversioned and can be moved, renamed and deleted.
1172 Deleting or moving a bookmark has no effect on the associated changesets.
1172 Deleting or moving a bookmark has no effect on the associated changesets.
1173
1173
1174 Creating or updating to a bookmark causes it to be marked as 'active'.
1174 Creating or updating to a bookmark causes it to be marked as 'active'.
1175 The active bookmark is indicated with a '*'.
1175 The active bookmark is indicated with a '*'.
1176 When a commit is made, the active bookmark will advance to the new commit.
1176 When a commit is made, the active bookmark will advance to the new commit.
1177 A plain :hg:`update` will also advance an active bookmark, if possible.
1177 A plain :hg:`update` will also advance an active bookmark, if possible.
1178 Updating away from a bookmark will cause it to be deactivated.
1178 Updating away from a bookmark will cause it to be deactivated.
1179
1179
1180 Bookmarks can be pushed and pulled between repositories (see
1180 Bookmarks can be pushed and pulled between repositories (see
1181 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1181 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1182 diverged, a new 'divergent bookmark' of the form 'name@path' will
1182 diverged, a new 'divergent bookmark' of the form 'name@path' will
1183 be created. Using :hg:`merge` will resolve the divergence.
1183 be created. Using :hg:`merge` will resolve the divergence.
1184
1184
1185 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1185 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1186 the active bookmark's name.
1186 the active bookmark's name.
1187
1187
1188 A bookmark named '@' has the special property that :hg:`clone` will
1188 A bookmark named '@' has the special property that :hg:`clone` will
1189 check it out by default if it exists.
1189 check it out by default if it exists.
1190
1190
1191 .. container:: verbose
1191 .. container:: verbose
1192
1192
1193 Template:
1193 Template:
1194
1194
1195 The following keywords are supported in addition to the common template
1195 The following keywords are supported in addition to the common template
1196 keywords and functions such as ``{bookmark}``. See also
1196 keywords and functions such as ``{bookmark}``. See also
1197 :hg:`help templates`.
1197 :hg:`help templates`.
1198
1198
1199 :active: Boolean. True if the bookmark is active.
1199 :active: Boolean. True if the bookmark is active.
1200
1200
1201 Examples:
1201 Examples:
1202
1202
1203 - create an active bookmark for a new line of development::
1203 - create an active bookmark for a new line of development::
1204
1204
1205 hg book new-feature
1205 hg book new-feature
1206
1206
1207 - create an inactive bookmark as a place marker::
1207 - create an inactive bookmark as a place marker::
1208
1208
1209 hg book -i reviewed
1209 hg book -i reviewed
1210
1210
1211 - create an inactive bookmark on another changeset::
1211 - create an inactive bookmark on another changeset::
1212
1212
1213 hg book -r .^ tested
1213 hg book -r .^ tested
1214
1214
1215 - rename bookmark turkey to dinner::
1215 - rename bookmark turkey to dinner::
1216
1216
1217 hg book -m turkey dinner
1217 hg book -m turkey dinner
1218
1218
1219 - move the '@' bookmark from another branch::
1219 - move the '@' bookmark from another branch::
1220
1220
1221 hg book -f @
1221 hg book -f @
1222
1222
1223 - print only the active bookmark name::
1223 - print only the active bookmark name::
1224
1224
1225 hg book -ql .
1225 hg book -ql .
1226 '''
1226 '''
1227 opts = pycompat.byteskwargs(opts)
1227 opts = pycompat.byteskwargs(opts)
1228 force = opts.get(b'force')
1228 force = opts.get(b'force')
1229 rev = opts.get(b'rev')
1229 rev = opts.get(b'rev')
1230 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1230 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1231
1231
1232 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1232 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1233 if len(selactions) > 1:
1233 if len(selactions) > 1:
1234 raise error.Abort(
1234 raise error.Abort(
1235 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1235 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1236 )
1236 )
1237 if selactions:
1237 if selactions:
1238 action = selactions[0]
1238 action = selactions[0]
1239 elif names or rev:
1239 elif names or rev:
1240 action = b'add'
1240 action = b'add'
1241 elif inactive:
1241 elif inactive:
1242 action = b'inactive' # meaning deactivate
1242 action = b'inactive' # meaning deactivate
1243 else:
1243 else:
1244 action = b'list'
1244 action = b'list'
1245
1245
1246 if rev and action in {b'delete', b'rename', b'list'}:
1246 if rev and action in {b'delete', b'rename', b'list'}:
1247 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1247 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1248 if inactive and action in {b'delete', b'list'}:
1248 if inactive and action in {b'delete', b'list'}:
1249 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1249 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1250 if not names and action in {b'add', b'delete'}:
1250 if not names and action in {b'add', b'delete'}:
1251 raise error.Abort(_(b"bookmark name required"))
1251 raise error.Abort(_(b"bookmark name required"))
1252
1252
1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1255 if action == b'delete':
1255 if action == b'delete':
1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1257 bookmarks.delete(repo, tr, names)
1257 bookmarks.delete(repo, tr, names)
1258 elif action == b'rename':
1258 elif action == b'rename':
1259 if not names:
1259 if not names:
1260 raise error.Abort(_(b"new bookmark name required"))
1260 raise error.Abort(_(b"new bookmark name required"))
1261 elif len(names) > 1:
1261 elif len(names) > 1:
1262 raise error.Abort(_(b"only one new bookmark name allowed"))
1262 raise error.Abort(_(b"only one new bookmark name allowed"))
1263 oldname = repo._bookmarks.expandname(opts[b'rename'])
1263 oldname = repo._bookmarks.expandname(opts[b'rename'])
1264 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1264 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1265 elif action == b'add':
1265 elif action == b'add':
1266 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1266 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1267 elif action == b'inactive':
1267 elif action == b'inactive':
1268 if len(repo._bookmarks) == 0:
1268 if len(repo._bookmarks) == 0:
1269 ui.status(_(b"no bookmarks set\n"))
1269 ui.status(_(b"no bookmarks set\n"))
1270 elif not repo._activebookmark:
1270 elif not repo._activebookmark:
1271 ui.status(_(b"no active bookmark\n"))
1271 ui.status(_(b"no active bookmark\n"))
1272 else:
1272 else:
1273 bookmarks.deactivate(repo)
1273 bookmarks.deactivate(repo)
1274 elif action == b'list':
1274 elif action == b'list':
1275 names = pycompat.maplist(repo._bookmarks.expandname, names)
1275 names = pycompat.maplist(repo._bookmarks.expandname, names)
1276 with ui.formatter(b'bookmarks', opts) as fm:
1276 with ui.formatter(b'bookmarks', opts) as fm:
1277 bookmarks.printbookmarks(ui, repo, fm, names)
1277 bookmarks.printbookmarks(ui, repo, fm, names)
1278 else:
1278 else:
1279 raise error.ProgrammingError(b'invalid action: %s' % action)
1279 raise error.ProgrammingError(b'invalid action: %s' % action)
1280
1280
1281
1281
1282 @command(
1282 @command(
1283 b'branch',
1283 b'branch',
1284 [
1284 [
1285 (
1285 (
1286 b'f',
1286 b'f',
1287 b'force',
1287 b'force',
1288 None,
1288 None,
1289 _(b'set branch name even if it shadows an existing branch'),
1289 _(b'set branch name even if it shadows an existing branch'),
1290 ),
1290 ),
1291 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1291 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1292 (
1292 (
1293 b'r',
1293 b'r',
1294 b'rev',
1294 b'rev',
1295 [],
1295 [],
1296 _(b'change branches of the given revs (EXPERIMENTAL)'),
1296 _(b'change branches of the given revs (EXPERIMENTAL)'),
1297 ),
1297 ),
1298 ],
1298 ],
1299 _(b'[-fC] [NAME]'),
1299 _(b'[-fC] [NAME]'),
1300 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1300 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1301 )
1301 )
1302 def branch(ui, repo, label=None, **opts):
1302 def branch(ui, repo, label=None, **opts):
1303 """set or show the current branch name
1303 """set or show the current branch name
1304
1304
1305 .. note::
1305 .. note::
1306
1306
1307 Branch names are permanent and global. Use :hg:`bookmark` to create a
1307 Branch names are permanent and global. Use :hg:`bookmark` to create a
1308 light-weight bookmark instead. See :hg:`help glossary` for more
1308 light-weight bookmark instead. See :hg:`help glossary` for more
1309 information about named branches and bookmarks.
1309 information about named branches and bookmarks.
1310
1310
1311 With no argument, show the current branch name. With one argument,
1311 With no argument, show the current branch name. With one argument,
1312 set the working directory branch name (the branch will not exist
1312 set the working directory branch name (the branch will not exist
1313 in the repository until the next commit). Standard practice
1313 in the repository until the next commit). Standard practice
1314 recommends that primary development take place on the 'default'
1314 recommends that primary development take place on the 'default'
1315 branch.
1315 branch.
1316
1316
1317 Unless -f/--force is specified, branch will not let you set a
1317 Unless -f/--force is specified, branch will not let you set a
1318 branch name that already exists.
1318 branch name that already exists.
1319
1319
1320 Use -C/--clean to reset the working directory branch to that of
1320 Use -C/--clean to reset the working directory branch to that of
1321 the parent of the working directory, negating a previous branch
1321 the parent of the working directory, negating a previous branch
1322 change.
1322 change.
1323
1323
1324 Use the command :hg:`update` to switch to an existing branch. Use
1324 Use the command :hg:`update` to switch to an existing branch. Use
1325 :hg:`commit --close-branch` to mark this branch head as closed.
1325 :hg:`commit --close-branch` to mark this branch head as closed.
1326 When all heads of a branch are closed, the branch will be
1326 When all heads of a branch are closed, the branch will be
1327 considered closed.
1327 considered closed.
1328
1328
1329 Returns 0 on success.
1329 Returns 0 on success.
1330 """
1330 """
1331 opts = pycompat.byteskwargs(opts)
1331 opts = pycompat.byteskwargs(opts)
1332 revs = opts.get(b'rev')
1332 revs = opts.get(b'rev')
1333 if label:
1333 if label:
1334 label = label.strip()
1334 label = label.strip()
1335
1335
1336 if not opts.get(b'clean') and not label:
1336 if not opts.get(b'clean') and not label:
1337 if revs:
1337 if revs:
1338 raise error.Abort(_(b"no branch name specified for the revisions"))
1338 raise error.Abort(_(b"no branch name specified for the revisions"))
1339 ui.write(b"%s\n" % repo.dirstate.branch())
1339 ui.write(b"%s\n" % repo.dirstate.branch())
1340 return
1340 return
1341
1341
1342 with repo.wlock():
1342 with repo.wlock():
1343 if opts.get(b'clean'):
1343 if opts.get(b'clean'):
1344 label = repo[b'.'].branch()
1344 label = repo[b'.'].branch()
1345 repo.dirstate.setbranch(label)
1345 repo.dirstate.setbranch(label)
1346 ui.status(_(b'reset working directory to branch %s\n') % label)
1346 ui.status(_(b'reset working directory to branch %s\n') % label)
1347 elif label:
1347 elif label:
1348
1348
1349 scmutil.checknewlabel(repo, label, b'branch')
1349 scmutil.checknewlabel(repo, label, b'branch')
1350 if revs:
1350 if revs:
1351 return cmdutil.changebranch(ui, repo, revs, label)
1351 return cmdutil.changebranch(ui, repo, revs, label)
1352
1352
1353 if not opts.get(b'force') and label in repo.branchmap():
1353 if not opts.get(b'force') and label in repo.branchmap():
1354 if label not in [p.branch() for p in repo[None].parents()]:
1354 if label not in [p.branch() for p in repo[None].parents()]:
1355 raise error.Abort(
1355 raise error.Abort(
1356 _(b'a branch of the same name already exists'),
1356 _(b'a branch of the same name already exists'),
1357 # i18n: "it" refers to an existing branch
1357 # i18n: "it" refers to an existing branch
1358 hint=_(b"use 'hg update' to switch to it"),
1358 hint=_(b"use 'hg update' to switch to it"),
1359 )
1359 )
1360
1360
1361 repo.dirstate.setbranch(label)
1361 repo.dirstate.setbranch(label)
1362 ui.status(_(b'marked working directory as branch %s\n') % label)
1362 ui.status(_(b'marked working directory as branch %s\n') % label)
1363
1363
1364 # find any open named branches aside from default
1364 # find any open named branches aside from default
1365 for n, h, t, c in repo.branchmap().iterbranches():
1365 for n, h, t, c in repo.branchmap().iterbranches():
1366 if n != b"default" and not c:
1366 if n != b"default" and not c:
1367 return 0
1367 return 0
1368 ui.status(
1368 ui.status(
1369 _(
1369 _(
1370 b'(branches are permanent and global, '
1370 b'(branches are permanent and global, '
1371 b'did you want a bookmark?)\n'
1371 b'did you want a bookmark?)\n'
1372 )
1372 )
1373 )
1373 )
1374
1374
1375
1375
1376 @command(
1376 @command(
1377 b'branches',
1377 b'branches',
1378 [
1378 [
1379 (
1379 (
1380 b'a',
1380 b'a',
1381 b'active',
1381 b'active',
1382 False,
1382 False,
1383 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1383 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1384 ),
1384 ),
1385 (b'c', b'closed', False, _(b'show normal and closed branches')),
1385 (b'c', b'closed', False, _(b'show normal and closed branches')),
1386 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1386 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1387 ]
1387 ]
1388 + formatteropts,
1388 + formatteropts,
1389 _(b'[-c]'),
1389 _(b'[-c]'),
1390 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1390 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1391 intents={INTENT_READONLY},
1391 intents={INTENT_READONLY},
1392 )
1392 )
1393 def branches(ui, repo, active=False, closed=False, **opts):
1393 def branches(ui, repo, active=False, closed=False, **opts):
1394 """list repository named branches
1394 """list repository named branches
1395
1395
1396 List the repository's named branches, indicating which ones are
1396 List the repository's named branches, indicating which ones are
1397 inactive. If -c/--closed is specified, also list branches which have
1397 inactive. If -c/--closed is specified, also list branches which have
1398 been marked closed (see :hg:`commit --close-branch`).
1398 been marked closed (see :hg:`commit --close-branch`).
1399
1399
1400 Use the command :hg:`update` to switch to an existing branch.
1400 Use the command :hg:`update` to switch to an existing branch.
1401
1401
1402 .. container:: verbose
1402 .. container:: verbose
1403
1403
1404 Template:
1404 Template:
1405
1405
1406 The following keywords are supported in addition to the common template
1406 The following keywords are supported in addition to the common template
1407 keywords and functions such as ``{branch}``. See also
1407 keywords and functions such as ``{branch}``. See also
1408 :hg:`help templates`.
1408 :hg:`help templates`.
1409
1409
1410 :active: Boolean. True if the branch is active.
1410 :active: Boolean. True if the branch is active.
1411 :closed: Boolean. True if the branch is closed.
1411 :closed: Boolean. True if the branch is closed.
1412 :current: Boolean. True if it is the current branch.
1412 :current: Boolean. True if it is the current branch.
1413
1413
1414 Returns 0.
1414 Returns 0.
1415 """
1415 """
1416
1416
1417 opts = pycompat.byteskwargs(opts)
1417 opts = pycompat.byteskwargs(opts)
1418 revs = opts.get(b'rev')
1418 revs = opts.get(b'rev')
1419 selectedbranches = None
1419 selectedbranches = None
1420 if revs:
1420 if revs:
1421 revs = scmutil.revrange(repo, revs)
1421 revs = scmutil.revrange(repo, revs)
1422 getbi = repo.revbranchcache().branchinfo
1422 getbi = repo.revbranchcache().branchinfo
1423 selectedbranches = {getbi(r)[0] for r in revs}
1423 selectedbranches = {getbi(r)[0] for r in revs}
1424
1424
1425 ui.pager(b'branches')
1425 ui.pager(b'branches')
1426 fm = ui.formatter(b'branches', opts)
1426 fm = ui.formatter(b'branches', opts)
1427 hexfunc = fm.hexfunc
1427 hexfunc = fm.hexfunc
1428
1428
1429 allheads = set(repo.heads())
1429 allheads = set(repo.heads())
1430 branches = []
1430 branches = []
1431 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1431 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1432 if selectedbranches is not None and tag not in selectedbranches:
1432 if selectedbranches is not None and tag not in selectedbranches:
1433 continue
1433 continue
1434 isactive = False
1434 isactive = False
1435 if not isclosed:
1435 if not isclosed:
1436 openheads = set(repo.branchmap().iteropen(heads))
1436 openheads = set(repo.branchmap().iteropen(heads))
1437 isactive = bool(openheads & allheads)
1437 isactive = bool(openheads & allheads)
1438 branches.append((tag, repo[tip], isactive, not isclosed))
1438 branches.append((tag, repo[tip], isactive, not isclosed))
1439 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1439 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1440
1440
1441 for tag, ctx, isactive, isopen in branches:
1441 for tag, ctx, isactive, isopen in branches:
1442 if active and not isactive:
1442 if active and not isactive:
1443 continue
1443 continue
1444 if isactive:
1444 if isactive:
1445 label = b'branches.active'
1445 label = b'branches.active'
1446 notice = b''
1446 notice = b''
1447 elif not isopen:
1447 elif not isopen:
1448 if not closed:
1448 if not closed:
1449 continue
1449 continue
1450 label = b'branches.closed'
1450 label = b'branches.closed'
1451 notice = _(b' (closed)')
1451 notice = _(b' (closed)')
1452 else:
1452 else:
1453 label = b'branches.inactive'
1453 label = b'branches.inactive'
1454 notice = _(b' (inactive)')
1454 notice = _(b' (inactive)')
1455 current = tag == repo.dirstate.branch()
1455 current = tag == repo.dirstate.branch()
1456 if current:
1456 if current:
1457 label = b'branches.current'
1457 label = b'branches.current'
1458
1458
1459 fm.startitem()
1459 fm.startitem()
1460 fm.write(b'branch', b'%s', tag, label=label)
1460 fm.write(b'branch', b'%s', tag, label=label)
1461 rev = ctx.rev()
1461 rev = ctx.rev()
1462 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1462 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1463 fmt = b' ' * padsize + b' %d:%s'
1463 fmt = b' ' * padsize + b' %d:%s'
1464 fm.condwrite(
1464 fm.condwrite(
1465 not ui.quiet,
1465 not ui.quiet,
1466 b'rev node',
1466 b'rev node',
1467 fmt,
1467 fmt,
1468 rev,
1468 rev,
1469 hexfunc(ctx.node()),
1469 hexfunc(ctx.node()),
1470 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1470 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1471 )
1471 )
1472 fm.context(ctx=ctx)
1472 fm.context(ctx=ctx)
1473 fm.data(active=isactive, closed=not isopen, current=current)
1473 fm.data(active=isactive, closed=not isopen, current=current)
1474 if not ui.quiet:
1474 if not ui.quiet:
1475 fm.plain(notice)
1475 fm.plain(notice)
1476 fm.plain(b'\n')
1476 fm.plain(b'\n')
1477 fm.end()
1477 fm.end()
1478
1478
1479
1479
1480 @command(
1480 @command(
1481 b'bundle',
1481 b'bundle',
1482 [
1482 [
1483 (
1483 (
1484 b'f',
1484 b'f',
1485 b'force',
1485 b'force',
1486 None,
1486 None,
1487 _(b'run even when the destination is unrelated'),
1487 _(b'run even when the destination is unrelated'),
1488 ),
1488 ),
1489 (
1489 (
1490 b'r',
1490 b'r',
1491 b'rev',
1491 b'rev',
1492 [],
1492 [],
1493 _(b'a changeset intended to be added to the destination'),
1493 _(b'a changeset intended to be added to the destination'),
1494 _(b'REV'),
1494 _(b'REV'),
1495 ),
1495 ),
1496 (
1496 (
1497 b'b',
1497 b'b',
1498 b'branch',
1498 b'branch',
1499 [],
1499 [],
1500 _(b'a specific branch you would like to bundle'),
1500 _(b'a specific branch you would like to bundle'),
1501 _(b'BRANCH'),
1501 _(b'BRANCH'),
1502 ),
1502 ),
1503 (
1503 (
1504 b'',
1504 b'',
1505 b'base',
1505 b'base',
1506 [],
1506 [],
1507 _(b'a base changeset assumed to be available at the destination'),
1507 _(b'a base changeset assumed to be available at the destination'),
1508 _(b'REV'),
1508 _(b'REV'),
1509 ),
1509 ),
1510 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1510 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1511 (
1511 (
1512 b't',
1512 b't',
1513 b'type',
1513 b'type',
1514 b'bzip2',
1514 b'bzip2',
1515 _(b'bundle compression type to use'),
1515 _(b'bundle compression type to use'),
1516 _(b'TYPE'),
1516 _(b'TYPE'),
1517 ),
1517 ),
1518 ]
1518 ]
1519 + remoteopts,
1519 + remoteopts,
1520 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1520 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1521 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1521 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1522 )
1522 )
1523 def bundle(ui, repo, fname, dest=None, **opts):
1523 def bundle(ui, repo, fname, dest=None, **opts):
1524 """create a bundle file
1524 """create a bundle file
1525
1525
1526 Generate a bundle file containing data to be transferred to another
1526 Generate a bundle file containing data to be transferred to another
1527 repository.
1527 repository.
1528
1528
1529 To create a bundle containing all changesets, use -a/--all
1529 To create a bundle containing all changesets, use -a/--all
1530 (or --base null). Otherwise, hg assumes the destination will have
1530 (or --base null). Otherwise, hg assumes the destination will have
1531 all the nodes you specify with --base parameters. Otherwise, hg
1531 all the nodes you specify with --base parameters. Otherwise, hg
1532 will assume the repository has all the nodes in destination, or
1532 will assume the repository has all the nodes in destination, or
1533 default-push/default if no destination is specified, where destination
1533 default-push/default if no destination is specified, where destination
1534 is the repository you provide through DEST option.
1534 is the repository you provide through DEST option.
1535
1535
1536 You can change bundle format with the -t/--type option. See
1536 You can change bundle format with the -t/--type option. See
1537 :hg:`help bundlespec` for documentation on this format. By default,
1537 :hg:`help bundlespec` for documentation on this format. By default,
1538 the most appropriate format is used and compression defaults to
1538 the most appropriate format is used and compression defaults to
1539 bzip2.
1539 bzip2.
1540
1540
1541 The bundle file can then be transferred using conventional means
1541 The bundle file can then be transferred using conventional means
1542 and applied to another repository with the unbundle or pull
1542 and applied to another repository with the unbundle or pull
1543 command. This is useful when direct push and pull are not
1543 command. This is useful when direct push and pull are not
1544 available or when exporting an entire repository is undesirable.
1544 available or when exporting an entire repository is undesirable.
1545
1545
1546 Applying bundles preserves all changeset contents including
1546 Applying bundles preserves all changeset contents including
1547 permissions, copy/rename information, and revision history.
1547 permissions, copy/rename information, and revision history.
1548
1548
1549 Returns 0 on success, 1 if no changes found.
1549 Returns 0 on success, 1 if no changes found.
1550 """
1550 """
1551 opts = pycompat.byteskwargs(opts)
1551 opts = pycompat.byteskwargs(opts)
1552 revs = None
1552 revs = None
1553 if b'rev' in opts:
1553 if b'rev' in opts:
1554 revstrings = opts[b'rev']
1554 revstrings = opts[b'rev']
1555 revs = scmutil.revrange(repo, revstrings)
1555 revs = scmutil.revrange(repo, revstrings)
1556 if revstrings and not revs:
1556 if revstrings and not revs:
1557 raise error.Abort(_(b'no commits to bundle'))
1557 raise error.Abort(_(b'no commits to bundle'))
1558
1558
1559 bundletype = opts.get(b'type', b'bzip2').lower()
1559 bundletype = opts.get(b'type', b'bzip2').lower()
1560 try:
1560 try:
1561 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1561 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1562 except error.UnsupportedBundleSpecification as e:
1562 except error.UnsupportedBundleSpecification as e:
1563 raise error.Abort(
1563 raise error.Abort(
1564 pycompat.bytestr(e),
1564 pycompat.bytestr(e),
1565 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1565 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1566 )
1566 )
1567 cgversion = bundlespec.contentopts[b"cg.version"]
1567 cgversion = bundlespec.contentopts[b"cg.version"]
1568
1568
1569 # Packed bundles are a pseudo bundle format for now.
1569 # Packed bundles are a pseudo bundle format for now.
1570 if cgversion == b's1':
1570 if cgversion == b's1':
1571 raise error.Abort(
1571 raise error.Abort(
1572 _(b'packed bundles cannot be produced by "hg bundle"'),
1572 _(b'packed bundles cannot be produced by "hg bundle"'),
1573 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1573 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1574 )
1574 )
1575
1575
1576 if opts.get(b'all'):
1576 if opts.get(b'all'):
1577 if dest:
1577 if dest:
1578 raise error.Abort(
1578 raise error.Abort(
1579 _(b"--all is incompatible with specifying a destination")
1579 _(b"--all is incompatible with specifying a destination")
1580 )
1580 )
1581 if opts.get(b'base'):
1581 if opts.get(b'base'):
1582 ui.warn(_(b"ignoring --base because --all was specified\n"))
1582 ui.warn(_(b"ignoring --base because --all was specified\n"))
1583 base = [nullrev]
1583 base = [nullrev]
1584 else:
1584 else:
1585 base = scmutil.revrange(repo, opts.get(b'base'))
1585 base = scmutil.revrange(repo, opts.get(b'base'))
1586 if cgversion not in changegroup.supportedoutgoingversions(repo):
1586 if cgversion not in changegroup.supportedoutgoingversions(repo):
1587 raise error.Abort(
1587 raise error.Abort(
1588 _(b"repository does not support bundle version %s") % cgversion
1588 _(b"repository does not support bundle version %s") % cgversion
1589 )
1589 )
1590
1590
1591 if base:
1591 if base:
1592 if dest:
1592 if dest:
1593 raise error.Abort(
1593 raise error.Abort(
1594 _(b"--base is incompatible with specifying a destination")
1594 _(b"--base is incompatible with specifying a destination")
1595 )
1595 )
1596 common = [repo[rev].node() for rev in base]
1596 common = [repo[rev].node() for rev in base]
1597 heads = [repo[r].node() for r in revs] if revs else None
1597 heads = [repo[r].node() for r in revs] if revs else None
1598 outgoing = discovery.outgoing(repo, common, heads)
1598 outgoing = discovery.outgoing(repo, common, heads)
1599 else:
1599 else:
1600 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1600 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1601 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1601 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1602 other = hg.peer(repo, opts, dest)
1602 other = hg.peer(repo, opts, dest)
1603 revs = [repo[r].hex() for r in revs]
1603 revs = [repo[r].hex() for r in revs]
1604 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1604 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1605 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1605 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1606 outgoing = discovery.findcommonoutgoing(
1606 outgoing = discovery.findcommonoutgoing(
1607 repo,
1607 repo,
1608 other,
1608 other,
1609 onlyheads=heads,
1609 onlyheads=heads,
1610 force=opts.get(b'force'),
1610 force=opts.get(b'force'),
1611 portable=True,
1611 portable=True,
1612 )
1612 )
1613
1613
1614 if not outgoing.missing:
1614 if not outgoing.missing:
1615 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1615 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1616 return 1
1616 return 1
1617
1617
1618 if cgversion == b'01': # bundle1
1618 if cgversion == b'01': # bundle1
1619 bversion = b'HG10' + bundlespec.wirecompression
1619 bversion = b'HG10' + bundlespec.wirecompression
1620 bcompression = None
1620 bcompression = None
1621 elif cgversion in (b'02', b'03'):
1621 elif cgversion in (b'02', b'03'):
1622 bversion = b'HG20'
1622 bversion = b'HG20'
1623 bcompression = bundlespec.wirecompression
1623 bcompression = bundlespec.wirecompression
1624 else:
1624 else:
1625 raise error.ProgrammingError(
1625 raise error.ProgrammingError(
1626 b'bundle: unexpected changegroup version %s' % cgversion
1626 b'bundle: unexpected changegroup version %s' % cgversion
1627 )
1627 )
1628
1628
1629 # TODO compression options should be derived from bundlespec parsing.
1629 # TODO compression options should be derived from bundlespec parsing.
1630 # This is a temporary hack to allow adjusting bundle compression
1630 # This is a temporary hack to allow adjusting bundle compression
1631 # level without a) formalizing the bundlespec changes to declare it
1631 # level without a) formalizing the bundlespec changes to declare it
1632 # b) introducing a command flag.
1632 # b) introducing a command flag.
1633 compopts = {}
1633 compopts = {}
1634 complevel = ui.configint(
1634 complevel = ui.configint(
1635 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1635 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1636 )
1636 )
1637 if complevel is None:
1637 if complevel is None:
1638 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1638 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1639 if complevel is not None:
1639 if complevel is not None:
1640 compopts[b'level'] = complevel
1640 compopts[b'level'] = complevel
1641
1641
1642 # Allow overriding the bundling of obsmarker in phases through
1642 # Allow overriding the bundling of obsmarker in phases through
1643 # configuration while we don't have a bundle version that include them
1643 # configuration while we don't have a bundle version that include them
1644 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1644 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1645 bundlespec.contentopts[b'obsolescence'] = True
1645 bundlespec.contentopts[b'obsolescence'] = True
1646 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1646 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1647 bundlespec.contentopts[b'phases'] = True
1647 bundlespec.contentopts[b'phases'] = True
1648
1648
1649 bundle2.writenewbundle(
1649 bundle2.writenewbundle(
1650 ui,
1650 ui,
1651 repo,
1651 repo,
1652 b'bundle',
1652 b'bundle',
1653 fname,
1653 fname,
1654 bversion,
1654 bversion,
1655 outgoing,
1655 outgoing,
1656 bundlespec.contentopts,
1656 bundlespec.contentopts,
1657 compression=bcompression,
1657 compression=bcompression,
1658 compopts=compopts,
1658 compopts=compopts,
1659 )
1659 )
1660
1660
1661
1661
1662 @command(
1662 @command(
1663 b'cat',
1663 b'cat',
1664 [
1664 [
1665 (
1665 (
1666 b'o',
1666 b'o',
1667 b'output',
1667 b'output',
1668 b'',
1668 b'',
1669 _(b'print output to file with formatted name'),
1669 _(b'print output to file with formatted name'),
1670 _(b'FORMAT'),
1670 _(b'FORMAT'),
1671 ),
1671 ),
1672 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1672 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1673 (b'', b'decode', None, _(b'apply any matching decode filter')),
1673 (b'', b'decode', None, _(b'apply any matching decode filter')),
1674 ]
1674 ]
1675 + walkopts
1675 + walkopts
1676 + formatteropts,
1676 + formatteropts,
1677 _(b'[OPTION]... FILE...'),
1677 _(b'[OPTION]... FILE...'),
1678 helpcategory=command.CATEGORY_FILE_CONTENTS,
1678 helpcategory=command.CATEGORY_FILE_CONTENTS,
1679 inferrepo=True,
1679 inferrepo=True,
1680 intents={INTENT_READONLY},
1680 intents={INTENT_READONLY},
1681 )
1681 )
1682 def cat(ui, repo, file1, *pats, **opts):
1682 def cat(ui, repo, file1, *pats, **opts):
1683 """output the current or given revision of files
1683 """output the current or given revision of files
1684
1684
1685 Print the specified files as they were at the given revision. If
1685 Print the specified files as they were at the given revision. If
1686 no revision is given, the parent of the working directory is used.
1686 no revision is given, the parent of the working directory is used.
1687
1687
1688 Output may be to a file, in which case the name of the file is
1688 Output may be to a file, in which case the name of the file is
1689 given using a template string. See :hg:`help templates`. In addition
1689 given using a template string. See :hg:`help templates`. In addition
1690 to the common template keywords, the following formatting rules are
1690 to the common template keywords, the following formatting rules are
1691 supported:
1691 supported:
1692
1692
1693 :``%%``: literal "%" character
1693 :``%%``: literal "%" character
1694 :``%s``: basename of file being printed
1694 :``%s``: basename of file being printed
1695 :``%d``: dirname of file being printed, or '.' if in repository root
1695 :``%d``: dirname of file being printed, or '.' if in repository root
1696 :``%p``: root-relative path name of file being printed
1696 :``%p``: root-relative path name of file being printed
1697 :``%H``: changeset hash (40 hexadecimal digits)
1697 :``%H``: changeset hash (40 hexadecimal digits)
1698 :``%R``: changeset revision number
1698 :``%R``: changeset revision number
1699 :``%h``: short-form changeset hash (12 hexadecimal digits)
1699 :``%h``: short-form changeset hash (12 hexadecimal digits)
1700 :``%r``: zero-padded changeset revision number
1700 :``%r``: zero-padded changeset revision number
1701 :``%b``: basename of the exporting repository
1701 :``%b``: basename of the exporting repository
1702 :``\\``: literal "\\" character
1702 :``\\``: literal "\\" character
1703
1703
1704 .. container:: verbose
1704 .. container:: verbose
1705
1705
1706 Template:
1706 Template:
1707
1707
1708 The following keywords are supported in addition to the common template
1708 The following keywords are supported in addition to the common template
1709 keywords and functions. See also :hg:`help templates`.
1709 keywords and functions. See also :hg:`help templates`.
1710
1710
1711 :data: String. File content.
1711 :data: String. File content.
1712 :path: String. Repository-absolute path of the file.
1712 :path: String. Repository-absolute path of the file.
1713
1713
1714 Returns 0 on success.
1714 Returns 0 on success.
1715 """
1715 """
1716 opts = pycompat.byteskwargs(opts)
1716 opts = pycompat.byteskwargs(opts)
1717 rev = opts.get(b'rev')
1717 rev = opts.get(b'rev')
1718 if rev:
1718 if rev:
1719 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1719 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1720 ctx = scmutil.revsingle(repo, rev)
1720 ctx = scmutil.revsingle(repo, rev)
1721 m = scmutil.match(ctx, (file1,) + pats, opts)
1721 m = scmutil.match(ctx, (file1,) + pats, opts)
1722 fntemplate = opts.pop(b'output', b'')
1722 fntemplate = opts.pop(b'output', b'')
1723 if cmdutil.isstdiofilename(fntemplate):
1723 if cmdutil.isstdiofilename(fntemplate):
1724 fntemplate = b''
1724 fntemplate = b''
1725
1725
1726 if fntemplate:
1726 if fntemplate:
1727 fm = formatter.nullformatter(ui, b'cat', opts)
1727 fm = formatter.nullformatter(ui, b'cat', opts)
1728 else:
1728 else:
1729 ui.pager(b'cat')
1729 ui.pager(b'cat')
1730 fm = ui.formatter(b'cat', opts)
1730 fm = ui.formatter(b'cat', opts)
1731 with fm:
1731 with fm:
1732 return cmdutil.cat(
1732 return cmdutil.cat(
1733 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1733 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1734 )
1734 )
1735
1735
1736
1736
1737 @command(
1737 @command(
1738 b'clone',
1738 b'clone',
1739 [
1739 [
1740 (
1740 (
1741 b'U',
1741 b'U',
1742 b'noupdate',
1742 b'noupdate',
1743 None,
1743 None,
1744 _(
1744 _(
1745 b'the clone will include an empty working '
1745 b'the clone will include an empty working '
1746 b'directory (only a repository)'
1746 b'directory (only a repository)'
1747 ),
1747 ),
1748 ),
1748 ),
1749 (
1749 (
1750 b'u',
1750 b'u',
1751 b'updaterev',
1751 b'updaterev',
1752 b'',
1752 b'',
1753 _(b'revision, tag, or branch to check out'),
1753 _(b'revision, tag, or branch to check out'),
1754 _(b'REV'),
1754 _(b'REV'),
1755 ),
1755 ),
1756 (
1756 (
1757 b'r',
1757 b'r',
1758 b'rev',
1758 b'rev',
1759 [],
1759 [],
1760 _(
1760 _(
1761 b'do not clone everything, but include this changeset'
1761 b'do not clone everything, but include this changeset'
1762 b' and its ancestors'
1762 b' and its ancestors'
1763 ),
1763 ),
1764 _(b'REV'),
1764 _(b'REV'),
1765 ),
1765 ),
1766 (
1766 (
1767 b'b',
1767 b'b',
1768 b'branch',
1768 b'branch',
1769 [],
1769 [],
1770 _(
1770 _(
1771 b'do not clone everything, but include this branch\'s'
1771 b'do not clone everything, but include this branch\'s'
1772 b' changesets and their ancestors'
1772 b' changesets and their ancestors'
1773 ),
1773 ),
1774 _(b'BRANCH'),
1774 _(b'BRANCH'),
1775 ),
1775 ),
1776 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1776 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1777 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1777 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1778 (b'', b'stream', None, _(b'clone with minimal data processing')),
1778 (b'', b'stream', None, _(b'clone with minimal data processing')),
1779 ]
1779 ]
1780 + remoteopts,
1780 + remoteopts,
1781 _(b'[OPTION]... SOURCE [DEST]'),
1781 _(b'[OPTION]... SOURCE [DEST]'),
1782 helpcategory=command.CATEGORY_REPO_CREATION,
1782 helpcategory=command.CATEGORY_REPO_CREATION,
1783 helpbasic=True,
1783 helpbasic=True,
1784 norepo=True,
1784 norepo=True,
1785 )
1785 )
1786 def clone(ui, source, dest=None, **opts):
1786 def clone(ui, source, dest=None, **opts):
1787 """make a copy of an existing repository
1787 """make a copy of an existing repository
1788
1788
1789 Create a copy of an existing repository in a new directory.
1789 Create a copy of an existing repository in a new directory.
1790
1790
1791 If no destination directory name is specified, it defaults to the
1791 If no destination directory name is specified, it defaults to the
1792 basename of the source.
1792 basename of the source.
1793
1793
1794 The location of the source is added to the new repository's
1794 The location of the source is added to the new repository's
1795 ``.hg/hgrc`` file, as the default to be used for future pulls.
1795 ``.hg/hgrc`` file, as the default to be used for future pulls.
1796
1796
1797 Only local paths and ``ssh://`` URLs are supported as
1797 Only local paths and ``ssh://`` URLs are supported as
1798 destinations. For ``ssh://`` destinations, no working directory or
1798 destinations. For ``ssh://`` destinations, no working directory or
1799 ``.hg/hgrc`` will be created on the remote side.
1799 ``.hg/hgrc`` will be created on the remote side.
1800
1800
1801 If the source repository has a bookmark called '@' set, that
1801 If the source repository has a bookmark called '@' set, that
1802 revision will be checked out in the new repository by default.
1802 revision will be checked out in the new repository by default.
1803
1803
1804 To check out a particular version, use -u/--update, or
1804 To check out a particular version, use -u/--update, or
1805 -U/--noupdate to create a clone with no working directory.
1805 -U/--noupdate to create a clone with no working directory.
1806
1806
1807 To pull only a subset of changesets, specify one or more revisions
1807 To pull only a subset of changesets, specify one or more revisions
1808 identifiers with -r/--rev or branches with -b/--branch. The
1808 identifiers with -r/--rev or branches with -b/--branch. The
1809 resulting clone will contain only the specified changesets and
1809 resulting clone will contain only the specified changesets and
1810 their ancestors. These options (or 'clone src#rev dest') imply
1810 their ancestors. These options (or 'clone src#rev dest') imply
1811 --pull, even for local source repositories.
1811 --pull, even for local source repositories.
1812
1812
1813 In normal clone mode, the remote normalizes repository data into a common
1813 In normal clone mode, the remote normalizes repository data into a common
1814 exchange format and the receiving end translates this data into its local
1814 exchange format and the receiving end translates this data into its local
1815 storage format. --stream activates a different clone mode that essentially
1815 storage format. --stream activates a different clone mode that essentially
1816 copies repository files from the remote with minimal data processing. This
1816 copies repository files from the remote with minimal data processing. This
1817 significantly reduces the CPU cost of a clone both remotely and locally.
1817 significantly reduces the CPU cost of a clone both remotely and locally.
1818 However, it often increases the transferred data size by 30-40%. This can
1818 However, it often increases the transferred data size by 30-40%. This can
1819 result in substantially faster clones where I/O throughput is plentiful,
1819 result in substantially faster clones where I/O throughput is plentiful,
1820 especially for larger repositories. A side-effect of --stream clones is
1820 especially for larger repositories. A side-effect of --stream clones is
1821 that storage settings and requirements on the remote are applied locally:
1821 that storage settings and requirements on the remote are applied locally:
1822 a modern client may inherit legacy or inefficient storage used by the
1822 a modern client may inherit legacy or inefficient storage used by the
1823 remote or a legacy Mercurial client may not be able to clone from a
1823 remote or a legacy Mercurial client may not be able to clone from a
1824 modern Mercurial remote.
1824 modern Mercurial remote.
1825
1825
1826 .. note::
1826 .. note::
1827
1827
1828 Specifying a tag will include the tagged changeset but not the
1828 Specifying a tag will include the tagged changeset but not the
1829 changeset containing the tag.
1829 changeset containing the tag.
1830
1830
1831 .. container:: verbose
1831 .. container:: verbose
1832
1832
1833 For efficiency, hardlinks are used for cloning whenever the
1833 For efficiency, hardlinks are used for cloning whenever the
1834 source and destination are on the same filesystem (note this
1834 source and destination are on the same filesystem (note this
1835 applies only to the repository data, not to the working
1835 applies only to the repository data, not to the working
1836 directory). Some filesystems, such as AFS, implement hardlinking
1836 directory). Some filesystems, such as AFS, implement hardlinking
1837 incorrectly, but do not report errors. In these cases, use the
1837 incorrectly, but do not report errors. In these cases, use the
1838 --pull option to avoid hardlinking.
1838 --pull option to avoid hardlinking.
1839
1839
1840 Mercurial will update the working directory to the first applicable
1840 Mercurial will update the working directory to the first applicable
1841 revision from this list:
1841 revision from this list:
1842
1842
1843 a) null if -U or the source repository has no changesets
1843 a) null if -U or the source repository has no changesets
1844 b) if -u . and the source repository is local, the first parent of
1844 b) if -u . and the source repository is local, the first parent of
1845 the source repository's working directory
1845 the source repository's working directory
1846 c) the changeset specified with -u (if a branch name, this means the
1846 c) the changeset specified with -u (if a branch name, this means the
1847 latest head of that branch)
1847 latest head of that branch)
1848 d) the changeset specified with -r
1848 d) the changeset specified with -r
1849 e) the tipmost head specified with -b
1849 e) the tipmost head specified with -b
1850 f) the tipmost head specified with the url#branch source syntax
1850 f) the tipmost head specified with the url#branch source syntax
1851 g) the revision marked with the '@' bookmark, if present
1851 g) the revision marked with the '@' bookmark, if present
1852 h) the tipmost head of the default branch
1852 h) the tipmost head of the default branch
1853 i) tip
1853 i) tip
1854
1854
1855 When cloning from servers that support it, Mercurial may fetch
1855 When cloning from servers that support it, Mercurial may fetch
1856 pre-generated data from a server-advertised URL or inline from the
1856 pre-generated data from a server-advertised URL or inline from the
1857 same stream. When this is done, hooks operating on incoming changesets
1857 same stream. When this is done, hooks operating on incoming changesets
1858 and changegroups may fire more than once, once for each pre-generated
1858 and changegroups may fire more than once, once for each pre-generated
1859 bundle and as well as for any additional remaining data. In addition,
1859 bundle and as well as for any additional remaining data. In addition,
1860 if an error occurs, the repository may be rolled back to a partial
1860 if an error occurs, the repository may be rolled back to a partial
1861 clone. This behavior may change in future releases.
1861 clone. This behavior may change in future releases.
1862 See :hg:`help -e clonebundles` for more.
1862 See :hg:`help -e clonebundles` for more.
1863
1863
1864 Examples:
1864 Examples:
1865
1865
1866 - clone a remote repository to a new directory named hg/::
1866 - clone a remote repository to a new directory named hg/::
1867
1867
1868 hg clone https://www.mercurial-scm.org/repo/hg/
1868 hg clone https://www.mercurial-scm.org/repo/hg/
1869
1869
1870 - create a lightweight local clone::
1870 - create a lightweight local clone::
1871
1871
1872 hg clone project/ project-feature/
1872 hg clone project/ project-feature/
1873
1873
1874 - clone from an absolute path on an ssh server (note double-slash)::
1874 - clone from an absolute path on an ssh server (note double-slash)::
1875
1875
1876 hg clone ssh://user@server//home/projects/alpha/
1876 hg clone ssh://user@server//home/projects/alpha/
1877
1877
1878 - do a streaming clone while checking out a specified version::
1878 - do a streaming clone while checking out a specified version::
1879
1879
1880 hg clone --stream http://server/repo -u 1.5
1880 hg clone --stream http://server/repo -u 1.5
1881
1881
1882 - create a repository without changesets after a particular revision::
1882 - create a repository without changesets after a particular revision::
1883
1883
1884 hg clone -r 04e544 experimental/ good/
1884 hg clone -r 04e544 experimental/ good/
1885
1885
1886 - clone (and track) a particular named branch::
1886 - clone (and track) a particular named branch::
1887
1887
1888 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1888 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1889
1889
1890 See :hg:`help urls` for details on specifying URLs.
1890 See :hg:`help urls` for details on specifying URLs.
1891
1891
1892 Returns 0 on success.
1892 Returns 0 on success.
1893 """
1893 """
1894 opts = pycompat.byteskwargs(opts)
1894 opts = pycompat.byteskwargs(opts)
1895 if opts.get(b'noupdate') and opts.get(b'updaterev'):
1895 if opts.get(b'noupdate') and opts.get(b'updaterev'):
1896 raise error.Abort(_(b"cannot specify both --noupdate and --updaterev"))
1896 raise error.Abort(_(b"cannot specify both --noupdate and --updaterev"))
1897
1897
1898 # --include/--exclude can come from narrow or sparse.
1898 # --include/--exclude can come from narrow or sparse.
1899 includepats, excludepats = None, None
1899 includepats, excludepats = None, None
1900
1900
1901 # hg.clone() differentiates between None and an empty set. So make sure
1901 # hg.clone() differentiates between None and an empty set. So make sure
1902 # patterns are sets if narrow is requested without patterns.
1902 # patterns are sets if narrow is requested without patterns.
1903 if opts.get(b'narrow'):
1903 if opts.get(b'narrow'):
1904 includepats = set()
1904 includepats = set()
1905 excludepats = set()
1905 excludepats = set()
1906
1906
1907 if opts.get(b'include'):
1907 if opts.get(b'include'):
1908 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1908 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1909 if opts.get(b'exclude'):
1909 if opts.get(b'exclude'):
1910 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1910 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1911
1911
1912 r = hg.clone(
1912 r = hg.clone(
1913 ui,
1913 ui,
1914 opts,
1914 opts,
1915 source,
1915 source,
1916 dest,
1916 dest,
1917 pull=opts.get(b'pull'),
1917 pull=opts.get(b'pull'),
1918 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1918 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1919 revs=opts.get(b'rev'),
1919 revs=opts.get(b'rev'),
1920 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1920 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1921 branch=opts.get(b'branch'),
1921 branch=opts.get(b'branch'),
1922 shareopts=opts.get(b'shareopts'),
1922 shareopts=opts.get(b'shareopts'),
1923 storeincludepats=includepats,
1923 storeincludepats=includepats,
1924 storeexcludepats=excludepats,
1924 storeexcludepats=excludepats,
1925 depth=opts.get(b'depth') or None,
1925 depth=opts.get(b'depth') or None,
1926 )
1926 )
1927
1927
1928 return r is None
1928 return r is None
1929
1929
1930
1930
1931 @command(
1931 @command(
1932 b'commit|ci',
1932 b'commit|ci',
1933 [
1933 [
1934 (
1934 (
1935 b'A',
1935 b'A',
1936 b'addremove',
1936 b'addremove',
1937 None,
1937 None,
1938 _(b'mark new/missing files as added/removed before committing'),
1938 _(b'mark new/missing files as added/removed before committing'),
1939 ),
1939 ),
1940 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1940 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1941 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1941 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1942 (b's', b'secret', None, _(b'use the secret phase for committing')),
1942 (b's', b'secret', None, _(b'use the secret phase for committing')),
1943 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1943 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1944 (
1944 (
1945 b'',
1945 b'',
1946 b'force-close-branch',
1946 b'force-close-branch',
1947 None,
1947 None,
1948 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1948 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1949 ),
1949 ),
1950 (b'i', b'interactive', None, _(b'use interactive mode')),
1950 (b'i', b'interactive', None, _(b'use interactive mode')),
1951 ]
1951 ]
1952 + walkopts
1952 + walkopts
1953 + commitopts
1953 + commitopts
1954 + commitopts2
1954 + commitopts2
1955 + subrepoopts,
1955 + subrepoopts,
1956 _(b'[OPTION]... [FILE]...'),
1956 _(b'[OPTION]... [FILE]...'),
1957 helpcategory=command.CATEGORY_COMMITTING,
1957 helpcategory=command.CATEGORY_COMMITTING,
1958 helpbasic=True,
1958 helpbasic=True,
1959 inferrepo=True,
1959 inferrepo=True,
1960 )
1960 )
1961 def commit(ui, repo, *pats, **opts):
1961 def commit(ui, repo, *pats, **opts):
1962 """commit the specified files or all outstanding changes
1962 """commit the specified files or all outstanding changes
1963
1963
1964 Commit changes to the given files into the repository. Unlike a
1964 Commit changes to the given files into the repository. Unlike a
1965 centralized SCM, this operation is a local operation. See
1965 centralized SCM, this operation is a local operation. See
1966 :hg:`push` for a way to actively distribute your changes.
1966 :hg:`push` for a way to actively distribute your changes.
1967
1967
1968 If a list of files is omitted, all changes reported by :hg:`status`
1968 If a list of files is omitted, all changes reported by :hg:`status`
1969 will be committed.
1969 will be committed.
1970
1970
1971 If you are committing the result of a merge, do not provide any
1971 If you are committing the result of a merge, do not provide any
1972 filenames or -I/-X filters.
1972 filenames or -I/-X filters.
1973
1973
1974 If no commit message is specified, Mercurial starts your
1974 If no commit message is specified, Mercurial starts your
1975 configured editor where you can enter a message. In case your
1975 configured editor where you can enter a message. In case your
1976 commit fails, you will find a backup of your message in
1976 commit fails, you will find a backup of your message in
1977 ``.hg/last-message.txt``.
1977 ``.hg/last-message.txt``.
1978
1978
1979 The --close-branch flag can be used to mark the current branch
1979 The --close-branch flag can be used to mark the current branch
1980 head closed. When all heads of a branch are closed, the branch
1980 head closed. When all heads of a branch are closed, the branch
1981 will be considered closed and no longer listed.
1981 will be considered closed and no longer listed.
1982
1982
1983 The --amend flag can be used to amend the parent of the
1983 The --amend flag can be used to amend the parent of the
1984 working directory with a new commit that contains the changes
1984 working directory with a new commit that contains the changes
1985 in the parent in addition to those currently reported by :hg:`status`,
1985 in the parent in addition to those currently reported by :hg:`status`,
1986 if there are any. The old commit is stored in a backup bundle in
1986 if there are any. The old commit is stored in a backup bundle in
1987 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1987 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1988 on how to restore it).
1988 on how to restore it).
1989
1989
1990 Message, user and date are taken from the amended commit unless
1990 Message, user and date are taken from the amended commit unless
1991 specified. When a message isn't specified on the command line,
1991 specified. When a message isn't specified on the command line,
1992 the editor will open with the message of the amended commit.
1992 the editor will open with the message of the amended commit.
1993
1993
1994 It is not possible to amend public changesets (see :hg:`help phases`)
1994 It is not possible to amend public changesets (see :hg:`help phases`)
1995 or changesets that have children.
1995 or changesets that have children.
1996
1996
1997 See :hg:`help dates` for a list of formats valid for -d/--date.
1997 See :hg:`help dates` for a list of formats valid for -d/--date.
1998
1998
1999 Returns 0 on success, 1 if nothing changed.
1999 Returns 0 on success, 1 if nothing changed.
2000
2000
2001 .. container:: verbose
2001 .. container:: verbose
2002
2002
2003 Examples:
2003 Examples:
2004
2004
2005 - commit all files ending in .py::
2005 - commit all files ending in .py::
2006
2006
2007 hg commit --include "set:**.py"
2007 hg commit --include "set:**.py"
2008
2008
2009 - commit all non-binary files::
2009 - commit all non-binary files::
2010
2010
2011 hg commit --exclude "set:binary()"
2011 hg commit --exclude "set:binary()"
2012
2012
2013 - amend the current commit and set the date to now::
2013 - amend the current commit and set the date to now::
2014
2014
2015 hg commit --amend --date now
2015 hg commit --amend --date now
2016 """
2016 """
2017 with repo.wlock(), repo.lock():
2017 with repo.wlock(), repo.lock():
2018 return _docommit(ui, repo, *pats, **opts)
2018 return _docommit(ui, repo, *pats, **opts)
2019
2019
2020
2020
2021 def _docommit(ui, repo, *pats, **opts):
2021 def _docommit(ui, repo, *pats, **opts):
2022 if opts.get(r'interactive'):
2022 if opts.get(r'interactive'):
2023 opts.pop(r'interactive')
2023 opts.pop(r'interactive')
2024 ret = cmdutil.dorecord(
2024 ret = cmdutil.dorecord(
2025 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2025 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2026 )
2026 )
2027 # ret can be 0 (no changes to record) or the value returned by
2027 # ret can be 0 (no changes to record) or the value returned by
2028 # commit(), 1 if nothing changed or None on success.
2028 # commit(), 1 if nothing changed or None on success.
2029 return 1 if ret == 0 else ret
2029 return 1 if ret == 0 else ret
2030
2030
2031 opts = pycompat.byteskwargs(opts)
2031 opts = pycompat.byteskwargs(opts)
2032 if opts.get(b'subrepos'):
2032 if opts.get(b'subrepos'):
2033 if opts.get(b'amend'):
2033 if opts.get(b'amend'):
2034 raise error.Abort(_(b'cannot amend with --subrepos'))
2034 raise error.Abort(_(b'cannot amend with --subrepos'))
2035 # Let --subrepos on the command line override config setting.
2035 # Let --subrepos on the command line override config setting.
2036 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2036 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2037
2037
2038 cmdutil.checkunfinished(repo, commit=True)
2038 cmdutil.checkunfinished(repo, commit=True)
2039
2039
2040 branch = repo[None].branch()
2040 branch = repo[None].branch()
2041 bheads = repo.branchheads(branch)
2041 bheads = repo.branchheads(branch)
2042
2042
2043 extra = {}
2043 extra = {}
2044 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2044 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2045 extra[b'close'] = b'1'
2045 extra[b'close'] = b'1'
2046
2046
2047 if repo[b'.'].closesbranch():
2047 if repo[b'.'].closesbranch():
2048 raise error.Abort(
2048 raise error.Abort(
2049 _(b'current revision is already a branch closing head')
2049 _(b'current revision is already a branch closing head')
2050 )
2050 )
2051 elif not bheads:
2051 elif not bheads:
2052 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2052 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2053 elif (
2053 elif (
2054 branch == repo[b'.'].branch()
2054 branch == repo[b'.'].branch()
2055 and repo[b'.'].node() not in bheads
2055 and repo[b'.'].node() not in bheads
2056 and not opts.get(b'force_close_branch')
2056 and not opts.get(b'force_close_branch')
2057 ):
2057 ):
2058 hint = _(
2058 hint = _(
2059 b'use --force-close-branch to close branch from a non-head'
2059 b'use --force-close-branch to close branch from a non-head'
2060 b' changeset'
2060 b' changeset'
2061 )
2061 )
2062 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2062 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2063 elif opts.get(b'amend'):
2063 elif opts.get(b'amend'):
2064 if (
2064 if (
2065 repo[b'.'].p1().branch() != branch
2065 repo[b'.'].p1().branch() != branch
2066 and repo[b'.'].p2().branch() != branch
2066 and repo[b'.'].p2().branch() != branch
2067 ):
2067 ):
2068 raise error.Abort(_(b'can only close branch heads'))
2068 raise error.Abort(_(b'can only close branch heads'))
2069
2069
2070 if opts.get(b'amend'):
2070 if opts.get(b'amend'):
2071 if ui.configbool(b'ui', b'commitsubrepos'):
2071 if ui.configbool(b'ui', b'commitsubrepos'):
2072 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2072 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2073
2073
2074 old = repo[b'.']
2074 old = repo[b'.']
2075 rewriteutil.precheck(repo, [old.rev()], b'amend')
2075 rewriteutil.precheck(repo, [old.rev()], b'amend')
2076
2076
2077 # Currently histedit gets confused if an amend happens while histedit
2077 # Currently histedit gets confused if an amend happens while histedit
2078 # is in progress. Since we have a checkunfinished command, we are
2078 # is in progress. Since we have a checkunfinished command, we are
2079 # temporarily honoring it.
2079 # temporarily honoring it.
2080 #
2080 #
2081 # Note: eventually this guard will be removed. Please do not expect
2081 # Note: eventually this guard will be removed. Please do not expect
2082 # this behavior to remain.
2082 # this behavior to remain.
2083 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2083 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2084 cmdutil.checkunfinished(repo)
2084 cmdutil.checkunfinished(repo)
2085
2085
2086 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2086 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2087 if node == old.node():
2087 if node == old.node():
2088 ui.status(_(b"nothing changed\n"))
2088 ui.status(_(b"nothing changed\n"))
2089 return 1
2089 return 1
2090 else:
2090 else:
2091
2091
2092 def commitfunc(ui, repo, message, match, opts):
2092 def commitfunc(ui, repo, message, match, opts):
2093 overrides = {}
2093 overrides = {}
2094 if opts.get(b'secret'):
2094 if opts.get(b'secret'):
2095 overrides[(b'phases', b'new-commit')] = b'secret'
2095 overrides[(b'phases', b'new-commit')] = b'secret'
2096
2096
2097 baseui = repo.baseui
2097 baseui = repo.baseui
2098 with baseui.configoverride(overrides, b'commit'):
2098 with baseui.configoverride(overrides, b'commit'):
2099 with ui.configoverride(overrides, b'commit'):
2099 with ui.configoverride(overrides, b'commit'):
2100 editform = cmdutil.mergeeditform(
2100 editform = cmdutil.mergeeditform(
2101 repo[None], b'commit.normal'
2101 repo[None], b'commit.normal'
2102 )
2102 )
2103 editor = cmdutil.getcommiteditor(
2103 editor = cmdutil.getcommiteditor(
2104 editform=editform, **pycompat.strkwargs(opts)
2104 editform=editform, **pycompat.strkwargs(opts)
2105 )
2105 )
2106 return repo.commit(
2106 return repo.commit(
2107 message,
2107 message,
2108 opts.get(b'user'),
2108 opts.get(b'user'),
2109 opts.get(b'date'),
2109 opts.get(b'date'),
2110 match,
2110 match,
2111 editor=editor,
2111 editor=editor,
2112 extra=extra,
2112 extra=extra,
2113 )
2113 )
2114
2114
2115 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2115 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2116
2116
2117 if not node:
2117 if not node:
2118 stat = cmdutil.postcommitstatus(repo, pats, opts)
2118 stat = cmdutil.postcommitstatus(repo, pats, opts)
2119 if stat[3]:
2119 if stat[3]:
2120 ui.status(
2120 ui.status(
2121 _(
2121 _(
2122 b"nothing changed (%d missing files, see "
2122 b"nothing changed (%d missing files, see "
2123 b"'hg status')\n"
2123 b"'hg status')\n"
2124 )
2124 )
2125 % len(stat[3])
2125 % len(stat[3])
2126 )
2126 )
2127 else:
2127 else:
2128 ui.status(_(b"nothing changed\n"))
2128 ui.status(_(b"nothing changed\n"))
2129 return 1
2129 return 1
2130
2130
2131 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2131 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2132
2132
2133 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2133 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2134 status(
2134 status(
2135 ui,
2135 ui,
2136 repo,
2136 repo,
2137 modified=True,
2137 modified=True,
2138 added=True,
2138 added=True,
2139 removed=True,
2139 removed=True,
2140 deleted=True,
2140 deleted=True,
2141 unknown=True,
2141 unknown=True,
2142 subrepos=opts.get(b'subrepos'),
2142 subrepos=opts.get(b'subrepos'),
2143 )
2143 )
2144
2144
2145
2145
2146 @command(
2146 @command(
2147 b'config|showconfig|debugconfig',
2147 b'config|showconfig|debugconfig',
2148 [
2148 [
2149 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2149 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2150 (b'e', b'edit', None, _(b'edit user config')),
2150 (b'e', b'edit', None, _(b'edit user config')),
2151 (b'l', b'local', None, _(b'edit repository config')),
2151 (b'l', b'local', None, _(b'edit repository config')),
2152 (b'g', b'global', None, _(b'edit global config')),
2152 (b'g', b'global', None, _(b'edit global config')),
2153 ]
2153 ]
2154 + formatteropts,
2154 + formatteropts,
2155 _(b'[-u] [NAME]...'),
2155 _(b'[-u] [NAME]...'),
2156 helpcategory=command.CATEGORY_HELP,
2156 helpcategory=command.CATEGORY_HELP,
2157 optionalrepo=True,
2157 optionalrepo=True,
2158 intents={INTENT_READONLY},
2158 intents={INTENT_READONLY},
2159 )
2159 )
2160 def config(ui, repo, *values, **opts):
2160 def config(ui, repo, *values, **opts):
2161 """show combined config settings from all hgrc files
2161 """show combined config settings from all hgrc files
2162
2162
2163 With no arguments, print names and values of all config items.
2163 With no arguments, print names and values of all config items.
2164
2164
2165 With one argument of the form section.name, print just the value
2165 With one argument of the form section.name, print just the value
2166 of that config item.
2166 of that config item.
2167
2167
2168 With multiple arguments, print names and values of all config
2168 With multiple arguments, print names and values of all config
2169 items with matching section names or section.names.
2169 items with matching section names or section.names.
2170
2170
2171 With --edit, start an editor on the user-level config file. With
2171 With --edit, start an editor on the user-level config file. With
2172 --global, edit the system-wide config file. With --local, edit the
2172 --global, edit the system-wide config file. With --local, edit the
2173 repository-level config file.
2173 repository-level config file.
2174
2174
2175 With --debug, the source (filename and line number) is printed
2175 With --debug, the source (filename and line number) is printed
2176 for each config item.
2176 for each config item.
2177
2177
2178 See :hg:`help config` for more information about config files.
2178 See :hg:`help config` for more information about config files.
2179
2179
2180 .. container:: verbose
2180 .. container:: verbose
2181
2181
2182 Template:
2182 Template:
2183
2183
2184 The following keywords are supported. See also :hg:`help templates`.
2184 The following keywords are supported. See also :hg:`help templates`.
2185
2185
2186 :name: String. Config name.
2186 :name: String. Config name.
2187 :source: String. Filename and line number where the item is defined.
2187 :source: String. Filename and line number where the item is defined.
2188 :value: String. Config value.
2188 :value: String. Config value.
2189
2189
2190 Returns 0 on success, 1 if NAME does not exist.
2190 Returns 0 on success, 1 if NAME does not exist.
2191
2191
2192 """
2192 """
2193
2193
2194 opts = pycompat.byteskwargs(opts)
2194 opts = pycompat.byteskwargs(opts)
2195 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2195 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2196 if opts.get(b'local') and opts.get(b'global'):
2196 if opts.get(b'local') and opts.get(b'global'):
2197 raise error.Abort(_(b"can't use --local and --global together"))
2197 raise error.Abort(_(b"can't use --local and --global together"))
2198
2198
2199 if opts.get(b'local'):
2199 if opts.get(b'local'):
2200 if not repo:
2200 if not repo:
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2202 paths = [repo.vfs.join(b'hgrc')]
2202 paths = [repo.vfs.join(b'hgrc')]
2203 elif opts.get(b'global'):
2203 elif opts.get(b'global'):
2204 paths = rcutil.systemrcpath()
2204 paths = rcutil.systemrcpath()
2205 else:
2205 else:
2206 paths = rcutil.userrcpath()
2206 paths = rcutil.userrcpath()
2207
2207
2208 for f in paths:
2208 for f in paths:
2209 if os.path.exists(f):
2209 if os.path.exists(f):
2210 break
2210 break
2211 else:
2211 else:
2212 if opts.get(b'global'):
2212 if opts.get(b'global'):
2213 samplehgrc = uimod.samplehgrcs[b'global']
2213 samplehgrc = uimod.samplehgrcs[b'global']
2214 elif opts.get(b'local'):
2214 elif opts.get(b'local'):
2215 samplehgrc = uimod.samplehgrcs[b'local']
2215 samplehgrc = uimod.samplehgrcs[b'local']
2216 else:
2216 else:
2217 samplehgrc = uimod.samplehgrcs[b'user']
2217 samplehgrc = uimod.samplehgrcs[b'user']
2218
2218
2219 f = paths[0]
2219 f = paths[0]
2220 fp = open(f, b"wb")
2220 fp = open(f, b"wb")
2221 fp.write(util.tonativeeol(samplehgrc))
2221 fp.write(util.tonativeeol(samplehgrc))
2222 fp.close()
2222 fp.close()
2223
2223
2224 editor = ui.geteditor()
2224 editor = ui.geteditor()
2225 ui.system(
2225 ui.system(
2226 b"%s \"%s\"" % (editor, f),
2226 b"%s \"%s\"" % (editor, f),
2227 onerr=error.Abort,
2227 onerr=error.Abort,
2228 errprefix=_(b"edit failed"),
2228 errprefix=_(b"edit failed"),
2229 blockedtag=b'config_edit',
2229 blockedtag=b'config_edit',
2230 )
2230 )
2231 return
2231 return
2232 ui.pager(b'config')
2232 ui.pager(b'config')
2233 fm = ui.formatter(b'config', opts)
2233 fm = ui.formatter(b'config', opts)
2234 for t, f in rcutil.rccomponents():
2234 for t, f in rcutil.rccomponents():
2235 if t == b'path':
2235 if t == b'path':
2236 ui.debug(b'read config from: %s\n' % f)
2236 ui.debug(b'read config from: %s\n' % f)
2237 elif t == b'items':
2237 elif t == b'items':
2238 for section, name, value, source in f:
2238 for section, name, value, source in f:
2239 ui.debug(b'set config by: %s\n' % source)
2239 ui.debug(b'set config by: %s\n' % source)
2240 else:
2240 else:
2241 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2241 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2242 untrusted = bool(opts.get(b'untrusted'))
2242 untrusted = bool(opts.get(b'untrusted'))
2243
2243
2244 selsections = selentries = []
2244 selsections = selentries = []
2245 if values:
2245 if values:
2246 selsections = [v for v in values if b'.' not in v]
2246 selsections = [v for v in values if b'.' not in v]
2247 selentries = [v for v in values if b'.' in v]
2247 selentries = [v for v in values if b'.' in v]
2248 uniquesel = len(selentries) == 1 and not selsections
2248 uniquesel = len(selentries) == 1 and not selsections
2249 selsections = set(selsections)
2249 selsections = set(selsections)
2250 selentries = set(selentries)
2250 selentries = set(selentries)
2251
2251
2252 matched = False
2252 matched = False
2253 for section, name, value in ui.walkconfig(untrusted=untrusted):
2253 for section, name, value in ui.walkconfig(untrusted=untrusted):
2254 source = ui.configsource(section, name, untrusted)
2254 source = ui.configsource(section, name, untrusted)
2255 value = pycompat.bytestr(value)
2255 value = pycompat.bytestr(value)
2256 defaultvalue = ui.configdefault(section, name)
2256 defaultvalue = ui.configdefault(section, name)
2257 if fm.isplain():
2257 if fm.isplain():
2258 source = source or b'none'
2258 source = source or b'none'
2259 value = value.replace(b'\n', b'\\n')
2259 value = value.replace(b'\n', b'\\n')
2260 entryname = section + b'.' + name
2260 entryname = section + b'.' + name
2261 if values and not (section in selsections or entryname in selentries):
2261 if values and not (section in selsections or entryname in selentries):
2262 continue
2262 continue
2263 fm.startitem()
2263 fm.startitem()
2264 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2264 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2265 if uniquesel:
2265 if uniquesel:
2266 fm.data(name=entryname)
2266 fm.data(name=entryname)
2267 fm.write(b'value', b'%s\n', value)
2267 fm.write(b'value', b'%s\n', value)
2268 else:
2268 else:
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2270 if formatter.isprintable(defaultvalue):
2270 if formatter.isprintable(defaultvalue):
2271 fm.data(defaultvalue=defaultvalue)
2271 fm.data(defaultvalue=defaultvalue)
2272 elif isinstance(defaultvalue, list) and all(
2273 formatter.isprintable(e) for e in defaultvalue
2274 ):
2275 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2272 # TODO: no idea how to process unsupported defaultvalue types
2276 # TODO: no idea how to process unsupported defaultvalue types
2273 matched = True
2277 matched = True
2274 fm.end()
2278 fm.end()
2275 if matched:
2279 if matched:
2276 return 0
2280 return 0
2277 return 1
2281 return 1
2278
2282
2279
2283
2280 @command(
2284 @command(
2281 b'continue',
2285 b'continue',
2282 dryrunopts,
2286 dryrunopts,
2283 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2287 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2284 helpbasic=True,
2288 helpbasic=True,
2285 )
2289 )
2286 def continuecmd(ui, repo, **opts):
2290 def continuecmd(ui, repo, **opts):
2287 """resumes an interrupted operation (EXPERIMENTAL)
2291 """resumes an interrupted operation (EXPERIMENTAL)
2288
2292
2289 Finishes a multistep operation like graft, histedit, rebase, merge,
2293 Finishes a multistep operation like graft, histedit, rebase, merge,
2290 and unshelve if they are in an interrupted state.
2294 and unshelve if they are in an interrupted state.
2291
2295
2292 use --dry-run/-n to dry run the command.
2296 use --dry-run/-n to dry run the command.
2293 """
2297 """
2294 dryrun = opts.get(r'dry_run')
2298 dryrun = opts.get(r'dry_run')
2295 contstate = cmdutil.getunfinishedstate(repo)
2299 contstate = cmdutil.getunfinishedstate(repo)
2296 if not contstate:
2300 if not contstate:
2297 raise error.Abort(_(b'no operation in progress'))
2301 raise error.Abort(_(b'no operation in progress'))
2298 if not contstate.continuefunc:
2302 if not contstate.continuefunc:
2299 raise error.Abort(
2303 raise error.Abort(
2300 (
2304 (
2301 _(b"%s in progress but does not support 'hg continue'")
2305 _(b"%s in progress but does not support 'hg continue'")
2302 % (contstate._opname)
2306 % (contstate._opname)
2303 ),
2307 ),
2304 hint=contstate.continuemsg(),
2308 hint=contstate.continuemsg(),
2305 )
2309 )
2306 if dryrun:
2310 if dryrun:
2307 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2311 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2308 return
2312 return
2309 return contstate.continuefunc(ui, repo)
2313 return contstate.continuefunc(ui, repo)
2310
2314
2311
2315
2312 @command(
2316 @command(
2313 b'copy|cp',
2317 b'copy|cp',
2314 [
2318 [
2315 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2319 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2316 (
2320 (
2317 b'f',
2321 b'f',
2318 b'force',
2322 b'force',
2319 None,
2323 None,
2320 _(b'forcibly copy over an existing managed file'),
2324 _(b'forcibly copy over an existing managed file'),
2321 ),
2325 ),
2322 ]
2326 ]
2323 + walkopts
2327 + walkopts
2324 + dryrunopts,
2328 + dryrunopts,
2325 _(b'[OPTION]... SOURCE... DEST'),
2329 _(b'[OPTION]... SOURCE... DEST'),
2326 helpcategory=command.CATEGORY_FILE_CONTENTS,
2330 helpcategory=command.CATEGORY_FILE_CONTENTS,
2327 )
2331 )
2328 def copy(ui, repo, *pats, **opts):
2332 def copy(ui, repo, *pats, **opts):
2329 """mark files as copied for the next commit
2333 """mark files as copied for the next commit
2330
2334
2331 Mark dest as having copies of source files. If dest is a
2335 Mark dest as having copies of source files. If dest is a
2332 directory, copies are put in that directory. If dest is a file,
2336 directory, copies are put in that directory. If dest is a file,
2333 the source must be a single file.
2337 the source must be a single file.
2334
2338
2335 By default, this command copies the contents of files as they
2339 By default, this command copies the contents of files as they
2336 exist in the working directory. If invoked with -A/--after, the
2340 exist in the working directory. If invoked with -A/--after, the
2337 operation is recorded, but no copying is performed.
2341 operation is recorded, but no copying is performed.
2338
2342
2339 This command takes effect with the next commit. To undo a copy
2343 This command takes effect with the next commit. To undo a copy
2340 before that, see :hg:`revert`.
2344 before that, see :hg:`revert`.
2341
2345
2342 Returns 0 on success, 1 if errors are encountered.
2346 Returns 0 on success, 1 if errors are encountered.
2343 """
2347 """
2344 opts = pycompat.byteskwargs(opts)
2348 opts = pycompat.byteskwargs(opts)
2345 with repo.wlock(False):
2349 with repo.wlock(False):
2346 return cmdutil.copy(ui, repo, pats, opts)
2350 return cmdutil.copy(ui, repo, pats, opts)
2347
2351
2348
2352
2349 @command(
2353 @command(
2350 b'debugcommands',
2354 b'debugcommands',
2351 [],
2355 [],
2352 _(b'[COMMAND]'),
2356 _(b'[COMMAND]'),
2353 helpcategory=command.CATEGORY_HELP,
2357 helpcategory=command.CATEGORY_HELP,
2354 norepo=True,
2358 norepo=True,
2355 )
2359 )
2356 def debugcommands(ui, cmd=b'', *args):
2360 def debugcommands(ui, cmd=b'', *args):
2357 """list all available commands and options"""
2361 """list all available commands and options"""
2358 for cmd, vals in sorted(pycompat.iteritems(table)):
2362 for cmd, vals in sorted(pycompat.iteritems(table)):
2359 cmd = cmd.split(b'|')[0]
2363 cmd = cmd.split(b'|')[0]
2360 opts = b', '.join([i[1] for i in vals[1]])
2364 opts = b', '.join([i[1] for i in vals[1]])
2361 ui.write(b'%s: %s\n' % (cmd, opts))
2365 ui.write(b'%s: %s\n' % (cmd, opts))
2362
2366
2363
2367
2364 @command(
2368 @command(
2365 b'debugcomplete',
2369 b'debugcomplete',
2366 [(b'o', b'options', None, _(b'show the command options'))],
2370 [(b'o', b'options', None, _(b'show the command options'))],
2367 _(b'[-o] CMD'),
2371 _(b'[-o] CMD'),
2368 helpcategory=command.CATEGORY_HELP,
2372 helpcategory=command.CATEGORY_HELP,
2369 norepo=True,
2373 norepo=True,
2370 )
2374 )
2371 def debugcomplete(ui, cmd=b'', **opts):
2375 def debugcomplete(ui, cmd=b'', **opts):
2372 """returns the completion list associated with the given command"""
2376 """returns the completion list associated with the given command"""
2373
2377
2374 if opts.get(r'options'):
2378 if opts.get(r'options'):
2375 options = []
2379 options = []
2376 otables = [globalopts]
2380 otables = [globalopts]
2377 if cmd:
2381 if cmd:
2378 aliases, entry = cmdutil.findcmd(cmd, table, False)
2382 aliases, entry = cmdutil.findcmd(cmd, table, False)
2379 otables.append(entry[1])
2383 otables.append(entry[1])
2380 for t in otables:
2384 for t in otables:
2381 for o in t:
2385 for o in t:
2382 if b"(DEPRECATED)" in o[3]:
2386 if b"(DEPRECATED)" in o[3]:
2383 continue
2387 continue
2384 if o[0]:
2388 if o[0]:
2385 options.append(b'-%s' % o[0])
2389 options.append(b'-%s' % o[0])
2386 options.append(b'--%s' % o[1])
2390 options.append(b'--%s' % o[1])
2387 ui.write(b"%s\n" % b"\n".join(options))
2391 ui.write(b"%s\n" % b"\n".join(options))
2388 return
2392 return
2389
2393
2390 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2394 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2391 if ui.verbose:
2395 if ui.verbose:
2392 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2396 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2393 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2397 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2394
2398
2395
2399
2396 @command(
2400 @command(
2397 b'diff',
2401 b'diff',
2398 [
2402 [
2399 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2403 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2400 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2404 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2401 ]
2405 ]
2402 + diffopts
2406 + diffopts
2403 + diffopts2
2407 + diffopts2
2404 + walkopts
2408 + walkopts
2405 + subrepoopts,
2409 + subrepoopts,
2406 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2410 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2407 helpcategory=command.CATEGORY_FILE_CONTENTS,
2411 helpcategory=command.CATEGORY_FILE_CONTENTS,
2408 helpbasic=True,
2412 helpbasic=True,
2409 inferrepo=True,
2413 inferrepo=True,
2410 intents={INTENT_READONLY},
2414 intents={INTENT_READONLY},
2411 )
2415 )
2412 def diff(ui, repo, *pats, **opts):
2416 def diff(ui, repo, *pats, **opts):
2413 """diff repository (or selected files)
2417 """diff repository (or selected files)
2414
2418
2415 Show differences between revisions for the specified files.
2419 Show differences between revisions for the specified files.
2416
2420
2417 Differences between files are shown using the unified diff format.
2421 Differences between files are shown using the unified diff format.
2418
2422
2419 .. note::
2423 .. note::
2420
2424
2421 :hg:`diff` may generate unexpected results for merges, as it will
2425 :hg:`diff` may generate unexpected results for merges, as it will
2422 default to comparing against the working directory's first
2426 default to comparing against the working directory's first
2423 parent changeset if no revisions are specified.
2427 parent changeset if no revisions are specified.
2424
2428
2425 When two revision arguments are given, then changes are shown
2429 When two revision arguments are given, then changes are shown
2426 between those revisions. If only one revision is specified then
2430 between those revisions. If only one revision is specified then
2427 that revision is compared to the working directory, and, when no
2431 that revision is compared to the working directory, and, when no
2428 revisions are specified, the working directory files are compared
2432 revisions are specified, the working directory files are compared
2429 to its first parent.
2433 to its first parent.
2430
2434
2431 Alternatively you can specify -c/--change with a revision to see
2435 Alternatively you can specify -c/--change with a revision to see
2432 the changes in that changeset relative to its first parent.
2436 the changes in that changeset relative to its first parent.
2433
2437
2434 Without the -a/--text option, diff will avoid generating diffs of
2438 Without the -a/--text option, diff will avoid generating diffs of
2435 files it detects as binary. With -a, diff will generate a diff
2439 files it detects as binary. With -a, diff will generate a diff
2436 anyway, probably with undesirable results.
2440 anyway, probably with undesirable results.
2437
2441
2438 Use the -g/--git option to generate diffs in the git extended diff
2442 Use the -g/--git option to generate diffs in the git extended diff
2439 format. For more information, read :hg:`help diffs`.
2443 format. For more information, read :hg:`help diffs`.
2440
2444
2441 .. container:: verbose
2445 .. container:: verbose
2442
2446
2443 Examples:
2447 Examples:
2444
2448
2445 - compare a file in the current working directory to its parent::
2449 - compare a file in the current working directory to its parent::
2446
2450
2447 hg diff foo.c
2451 hg diff foo.c
2448
2452
2449 - compare two historical versions of a directory, with rename info::
2453 - compare two historical versions of a directory, with rename info::
2450
2454
2451 hg diff --git -r 1.0:1.2 lib/
2455 hg diff --git -r 1.0:1.2 lib/
2452
2456
2453 - get change stats relative to the last change on some date::
2457 - get change stats relative to the last change on some date::
2454
2458
2455 hg diff --stat -r "date('may 2')"
2459 hg diff --stat -r "date('may 2')"
2456
2460
2457 - diff all newly-added files that contain a keyword::
2461 - diff all newly-added files that contain a keyword::
2458
2462
2459 hg diff "set:added() and grep(GNU)"
2463 hg diff "set:added() and grep(GNU)"
2460
2464
2461 - compare a revision and its parents::
2465 - compare a revision and its parents::
2462
2466
2463 hg diff -c 9353 # compare against first parent
2467 hg diff -c 9353 # compare against first parent
2464 hg diff -r 9353^:9353 # same using revset syntax
2468 hg diff -r 9353^:9353 # same using revset syntax
2465 hg diff -r 9353^2:9353 # compare against the second parent
2469 hg diff -r 9353^2:9353 # compare against the second parent
2466
2470
2467 Returns 0 on success.
2471 Returns 0 on success.
2468 """
2472 """
2469
2473
2470 opts = pycompat.byteskwargs(opts)
2474 opts = pycompat.byteskwargs(opts)
2471 revs = opts.get(b'rev')
2475 revs = opts.get(b'rev')
2472 change = opts.get(b'change')
2476 change = opts.get(b'change')
2473 stat = opts.get(b'stat')
2477 stat = opts.get(b'stat')
2474 reverse = opts.get(b'reverse')
2478 reverse = opts.get(b'reverse')
2475
2479
2476 if revs and change:
2480 if revs and change:
2477 msg = _(b'cannot specify --rev and --change at the same time')
2481 msg = _(b'cannot specify --rev and --change at the same time')
2478 raise error.Abort(msg)
2482 raise error.Abort(msg)
2479 elif change:
2483 elif change:
2480 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2484 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2481 ctx2 = scmutil.revsingle(repo, change, None)
2485 ctx2 = scmutil.revsingle(repo, change, None)
2482 ctx1 = ctx2.p1()
2486 ctx1 = ctx2.p1()
2483 else:
2487 else:
2484 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2488 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2485 ctx1, ctx2 = scmutil.revpair(repo, revs)
2489 ctx1, ctx2 = scmutil.revpair(repo, revs)
2486 node1, node2 = ctx1.node(), ctx2.node()
2490 node1, node2 = ctx1.node(), ctx2.node()
2487
2491
2488 if reverse:
2492 if reverse:
2489 node1, node2 = node2, node1
2493 node1, node2 = node2, node1
2490
2494
2491 diffopts = patch.diffallopts(ui, opts)
2495 diffopts = patch.diffallopts(ui, opts)
2492 m = scmutil.match(ctx2, pats, opts)
2496 m = scmutil.match(ctx2, pats, opts)
2493 m = repo.narrowmatch(m)
2497 m = repo.narrowmatch(m)
2494 ui.pager(b'diff')
2498 ui.pager(b'diff')
2495 logcmdutil.diffordiffstat(
2499 logcmdutil.diffordiffstat(
2496 ui,
2500 ui,
2497 repo,
2501 repo,
2498 diffopts,
2502 diffopts,
2499 node1,
2503 node1,
2500 node2,
2504 node2,
2501 m,
2505 m,
2502 stat=stat,
2506 stat=stat,
2503 listsubrepos=opts.get(b'subrepos'),
2507 listsubrepos=opts.get(b'subrepos'),
2504 root=opts.get(b'root'),
2508 root=opts.get(b'root'),
2505 )
2509 )
2506
2510
2507
2511
2508 @command(
2512 @command(
2509 b'export',
2513 b'export',
2510 [
2514 [
2511 (
2515 (
2512 b'B',
2516 b'B',
2513 b'bookmark',
2517 b'bookmark',
2514 b'',
2518 b'',
2515 _(b'export changes only reachable by given bookmark'),
2519 _(b'export changes only reachable by given bookmark'),
2516 _(b'BOOKMARK'),
2520 _(b'BOOKMARK'),
2517 ),
2521 ),
2518 (
2522 (
2519 b'o',
2523 b'o',
2520 b'output',
2524 b'output',
2521 b'',
2525 b'',
2522 _(b'print output to file with formatted name'),
2526 _(b'print output to file with formatted name'),
2523 _(b'FORMAT'),
2527 _(b'FORMAT'),
2524 ),
2528 ),
2525 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2529 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2526 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2530 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2527 ]
2531 ]
2528 + diffopts
2532 + diffopts
2529 + formatteropts,
2533 + formatteropts,
2530 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2534 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2531 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2535 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2532 helpbasic=True,
2536 helpbasic=True,
2533 intents={INTENT_READONLY},
2537 intents={INTENT_READONLY},
2534 )
2538 )
2535 def export(ui, repo, *changesets, **opts):
2539 def export(ui, repo, *changesets, **opts):
2536 """dump the header and diffs for one or more changesets
2540 """dump the header and diffs for one or more changesets
2537
2541
2538 Print the changeset header and diffs for one or more revisions.
2542 Print the changeset header and diffs for one or more revisions.
2539 If no revision is given, the parent of the working directory is used.
2543 If no revision is given, the parent of the working directory is used.
2540
2544
2541 The information shown in the changeset header is: author, date,
2545 The information shown in the changeset header is: author, date,
2542 branch name (if non-default), changeset hash, parent(s) and commit
2546 branch name (if non-default), changeset hash, parent(s) and commit
2543 comment.
2547 comment.
2544
2548
2545 .. note::
2549 .. note::
2546
2550
2547 :hg:`export` may generate unexpected diff output for merge
2551 :hg:`export` may generate unexpected diff output for merge
2548 changesets, as it will compare the merge changeset against its
2552 changesets, as it will compare the merge changeset against its
2549 first parent only.
2553 first parent only.
2550
2554
2551 Output may be to a file, in which case the name of the file is
2555 Output may be to a file, in which case the name of the file is
2552 given using a template string. See :hg:`help templates`. In addition
2556 given using a template string. See :hg:`help templates`. In addition
2553 to the common template keywords, the following formatting rules are
2557 to the common template keywords, the following formatting rules are
2554 supported:
2558 supported:
2555
2559
2556 :``%%``: literal "%" character
2560 :``%%``: literal "%" character
2557 :``%H``: changeset hash (40 hexadecimal digits)
2561 :``%H``: changeset hash (40 hexadecimal digits)
2558 :``%N``: number of patches being generated
2562 :``%N``: number of patches being generated
2559 :``%R``: changeset revision number
2563 :``%R``: changeset revision number
2560 :``%b``: basename of the exporting repository
2564 :``%b``: basename of the exporting repository
2561 :``%h``: short-form changeset hash (12 hexadecimal digits)
2565 :``%h``: short-form changeset hash (12 hexadecimal digits)
2562 :``%m``: first line of the commit message (only alphanumeric characters)
2566 :``%m``: first line of the commit message (only alphanumeric characters)
2563 :``%n``: zero-padded sequence number, starting at 1
2567 :``%n``: zero-padded sequence number, starting at 1
2564 :``%r``: zero-padded changeset revision number
2568 :``%r``: zero-padded changeset revision number
2565 :``\\``: literal "\\" character
2569 :``\\``: literal "\\" character
2566
2570
2567 Without the -a/--text option, export will avoid generating diffs
2571 Without the -a/--text option, export will avoid generating diffs
2568 of files it detects as binary. With -a, export will generate a
2572 of files it detects as binary. With -a, export will generate a
2569 diff anyway, probably with undesirable results.
2573 diff anyway, probably with undesirable results.
2570
2574
2571 With -B/--bookmark changesets reachable by the given bookmark are
2575 With -B/--bookmark changesets reachable by the given bookmark are
2572 selected.
2576 selected.
2573
2577
2574 Use the -g/--git option to generate diffs in the git extended diff
2578 Use the -g/--git option to generate diffs in the git extended diff
2575 format. See :hg:`help diffs` for more information.
2579 format. See :hg:`help diffs` for more information.
2576
2580
2577 With the --switch-parent option, the diff will be against the
2581 With the --switch-parent option, the diff will be against the
2578 second parent. It can be useful to review a merge.
2582 second parent. It can be useful to review a merge.
2579
2583
2580 .. container:: verbose
2584 .. container:: verbose
2581
2585
2582 Template:
2586 Template:
2583
2587
2584 The following keywords are supported in addition to the common template
2588 The following keywords are supported in addition to the common template
2585 keywords and functions. See also :hg:`help templates`.
2589 keywords and functions. See also :hg:`help templates`.
2586
2590
2587 :diff: String. Diff content.
2591 :diff: String. Diff content.
2588 :parents: List of strings. Parent nodes of the changeset.
2592 :parents: List of strings. Parent nodes of the changeset.
2589
2593
2590 Examples:
2594 Examples:
2591
2595
2592 - use export and import to transplant a bugfix to the current
2596 - use export and import to transplant a bugfix to the current
2593 branch::
2597 branch::
2594
2598
2595 hg export -r 9353 | hg import -
2599 hg export -r 9353 | hg import -
2596
2600
2597 - export all the changesets between two revisions to a file with
2601 - export all the changesets between two revisions to a file with
2598 rename information::
2602 rename information::
2599
2603
2600 hg export --git -r 123:150 > changes.txt
2604 hg export --git -r 123:150 > changes.txt
2601
2605
2602 - split outgoing changes into a series of patches with
2606 - split outgoing changes into a series of patches with
2603 descriptive names::
2607 descriptive names::
2604
2608
2605 hg export -r "outgoing()" -o "%n-%m.patch"
2609 hg export -r "outgoing()" -o "%n-%m.patch"
2606
2610
2607 Returns 0 on success.
2611 Returns 0 on success.
2608 """
2612 """
2609 opts = pycompat.byteskwargs(opts)
2613 opts = pycompat.byteskwargs(opts)
2610 bookmark = opts.get(b'bookmark')
2614 bookmark = opts.get(b'bookmark')
2611 changesets += tuple(opts.get(b'rev', []))
2615 changesets += tuple(opts.get(b'rev', []))
2612
2616
2613 if bookmark and changesets:
2617 if bookmark and changesets:
2614 raise error.Abort(_(b"-r and -B are mutually exclusive"))
2618 raise error.Abort(_(b"-r and -B are mutually exclusive"))
2615
2619
2616 if bookmark:
2620 if bookmark:
2617 if bookmark not in repo._bookmarks:
2621 if bookmark not in repo._bookmarks:
2618 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2622 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2619
2623
2620 revs = scmutil.bookmarkrevs(repo, bookmark)
2624 revs = scmutil.bookmarkrevs(repo, bookmark)
2621 else:
2625 else:
2622 if not changesets:
2626 if not changesets:
2623 changesets = [b'.']
2627 changesets = [b'.']
2624
2628
2625 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2629 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2626 revs = scmutil.revrange(repo, changesets)
2630 revs = scmutil.revrange(repo, changesets)
2627
2631
2628 if not revs:
2632 if not revs:
2629 raise error.Abort(_(b"export requires at least one changeset"))
2633 raise error.Abort(_(b"export requires at least one changeset"))
2630 if len(revs) > 1:
2634 if len(revs) > 1:
2631 ui.note(_(b'exporting patches:\n'))
2635 ui.note(_(b'exporting patches:\n'))
2632 else:
2636 else:
2633 ui.note(_(b'exporting patch:\n'))
2637 ui.note(_(b'exporting patch:\n'))
2634
2638
2635 fntemplate = opts.get(b'output')
2639 fntemplate = opts.get(b'output')
2636 if cmdutil.isstdiofilename(fntemplate):
2640 if cmdutil.isstdiofilename(fntemplate):
2637 fntemplate = b''
2641 fntemplate = b''
2638
2642
2639 if fntemplate:
2643 if fntemplate:
2640 fm = formatter.nullformatter(ui, b'export', opts)
2644 fm = formatter.nullformatter(ui, b'export', opts)
2641 else:
2645 else:
2642 ui.pager(b'export')
2646 ui.pager(b'export')
2643 fm = ui.formatter(b'export', opts)
2647 fm = ui.formatter(b'export', opts)
2644 with fm:
2648 with fm:
2645 cmdutil.export(
2649 cmdutil.export(
2646 repo,
2650 repo,
2647 revs,
2651 revs,
2648 fm,
2652 fm,
2649 fntemplate=fntemplate,
2653 fntemplate=fntemplate,
2650 switch_parent=opts.get(b'switch_parent'),
2654 switch_parent=opts.get(b'switch_parent'),
2651 opts=patch.diffallopts(ui, opts),
2655 opts=patch.diffallopts(ui, opts),
2652 )
2656 )
2653
2657
2654
2658
2655 @command(
2659 @command(
2656 b'files',
2660 b'files',
2657 [
2661 [
2658 (
2662 (
2659 b'r',
2663 b'r',
2660 b'rev',
2664 b'rev',
2661 b'',
2665 b'',
2662 _(b'search the repository as it is in REV'),
2666 _(b'search the repository as it is in REV'),
2663 _(b'REV'),
2667 _(b'REV'),
2664 ),
2668 ),
2665 (
2669 (
2666 b'0',
2670 b'0',
2667 b'print0',
2671 b'print0',
2668 None,
2672 None,
2669 _(b'end filenames with NUL, for use with xargs'),
2673 _(b'end filenames with NUL, for use with xargs'),
2670 ),
2674 ),
2671 ]
2675 ]
2672 + walkopts
2676 + walkopts
2673 + formatteropts
2677 + formatteropts
2674 + subrepoopts,
2678 + subrepoopts,
2675 _(b'[OPTION]... [FILE]...'),
2679 _(b'[OPTION]... [FILE]...'),
2676 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2680 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2677 intents={INTENT_READONLY},
2681 intents={INTENT_READONLY},
2678 )
2682 )
2679 def files(ui, repo, *pats, **opts):
2683 def files(ui, repo, *pats, **opts):
2680 """list tracked files
2684 """list tracked files
2681
2685
2682 Print files under Mercurial control in the working directory or
2686 Print files under Mercurial control in the working directory or
2683 specified revision for given files (excluding removed files).
2687 specified revision for given files (excluding removed files).
2684 Files can be specified as filenames or filesets.
2688 Files can be specified as filenames or filesets.
2685
2689
2686 If no files are given to match, this command prints the names
2690 If no files are given to match, this command prints the names
2687 of all files under Mercurial control.
2691 of all files under Mercurial control.
2688
2692
2689 .. container:: verbose
2693 .. container:: verbose
2690
2694
2691 Template:
2695 Template:
2692
2696
2693 The following keywords are supported in addition to the common template
2697 The following keywords are supported in addition to the common template
2694 keywords and functions. See also :hg:`help templates`.
2698 keywords and functions. See also :hg:`help templates`.
2695
2699
2696 :flags: String. Character denoting file's symlink and executable bits.
2700 :flags: String. Character denoting file's symlink and executable bits.
2697 :path: String. Repository-absolute path of the file.
2701 :path: String. Repository-absolute path of the file.
2698 :size: Integer. Size of the file in bytes.
2702 :size: Integer. Size of the file in bytes.
2699
2703
2700 Examples:
2704 Examples:
2701
2705
2702 - list all files under the current directory::
2706 - list all files under the current directory::
2703
2707
2704 hg files .
2708 hg files .
2705
2709
2706 - shows sizes and flags for current revision::
2710 - shows sizes and flags for current revision::
2707
2711
2708 hg files -vr .
2712 hg files -vr .
2709
2713
2710 - list all files named README::
2714 - list all files named README::
2711
2715
2712 hg files -I "**/README"
2716 hg files -I "**/README"
2713
2717
2714 - list all binary files::
2718 - list all binary files::
2715
2719
2716 hg files "set:binary()"
2720 hg files "set:binary()"
2717
2721
2718 - find files containing a regular expression::
2722 - find files containing a regular expression::
2719
2723
2720 hg files "set:grep('bob')"
2724 hg files "set:grep('bob')"
2721
2725
2722 - search tracked file contents with xargs and grep::
2726 - search tracked file contents with xargs and grep::
2723
2727
2724 hg files -0 | xargs -0 grep foo
2728 hg files -0 | xargs -0 grep foo
2725
2729
2726 See :hg:`help patterns` and :hg:`help filesets` for more information
2730 See :hg:`help patterns` and :hg:`help filesets` for more information
2727 on specifying file patterns.
2731 on specifying file patterns.
2728
2732
2729 Returns 0 if a match is found, 1 otherwise.
2733 Returns 0 if a match is found, 1 otherwise.
2730
2734
2731 """
2735 """
2732
2736
2733 opts = pycompat.byteskwargs(opts)
2737 opts = pycompat.byteskwargs(opts)
2734 rev = opts.get(b'rev')
2738 rev = opts.get(b'rev')
2735 if rev:
2739 if rev:
2736 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2740 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2737 ctx = scmutil.revsingle(repo, rev, None)
2741 ctx = scmutil.revsingle(repo, rev, None)
2738
2742
2739 end = b'\n'
2743 end = b'\n'
2740 if opts.get(b'print0'):
2744 if opts.get(b'print0'):
2741 end = b'\0'
2745 end = b'\0'
2742 fmt = b'%s' + end
2746 fmt = b'%s' + end
2743
2747
2744 m = scmutil.match(ctx, pats, opts)
2748 m = scmutil.match(ctx, pats, opts)
2745 ui.pager(b'files')
2749 ui.pager(b'files')
2746 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2750 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2747 with ui.formatter(b'files', opts) as fm:
2751 with ui.formatter(b'files', opts) as fm:
2748 return cmdutil.files(
2752 return cmdutil.files(
2749 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2753 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2750 )
2754 )
2751
2755
2752
2756
2753 @command(
2757 @command(
2754 b'forget',
2758 b'forget',
2755 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2759 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2756 + walkopts
2760 + walkopts
2757 + dryrunopts,
2761 + dryrunopts,
2758 _(b'[OPTION]... FILE...'),
2762 _(b'[OPTION]... FILE...'),
2759 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2763 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2760 helpbasic=True,
2764 helpbasic=True,
2761 inferrepo=True,
2765 inferrepo=True,
2762 )
2766 )
2763 def forget(ui, repo, *pats, **opts):
2767 def forget(ui, repo, *pats, **opts):
2764 """forget the specified files on the next commit
2768 """forget the specified files on the next commit
2765
2769
2766 Mark the specified files so they will no longer be tracked
2770 Mark the specified files so they will no longer be tracked
2767 after the next commit.
2771 after the next commit.
2768
2772
2769 This only removes files from the current branch, not from the
2773 This only removes files from the current branch, not from the
2770 entire project history, and it does not delete them from the
2774 entire project history, and it does not delete them from the
2771 working directory.
2775 working directory.
2772
2776
2773 To delete the file from the working directory, see :hg:`remove`.
2777 To delete the file from the working directory, see :hg:`remove`.
2774
2778
2775 To undo a forget before the next commit, see :hg:`add`.
2779 To undo a forget before the next commit, see :hg:`add`.
2776
2780
2777 .. container:: verbose
2781 .. container:: verbose
2778
2782
2779 Examples:
2783 Examples:
2780
2784
2781 - forget newly-added binary files::
2785 - forget newly-added binary files::
2782
2786
2783 hg forget "set:added() and binary()"
2787 hg forget "set:added() and binary()"
2784
2788
2785 - forget files that would be excluded by .hgignore::
2789 - forget files that would be excluded by .hgignore::
2786
2790
2787 hg forget "set:hgignore()"
2791 hg forget "set:hgignore()"
2788
2792
2789 Returns 0 on success.
2793 Returns 0 on success.
2790 """
2794 """
2791
2795
2792 opts = pycompat.byteskwargs(opts)
2796 opts = pycompat.byteskwargs(opts)
2793 if not pats:
2797 if not pats:
2794 raise error.Abort(_(b'no files specified'))
2798 raise error.Abort(_(b'no files specified'))
2795
2799
2796 m = scmutil.match(repo[None], pats, opts)
2800 m = scmutil.match(repo[None], pats, opts)
2797 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2801 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2798 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2802 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2799 rejected = cmdutil.forget(
2803 rejected = cmdutil.forget(
2800 ui,
2804 ui,
2801 repo,
2805 repo,
2802 m,
2806 m,
2803 prefix=b"",
2807 prefix=b"",
2804 uipathfn=uipathfn,
2808 uipathfn=uipathfn,
2805 explicitonly=False,
2809 explicitonly=False,
2806 dryrun=dryrun,
2810 dryrun=dryrun,
2807 interactive=interactive,
2811 interactive=interactive,
2808 )[0]
2812 )[0]
2809 return rejected and 1 or 0
2813 return rejected and 1 or 0
2810
2814
2811
2815
2812 @command(
2816 @command(
2813 b'graft',
2817 b'graft',
2814 [
2818 [
2815 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2819 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2816 (
2820 (
2817 b'',
2821 b'',
2818 b'base',
2822 b'base',
2819 b'',
2823 b'',
2820 _(b'base revision when doing the graft merge (ADVANCED)'),
2824 _(b'base revision when doing the graft merge (ADVANCED)'),
2821 _(b'REV'),
2825 _(b'REV'),
2822 ),
2826 ),
2823 (b'c', b'continue', False, _(b'resume interrupted graft')),
2827 (b'c', b'continue', False, _(b'resume interrupted graft')),
2824 (b'', b'stop', False, _(b'stop interrupted graft')),
2828 (b'', b'stop', False, _(b'stop interrupted graft')),
2825 (b'', b'abort', False, _(b'abort interrupted graft')),
2829 (b'', b'abort', False, _(b'abort interrupted graft')),
2826 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2830 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2827 (b'', b'log', None, _(b'append graft info to log message')),
2831 (b'', b'log', None, _(b'append graft info to log message')),
2828 (
2832 (
2829 b'',
2833 b'',
2830 b'no-commit',
2834 b'no-commit',
2831 None,
2835 None,
2832 _(b"don't commit, just apply the changes in working directory"),
2836 _(b"don't commit, just apply the changes in working directory"),
2833 ),
2837 ),
2834 (b'f', b'force', False, _(b'force graft')),
2838 (b'f', b'force', False, _(b'force graft')),
2835 (
2839 (
2836 b'D',
2840 b'D',
2837 b'currentdate',
2841 b'currentdate',
2838 False,
2842 False,
2839 _(b'record the current date as commit date'),
2843 _(b'record the current date as commit date'),
2840 ),
2844 ),
2841 (
2845 (
2842 b'U',
2846 b'U',
2843 b'currentuser',
2847 b'currentuser',
2844 False,
2848 False,
2845 _(b'record the current user as committer'),
2849 _(b'record the current user as committer'),
2846 ),
2850 ),
2847 ]
2851 ]
2848 + commitopts2
2852 + commitopts2
2849 + mergetoolopts
2853 + mergetoolopts
2850 + dryrunopts,
2854 + dryrunopts,
2851 _(b'[OPTION]... [-r REV]... REV...'),
2855 _(b'[OPTION]... [-r REV]... REV...'),
2852 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2856 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2853 )
2857 )
2854 def graft(ui, repo, *revs, **opts):
2858 def graft(ui, repo, *revs, **opts):
2855 '''copy changes from other branches onto the current branch
2859 '''copy changes from other branches onto the current branch
2856
2860
2857 This command uses Mercurial's merge logic to copy individual
2861 This command uses Mercurial's merge logic to copy individual
2858 changes from other branches without merging branches in the
2862 changes from other branches without merging branches in the
2859 history graph. This is sometimes known as 'backporting' or
2863 history graph. This is sometimes known as 'backporting' or
2860 'cherry-picking'. By default, graft will copy user, date, and
2864 'cherry-picking'. By default, graft will copy user, date, and
2861 description from the source changesets.
2865 description from the source changesets.
2862
2866
2863 Changesets that are ancestors of the current revision, that have
2867 Changesets that are ancestors of the current revision, that have
2864 already been grafted, or that are merges will be skipped.
2868 already been grafted, or that are merges will be skipped.
2865
2869
2866 If --log is specified, log messages will have a comment appended
2870 If --log is specified, log messages will have a comment appended
2867 of the form::
2871 of the form::
2868
2872
2869 (grafted from CHANGESETHASH)
2873 (grafted from CHANGESETHASH)
2870
2874
2871 If --force is specified, revisions will be grafted even if they
2875 If --force is specified, revisions will be grafted even if they
2872 are already ancestors of, or have been grafted to, the destination.
2876 are already ancestors of, or have been grafted to, the destination.
2873 This is useful when the revisions have since been backed out.
2877 This is useful when the revisions have since been backed out.
2874
2878
2875 If a graft merge results in conflicts, the graft process is
2879 If a graft merge results in conflicts, the graft process is
2876 interrupted so that the current merge can be manually resolved.
2880 interrupted so that the current merge can be manually resolved.
2877 Once all conflicts are addressed, the graft process can be
2881 Once all conflicts are addressed, the graft process can be
2878 continued with the -c/--continue option.
2882 continued with the -c/--continue option.
2879
2883
2880 The -c/--continue option reapplies all the earlier options.
2884 The -c/--continue option reapplies all the earlier options.
2881
2885
2882 .. container:: verbose
2886 .. container:: verbose
2883
2887
2884 The --base option exposes more of how graft internally uses merge with a
2888 The --base option exposes more of how graft internally uses merge with a
2885 custom base revision. --base can be used to specify another ancestor than
2889 custom base revision. --base can be used to specify another ancestor than
2886 the first and only parent.
2890 the first and only parent.
2887
2891
2888 The command::
2892 The command::
2889
2893
2890 hg graft -r 345 --base 234
2894 hg graft -r 345 --base 234
2891
2895
2892 is thus pretty much the same as::
2896 is thus pretty much the same as::
2893
2897
2894 hg diff -r 234 -r 345 | hg import
2898 hg diff -r 234 -r 345 | hg import
2895
2899
2896 but using merge to resolve conflicts and track moved files.
2900 but using merge to resolve conflicts and track moved files.
2897
2901
2898 The result of a merge can thus be backported as a single commit by
2902 The result of a merge can thus be backported as a single commit by
2899 specifying one of the merge parents as base, and thus effectively
2903 specifying one of the merge parents as base, and thus effectively
2900 grafting the changes from the other side.
2904 grafting the changes from the other side.
2901
2905
2902 It is also possible to collapse multiple changesets and clean up history
2906 It is also possible to collapse multiple changesets and clean up history
2903 by specifying another ancestor as base, much like rebase --collapse
2907 by specifying another ancestor as base, much like rebase --collapse
2904 --keep.
2908 --keep.
2905
2909
2906 The commit message can be tweaked after the fact using commit --amend .
2910 The commit message can be tweaked after the fact using commit --amend .
2907
2911
2908 For using non-ancestors as the base to backout changes, see the backout
2912 For using non-ancestors as the base to backout changes, see the backout
2909 command and the hidden --parent option.
2913 command and the hidden --parent option.
2910
2914
2911 .. container:: verbose
2915 .. container:: verbose
2912
2916
2913 Examples:
2917 Examples:
2914
2918
2915 - copy a single change to the stable branch and edit its description::
2919 - copy a single change to the stable branch and edit its description::
2916
2920
2917 hg update stable
2921 hg update stable
2918 hg graft --edit 9393
2922 hg graft --edit 9393
2919
2923
2920 - graft a range of changesets with one exception, updating dates::
2924 - graft a range of changesets with one exception, updating dates::
2921
2925
2922 hg graft -D "2085::2093 and not 2091"
2926 hg graft -D "2085::2093 and not 2091"
2923
2927
2924 - continue a graft after resolving conflicts::
2928 - continue a graft after resolving conflicts::
2925
2929
2926 hg graft -c
2930 hg graft -c
2927
2931
2928 - show the source of a grafted changeset::
2932 - show the source of a grafted changeset::
2929
2933
2930 hg log --debug -r .
2934 hg log --debug -r .
2931
2935
2932 - show revisions sorted by date::
2936 - show revisions sorted by date::
2933
2937
2934 hg log -r "sort(all(), date)"
2938 hg log -r "sort(all(), date)"
2935
2939
2936 - backport the result of a merge as a single commit::
2940 - backport the result of a merge as a single commit::
2937
2941
2938 hg graft -r 123 --base 123^
2942 hg graft -r 123 --base 123^
2939
2943
2940 - land a feature branch as one changeset::
2944 - land a feature branch as one changeset::
2941
2945
2942 hg up -cr default
2946 hg up -cr default
2943 hg graft -r featureX --base "ancestor('featureX', 'default')"
2947 hg graft -r featureX --base "ancestor('featureX', 'default')"
2944
2948
2945 See :hg:`help revisions` for more about specifying revisions.
2949 See :hg:`help revisions` for more about specifying revisions.
2946
2950
2947 Returns 0 on successful completion.
2951 Returns 0 on successful completion.
2948 '''
2952 '''
2949 with repo.wlock():
2953 with repo.wlock():
2950 return _dograft(ui, repo, *revs, **opts)
2954 return _dograft(ui, repo, *revs, **opts)
2951
2955
2952
2956
2953 def _dograft(ui, repo, *revs, **opts):
2957 def _dograft(ui, repo, *revs, **opts):
2954 opts = pycompat.byteskwargs(opts)
2958 opts = pycompat.byteskwargs(opts)
2955 if revs and opts.get(b'rev'):
2959 if revs and opts.get(b'rev'):
2956 ui.warn(
2960 ui.warn(
2957 _(
2961 _(
2958 b'warning: inconsistent use of --rev might give unexpected '
2962 b'warning: inconsistent use of --rev might give unexpected '
2959 b'revision ordering!\n'
2963 b'revision ordering!\n'
2960 )
2964 )
2961 )
2965 )
2962
2966
2963 revs = list(revs)
2967 revs = list(revs)
2964 revs.extend(opts.get(b'rev'))
2968 revs.extend(opts.get(b'rev'))
2965 basectx = None
2969 basectx = None
2966 if opts.get(b'base'):
2970 if opts.get(b'base'):
2967 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2971 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2968 # a dict of data to be stored in state file
2972 # a dict of data to be stored in state file
2969 statedata = {}
2973 statedata = {}
2970 # list of new nodes created by ongoing graft
2974 # list of new nodes created by ongoing graft
2971 statedata[b'newnodes'] = []
2975 statedata[b'newnodes'] = []
2972
2976
2973 if opts.get(b'user') and opts.get(b'currentuser'):
2977 if opts.get(b'user') and opts.get(b'currentuser'):
2974 raise error.Abort(_(b'--user and --currentuser are mutually exclusive'))
2978 raise error.Abort(_(b'--user and --currentuser are mutually exclusive'))
2975 if opts.get(b'date') and opts.get(b'currentdate'):
2979 if opts.get(b'date') and opts.get(b'currentdate'):
2976 raise error.Abort(_(b'--date and --currentdate are mutually exclusive'))
2980 raise error.Abort(_(b'--date and --currentdate are mutually exclusive'))
2977 if not opts.get(b'user') and opts.get(b'currentuser'):
2981 if not opts.get(b'user') and opts.get(b'currentuser'):
2978 opts[b'user'] = ui.username()
2982 opts[b'user'] = ui.username()
2979 if not opts.get(b'date') and opts.get(b'currentdate'):
2983 if not opts.get(b'date') and opts.get(b'currentdate'):
2980 opts[b'date'] = b"%d %d" % dateutil.makedate()
2984 opts[b'date'] = b"%d %d" % dateutil.makedate()
2981
2985
2982 editor = cmdutil.getcommiteditor(
2986 editor = cmdutil.getcommiteditor(
2983 editform=b'graft', **pycompat.strkwargs(opts)
2987 editform=b'graft', **pycompat.strkwargs(opts)
2984 )
2988 )
2985
2989
2986 cont = False
2990 cont = False
2987 if opts.get(b'no_commit'):
2991 if opts.get(b'no_commit'):
2988 if opts.get(b'edit'):
2992 if opts.get(b'edit'):
2989 raise error.Abort(
2993 raise error.Abort(
2990 _(b"cannot specify --no-commit and --edit together")
2994 _(b"cannot specify --no-commit and --edit together")
2991 )
2995 )
2992 if opts.get(b'currentuser'):
2996 if opts.get(b'currentuser'):
2993 raise error.Abort(
2997 raise error.Abort(
2994 _(b"cannot specify --no-commit and --currentuser together")
2998 _(b"cannot specify --no-commit and --currentuser together")
2995 )
2999 )
2996 if opts.get(b'currentdate'):
3000 if opts.get(b'currentdate'):
2997 raise error.Abort(
3001 raise error.Abort(
2998 _(b"cannot specify --no-commit and --currentdate together")
3002 _(b"cannot specify --no-commit and --currentdate together")
2999 )
3003 )
3000 if opts.get(b'log'):
3004 if opts.get(b'log'):
3001 raise error.Abort(
3005 raise error.Abort(
3002 _(b"cannot specify --no-commit and --log together")
3006 _(b"cannot specify --no-commit and --log together")
3003 )
3007 )
3004
3008
3005 graftstate = statemod.cmdstate(repo, b'graftstate')
3009 graftstate = statemod.cmdstate(repo, b'graftstate')
3006
3010
3007 if opts.get(b'stop'):
3011 if opts.get(b'stop'):
3008 if opts.get(b'continue'):
3012 if opts.get(b'continue'):
3009 raise error.Abort(
3013 raise error.Abort(
3010 _(b"cannot use '--continue' and '--stop' together")
3014 _(b"cannot use '--continue' and '--stop' together")
3011 )
3015 )
3012 if opts.get(b'abort'):
3016 if opts.get(b'abort'):
3013 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3017 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3014
3018
3015 if any(
3019 if any(
3016 (
3020 (
3017 opts.get(b'edit'),
3021 opts.get(b'edit'),
3018 opts.get(b'log'),
3022 opts.get(b'log'),
3019 opts.get(b'user'),
3023 opts.get(b'user'),
3020 opts.get(b'date'),
3024 opts.get(b'date'),
3021 opts.get(b'currentdate'),
3025 opts.get(b'currentdate'),
3022 opts.get(b'currentuser'),
3026 opts.get(b'currentuser'),
3023 opts.get(b'rev'),
3027 opts.get(b'rev'),
3024 )
3028 )
3025 ):
3029 ):
3026 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3030 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3027 return _stopgraft(ui, repo, graftstate)
3031 return _stopgraft(ui, repo, graftstate)
3028 elif opts.get(b'abort'):
3032 elif opts.get(b'abort'):
3029 if opts.get(b'continue'):
3033 if opts.get(b'continue'):
3030 raise error.Abort(
3034 raise error.Abort(
3031 _(b"cannot use '--continue' and '--abort' together")
3035 _(b"cannot use '--continue' and '--abort' together")
3032 )
3036 )
3033 if any(
3037 if any(
3034 (
3038 (
3035 opts.get(b'edit'),
3039 opts.get(b'edit'),
3036 opts.get(b'log'),
3040 opts.get(b'log'),
3037 opts.get(b'user'),
3041 opts.get(b'user'),
3038 opts.get(b'date'),
3042 opts.get(b'date'),
3039 opts.get(b'currentdate'),
3043 opts.get(b'currentdate'),
3040 opts.get(b'currentuser'),
3044 opts.get(b'currentuser'),
3041 opts.get(b'rev'),
3045 opts.get(b'rev'),
3042 )
3046 )
3043 ):
3047 ):
3044 raise error.Abort(
3048 raise error.Abort(
3045 _(b"cannot specify any other flag with '--abort'")
3049 _(b"cannot specify any other flag with '--abort'")
3046 )
3050 )
3047
3051
3048 return cmdutil.abortgraft(ui, repo, graftstate)
3052 return cmdutil.abortgraft(ui, repo, graftstate)
3049 elif opts.get(b'continue'):
3053 elif opts.get(b'continue'):
3050 cont = True
3054 cont = True
3051 if revs:
3055 if revs:
3052 raise error.Abort(_(b"can't specify --continue and revisions"))
3056 raise error.Abort(_(b"can't specify --continue and revisions"))
3053 # read in unfinished revisions
3057 # read in unfinished revisions
3054 if graftstate.exists():
3058 if graftstate.exists():
3055 statedata = cmdutil.readgraftstate(repo, graftstate)
3059 statedata = cmdutil.readgraftstate(repo, graftstate)
3056 if statedata.get(b'date'):
3060 if statedata.get(b'date'):
3057 opts[b'date'] = statedata[b'date']
3061 opts[b'date'] = statedata[b'date']
3058 if statedata.get(b'user'):
3062 if statedata.get(b'user'):
3059 opts[b'user'] = statedata[b'user']
3063 opts[b'user'] = statedata[b'user']
3060 if statedata.get(b'log'):
3064 if statedata.get(b'log'):
3061 opts[b'log'] = True
3065 opts[b'log'] = True
3062 if statedata.get(b'no_commit'):
3066 if statedata.get(b'no_commit'):
3063 opts[b'no_commit'] = statedata.get(b'no_commit')
3067 opts[b'no_commit'] = statedata.get(b'no_commit')
3064 nodes = statedata[b'nodes']
3068 nodes = statedata[b'nodes']
3065 revs = [repo[node].rev() for node in nodes]
3069 revs = [repo[node].rev() for node in nodes]
3066 else:
3070 else:
3067 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3071 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3068 else:
3072 else:
3069 if not revs:
3073 if not revs:
3070 raise error.Abort(_(b'no revisions specified'))
3074 raise error.Abort(_(b'no revisions specified'))
3071 cmdutil.checkunfinished(repo)
3075 cmdutil.checkunfinished(repo)
3072 cmdutil.bailifchanged(repo)
3076 cmdutil.bailifchanged(repo)
3073 revs = scmutil.revrange(repo, revs)
3077 revs = scmutil.revrange(repo, revs)
3074
3078
3075 skipped = set()
3079 skipped = set()
3076 if basectx is None:
3080 if basectx is None:
3077 # check for merges
3081 # check for merges
3078 for rev in repo.revs(b'%ld and merge()', revs):
3082 for rev in repo.revs(b'%ld and merge()', revs):
3079 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3083 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3080 skipped.add(rev)
3084 skipped.add(rev)
3081 revs = [r for r in revs if r not in skipped]
3085 revs = [r for r in revs if r not in skipped]
3082 if not revs:
3086 if not revs:
3083 return -1
3087 return -1
3084 if basectx is not None and len(revs) != 1:
3088 if basectx is not None and len(revs) != 1:
3085 raise error.Abort(_(b'only one revision allowed with --base '))
3089 raise error.Abort(_(b'only one revision allowed with --base '))
3086
3090
3087 # Don't check in the --continue case, in effect retaining --force across
3091 # Don't check in the --continue case, in effect retaining --force across
3088 # --continues. That's because without --force, any revisions we decided to
3092 # --continues. That's because without --force, any revisions we decided to
3089 # skip would have been filtered out here, so they wouldn't have made their
3093 # skip would have been filtered out here, so they wouldn't have made their
3090 # way to the graftstate. With --force, any revisions we would have otherwise
3094 # way to the graftstate. With --force, any revisions we would have otherwise
3091 # skipped would not have been filtered out, and if they hadn't been applied
3095 # skipped would not have been filtered out, and if they hadn't been applied
3092 # already, they'd have been in the graftstate.
3096 # already, they'd have been in the graftstate.
3093 if not (cont or opts.get(b'force')) and basectx is None:
3097 if not (cont or opts.get(b'force')) and basectx is None:
3094 # check for ancestors of dest branch
3098 # check for ancestors of dest branch
3095 crev = repo[b'.'].rev()
3099 crev = repo[b'.'].rev()
3096 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3100 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3097 # XXX make this lazy in the future
3101 # XXX make this lazy in the future
3098 # don't mutate while iterating, create a copy
3102 # don't mutate while iterating, create a copy
3099 for rev in list(revs):
3103 for rev in list(revs):
3100 if rev in ancestors:
3104 if rev in ancestors:
3101 ui.warn(
3105 ui.warn(
3102 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3106 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3103 )
3107 )
3104 # XXX remove on list is slow
3108 # XXX remove on list is slow
3105 revs.remove(rev)
3109 revs.remove(rev)
3106 if not revs:
3110 if not revs:
3107 return -1
3111 return -1
3108
3112
3109 # analyze revs for earlier grafts
3113 # analyze revs for earlier grafts
3110 ids = {}
3114 ids = {}
3111 for ctx in repo.set(b"%ld", revs):
3115 for ctx in repo.set(b"%ld", revs):
3112 ids[ctx.hex()] = ctx.rev()
3116 ids[ctx.hex()] = ctx.rev()
3113 n = ctx.extra().get(b'source')
3117 n = ctx.extra().get(b'source')
3114 if n:
3118 if n:
3115 ids[n] = ctx.rev()
3119 ids[n] = ctx.rev()
3116
3120
3117 # check ancestors for earlier grafts
3121 # check ancestors for earlier grafts
3118 ui.debug(b'scanning for duplicate grafts\n')
3122 ui.debug(b'scanning for duplicate grafts\n')
3119
3123
3120 # The only changesets we can be sure doesn't contain grafts of any
3124 # The only changesets we can be sure doesn't contain grafts of any
3121 # revs, are the ones that are common ancestors of *all* revs:
3125 # revs, are the ones that are common ancestors of *all* revs:
3122 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3126 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3123 ctx = repo[rev]
3127 ctx = repo[rev]
3124 n = ctx.extra().get(b'source')
3128 n = ctx.extra().get(b'source')
3125 if n in ids:
3129 if n in ids:
3126 try:
3130 try:
3127 r = repo[n].rev()
3131 r = repo[n].rev()
3128 except error.RepoLookupError:
3132 except error.RepoLookupError:
3129 r = None
3133 r = None
3130 if r in revs:
3134 if r in revs:
3131 ui.warn(
3135 ui.warn(
3132 _(
3136 _(
3133 b'skipping revision %d:%s '
3137 b'skipping revision %d:%s '
3134 b'(already grafted to %d:%s)\n'
3138 b'(already grafted to %d:%s)\n'
3135 )
3139 )
3136 % (r, repo[r], rev, ctx)
3140 % (r, repo[r], rev, ctx)
3137 )
3141 )
3138 revs.remove(r)
3142 revs.remove(r)
3139 elif ids[n] in revs:
3143 elif ids[n] in revs:
3140 if r is None:
3144 if r is None:
3141 ui.warn(
3145 ui.warn(
3142 _(
3146 _(
3143 b'skipping already grafted revision %d:%s '
3147 b'skipping already grafted revision %d:%s '
3144 b'(%d:%s also has unknown origin %s)\n'
3148 b'(%d:%s also has unknown origin %s)\n'
3145 )
3149 )
3146 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3150 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3147 )
3151 )
3148 else:
3152 else:
3149 ui.warn(
3153 ui.warn(
3150 _(
3154 _(
3151 b'skipping already grafted revision %d:%s '
3155 b'skipping already grafted revision %d:%s '
3152 b'(%d:%s also has origin %d:%s)\n'
3156 b'(%d:%s also has origin %d:%s)\n'
3153 )
3157 )
3154 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3158 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3155 )
3159 )
3156 revs.remove(ids[n])
3160 revs.remove(ids[n])
3157 elif ctx.hex() in ids:
3161 elif ctx.hex() in ids:
3158 r = ids[ctx.hex()]
3162 r = ids[ctx.hex()]
3159 if r in revs:
3163 if r in revs:
3160 ui.warn(
3164 ui.warn(
3161 _(
3165 _(
3162 b'skipping already grafted revision %d:%s '
3166 b'skipping already grafted revision %d:%s '
3163 b'(was grafted from %d:%s)\n'
3167 b'(was grafted from %d:%s)\n'
3164 )
3168 )
3165 % (r, repo[r], rev, ctx)
3169 % (r, repo[r], rev, ctx)
3166 )
3170 )
3167 revs.remove(r)
3171 revs.remove(r)
3168 if not revs:
3172 if not revs:
3169 return -1
3173 return -1
3170
3174
3171 if opts.get(b'no_commit'):
3175 if opts.get(b'no_commit'):
3172 statedata[b'no_commit'] = True
3176 statedata[b'no_commit'] = True
3173 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3177 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3174 desc = b'%d:%s "%s"' % (
3178 desc = b'%d:%s "%s"' % (
3175 ctx.rev(),
3179 ctx.rev(),
3176 ctx,
3180 ctx,
3177 ctx.description().split(b'\n', 1)[0],
3181 ctx.description().split(b'\n', 1)[0],
3178 )
3182 )
3179 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3183 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3180 if names:
3184 if names:
3181 desc += b' (%s)' % b' '.join(names)
3185 desc += b' (%s)' % b' '.join(names)
3182 ui.status(_(b'grafting %s\n') % desc)
3186 ui.status(_(b'grafting %s\n') % desc)
3183 if opts.get(b'dry_run'):
3187 if opts.get(b'dry_run'):
3184 continue
3188 continue
3185
3189
3186 source = ctx.extra().get(b'source')
3190 source = ctx.extra().get(b'source')
3187 extra = {}
3191 extra = {}
3188 if source:
3192 if source:
3189 extra[b'source'] = source
3193 extra[b'source'] = source
3190 extra[b'intermediate-source'] = ctx.hex()
3194 extra[b'intermediate-source'] = ctx.hex()
3191 else:
3195 else:
3192 extra[b'source'] = ctx.hex()
3196 extra[b'source'] = ctx.hex()
3193 user = ctx.user()
3197 user = ctx.user()
3194 if opts.get(b'user'):
3198 if opts.get(b'user'):
3195 user = opts[b'user']
3199 user = opts[b'user']
3196 statedata[b'user'] = user
3200 statedata[b'user'] = user
3197 date = ctx.date()
3201 date = ctx.date()
3198 if opts.get(b'date'):
3202 if opts.get(b'date'):
3199 date = opts[b'date']
3203 date = opts[b'date']
3200 statedata[b'date'] = date
3204 statedata[b'date'] = date
3201 message = ctx.description()
3205 message = ctx.description()
3202 if opts.get(b'log'):
3206 if opts.get(b'log'):
3203 message += b'\n(grafted from %s)' % ctx.hex()
3207 message += b'\n(grafted from %s)' % ctx.hex()
3204 statedata[b'log'] = True
3208 statedata[b'log'] = True
3205
3209
3206 # we don't merge the first commit when continuing
3210 # we don't merge the first commit when continuing
3207 if not cont:
3211 if not cont:
3208 # perform the graft merge with p1(rev) as 'ancestor'
3212 # perform the graft merge with p1(rev) as 'ancestor'
3209 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3213 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3210 base = ctx.p1() if basectx is None else basectx
3214 base = ctx.p1() if basectx is None else basectx
3211 with ui.configoverride(overrides, b'graft'):
3215 with ui.configoverride(overrides, b'graft'):
3212 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3216 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3213 # report any conflicts
3217 # report any conflicts
3214 if stats.unresolvedcount > 0:
3218 if stats.unresolvedcount > 0:
3215 # write out state for --continue
3219 # write out state for --continue
3216 nodes = [repo[rev].hex() for rev in revs[pos:]]
3220 nodes = [repo[rev].hex() for rev in revs[pos:]]
3217 statedata[b'nodes'] = nodes
3221 statedata[b'nodes'] = nodes
3218 stateversion = 1
3222 stateversion = 1
3219 graftstate.save(stateversion, statedata)
3223 graftstate.save(stateversion, statedata)
3220 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3224 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3221 raise error.Abort(
3225 raise error.Abort(
3222 _(b"unresolved conflicts, can't continue"), hint=hint
3226 _(b"unresolved conflicts, can't continue"), hint=hint
3223 )
3227 )
3224 else:
3228 else:
3225 cont = False
3229 cont = False
3226
3230
3227 # commit if --no-commit is false
3231 # commit if --no-commit is false
3228 if not opts.get(b'no_commit'):
3232 if not opts.get(b'no_commit'):
3229 node = repo.commit(
3233 node = repo.commit(
3230 text=message, user=user, date=date, extra=extra, editor=editor
3234 text=message, user=user, date=date, extra=extra, editor=editor
3231 )
3235 )
3232 if node is None:
3236 if node is None:
3233 ui.warn(
3237 ui.warn(
3234 _(b'note: graft of %d:%s created no changes to commit\n')
3238 _(b'note: graft of %d:%s created no changes to commit\n')
3235 % (ctx.rev(), ctx)
3239 % (ctx.rev(), ctx)
3236 )
3240 )
3237 # checking that newnodes exist because old state files won't have it
3241 # checking that newnodes exist because old state files won't have it
3238 elif statedata.get(b'newnodes') is not None:
3242 elif statedata.get(b'newnodes') is not None:
3239 statedata[b'newnodes'].append(node)
3243 statedata[b'newnodes'].append(node)
3240
3244
3241 # remove state when we complete successfully
3245 # remove state when we complete successfully
3242 if not opts.get(b'dry_run'):
3246 if not opts.get(b'dry_run'):
3243 graftstate.delete()
3247 graftstate.delete()
3244
3248
3245 return 0
3249 return 0
3246
3250
3247
3251
3248 def _stopgraft(ui, repo, graftstate):
3252 def _stopgraft(ui, repo, graftstate):
3249 """stop the interrupted graft"""
3253 """stop the interrupted graft"""
3250 if not graftstate.exists():
3254 if not graftstate.exists():
3251 raise error.Abort(_(b"no interrupted graft found"))
3255 raise error.Abort(_(b"no interrupted graft found"))
3252 pctx = repo[b'.']
3256 pctx = repo[b'.']
3253 hg.updaterepo(repo, pctx.node(), overwrite=True)
3257 hg.updaterepo(repo, pctx.node(), overwrite=True)
3254 graftstate.delete()
3258 graftstate.delete()
3255 ui.status(_(b"stopped the interrupted graft\n"))
3259 ui.status(_(b"stopped the interrupted graft\n"))
3256 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3260 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3257 return 0
3261 return 0
3258
3262
3259
3263
3260 statemod.addunfinished(
3264 statemod.addunfinished(
3261 b'graft',
3265 b'graft',
3262 fname=b'graftstate',
3266 fname=b'graftstate',
3263 clearable=True,
3267 clearable=True,
3264 stopflag=True,
3268 stopflag=True,
3265 continueflag=True,
3269 continueflag=True,
3266 abortfunc=cmdutil.hgabortgraft,
3270 abortfunc=cmdutil.hgabortgraft,
3267 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3271 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3268 )
3272 )
3269
3273
3270
3274
3271 @command(
3275 @command(
3272 b'grep',
3276 b'grep',
3273 [
3277 [
3274 (b'0', b'print0', None, _(b'end fields with NUL')),
3278 (b'0', b'print0', None, _(b'end fields with NUL')),
3275 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3279 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3276 (
3280 (
3277 b'',
3281 b'',
3278 b'diff',
3282 b'diff',
3279 None,
3283 None,
3280 _(
3284 _(
3281 b'search revision differences for when the pattern was added '
3285 b'search revision differences for when the pattern was added '
3282 b'or removed'
3286 b'or removed'
3283 ),
3287 ),
3284 ),
3288 ),
3285 (b'a', b'text', None, _(b'treat all files as text')),
3289 (b'a', b'text', None, _(b'treat all files as text')),
3286 (
3290 (
3287 b'f',
3291 b'f',
3288 b'follow',
3292 b'follow',
3289 None,
3293 None,
3290 _(
3294 _(
3291 b'follow changeset history,'
3295 b'follow changeset history,'
3292 b' or file history across copies and renames'
3296 b' or file history across copies and renames'
3293 ),
3297 ),
3294 ),
3298 ),
3295 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3299 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3296 (
3300 (
3297 b'l',
3301 b'l',
3298 b'files-with-matches',
3302 b'files-with-matches',
3299 None,
3303 None,
3300 _(b'print only filenames and revisions that match'),
3304 _(b'print only filenames and revisions that match'),
3301 ),
3305 ),
3302 (b'n', b'line-number', None, _(b'print matching line numbers')),
3306 (b'n', b'line-number', None, _(b'print matching line numbers')),
3303 (
3307 (
3304 b'r',
3308 b'r',
3305 b'rev',
3309 b'rev',
3306 [],
3310 [],
3307 _(b'search files changed within revision range'),
3311 _(b'search files changed within revision range'),
3308 _(b'REV'),
3312 _(b'REV'),
3309 ),
3313 ),
3310 (
3314 (
3311 b'',
3315 b'',
3312 b'all-files',
3316 b'all-files',
3313 None,
3317 None,
3314 _(
3318 _(
3315 b'include all files in the changeset while grepping (DEPRECATED)'
3319 b'include all files in the changeset while grepping (DEPRECATED)'
3316 ),
3320 ),
3317 ),
3321 ),
3318 (b'u', b'user', None, _(b'list the author (long with -v)')),
3322 (b'u', b'user', None, _(b'list the author (long with -v)')),
3319 (b'd', b'date', None, _(b'list the date (short with -q)')),
3323 (b'd', b'date', None, _(b'list the date (short with -q)')),
3320 ]
3324 ]
3321 + formatteropts
3325 + formatteropts
3322 + walkopts,
3326 + walkopts,
3323 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3327 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3324 helpcategory=command.CATEGORY_FILE_CONTENTS,
3328 helpcategory=command.CATEGORY_FILE_CONTENTS,
3325 inferrepo=True,
3329 inferrepo=True,
3326 intents={INTENT_READONLY},
3330 intents={INTENT_READONLY},
3327 )
3331 )
3328 def grep(ui, repo, pattern, *pats, **opts):
3332 def grep(ui, repo, pattern, *pats, **opts):
3329 """search for a pattern in specified files
3333 """search for a pattern in specified files
3330
3334
3331 Search the working directory or revision history for a regular
3335 Search the working directory or revision history for a regular
3332 expression in the specified files for the entire repository.
3336 expression in the specified files for the entire repository.
3333
3337
3334 By default, grep searches the repository files in the working
3338 By default, grep searches the repository files in the working
3335 directory and prints the files where it finds a match. To specify
3339 directory and prints the files where it finds a match. To specify
3336 historical revisions instead of the working directory, use the
3340 historical revisions instead of the working directory, use the
3337 --rev flag.
3341 --rev flag.
3338
3342
3339 To search instead historical revision differences that contains a
3343 To search instead historical revision differences that contains a
3340 change in match status ("-" for a match that becomes a non-match,
3344 change in match status ("-" for a match that becomes a non-match,
3341 or "+" for a non-match that becomes a match), use the --diff flag.
3345 or "+" for a non-match that becomes a match), use the --diff flag.
3342
3346
3343 PATTERN can be any Python (roughly Perl-compatible) regular
3347 PATTERN can be any Python (roughly Perl-compatible) regular
3344 expression.
3348 expression.
3345
3349
3346 If no FILEs are specified and the --rev flag isn't supplied, all
3350 If no FILEs are specified and the --rev flag isn't supplied, all
3347 files in the working directory are searched. When using the --rev
3351 files in the working directory are searched. When using the --rev
3348 flag and specifying FILEs, use the --follow argument to also
3352 flag and specifying FILEs, use the --follow argument to also
3349 follow the specified FILEs across renames and copies.
3353 follow the specified FILEs across renames and copies.
3350
3354
3351 .. container:: verbose
3355 .. container:: verbose
3352
3356
3353 Template:
3357 Template:
3354
3358
3355 The following keywords are supported in addition to the common template
3359 The following keywords are supported in addition to the common template
3356 keywords and functions. See also :hg:`help templates`.
3360 keywords and functions. See also :hg:`help templates`.
3357
3361
3358 :change: String. Character denoting insertion ``+`` or removal ``-``.
3362 :change: String. Character denoting insertion ``+`` or removal ``-``.
3359 Available if ``--diff`` is specified.
3363 Available if ``--diff`` is specified.
3360 :lineno: Integer. Line number of the match.
3364 :lineno: Integer. Line number of the match.
3361 :path: String. Repository-absolute path of the file.
3365 :path: String. Repository-absolute path of the file.
3362 :texts: List of text chunks.
3366 :texts: List of text chunks.
3363
3367
3364 And each entry of ``{texts}`` provides the following sub-keywords.
3368 And each entry of ``{texts}`` provides the following sub-keywords.
3365
3369
3366 :matched: Boolean. True if the chunk matches the specified pattern.
3370 :matched: Boolean. True if the chunk matches the specified pattern.
3367 :text: String. Chunk content.
3371 :text: String. Chunk content.
3368
3372
3369 See :hg:`help templates.operators` for the list expansion syntax.
3373 See :hg:`help templates.operators` for the list expansion syntax.
3370
3374
3371 Returns 0 if a match is found, 1 otherwise.
3375 Returns 0 if a match is found, 1 otherwise.
3372
3376
3373 """
3377 """
3374 opts = pycompat.byteskwargs(opts)
3378 opts = pycompat.byteskwargs(opts)
3375 diff = opts.get(b'all') or opts.get(b'diff')
3379 diff = opts.get(b'all') or opts.get(b'diff')
3376 if diff and opts.get(b'all_files'):
3380 if diff and opts.get(b'all_files'):
3377 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3381 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3378 if opts.get(b'all_files') is None and not diff:
3382 if opts.get(b'all_files') is None and not diff:
3379 opts[b'all_files'] = True
3383 opts[b'all_files'] = True
3380 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3384 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3381 all_files = opts.get(b'all_files')
3385 all_files = opts.get(b'all_files')
3382 if plaingrep:
3386 if plaingrep:
3383 opts[b'rev'] = [b'wdir()']
3387 opts[b'rev'] = [b'wdir()']
3384
3388
3385 reflags = re.M
3389 reflags = re.M
3386 if opts.get(b'ignore_case'):
3390 if opts.get(b'ignore_case'):
3387 reflags |= re.I
3391 reflags |= re.I
3388 try:
3392 try:
3389 regexp = util.re.compile(pattern, reflags)
3393 regexp = util.re.compile(pattern, reflags)
3390 except re.error as inst:
3394 except re.error as inst:
3391 ui.warn(
3395 ui.warn(
3392 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3396 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3393 )
3397 )
3394 return 1
3398 return 1
3395 sep, eol = b':', b'\n'
3399 sep, eol = b':', b'\n'
3396 if opts.get(b'print0'):
3400 if opts.get(b'print0'):
3397 sep = eol = b'\0'
3401 sep = eol = b'\0'
3398
3402
3399 getfile = util.lrucachefunc(repo.file)
3403 getfile = util.lrucachefunc(repo.file)
3400
3404
3401 def matchlines(body):
3405 def matchlines(body):
3402 begin = 0
3406 begin = 0
3403 linenum = 0
3407 linenum = 0
3404 while begin < len(body):
3408 while begin < len(body):
3405 match = regexp.search(body, begin)
3409 match = regexp.search(body, begin)
3406 if not match:
3410 if not match:
3407 break
3411 break
3408 mstart, mend = match.span()
3412 mstart, mend = match.span()
3409 linenum += body.count(b'\n', begin, mstart) + 1
3413 linenum += body.count(b'\n', begin, mstart) + 1
3410 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3414 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3411 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3415 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3412 lend = begin - 1
3416 lend = begin - 1
3413 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3417 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3414
3418
3415 class linestate(object):
3419 class linestate(object):
3416 def __init__(self, line, linenum, colstart, colend):
3420 def __init__(self, line, linenum, colstart, colend):
3417 self.line = line
3421 self.line = line
3418 self.linenum = linenum
3422 self.linenum = linenum
3419 self.colstart = colstart
3423 self.colstart = colstart
3420 self.colend = colend
3424 self.colend = colend
3421
3425
3422 def __hash__(self):
3426 def __hash__(self):
3423 return hash((self.linenum, self.line))
3427 return hash((self.linenum, self.line))
3424
3428
3425 def __eq__(self, other):
3429 def __eq__(self, other):
3426 return self.line == other.line
3430 return self.line == other.line
3427
3431
3428 def findpos(self):
3432 def findpos(self):
3429 """Iterate all (start, end) indices of matches"""
3433 """Iterate all (start, end) indices of matches"""
3430 yield self.colstart, self.colend
3434 yield self.colstart, self.colend
3431 p = self.colend
3435 p = self.colend
3432 while p < len(self.line):
3436 while p < len(self.line):
3433 m = regexp.search(self.line, p)
3437 m = regexp.search(self.line, p)
3434 if not m:
3438 if not m:
3435 break
3439 break
3436 yield m.span()
3440 yield m.span()
3437 p = m.end()
3441 p = m.end()
3438
3442
3439 matches = {}
3443 matches = {}
3440 copies = {}
3444 copies = {}
3441
3445
3442 def grepbody(fn, rev, body):
3446 def grepbody(fn, rev, body):
3443 matches[rev].setdefault(fn, [])
3447 matches[rev].setdefault(fn, [])
3444 m = matches[rev][fn]
3448 m = matches[rev][fn]
3445 for lnum, cstart, cend, line in matchlines(body):
3449 for lnum, cstart, cend, line in matchlines(body):
3446 s = linestate(line, lnum, cstart, cend)
3450 s = linestate(line, lnum, cstart, cend)
3447 m.append(s)
3451 m.append(s)
3448
3452
3449 def difflinestates(a, b):
3453 def difflinestates(a, b):
3450 sm = difflib.SequenceMatcher(None, a, b)
3454 sm = difflib.SequenceMatcher(None, a, b)
3451 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3455 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3452 if tag == r'insert':
3456 if tag == r'insert':
3453 for i in pycompat.xrange(blo, bhi):
3457 for i in pycompat.xrange(blo, bhi):
3454 yield (b'+', b[i])
3458 yield (b'+', b[i])
3455 elif tag == r'delete':
3459 elif tag == r'delete':
3456 for i in pycompat.xrange(alo, ahi):
3460 for i in pycompat.xrange(alo, ahi):
3457 yield (b'-', a[i])
3461 yield (b'-', a[i])
3458 elif tag == r'replace':
3462 elif tag == r'replace':
3459 for i in pycompat.xrange(alo, ahi):
3463 for i in pycompat.xrange(alo, ahi):
3460 yield (b'-', a[i])
3464 yield (b'-', a[i])
3461 for i in pycompat.xrange(blo, bhi):
3465 for i in pycompat.xrange(blo, bhi):
3462 yield (b'+', b[i])
3466 yield (b'+', b[i])
3463
3467
3464 uipathfn = scmutil.getuipathfn(repo)
3468 uipathfn = scmutil.getuipathfn(repo)
3465
3469
3466 def display(fm, fn, ctx, pstates, states):
3470 def display(fm, fn, ctx, pstates, states):
3467 rev = scmutil.intrev(ctx)
3471 rev = scmutil.intrev(ctx)
3468 if fm.isplain():
3472 if fm.isplain():
3469 formatuser = ui.shortuser
3473 formatuser = ui.shortuser
3470 else:
3474 else:
3471 formatuser = pycompat.bytestr
3475 formatuser = pycompat.bytestr
3472 if ui.quiet:
3476 if ui.quiet:
3473 datefmt = b'%Y-%m-%d'
3477 datefmt = b'%Y-%m-%d'
3474 else:
3478 else:
3475 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3479 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3476 found = False
3480 found = False
3477
3481
3478 @util.cachefunc
3482 @util.cachefunc
3479 def binary():
3483 def binary():
3480 flog = getfile(fn)
3484 flog = getfile(fn)
3481 try:
3485 try:
3482 return stringutil.binary(flog.read(ctx.filenode(fn)))
3486 return stringutil.binary(flog.read(ctx.filenode(fn)))
3483 except error.WdirUnsupported:
3487 except error.WdirUnsupported:
3484 return ctx[fn].isbinary()
3488 return ctx[fn].isbinary()
3485
3489
3486 fieldnamemap = {b'linenumber': b'lineno'}
3490 fieldnamemap = {b'linenumber': b'lineno'}
3487 if diff:
3491 if diff:
3488 iter = difflinestates(pstates, states)
3492 iter = difflinestates(pstates, states)
3489 else:
3493 else:
3490 iter = [(b'', l) for l in states]
3494 iter = [(b'', l) for l in states]
3491 for change, l in iter:
3495 for change, l in iter:
3492 fm.startitem()
3496 fm.startitem()
3493 fm.context(ctx=ctx)
3497 fm.context(ctx=ctx)
3494 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3498 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3495 fm.plain(uipathfn(fn), label=b'grep.filename')
3499 fm.plain(uipathfn(fn), label=b'grep.filename')
3496
3500
3497 cols = [
3501 cols = [
3498 (b'rev', b'%d', rev, not plaingrep, b''),
3502 (b'rev', b'%d', rev, not plaingrep, b''),
3499 (
3503 (
3500 b'linenumber',
3504 b'linenumber',
3501 b'%d',
3505 b'%d',
3502 l.linenum,
3506 l.linenum,
3503 opts.get(b'line_number'),
3507 opts.get(b'line_number'),
3504 b'',
3508 b'',
3505 ),
3509 ),
3506 ]
3510 ]
3507 if diff:
3511 if diff:
3508 cols.append(
3512 cols.append(
3509 (
3513 (
3510 b'change',
3514 b'change',
3511 b'%s',
3515 b'%s',
3512 change,
3516 change,
3513 True,
3517 True,
3514 b'grep.inserted '
3518 b'grep.inserted '
3515 if change == b'+'
3519 if change == b'+'
3516 else b'grep.deleted ',
3520 else b'grep.deleted ',
3517 )
3521 )
3518 )
3522 )
3519 cols.extend(
3523 cols.extend(
3520 [
3524 [
3521 (
3525 (
3522 b'user',
3526 b'user',
3523 b'%s',
3527 b'%s',
3524 formatuser(ctx.user()),
3528 formatuser(ctx.user()),
3525 opts.get(b'user'),
3529 opts.get(b'user'),
3526 b'',
3530 b'',
3527 ),
3531 ),
3528 (
3532 (
3529 b'date',
3533 b'date',
3530 b'%s',
3534 b'%s',
3531 fm.formatdate(ctx.date(), datefmt),
3535 fm.formatdate(ctx.date(), datefmt),
3532 opts.get(b'date'),
3536 opts.get(b'date'),
3533 b'',
3537 b'',
3534 ),
3538 ),
3535 ]
3539 ]
3536 )
3540 )
3537 for name, fmt, data, cond, extra_label in cols:
3541 for name, fmt, data, cond, extra_label in cols:
3538 if cond:
3542 if cond:
3539 fm.plain(sep, label=b'grep.sep')
3543 fm.plain(sep, label=b'grep.sep')
3540 field = fieldnamemap.get(name, name)
3544 field = fieldnamemap.get(name, name)
3541 label = extra_label + (b'grep.%s' % name)
3545 label = extra_label + (b'grep.%s' % name)
3542 fm.condwrite(cond, field, fmt, data, label=label)
3546 fm.condwrite(cond, field, fmt, data, label=label)
3543 if not opts.get(b'files_with_matches'):
3547 if not opts.get(b'files_with_matches'):
3544 fm.plain(sep, label=b'grep.sep')
3548 fm.plain(sep, label=b'grep.sep')
3545 if not opts.get(b'text') and binary():
3549 if not opts.get(b'text') and binary():
3546 fm.plain(_(b" Binary file matches"))
3550 fm.plain(_(b" Binary file matches"))
3547 else:
3551 else:
3548 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3552 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3549 fm.plain(eol)
3553 fm.plain(eol)
3550 found = True
3554 found = True
3551 if opts.get(b'files_with_matches'):
3555 if opts.get(b'files_with_matches'):
3552 break
3556 break
3553 return found
3557 return found
3554
3558
3555 def displaymatches(fm, l):
3559 def displaymatches(fm, l):
3556 p = 0
3560 p = 0
3557 for s, e in l.findpos():
3561 for s, e in l.findpos():
3558 if p < s:
3562 if p < s:
3559 fm.startitem()
3563 fm.startitem()
3560 fm.write(b'text', b'%s', l.line[p:s])
3564 fm.write(b'text', b'%s', l.line[p:s])
3561 fm.data(matched=False)
3565 fm.data(matched=False)
3562 fm.startitem()
3566 fm.startitem()
3563 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3567 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3564 fm.data(matched=True)
3568 fm.data(matched=True)
3565 p = e
3569 p = e
3566 if p < len(l.line):
3570 if p < len(l.line):
3567 fm.startitem()
3571 fm.startitem()
3568 fm.write(b'text', b'%s', l.line[p:])
3572 fm.write(b'text', b'%s', l.line[p:])
3569 fm.data(matched=False)
3573 fm.data(matched=False)
3570 fm.end()
3574 fm.end()
3571
3575
3572 skip = set()
3576 skip = set()
3573 revfiles = {}
3577 revfiles = {}
3574 match = scmutil.match(repo[None], pats, opts)
3578 match = scmutil.match(repo[None], pats, opts)
3575 found = False
3579 found = False
3576 follow = opts.get(b'follow')
3580 follow = opts.get(b'follow')
3577
3581
3578 getrenamed = scmutil.getrenamedfn(repo)
3582 getrenamed = scmutil.getrenamedfn(repo)
3579
3583
3580 def prep(ctx, fns):
3584 def prep(ctx, fns):
3581 rev = ctx.rev()
3585 rev = ctx.rev()
3582 pctx = ctx.p1()
3586 pctx = ctx.p1()
3583 parent = pctx.rev()
3587 parent = pctx.rev()
3584 matches.setdefault(rev, {})
3588 matches.setdefault(rev, {})
3585 matches.setdefault(parent, {})
3589 matches.setdefault(parent, {})
3586 files = revfiles.setdefault(rev, [])
3590 files = revfiles.setdefault(rev, [])
3587 for fn in fns:
3591 for fn in fns:
3588 flog = getfile(fn)
3592 flog = getfile(fn)
3589 try:
3593 try:
3590 fnode = ctx.filenode(fn)
3594 fnode = ctx.filenode(fn)
3591 except error.LookupError:
3595 except error.LookupError:
3592 continue
3596 continue
3593
3597
3594 copy = None
3598 copy = None
3595 if follow:
3599 if follow:
3596 copy = getrenamed(fn, rev)
3600 copy = getrenamed(fn, rev)
3597 if copy:
3601 if copy:
3598 copies.setdefault(rev, {})[fn] = copy
3602 copies.setdefault(rev, {})[fn] = copy
3599 if fn in skip:
3603 if fn in skip:
3600 skip.add(copy)
3604 skip.add(copy)
3601 if fn in skip:
3605 if fn in skip:
3602 continue
3606 continue
3603 files.append(fn)
3607 files.append(fn)
3604
3608
3605 if fn not in matches[rev]:
3609 if fn not in matches[rev]:
3606 try:
3610 try:
3607 content = flog.read(fnode)
3611 content = flog.read(fnode)
3608 except error.WdirUnsupported:
3612 except error.WdirUnsupported:
3609 content = ctx[fn].data()
3613 content = ctx[fn].data()
3610 grepbody(fn, rev, content)
3614 grepbody(fn, rev, content)
3611
3615
3612 pfn = copy or fn
3616 pfn = copy or fn
3613 if pfn not in matches[parent]:
3617 if pfn not in matches[parent]:
3614 try:
3618 try:
3615 fnode = pctx.filenode(pfn)
3619 fnode = pctx.filenode(pfn)
3616 grepbody(pfn, parent, flog.read(fnode))
3620 grepbody(pfn, parent, flog.read(fnode))
3617 except error.LookupError:
3621 except error.LookupError:
3618 pass
3622 pass
3619
3623
3620 ui.pager(b'grep')
3624 ui.pager(b'grep')
3621 fm = ui.formatter(b'grep', opts)
3625 fm = ui.formatter(b'grep', opts)
3622 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3626 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3623 rev = ctx.rev()
3627 rev = ctx.rev()
3624 parent = ctx.p1().rev()
3628 parent = ctx.p1().rev()
3625 for fn in sorted(revfiles.get(rev, [])):
3629 for fn in sorted(revfiles.get(rev, [])):
3626 states = matches[rev][fn]
3630 states = matches[rev][fn]
3627 copy = copies.get(rev, {}).get(fn)
3631 copy = copies.get(rev, {}).get(fn)
3628 if fn in skip:
3632 if fn in skip:
3629 if copy:
3633 if copy:
3630 skip.add(copy)
3634 skip.add(copy)
3631 continue
3635 continue
3632 pstates = matches.get(parent, {}).get(copy or fn, [])
3636 pstates = matches.get(parent, {}).get(copy or fn, [])
3633 if pstates or states:
3637 if pstates or states:
3634 r = display(fm, fn, ctx, pstates, states)
3638 r = display(fm, fn, ctx, pstates, states)
3635 found = found or r
3639 found = found or r
3636 if r and not diff and not all_files:
3640 if r and not diff and not all_files:
3637 skip.add(fn)
3641 skip.add(fn)
3638 if copy:
3642 if copy:
3639 skip.add(copy)
3643 skip.add(copy)
3640 del revfiles[rev]
3644 del revfiles[rev]
3641 # We will keep the matches dict for the duration of the window
3645 # We will keep the matches dict for the duration of the window
3642 # clear the matches dict once the window is over
3646 # clear the matches dict once the window is over
3643 if not revfiles:
3647 if not revfiles:
3644 matches.clear()
3648 matches.clear()
3645 fm.end()
3649 fm.end()
3646
3650
3647 return not found
3651 return not found
3648
3652
3649
3653
3650 @command(
3654 @command(
3651 b'heads',
3655 b'heads',
3652 [
3656 [
3653 (
3657 (
3654 b'r',
3658 b'r',
3655 b'rev',
3659 b'rev',
3656 b'',
3660 b'',
3657 _(b'show only heads which are descendants of STARTREV'),
3661 _(b'show only heads which are descendants of STARTREV'),
3658 _(b'STARTREV'),
3662 _(b'STARTREV'),
3659 ),
3663 ),
3660 (b't', b'topo', False, _(b'show topological heads only')),
3664 (b't', b'topo', False, _(b'show topological heads only')),
3661 (
3665 (
3662 b'a',
3666 b'a',
3663 b'active',
3667 b'active',
3664 False,
3668 False,
3665 _(b'show active branchheads only (DEPRECATED)'),
3669 _(b'show active branchheads only (DEPRECATED)'),
3666 ),
3670 ),
3667 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3671 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3668 ]
3672 ]
3669 + templateopts,
3673 + templateopts,
3670 _(b'[-ct] [-r STARTREV] [REV]...'),
3674 _(b'[-ct] [-r STARTREV] [REV]...'),
3671 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3675 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3672 intents={INTENT_READONLY},
3676 intents={INTENT_READONLY},
3673 )
3677 )
3674 def heads(ui, repo, *branchrevs, **opts):
3678 def heads(ui, repo, *branchrevs, **opts):
3675 """show branch heads
3679 """show branch heads
3676
3680
3677 With no arguments, show all open branch heads in the repository.
3681 With no arguments, show all open branch heads in the repository.
3678 Branch heads are changesets that have no descendants on the
3682 Branch heads are changesets that have no descendants on the
3679 same branch. They are where development generally takes place and
3683 same branch. They are where development generally takes place and
3680 are the usual targets for update and merge operations.
3684 are the usual targets for update and merge operations.
3681
3685
3682 If one or more REVs are given, only open branch heads on the
3686 If one or more REVs are given, only open branch heads on the
3683 branches associated with the specified changesets are shown. This
3687 branches associated with the specified changesets are shown. This
3684 means that you can use :hg:`heads .` to see the heads on the
3688 means that you can use :hg:`heads .` to see the heads on the
3685 currently checked-out branch.
3689 currently checked-out branch.
3686
3690
3687 If -c/--closed is specified, also show branch heads marked closed
3691 If -c/--closed is specified, also show branch heads marked closed
3688 (see :hg:`commit --close-branch`).
3692 (see :hg:`commit --close-branch`).
3689
3693
3690 If STARTREV is specified, only those heads that are descendants of
3694 If STARTREV is specified, only those heads that are descendants of
3691 STARTREV will be displayed.
3695 STARTREV will be displayed.
3692
3696
3693 If -t/--topo is specified, named branch mechanics will be ignored and only
3697 If -t/--topo is specified, named branch mechanics will be ignored and only
3694 topological heads (changesets with no children) will be shown.
3698 topological heads (changesets with no children) will be shown.
3695
3699
3696 Returns 0 if matching heads are found, 1 if not.
3700 Returns 0 if matching heads are found, 1 if not.
3697 """
3701 """
3698
3702
3699 opts = pycompat.byteskwargs(opts)
3703 opts = pycompat.byteskwargs(opts)
3700 start = None
3704 start = None
3701 rev = opts.get(b'rev')
3705 rev = opts.get(b'rev')
3702 if rev:
3706 if rev:
3703 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3707 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3704 start = scmutil.revsingle(repo, rev, None).node()
3708 start = scmutil.revsingle(repo, rev, None).node()
3705
3709
3706 if opts.get(b'topo'):
3710 if opts.get(b'topo'):
3707 heads = [repo[h] for h in repo.heads(start)]
3711 heads = [repo[h] for h in repo.heads(start)]
3708 else:
3712 else:
3709 heads = []
3713 heads = []
3710 for branch in repo.branchmap():
3714 for branch in repo.branchmap():
3711 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3715 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3712 heads = [repo[h] for h in heads]
3716 heads = [repo[h] for h in heads]
3713
3717
3714 if branchrevs:
3718 if branchrevs:
3715 branches = set(
3719 branches = set(
3716 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3720 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3717 )
3721 )
3718 heads = [h for h in heads if h.branch() in branches]
3722 heads = [h for h in heads if h.branch() in branches]
3719
3723
3720 if opts.get(b'active') and branchrevs:
3724 if opts.get(b'active') and branchrevs:
3721 dagheads = repo.heads(start)
3725 dagheads = repo.heads(start)
3722 heads = [h for h in heads if h.node() in dagheads]
3726 heads = [h for h in heads if h.node() in dagheads]
3723
3727
3724 if branchrevs:
3728 if branchrevs:
3725 haveheads = set(h.branch() for h in heads)
3729 haveheads = set(h.branch() for h in heads)
3726 if branches - haveheads:
3730 if branches - haveheads:
3727 headless = b', '.join(b for b in branches - haveheads)
3731 headless = b', '.join(b for b in branches - haveheads)
3728 msg = _(b'no open branch heads found on branches %s')
3732 msg = _(b'no open branch heads found on branches %s')
3729 if opts.get(b'rev'):
3733 if opts.get(b'rev'):
3730 msg += _(b' (started at %s)') % opts[b'rev']
3734 msg += _(b' (started at %s)') % opts[b'rev']
3731 ui.warn((msg + b'\n') % headless)
3735 ui.warn((msg + b'\n') % headless)
3732
3736
3733 if not heads:
3737 if not heads:
3734 return 1
3738 return 1
3735
3739
3736 ui.pager(b'heads')
3740 ui.pager(b'heads')
3737 heads = sorted(heads, key=lambda x: -(x.rev()))
3741 heads = sorted(heads, key=lambda x: -(x.rev()))
3738 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3742 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3739 for ctx in heads:
3743 for ctx in heads:
3740 displayer.show(ctx)
3744 displayer.show(ctx)
3741 displayer.close()
3745 displayer.close()
3742
3746
3743
3747
3744 @command(
3748 @command(
3745 b'help',
3749 b'help',
3746 [
3750 [
3747 (b'e', b'extension', None, _(b'show only help for extensions')),
3751 (b'e', b'extension', None, _(b'show only help for extensions')),
3748 (b'c', b'command', None, _(b'show only help for commands')),
3752 (b'c', b'command', None, _(b'show only help for commands')),
3749 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3753 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3750 (
3754 (
3751 b's',
3755 b's',
3752 b'system',
3756 b'system',
3753 [],
3757 [],
3754 _(b'show help for specific platform(s)'),
3758 _(b'show help for specific platform(s)'),
3755 _(b'PLATFORM'),
3759 _(b'PLATFORM'),
3756 ),
3760 ),
3757 ],
3761 ],
3758 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3762 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3759 helpcategory=command.CATEGORY_HELP,
3763 helpcategory=command.CATEGORY_HELP,
3760 norepo=True,
3764 norepo=True,
3761 intents={INTENT_READONLY},
3765 intents={INTENT_READONLY},
3762 )
3766 )
3763 def help_(ui, name=None, **opts):
3767 def help_(ui, name=None, **opts):
3764 """show help for a given topic or a help overview
3768 """show help for a given topic or a help overview
3765
3769
3766 With no arguments, print a list of commands with short help messages.
3770 With no arguments, print a list of commands with short help messages.
3767
3771
3768 Given a topic, extension, or command name, print help for that
3772 Given a topic, extension, or command name, print help for that
3769 topic.
3773 topic.
3770
3774
3771 Returns 0 if successful.
3775 Returns 0 if successful.
3772 """
3776 """
3773
3777
3774 keep = opts.get(r'system') or []
3778 keep = opts.get(r'system') or []
3775 if len(keep) == 0:
3779 if len(keep) == 0:
3776 if pycompat.sysplatform.startswith(b'win'):
3780 if pycompat.sysplatform.startswith(b'win'):
3777 keep.append(b'windows')
3781 keep.append(b'windows')
3778 elif pycompat.sysplatform == b'OpenVMS':
3782 elif pycompat.sysplatform == b'OpenVMS':
3779 keep.append(b'vms')
3783 keep.append(b'vms')
3780 elif pycompat.sysplatform == b'plan9':
3784 elif pycompat.sysplatform == b'plan9':
3781 keep.append(b'plan9')
3785 keep.append(b'plan9')
3782 else:
3786 else:
3783 keep.append(b'unix')
3787 keep.append(b'unix')
3784 keep.append(pycompat.sysplatform.lower())
3788 keep.append(pycompat.sysplatform.lower())
3785 if ui.verbose:
3789 if ui.verbose:
3786 keep.append(b'verbose')
3790 keep.append(b'verbose')
3787
3791
3788 commands = sys.modules[__name__]
3792 commands = sys.modules[__name__]
3789 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3793 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3790 ui.pager(b'help')
3794 ui.pager(b'help')
3791 ui.write(formatted)
3795 ui.write(formatted)
3792
3796
3793
3797
3794 @command(
3798 @command(
3795 b'identify|id',
3799 b'identify|id',
3796 [
3800 [
3797 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3801 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3798 (b'n', b'num', None, _(b'show local revision number')),
3802 (b'n', b'num', None, _(b'show local revision number')),
3799 (b'i', b'id', None, _(b'show global revision id')),
3803 (b'i', b'id', None, _(b'show global revision id')),
3800 (b'b', b'branch', None, _(b'show branch')),
3804 (b'b', b'branch', None, _(b'show branch')),
3801 (b't', b'tags', None, _(b'show tags')),
3805 (b't', b'tags', None, _(b'show tags')),
3802 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3806 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3803 ]
3807 ]
3804 + remoteopts
3808 + remoteopts
3805 + formatteropts,
3809 + formatteropts,
3806 _(b'[-nibtB] [-r REV] [SOURCE]'),
3810 _(b'[-nibtB] [-r REV] [SOURCE]'),
3807 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3811 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3808 optionalrepo=True,
3812 optionalrepo=True,
3809 intents={INTENT_READONLY},
3813 intents={INTENT_READONLY},
3810 )
3814 )
3811 def identify(
3815 def identify(
3812 ui,
3816 ui,
3813 repo,
3817 repo,
3814 source=None,
3818 source=None,
3815 rev=None,
3819 rev=None,
3816 num=None,
3820 num=None,
3817 id=None,
3821 id=None,
3818 branch=None,
3822 branch=None,
3819 tags=None,
3823 tags=None,
3820 bookmarks=None,
3824 bookmarks=None,
3821 **opts
3825 **opts
3822 ):
3826 ):
3823 """identify the working directory or specified revision
3827 """identify the working directory or specified revision
3824
3828
3825 Print a summary identifying the repository state at REV using one or
3829 Print a summary identifying the repository state at REV using one or
3826 two parent hash identifiers, followed by a "+" if the working
3830 two parent hash identifiers, followed by a "+" if the working
3827 directory has uncommitted changes, the branch name (if not default),
3831 directory has uncommitted changes, the branch name (if not default),
3828 a list of tags, and a list of bookmarks.
3832 a list of tags, and a list of bookmarks.
3829
3833
3830 When REV is not given, print a summary of the current state of the
3834 When REV is not given, print a summary of the current state of the
3831 repository including the working directory. Specify -r. to get information
3835 repository including the working directory. Specify -r. to get information
3832 of the working directory parent without scanning uncommitted changes.
3836 of the working directory parent without scanning uncommitted changes.
3833
3837
3834 Specifying a path to a repository root or Mercurial bundle will
3838 Specifying a path to a repository root or Mercurial bundle will
3835 cause lookup to operate on that repository/bundle.
3839 cause lookup to operate on that repository/bundle.
3836
3840
3837 .. container:: verbose
3841 .. container:: verbose
3838
3842
3839 Template:
3843 Template:
3840
3844
3841 The following keywords are supported in addition to the common template
3845 The following keywords are supported in addition to the common template
3842 keywords and functions. See also :hg:`help templates`.
3846 keywords and functions. See also :hg:`help templates`.
3843
3847
3844 :dirty: String. Character ``+`` denoting if the working directory has
3848 :dirty: String. Character ``+`` denoting if the working directory has
3845 uncommitted changes.
3849 uncommitted changes.
3846 :id: String. One or two nodes, optionally followed by ``+``.
3850 :id: String. One or two nodes, optionally followed by ``+``.
3847 :parents: List of strings. Parent nodes of the changeset.
3851 :parents: List of strings. Parent nodes of the changeset.
3848
3852
3849 Examples:
3853 Examples:
3850
3854
3851 - generate a build identifier for the working directory::
3855 - generate a build identifier for the working directory::
3852
3856
3853 hg id --id > build-id.dat
3857 hg id --id > build-id.dat
3854
3858
3855 - find the revision corresponding to a tag::
3859 - find the revision corresponding to a tag::
3856
3860
3857 hg id -n -r 1.3
3861 hg id -n -r 1.3
3858
3862
3859 - check the most recent revision of a remote repository::
3863 - check the most recent revision of a remote repository::
3860
3864
3861 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3865 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3862
3866
3863 See :hg:`log` for generating more information about specific revisions,
3867 See :hg:`log` for generating more information about specific revisions,
3864 including full hash identifiers.
3868 including full hash identifiers.
3865
3869
3866 Returns 0 if successful.
3870 Returns 0 if successful.
3867 """
3871 """
3868
3872
3869 opts = pycompat.byteskwargs(opts)
3873 opts = pycompat.byteskwargs(opts)
3870 if not repo and not source:
3874 if not repo and not source:
3871 raise error.Abort(
3875 raise error.Abort(
3872 _(b"there is no Mercurial repository here (.hg not found)")
3876 _(b"there is no Mercurial repository here (.hg not found)")
3873 )
3877 )
3874
3878
3875 default = not (num or id or branch or tags or bookmarks)
3879 default = not (num or id or branch or tags or bookmarks)
3876 output = []
3880 output = []
3877 revs = []
3881 revs = []
3878
3882
3879 if source:
3883 if source:
3880 source, branches = hg.parseurl(ui.expandpath(source))
3884 source, branches = hg.parseurl(ui.expandpath(source))
3881 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3885 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3882 repo = peer.local()
3886 repo = peer.local()
3883 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3887 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3884
3888
3885 fm = ui.formatter(b'identify', opts)
3889 fm = ui.formatter(b'identify', opts)
3886 fm.startitem()
3890 fm.startitem()
3887
3891
3888 if not repo:
3892 if not repo:
3889 if num or branch or tags:
3893 if num or branch or tags:
3890 raise error.Abort(
3894 raise error.Abort(
3891 _(b"can't query remote revision number, branch, or tags")
3895 _(b"can't query remote revision number, branch, or tags")
3892 )
3896 )
3893 if not rev and revs:
3897 if not rev and revs:
3894 rev = revs[0]
3898 rev = revs[0]
3895 if not rev:
3899 if not rev:
3896 rev = b"tip"
3900 rev = b"tip"
3897
3901
3898 remoterev = peer.lookup(rev)
3902 remoterev = peer.lookup(rev)
3899 hexrev = fm.hexfunc(remoterev)
3903 hexrev = fm.hexfunc(remoterev)
3900 if default or id:
3904 if default or id:
3901 output = [hexrev]
3905 output = [hexrev]
3902 fm.data(id=hexrev)
3906 fm.data(id=hexrev)
3903
3907
3904 @util.cachefunc
3908 @util.cachefunc
3905 def getbms():
3909 def getbms():
3906 bms = []
3910 bms = []
3907
3911
3908 if b'bookmarks' in peer.listkeys(b'namespaces'):
3912 if b'bookmarks' in peer.listkeys(b'namespaces'):
3909 hexremoterev = hex(remoterev)
3913 hexremoterev = hex(remoterev)
3910 bms = [
3914 bms = [
3911 bm
3915 bm
3912 for bm, bmr in pycompat.iteritems(
3916 for bm, bmr in pycompat.iteritems(
3913 peer.listkeys(b'bookmarks')
3917 peer.listkeys(b'bookmarks')
3914 )
3918 )
3915 if bmr == hexremoterev
3919 if bmr == hexremoterev
3916 ]
3920 ]
3917
3921
3918 return sorted(bms)
3922 return sorted(bms)
3919
3923
3920 if fm.isplain():
3924 if fm.isplain():
3921 if bookmarks:
3925 if bookmarks:
3922 output.extend(getbms())
3926 output.extend(getbms())
3923 elif default and not ui.quiet:
3927 elif default and not ui.quiet:
3924 # multiple bookmarks for a single parent separated by '/'
3928 # multiple bookmarks for a single parent separated by '/'
3925 bm = b'/'.join(getbms())
3929 bm = b'/'.join(getbms())
3926 if bm:
3930 if bm:
3927 output.append(bm)
3931 output.append(bm)
3928 else:
3932 else:
3929 fm.data(node=hex(remoterev))
3933 fm.data(node=hex(remoterev))
3930 if bookmarks or b'bookmarks' in fm.datahint():
3934 if bookmarks or b'bookmarks' in fm.datahint():
3931 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3935 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3932 else:
3936 else:
3933 if rev:
3937 if rev:
3934 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3938 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3935 ctx = scmutil.revsingle(repo, rev, None)
3939 ctx = scmutil.revsingle(repo, rev, None)
3936
3940
3937 if ctx.rev() is None:
3941 if ctx.rev() is None:
3938 ctx = repo[None]
3942 ctx = repo[None]
3939 parents = ctx.parents()
3943 parents = ctx.parents()
3940 taglist = []
3944 taglist = []
3941 for p in parents:
3945 for p in parents:
3942 taglist.extend(p.tags())
3946 taglist.extend(p.tags())
3943
3947
3944 dirty = b""
3948 dirty = b""
3945 if ctx.dirty(missing=True, merge=False, branch=False):
3949 if ctx.dirty(missing=True, merge=False, branch=False):
3946 dirty = b'+'
3950 dirty = b'+'
3947 fm.data(dirty=dirty)
3951 fm.data(dirty=dirty)
3948
3952
3949 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3953 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3950 if default or id:
3954 if default or id:
3951 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3955 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3952 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3956 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3953
3957
3954 if num:
3958 if num:
3955 numoutput = [b"%d" % p.rev() for p in parents]
3959 numoutput = [b"%d" % p.rev() for p in parents]
3956 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3960 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3957
3961
3958 fm.data(
3962 fm.data(
3959 parents=fm.formatlist(
3963 parents=fm.formatlist(
3960 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3964 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3961 )
3965 )
3962 )
3966 )
3963 else:
3967 else:
3964 hexoutput = fm.hexfunc(ctx.node())
3968 hexoutput = fm.hexfunc(ctx.node())
3965 if default or id:
3969 if default or id:
3966 output = [hexoutput]
3970 output = [hexoutput]
3967 fm.data(id=hexoutput)
3971 fm.data(id=hexoutput)
3968
3972
3969 if num:
3973 if num:
3970 output.append(pycompat.bytestr(ctx.rev()))
3974 output.append(pycompat.bytestr(ctx.rev()))
3971 taglist = ctx.tags()
3975 taglist = ctx.tags()
3972
3976
3973 if default and not ui.quiet:
3977 if default and not ui.quiet:
3974 b = ctx.branch()
3978 b = ctx.branch()
3975 if b != b'default':
3979 if b != b'default':
3976 output.append(b"(%s)" % b)
3980 output.append(b"(%s)" % b)
3977
3981
3978 # multiple tags for a single parent separated by '/'
3982 # multiple tags for a single parent separated by '/'
3979 t = b'/'.join(taglist)
3983 t = b'/'.join(taglist)
3980 if t:
3984 if t:
3981 output.append(t)
3985 output.append(t)
3982
3986
3983 # multiple bookmarks for a single parent separated by '/'
3987 # multiple bookmarks for a single parent separated by '/'
3984 bm = b'/'.join(ctx.bookmarks())
3988 bm = b'/'.join(ctx.bookmarks())
3985 if bm:
3989 if bm:
3986 output.append(bm)
3990 output.append(bm)
3987 else:
3991 else:
3988 if branch:
3992 if branch:
3989 output.append(ctx.branch())
3993 output.append(ctx.branch())
3990
3994
3991 if tags:
3995 if tags:
3992 output.extend(taglist)
3996 output.extend(taglist)
3993
3997
3994 if bookmarks:
3998 if bookmarks:
3995 output.extend(ctx.bookmarks())
3999 output.extend(ctx.bookmarks())
3996
4000
3997 fm.data(node=ctx.hex())
4001 fm.data(node=ctx.hex())
3998 fm.data(branch=ctx.branch())
4002 fm.data(branch=ctx.branch())
3999 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4003 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4000 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4004 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4001 fm.context(ctx=ctx)
4005 fm.context(ctx=ctx)
4002
4006
4003 fm.plain(b"%s\n" % b' '.join(output))
4007 fm.plain(b"%s\n" % b' '.join(output))
4004 fm.end()
4008 fm.end()
4005
4009
4006
4010
4007 @command(
4011 @command(
4008 b'import|patch',
4012 b'import|patch',
4009 [
4013 [
4010 (
4014 (
4011 b'p',
4015 b'p',
4012 b'strip',
4016 b'strip',
4013 1,
4017 1,
4014 _(
4018 _(
4015 b'directory strip option for patch. This has the same '
4019 b'directory strip option for patch. This has the same '
4016 b'meaning as the corresponding patch option'
4020 b'meaning as the corresponding patch option'
4017 ),
4021 ),
4018 _(b'NUM'),
4022 _(b'NUM'),
4019 ),
4023 ),
4020 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4024 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4021 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4025 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4022 (
4026 (
4023 b'f',
4027 b'f',
4024 b'force',
4028 b'force',
4025 None,
4029 None,
4026 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4030 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4027 ),
4031 ),
4028 (
4032 (
4029 b'',
4033 b'',
4030 b'no-commit',
4034 b'no-commit',
4031 None,
4035 None,
4032 _(b"don't commit, just update the working directory"),
4036 _(b"don't commit, just update the working directory"),
4033 ),
4037 ),
4034 (
4038 (
4035 b'',
4039 b'',
4036 b'bypass',
4040 b'bypass',
4037 None,
4041 None,
4038 _(b"apply patch without touching the working directory"),
4042 _(b"apply patch without touching the working directory"),
4039 ),
4043 ),
4040 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4044 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4041 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4045 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4042 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4046 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4043 (
4047 (
4044 b'',
4048 b'',
4045 b'import-branch',
4049 b'import-branch',
4046 None,
4050 None,
4047 _(b'use any branch information in patch (implied by --exact)'),
4051 _(b'use any branch information in patch (implied by --exact)'),
4048 ),
4052 ),
4049 ]
4053 ]
4050 + commitopts
4054 + commitopts
4051 + commitopts2
4055 + commitopts2
4052 + similarityopts,
4056 + similarityopts,
4053 _(b'[OPTION]... PATCH...'),
4057 _(b'[OPTION]... PATCH...'),
4054 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4058 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4055 )
4059 )
4056 def import_(ui, repo, patch1=None, *patches, **opts):
4060 def import_(ui, repo, patch1=None, *patches, **opts):
4057 """import an ordered set of patches
4061 """import an ordered set of patches
4058
4062
4059 Import a list of patches and commit them individually (unless
4063 Import a list of patches and commit them individually (unless
4060 --no-commit is specified).
4064 --no-commit is specified).
4061
4065
4062 To read a patch from standard input (stdin), use "-" as the patch
4066 To read a patch from standard input (stdin), use "-" as the patch
4063 name. If a URL is specified, the patch will be downloaded from
4067 name. If a URL is specified, the patch will be downloaded from
4064 there.
4068 there.
4065
4069
4066 Import first applies changes to the working directory (unless
4070 Import first applies changes to the working directory (unless
4067 --bypass is specified), import will abort if there are outstanding
4071 --bypass is specified), import will abort if there are outstanding
4068 changes.
4072 changes.
4069
4073
4070 Use --bypass to apply and commit patches directly to the
4074 Use --bypass to apply and commit patches directly to the
4071 repository, without affecting the working directory. Without
4075 repository, without affecting the working directory. Without
4072 --exact, patches will be applied on top of the working directory
4076 --exact, patches will be applied on top of the working directory
4073 parent revision.
4077 parent revision.
4074
4078
4075 You can import a patch straight from a mail message. Even patches
4079 You can import a patch straight from a mail message. Even patches
4076 as attachments work (to use the body part, it must have type
4080 as attachments work (to use the body part, it must have type
4077 text/plain or text/x-patch). From and Subject headers of email
4081 text/plain or text/x-patch). From and Subject headers of email
4078 message are used as default committer and commit message. All
4082 message are used as default committer and commit message. All
4079 text/plain body parts before first diff are added to the commit
4083 text/plain body parts before first diff are added to the commit
4080 message.
4084 message.
4081
4085
4082 If the imported patch was generated by :hg:`export`, user and
4086 If the imported patch was generated by :hg:`export`, user and
4083 description from patch override values from message headers and
4087 description from patch override values from message headers and
4084 body. Values given on command line with -m/--message and -u/--user
4088 body. Values given on command line with -m/--message and -u/--user
4085 override these.
4089 override these.
4086
4090
4087 If --exact is specified, import will set the working directory to
4091 If --exact is specified, import will set the working directory to
4088 the parent of each patch before applying it, and will abort if the
4092 the parent of each patch before applying it, and will abort if the
4089 resulting changeset has a different ID than the one recorded in
4093 resulting changeset has a different ID than the one recorded in
4090 the patch. This will guard against various ways that portable
4094 the patch. This will guard against various ways that portable
4091 patch formats and mail systems might fail to transfer Mercurial
4095 patch formats and mail systems might fail to transfer Mercurial
4092 data or metadata. See :hg:`bundle` for lossless transmission.
4096 data or metadata. See :hg:`bundle` for lossless transmission.
4093
4097
4094 Use --partial to ensure a changeset will be created from the patch
4098 Use --partial to ensure a changeset will be created from the patch
4095 even if some hunks fail to apply. Hunks that fail to apply will be
4099 even if some hunks fail to apply. Hunks that fail to apply will be
4096 written to a <target-file>.rej file. Conflicts can then be resolved
4100 written to a <target-file>.rej file. Conflicts can then be resolved
4097 by hand before :hg:`commit --amend` is run to update the created
4101 by hand before :hg:`commit --amend` is run to update the created
4098 changeset. This flag exists to let people import patches that
4102 changeset. This flag exists to let people import patches that
4099 partially apply without losing the associated metadata (author,
4103 partially apply without losing the associated metadata (author,
4100 date, description, ...).
4104 date, description, ...).
4101
4105
4102 .. note::
4106 .. note::
4103
4107
4104 When no hunks apply cleanly, :hg:`import --partial` will create
4108 When no hunks apply cleanly, :hg:`import --partial` will create
4105 an empty changeset, importing only the patch metadata.
4109 an empty changeset, importing only the patch metadata.
4106
4110
4107 With -s/--similarity, hg will attempt to discover renames and
4111 With -s/--similarity, hg will attempt to discover renames and
4108 copies in the patch in the same way as :hg:`addremove`.
4112 copies in the patch in the same way as :hg:`addremove`.
4109
4113
4110 It is possible to use external patch programs to perform the patch
4114 It is possible to use external patch programs to perform the patch
4111 by setting the ``ui.patch`` configuration option. For the default
4115 by setting the ``ui.patch`` configuration option. For the default
4112 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4116 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4113 See :hg:`help config` for more information about configuration
4117 See :hg:`help config` for more information about configuration
4114 files and how to use these options.
4118 files and how to use these options.
4115
4119
4116 See :hg:`help dates` for a list of formats valid for -d/--date.
4120 See :hg:`help dates` for a list of formats valid for -d/--date.
4117
4121
4118 .. container:: verbose
4122 .. container:: verbose
4119
4123
4120 Examples:
4124 Examples:
4121
4125
4122 - import a traditional patch from a website and detect renames::
4126 - import a traditional patch from a website and detect renames::
4123
4127
4124 hg import -s 80 http://example.com/bugfix.patch
4128 hg import -s 80 http://example.com/bugfix.patch
4125
4129
4126 - import a changeset from an hgweb server::
4130 - import a changeset from an hgweb server::
4127
4131
4128 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4132 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4129
4133
4130 - import all the patches in an Unix-style mbox::
4134 - import all the patches in an Unix-style mbox::
4131
4135
4132 hg import incoming-patches.mbox
4136 hg import incoming-patches.mbox
4133
4137
4134 - import patches from stdin::
4138 - import patches from stdin::
4135
4139
4136 hg import -
4140 hg import -
4137
4141
4138 - attempt to exactly restore an exported changeset (not always
4142 - attempt to exactly restore an exported changeset (not always
4139 possible)::
4143 possible)::
4140
4144
4141 hg import --exact proposed-fix.patch
4145 hg import --exact proposed-fix.patch
4142
4146
4143 - use an external tool to apply a patch which is too fuzzy for
4147 - use an external tool to apply a patch which is too fuzzy for
4144 the default internal tool.
4148 the default internal tool.
4145
4149
4146 hg import --config ui.patch="patch --merge" fuzzy.patch
4150 hg import --config ui.patch="patch --merge" fuzzy.patch
4147
4151
4148 - change the default fuzzing from 2 to a less strict 7
4152 - change the default fuzzing from 2 to a less strict 7
4149
4153
4150 hg import --config ui.fuzz=7 fuzz.patch
4154 hg import --config ui.fuzz=7 fuzz.patch
4151
4155
4152 Returns 0 on success, 1 on partial success (see --partial).
4156 Returns 0 on success, 1 on partial success (see --partial).
4153 """
4157 """
4154
4158
4155 opts = pycompat.byteskwargs(opts)
4159 opts = pycompat.byteskwargs(opts)
4156 if not patch1:
4160 if not patch1:
4157 raise error.Abort(_(b'need at least one patch to import'))
4161 raise error.Abort(_(b'need at least one patch to import'))
4158
4162
4159 patches = (patch1,) + patches
4163 patches = (patch1,) + patches
4160
4164
4161 date = opts.get(b'date')
4165 date = opts.get(b'date')
4162 if date:
4166 if date:
4163 opts[b'date'] = dateutil.parsedate(date)
4167 opts[b'date'] = dateutil.parsedate(date)
4164
4168
4165 exact = opts.get(b'exact')
4169 exact = opts.get(b'exact')
4166 update = not opts.get(b'bypass')
4170 update = not opts.get(b'bypass')
4167 if not update and opts.get(b'no_commit'):
4171 if not update and opts.get(b'no_commit'):
4168 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4172 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4169 try:
4173 try:
4170 sim = float(opts.get(b'similarity') or 0)
4174 sim = float(opts.get(b'similarity') or 0)
4171 except ValueError:
4175 except ValueError:
4172 raise error.Abort(_(b'similarity must be a number'))
4176 raise error.Abort(_(b'similarity must be a number'))
4173 if sim < 0 or sim > 100:
4177 if sim < 0 or sim > 100:
4174 raise error.Abort(_(b'similarity must be between 0 and 100'))
4178 raise error.Abort(_(b'similarity must be between 0 and 100'))
4175 if sim and not update:
4179 if sim and not update:
4176 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4180 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4177 if exact:
4181 if exact:
4178 if opts.get(b'edit'):
4182 if opts.get(b'edit'):
4179 raise error.Abort(_(b'cannot use --exact with --edit'))
4183 raise error.Abort(_(b'cannot use --exact with --edit'))
4180 if opts.get(b'prefix'):
4184 if opts.get(b'prefix'):
4181 raise error.Abort(_(b'cannot use --exact with --prefix'))
4185 raise error.Abort(_(b'cannot use --exact with --prefix'))
4182
4186
4183 base = opts[b"base"]
4187 base = opts[b"base"]
4184 msgs = []
4188 msgs = []
4185 ret = 0
4189 ret = 0
4186
4190
4187 with repo.wlock():
4191 with repo.wlock():
4188 if update:
4192 if update:
4189 cmdutil.checkunfinished(repo)
4193 cmdutil.checkunfinished(repo)
4190 if exact or not opts.get(b'force'):
4194 if exact or not opts.get(b'force'):
4191 cmdutil.bailifchanged(repo)
4195 cmdutil.bailifchanged(repo)
4192
4196
4193 if not opts.get(b'no_commit'):
4197 if not opts.get(b'no_commit'):
4194 lock = repo.lock
4198 lock = repo.lock
4195 tr = lambda: repo.transaction(b'import')
4199 tr = lambda: repo.transaction(b'import')
4196 dsguard = util.nullcontextmanager
4200 dsguard = util.nullcontextmanager
4197 else:
4201 else:
4198 lock = util.nullcontextmanager
4202 lock = util.nullcontextmanager
4199 tr = util.nullcontextmanager
4203 tr = util.nullcontextmanager
4200 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4204 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4201 with lock(), tr(), dsguard():
4205 with lock(), tr(), dsguard():
4202 parents = repo[None].parents()
4206 parents = repo[None].parents()
4203 for patchurl in patches:
4207 for patchurl in patches:
4204 if patchurl == b'-':
4208 if patchurl == b'-':
4205 ui.status(_(b'applying patch from stdin\n'))
4209 ui.status(_(b'applying patch from stdin\n'))
4206 patchfile = ui.fin
4210 patchfile = ui.fin
4207 patchurl = b'stdin' # for error message
4211 patchurl = b'stdin' # for error message
4208 else:
4212 else:
4209 patchurl = os.path.join(base, patchurl)
4213 patchurl = os.path.join(base, patchurl)
4210 ui.status(_(b'applying %s\n') % patchurl)
4214 ui.status(_(b'applying %s\n') % patchurl)
4211 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4215 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4212
4216
4213 haspatch = False
4217 haspatch = False
4214 for hunk in patch.split(patchfile):
4218 for hunk in patch.split(patchfile):
4215 with patch.extract(ui, hunk) as patchdata:
4219 with patch.extract(ui, hunk) as patchdata:
4216 msg, node, rej = cmdutil.tryimportone(
4220 msg, node, rej = cmdutil.tryimportone(
4217 ui, repo, patchdata, parents, opts, msgs, hg.clean
4221 ui, repo, patchdata, parents, opts, msgs, hg.clean
4218 )
4222 )
4219 if msg:
4223 if msg:
4220 haspatch = True
4224 haspatch = True
4221 ui.note(msg + b'\n')
4225 ui.note(msg + b'\n')
4222 if update or exact:
4226 if update or exact:
4223 parents = repo[None].parents()
4227 parents = repo[None].parents()
4224 else:
4228 else:
4225 parents = [repo[node]]
4229 parents = [repo[node]]
4226 if rej:
4230 if rej:
4227 ui.write_err(_(b"patch applied partially\n"))
4231 ui.write_err(_(b"patch applied partially\n"))
4228 ui.write_err(
4232 ui.write_err(
4229 _(
4233 _(
4230 b"(fix the .rej files and run "
4234 b"(fix the .rej files and run "
4231 b"`hg commit --amend`)\n"
4235 b"`hg commit --amend`)\n"
4232 )
4236 )
4233 )
4237 )
4234 ret = 1
4238 ret = 1
4235 break
4239 break
4236
4240
4237 if not haspatch:
4241 if not haspatch:
4238 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4242 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4239
4243
4240 if msgs:
4244 if msgs:
4241 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4245 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4242 return ret
4246 return ret
4243
4247
4244
4248
4245 @command(
4249 @command(
4246 b'incoming|in',
4250 b'incoming|in',
4247 [
4251 [
4248 (
4252 (
4249 b'f',
4253 b'f',
4250 b'force',
4254 b'force',
4251 None,
4255 None,
4252 _(b'run even if remote repository is unrelated'),
4256 _(b'run even if remote repository is unrelated'),
4253 ),
4257 ),
4254 (b'n', b'newest-first', None, _(b'show newest record first')),
4258 (b'n', b'newest-first', None, _(b'show newest record first')),
4255 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4259 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4256 (
4260 (
4257 b'r',
4261 b'r',
4258 b'rev',
4262 b'rev',
4259 [],
4263 [],
4260 _(b'a remote changeset intended to be added'),
4264 _(b'a remote changeset intended to be added'),
4261 _(b'REV'),
4265 _(b'REV'),
4262 ),
4266 ),
4263 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4267 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4264 (
4268 (
4265 b'b',
4269 b'b',
4266 b'branch',
4270 b'branch',
4267 [],
4271 [],
4268 _(b'a specific branch you would like to pull'),
4272 _(b'a specific branch you would like to pull'),
4269 _(b'BRANCH'),
4273 _(b'BRANCH'),
4270 ),
4274 ),
4271 ]
4275 ]
4272 + logopts
4276 + logopts
4273 + remoteopts
4277 + remoteopts
4274 + subrepoopts,
4278 + subrepoopts,
4275 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4279 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4276 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4280 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4277 )
4281 )
4278 def incoming(ui, repo, source=b"default", **opts):
4282 def incoming(ui, repo, source=b"default", **opts):
4279 """show new changesets found in source
4283 """show new changesets found in source
4280
4284
4281 Show new changesets found in the specified path/URL or the default
4285 Show new changesets found in the specified path/URL or the default
4282 pull location. These are the changesets that would have been pulled
4286 pull location. These are the changesets that would have been pulled
4283 by :hg:`pull` at the time you issued this command.
4287 by :hg:`pull` at the time you issued this command.
4284
4288
4285 See pull for valid source format details.
4289 See pull for valid source format details.
4286
4290
4287 .. container:: verbose
4291 .. container:: verbose
4288
4292
4289 With -B/--bookmarks, the result of bookmark comparison between
4293 With -B/--bookmarks, the result of bookmark comparison between
4290 local and remote repositories is displayed. With -v/--verbose,
4294 local and remote repositories is displayed. With -v/--verbose,
4291 status is also displayed for each bookmark like below::
4295 status is also displayed for each bookmark like below::
4292
4296
4293 BM1 01234567890a added
4297 BM1 01234567890a added
4294 BM2 1234567890ab advanced
4298 BM2 1234567890ab advanced
4295 BM3 234567890abc diverged
4299 BM3 234567890abc diverged
4296 BM4 34567890abcd changed
4300 BM4 34567890abcd changed
4297
4301
4298 The action taken locally when pulling depends on the
4302 The action taken locally when pulling depends on the
4299 status of each bookmark:
4303 status of each bookmark:
4300
4304
4301 :``added``: pull will create it
4305 :``added``: pull will create it
4302 :``advanced``: pull will update it
4306 :``advanced``: pull will update it
4303 :``diverged``: pull will create a divergent bookmark
4307 :``diverged``: pull will create a divergent bookmark
4304 :``changed``: result depends on remote changesets
4308 :``changed``: result depends on remote changesets
4305
4309
4306 From the point of view of pulling behavior, bookmark
4310 From the point of view of pulling behavior, bookmark
4307 existing only in the remote repository are treated as ``added``,
4311 existing only in the remote repository are treated as ``added``,
4308 even if it is in fact locally deleted.
4312 even if it is in fact locally deleted.
4309
4313
4310 .. container:: verbose
4314 .. container:: verbose
4311
4315
4312 For remote repository, using --bundle avoids downloading the
4316 For remote repository, using --bundle avoids downloading the
4313 changesets twice if the incoming is followed by a pull.
4317 changesets twice if the incoming is followed by a pull.
4314
4318
4315 Examples:
4319 Examples:
4316
4320
4317 - show incoming changes with patches and full description::
4321 - show incoming changes with patches and full description::
4318
4322
4319 hg incoming -vp
4323 hg incoming -vp
4320
4324
4321 - show incoming changes excluding merges, store a bundle::
4325 - show incoming changes excluding merges, store a bundle::
4322
4326
4323 hg in -vpM --bundle incoming.hg
4327 hg in -vpM --bundle incoming.hg
4324 hg pull incoming.hg
4328 hg pull incoming.hg
4325
4329
4326 - briefly list changes inside a bundle::
4330 - briefly list changes inside a bundle::
4327
4331
4328 hg in changes.hg -T "{desc|firstline}\\n"
4332 hg in changes.hg -T "{desc|firstline}\\n"
4329
4333
4330 Returns 0 if there are incoming changes, 1 otherwise.
4334 Returns 0 if there are incoming changes, 1 otherwise.
4331 """
4335 """
4332 opts = pycompat.byteskwargs(opts)
4336 opts = pycompat.byteskwargs(opts)
4333 if opts.get(b'graph'):
4337 if opts.get(b'graph'):
4334 logcmdutil.checkunsupportedgraphflags([], opts)
4338 logcmdutil.checkunsupportedgraphflags([], opts)
4335
4339
4336 def display(other, chlist, displayer):
4340 def display(other, chlist, displayer):
4337 revdag = logcmdutil.graphrevs(other, chlist, opts)
4341 revdag = logcmdutil.graphrevs(other, chlist, opts)
4338 logcmdutil.displaygraph(
4342 logcmdutil.displaygraph(
4339 ui, repo, revdag, displayer, graphmod.asciiedges
4343 ui, repo, revdag, displayer, graphmod.asciiedges
4340 )
4344 )
4341
4345
4342 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4346 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4343 return 0
4347 return 0
4344
4348
4345 if opts.get(b'bundle') and opts.get(b'subrepos'):
4349 if opts.get(b'bundle') and opts.get(b'subrepos'):
4346 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4350 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4347
4351
4348 if opts.get(b'bookmarks'):
4352 if opts.get(b'bookmarks'):
4349 source, branches = hg.parseurl(
4353 source, branches = hg.parseurl(
4350 ui.expandpath(source), opts.get(b'branch')
4354 ui.expandpath(source), opts.get(b'branch')
4351 )
4355 )
4352 other = hg.peer(repo, opts, source)
4356 other = hg.peer(repo, opts, source)
4353 if b'bookmarks' not in other.listkeys(b'namespaces'):
4357 if b'bookmarks' not in other.listkeys(b'namespaces'):
4354 ui.warn(_(b"remote doesn't support bookmarks\n"))
4358 ui.warn(_(b"remote doesn't support bookmarks\n"))
4355 return 0
4359 return 0
4356 ui.pager(b'incoming')
4360 ui.pager(b'incoming')
4357 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4361 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4358 return bookmarks.incoming(ui, repo, other)
4362 return bookmarks.incoming(ui, repo, other)
4359
4363
4360 repo._subtoppath = ui.expandpath(source)
4364 repo._subtoppath = ui.expandpath(source)
4361 try:
4365 try:
4362 return hg.incoming(ui, repo, source, opts)
4366 return hg.incoming(ui, repo, source, opts)
4363 finally:
4367 finally:
4364 del repo._subtoppath
4368 del repo._subtoppath
4365
4369
4366
4370
4367 @command(
4371 @command(
4368 b'init',
4372 b'init',
4369 remoteopts,
4373 remoteopts,
4370 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4374 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4371 helpcategory=command.CATEGORY_REPO_CREATION,
4375 helpcategory=command.CATEGORY_REPO_CREATION,
4372 helpbasic=True,
4376 helpbasic=True,
4373 norepo=True,
4377 norepo=True,
4374 )
4378 )
4375 def init(ui, dest=b".", **opts):
4379 def init(ui, dest=b".", **opts):
4376 """create a new repository in the given directory
4380 """create a new repository in the given directory
4377
4381
4378 Initialize a new repository in the given directory. If the given
4382 Initialize a new repository in the given directory. If the given
4379 directory does not exist, it will be created.
4383 directory does not exist, it will be created.
4380
4384
4381 If no directory is given, the current directory is used.
4385 If no directory is given, the current directory is used.
4382
4386
4383 It is possible to specify an ``ssh://`` URL as the destination.
4387 It is possible to specify an ``ssh://`` URL as the destination.
4384 See :hg:`help urls` for more information.
4388 See :hg:`help urls` for more information.
4385
4389
4386 Returns 0 on success.
4390 Returns 0 on success.
4387 """
4391 """
4388 opts = pycompat.byteskwargs(opts)
4392 opts = pycompat.byteskwargs(opts)
4389 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4393 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390
4394
4391
4395
4392 @command(
4396 @command(
4393 b'locate',
4397 b'locate',
4394 [
4398 [
4395 (
4399 (
4396 b'r',
4400 b'r',
4397 b'rev',
4401 b'rev',
4398 b'',
4402 b'',
4399 _(b'search the repository as it is in REV'),
4403 _(b'search the repository as it is in REV'),
4400 _(b'REV'),
4404 _(b'REV'),
4401 ),
4405 ),
4402 (
4406 (
4403 b'0',
4407 b'0',
4404 b'print0',
4408 b'print0',
4405 None,
4409 None,
4406 _(b'end filenames with NUL, for use with xargs'),
4410 _(b'end filenames with NUL, for use with xargs'),
4407 ),
4411 ),
4408 (
4412 (
4409 b'f',
4413 b'f',
4410 b'fullpath',
4414 b'fullpath',
4411 None,
4415 None,
4412 _(b'print complete paths from the filesystem root'),
4416 _(b'print complete paths from the filesystem root'),
4413 ),
4417 ),
4414 ]
4418 ]
4415 + walkopts,
4419 + walkopts,
4416 _(b'[OPTION]... [PATTERN]...'),
4420 _(b'[OPTION]... [PATTERN]...'),
4417 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4421 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4418 )
4422 )
4419 def locate(ui, repo, *pats, **opts):
4423 def locate(ui, repo, *pats, **opts):
4420 """locate files matching specific patterns (DEPRECATED)
4424 """locate files matching specific patterns (DEPRECATED)
4421
4425
4422 Print files under Mercurial control in the working directory whose
4426 Print files under Mercurial control in the working directory whose
4423 names match the given patterns.
4427 names match the given patterns.
4424
4428
4425 By default, this command searches all directories in the working
4429 By default, this command searches all directories in the working
4426 directory. To search just the current directory and its
4430 directory. To search just the current directory and its
4427 subdirectories, use "--include .".
4431 subdirectories, use "--include .".
4428
4432
4429 If no patterns are given to match, this command prints the names
4433 If no patterns are given to match, this command prints the names
4430 of all files under Mercurial control in the working directory.
4434 of all files under Mercurial control in the working directory.
4431
4435
4432 If you want to feed the output of this command into the "xargs"
4436 If you want to feed the output of this command into the "xargs"
4433 command, use the -0 option to both this command and "xargs". This
4437 command, use the -0 option to both this command and "xargs". This
4434 will avoid the problem of "xargs" treating single filenames that
4438 will avoid the problem of "xargs" treating single filenames that
4435 contain whitespace as multiple filenames.
4439 contain whitespace as multiple filenames.
4436
4440
4437 See :hg:`help files` for a more versatile command.
4441 See :hg:`help files` for a more versatile command.
4438
4442
4439 Returns 0 if a match is found, 1 otherwise.
4443 Returns 0 if a match is found, 1 otherwise.
4440 """
4444 """
4441 opts = pycompat.byteskwargs(opts)
4445 opts = pycompat.byteskwargs(opts)
4442 if opts.get(b'print0'):
4446 if opts.get(b'print0'):
4443 end = b'\0'
4447 end = b'\0'
4444 else:
4448 else:
4445 end = b'\n'
4449 end = b'\n'
4446 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4450 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4447
4451
4448 ret = 1
4452 ret = 1
4449 m = scmutil.match(
4453 m = scmutil.match(
4450 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4454 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4451 )
4455 )
4452
4456
4453 ui.pager(b'locate')
4457 ui.pager(b'locate')
4454 if ctx.rev() is None:
4458 if ctx.rev() is None:
4455 # When run on the working copy, "locate" includes removed files, so
4459 # When run on the working copy, "locate" includes removed files, so
4456 # we get the list of files from the dirstate.
4460 # we get the list of files from the dirstate.
4457 filesgen = sorted(repo.dirstate.matches(m))
4461 filesgen = sorted(repo.dirstate.matches(m))
4458 else:
4462 else:
4459 filesgen = ctx.matches(m)
4463 filesgen = ctx.matches(m)
4460 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4464 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4461 for abs in filesgen:
4465 for abs in filesgen:
4462 if opts.get(b'fullpath'):
4466 if opts.get(b'fullpath'):
4463 ui.write(repo.wjoin(abs), end)
4467 ui.write(repo.wjoin(abs), end)
4464 else:
4468 else:
4465 ui.write(uipathfn(abs), end)
4469 ui.write(uipathfn(abs), end)
4466 ret = 0
4470 ret = 0
4467
4471
4468 return ret
4472 return ret
4469
4473
4470
4474
4471 @command(
4475 @command(
4472 b'log|history',
4476 b'log|history',
4473 [
4477 [
4474 (
4478 (
4475 b'f',
4479 b'f',
4476 b'follow',
4480 b'follow',
4477 None,
4481 None,
4478 _(
4482 _(
4479 b'follow changeset history, or file history across copies and renames'
4483 b'follow changeset history, or file history across copies and renames'
4480 ),
4484 ),
4481 ),
4485 ),
4482 (
4486 (
4483 b'',
4487 b'',
4484 b'follow-first',
4488 b'follow-first',
4485 None,
4489 None,
4486 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4490 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4487 ),
4491 ),
4488 (
4492 (
4489 b'd',
4493 b'd',
4490 b'date',
4494 b'date',
4491 b'',
4495 b'',
4492 _(b'show revisions matching date spec'),
4496 _(b'show revisions matching date spec'),
4493 _(b'DATE'),
4497 _(b'DATE'),
4494 ),
4498 ),
4495 (b'C', b'copies', None, _(b'show copied files')),
4499 (b'C', b'copies', None, _(b'show copied files')),
4496 (
4500 (
4497 b'k',
4501 b'k',
4498 b'keyword',
4502 b'keyword',
4499 [],
4503 [],
4500 _(b'do case-insensitive search for a given text'),
4504 _(b'do case-insensitive search for a given text'),
4501 _(b'TEXT'),
4505 _(b'TEXT'),
4502 ),
4506 ),
4503 (
4507 (
4504 b'r',
4508 b'r',
4505 b'rev',
4509 b'rev',
4506 [],
4510 [],
4507 _(b'show the specified revision or revset'),
4511 _(b'show the specified revision or revset'),
4508 _(b'REV'),
4512 _(b'REV'),
4509 ),
4513 ),
4510 (
4514 (
4511 b'L',
4515 b'L',
4512 b'line-range',
4516 b'line-range',
4513 [],
4517 [],
4514 _(b'follow line range of specified file (EXPERIMENTAL)'),
4518 _(b'follow line range of specified file (EXPERIMENTAL)'),
4515 _(b'FILE,RANGE'),
4519 _(b'FILE,RANGE'),
4516 ),
4520 ),
4517 (
4521 (
4518 b'',
4522 b'',
4519 b'removed',
4523 b'removed',
4520 None,
4524 None,
4521 _(b'include revisions where files were removed'),
4525 _(b'include revisions where files were removed'),
4522 ),
4526 ),
4523 (
4527 (
4524 b'm',
4528 b'm',
4525 b'only-merges',
4529 b'only-merges',
4526 None,
4530 None,
4527 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4531 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4528 ),
4532 ),
4529 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4533 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4530 (
4534 (
4531 b'',
4535 b'',
4532 b'only-branch',
4536 b'only-branch',
4533 [],
4537 [],
4534 _(
4538 _(
4535 b'show only changesets within the given named branch (DEPRECATED)'
4539 b'show only changesets within the given named branch (DEPRECATED)'
4536 ),
4540 ),
4537 _(b'BRANCH'),
4541 _(b'BRANCH'),
4538 ),
4542 ),
4539 (
4543 (
4540 b'b',
4544 b'b',
4541 b'branch',
4545 b'branch',
4542 [],
4546 [],
4543 _(b'show changesets within the given named branch'),
4547 _(b'show changesets within the given named branch'),
4544 _(b'BRANCH'),
4548 _(b'BRANCH'),
4545 ),
4549 ),
4546 (
4550 (
4547 b'P',
4551 b'P',
4548 b'prune',
4552 b'prune',
4549 [],
4553 [],
4550 _(b'do not display revision or any of its ancestors'),
4554 _(b'do not display revision or any of its ancestors'),
4551 _(b'REV'),
4555 _(b'REV'),
4552 ),
4556 ),
4553 ]
4557 ]
4554 + logopts
4558 + logopts
4555 + walkopts,
4559 + walkopts,
4556 _(b'[OPTION]... [FILE]'),
4560 _(b'[OPTION]... [FILE]'),
4557 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4561 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4558 helpbasic=True,
4562 helpbasic=True,
4559 inferrepo=True,
4563 inferrepo=True,
4560 intents={INTENT_READONLY},
4564 intents={INTENT_READONLY},
4561 )
4565 )
4562 def log(ui, repo, *pats, **opts):
4566 def log(ui, repo, *pats, **opts):
4563 """show revision history of entire repository or files
4567 """show revision history of entire repository or files
4564
4568
4565 Print the revision history of the specified files or the entire
4569 Print the revision history of the specified files or the entire
4566 project.
4570 project.
4567
4571
4568 If no revision range is specified, the default is ``tip:0`` unless
4572 If no revision range is specified, the default is ``tip:0`` unless
4569 --follow is set, in which case the working directory parent is
4573 --follow is set, in which case the working directory parent is
4570 used as the starting revision.
4574 used as the starting revision.
4571
4575
4572 File history is shown without following rename or copy history of
4576 File history is shown without following rename or copy history of
4573 files. Use -f/--follow with a filename to follow history across
4577 files. Use -f/--follow with a filename to follow history across
4574 renames and copies. --follow without a filename will only show
4578 renames and copies. --follow without a filename will only show
4575 ancestors of the starting revision.
4579 ancestors of the starting revision.
4576
4580
4577 By default this command prints revision number and changeset id,
4581 By default this command prints revision number and changeset id,
4578 tags, non-trivial parents, user, date and time, and a summary for
4582 tags, non-trivial parents, user, date and time, and a summary for
4579 each commit. When the -v/--verbose switch is used, the list of
4583 each commit. When the -v/--verbose switch is used, the list of
4580 changed files and full commit message are shown.
4584 changed files and full commit message are shown.
4581
4585
4582 With --graph the revisions are shown as an ASCII art DAG with the most
4586 With --graph the revisions are shown as an ASCII art DAG with the most
4583 recent changeset at the top.
4587 recent changeset at the top.
4584 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4588 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4585 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4589 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4586 changeset from the lines below is a parent of the 'o' merge on the same
4590 changeset from the lines below is a parent of the 'o' merge on the same
4587 line.
4591 line.
4588 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4592 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4589 of a '|' indicates one or more revisions in a path are omitted.
4593 of a '|' indicates one or more revisions in a path are omitted.
4590
4594
4591 .. container:: verbose
4595 .. container:: verbose
4592
4596
4593 Use -L/--line-range FILE,M:N options to follow the history of lines
4597 Use -L/--line-range FILE,M:N options to follow the history of lines
4594 from M to N in FILE. With -p/--patch only diff hunks affecting
4598 from M to N in FILE. With -p/--patch only diff hunks affecting
4595 specified line range will be shown. This option requires --follow;
4599 specified line range will be shown. This option requires --follow;
4596 it can be specified multiple times. Currently, this option is not
4600 it can be specified multiple times. Currently, this option is not
4597 compatible with --graph. This option is experimental.
4601 compatible with --graph. This option is experimental.
4598
4602
4599 .. note::
4603 .. note::
4600
4604
4601 :hg:`log --patch` may generate unexpected diff output for merge
4605 :hg:`log --patch` may generate unexpected diff output for merge
4602 changesets, as it will only compare the merge changeset against
4606 changesets, as it will only compare the merge changeset against
4603 its first parent. Also, only files different from BOTH parents
4607 its first parent. Also, only files different from BOTH parents
4604 will appear in files:.
4608 will appear in files:.
4605
4609
4606 .. note::
4610 .. note::
4607
4611
4608 For performance reasons, :hg:`log FILE` may omit duplicate changes
4612 For performance reasons, :hg:`log FILE` may omit duplicate changes
4609 made on branches and will not show removals or mode changes. To
4613 made on branches and will not show removals or mode changes. To
4610 see all such changes, use the --removed switch.
4614 see all such changes, use the --removed switch.
4611
4615
4612 .. container:: verbose
4616 .. container:: verbose
4613
4617
4614 .. note::
4618 .. note::
4615
4619
4616 The history resulting from -L/--line-range options depends on diff
4620 The history resulting from -L/--line-range options depends on diff
4617 options; for instance if white-spaces are ignored, respective changes
4621 options; for instance if white-spaces are ignored, respective changes
4618 with only white-spaces in specified line range will not be listed.
4622 with only white-spaces in specified line range will not be listed.
4619
4623
4620 .. container:: verbose
4624 .. container:: verbose
4621
4625
4622 Some examples:
4626 Some examples:
4623
4627
4624 - changesets with full descriptions and file lists::
4628 - changesets with full descriptions and file lists::
4625
4629
4626 hg log -v
4630 hg log -v
4627
4631
4628 - changesets ancestral to the working directory::
4632 - changesets ancestral to the working directory::
4629
4633
4630 hg log -f
4634 hg log -f
4631
4635
4632 - last 10 commits on the current branch::
4636 - last 10 commits on the current branch::
4633
4637
4634 hg log -l 10 -b .
4638 hg log -l 10 -b .
4635
4639
4636 - changesets showing all modifications of a file, including removals::
4640 - changesets showing all modifications of a file, including removals::
4637
4641
4638 hg log --removed file.c
4642 hg log --removed file.c
4639
4643
4640 - all changesets that touch a directory, with diffs, excluding merges::
4644 - all changesets that touch a directory, with diffs, excluding merges::
4641
4645
4642 hg log -Mp lib/
4646 hg log -Mp lib/
4643
4647
4644 - all revision numbers that match a keyword::
4648 - all revision numbers that match a keyword::
4645
4649
4646 hg log -k bug --template "{rev}\\n"
4650 hg log -k bug --template "{rev}\\n"
4647
4651
4648 - the full hash identifier of the working directory parent::
4652 - the full hash identifier of the working directory parent::
4649
4653
4650 hg log -r . --template "{node}\\n"
4654 hg log -r . --template "{node}\\n"
4651
4655
4652 - list available log templates::
4656 - list available log templates::
4653
4657
4654 hg log -T list
4658 hg log -T list
4655
4659
4656 - check if a given changeset is included in a tagged release::
4660 - check if a given changeset is included in a tagged release::
4657
4661
4658 hg log -r "a21ccf and ancestor(1.9)"
4662 hg log -r "a21ccf and ancestor(1.9)"
4659
4663
4660 - find all changesets by some user in a date range::
4664 - find all changesets by some user in a date range::
4661
4665
4662 hg log -k alice -d "may 2008 to jul 2008"
4666 hg log -k alice -d "may 2008 to jul 2008"
4663
4667
4664 - summary of all changesets after the last tag::
4668 - summary of all changesets after the last tag::
4665
4669
4666 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4670 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4667
4671
4668 - changesets touching lines 13 to 23 for file.c::
4672 - changesets touching lines 13 to 23 for file.c::
4669
4673
4670 hg log -L file.c,13:23
4674 hg log -L file.c,13:23
4671
4675
4672 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4676 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4673 main.c with patch::
4677 main.c with patch::
4674
4678
4675 hg log -L file.c,13:23 -L main.c,2:6 -p
4679 hg log -L file.c,13:23 -L main.c,2:6 -p
4676
4680
4677 See :hg:`help dates` for a list of formats valid for -d/--date.
4681 See :hg:`help dates` for a list of formats valid for -d/--date.
4678
4682
4679 See :hg:`help revisions` for more about specifying and ordering
4683 See :hg:`help revisions` for more about specifying and ordering
4680 revisions.
4684 revisions.
4681
4685
4682 See :hg:`help templates` for more about pre-packaged styles and
4686 See :hg:`help templates` for more about pre-packaged styles and
4683 specifying custom templates. The default template used by the log
4687 specifying custom templates. The default template used by the log
4684 command can be customized via the ``ui.logtemplate`` configuration
4688 command can be customized via the ``ui.logtemplate`` configuration
4685 setting.
4689 setting.
4686
4690
4687 Returns 0 on success.
4691 Returns 0 on success.
4688
4692
4689 """
4693 """
4690 opts = pycompat.byteskwargs(opts)
4694 opts = pycompat.byteskwargs(opts)
4691 linerange = opts.get(b'line_range')
4695 linerange = opts.get(b'line_range')
4692
4696
4693 if linerange and not opts.get(b'follow'):
4697 if linerange and not opts.get(b'follow'):
4694 raise error.Abort(_(b'--line-range requires --follow'))
4698 raise error.Abort(_(b'--line-range requires --follow'))
4695
4699
4696 if linerange and pats:
4700 if linerange and pats:
4697 # TODO: take pats as patterns with no line-range filter
4701 # TODO: take pats as patterns with no line-range filter
4698 raise error.Abort(
4702 raise error.Abort(
4699 _(b'FILE arguments are not compatible with --line-range option')
4703 _(b'FILE arguments are not compatible with --line-range option')
4700 )
4704 )
4701
4705
4702 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4706 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4703 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4707 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4704 if linerange:
4708 if linerange:
4705 # TODO: should follow file history from logcmdutil._initialrevs(),
4709 # TODO: should follow file history from logcmdutil._initialrevs(),
4706 # then filter the result by logcmdutil._makerevset() and --limit
4710 # then filter the result by logcmdutil._makerevset() and --limit
4707 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4711 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4708
4712
4709 getcopies = None
4713 getcopies = None
4710 if opts.get(b'copies'):
4714 if opts.get(b'copies'):
4711 endrev = None
4715 endrev = None
4712 if revs:
4716 if revs:
4713 endrev = revs.max() + 1
4717 endrev = revs.max() + 1
4714 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4718 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4715
4719
4716 ui.pager(b'log')
4720 ui.pager(b'log')
4717 displayer = logcmdutil.changesetdisplayer(
4721 displayer = logcmdutil.changesetdisplayer(
4718 ui, repo, opts, differ, buffered=True
4722 ui, repo, opts, differ, buffered=True
4719 )
4723 )
4720 if opts.get(b'graph'):
4724 if opts.get(b'graph'):
4721 displayfn = logcmdutil.displaygraphrevs
4725 displayfn = logcmdutil.displaygraphrevs
4722 else:
4726 else:
4723 displayfn = logcmdutil.displayrevs
4727 displayfn = logcmdutil.displayrevs
4724 displayfn(ui, repo, revs, displayer, getcopies)
4728 displayfn(ui, repo, revs, displayer, getcopies)
4725
4729
4726
4730
4727 @command(
4731 @command(
4728 b'manifest',
4732 b'manifest',
4729 [
4733 [
4730 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4734 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4731 (b'', b'all', False, _(b"list files from all revisions")),
4735 (b'', b'all', False, _(b"list files from all revisions")),
4732 ]
4736 ]
4733 + formatteropts,
4737 + formatteropts,
4734 _(b'[-r REV]'),
4738 _(b'[-r REV]'),
4735 helpcategory=command.CATEGORY_MAINTENANCE,
4739 helpcategory=command.CATEGORY_MAINTENANCE,
4736 intents={INTENT_READONLY},
4740 intents={INTENT_READONLY},
4737 )
4741 )
4738 def manifest(ui, repo, node=None, rev=None, **opts):
4742 def manifest(ui, repo, node=None, rev=None, **opts):
4739 """output the current or given revision of the project manifest
4743 """output the current or given revision of the project manifest
4740
4744
4741 Print a list of version controlled files for the given revision.
4745 Print a list of version controlled files for the given revision.
4742 If no revision is given, the first parent of the working directory
4746 If no revision is given, the first parent of the working directory
4743 is used, or the null revision if no revision is checked out.
4747 is used, or the null revision if no revision is checked out.
4744
4748
4745 With -v, print file permissions, symlink and executable bits.
4749 With -v, print file permissions, symlink and executable bits.
4746 With --debug, print file revision hashes.
4750 With --debug, print file revision hashes.
4747
4751
4748 If option --all is specified, the list of all files from all revisions
4752 If option --all is specified, the list of all files from all revisions
4749 is printed. This includes deleted and renamed files.
4753 is printed. This includes deleted and renamed files.
4750
4754
4751 Returns 0 on success.
4755 Returns 0 on success.
4752 """
4756 """
4753 opts = pycompat.byteskwargs(opts)
4757 opts = pycompat.byteskwargs(opts)
4754 fm = ui.formatter(b'manifest', opts)
4758 fm = ui.formatter(b'manifest', opts)
4755
4759
4756 if opts.get(b'all'):
4760 if opts.get(b'all'):
4757 if rev or node:
4761 if rev or node:
4758 raise error.Abort(_(b"can't specify a revision with --all"))
4762 raise error.Abort(_(b"can't specify a revision with --all"))
4759
4763
4760 res = set()
4764 res = set()
4761 for rev in repo:
4765 for rev in repo:
4762 ctx = repo[rev]
4766 ctx = repo[rev]
4763 res |= set(ctx.files())
4767 res |= set(ctx.files())
4764
4768
4765 ui.pager(b'manifest')
4769 ui.pager(b'manifest')
4766 for f in sorted(res):
4770 for f in sorted(res):
4767 fm.startitem()
4771 fm.startitem()
4768 fm.write(b"path", b'%s\n', f)
4772 fm.write(b"path", b'%s\n', f)
4769 fm.end()
4773 fm.end()
4770 return
4774 return
4771
4775
4772 if rev and node:
4776 if rev and node:
4773 raise error.Abort(_(b"please specify just one revision"))
4777 raise error.Abort(_(b"please specify just one revision"))
4774
4778
4775 if not node:
4779 if not node:
4776 node = rev
4780 node = rev
4777
4781
4778 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4782 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4779 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4783 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4780 if node:
4784 if node:
4781 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4785 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4782 ctx = scmutil.revsingle(repo, node)
4786 ctx = scmutil.revsingle(repo, node)
4783 mf = ctx.manifest()
4787 mf = ctx.manifest()
4784 ui.pager(b'manifest')
4788 ui.pager(b'manifest')
4785 for f in ctx:
4789 for f in ctx:
4786 fm.startitem()
4790 fm.startitem()
4787 fm.context(ctx=ctx)
4791 fm.context(ctx=ctx)
4788 fl = ctx[f].flags()
4792 fl = ctx[f].flags()
4789 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4793 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4790 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4794 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4791 fm.write(b'path', b'%s\n', f)
4795 fm.write(b'path', b'%s\n', f)
4792 fm.end()
4796 fm.end()
4793
4797
4794
4798
4795 @command(
4799 @command(
4796 b'merge',
4800 b'merge',
4797 [
4801 [
4798 (
4802 (
4799 b'f',
4803 b'f',
4800 b'force',
4804 b'force',
4801 None,
4805 None,
4802 _(b'force a merge including outstanding changes (DEPRECATED)'),
4806 _(b'force a merge including outstanding changes (DEPRECATED)'),
4803 ),
4807 ),
4804 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4808 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4805 (
4809 (
4806 b'P',
4810 b'P',
4807 b'preview',
4811 b'preview',
4808 None,
4812 None,
4809 _(b'review revisions to merge (no merge is performed)'),
4813 _(b'review revisions to merge (no merge is performed)'),
4810 ),
4814 ),
4811 (b'', b'abort', None, _(b'abort the ongoing merge')),
4815 (b'', b'abort', None, _(b'abort the ongoing merge')),
4812 ]
4816 ]
4813 + mergetoolopts,
4817 + mergetoolopts,
4814 _(b'[-P] [[-r] REV]'),
4818 _(b'[-P] [[-r] REV]'),
4815 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4819 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4816 helpbasic=True,
4820 helpbasic=True,
4817 )
4821 )
4818 def merge(ui, repo, node=None, **opts):
4822 def merge(ui, repo, node=None, **opts):
4819 """merge another revision into working directory
4823 """merge another revision into working directory
4820
4824
4821 The current working directory is updated with all changes made in
4825 The current working directory is updated with all changes made in
4822 the requested revision since the last common predecessor revision.
4826 the requested revision since the last common predecessor revision.
4823
4827
4824 Files that changed between either parent are marked as changed for
4828 Files that changed between either parent are marked as changed for
4825 the next commit and a commit must be performed before any further
4829 the next commit and a commit must be performed before any further
4826 updates to the repository are allowed. The next commit will have
4830 updates to the repository are allowed. The next commit will have
4827 two parents.
4831 two parents.
4828
4832
4829 ``--tool`` can be used to specify the merge tool used for file
4833 ``--tool`` can be used to specify the merge tool used for file
4830 merges. It overrides the HGMERGE environment variable and your
4834 merges. It overrides the HGMERGE environment variable and your
4831 configuration files. See :hg:`help merge-tools` for options.
4835 configuration files. See :hg:`help merge-tools` for options.
4832
4836
4833 If no revision is specified, the working directory's parent is a
4837 If no revision is specified, the working directory's parent is a
4834 head revision, and the current branch contains exactly one other
4838 head revision, and the current branch contains exactly one other
4835 head, the other head is merged with by default. Otherwise, an
4839 head, the other head is merged with by default. Otherwise, an
4836 explicit revision with which to merge must be provided.
4840 explicit revision with which to merge must be provided.
4837
4841
4838 See :hg:`help resolve` for information on handling file conflicts.
4842 See :hg:`help resolve` for information on handling file conflicts.
4839
4843
4840 To undo an uncommitted merge, use :hg:`merge --abort` which
4844 To undo an uncommitted merge, use :hg:`merge --abort` which
4841 will check out a clean copy of the original merge parent, losing
4845 will check out a clean copy of the original merge parent, losing
4842 all changes.
4846 all changes.
4843
4847
4844 Returns 0 on success, 1 if there are unresolved files.
4848 Returns 0 on success, 1 if there are unresolved files.
4845 """
4849 """
4846
4850
4847 opts = pycompat.byteskwargs(opts)
4851 opts = pycompat.byteskwargs(opts)
4848 abort = opts.get(b'abort')
4852 abort = opts.get(b'abort')
4849 if abort and repo.dirstate.p2() == nullid:
4853 if abort and repo.dirstate.p2() == nullid:
4850 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4854 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4851 if abort:
4855 if abort:
4852 state = cmdutil.getunfinishedstate(repo)
4856 state = cmdutil.getunfinishedstate(repo)
4853 if state and state._opname != b'merge':
4857 if state and state._opname != b'merge':
4854 raise error.Abort(
4858 raise error.Abort(
4855 _(b'cannot abort merge with %s in progress') % (state._opname),
4859 _(b'cannot abort merge with %s in progress') % (state._opname),
4856 hint=state.hint(),
4860 hint=state.hint(),
4857 )
4861 )
4858 if node:
4862 if node:
4859 raise error.Abort(_(b"cannot specify a node with --abort"))
4863 raise error.Abort(_(b"cannot specify a node with --abort"))
4860 if opts.get(b'rev'):
4864 if opts.get(b'rev'):
4861 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4865 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4862 if opts.get(b'preview'):
4866 if opts.get(b'preview'):
4863 raise error.Abort(_(b"cannot specify --preview with --abort"))
4867 raise error.Abort(_(b"cannot specify --preview with --abort"))
4864 if opts.get(b'rev') and node:
4868 if opts.get(b'rev') and node:
4865 raise error.Abort(_(b"please specify just one revision"))
4869 raise error.Abort(_(b"please specify just one revision"))
4866 if not node:
4870 if not node:
4867 node = opts.get(b'rev')
4871 node = opts.get(b'rev')
4868
4872
4869 if node:
4873 if node:
4870 node = scmutil.revsingle(repo, node).node()
4874 node = scmutil.revsingle(repo, node).node()
4871
4875
4872 if not node and not abort:
4876 if not node and not abort:
4873 node = repo[destutil.destmerge(repo)].node()
4877 node = repo[destutil.destmerge(repo)].node()
4874
4878
4875 if opts.get(b'preview'):
4879 if opts.get(b'preview'):
4876 # find nodes that are ancestors of p2 but not of p1
4880 # find nodes that are ancestors of p2 but not of p1
4877 p1 = repo.lookup(b'.')
4881 p1 = repo.lookup(b'.')
4878 p2 = node
4882 p2 = node
4879 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4883 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4880
4884
4881 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4885 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4882 for node in nodes:
4886 for node in nodes:
4883 displayer.show(repo[node])
4887 displayer.show(repo[node])
4884 displayer.close()
4888 displayer.close()
4885 return 0
4889 return 0
4886
4890
4887 # ui.forcemerge is an internal variable, do not document
4891 # ui.forcemerge is an internal variable, do not document
4888 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4892 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4889 with ui.configoverride(overrides, b'merge'):
4893 with ui.configoverride(overrides, b'merge'):
4890 force = opts.get(b'force')
4894 force = opts.get(b'force')
4891 labels = [b'working copy', b'merge rev']
4895 labels = [b'working copy', b'merge rev']
4892 return hg.merge(
4896 return hg.merge(
4893 repo,
4897 repo,
4894 node,
4898 node,
4895 force=force,
4899 force=force,
4896 mergeforce=force,
4900 mergeforce=force,
4897 labels=labels,
4901 labels=labels,
4898 abort=abort,
4902 abort=abort,
4899 )
4903 )
4900
4904
4901
4905
4902 statemod.addunfinished(
4906 statemod.addunfinished(
4903 b'merge',
4907 b'merge',
4904 fname=None,
4908 fname=None,
4905 clearable=True,
4909 clearable=True,
4906 allowcommit=True,
4910 allowcommit=True,
4907 cmdmsg=_(b'outstanding uncommitted merge'),
4911 cmdmsg=_(b'outstanding uncommitted merge'),
4908 abortfunc=hg.abortmerge,
4912 abortfunc=hg.abortmerge,
4909 statushint=_(
4913 statushint=_(
4910 b'To continue: hg commit\nTo abort: hg merge --abort'
4914 b'To continue: hg commit\nTo abort: hg merge --abort'
4911 ),
4915 ),
4912 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4916 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4913 )
4917 )
4914
4918
4915
4919
4916 @command(
4920 @command(
4917 b'outgoing|out',
4921 b'outgoing|out',
4918 [
4922 [
4919 (
4923 (
4920 b'f',
4924 b'f',
4921 b'force',
4925 b'force',
4922 None,
4926 None,
4923 _(b'run even when the destination is unrelated'),
4927 _(b'run even when the destination is unrelated'),
4924 ),
4928 ),
4925 (
4929 (
4926 b'r',
4930 b'r',
4927 b'rev',
4931 b'rev',
4928 [],
4932 [],
4929 _(b'a changeset intended to be included in the destination'),
4933 _(b'a changeset intended to be included in the destination'),
4930 _(b'REV'),
4934 _(b'REV'),
4931 ),
4935 ),
4932 (b'n', b'newest-first', None, _(b'show newest record first')),
4936 (b'n', b'newest-first', None, _(b'show newest record first')),
4933 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4937 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4934 (
4938 (
4935 b'b',
4939 b'b',
4936 b'branch',
4940 b'branch',
4937 [],
4941 [],
4938 _(b'a specific branch you would like to push'),
4942 _(b'a specific branch you would like to push'),
4939 _(b'BRANCH'),
4943 _(b'BRANCH'),
4940 ),
4944 ),
4941 ]
4945 ]
4942 + logopts
4946 + logopts
4943 + remoteopts
4947 + remoteopts
4944 + subrepoopts,
4948 + subrepoopts,
4945 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4949 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4946 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4950 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4947 )
4951 )
4948 def outgoing(ui, repo, dest=None, **opts):
4952 def outgoing(ui, repo, dest=None, **opts):
4949 """show changesets not found in the destination
4953 """show changesets not found in the destination
4950
4954
4951 Show changesets not found in the specified destination repository
4955 Show changesets not found in the specified destination repository
4952 or the default push location. These are the changesets that would
4956 or the default push location. These are the changesets that would
4953 be pushed if a push was requested.
4957 be pushed if a push was requested.
4954
4958
4955 See pull for details of valid destination formats.
4959 See pull for details of valid destination formats.
4956
4960
4957 .. container:: verbose
4961 .. container:: verbose
4958
4962
4959 With -B/--bookmarks, the result of bookmark comparison between
4963 With -B/--bookmarks, the result of bookmark comparison between
4960 local and remote repositories is displayed. With -v/--verbose,
4964 local and remote repositories is displayed. With -v/--verbose,
4961 status is also displayed for each bookmark like below::
4965 status is also displayed for each bookmark like below::
4962
4966
4963 BM1 01234567890a added
4967 BM1 01234567890a added
4964 BM2 deleted
4968 BM2 deleted
4965 BM3 234567890abc advanced
4969 BM3 234567890abc advanced
4966 BM4 34567890abcd diverged
4970 BM4 34567890abcd diverged
4967 BM5 4567890abcde changed
4971 BM5 4567890abcde changed
4968
4972
4969 The action taken when pushing depends on the
4973 The action taken when pushing depends on the
4970 status of each bookmark:
4974 status of each bookmark:
4971
4975
4972 :``added``: push with ``-B`` will create it
4976 :``added``: push with ``-B`` will create it
4973 :``deleted``: push with ``-B`` will delete it
4977 :``deleted``: push with ``-B`` will delete it
4974 :``advanced``: push will update it
4978 :``advanced``: push will update it
4975 :``diverged``: push with ``-B`` will update it
4979 :``diverged``: push with ``-B`` will update it
4976 :``changed``: push with ``-B`` will update it
4980 :``changed``: push with ``-B`` will update it
4977
4981
4978 From the point of view of pushing behavior, bookmarks
4982 From the point of view of pushing behavior, bookmarks
4979 existing only in the remote repository are treated as
4983 existing only in the remote repository are treated as
4980 ``deleted``, even if it is in fact added remotely.
4984 ``deleted``, even if it is in fact added remotely.
4981
4985
4982 Returns 0 if there are outgoing changes, 1 otherwise.
4986 Returns 0 if there are outgoing changes, 1 otherwise.
4983 """
4987 """
4984 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4988 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4985 # style URLs, so don't overwrite dest.
4989 # style URLs, so don't overwrite dest.
4986 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4990 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4987 if not path:
4991 if not path:
4988 raise error.Abort(
4992 raise error.Abort(
4989 _(b'default repository not configured!'),
4993 _(b'default repository not configured!'),
4990 hint=_(b"see 'hg help config.paths'"),
4994 hint=_(b"see 'hg help config.paths'"),
4991 )
4995 )
4992
4996
4993 opts = pycompat.byteskwargs(opts)
4997 opts = pycompat.byteskwargs(opts)
4994 if opts.get(b'graph'):
4998 if opts.get(b'graph'):
4995 logcmdutil.checkunsupportedgraphflags([], opts)
4999 logcmdutil.checkunsupportedgraphflags([], opts)
4996 o, other = hg._outgoing(ui, repo, dest, opts)
5000 o, other = hg._outgoing(ui, repo, dest, opts)
4997 if not o:
5001 if not o:
4998 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5002 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4999 return
5003 return
5000
5004
5001 revdag = logcmdutil.graphrevs(repo, o, opts)
5005 revdag = logcmdutil.graphrevs(repo, o, opts)
5002 ui.pager(b'outgoing')
5006 ui.pager(b'outgoing')
5003 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5007 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5004 logcmdutil.displaygraph(
5008 logcmdutil.displaygraph(
5005 ui, repo, revdag, displayer, graphmod.asciiedges
5009 ui, repo, revdag, displayer, graphmod.asciiedges
5006 )
5010 )
5007 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5011 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5008 return 0
5012 return 0
5009
5013
5010 if opts.get(b'bookmarks'):
5014 if opts.get(b'bookmarks'):
5011 dest = path.pushloc or path.loc
5015 dest = path.pushloc or path.loc
5012 other = hg.peer(repo, opts, dest)
5016 other = hg.peer(repo, opts, dest)
5013 if b'bookmarks' not in other.listkeys(b'namespaces'):
5017 if b'bookmarks' not in other.listkeys(b'namespaces'):
5014 ui.warn(_(b"remote doesn't support bookmarks\n"))
5018 ui.warn(_(b"remote doesn't support bookmarks\n"))
5015 return 0
5019 return 0
5016 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5020 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5017 ui.pager(b'outgoing')
5021 ui.pager(b'outgoing')
5018 return bookmarks.outgoing(ui, repo, other)
5022 return bookmarks.outgoing(ui, repo, other)
5019
5023
5020 repo._subtoppath = path.pushloc or path.loc
5024 repo._subtoppath = path.pushloc or path.loc
5021 try:
5025 try:
5022 return hg.outgoing(ui, repo, dest, opts)
5026 return hg.outgoing(ui, repo, dest, opts)
5023 finally:
5027 finally:
5024 del repo._subtoppath
5028 del repo._subtoppath
5025
5029
5026
5030
5027 @command(
5031 @command(
5028 b'parents',
5032 b'parents',
5029 [
5033 [
5030 (
5034 (
5031 b'r',
5035 b'r',
5032 b'rev',
5036 b'rev',
5033 b'',
5037 b'',
5034 _(b'show parents of the specified revision'),
5038 _(b'show parents of the specified revision'),
5035 _(b'REV'),
5039 _(b'REV'),
5036 ),
5040 ),
5037 ]
5041 ]
5038 + templateopts,
5042 + templateopts,
5039 _(b'[-r REV] [FILE]'),
5043 _(b'[-r REV] [FILE]'),
5040 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5044 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5041 inferrepo=True,
5045 inferrepo=True,
5042 )
5046 )
5043 def parents(ui, repo, file_=None, **opts):
5047 def parents(ui, repo, file_=None, **opts):
5044 """show the parents of the working directory or revision (DEPRECATED)
5048 """show the parents of the working directory or revision (DEPRECATED)
5045
5049
5046 Print the working directory's parent revisions. If a revision is
5050 Print the working directory's parent revisions. If a revision is
5047 given via -r/--rev, the parent of that revision will be printed.
5051 given via -r/--rev, the parent of that revision will be printed.
5048 If a file argument is given, the revision in which the file was
5052 If a file argument is given, the revision in which the file was
5049 last changed (before the working directory revision or the
5053 last changed (before the working directory revision or the
5050 argument to --rev if given) is printed.
5054 argument to --rev if given) is printed.
5051
5055
5052 This command is equivalent to::
5056 This command is equivalent to::
5053
5057
5054 hg log -r "p1()+p2()" or
5058 hg log -r "p1()+p2()" or
5055 hg log -r "p1(REV)+p2(REV)" or
5059 hg log -r "p1(REV)+p2(REV)" or
5056 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5060 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5057 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5061 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5058
5062
5059 See :hg:`summary` and :hg:`help revsets` for related information.
5063 See :hg:`summary` and :hg:`help revsets` for related information.
5060
5064
5061 Returns 0 on success.
5065 Returns 0 on success.
5062 """
5066 """
5063
5067
5064 opts = pycompat.byteskwargs(opts)
5068 opts = pycompat.byteskwargs(opts)
5065 rev = opts.get(b'rev')
5069 rev = opts.get(b'rev')
5066 if rev:
5070 if rev:
5067 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5071 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5068 ctx = scmutil.revsingle(repo, rev, None)
5072 ctx = scmutil.revsingle(repo, rev, None)
5069
5073
5070 if file_:
5074 if file_:
5071 m = scmutil.match(ctx, (file_,), opts)
5075 m = scmutil.match(ctx, (file_,), opts)
5072 if m.anypats() or len(m.files()) != 1:
5076 if m.anypats() or len(m.files()) != 1:
5073 raise error.Abort(_(b'can only specify an explicit filename'))
5077 raise error.Abort(_(b'can only specify an explicit filename'))
5074 file_ = m.files()[0]
5078 file_ = m.files()[0]
5075 filenodes = []
5079 filenodes = []
5076 for cp in ctx.parents():
5080 for cp in ctx.parents():
5077 if not cp:
5081 if not cp:
5078 continue
5082 continue
5079 try:
5083 try:
5080 filenodes.append(cp.filenode(file_))
5084 filenodes.append(cp.filenode(file_))
5081 except error.LookupError:
5085 except error.LookupError:
5082 pass
5086 pass
5083 if not filenodes:
5087 if not filenodes:
5084 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5088 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5085 p = []
5089 p = []
5086 for fn in filenodes:
5090 for fn in filenodes:
5087 fctx = repo.filectx(file_, fileid=fn)
5091 fctx = repo.filectx(file_, fileid=fn)
5088 p.append(fctx.node())
5092 p.append(fctx.node())
5089 else:
5093 else:
5090 p = [cp.node() for cp in ctx.parents()]
5094 p = [cp.node() for cp in ctx.parents()]
5091
5095
5092 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5096 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5093 for n in p:
5097 for n in p:
5094 if n != nullid:
5098 if n != nullid:
5095 displayer.show(repo[n])
5099 displayer.show(repo[n])
5096 displayer.close()
5100 displayer.close()
5097
5101
5098
5102
5099 @command(
5103 @command(
5100 b'paths',
5104 b'paths',
5101 formatteropts,
5105 formatteropts,
5102 _(b'[NAME]'),
5106 _(b'[NAME]'),
5103 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5107 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5104 optionalrepo=True,
5108 optionalrepo=True,
5105 intents={INTENT_READONLY},
5109 intents={INTENT_READONLY},
5106 )
5110 )
5107 def paths(ui, repo, search=None, **opts):
5111 def paths(ui, repo, search=None, **opts):
5108 """show aliases for remote repositories
5112 """show aliases for remote repositories
5109
5113
5110 Show definition of symbolic path name NAME. If no name is given,
5114 Show definition of symbolic path name NAME. If no name is given,
5111 show definition of all available names.
5115 show definition of all available names.
5112
5116
5113 Option -q/--quiet suppresses all output when searching for NAME
5117 Option -q/--quiet suppresses all output when searching for NAME
5114 and shows only the path names when listing all definitions.
5118 and shows only the path names when listing all definitions.
5115
5119
5116 Path names are defined in the [paths] section of your
5120 Path names are defined in the [paths] section of your
5117 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5121 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5118 repository, ``.hg/hgrc`` is used, too.
5122 repository, ``.hg/hgrc`` is used, too.
5119
5123
5120 The path names ``default`` and ``default-push`` have a special
5124 The path names ``default`` and ``default-push`` have a special
5121 meaning. When performing a push or pull operation, they are used
5125 meaning. When performing a push or pull operation, they are used
5122 as fallbacks if no location is specified on the command-line.
5126 as fallbacks if no location is specified on the command-line.
5123 When ``default-push`` is set, it will be used for push and
5127 When ``default-push`` is set, it will be used for push and
5124 ``default`` will be used for pull; otherwise ``default`` is used
5128 ``default`` will be used for pull; otherwise ``default`` is used
5125 as the fallback for both. When cloning a repository, the clone
5129 as the fallback for both. When cloning a repository, the clone
5126 source is written as ``default`` in ``.hg/hgrc``.
5130 source is written as ``default`` in ``.hg/hgrc``.
5127
5131
5128 .. note::
5132 .. note::
5129
5133
5130 ``default`` and ``default-push`` apply to all inbound (e.g.
5134 ``default`` and ``default-push`` apply to all inbound (e.g.
5131 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5135 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5132 and :hg:`bundle`) operations.
5136 and :hg:`bundle`) operations.
5133
5137
5134 See :hg:`help urls` for more information.
5138 See :hg:`help urls` for more information.
5135
5139
5136 .. container:: verbose
5140 .. container:: verbose
5137
5141
5138 Template:
5142 Template:
5139
5143
5140 The following keywords are supported. See also :hg:`help templates`.
5144 The following keywords are supported. See also :hg:`help templates`.
5141
5145
5142 :name: String. Symbolic name of the path alias.
5146 :name: String. Symbolic name of the path alias.
5143 :pushurl: String. URL for push operations.
5147 :pushurl: String. URL for push operations.
5144 :url: String. URL or directory path for the other operations.
5148 :url: String. URL or directory path for the other operations.
5145
5149
5146 Returns 0 on success.
5150 Returns 0 on success.
5147 """
5151 """
5148
5152
5149 opts = pycompat.byteskwargs(opts)
5153 opts = pycompat.byteskwargs(opts)
5150 ui.pager(b'paths')
5154 ui.pager(b'paths')
5151 if search:
5155 if search:
5152 pathitems = [
5156 pathitems = [
5153 (name, path)
5157 (name, path)
5154 for name, path in pycompat.iteritems(ui.paths)
5158 for name, path in pycompat.iteritems(ui.paths)
5155 if name == search
5159 if name == search
5156 ]
5160 ]
5157 else:
5161 else:
5158 pathitems = sorted(pycompat.iteritems(ui.paths))
5162 pathitems = sorted(pycompat.iteritems(ui.paths))
5159
5163
5160 fm = ui.formatter(b'paths', opts)
5164 fm = ui.formatter(b'paths', opts)
5161 if fm.isplain():
5165 if fm.isplain():
5162 hidepassword = util.hidepassword
5166 hidepassword = util.hidepassword
5163 else:
5167 else:
5164 hidepassword = bytes
5168 hidepassword = bytes
5165 if ui.quiet:
5169 if ui.quiet:
5166 namefmt = b'%s\n'
5170 namefmt = b'%s\n'
5167 else:
5171 else:
5168 namefmt = b'%s = '
5172 namefmt = b'%s = '
5169 showsubopts = not search and not ui.quiet
5173 showsubopts = not search and not ui.quiet
5170
5174
5171 for name, path in pathitems:
5175 for name, path in pathitems:
5172 fm.startitem()
5176 fm.startitem()
5173 fm.condwrite(not search, b'name', namefmt, name)
5177 fm.condwrite(not search, b'name', namefmt, name)
5174 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5178 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5175 for subopt, value in sorted(path.suboptions.items()):
5179 for subopt, value in sorted(path.suboptions.items()):
5176 assert subopt not in (b'name', b'url')
5180 assert subopt not in (b'name', b'url')
5177 if showsubopts:
5181 if showsubopts:
5178 fm.plain(b'%s:%s = ' % (name, subopt))
5182 fm.plain(b'%s:%s = ' % (name, subopt))
5179 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5183 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5180
5184
5181 fm.end()
5185 fm.end()
5182
5186
5183 if search and not pathitems:
5187 if search and not pathitems:
5184 if not ui.quiet:
5188 if not ui.quiet:
5185 ui.warn(_(b"not found!\n"))
5189 ui.warn(_(b"not found!\n"))
5186 return 1
5190 return 1
5187 else:
5191 else:
5188 return 0
5192 return 0
5189
5193
5190
5194
5191 @command(
5195 @command(
5192 b'phase',
5196 b'phase',
5193 [
5197 [
5194 (b'p', b'public', False, _(b'set changeset phase to public')),
5198 (b'p', b'public', False, _(b'set changeset phase to public')),
5195 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5199 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5196 (b's', b'secret', False, _(b'set changeset phase to secret')),
5200 (b's', b'secret', False, _(b'set changeset phase to secret')),
5197 (b'f', b'force', False, _(b'allow to move boundary backward')),
5201 (b'f', b'force', False, _(b'allow to move boundary backward')),
5198 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5202 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5199 ],
5203 ],
5200 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5204 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5201 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5205 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5202 )
5206 )
5203 def phase(ui, repo, *revs, **opts):
5207 def phase(ui, repo, *revs, **opts):
5204 """set or show the current phase name
5208 """set or show the current phase name
5205
5209
5206 With no argument, show the phase name of the current revision(s).
5210 With no argument, show the phase name of the current revision(s).
5207
5211
5208 With one of -p/--public, -d/--draft or -s/--secret, change the
5212 With one of -p/--public, -d/--draft or -s/--secret, change the
5209 phase value of the specified revisions.
5213 phase value of the specified revisions.
5210
5214
5211 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5215 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5212 lower phase to a higher phase. Phases are ordered as follows::
5216 lower phase to a higher phase. Phases are ordered as follows::
5213
5217
5214 public < draft < secret
5218 public < draft < secret
5215
5219
5216 Returns 0 on success, 1 if some phases could not be changed.
5220 Returns 0 on success, 1 if some phases could not be changed.
5217
5221
5218 (For more information about the phases concept, see :hg:`help phases`.)
5222 (For more information about the phases concept, see :hg:`help phases`.)
5219 """
5223 """
5220 opts = pycompat.byteskwargs(opts)
5224 opts = pycompat.byteskwargs(opts)
5221 # search for a unique phase argument
5225 # search for a unique phase argument
5222 targetphase = None
5226 targetphase = None
5223 for idx, name in enumerate(phases.cmdphasenames):
5227 for idx, name in enumerate(phases.cmdphasenames):
5224 if opts[name]:
5228 if opts[name]:
5225 if targetphase is not None:
5229 if targetphase is not None:
5226 raise error.Abort(_(b'only one phase can be specified'))
5230 raise error.Abort(_(b'only one phase can be specified'))
5227 targetphase = idx
5231 targetphase = idx
5228
5232
5229 # look for specified revision
5233 # look for specified revision
5230 revs = list(revs)
5234 revs = list(revs)
5231 revs.extend(opts[b'rev'])
5235 revs.extend(opts[b'rev'])
5232 if not revs:
5236 if not revs:
5233 # display both parents as the second parent phase can influence
5237 # display both parents as the second parent phase can influence
5234 # the phase of a merge commit
5238 # the phase of a merge commit
5235 revs = [c.rev() for c in repo[None].parents()]
5239 revs = [c.rev() for c in repo[None].parents()]
5236
5240
5237 revs = scmutil.revrange(repo, revs)
5241 revs = scmutil.revrange(repo, revs)
5238
5242
5239 ret = 0
5243 ret = 0
5240 if targetphase is None:
5244 if targetphase is None:
5241 # display
5245 # display
5242 for r in revs:
5246 for r in revs:
5243 ctx = repo[r]
5247 ctx = repo[r]
5244 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5248 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5245 else:
5249 else:
5246 with repo.lock(), repo.transaction(b"phase") as tr:
5250 with repo.lock(), repo.transaction(b"phase") as tr:
5247 # set phase
5251 # set phase
5248 if not revs:
5252 if not revs:
5249 raise error.Abort(_(b'empty revision set'))
5253 raise error.Abort(_(b'empty revision set'))
5250 nodes = [repo[r].node() for r in revs]
5254 nodes = [repo[r].node() for r in revs]
5251 # moving revision from public to draft may hide them
5255 # moving revision from public to draft may hide them
5252 # We have to check result on an unfiltered repository
5256 # We have to check result on an unfiltered repository
5253 unfi = repo.unfiltered()
5257 unfi = repo.unfiltered()
5254 getphase = unfi._phasecache.phase
5258 getphase = unfi._phasecache.phase
5255 olddata = [getphase(unfi, r) for r in unfi]
5259 olddata = [getphase(unfi, r) for r in unfi]
5256 phases.advanceboundary(repo, tr, targetphase, nodes)
5260 phases.advanceboundary(repo, tr, targetphase, nodes)
5257 if opts[b'force']:
5261 if opts[b'force']:
5258 phases.retractboundary(repo, tr, targetphase, nodes)
5262 phases.retractboundary(repo, tr, targetphase, nodes)
5259 getphase = unfi._phasecache.phase
5263 getphase = unfi._phasecache.phase
5260 newdata = [getphase(unfi, r) for r in unfi]
5264 newdata = [getphase(unfi, r) for r in unfi]
5261 changes = sum(newdata[r] != olddata[r] for r in unfi)
5265 changes = sum(newdata[r] != olddata[r] for r in unfi)
5262 cl = unfi.changelog
5266 cl = unfi.changelog
5263 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5267 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5264 if rejected:
5268 if rejected:
5265 ui.warn(
5269 ui.warn(
5266 _(
5270 _(
5267 b'cannot move %i changesets to a higher '
5271 b'cannot move %i changesets to a higher '
5268 b'phase, use --force\n'
5272 b'phase, use --force\n'
5269 )
5273 )
5270 % len(rejected)
5274 % len(rejected)
5271 )
5275 )
5272 ret = 1
5276 ret = 1
5273 if changes:
5277 if changes:
5274 msg = _(b'phase changed for %i changesets\n') % changes
5278 msg = _(b'phase changed for %i changesets\n') % changes
5275 if ret:
5279 if ret:
5276 ui.status(msg)
5280 ui.status(msg)
5277 else:
5281 else:
5278 ui.note(msg)
5282 ui.note(msg)
5279 else:
5283 else:
5280 ui.warn(_(b'no phases changed\n'))
5284 ui.warn(_(b'no phases changed\n'))
5281 return ret
5285 return ret
5282
5286
5283
5287
5284 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5288 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5285 """Run after a changegroup has been added via pull/unbundle
5289 """Run after a changegroup has been added via pull/unbundle
5286
5290
5287 This takes arguments below:
5291 This takes arguments below:
5288
5292
5289 :modheads: change of heads by pull/unbundle
5293 :modheads: change of heads by pull/unbundle
5290 :optupdate: updating working directory is needed or not
5294 :optupdate: updating working directory is needed or not
5291 :checkout: update destination revision (or None to default destination)
5295 :checkout: update destination revision (or None to default destination)
5292 :brev: a name, which might be a bookmark to be activated after updating
5296 :brev: a name, which might be a bookmark to be activated after updating
5293 """
5297 """
5294 if modheads == 0:
5298 if modheads == 0:
5295 return
5299 return
5296 if optupdate:
5300 if optupdate:
5297 try:
5301 try:
5298 return hg.updatetotally(ui, repo, checkout, brev)
5302 return hg.updatetotally(ui, repo, checkout, brev)
5299 except error.UpdateAbort as inst:
5303 except error.UpdateAbort as inst:
5300 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5304 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5301 hint = inst.hint
5305 hint = inst.hint
5302 raise error.UpdateAbort(msg, hint=hint)
5306 raise error.UpdateAbort(msg, hint=hint)
5303 if modheads is not None and modheads > 1:
5307 if modheads is not None and modheads > 1:
5304 currentbranchheads = len(repo.branchheads())
5308 currentbranchheads = len(repo.branchheads())
5305 if currentbranchheads == modheads:
5309 if currentbranchheads == modheads:
5306 ui.status(
5310 ui.status(
5307 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5311 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5308 )
5312 )
5309 elif currentbranchheads > 1:
5313 elif currentbranchheads > 1:
5310 ui.status(
5314 ui.status(
5311 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5315 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5312 )
5316 )
5313 else:
5317 else:
5314 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5318 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5315 elif not ui.configbool(b'commands', b'update.requiredest'):
5319 elif not ui.configbool(b'commands', b'update.requiredest'):
5316 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5320 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5317
5321
5318
5322
5319 @command(
5323 @command(
5320 b'pull',
5324 b'pull',
5321 [
5325 [
5322 (
5326 (
5323 b'u',
5327 b'u',
5324 b'update',
5328 b'update',
5325 None,
5329 None,
5326 _(b'update to new branch head if new descendants were pulled'),
5330 _(b'update to new branch head if new descendants were pulled'),
5327 ),
5331 ),
5328 (
5332 (
5329 b'f',
5333 b'f',
5330 b'force',
5334 b'force',
5331 None,
5335 None,
5332 _(b'run even when remote repository is unrelated'),
5336 _(b'run even when remote repository is unrelated'),
5333 ),
5337 ),
5334 (
5338 (
5335 b'r',
5339 b'r',
5336 b'rev',
5340 b'rev',
5337 [],
5341 [],
5338 _(b'a remote changeset intended to be added'),
5342 _(b'a remote changeset intended to be added'),
5339 _(b'REV'),
5343 _(b'REV'),
5340 ),
5344 ),
5341 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5345 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5342 (
5346 (
5343 b'b',
5347 b'b',
5344 b'branch',
5348 b'branch',
5345 [],
5349 [],
5346 _(b'a specific branch you would like to pull'),
5350 _(b'a specific branch you would like to pull'),
5347 _(b'BRANCH'),
5351 _(b'BRANCH'),
5348 ),
5352 ),
5349 ]
5353 ]
5350 + remoteopts,
5354 + remoteopts,
5351 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5355 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5352 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5356 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5353 helpbasic=True,
5357 helpbasic=True,
5354 )
5358 )
5355 def pull(ui, repo, source=b"default", **opts):
5359 def pull(ui, repo, source=b"default", **opts):
5356 """pull changes from the specified source
5360 """pull changes from the specified source
5357
5361
5358 Pull changes from a remote repository to a local one.
5362 Pull changes from a remote repository to a local one.
5359
5363
5360 This finds all changes from the repository at the specified path
5364 This finds all changes from the repository at the specified path
5361 or URL and adds them to a local repository (the current one unless
5365 or URL and adds them to a local repository (the current one unless
5362 -R is specified). By default, this does not update the copy of the
5366 -R is specified). By default, this does not update the copy of the
5363 project in the working directory.
5367 project in the working directory.
5364
5368
5365 When cloning from servers that support it, Mercurial may fetch
5369 When cloning from servers that support it, Mercurial may fetch
5366 pre-generated data. When this is done, hooks operating on incoming
5370 pre-generated data. When this is done, hooks operating on incoming
5367 changesets and changegroups may fire more than once, once for each
5371 changesets and changegroups may fire more than once, once for each
5368 pre-generated bundle and as well as for any additional remaining
5372 pre-generated bundle and as well as for any additional remaining
5369 data. See :hg:`help -e clonebundles` for more.
5373 data. See :hg:`help -e clonebundles` for more.
5370
5374
5371 Use :hg:`incoming` if you want to see what would have been added
5375 Use :hg:`incoming` if you want to see what would have been added
5372 by a pull at the time you issued this command. If you then decide
5376 by a pull at the time you issued this command. If you then decide
5373 to add those changes to the repository, you should use :hg:`pull
5377 to add those changes to the repository, you should use :hg:`pull
5374 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5378 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5375
5379
5376 If SOURCE is omitted, the 'default' path will be used.
5380 If SOURCE is omitted, the 'default' path will be used.
5377 See :hg:`help urls` for more information.
5381 See :hg:`help urls` for more information.
5378
5382
5379 Specifying bookmark as ``.`` is equivalent to specifying the active
5383 Specifying bookmark as ``.`` is equivalent to specifying the active
5380 bookmark's name.
5384 bookmark's name.
5381
5385
5382 Returns 0 on success, 1 if an update had unresolved files.
5386 Returns 0 on success, 1 if an update had unresolved files.
5383 """
5387 """
5384
5388
5385 opts = pycompat.byteskwargs(opts)
5389 opts = pycompat.byteskwargs(opts)
5386 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5390 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5387 b'update'
5391 b'update'
5388 ):
5392 ):
5389 msg = _(b'update destination required by configuration')
5393 msg = _(b'update destination required by configuration')
5390 hint = _(b'use hg pull followed by hg update DEST')
5394 hint = _(b'use hg pull followed by hg update DEST')
5391 raise error.Abort(msg, hint=hint)
5395 raise error.Abort(msg, hint=hint)
5392
5396
5393 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5397 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5394 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5398 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5395 other = hg.peer(repo, opts, source)
5399 other = hg.peer(repo, opts, source)
5396 try:
5400 try:
5397 revs, checkout = hg.addbranchrevs(
5401 revs, checkout = hg.addbranchrevs(
5398 repo, other, branches, opts.get(b'rev')
5402 repo, other, branches, opts.get(b'rev')
5399 )
5403 )
5400
5404
5401 pullopargs = {}
5405 pullopargs = {}
5402
5406
5403 nodes = None
5407 nodes = None
5404 if opts.get(b'bookmark') or revs:
5408 if opts.get(b'bookmark') or revs:
5405 # The list of bookmark used here is the same used to actually update
5409 # The list of bookmark used here is the same used to actually update
5406 # the bookmark names, to avoid the race from issue 4689 and we do
5410 # the bookmark names, to avoid the race from issue 4689 and we do
5407 # all lookup and bookmark queries in one go so they see the same
5411 # all lookup and bookmark queries in one go so they see the same
5408 # version of the server state (issue 4700).
5412 # version of the server state (issue 4700).
5409 nodes = []
5413 nodes = []
5410 fnodes = []
5414 fnodes = []
5411 revs = revs or []
5415 revs = revs or []
5412 if revs and not other.capable(b'lookup'):
5416 if revs and not other.capable(b'lookup'):
5413 err = _(
5417 err = _(
5414 b"other repository doesn't support revision lookup, "
5418 b"other repository doesn't support revision lookup, "
5415 b"so a rev cannot be specified."
5419 b"so a rev cannot be specified."
5416 )
5420 )
5417 raise error.Abort(err)
5421 raise error.Abort(err)
5418 with other.commandexecutor() as e:
5422 with other.commandexecutor() as e:
5419 fremotebookmarks = e.callcommand(
5423 fremotebookmarks = e.callcommand(
5420 b'listkeys', {b'namespace': b'bookmarks'}
5424 b'listkeys', {b'namespace': b'bookmarks'}
5421 )
5425 )
5422 for r in revs:
5426 for r in revs:
5423 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5427 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5424 remotebookmarks = fremotebookmarks.result()
5428 remotebookmarks = fremotebookmarks.result()
5425 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5429 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5426 pullopargs[b'remotebookmarks'] = remotebookmarks
5430 pullopargs[b'remotebookmarks'] = remotebookmarks
5427 for b in opts.get(b'bookmark', []):
5431 for b in opts.get(b'bookmark', []):
5428 b = repo._bookmarks.expandname(b)
5432 b = repo._bookmarks.expandname(b)
5429 if b not in remotebookmarks:
5433 if b not in remotebookmarks:
5430 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5434 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5431 nodes.append(remotebookmarks[b])
5435 nodes.append(remotebookmarks[b])
5432 for i, rev in enumerate(revs):
5436 for i, rev in enumerate(revs):
5433 node = fnodes[i].result()
5437 node = fnodes[i].result()
5434 nodes.append(node)
5438 nodes.append(node)
5435 if rev == checkout:
5439 if rev == checkout:
5436 checkout = node
5440 checkout = node
5437
5441
5438 wlock = util.nullcontextmanager()
5442 wlock = util.nullcontextmanager()
5439 if opts.get(b'update'):
5443 if opts.get(b'update'):
5440 wlock = repo.wlock()
5444 wlock = repo.wlock()
5441 with wlock:
5445 with wlock:
5442 pullopargs.update(opts.get(b'opargs', {}))
5446 pullopargs.update(opts.get(b'opargs', {}))
5443 modheads = exchange.pull(
5447 modheads = exchange.pull(
5444 repo,
5448 repo,
5445 other,
5449 other,
5446 heads=nodes,
5450 heads=nodes,
5447 force=opts.get(b'force'),
5451 force=opts.get(b'force'),
5448 bookmarks=opts.get(b'bookmark', ()),
5452 bookmarks=opts.get(b'bookmark', ()),
5449 opargs=pullopargs,
5453 opargs=pullopargs,
5450 ).cgresult
5454 ).cgresult
5451
5455
5452 # brev is a name, which might be a bookmark to be activated at
5456 # brev is a name, which might be a bookmark to be activated at
5453 # the end of the update. In other words, it is an explicit
5457 # the end of the update. In other words, it is an explicit
5454 # destination of the update
5458 # destination of the update
5455 brev = None
5459 brev = None
5456
5460
5457 if checkout:
5461 if checkout:
5458 checkout = repo.unfiltered().changelog.rev(checkout)
5462 checkout = repo.unfiltered().changelog.rev(checkout)
5459
5463
5460 # order below depends on implementation of
5464 # order below depends on implementation of
5461 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5465 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5462 # because 'checkout' is determined without it.
5466 # because 'checkout' is determined without it.
5463 if opts.get(b'rev'):
5467 if opts.get(b'rev'):
5464 brev = opts[b'rev'][0]
5468 brev = opts[b'rev'][0]
5465 elif opts.get(b'branch'):
5469 elif opts.get(b'branch'):
5466 brev = opts[b'branch'][0]
5470 brev = opts[b'branch'][0]
5467 else:
5471 else:
5468 brev = branches[0]
5472 brev = branches[0]
5469 repo._subtoppath = source
5473 repo._subtoppath = source
5470 try:
5474 try:
5471 ret = postincoming(
5475 ret = postincoming(
5472 ui, repo, modheads, opts.get(b'update'), checkout, brev
5476 ui, repo, modheads, opts.get(b'update'), checkout, brev
5473 )
5477 )
5474 except error.FilteredRepoLookupError as exc:
5478 except error.FilteredRepoLookupError as exc:
5475 msg = _(b'cannot update to target: %s') % exc.args[0]
5479 msg = _(b'cannot update to target: %s') % exc.args[0]
5476 exc.args = (msg,) + exc.args[1:]
5480 exc.args = (msg,) + exc.args[1:]
5477 raise
5481 raise
5478 finally:
5482 finally:
5479 del repo._subtoppath
5483 del repo._subtoppath
5480
5484
5481 finally:
5485 finally:
5482 other.close()
5486 other.close()
5483 return ret
5487 return ret
5484
5488
5485
5489
5486 @command(
5490 @command(
5487 b'push',
5491 b'push',
5488 [
5492 [
5489 (b'f', b'force', None, _(b'force push')),
5493 (b'f', b'force', None, _(b'force push')),
5490 (
5494 (
5491 b'r',
5495 b'r',
5492 b'rev',
5496 b'rev',
5493 [],
5497 [],
5494 _(b'a changeset intended to be included in the destination'),
5498 _(b'a changeset intended to be included in the destination'),
5495 _(b'REV'),
5499 _(b'REV'),
5496 ),
5500 ),
5497 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5501 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5498 (
5502 (
5499 b'b',
5503 b'b',
5500 b'branch',
5504 b'branch',
5501 [],
5505 [],
5502 _(b'a specific branch you would like to push'),
5506 _(b'a specific branch you would like to push'),
5503 _(b'BRANCH'),
5507 _(b'BRANCH'),
5504 ),
5508 ),
5505 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5509 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5506 (
5510 (
5507 b'',
5511 b'',
5508 b'pushvars',
5512 b'pushvars',
5509 [],
5513 [],
5510 _(b'variables that can be sent to server (ADVANCED)'),
5514 _(b'variables that can be sent to server (ADVANCED)'),
5511 ),
5515 ),
5512 (
5516 (
5513 b'',
5517 b'',
5514 b'publish',
5518 b'publish',
5515 False,
5519 False,
5516 _(b'push the changeset as public (EXPERIMENTAL)'),
5520 _(b'push the changeset as public (EXPERIMENTAL)'),
5517 ),
5521 ),
5518 ]
5522 ]
5519 + remoteopts,
5523 + remoteopts,
5520 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5524 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5521 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5525 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5522 helpbasic=True,
5526 helpbasic=True,
5523 )
5527 )
5524 def push(ui, repo, dest=None, **opts):
5528 def push(ui, repo, dest=None, **opts):
5525 """push changes to the specified destination
5529 """push changes to the specified destination
5526
5530
5527 Push changesets from the local repository to the specified
5531 Push changesets from the local repository to the specified
5528 destination.
5532 destination.
5529
5533
5530 This operation is symmetrical to pull: it is identical to a pull
5534 This operation is symmetrical to pull: it is identical to a pull
5531 in the destination repository from the current one.
5535 in the destination repository from the current one.
5532
5536
5533 By default, push will not allow creation of new heads at the
5537 By default, push will not allow creation of new heads at the
5534 destination, since multiple heads would make it unclear which head
5538 destination, since multiple heads would make it unclear which head
5535 to use. In this situation, it is recommended to pull and merge
5539 to use. In this situation, it is recommended to pull and merge
5536 before pushing.
5540 before pushing.
5537
5541
5538 Use --new-branch if you want to allow push to create a new named
5542 Use --new-branch if you want to allow push to create a new named
5539 branch that is not present at the destination. This allows you to
5543 branch that is not present at the destination. This allows you to
5540 only create a new branch without forcing other changes.
5544 only create a new branch without forcing other changes.
5541
5545
5542 .. note::
5546 .. note::
5543
5547
5544 Extra care should be taken with the -f/--force option,
5548 Extra care should be taken with the -f/--force option,
5545 which will push all new heads on all branches, an action which will
5549 which will push all new heads on all branches, an action which will
5546 almost always cause confusion for collaborators.
5550 almost always cause confusion for collaborators.
5547
5551
5548 If -r/--rev is used, the specified revision and all its ancestors
5552 If -r/--rev is used, the specified revision and all its ancestors
5549 will be pushed to the remote repository.
5553 will be pushed to the remote repository.
5550
5554
5551 If -B/--bookmark is used, the specified bookmarked revision, its
5555 If -B/--bookmark is used, the specified bookmarked revision, its
5552 ancestors, and the bookmark will be pushed to the remote
5556 ancestors, and the bookmark will be pushed to the remote
5553 repository. Specifying ``.`` is equivalent to specifying the active
5557 repository. Specifying ``.`` is equivalent to specifying the active
5554 bookmark's name.
5558 bookmark's name.
5555
5559
5556 Please see :hg:`help urls` for important details about ``ssh://``
5560 Please see :hg:`help urls` for important details about ``ssh://``
5557 URLs. If DESTINATION is omitted, a default path will be used.
5561 URLs. If DESTINATION is omitted, a default path will be used.
5558
5562
5559 .. container:: verbose
5563 .. container:: verbose
5560
5564
5561 The --pushvars option sends strings to the server that become
5565 The --pushvars option sends strings to the server that become
5562 environment variables prepended with ``HG_USERVAR_``. For example,
5566 environment variables prepended with ``HG_USERVAR_``. For example,
5563 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5567 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5564 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5568 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5565
5569
5566 pushvars can provide for user-overridable hooks as well as set debug
5570 pushvars can provide for user-overridable hooks as well as set debug
5567 levels. One example is having a hook that blocks commits containing
5571 levels. One example is having a hook that blocks commits containing
5568 conflict markers, but enables the user to override the hook if the file
5572 conflict markers, but enables the user to override the hook if the file
5569 is using conflict markers for testing purposes or the file format has
5573 is using conflict markers for testing purposes or the file format has
5570 strings that look like conflict markers.
5574 strings that look like conflict markers.
5571
5575
5572 By default, servers will ignore `--pushvars`. To enable it add the
5576 By default, servers will ignore `--pushvars`. To enable it add the
5573 following to your configuration file::
5577 following to your configuration file::
5574
5578
5575 [push]
5579 [push]
5576 pushvars.server = true
5580 pushvars.server = true
5577
5581
5578 Returns 0 if push was successful, 1 if nothing to push.
5582 Returns 0 if push was successful, 1 if nothing to push.
5579 """
5583 """
5580
5584
5581 opts = pycompat.byteskwargs(opts)
5585 opts = pycompat.byteskwargs(opts)
5582 if opts.get(b'bookmark'):
5586 if opts.get(b'bookmark'):
5583 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5587 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5584 for b in opts[b'bookmark']:
5588 for b in opts[b'bookmark']:
5585 # translate -B options to -r so changesets get pushed
5589 # translate -B options to -r so changesets get pushed
5586 b = repo._bookmarks.expandname(b)
5590 b = repo._bookmarks.expandname(b)
5587 if b in repo._bookmarks:
5591 if b in repo._bookmarks:
5588 opts.setdefault(b'rev', []).append(b)
5592 opts.setdefault(b'rev', []).append(b)
5589 else:
5593 else:
5590 # if we try to push a deleted bookmark, translate it to null
5594 # if we try to push a deleted bookmark, translate it to null
5591 # this lets simultaneous -r, -b options continue working
5595 # this lets simultaneous -r, -b options continue working
5592 opts.setdefault(b'rev', []).append(b"null")
5596 opts.setdefault(b'rev', []).append(b"null")
5593
5597
5594 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5598 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5595 if not path:
5599 if not path:
5596 raise error.Abort(
5600 raise error.Abort(
5597 _(b'default repository not configured!'),
5601 _(b'default repository not configured!'),
5598 hint=_(b"see 'hg help config.paths'"),
5602 hint=_(b"see 'hg help config.paths'"),
5599 )
5603 )
5600 dest = path.pushloc or path.loc
5604 dest = path.pushloc or path.loc
5601 branches = (path.branch, opts.get(b'branch') or [])
5605 branches = (path.branch, opts.get(b'branch') or [])
5602 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5606 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5603 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5607 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5604 other = hg.peer(repo, opts, dest)
5608 other = hg.peer(repo, opts, dest)
5605
5609
5606 if revs:
5610 if revs:
5607 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5611 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5608 if not revs:
5612 if not revs:
5609 raise error.Abort(
5613 raise error.Abort(
5610 _(b"specified revisions evaluate to an empty set"),
5614 _(b"specified revisions evaluate to an empty set"),
5611 hint=_(b"use different revision arguments"),
5615 hint=_(b"use different revision arguments"),
5612 )
5616 )
5613 elif path.pushrev:
5617 elif path.pushrev:
5614 # It doesn't make any sense to specify ancestor revisions. So limit
5618 # It doesn't make any sense to specify ancestor revisions. So limit
5615 # to DAG heads to make discovery simpler.
5619 # to DAG heads to make discovery simpler.
5616 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5620 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5617 revs = scmutil.revrange(repo, [expr])
5621 revs = scmutil.revrange(repo, [expr])
5618 revs = [repo[rev].node() for rev in revs]
5622 revs = [repo[rev].node() for rev in revs]
5619 if not revs:
5623 if not revs:
5620 raise error.Abort(
5624 raise error.Abort(
5621 _(b'default push revset for path evaluates to an empty set')
5625 _(b'default push revset for path evaluates to an empty set')
5622 )
5626 )
5623 elif ui.configbool(b'commands', b'push.require-revs'):
5627 elif ui.configbool(b'commands', b'push.require-revs'):
5624 raise error.Abort(
5628 raise error.Abort(
5625 _(b'no revisions specified to push'),
5629 _(b'no revisions specified to push'),
5626 hint=_(b'did you mean "hg push -r ."?'),
5630 hint=_(b'did you mean "hg push -r ."?'),
5627 )
5631 )
5628
5632
5629 repo._subtoppath = dest
5633 repo._subtoppath = dest
5630 try:
5634 try:
5631 # push subrepos depth-first for coherent ordering
5635 # push subrepos depth-first for coherent ordering
5632 c = repo[b'.']
5636 c = repo[b'.']
5633 subs = c.substate # only repos that are committed
5637 subs = c.substate # only repos that are committed
5634 for s in sorted(subs):
5638 for s in sorted(subs):
5635 result = c.sub(s).push(opts)
5639 result = c.sub(s).push(opts)
5636 if result == 0:
5640 if result == 0:
5637 return not result
5641 return not result
5638 finally:
5642 finally:
5639 del repo._subtoppath
5643 del repo._subtoppath
5640
5644
5641 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5645 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5642 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5646 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5643
5647
5644 pushop = exchange.push(
5648 pushop = exchange.push(
5645 repo,
5649 repo,
5646 other,
5650 other,
5647 opts.get(b'force'),
5651 opts.get(b'force'),
5648 revs=revs,
5652 revs=revs,
5649 newbranch=opts.get(b'new_branch'),
5653 newbranch=opts.get(b'new_branch'),
5650 bookmarks=opts.get(b'bookmark', ()),
5654 bookmarks=opts.get(b'bookmark', ()),
5651 publish=opts.get(b'publish'),
5655 publish=opts.get(b'publish'),
5652 opargs=opargs,
5656 opargs=opargs,
5653 )
5657 )
5654
5658
5655 result = not pushop.cgresult
5659 result = not pushop.cgresult
5656
5660
5657 if pushop.bkresult is not None:
5661 if pushop.bkresult is not None:
5658 if pushop.bkresult == 2:
5662 if pushop.bkresult == 2:
5659 result = 2
5663 result = 2
5660 elif not result and pushop.bkresult:
5664 elif not result and pushop.bkresult:
5661 result = 2
5665 result = 2
5662
5666
5663 return result
5667 return result
5664
5668
5665
5669
5666 @command(
5670 @command(
5667 b'recover',
5671 b'recover',
5668 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5672 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5669 helpcategory=command.CATEGORY_MAINTENANCE,
5673 helpcategory=command.CATEGORY_MAINTENANCE,
5670 )
5674 )
5671 def recover(ui, repo, **opts):
5675 def recover(ui, repo, **opts):
5672 """roll back an interrupted transaction
5676 """roll back an interrupted transaction
5673
5677
5674 Recover from an interrupted commit or pull.
5678 Recover from an interrupted commit or pull.
5675
5679
5676 This command tries to fix the repository status after an
5680 This command tries to fix the repository status after an
5677 interrupted operation. It should only be necessary when Mercurial
5681 interrupted operation. It should only be necessary when Mercurial
5678 suggests it.
5682 suggests it.
5679
5683
5680 Returns 0 if successful, 1 if nothing to recover or verify fails.
5684 Returns 0 if successful, 1 if nothing to recover or verify fails.
5681 """
5685 """
5682 ret = repo.recover()
5686 ret = repo.recover()
5683 if ret:
5687 if ret:
5684 if opts[r'verify']:
5688 if opts[r'verify']:
5685 return hg.verify(repo)
5689 return hg.verify(repo)
5686 else:
5690 else:
5687 msg = _(
5691 msg = _(
5688 b"(verify step skipped, run `hg verify` to check your "
5692 b"(verify step skipped, run `hg verify` to check your "
5689 b"repository content)\n"
5693 b"repository content)\n"
5690 )
5694 )
5691 ui.warn(msg)
5695 ui.warn(msg)
5692 return 0
5696 return 0
5693 return 1
5697 return 1
5694
5698
5695
5699
5696 @command(
5700 @command(
5697 b'remove|rm',
5701 b'remove|rm',
5698 [
5702 [
5699 (b'A', b'after', None, _(b'record delete for missing files')),
5703 (b'A', b'after', None, _(b'record delete for missing files')),
5700 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5704 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5701 ]
5705 ]
5702 + subrepoopts
5706 + subrepoopts
5703 + walkopts
5707 + walkopts
5704 + dryrunopts,
5708 + dryrunopts,
5705 _(b'[OPTION]... FILE...'),
5709 _(b'[OPTION]... FILE...'),
5706 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5710 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5707 helpbasic=True,
5711 helpbasic=True,
5708 inferrepo=True,
5712 inferrepo=True,
5709 )
5713 )
5710 def remove(ui, repo, *pats, **opts):
5714 def remove(ui, repo, *pats, **opts):
5711 """remove the specified files on the next commit
5715 """remove the specified files on the next commit
5712
5716
5713 Schedule the indicated files for removal from the current branch.
5717 Schedule the indicated files for removal from the current branch.
5714
5718
5715 This command schedules the files to be removed at the next commit.
5719 This command schedules the files to be removed at the next commit.
5716 To undo a remove before that, see :hg:`revert`. To undo added
5720 To undo a remove before that, see :hg:`revert`. To undo added
5717 files, see :hg:`forget`.
5721 files, see :hg:`forget`.
5718
5722
5719 .. container:: verbose
5723 .. container:: verbose
5720
5724
5721 -A/--after can be used to remove only files that have already
5725 -A/--after can be used to remove only files that have already
5722 been deleted, -f/--force can be used to force deletion, and -Af
5726 been deleted, -f/--force can be used to force deletion, and -Af
5723 can be used to remove files from the next revision without
5727 can be used to remove files from the next revision without
5724 deleting them from the working directory.
5728 deleting them from the working directory.
5725
5729
5726 The following table details the behavior of remove for different
5730 The following table details the behavior of remove for different
5727 file states (columns) and option combinations (rows). The file
5731 file states (columns) and option combinations (rows). The file
5728 states are Added [A], Clean [C], Modified [M] and Missing [!]
5732 states are Added [A], Clean [C], Modified [M] and Missing [!]
5729 (as reported by :hg:`status`). The actions are Warn, Remove
5733 (as reported by :hg:`status`). The actions are Warn, Remove
5730 (from branch) and Delete (from disk):
5734 (from branch) and Delete (from disk):
5731
5735
5732 ========= == == == ==
5736 ========= == == == ==
5733 opt/state A C M !
5737 opt/state A C M !
5734 ========= == == == ==
5738 ========= == == == ==
5735 none W RD W R
5739 none W RD W R
5736 -f R RD RD R
5740 -f R RD RD R
5737 -A W W W R
5741 -A W W W R
5738 -Af R R R R
5742 -Af R R R R
5739 ========= == == == ==
5743 ========= == == == ==
5740
5744
5741 .. note::
5745 .. note::
5742
5746
5743 :hg:`remove` never deletes files in Added [A] state from the
5747 :hg:`remove` never deletes files in Added [A] state from the
5744 working directory, not even if ``--force`` is specified.
5748 working directory, not even if ``--force`` is specified.
5745
5749
5746 Returns 0 on success, 1 if any warnings encountered.
5750 Returns 0 on success, 1 if any warnings encountered.
5747 """
5751 """
5748
5752
5749 opts = pycompat.byteskwargs(opts)
5753 opts = pycompat.byteskwargs(opts)
5750 after, force = opts.get(b'after'), opts.get(b'force')
5754 after, force = opts.get(b'after'), opts.get(b'force')
5751 dryrun = opts.get(b'dry_run')
5755 dryrun = opts.get(b'dry_run')
5752 if not pats and not after:
5756 if not pats and not after:
5753 raise error.Abort(_(b'no files specified'))
5757 raise error.Abort(_(b'no files specified'))
5754
5758
5755 m = scmutil.match(repo[None], pats, opts)
5759 m = scmutil.match(repo[None], pats, opts)
5756 subrepos = opts.get(b'subrepos')
5760 subrepos = opts.get(b'subrepos')
5757 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5761 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5758 return cmdutil.remove(
5762 return cmdutil.remove(
5759 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5763 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5760 )
5764 )
5761
5765
5762
5766
5763 @command(
5767 @command(
5764 b'rename|move|mv',
5768 b'rename|move|mv',
5765 [
5769 [
5766 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5770 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5767 (
5771 (
5768 b'f',
5772 b'f',
5769 b'force',
5773 b'force',
5770 None,
5774 None,
5771 _(b'forcibly move over an existing managed file'),
5775 _(b'forcibly move over an existing managed file'),
5772 ),
5776 ),
5773 ]
5777 ]
5774 + walkopts
5778 + walkopts
5775 + dryrunopts,
5779 + dryrunopts,
5776 _(b'[OPTION]... SOURCE... DEST'),
5780 _(b'[OPTION]... SOURCE... DEST'),
5777 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5781 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5778 )
5782 )
5779 def rename(ui, repo, *pats, **opts):
5783 def rename(ui, repo, *pats, **opts):
5780 """rename files; equivalent of copy + remove
5784 """rename files; equivalent of copy + remove
5781
5785
5782 Mark dest as copies of sources; mark sources for deletion. If dest
5786 Mark dest as copies of sources; mark sources for deletion. If dest
5783 is a directory, copies are put in that directory. If dest is a
5787 is a directory, copies are put in that directory. If dest is a
5784 file, there can only be one source.
5788 file, there can only be one source.
5785
5789
5786 By default, this command copies the contents of files as they
5790 By default, this command copies the contents of files as they
5787 exist in the working directory. If invoked with -A/--after, the
5791 exist in the working directory. If invoked with -A/--after, the
5788 operation is recorded, but no copying is performed.
5792 operation is recorded, but no copying is performed.
5789
5793
5790 This command takes effect at the next commit. To undo a rename
5794 This command takes effect at the next commit. To undo a rename
5791 before that, see :hg:`revert`.
5795 before that, see :hg:`revert`.
5792
5796
5793 Returns 0 on success, 1 if errors are encountered.
5797 Returns 0 on success, 1 if errors are encountered.
5794 """
5798 """
5795 opts = pycompat.byteskwargs(opts)
5799 opts = pycompat.byteskwargs(opts)
5796 with repo.wlock(False):
5800 with repo.wlock(False):
5797 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5801 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5798
5802
5799
5803
5800 @command(
5804 @command(
5801 b'resolve',
5805 b'resolve',
5802 [
5806 [
5803 (b'a', b'all', None, _(b'select all unresolved files')),
5807 (b'a', b'all', None, _(b'select all unresolved files')),
5804 (b'l', b'list', None, _(b'list state of files needing merge')),
5808 (b'l', b'list', None, _(b'list state of files needing merge')),
5805 (b'm', b'mark', None, _(b'mark files as resolved')),
5809 (b'm', b'mark', None, _(b'mark files as resolved')),
5806 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5810 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5807 (b'n', b'no-status', None, _(b'hide status prefix')),
5811 (b'n', b'no-status', None, _(b'hide status prefix')),
5808 (b'', b're-merge', None, _(b're-merge files')),
5812 (b'', b're-merge', None, _(b're-merge files')),
5809 ]
5813 ]
5810 + mergetoolopts
5814 + mergetoolopts
5811 + walkopts
5815 + walkopts
5812 + formatteropts,
5816 + formatteropts,
5813 _(b'[OPTION]... [FILE]...'),
5817 _(b'[OPTION]... [FILE]...'),
5814 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5818 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5815 inferrepo=True,
5819 inferrepo=True,
5816 )
5820 )
5817 def resolve(ui, repo, *pats, **opts):
5821 def resolve(ui, repo, *pats, **opts):
5818 """redo merges or set/view the merge status of files
5822 """redo merges or set/view the merge status of files
5819
5823
5820 Merges with unresolved conflicts are often the result of
5824 Merges with unresolved conflicts are often the result of
5821 non-interactive merging using the ``internal:merge`` configuration
5825 non-interactive merging using the ``internal:merge`` configuration
5822 setting, or a command-line merge tool like ``diff3``. The resolve
5826 setting, or a command-line merge tool like ``diff3``. The resolve
5823 command is used to manage the files involved in a merge, after
5827 command is used to manage the files involved in a merge, after
5824 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5828 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5825 working directory must have two parents). See :hg:`help
5829 working directory must have two parents). See :hg:`help
5826 merge-tools` for information on configuring merge tools.
5830 merge-tools` for information on configuring merge tools.
5827
5831
5828 The resolve command can be used in the following ways:
5832 The resolve command can be used in the following ways:
5829
5833
5830 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5834 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5831 the specified files, discarding any previous merge attempts. Re-merging
5835 the specified files, discarding any previous merge attempts. Re-merging
5832 is not performed for files already marked as resolved. Use ``--all/-a``
5836 is not performed for files already marked as resolved. Use ``--all/-a``
5833 to select all unresolved files. ``--tool`` can be used to specify
5837 to select all unresolved files. ``--tool`` can be used to specify
5834 the merge tool used for the given files. It overrides the HGMERGE
5838 the merge tool used for the given files. It overrides the HGMERGE
5835 environment variable and your configuration files. Previous file
5839 environment variable and your configuration files. Previous file
5836 contents are saved with a ``.orig`` suffix.
5840 contents are saved with a ``.orig`` suffix.
5837
5841
5838 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5842 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5839 (e.g. after having manually fixed-up the files). The default is
5843 (e.g. after having manually fixed-up the files). The default is
5840 to mark all unresolved files.
5844 to mark all unresolved files.
5841
5845
5842 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5846 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5843 default is to mark all resolved files.
5847 default is to mark all resolved files.
5844
5848
5845 - :hg:`resolve -l`: list files which had or still have conflicts.
5849 - :hg:`resolve -l`: list files which had or still have conflicts.
5846 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5850 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5847 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5851 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5848 the list. See :hg:`help filesets` for details.
5852 the list. See :hg:`help filesets` for details.
5849
5853
5850 .. note::
5854 .. note::
5851
5855
5852 Mercurial will not let you commit files with unresolved merge
5856 Mercurial will not let you commit files with unresolved merge
5853 conflicts. You must use :hg:`resolve -m ...` before you can
5857 conflicts. You must use :hg:`resolve -m ...` before you can
5854 commit after a conflicting merge.
5858 commit after a conflicting merge.
5855
5859
5856 .. container:: verbose
5860 .. container:: verbose
5857
5861
5858 Template:
5862 Template:
5859
5863
5860 The following keywords are supported in addition to the common template
5864 The following keywords are supported in addition to the common template
5861 keywords and functions. See also :hg:`help templates`.
5865 keywords and functions. See also :hg:`help templates`.
5862
5866
5863 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5867 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5864 :path: String. Repository-absolute path of the file.
5868 :path: String. Repository-absolute path of the file.
5865
5869
5866 Returns 0 on success, 1 if any files fail a resolve attempt.
5870 Returns 0 on success, 1 if any files fail a resolve attempt.
5867 """
5871 """
5868
5872
5869 opts = pycompat.byteskwargs(opts)
5873 opts = pycompat.byteskwargs(opts)
5870 confirm = ui.configbool(b'commands', b'resolve.confirm')
5874 confirm = ui.configbool(b'commands', b'resolve.confirm')
5871 flaglist = b'all mark unmark list no_status re_merge'.split()
5875 flaglist = b'all mark unmark list no_status re_merge'.split()
5872 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5876 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5873
5877
5874 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5878 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5875 if actioncount > 1:
5879 if actioncount > 1:
5876 raise error.Abort(_(b"too many actions specified"))
5880 raise error.Abort(_(b"too many actions specified"))
5877 elif actioncount == 0 and ui.configbool(
5881 elif actioncount == 0 and ui.configbool(
5878 b'commands', b'resolve.explicit-re-merge'
5882 b'commands', b'resolve.explicit-re-merge'
5879 ):
5883 ):
5880 hint = _(b'use --mark, --unmark, --list or --re-merge')
5884 hint = _(b'use --mark, --unmark, --list or --re-merge')
5881 raise error.Abort(_(b'no action specified'), hint=hint)
5885 raise error.Abort(_(b'no action specified'), hint=hint)
5882 if pats and all:
5886 if pats and all:
5883 raise error.Abort(_(b"can't specify --all and patterns"))
5887 raise error.Abort(_(b"can't specify --all and patterns"))
5884 if not (all or pats or show or mark or unmark):
5888 if not (all or pats or show or mark or unmark):
5885 raise error.Abort(
5889 raise error.Abort(
5886 _(b'no files or directories specified'),
5890 _(b'no files or directories specified'),
5887 hint=b'use --all to re-merge all unresolved files',
5891 hint=b'use --all to re-merge all unresolved files',
5888 )
5892 )
5889
5893
5890 if confirm:
5894 if confirm:
5891 if all:
5895 if all:
5892 if ui.promptchoice(
5896 if ui.promptchoice(
5893 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5897 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5894 ):
5898 ):
5895 raise error.Abort(_(b'user quit'))
5899 raise error.Abort(_(b'user quit'))
5896 if mark and not pats:
5900 if mark and not pats:
5897 if ui.promptchoice(
5901 if ui.promptchoice(
5898 _(
5902 _(
5899 b'mark all unresolved files as resolved (yn)?'
5903 b'mark all unresolved files as resolved (yn)?'
5900 b'$$ &Yes $$ &No'
5904 b'$$ &Yes $$ &No'
5901 )
5905 )
5902 ):
5906 ):
5903 raise error.Abort(_(b'user quit'))
5907 raise error.Abort(_(b'user quit'))
5904 if unmark and not pats:
5908 if unmark and not pats:
5905 if ui.promptchoice(
5909 if ui.promptchoice(
5906 _(
5910 _(
5907 b'mark all resolved files as unresolved (yn)?'
5911 b'mark all resolved files as unresolved (yn)?'
5908 b'$$ &Yes $$ &No'
5912 b'$$ &Yes $$ &No'
5909 )
5913 )
5910 ):
5914 ):
5911 raise error.Abort(_(b'user quit'))
5915 raise error.Abort(_(b'user quit'))
5912
5916
5913 uipathfn = scmutil.getuipathfn(repo)
5917 uipathfn = scmutil.getuipathfn(repo)
5914
5918
5915 if show:
5919 if show:
5916 ui.pager(b'resolve')
5920 ui.pager(b'resolve')
5917 fm = ui.formatter(b'resolve', opts)
5921 fm = ui.formatter(b'resolve', opts)
5918 ms = mergemod.mergestate.read(repo)
5922 ms = mergemod.mergestate.read(repo)
5919 wctx = repo[None]
5923 wctx = repo[None]
5920 m = scmutil.match(wctx, pats, opts)
5924 m = scmutil.match(wctx, pats, opts)
5921
5925
5922 # Labels and keys based on merge state. Unresolved path conflicts show
5926 # Labels and keys based on merge state. Unresolved path conflicts show
5923 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5927 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5924 # resolved conflicts.
5928 # resolved conflicts.
5925 mergestateinfo = {
5929 mergestateinfo = {
5926 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5930 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5927 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5931 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5928 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5932 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5929 b'resolve.unresolved',
5933 b'resolve.unresolved',
5930 b'P',
5934 b'P',
5931 ),
5935 ),
5932 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5936 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5933 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5937 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5934 b'resolve.driverresolved',
5938 b'resolve.driverresolved',
5935 b'D',
5939 b'D',
5936 ),
5940 ),
5937 }
5941 }
5938
5942
5939 for f in ms:
5943 for f in ms:
5940 if not m(f):
5944 if not m(f):
5941 continue
5945 continue
5942
5946
5943 label, key = mergestateinfo[ms[f]]
5947 label, key = mergestateinfo[ms[f]]
5944 fm.startitem()
5948 fm.startitem()
5945 fm.context(ctx=wctx)
5949 fm.context(ctx=wctx)
5946 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5950 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5947 fm.data(path=f)
5951 fm.data(path=f)
5948 fm.plain(b'%s\n' % uipathfn(f), label=label)
5952 fm.plain(b'%s\n' % uipathfn(f), label=label)
5949 fm.end()
5953 fm.end()
5950 return 0
5954 return 0
5951
5955
5952 with repo.wlock():
5956 with repo.wlock():
5953 ms = mergemod.mergestate.read(repo)
5957 ms = mergemod.mergestate.read(repo)
5954
5958
5955 if not (ms.active() or repo.dirstate.p2() != nullid):
5959 if not (ms.active() or repo.dirstate.p2() != nullid):
5956 raise error.Abort(
5960 raise error.Abort(
5957 _(b'resolve command not applicable when not merging')
5961 _(b'resolve command not applicable when not merging')
5958 )
5962 )
5959
5963
5960 wctx = repo[None]
5964 wctx = repo[None]
5961
5965
5962 if (
5966 if (
5963 ms.mergedriver
5967 ms.mergedriver
5964 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5968 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5965 ):
5969 ):
5966 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5970 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5967 ms.commit()
5971 ms.commit()
5968 # allow mark and unmark to go through
5972 # allow mark and unmark to go through
5969 if not mark and not unmark and not proceed:
5973 if not mark and not unmark and not proceed:
5970 return 1
5974 return 1
5971
5975
5972 m = scmutil.match(wctx, pats, opts)
5976 m = scmutil.match(wctx, pats, opts)
5973 ret = 0
5977 ret = 0
5974 didwork = False
5978 didwork = False
5975 runconclude = False
5979 runconclude = False
5976
5980
5977 tocomplete = []
5981 tocomplete = []
5978 hasconflictmarkers = []
5982 hasconflictmarkers = []
5979 if mark:
5983 if mark:
5980 markcheck = ui.config(b'commands', b'resolve.mark-check')
5984 markcheck = ui.config(b'commands', b'resolve.mark-check')
5981 if markcheck not in [b'warn', b'abort']:
5985 if markcheck not in [b'warn', b'abort']:
5982 # Treat all invalid / unrecognized values as 'none'.
5986 # Treat all invalid / unrecognized values as 'none'.
5983 markcheck = False
5987 markcheck = False
5984 for f in ms:
5988 for f in ms:
5985 if not m(f):
5989 if not m(f):
5986 continue
5990 continue
5987
5991
5988 didwork = True
5992 didwork = True
5989
5993
5990 # don't let driver-resolved files be marked, and run the conclude
5994 # don't let driver-resolved files be marked, and run the conclude
5991 # step if asked to resolve
5995 # step if asked to resolve
5992 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5996 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5993 exact = m.exact(f)
5997 exact = m.exact(f)
5994 if mark:
5998 if mark:
5995 if exact:
5999 if exact:
5996 ui.warn(
6000 ui.warn(
5997 _(b'not marking %s as it is driver-resolved\n')
6001 _(b'not marking %s as it is driver-resolved\n')
5998 % uipathfn(f)
6002 % uipathfn(f)
5999 )
6003 )
6000 elif unmark:
6004 elif unmark:
6001 if exact:
6005 if exact:
6002 ui.warn(
6006 ui.warn(
6003 _(b'not unmarking %s as it is driver-resolved\n')
6007 _(b'not unmarking %s as it is driver-resolved\n')
6004 % uipathfn(f)
6008 % uipathfn(f)
6005 )
6009 )
6006 else:
6010 else:
6007 runconclude = True
6011 runconclude = True
6008 continue
6012 continue
6009
6013
6010 # path conflicts must be resolved manually
6014 # path conflicts must be resolved manually
6011 if ms[f] in (
6015 if ms[f] in (
6012 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6016 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6013 mergemod.MERGE_RECORD_RESOLVED_PATH,
6017 mergemod.MERGE_RECORD_RESOLVED_PATH,
6014 ):
6018 ):
6015 if mark:
6019 if mark:
6016 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6020 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6017 elif unmark:
6021 elif unmark:
6018 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6022 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6019 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6023 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6020 ui.warn(
6024 ui.warn(
6021 _(b'%s: path conflict must be resolved manually\n')
6025 _(b'%s: path conflict must be resolved manually\n')
6022 % uipathfn(f)
6026 % uipathfn(f)
6023 )
6027 )
6024 continue
6028 continue
6025
6029
6026 if mark:
6030 if mark:
6027 if markcheck:
6031 if markcheck:
6028 fdata = repo.wvfs.tryread(f)
6032 fdata = repo.wvfs.tryread(f)
6029 if (
6033 if (
6030 filemerge.hasconflictmarkers(fdata)
6034 filemerge.hasconflictmarkers(fdata)
6031 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6035 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6032 ):
6036 ):
6033 hasconflictmarkers.append(f)
6037 hasconflictmarkers.append(f)
6034 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6038 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6035 elif unmark:
6039 elif unmark:
6036 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6040 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6037 else:
6041 else:
6038 # backup pre-resolve (merge uses .orig for its own purposes)
6042 # backup pre-resolve (merge uses .orig for its own purposes)
6039 a = repo.wjoin(f)
6043 a = repo.wjoin(f)
6040 try:
6044 try:
6041 util.copyfile(a, a + b".resolve")
6045 util.copyfile(a, a + b".resolve")
6042 except (IOError, OSError) as inst:
6046 except (IOError, OSError) as inst:
6043 if inst.errno != errno.ENOENT:
6047 if inst.errno != errno.ENOENT:
6044 raise
6048 raise
6045
6049
6046 try:
6050 try:
6047 # preresolve file
6051 # preresolve file
6048 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6052 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6049 with ui.configoverride(overrides, b'resolve'):
6053 with ui.configoverride(overrides, b'resolve'):
6050 complete, r = ms.preresolve(f, wctx)
6054 complete, r = ms.preresolve(f, wctx)
6051 if not complete:
6055 if not complete:
6052 tocomplete.append(f)
6056 tocomplete.append(f)
6053 elif r:
6057 elif r:
6054 ret = 1
6058 ret = 1
6055 finally:
6059 finally:
6056 ms.commit()
6060 ms.commit()
6057
6061
6058 # replace filemerge's .orig file with our resolve file, but only
6062 # replace filemerge's .orig file with our resolve file, but only
6059 # for merges that are complete
6063 # for merges that are complete
6060 if complete:
6064 if complete:
6061 try:
6065 try:
6062 util.rename(
6066 util.rename(
6063 a + b".resolve", scmutil.backuppath(ui, repo, f)
6067 a + b".resolve", scmutil.backuppath(ui, repo, f)
6064 )
6068 )
6065 except OSError as inst:
6069 except OSError as inst:
6066 if inst.errno != errno.ENOENT:
6070 if inst.errno != errno.ENOENT:
6067 raise
6071 raise
6068
6072
6069 if hasconflictmarkers:
6073 if hasconflictmarkers:
6070 ui.warn(
6074 ui.warn(
6071 _(
6075 _(
6072 b'warning: the following files still have conflict '
6076 b'warning: the following files still have conflict '
6073 b'markers:\n'
6077 b'markers:\n'
6074 )
6078 )
6075 + b''.join(
6079 + b''.join(
6076 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6080 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6077 )
6081 )
6078 )
6082 )
6079 if markcheck == b'abort' and not all and not pats:
6083 if markcheck == b'abort' and not all and not pats:
6080 raise error.Abort(
6084 raise error.Abort(
6081 _(b'conflict markers detected'),
6085 _(b'conflict markers detected'),
6082 hint=_(b'use --all to mark anyway'),
6086 hint=_(b'use --all to mark anyway'),
6083 )
6087 )
6084
6088
6085 for f in tocomplete:
6089 for f in tocomplete:
6086 try:
6090 try:
6087 # resolve file
6091 # resolve file
6088 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6092 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6089 with ui.configoverride(overrides, b'resolve'):
6093 with ui.configoverride(overrides, b'resolve'):
6090 r = ms.resolve(f, wctx)
6094 r = ms.resolve(f, wctx)
6091 if r:
6095 if r:
6092 ret = 1
6096 ret = 1
6093 finally:
6097 finally:
6094 ms.commit()
6098 ms.commit()
6095
6099
6096 # replace filemerge's .orig file with our resolve file
6100 # replace filemerge's .orig file with our resolve file
6097 a = repo.wjoin(f)
6101 a = repo.wjoin(f)
6098 try:
6102 try:
6099 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6103 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6100 except OSError as inst:
6104 except OSError as inst:
6101 if inst.errno != errno.ENOENT:
6105 if inst.errno != errno.ENOENT:
6102 raise
6106 raise
6103
6107
6104 ms.commit()
6108 ms.commit()
6105 ms.recordactions()
6109 ms.recordactions()
6106
6110
6107 if not didwork and pats:
6111 if not didwork and pats:
6108 hint = None
6112 hint = None
6109 if not any([p for p in pats if p.find(b':') >= 0]):
6113 if not any([p for p in pats if p.find(b':') >= 0]):
6110 pats = [b'path:%s' % p for p in pats]
6114 pats = [b'path:%s' % p for p in pats]
6111 m = scmutil.match(wctx, pats, opts)
6115 m = scmutil.match(wctx, pats, opts)
6112 for f in ms:
6116 for f in ms:
6113 if not m(f):
6117 if not m(f):
6114 continue
6118 continue
6115
6119
6116 def flag(o):
6120 def flag(o):
6117 if o == b're_merge':
6121 if o == b're_merge':
6118 return b'--re-merge '
6122 return b'--re-merge '
6119 return b'-%s ' % o[0:1]
6123 return b'-%s ' % o[0:1]
6120
6124
6121 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6125 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6122 hint = _(b"(try: hg resolve %s%s)\n") % (
6126 hint = _(b"(try: hg resolve %s%s)\n") % (
6123 flags,
6127 flags,
6124 b' '.join(pats),
6128 b' '.join(pats),
6125 )
6129 )
6126 break
6130 break
6127 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6131 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6128 if hint:
6132 if hint:
6129 ui.warn(hint)
6133 ui.warn(hint)
6130 elif ms.mergedriver and ms.mdstate() != b's':
6134 elif ms.mergedriver and ms.mdstate() != b's':
6131 # run conclude step when either a driver-resolved file is requested
6135 # run conclude step when either a driver-resolved file is requested
6132 # or there are no driver-resolved files
6136 # or there are no driver-resolved files
6133 # we can't use 'ret' to determine whether any files are unresolved
6137 # we can't use 'ret' to determine whether any files are unresolved
6134 # because we might not have tried to resolve some
6138 # because we might not have tried to resolve some
6135 if (runconclude or not list(ms.driverresolved())) and not list(
6139 if (runconclude or not list(ms.driverresolved())) and not list(
6136 ms.unresolved()
6140 ms.unresolved()
6137 ):
6141 ):
6138 proceed = mergemod.driverconclude(repo, ms, wctx)
6142 proceed = mergemod.driverconclude(repo, ms, wctx)
6139 ms.commit()
6143 ms.commit()
6140 if not proceed:
6144 if not proceed:
6141 return 1
6145 return 1
6142
6146
6143 # Nudge users into finishing an unfinished operation
6147 # Nudge users into finishing an unfinished operation
6144 unresolvedf = list(ms.unresolved())
6148 unresolvedf = list(ms.unresolved())
6145 driverresolvedf = list(ms.driverresolved())
6149 driverresolvedf = list(ms.driverresolved())
6146 if not unresolvedf and not driverresolvedf:
6150 if not unresolvedf and not driverresolvedf:
6147 ui.status(_(b'(no more unresolved files)\n'))
6151 ui.status(_(b'(no more unresolved files)\n'))
6148 cmdutil.checkafterresolved(repo)
6152 cmdutil.checkafterresolved(repo)
6149 elif not unresolvedf:
6153 elif not unresolvedf:
6150 ui.status(
6154 ui.status(
6151 _(
6155 _(
6152 b'(no more unresolved files -- '
6156 b'(no more unresolved files -- '
6153 b'run "hg resolve --all" to conclude)\n'
6157 b'run "hg resolve --all" to conclude)\n'
6154 )
6158 )
6155 )
6159 )
6156
6160
6157 return ret
6161 return ret
6158
6162
6159
6163
6160 @command(
6164 @command(
6161 b'revert',
6165 b'revert',
6162 [
6166 [
6163 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6167 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6164 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6168 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6165 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6169 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6166 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6170 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6167 (b'i', b'interactive', None, _(b'interactively select the changes')),
6171 (b'i', b'interactive', None, _(b'interactively select the changes')),
6168 ]
6172 ]
6169 + walkopts
6173 + walkopts
6170 + dryrunopts,
6174 + dryrunopts,
6171 _(b'[OPTION]... [-r REV] [NAME]...'),
6175 _(b'[OPTION]... [-r REV] [NAME]...'),
6172 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6176 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6173 )
6177 )
6174 def revert(ui, repo, *pats, **opts):
6178 def revert(ui, repo, *pats, **opts):
6175 """restore files to their checkout state
6179 """restore files to their checkout state
6176
6180
6177 .. note::
6181 .. note::
6178
6182
6179 To check out earlier revisions, you should use :hg:`update REV`.
6183 To check out earlier revisions, you should use :hg:`update REV`.
6180 To cancel an uncommitted merge (and lose your changes),
6184 To cancel an uncommitted merge (and lose your changes),
6181 use :hg:`merge --abort`.
6185 use :hg:`merge --abort`.
6182
6186
6183 With no revision specified, revert the specified files or directories
6187 With no revision specified, revert the specified files or directories
6184 to the contents they had in the parent of the working directory.
6188 to the contents they had in the parent of the working directory.
6185 This restores the contents of files to an unmodified
6189 This restores the contents of files to an unmodified
6186 state and unschedules adds, removes, copies, and renames. If the
6190 state and unschedules adds, removes, copies, and renames. If the
6187 working directory has two parents, you must explicitly specify a
6191 working directory has two parents, you must explicitly specify a
6188 revision.
6192 revision.
6189
6193
6190 Using the -r/--rev or -d/--date options, revert the given files or
6194 Using the -r/--rev or -d/--date options, revert the given files or
6191 directories to their states as of a specific revision. Because
6195 directories to their states as of a specific revision. Because
6192 revert does not change the working directory parents, this will
6196 revert does not change the working directory parents, this will
6193 cause these files to appear modified. This can be helpful to "back
6197 cause these files to appear modified. This can be helpful to "back
6194 out" some or all of an earlier change. See :hg:`backout` for a
6198 out" some or all of an earlier change. See :hg:`backout` for a
6195 related method.
6199 related method.
6196
6200
6197 Modified files are saved with a .orig suffix before reverting.
6201 Modified files are saved with a .orig suffix before reverting.
6198 To disable these backups, use --no-backup. It is possible to store
6202 To disable these backups, use --no-backup. It is possible to store
6199 the backup files in a custom directory relative to the root of the
6203 the backup files in a custom directory relative to the root of the
6200 repository by setting the ``ui.origbackuppath`` configuration
6204 repository by setting the ``ui.origbackuppath`` configuration
6201 option.
6205 option.
6202
6206
6203 See :hg:`help dates` for a list of formats valid for -d/--date.
6207 See :hg:`help dates` for a list of formats valid for -d/--date.
6204
6208
6205 See :hg:`help backout` for a way to reverse the effect of an
6209 See :hg:`help backout` for a way to reverse the effect of an
6206 earlier changeset.
6210 earlier changeset.
6207
6211
6208 Returns 0 on success.
6212 Returns 0 on success.
6209 """
6213 """
6210
6214
6211 opts = pycompat.byteskwargs(opts)
6215 opts = pycompat.byteskwargs(opts)
6212 if opts.get(b"date"):
6216 if opts.get(b"date"):
6213 if opts.get(b"rev"):
6217 if opts.get(b"rev"):
6214 raise error.Abort(_(b"you can't specify a revision and a date"))
6218 raise error.Abort(_(b"you can't specify a revision and a date"))
6215 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6219 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6216
6220
6217 parent, p2 = repo.dirstate.parents()
6221 parent, p2 = repo.dirstate.parents()
6218 if not opts.get(b'rev') and p2 != nullid:
6222 if not opts.get(b'rev') and p2 != nullid:
6219 # revert after merge is a trap for new users (issue2915)
6223 # revert after merge is a trap for new users (issue2915)
6220 raise error.Abort(
6224 raise error.Abort(
6221 _(b'uncommitted merge with no revision specified'),
6225 _(b'uncommitted merge with no revision specified'),
6222 hint=_(b"use 'hg update' or see 'hg help revert'"),
6226 hint=_(b"use 'hg update' or see 'hg help revert'"),
6223 )
6227 )
6224
6228
6225 rev = opts.get(b'rev')
6229 rev = opts.get(b'rev')
6226 if rev:
6230 if rev:
6227 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6231 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6228 ctx = scmutil.revsingle(repo, rev)
6232 ctx = scmutil.revsingle(repo, rev)
6229
6233
6230 if not (
6234 if not (
6231 pats
6235 pats
6232 or opts.get(b'include')
6236 or opts.get(b'include')
6233 or opts.get(b'exclude')
6237 or opts.get(b'exclude')
6234 or opts.get(b'all')
6238 or opts.get(b'all')
6235 or opts.get(b'interactive')
6239 or opts.get(b'interactive')
6236 ):
6240 ):
6237 msg = _(b"no files or directories specified")
6241 msg = _(b"no files or directories specified")
6238 if p2 != nullid:
6242 if p2 != nullid:
6239 hint = _(
6243 hint = _(
6240 b"uncommitted merge, use --all to discard all changes,"
6244 b"uncommitted merge, use --all to discard all changes,"
6241 b" or 'hg update -C .' to abort the merge"
6245 b" or 'hg update -C .' to abort the merge"
6242 )
6246 )
6243 raise error.Abort(msg, hint=hint)
6247 raise error.Abort(msg, hint=hint)
6244 dirty = any(repo.status())
6248 dirty = any(repo.status())
6245 node = ctx.node()
6249 node = ctx.node()
6246 if node != parent:
6250 if node != parent:
6247 if dirty:
6251 if dirty:
6248 hint = (
6252 hint = (
6249 _(
6253 _(
6250 b"uncommitted changes, use --all to discard all"
6254 b"uncommitted changes, use --all to discard all"
6251 b" changes, or 'hg update %d' to update"
6255 b" changes, or 'hg update %d' to update"
6252 )
6256 )
6253 % ctx.rev()
6257 % ctx.rev()
6254 )
6258 )
6255 else:
6259 else:
6256 hint = (
6260 hint = (
6257 _(
6261 _(
6258 b"use --all to revert all files,"
6262 b"use --all to revert all files,"
6259 b" or 'hg update %d' to update"
6263 b" or 'hg update %d' to update"
6260 )
6264 )
6261 % ctx.rev()
6265 % ctx.rev()
6262 )
6266 )
6263 elif dirty:
6267 elif dirty:
6264 hint = _(b"uncommitted changes, use --all to discard all changes")
6268 hint = _(b"uncommitted changes, use --all to discard all changes")
6265 else:
6269 else:
6266 hint = _(b"use --all to revert all files")
6270 hint = _(b"use --all to revert all files")
6267 raise error.Abort(msg, hint=hint)
6271 raise error.Abort(msg, hint=hint)
6268
6272
6269 return cmdutil.revert(
6273 return cmdutil.revert(
6270 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6274 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6271 )
6275 )
6272
6276
6273
6277
6274 @command(
6278 @command(
6275 b'rollback',
6279 b'rollback',
6276 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6280 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6277 helpcategory=command.CATEGORY_MAINTENANCE,
6281 helpcategory=command.CATEGORY_MAINTENANCE,
6278 )
6282 )
6279 def rollback(ui, repo, **opts):
6283 def rollback(ui, repo, **opts):
6280 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6284 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6281
6285
6282 Please use :hg:`commit --amend` instead of rollback to correct
6286 Please use :hg:`commit --amend` instead of rollback to correct
6283 mistakes in the last commit.
6287 mistakes in the last commit.
6284
6288
6285 This command should be used with care. There is only one level of
6289 This command should be used with care. There is only one level of
6286 rollback, and there is no way to undo a rollback. It will also
6290 rollback, and there is no way to undo a rollback. It will also
6287 restore the dirstate at the time of the last transaction, losing
6291 restore the dirstate at the time of the last transaction, losing
6288 any dirstate changes since that time. This command does not alter
6292 any dirstate changes since that time. This command does not alter
6289 the working directory.
6293 the working directory.
6290
6294
6291 Transactions are used to encapsulate the effects of all commands
6295 Transactions are used to encapsulate the effects of all commands
6292 that create new changesets or propagate existing changesets into a
6296 that create new changesets or propagate existing changesets into a
6293 repository.
6297 repository.
6294
6298
6295 .. container:: verbose
6299 .. container:: verbose
6296
6300
6297 For example, the following commands are transactional, and their
6301 For example, the following commands are transactional, and their
6298 effects can be rolled back:
6302 effects can be rolled back:
6299
6303
6300 - commit
6304 - commit
6301 - import
6305 - import
6302 - pull
6306 - pull
6303 - push (with this repository as the destination)
6307 - push (with this repository as the destination)
6304 - unbundle
6308 - unbundle
6305
6309
6306 To avoid permanent data loss, rollback will refuse to rollback a
6310 To avoid permanent data loss, rollback will refuse to rollback a
6307 commit transaction if it isn't checked out. Use --force to
6311 commit transaction if it isn't checked out. Use --force to
6308 override this protection.
6312 override this protection.
6309
6313
6310 The rollback command can be entirely disabled by setting the
6314 The rollback command can be entirely disabled by setting the
6311 ``ui.rollback`` configuration setting to false. If you're here
6315 ``ui.rollback`` configuration setting to false. If you're here
6312 because you want to use rollback and it's disabled, you can
6316 because you want to use rollback and it's disabled, you can
6313 re-enable the command by setting ``ui.rollback`` to true.
6317 re-enable the command by setting ``ui.rollback`` to true.
6314
6318
6315 This command is not intended for use on public repositories. Once
6319 This command is not intended for use on public repositories. Once
6316 changes are visible for pull by other users, rolling a transaction
6320 changes are visible for pull by other users, rolling a transaction
6317 back locally is ineffective (someone else may already have pulled
6321 back locally is ineffective (someone else may already have pulled
6318 the changes). Furthermore, a race is possible with readers of the
6322 the changes). Furthermore, a race is possible with readers of the
6319 repository; for example an in-progress pull from the repository
6323 repository; for example an in-progress pull from the repository
6320 may fail if a rollback is performed.
6324 may fail if a rollback is performed.
6321
6325
6322 Returns 0 on success, 1 if no rollback data is available.
6326 Returns 0 on success, 1 if no rollback data is available.
6323 """
6327 """
6324 if not ui.configbool(b'ui', b'rollback'):
6328 if not ui.configbool(b'ui', b'rollback'):
6325 raise error.Abort(
6329 raise error.Abort(
6326 _(b'rollback is disabled because it is unsafe'),
6330 _(b'rollback is disabled because it is unsafe'),
6327 hint=b'see `hg help -v rollback` for information',
6331 hint=b'see `hg help -v rollback` for information',
6328 )
6332 )
6329 return repo.rollback(dryrun=opts.get(r'dry_run'), force=opts.get(r'force'))
6333 return repo.rollback(dryrun=opts.get(r'dry_run'), force=opts.get(r'force'))
6330
6334
6331
6335
6332 @command(
6336 @command(
6333 b'root',
6337 b'root',
6334 [] + formatteropts,
6338 [] + formatteropts,
6335 intents={INTENT_READONLY},
6339 intents={INTENT_READONLY},
6336 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6340 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6337 )
6341 )
6338 def root(ui, repo, **opts):
6342 def root(ui, repo, **opts):
6339 """print the root (top) of the current working directory
6343 """print the root (top) of the current working directory
6340
6344
6341 Print the root directory of the current repository.
6345 Print the root directory of the current repository.
6342
6346
6343 .. container:: verbose
6347 .. container:: verbose
6344
6348
6345 Template:
6349 Template:
6346
6350
6347 The following keywords are supported in addition to the common template
6351 The following keywords are supported in addition to the common template
6348 keywords and functions. See also :hg:`help templates`.
6352 keywords and functions. See also :hg:`help templates`.
6349
6353
6350 :hgpath: String. Path to the .hg directory.
6354 :hgpath: String. Path to the .hg directory.
6351 :storepath: String. Path to the directory holding versioned data.
6355 :storepath: String. Path to the directory holding versioned data.
6352
6356
6353 Returns 0 on success.
6357 Returns 0 on success.
6354 """
6358 """
6355 opts = pycompat.byteskwargs(opts)
6359 opts = pycompat.byteskwargs(opts)
6356 with ui.formatter(b'root', opts) as fm:
6360 with ui.formatter(b'root', opts) as fm:
6357 fm.startitem()
6361 fm.startitem()
6358 fm.write(b'reporoot', b'%s\n', repo.root)
6362 fm.write(b'reporoot', b'%s\n', repo.root)
6359 fm.data(hgpath=repo.path, storepath=repo.spath)
6363 fm.data(hgpath=repo.path, storepath=repo.spath)
6360
6364
6361
6365
6362 @command(
6366 @command(
6363 b'serve',
6367 b'serve',
6364 [
6368 [
6365 (
6369 (
6366 b'A',
6370 b'A',
6367 b'accesslog',
6371 b'accesslog',
6368 b'',
6372 b'',
6369 _(b'name of access log file to write to'),
6373 _(b'name of access log file to write to'),
6370 _(b'FILE'),
6374 _(b'FILE'),
6371 ),
6375 ),
6372 (b'd', b'daemon', None, _(b'run server in background')),
6376 (b'd', b'daemon', None, _(b'run server in background')),
6373 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6377 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6374 (
6378 (
6375 b'E',
6379 b'E',
6376 b'errorlog',
6380 b'errorlog',
6377 b'',
6381 b'',
6378 _(b'name of error log file to write to'),
6382 _(b'name of error log file to write to'),
6379 _(b'FILE'),
6383 _(b'FILE'),
6380 ),
6384 ),
6381 # use string type, then we can check if something was passed
6385 # use string type, then we can check if something was passed
6382 (
6386 (
6383 b'p',
6387 b'p',
6384 b'port',
6388 b'port',
6385 b'',
6389 b'',
6386 _(b'port to listen on (default: 8000)'),
6390 _(b'port to listen on (default: 8000)'),
6387 _(b'PORT'),
6391 _(b'PORT'),
6388 ),
6392 ),
6389 (
6393 (
6390 b'a',
6394 b'a',
6391 b'address',
6395 b'address',
6392 b'',
6396 b'',
6393 _(b'address to listen on (default: all interfaces)'),
6397 _(b'address to listen on (default: all interfaces)'),
6394 _(b'ADDR'),
6398 _(b'ADDR'),
6395 ),
6399 ),
6396 (
6400 (
6397 b'',
6401 b'',
6398 b'prefix',
6402 b'prefix',
6399 b'',
6403 b'',
6400 _(b'prefix path to serve from (default: server root)'),
6404 _(b'prefix path to serve from (default: server root)'),
6401 _(b'PREFIX'),
6405 _(b'PREFIX'),
6402 ),
6406 ),
6403 (
6407 (
6404 b'n',
6408 b'n',
6405 b'name',
6409 b'name',
6406 b'',
6410 b'',
6407 _(b'name to show in web pages (default: working directory)'),
6411 _(b'name to show in web pages (default: working directory)'),
6408 _(b'NAME'),
6412 _(b'NAME'),
6409 ),
6413 ),
6410 (
6414 (
6411 b'',
6415 b'',
6412 b'web-conf',
6416 b'web-conf',
6413 b'',
6417 b'',
6414 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6418 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6415 _(b'FILE'),
6419 _(b'FILE'),
6416 ),
6420 ),
6417 (
6421 (
6418 b'',
6422 b'',
6419 b'webdir-conf',
6423 b'webdir-conf',
6420 b'',
6424 b'',
6421 _(b'name of the hgweb config file (DEPRECATED)'),
6425 _(b'name of the hgweb config file (DEPRECATED)'),
6422 _(b'FILE'),
6426 _(b'FILE'),
6423 ),
6427 ),
6424 (
6428 (
6425 b'',
6429 b'',
6426 b'pid-file',
6430 b'pid-file',
6427 b'',
6431 b'',
6428 _(b'name of file to write process ID to'),
6432 _(b'name of file to write process ID to'),
6429 _(b'FILE'),
6433 _(b'FILE'),
6430 ),
6434 ),
6431 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6435 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6432 (
6436 (
6433 b'',
6437 b'',
6434 b'cmdserver',
6438 b'cmdserver',
6435 b'',
6439 b'',
6436 _(b'for remote clients (ADVANCED)'),
6440 _(b'for remote clients (ADVANCED)'),
6437 _(b'MODE'),
6441 _(b'MODE'),
6438 ),
6442 ),
6439 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6443 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6440 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6444 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6441 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6445 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6442 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6446 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6443 (b'', b'print-url', None, _(b'start and print only the URL')),
6447 (b'', b'print-url', None, _(b'start and print only the URL')),
6444 ]
6448 ]
6445 + subrepoopts,
6449 + subrepoopts,
6446 _(b'[OPTION]...'),
6450 _(b'[OPTION]...'),
6447 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6451 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6448 helpbasic=True,
6452 helpbasic=True,
6449 optionalrepo=True,
6453 optionalrepo=True,
6450 )
6454 )
6451 def serve(ui, repo, **opts):
6455 def serve(ui, repo, **opts):
6452 """start stand-alone webserver
6456 """start stand-alone webserver
6453
6457
6454 Start a local HTTP repository browser and pull server. You can use
6458 Start a local HTTP repository browser and pull server. You can use
6455 this for ad-hoc sharing and browsing of repositories. It is
6459 this for ad-hoc sharing and browsing of repositories. It is
6456 recommended to use a real web server to serve a repository for
6460 recommended to use a real web server to serve a repository for
6457 longer periods of time.
6461 longer periods of time.
6458
6462
6459 Please note that the server does not implement access control.
6463 Please note that the server does not implement access control.
6460 This means that, by default, anybody can read from the server and
6464 This means that, by default, anybody can read from the server and
6461 nobody can write to it by default. Set the ``web.allow-push``
6465 nobody can write to it by default. Set the ``web.allow-push``
6462 option to ``*`` to allow everybody to push to the server. You
6466 option to ``*`` to allow everybody to push to the server. You
6463 should use a real web server if you need to authenticate users.
6467 should use a real web server if you need to authenticate users.
6464
6468
6465 By default, the server logs accesses to stdout and errors to
6469 By default, the server logs accesses to stdout and errors to
6466 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6470 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6467 files.
6471 files.
6468
6472
6469 To have the server choose a free port number to listen on, specify
6473 To have the server choose a free port number to listen on, specify
6470 a port number of 0; in this case, the server will print the port
6474 a port number of 0; in this case, the server will print the port
6471 number it uses.
6475 number it uses.
6472
6476
6473 Returns 0 on success.
6477 Returns 0 on success.
6474 """
6478 """
6475
6479
6476 opts = pycompat.byteskwargs(opts)
6480 opts = pycompat.byteskwargs(opts)
6477 if opts[b"stdio"] and opts[b"cmdserver"]:
6481 if opts[b"stdio"] and opts[b"cmdserver"]:
6478 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6482 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6479 if opts[b"print_url"] and ui.verbose:
6483 if opts[b"print_url"] and ui.verbose:
6480 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6484 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6481
6485
6482 if opts[b"stdio"]:
6486 if opts[b"stdio"]:
6483 if repo is None:
6487 if repo is None:
6484 raise error.RepoError(
6488 raise error.RepoError(
6485 _(b"there is no Mercurial repository here (.hg not found)")
6489 _(b"there is no Mercurial repository here (.hg not found)")
6486 )
6490 )
6487 s = wireprotoserver.sshserver(ui, repo)
6491 s = wireprotoserver.sshserver(ui, repo)
6488 s.serve_forever()
6492 s.serve_forever()
6489
6493
6490 service = server.createservice(ui, repo, opts)
6494 service = server.createservice(ui, repo, opts)
6491 return server.runservice(opts, initfn=service.init, runfn=service.run)
6495 return server.runservice(opts, initfn=service.init, runfn=service.run)
6492
6496
6493
6497
6494 @command(
6498 @command(
6495 b'shelve',
6499 b'shelve',
6496 [
6500 [
6497 (
6501 (
6498 b'A',
6502 b'A',
6499 b'addremove',
6503 b'addremove',
6500 None,
6504 None,
6501 _(b'mark new/missing files as added/removed before shelving'),
6505 _(b'mark new/missing files as added/removed before shelving'),
6502 ),
6506 ),
6503 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6507 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6504 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6508 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6505 (
6509 (
6506 b'',
6510 b'',
6507 b'date',
6511 b'date',
6508 b'',
6512 b'',
6509 _(b'shelve with the specified commit date'),
6513 _(b'shelve with the specified commit date'),
6510 _(b'DATE'),
6514 _(b'DATE'),
6511 ),
6515 ),
6512 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6516 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6513 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6517 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6514 (
6518 (
6515 b'k',
6519 b'k',
6516 b'keep',
6520 b'keep',
6517 False,
6521 False,
6518 _(b'shelve, but keep changes in the working directory'),
6522 _(b'shelve, but keep changes in the working directory'),
6519 ),
6523 ),
6520 (b'l', b'list', None, _(b'list current shelves')),
6524 (b'l', b'list', None, _(b'list current shelves')),
6521 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6525 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6522 (
6526 (
6523 b'n',
6527 b'n',
6524 b'name',
6528 b'name',
6525 b'',
6529 b'',
6526 _(b'use the given name for the shelved commit'),
6530 _(b'use the given name for the shelved commit'),
6527 _(b'NAME'),
6531 _(b'NAME'),
6528 ),
6532 ),
6529 (
6533 (
6530 b'p',
6534 b'p',
6531 b'patch',
6535 b'patch',
6532 None,
6536 None,
6533 _(
6537 _(
6534 b'output patches for changes (provide the names of the shelved '
6538 b'output patches for changes (provide the names of the shelved '
6535 b'changes as positional arguments)'
6539 b'changes as positional arguments)'
6536 ),
6540 ),
6537 ),
6541 ),
6538 (b'i', b'interactive', None, _(b'interactive mode')),
6542 (b'i', b'interactive', None, _(b'interactive mode')),
6539 (
6543 (
6540 b'',
6544 b'',
6541 b'stat',
6545 b'stat',
6542 None,
6546 None,
6543 _(
6547 _(
6544 b'output diffstat-style summary of changes (provide the names of '
6548 b'output diffstat-style summary of changes (provide the names of '
6545 b'the shelved changes as positional arguments)'
6549 b'the shelved changes as positional arguments)'
6546 ),
6550 ),
6547 ),
6551 ),
6548 ]
6552 ]
6549 + cmdutil.walkopts,
6553 + cmdutil.walkopts,
6550 _(b'hg shelve [OPTION]... [FILE]...'),
6554 _(b'hg shelve [OPTION]... [FILE]...'),
6551 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6555 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6552 )
6556 )
6553 def shelve(ui, repo, *pats, **opts):
6557 def shelve(ui, repo, *pats, **opts):
6554 '''save and set aside changes from the working directory
6558 '''save and set aside changes from the working directory
6555
6559
6556 Shelving takes files that "hg status" reports as not clean, saves
6560 Shelving takes files that "hg status" reports as not clean, saves
6557 the modifications to a bundle (a shelved change), and reverts the
6561 the modifications to a bundle (a shelved change), and reverts the
6558 files so that their state in the working directory becomes clean.
6562 files so that their state in the working directory becomes clean.
6559
6563
6560 To restore these changes to the working directory, using "hg
6564 To restore these changes to the working directory, using "hg
6561 unshelve"; this will work even if you switch to a different
6565 unshelve"; this will work even if you switch to a different
6562 commit.
6566 commit.
6563
6567
6564 When no files are specified, "hg shelve" saves all not-clean
6568 When no files are specified, "hg shelve" saves all not-clean
6565 files. If specific files or directories are named, only changes to
6569 files. If specific files or directories are named, only changes to
6566 those files are shelved.
6570 those files are shelved.
6567
6571
6568 In bare shelve (when no files are specified, without interactive,
6572 In bare shelve (when no files are specified, without interactive,
6569 include and exclude option), shelving remembers information if the
6573 include and exclude option), shelving remembers information if the
6570 working directory was on newly created branch, in other words working
6574 working directory was on newly created branch, in other words working
6571 directory was on different branch than its first parent. In this
6575 directory was on different branch than its first parent. In this
6572 situation unshelving restores branch information to the working directory.
6576 situation unshelving restores branch information to the working directory.
6573
6577
6574 Each shelved change has a name that makes it easier to find later.
6578 Each shelved change has a name that makes it easier to find later.
6575 The name of a shelved change defaults to being based on the active
6579 The name of a shelved change defaults to being based on the active
6576 bookmark, or if there is no active bookmark, the current named
6580 bookmark, or if there is no active bookmark, the current named
6577 branch. To specify a different name, use ``--name``.
6581 branch. To specify a different name, use ``--name``.
6578
6582
6579 To see a list of existing shelved changes, use the ``--list``
6583 To see a list of existing shelved changes, use the ``--list``
6580 option. For each shelved change, this will print its name, age,
6584 option. For each shelved change, this will print its name, age,
6581 and description; use ``--patch`` or ``--stat`` for more details.
6585 and description; use ``--patch`` or ``--stat`` for more details.
6582
6586
6583 To delete specific shelved changes, use ``--delete``. To delete
6587 To delete specific shelved changes, use ``--delete``. To delete
6584 all shelved changes, use ``--cleanup``.
6588 all shelved changes, use ``--cleanup``.
6585 '''
6589 '''
6586 opts = pycompat.byteskwargs(opts)
6590 opts = pycompat.byteskwargs(opts)
6587 allowables = [
6591 allowables = [
6588 (b'addremove', {b'create'}), # 'create' is pseudo action
6592 (b'addremove', {b'create'}), # 'create' is pseudo action
6589 (b'unknown', {b'create'}),
6593 (b'unknown', {b'create'}),
6590 (b'cleanup', {b'cleanup'}),
6594 (b'cleanup', {b'cleanup'}),
6591 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6595 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6592 (b'delete', {b'delete'}),
6596 (b'delete', {b'delete'}),
6593 (b'edit', {b'create'}),
6597 (b'edit', {b'create'}),
6594 (b'keep', {b'create'}),
6598 (b'keep', {b'create'}),
6595 (b'list', {b'list'}),
6599 (b'list', {b'list'}),
6596 (b'message', {b'create'}),
6600 (b'message', {b'create'}),
6597 (b'name', {b'create'}),
6601 (b'name', {b'create'}),
6598 (b'patch', {b'patch', b'list'}),
6602 (b'patch', {b'patch', b'list'}),
6599 (b'stat', {b'stat', b'list'}),
6603 (b'stat', {b'stat', b'list'}),
6600 ]
6604 ]
6601
6605
6602 def checkopt(opt):
6606 def checkopt(opt):
6603 if opts.get(opt):
6607 if opts.get(opt):
6604 for i, allowable in allowables:
6608 for i, allowable in allowables:
6605 if opts[i] and opt not in allowable:
6609 if opts[i] and opt not in allowable:
6606 raise error.Abort(
6610 raise error.Abort(
6607 _(
6611 _(
6608 b"options '--%s' and '--%s' may not be "
6612 b"options '--%s' and '--%s' may not be "
6609 b"used together"
6613 b"used together"
6610 )
6614 )
6611 % (opt, i)
6615 % (opt, i)
6612 )
6616 )
6613 return True
6617 return True
6614
6618
6615 if checkopt(b'cleanup'):
6619 if checkopt(b'cleanup'):
6616 if pats:
6620 if pats:
6617 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6621 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6618 return shelvemod.cleanupcmd(ui, repo)
6622 return shelvemod.cleanupcmd(ui, repo)
6619 elif checkopt(b'delete'):
6623 elif checkopt(b'delete'):
6620 return shelvemod.deletecmd(ui, repo, pats)
6624 return shelvemod.deletecmd(ui, repo, pats)
6621 elif checkopt(b'list'):
6625 elif checkopt(b'list'):
6622 return shelvemod.listcmd(ui, repo, pats, opts)
6626 return shelvemod.listcmd(ui, repo, pats, opts)
6623 elif checkopt(b'patch') or checkopt(b'stat'):
6627 elif checkopt(b'patch') or checkopt(b'stat'):
6624 return shelvemod.patchcmds(ui, repo, pats, opts)
6628 return shelvemod.patchcmds(ui, repo, pats, opts)
6625 else:
6629 else:
6626 return shelvemod.createcmd(ui, repo, pats, opts)
6630 return shelvemod.createcmd(ui, repo, pats, opts)
6627
6631
6628
6632
6629 _NOTTERSE = b'nothing'
6633 _NOTTERSE = b'nothing'
6630
6634
6631
6635
6632 @command(
6636 @command(
6633 b'status|st',
6637 b'status|st',
6634 [
6638 [
6635 (b'A', b'all', None, _(b'show status of all files')),
6639 (b'A', b'all', None, _(b'show status of all files')),
6636 (b'm', b'modified', None, _(b'show only modified files')),
6640 (b'm', b'modified', None, _(b'show only modified files')),
6637 (b'a', b'added', None, _(b'show only added files')),
6641 (b'a', b'added', None, _(b'show only added files')),
6638 (b'r', b'removed', None, _(b'show only removed files')),
6642 (b'r', b'removed', None, _(b'show only removed files')),
6639 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6643 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6640 (b'c', b'clean', None, _(b'show only files without changes')),
6644 (b'c', b'clean', None, _(b'show only files without changes')),
6641 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6645 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6642 (b'i', b'ignored', None, _(b'show only ignored files')),
6646 (b'i', b'ignored', None, _(b'show only ignored files')),
6643 (b'n', b'no-status', None, _(b'hide status prefix')),
6647 (b'n', b'no-status', None, _(b'hide status prefix')),
6644 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6648 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6645 (b'C', b'copies', None, _(b'show source of copied files')),
6649 (b'C', b'copies', None, _(b'show source of copied files')),
6646 (
6650 (
6647 b'0',
6651 b'0',
6648 b'print0',
6652 b'print0',
6649 None,
6653 None,
6650 _(b'end filenames with NUL, for use with xargs'),
6654 _(b'end filenames with NUL, for use with xargs'),
6651 ),
6655 ),
6652 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6656 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6653 (
6657 (
6654 b'',
6658 b'',
6655 b'change',
6659 b'change',
6656 b'',
6660 b'',
6657 _(b'list the changed files of a revision'),
6661 _(b'list the changed files of a revision'),
6658 _(b'REV'),
6662 _(b'REV'),
6659 ),
6663 ),
6660 ]
6664 ]
6661 + walkopts
6665 + walkopts
6662 + subrepoopts
6666 + subrepoopts
6663 + formatteropts,
6667 + formatteropts,
6664 _(b'[OPTION]... [FILE]...'),
6668 _(b'[OPTION]... [FILE]...'),
6665 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6669 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6666 helpbasic=True,
6670 helpbasic=True,
6667 inferrepo=True,
6671 inferrepo=True,
6668 intents={INTENT_READONLY},
6672 intents={INTENT_READONLY},
6669 )
6673 )
6670 def status(ui, repo, *pats, **opts):
6674 def status(ui, repo, *pats, **opts):
6671 """show changed files in the working directory
6675 """show changed files in the working directory
6672
6676
6673 Show status of files in the repository. If names are given, only
6677 Show status of files in the repository. If names are given, only
6674 files that match are shown. Files that are clean or ignored or
6678 files that match are shown. Files that are clean or ignored or
6675 the source of a copy/move operation, are not listed unless
6679 the source of a copy/move operation, are not listed unless
6676 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6680 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6677 Unless options described with "show only ..." are given, the
6681 Unless options described with "show only ..." are given, the
6678 options -mardu are used.
6682 options -mardu are used.
6679
6683
6680 Option -q/--quiet hides untracked (unknown and ignored) files
6684 Option -q/--quiet hides untracked (unknown and ignored) files
6681 unless explicitly requested with -u/--unknown or -i/--ignored.
6685 unless explicitly requested with -u/--unknown or -i/--ignored.
6682
6686
6683 .. note::
6687 .. note::
6684
6688
6685 :hg:`status` may appear to disagree with diff if permissions have
6689 :hg:`status` may appear to disagree with diff if permissions have
6686 changed or a merge has occurred. The standard diff format does
6690 changed or a merge has occurred. The standard diff format does
6687 not report permission changes and diff only reports changes
6691 not report permission changes and diff only reports changes
6688 relative to one merge parent.
6692 relative to one merge parent.
6689
6693
6690 If one revision is given, it is used as the base revision.
6694 If one revision is given, it is used as the base revision.
6691 If two revisions are given, the differences between them are
6695 If two revisions are given, the differences between them are
6692 shown. The --change option can also be used as a shortcut to list
6696 shown. The --change option can also be used as a shortcut to list
6693 the changed files of a revision from its first parent.
6697 the changed files of a revision from its first parent.
6694
6698
6695 The codes used to show the status of files are::
6699 The codes used to show the status of files are::
6696
6700
6697 M = modified
6701 M = modified
6698 A = added
6702 A = added
6699 R = removed
6703 R = removed
6700 C = clean
6704 C = clean
6701 ! = missing (deleted by non-hg command, but still tracked)
6705 ! = missing (deleted by non-hg command, but still tracked)
6702 ? = not tracked
6706 ? = not tracked
6703 I = ignored
6707 I = ignored
6704 = origin of the previous file (with --copies)
6708 = origin of the previous file (with --copies)
6705
6709
6706 .. container:: verbose
6710 .. container:: verbose
6707
6711
6708 The -t/--terse option abbreviates the output by showing only the directory
6712 The -t/--terse option abbreviates the output by showing only the directory
6709 name if all the files in it share the same status. The option takes an
6713 name if all the files in it share the same status. The option takes an
6710 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6714 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6711 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6715 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6712 for 'ignored' and 'c' for clean.
6716 for 'ignored' and 'c' for clean.
6713
6717
6714 It abbreviates only those statuses which are passed. Note that clean and
6718 It abbreviates only those statuses which are passed. Note that clean and
6715 ignored files are not displayed with '--terse ic' unless the -c/--clean
6719 ignored files are not displayed with '--terse ic' unless the -c/--clean
6716 and -i/--ignored options are also used.
6720 and -i/--ignored options are also used.
6717
6721
6718 The -v/--verbose option shows information when the repository is in an
6722 The -v/--verbose option shows information when the repository is in an
6719 unfinished merge, shelve, rebase state etc. You can have this behavior
6723 unfinished merge, shelve, rebase state etc. You can have this behavior
6720 turned on by default by enabling the ``commands.status.verbose`` option.
6724 turned on by default by enabling the ``commands.status.verbose`` option.
6721
6725
6722 You can skip displaying some of these states by setting
6726 You can skip displaying some of these states by setting
6723 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6727 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6724 'histedit', 'merge', 'rebase', or 'unshelve'.
6728 'histedit', 'merge', 'rebase', or 'unshelve'.
6725
6729
6726 Template:
6730 Template:
6727
6731
6728 The following keywords are supported in addition to the common template
6732 The following keywords are supported in addition to the common template
6729 keywords and functions. See also :hg:`help templates`.
6733 keywords and functions. See also :hg:`help templates`.
6730
6734
6731 :path: String. Repository-absolute path of the file.
6735 :path: String. Repository-absolute path of the file.
6732 :source: String. Repository-absolute path of the file originated from.
6736 :source: String. Repository-absolute path of the file originated from.
6733 Available if ``--copies`` is specified.
6737 Available if ``--copies`` is specified.
6734 :status: String. Character denoting file's status.
6738 :status: String. Character denoting file's status.
6735
6739
6736 Examples:
6740 Examples:
6737
6741
6738 - show changes in the working directory relative to a
6742 - show changes in the working directory relative to a
6739 changeset::
6743 changeset::
6740
6744
6741 hg status --rev 9353
6745 hg status --rev 9353
6742
6746
6743 - show changes in the working directory relative to the
6747 - show changes in the working directory relative to the
6744 current directory (see :hg:`help patterns` for more information)::
6748 current directory (see :hg:`help patterns` for more information)::
6745
6749
6746 hg status re:
6750 hg status re:
6747
6751
6748 - show all changes including copies in an existing changeset::
6752 - show all changes including copies in an existing changeset::
6749
6753
6750 hg status --copies --change 9353
6754 hg status --copies --change 9353
6751
6755
6752 - get a NUL separated list of added files, suitable for xargs::
6756 - get a NUL separated list of added files, suitable for xargs::
6753
6757
6754 hg status -an0
6758 hg status -an0
6755
6759
6756 - show more information about the repository status, abbreviating
6760 - show more information about the repository status, abbreviating
6757 added, removed, modified, deleted, and untracked paths::
6761 added, removed, modified, deleted, and untracked paths::
6758
6762
6759 hg status -v -t mardu
6763 hg status -v -t mardu
6760
6764
6761 Returns 0 on success.
6765 Returns 0 on success.
6762
6766
6763 """
6767 """
6764
6768
6765 opts = pycompat.byteskwargs(opts)
6769 opts = pycompat.byteskwargs(opts)
6766 revs = opts.get(b'rev')
6770 revs = opts.get(b'rev')
6767 change = opts.get(b'change')
6771 change = opts.get(b'change')
6768 terse = opts.get(b'terse')
6772 terse = opts.get(b'terse')
6769 if terse is _NOTTERSE:
6773 if terse is _NOTTERSE:
6770 if revs:
6774 if revs:
6771 terse = b''
6775 terse = b''
6772 else:
6776 else:
6773 terse = ui.config(b'commands', b'status.terse')
6777 terse = ui.config(b'commands', b'status.terse')
6774
6778
6775 if revs and change:
6779 if revs and change:
6776 msg = _(b'cannot specify --rev and --change at the same time')
6780 msg = _(b'cannot specify --rev and --change at the same time')
6777 raise error.Abort(msg)
6781 raise error.Abort(msg)
6778 elif revs and terse:
6782 elif revs and terse:
6779 msg = _(b'cannot use --terse with --rev')
6783 msg = _(b'cannot use --terse with --rev')
6780 raise error.Abort(msg)
6784 raise error.Abort(msg)
6781 elif change:
6785 elif change:
6782 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6786 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6783 ctx2 = scmutil.revsingle(repo, change, None)
6787 ctx2 = scmutil.revsingle(repo, change, None)
6784 ctx1 = ctx2.p1()
6788 ctx1 = ctx2.p1()
6785 else:
6789 else:
6786 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6790 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6787 ctx1, ctx2 = scmutil.revpair(repo, revs)
6791 ctx1, ctx2 = scmutil.revpair(repo, revs)
6788
6792
6789 forcerelativevalue = None
6793 forcerelativevalue = None
6790 if ui.hasconfig(b'commands', b'status.relative'):
6794 if ui.hasconfig(b'commands', b'status.relative'):
6791 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6795 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6792 uipathfn = scmutil.getuipathfn(
6796 uipathfn = scmutil.getuipathfn(
6793 repo,
6797 repo,
6794 legacyrelativevalue=bool(pats),
6798 legacyrelativevalue=bool(pats),
6795 forcerelativevalue=forcerelativevalue,
6799 forcerelativevalue=forcerelativevalue,
6796 )
6800 )
6797
6801
6798 if opts.get(b'print0'):
6802 if opts.get(b'print0'):
6799 end = b'\0'
6803 end = b'\0'
6800 else:
6804 else:
6801 end = b'\n'
6805 end = b'\n'
6802 copy = {}
6806 copy = {}
6803 states = b'modified added removed deleted unknown ignored clean'.split()
6807 states = b'modified added removed deleted unknown ignored clean'.split()
6804 show = [k for k in states if opts.get(k)]
6808 show = [k for k in states if opts.get(k)]
6805 if opts.get(b'all'):
6809 if opts.get(b'all'):
6806 show += ui.quiet and (states[:4] + [b'clean']) or states
6810 show += ui.quiet and (states[:4] + [b'clean']) or states
6807
6811
6808 if not show:
6812 if not show:
6809 if ui.quiet:
6813 if ui.quiet:
6810 show = states[:4]
6814 show = states[:4]
6811 else:
6815 else:
6812 show = states[:5]
6816 show = states[:5]
6813
6817
6814 m = scmutil.match(ctx2, pats, opts)
6818 m = scmutil.match(ctx2, pats, opts)
6815 if terse:
6819 if terse:
6816 # we need to compute clean and unknown to terse
6820 # we need to compute clean and unknown to terse
6817 stat = repo.status(
6821 stat = repo.status(
6818 ctx1.node(),
6822 ctx1.node(),
6819 ctx2.node(),
6823 ctx2.node(),
6820 m,
6824 m,
6821 b'ignored' in show or b'i' in terse,
6825 b'ignored' in show or b'i' in terse,
6822 clean=True,
6826 clean=True,
6823 unknown=True,
6827 unknown=True,
6824 listsubrepos=opts.get(b'subrepos'),
6828 listsubrepos=opts.get(b'subrepos'),
6825 )
6829 )
6826
6830
6827 stat = cmdutil.tersedir(stat, terse)
6831 stat = cmdutil.tersedir(stat, terse)
6828 else:
6832 else:
6829 stat = repo.status(
6833 stat = repo.status(
6830 ctx1.node(),
6834 ctx1.node(),
6831 ctx2.node(),
6835 ctx2.node(),
6832 m,
6836 m,
6833 b'ignored' in show,
6837 b'ignored' in show,
6834 b'clean' in show,
6838 b'clean' in show,
6835 b'unknown' in show,
6839 b'unknown' in show,
6836 opts.get(b'subrepos'),
6840 opts.get(b'subrepos'),
6837 )
6841 )
6838
6842
6839 changestates = zip(states, pycompat.iterbytestr(b'MAR!?IC'), stat)
6843 changestates = zip(states, pycompat.iterbytestr(b'MAR!?IC'), stat)
6840
6844
6841 if (
6845 if (
6842 opts.get(b'all')
6846 opts.get(b'all')
6843 or opts.get(b'copies')
6847 or opts.get(b'copies')
6844 or ui.configbool(b'ui', b'statuscopies')
6848 or ui.configbool(b'ui', b'statuscopies')
6845 ) and not opts.get(b'no_status'):
6849 ) and not opts.get(b'no_status'):
6846 copy = copies.pathcopies(ctx1, ctx2, m)
6850 copy = copies.pathcopies(ctx1, ctx2, m)
6847
6851
6848 ui.pager(b'status')
6852 ui.pager(b'status')
6849 fm = ui.formatter(b'status', opts)
6853 fm = ui.formatter(b'status', opts)
6850 fmt = b'%s' + end
6854 fmt = b'%s' + end
6851 showchar = not opts.get(b'no_status')
6855 showchar = not opts.get(b'no_status')
6852
6856
6853 for state, char, files in changestates:
6857 for state, char, files in changestates:
6854 if state in show:
6858 if state in show:
6855 label = b'status.' + state
6859 label = b'status.' + state
6856 for f in files:
6860 for f in files:
6857 fm.startitem()
6861 fm.startitem()
6858 fm.context(ctx=ctx2)
6862 fm.context(ctx=ctx2)
6859 fm.data(path=f)
6863 fm.data(path=f)
6860 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6864 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6861 fm.plain(fmt % uipathfn(f), label=label)
6865 fm.plain(fmt % uipathfn(f), label=label)
6862 if f in copy:
6866 if f in copy:
6863 fm.data(source=copy[f])
6867 fm.data(source=copy[f])
6864 fm.plain(
6868 fm.plain(
6865 (b' %s' + end) % uipathfn(copy[f]),
6869 (b' %s' + end) % uipathfn(copy[f]),
6866 label=b'status.copied',
6870 label=b'status.copied',
6867 )
6871 )
6868
6872
6869 if (
6873 if (
6870 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6874 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6871 ) and not ui.plain():
6875 ) and not ui.plain():
6872 cmdutil.morestatus(repo, fm)
6876 cmdutil.morestatus(repo, fm)
6873 fm.end()
6877 fm.end()
6874
6878
6875
6879
6876 @command(
6880 @command(
6877 b'summary|sum',
6881 b'summary|sum',
6878 [(b'', b'remote', None, _(b'check for push and pull'))],
6882 [(b'', b'remote', None, _(b'check for push and pull'))],
6879 b'[--remote]',
6883 b'[--remote]',
6880 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6884 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6881 helpbasic=True,
6885 helpbasic=True,
6882 intents={INTENT_READONLY},
6886 intents={INTENT_READONLY},
6883 )
6887 )
6884 def summary(ui, repo, **opts):
6888 def summary(ui, repo, **opts):
6885 """summarize working directory state
6889 """summarize working directory state
6886
6890
6887 This generates a brief summary of the working directory state,
6891 This generates a brief summary of the working directory state,
6888 including parents, branch, commit status, phase and available updates.
6892 including parents, branch, commit status, phase and available updates.
6889
6893
6890 With the --remote option, this will check the default paths for
6894 With the --remote option, this will check the default paths for
6891 incoming and outgoing changes. This can be time-consuming.
6895 incoming and outgoing changes. This can be time-consuming.
6892
6896
6893 Returns 0 on success.
6897 Returns 0 on success.
6894 """
6898 """
6895
6899
6896 opts = pycompat.byteskwargs(opts)
6900 opts = pycompat.byteskwargs(opts)
6897 ui.pager(b'summary')
6901 ui.pager(b'summary')
6898 ctx = repo[None]
6902 ctx = repo[None]
6899 parents = ctx.parents()
6903 parents = ctx.parents()
6900 pnode = parents[0].node()
6904 pnode = parents[0].node()
6901 marks = []
6905 marks = []
6902
6906
6903 try:
6907 try:
6904 ms = mergemod.mergestate.read(repo)
6908 ms = mergemod.mergestate.read(repo)
6905 except error.UnsupportedMergeRecords as e:
6909 except error.UnsupportedMergeRecords as e:
6906 s = b' '.join(e.recordtypes)
6910 s = b' '.join(e.recordtypes)
6907 ui.warn(
6911 ui.warn(
6908 _(b'warning: merge state has unsupported record types: %s\n') % s
6912 _(b'warning: merge state has unsupported record types: %s\n') % s
6909 )
6913 )
6910 unresolved = []
6914 unresolved = []
6911 else:
6915 else:
6912 unresolved = list(ms.unresolved())
6916 unresolved = list(ms.unresolved())
6913
6917
6914 for p in parents:
6918 for p in parents:
6915 # label with log.changeset (instead of log.parent) since this
6919 # label with log.changeset (instead of log.parent) since this
6916 # shows a working directory parent *changeset*:
6920 # shows a working directory parent *changeset*:
6917 # i18n: column positioning for "hg summary"
6921 # i18n: column positioning for "hg summary"
6918 ui.write(
6922 ui.write(
6919 _(b'parent: %d:%s ') % (p.rev(), p),
6923 _(b'parent: %d:%s ') % (p.rev(), p),
6920 label=logcmdutil.changesetlabels(p),
6924 label=logcmdutil.changesetlabels(p),
6921 )
6925 )
6922 ui.write(b' '.join(p.tags()), label=b'log.tag')
6926 ui.write(b' '.join(p.tags()), label=b'log.tag')
6923 if p.bookmarks():
6927 if p.bookmarks():
6924 marks.extend(p.bookmarks())
6928 marks.extend(p.bookmarks())
6925 if p.rev() == -1:
6929 if p.rev() == -1:
6926 if not len(repo):
6930 if not len(repo):
6927 ui.write(_(b' (empty repository)'))
6931 ui.write(_(b' (empty repository)'))
6928 else:
6932 else:
6929 ui.write(_(b' (no revision checked out)'))
6933 ui.write(_(b' (no revision checked out)'))
6930 if p.obsolete():
6934 if p.obsolete():
6931 ui.write(_(b' (obsolete)'))
6935 ui.write(_(b' (obsolete)'))
6932 if p.isunstable():
6936 if p.isunstable():
6933 instabilities = (
6937 instabilities = (
6934 ui.label(instability, b'trouble.%s' % instability)
6938 ui.label(instability, b'trouble.%s' % instability)
6935 for instability in p.instabilities()
6939 for instability in p.instabilities()
6936 )
6940 )
6937 ui.write(b' (' + b', '.join(instabilities) + b')')
6941 ui.write(b' (' + b', '.join(instabilities) + b')')
6938 ui.write(b'\n')
6942 ui.write(b'\n')
6939 if p.description():
6943 if p.description():
6940 ui.status(
6944 ui.status(
6941 b' ' + p.description().splitlines()[0].strip() + b'\n',
6945 b' ' + p.description().splitlines()[0].strip() + b'\n',
6942 label=b'log.summary',
6946 label=b'log.summary',
6943 )
6947 )
6944
6948
6945 branch = ctx.branch()
6949 branch = ctx.branch()
6946 bheads = repo.branchheads(branch)
6950 bheads = repo.branchheads(branch)
6947 # i18n: column positioning for "hg summary"
6951 # i18n: column positioning for "hg summary"
6948 m = _(b'branch: %s\n') % branch
6952 m = _(b'branch: %s\n') % branch
6949 if branch != b'default':
6953 if branch != b'default':
6950 ui.write(m, label=b'log.branch')
6954 ui.write(m, label=b'log.branch')
6951 else:
6955 else:
6952 ui.status(m, label=b'log.branch')
6956 ui.status(m, label=b'log.branch')
6953
6957
6954 if marks:
6958 if marks:
6955 active = repo._activebookmark
6959 active = repo._activebookmark
6956 # i18n: column positioning for "hg summary"
6960 # i18n: column positioning for "hg summary"
6957 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6961 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6958 if active is not None:
6962 if active is not None:
6959 if active in marks:
6963 if active in marks:
6960 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6964 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6961 marks.remove(active)
6965 marks.remove(active)
6962 else:
6966 else:
6963 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6967 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6964 for m in marks:
6968 for m in marks:
6965 ui.write(b' ' + m, label=b'log.bookmark')
6969 ui.write(b' ' + m, label=b'log.bookmark')
6966 ui.write(b'\n', label=b'log.bookmark')
6970 ui.write(b'\n', label=b'log.bookmark')
6967
6971
6968 status = repo.status(unknown=True)
6972 status = repo.status(unknown=True)
6969
6973
6970 c = repo.dirstate.copies()
6974 c = repo.dirstate.copies()
6971 copied, renamed = [], []
6975 copied, renamed = [], []
6972 for d, s in pycompat.iteritems(c):
6976 for d, s in pycompat.iteritems(c):
6973 if s in status.removed:
6977 if s in status.removed:
6974 status.removed.remove(s)
6978 status.removed.remove(s)
6975 renamed.append(d)
6979 renamed.append(d)
6976 else:
6980 else:
6977 copied.append(d)
6981 copied.append(d)
6978 if d in status.added:
6982 if d in status.added:
6979 status.added.remove(d)
6983 status.added.remove(d)
6980
6984
6981 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6985 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6982
6986
6983 labels = [
6987 labels = [
6984 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6988 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6985 (ui.label(_(b'%d added'), b'status.added'), status.added),
6989 (ui.label(_(b'%d added'), b'status.added'), status.added),
6986 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6990 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6987 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6991 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6988 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6992 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6989 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6993 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6990 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6994 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6991 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6995 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6992 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6996 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6993 ]
6997 ]
6994 t = []
6998 t = []
6995 for l, s in labels:
6999 for l, s in labels:
6996 if s:
7000 if s:
6997 t.append(l % len(s))
7001 t.append(l % len(s))
6998
7002
6999 t = b', '.join(t)
7003 t = b', '.join(t)
7000 cleanworkdir = False
7004 cleanworkdir = False
7001
7005
7002 if repo.vfs.exists(b'graftstate'):
7006 if repo.vfs.exists(b'graftstate'):
7003 t += _(b' (graft in progress)')
7007 t += _(b' (graft in progress)')
7004 if repo.vfs.exists(b'updatestate'):
7008 if repo.vfs.exists(b'updatestate'):
7005 t += _(b' (interrupted update)')
7009 t += _(b' (interrupted update)')
7006 elif len(parents) > 1:
7010 elif len(parents) > 1:
7007 t += _(b' (merge)')
7011 t += _(b' (merge)')
7008 elif branch != parents[0].branch():
7012 elif branch != parents[0].branch():
7009 t += _(b' (new branch)')
7013 t += _(b' (new branch)')
7010 elif parents[0].closesbranch() and pnode in repo.branchheads(
7014 elif parents[0].closesbranch() and pnode in repo.branchheads(
7011 branch, closed=True
7015 branch, closed=True
7012 ):
7016 ):
7013 t += _(b' (head closed)')
7017 t += _(b' (head closed)')
7014 elif not (
7018 elif not (
7015 status.modified
7019 status.modified
7016 or status.added
7020 or status.added
7017 or status.removed
7021 or status.removed
7018 or renamed
7022 or renamed
7019 or copied
7023 or copied
7020 or subs
7024 or subs
7021 ):
7025 ):
7022 t += _(b' (clean)')
7026 t += _(b' (clean)')
7023 cleanworkdir = True
7027 cleanworkdir = True
7024 elif pnode not in bheads:
7028 elif pnode not in bheads:
7025 t += _(b' (new branch head)')
7029 t += _(b' (new branch head)')
7026
7030
7027 if parents:
7031 if parents:
7028 pendingphase = max(p.phase() for p in parents)
7032 pendingphase = max(p.phase() for p in parents)
7029 else:
7033 else:
7030 pendingphase = phases.public
7034 pendingphase = phases.public
7031
7035
7032 if pendingphase > phases.newcommitphase(ui):
7036 if pendingphase > phases.newcommitphase(ui):
7033 t += b' (%s)' % phases.phasenames[pendingphase]
7037 t += b' (%s)' % phases.phasenames[pendingphase]
7034
7038
7035 if cleanworkdir:
7039 if cleanworkdir:
7036 # i18n: column positioning for "hg summary"
7040 # i18n: column positioning for "hg summary"
7037 ui.status(_(b'commit: %s\n') % t.strip())
7041 ui.status(_(b'commit: %s\n') % t.strip())
7038 else:
7042 else:
7039 # i18n: column positioning for "hg summary"
7043 # i18n: column positioning for "hg summary"
7040 ui.write(_(b'commit: %s\n') % t.strip())
7044 ui.write(_(b'commit: %s\n') % t.strip())
7041
7045
7042 # all ancestors of branch heads - all ancestors of parent = new csets
7046 # all ancestors of branch heads - all ancestors of parent = new csets
7043 new = len(
7047 new = len(
7044 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7048 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7045 )
7049 )
7046
7050
7047 if new == 0:
7051 if new == 0:
7048 # i18n: column positioning for "hg summary"
7052 # i18n: column positioning for "hg summary"
7049 ui.status(_(b'update: (current)\n'))
7053 ui.status(_(b'update: (current)\n'))
7050 elif pnode not in bheads:
7054 elif pnode not in bheads:
7051 # i18n: column positioning for "hg summary"
7055 # i18n: column positioning for "hg summary"
7052 ui.write(_(b'update: %d new changesets (update)\n') % new)
7056 ui.write(_(b'update: %d new changesets (update)\n') % new)
7053 else:
7057 else:
7054 # i18n: column positioning for "hg summary"
7058 # i18n: column positioning for "hg summary"
7055 ui.write(
7059 ui.write(
7056 _(b'update: %d new changesets, %d branch heads (merge)\n')
7060 _(b'update: %d new changesets, %d branch heads (merge)\n')
7057 % (new, len(bheads))
7061 % (new, len(bheads))
7058 )
7062 )
7059
7063
7060 t = []
7064 t = []
7061 draft = len(repo.revs(b'draft()'))
7065 draft = len(repo.revs(b'draft()'))
7062 if draft:
7066 if draft:
7063 t.append(_(b'%d draft') % draft)
7067 t.append(_(b'%d draft') % draft)
7064 secret = len(repo.revs(b'secret()'))
7068 secret = len(repo.revs(b'secret()'))
7065 if secret:
7069 if secret:
7066 t.append(_(b'%d secret') % secret)
7070 t.append(_(b'%d secret') % secret)
7067
7071
7068 if draft or secret:
7072 if draft or secret:
7069 ui.status(_(b'phases: %s\n') % b', '.join(t))
7073 ui.status(_(b'phases: %s\n') % b', '.join(t))
7070
7074
7071 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7075 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7072 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7076 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7073 numtrouble = len(repo.revs(trouble + b"()"))
7077 numtrouble = len(repo.revs(trouble + b"()"))
7074 # We write all the possibilities to ease translation
7078 # We write all the possibilities to ease translation
7075 troublemsg = {
7079 troublemsg = {
7076 b"orphan": _(b"orphan: %d changesets"),
7080 b"orphan": _(b"orphan: %d changesets"),
7077 b"contentdivergent": _(b"content-divergent: %d changesets"),
7081 b"contentdivergent": _(b"content-divergent: %d changesets"),
7078 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7082 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7079 }
7083 }
7080 if numtrouble > 0:
7084 if numtrouble > 0:
7081 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7085 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7082
7086
7083 cmdutil.summaryhooks(ui, repo)
7087 cmdutil.summaryhooks(ui, repo)
7084
7088
7085 if opts.get(b'remote'):
7089 if opts.get(b'remote'):
7086 needsincoming, needsoutgoing = True, True
7090 needsincoming, needsoutgoing = True, True
7087 else:
7091 else:
7088 needsincoming, needsoutgoing = False, False
7092 needsincoming, needsoutgoing = False, False
7089 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7093 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7090 if i:
7094 if i:
7091 needsincoming = True
7095 needsincoming = True
7092 if o:
7096 if o:
7093 needsoutgoing = True
7097 needsoutgoing = True
7094 if not needsincoming and not needsoutgoing:
7098 if not needsincoming and not needsoutgoing:
7095 return
7099 return
7096
7100
7097 def getincoming():
7101 def getincoming():
7098 source, branches = hg.parseurl(ui.expandpath(b'default'))
7102 source, branches = hg.parseurl(ui.expandpath(b'default'))
7099 sbranch = branches[0]
7103 sbranch = branches[0]
7100 try:
7104 try:
7101 other = hg.peer(repo, {}, source)
7105 other = hg.peer(repo, {}, source)
7102 except error.RepoError:
7106 except error.RepoError:
7103 if opts.get(b'remote'):
7107 if opts.get(b'remote'):
7104 raise
7108 raise
7105 return source, sbranch, None, None, None
7109 return source, sbranch, None, None, None
7106 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7110 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7107 if revs:
7111 if revs:
7108 revs = [other.lookup(rev) for rev in revs]
7112 revs = [other.lookup(rev) for rev in revs]
7109 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7113 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7110 repo.ui.pushbuffer()
7114 repo.ui.pushbuffer()
7111 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7115 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7112 repo.ui.popbuffer()
7116 repo.ui.popbuffer()
7113 return source, sbranch, other, commoninc, commoninc[1]
7117 return source, sbranch, other, commoninc, commoninc[1]
7114
7118
7115 if needsincoming:
7119 if needsincoming:
7116 source, sbranch, sother, commoninc, incoming = getincoming()
7120 source, sbranch, sother, commoninc, incoming = getincoming()
7117 else:
7121 else:
7118 source = sbranch = sother = commoninc = incoming = None
7122 source = sbranch = sother = commoninc = incoming = None
7119
7123
7120 def getoutgoing():
7124 def getoutgoing():
7121 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7125 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7122 dbranch = branches[0]
7126 dbranch = branches[0]
7123 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7127 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7124 if source != dest:
7128 if source != dest:
7125 try:
7129 try:
7126 dother = hg.peer(repo, {}, dest)
7130 dother = hg.peer(repo, {}, dest)
7127 except error.RepoError:
7131 except error.RepoError:
7128 if opts.get(b'remote'):
7132 if opts.get(b'remote'):
7129 raise
7133 raise
7130 return dest, dbranch, None, None
7134 return dest, dbranch, None, None
7131 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7135 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7132 elif sother is None:
7136 elif sother is None:
7133 # there is no explicit destination peer, but source one is invalid
7137 # there is no explicit destination peer, but source one is invalid
7134 return dest, dbranch, None, None
7138 return dest, dbranch, None, None
7135 else:
7139 else:
7136 dother = sother
7140 dother = sother
7137 if source != dest or (sbranch is not None and sbranch != dbranch):
7141 if source != dest or (sbranch is not None and sbranch != dbranch):
7138 common = None
7142 common = None
7139 else:
7143 else:
7140 common = commoninc
7144 common = commoninc
7141 if revs:
7145 if revs:
7142 revs = [repo.lookup(rev) for rev in revs]
7146 revs = [repo.lookup(rev) for rev in revs]
7143 repo.ui.pushbuffer()
7147 repo.ui.pushbuffer()
7144 outgoing = discovery.findcommonoutgoing(
7148 outgoing = discovery.findcommonoutgoing(
7145 repo, dother, onlyheads=revs, commoninc=common
7149 repo, dother, onlyheads=revs, commoninc=common
7146 )
7150 )
7147 repo.ui.popbuffer()
7151 repo.ui.popbuffer()
7148 return dest, dbranch, dother, outgoing
7152 return dest, dbranch, dother, outgoing
7149
7153
7150 if needsoutgoing:
7154 if needsoutgoing:
7151 dest, dbranch, dother, outgoing = getoutgoing()
7155 dest, dbranch, dother, outgoing = getoutgoing()
7152 else:
7156 else:
7153 dest = dbranch = dother = outgoing = None
7157 dest = dbranch = dother = outgoing = None
7154
7158
7155 if opts.get(b'remote'):
7159 if opts.get(b'remote'):
7156 t = []
7160 t = []
7157 if incoming:
7161 if incoming:
7158 t.append(_(b'1 or more incoming'))
7162 t.append(_(b'1 or more incoming'))
7159 o = outgoing.missing
7163 o = outgoing.missing
7160 if o:
7164 if o:
7161 t.append(_(b'%d outgoing') % len(o))
7165 t.append(_(b'%d outgoing') % len(o))
7162 other = dother or sother
7166 other = dother or sother
7163 if b'bookmarks' in other.listkeys(b'namespaces'):
7167 if b'bookmarks' in other.listkeys(b'namespaces'):
7164 counts = bookmarks.summary(repo, other)
7168 counts = bookmarks.summary(repo, other)
7165 if counts[0] > 0:
7169 if counts[0] > 0:
7166 t.append(_(b'%d incoming bookmarks') % counts[0])
7170 t.append(_(b'%d incoming bookmarks') % counts[0])
7167 if counts[1] > 0:
7171 if counts[1] > 0:
7168 t.append(_(b'%d outgoing bookmarks') % counts[1])
7172 t.append(_(b'%d outgoing bookmarks') % counts[1])
7169
7173
7170 if t:
7174 if t:
7171 # i18n: column positioning for "hg summary"
7175 # i18n: column positioning for "hg summary"
7172 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7176 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7173 else:
7177 else:
7174 # i18n: column positioning for "hg summary"
7178 # i18n: column positioning for "hg summary"
7175 ui.status(_(b'remote: (synced)\n'))
7179 ui.status(_(b'remote: (synced)\n'))
7176
7180
7177 cmdutil.summaryremotehooks(
7181 cmdutil.summaryremotehooks(
7178 ui,
7182 ui,
7179 repo,
7183 repo,
7180 opts,
7184 opts,
7181 (
7185 (
7182 (source, sbranch, sother, commoninc),
7186 (source, sbranch, sother, commoninc),
7183 (dest, dbranch, dother, outgoing),
7187 (dest, dbranch, dother, outgoing),
7184 ),
7188 ),
7185 )
7189 )
7186
7190
7187
7191
7188 @command(
7192 @command(
7189 b'tag',
7193 b'tag',
7190 [
7194 [
7191 (b'f', b'force', None, _(b'force tag')),
7195 (b'f', b'force', None, _(b'force tag')),
7192 (b'l', b'local', None, _(b'make the tag local')),
7196 (b'l', b'local', None, _(b'make the tag local')),
7193 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7197 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7194 (b'', b'remove', None, _(b'remove a tag')),
7198 (b'', b'remove', None, _(b'remove a tag')),
7195 # -l/--local is already there, commitopts cannot be used
7199 # -l/--local is already there, commitopts cannot be used
7196 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7200 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7197 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7201 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7198 ]
7202 ]
7199 + commitopts2,
7203 + commitopts2,
7200 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7204 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7201 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7205 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7202 )
7206 )
7203 def tag(ui, repo, name1, *names, **opts):
7207 def tag(ui, repo, name1, *names, **opts):
7204 """add one or more tags for the current or given revision
7208 """add one or more tags for the current or given revision
7205
7209
7206 Name a particular revision using <name>.
7210 Name a particular revision using <name>.
7207
7211
7208 Tags are used to name particular revisions of the repository and are
7212 Tags are used to name particular revisions of the repository and are
7209 very useful to compare different revisions, to go back to significant
7213 very useful to compare different revisions, to go back to significant
7210 earlier versions or to mark branch points as releases, etc. Changing
7214 earlier versions or to mark branch points as releases, etc. Changing
7211 an existing tag is normally disallowed; use -f/--force to override.
7215 an existing tag is normally disallowed; use -f/--force to override.
7212
7216
7213 If no revision is given, the parent of the working directory is
7217 If no revision is given, the parent of the working directory is
7214 used.
7218 used.
7215
7219
7216 To facilitate version control, distribution, and merging of tags,
7220 To facilitate version control, distribution, and merging of tags,
7217 they are stored as a file named ".hgtags" which is managed similarly
7221 they are stored as a file named ".hgtags" which is managed similarly
7218 to other project files and can be hand-edited if necessary. This
7222 to other project files and can be hand-edited if necessary. This
7219 also means that tagging creates a new commit. The file
7223 also means that tagging creates a new commit. The file
7220 ".hg/localtags" is used for local tags (not shared among
7224 ".hg/localtags" is used for local tags (not shared among
7221 repositories).
7225 repositories).
7222
7226
7223 Tag commits are usually made at the head of a branch. If the parent
7227 Tag commits are usually made at the head of a branch. If the parent
7224 of the working directory is not a branch head, :hg:`tag` aborts; use
7228 of the working directory is not a branch head, :hg:`tag` aborts; use
7225 -f/--force to force the tag commit to be based on a non-head
7229 -f/--force to force the tag commit to be based on a non-head
7226 changeset.
7230 changeset.
7227
7231
7228 See :hg:`help dates` for a list of formats valid for -d/--date.
7232 See :hg:`help dates` for a list of formats valid for -d/--date.
7229
7233
7230 Since tag names have priority over branch names during revision
7234 Since tag names have priority over branch names during revision
7231 lookup, using an existing branch name as a tag name is discouraged.
7235 lookup, using an existing branch name as a tag name is discouraged.
7232
7236
7233 Returns 0 on success.
7237 Returns 0 on success.
7234 """
7238 """
7235 opts = pycompat.byteskwargs(opts)
7239 opts = pycompat.byteskwargs(opts)
7236 with repo.wlock(), repo.lock():
7240 with repo.wlock(), repo.lock():
7237 rev_ = b"."
7241 rev_ = b"."
7238 names = [t.strip() for t in (name1,) + names]
7242 names = [t.strip() for t in (name1,) + names]
7239 if len(names) != len(set(names)):
7243 if len(names) != len(set(names)):
7240 raise error.Abort(_(b'tag names must be unique'))
7244 raise error.Abort(_(b'tag names must be unique'))
7241 for n in names:
7245 for n in names:
7242 scmutil.checknewlabel(repo, n, b'tag')
7246 scmutil.checknewlabel(repo, n, b'tag')
7243 if not n:
7247 if not n:
7244 raise error.Abort(
7248 raise error.Abort(
7245 _(b'tag names cannot consist entirely of whitespace')
7249 _(b'tag names cannot consist entirely of whitespace')
7246 )
7250 )
7247 if opts.get(b'rev') and opts.get(b'remove'):
7251 if opts.get(b'rev') and opts.get(b'remove'):
7248 raise error.Abort(_(b"--rev and --remove are incompatible"))
7252 raise error.Abort(_(b"--rev and --remove are incompatible"))
7249 if opts.get(b'rev'):
7253 if opts.get(b'rev'):
7250 rev_ = opts[b'rev']
7254 rev_ = opts[b'rev']
7251 message = opts.get(b'message')
7255 message = opts.get(b'message')
7252 if opts.get(b'remove'):
7256 if opts.get(b'remove'):
7253 if opts.get(b'local'):
7257 if opts.get(b'local'):
7254 expectedtype = b'local'
7258 expectedtype = b'local'
7255 else:
7259 else:
7256 expectedtype = b'global'
7260 expectedtype = b'global'
7257
7261
7258 for n in names:
7262 for n in names:
7259 if repo.tagtype(n) == b'global':
7263 if repo.tagtype(n) == b'global':
7260 alltags = tagsmod.findglobaltags(ui, repo)
7264 alltags = tagsmod.findglobaltags(ui, repo)
7261 if alltags[n][0] == nullid:
7265 if alltags[n][0] == nullid:
7262 raise error.Abort(_(b"tag '%s' is already removed") % n)
7266 raise error.Abort(_(b"tag '%s' is already removed") % n)
7263 if not repo.tagtype(n):
7267 if not repo.tagtype(n):
7264 raise error.Abort(_(b"tag '%s' does not exist") % n)
7268 raise error.Abort(_(b"tag '%s' does not exist") % n)
7265 if repo.tagtype(n) != expectedtype:
7269 if repo.tagtype(n) != expectedtype:
7266 if expectedtype == b'global':
7270 if expectedtype == b'global':
7267 raise error.Abort(
7271 raise error.Abort(
7268 _(b"tag '%s' is not a global tag") % n
7272 _(b"tag '%s' is not a global tag") % n
7269 )
7273 )
7270 else:
7274 else:
7271 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7275 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7272 rev_ = b'null'
7276 rev_ = b'null'
7273 if not message:
7277 if not message:
7274 # we don't translate commit messages
7278 # we don't translate commit messages
7275 message = b'Removed tag %s' % b', '.join(names)
7279 message = b'Removed tag %s' % b', '.join(names)
7276 elif not opts.get(b'force'):
7280 elif not opts.get(b'force'):
7277 for n in names:
7281 for n in names:
7278 if n in repo.tags():
7282 if n in repo.tags():
7279 raise error.Abort(
7283 raise error.Abort(
7280 _(b"tag '%s' already exists (use -f to force)") % n
7284 _(b"tag '%s' already exists (use -f to force)") % n
7281 )
7285 )
7282 if not opts.get(b'local'):
7286 if not opts.get(b'local'):
7283 p1, p2 = repo.dirstate.parents()
7287 p1, p2 = repo.dirstate.parents()
7284 if p2 != nullid:
7288 if p2 != nullid:
7285 raise error.Abort(_(b'uncommitted merge'))
7289 raise error.Abort(_(b'uncommitted merge'))
7286 bheads = repo.branchheads()
7290 bheads = repo.branchheads()
7287 if not opts.get(b'force') and bheads and p1 not in bheads:
7291 if not opts.get(b'force') and bheads and p1 not in bheads:
7288 raise error.Abort(
7292 raise error.Abort(
7289 _(
7293 _(
7290 b'working directory is not at a branch head '
7294 b'working directory is not at a branch head '
7291 b'(use -f to force)'
7295 b'(use -f to force)'
7292 )
7296 )
7293 )
7297 )
7294 node = scmutil.revsingle(repo, rev_).node()
7298 node = scmutil.revsingle(repo, rev_).node()
7295
7299
7296 if not message:
7300 if not message:
7297 # we don't translate commit messages
7301 # we don't translate commit messages
7298 message = b'Added tag %s for changeset %s' % (
7302 message = b'Added tag %s for changeset %s' % (
7299 b', '.join(names),
7303 b', '.join(names),
7300 short(node),
7304 short(node),
7301 )
7305 )
7302
7306
7303 date = opts.get(b'date')
7307 date = opts.get(b'date')
7304 if date:
7308 if date:
7305 date = dateutil.parsedate(date)
7309 date = dateutil.parsedate(date)
7306
7310
7307 if opts.get(b'remove'):
7311 if opts.get(b'remove'):
7308 editform = b'tag.remove'
7312 editform = b'tag.remove'
7309 else:
7313 else:
7310 editform = b'tag.add'
7314 editform = b'tag.add'
7311 editor = cmdutil.getcommiteditor(
7315 editor = cmdutil.getcommiteditor(
7312 editform=editform, **pycompat.strkwargs(opts)
7316 editform=editform, **pycompat.strkwargs(opts)
7313 )
7317 )
7314
7318
7315 # don't allow tagging the null rev
7319 # don't allow tagging the null rev
7316 if (
7320 if (
7317 not opts.get(b'remove')
7321 not opts.get(b'remove')
7318 and scmutil.revsingle(repo, rev_).rev() == nullrev
7322 and scmutil.revsingle(repo, rev_).rev() == nullrev
7319 ):
7323 ):
7320 raise error.Abort(_(b"cannot tag null revision"))
7324 raise error.Abort(_(b"cannot tag null revision"))
7321
7325
7322 tagsmod.tag(
7326 tagsmod.tag(
7323 repo,
7327 repo,
7324 names,
7328 names,
7325 node,
7329 node,
7326 message,
7330 message,
7327 opts.get(b'local'),
7331 opts.get(b'local'),
7328 opts.get(b'user'),
7332 opts.get(b'user'),
7329 date,
7333 date,
7330 editor=editor,
7334 editor=editor,
7331 )
7335 )
7332
7336
7333
7337
7334 @command(
7338 @command(
7335 b'tags',
7339 b'tags',
7336 formatteropts,
7340 formatteropts,
7337 b'',
7341 b'',
7338 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7342 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7339 intents={INTENT_READONLY},
7343 intents={INTENT_READONLY},
7340 )
7344 )
7341 def tags(ui, repo, **opts):
7345 def tags(ui, repo, **opts):
7342 """list repository tags
7346 """list repository tags
7343
7347
7344 This lists both regular and local tags. When the -v/--verbose
7348 This lists both regular and local tags. When the -v/--verbose
7345 switch is used, a third column "local" is printed for local tags.
7349 switch is used, a third column "local" is printed for local tags.
7346 When the -q/--quiet switch is used, only the tag name is printed.
7350 When the -q/--quiet switch is used, only the tag name is printed.
7347
7351
7348 .. container:: verbose
7352 .. container:: verbose
7349
7353
7350 Template:
7354 Template:
7351
7355
7352 The following keywords are supported in addition to the common template
7356 The following keywords are supported in addition to the common template
7353 keywords and functions such as ``{tag}``. See also
7357 keywords and functions such as ``{tag}``. See also
7354 :hg:`help templates`.
7358 :hg:`help templates`.
7355
7359
7356 :type: String. ``local`` for local tags.
7360 :type: String. ``local`` for local tags.
7357
7361
7358 Returns 0 on success.
7362 Returns 0 on success.
7359 """
7363 """
7360
7364
7361 opts = pycompat.byteskwargs(opts)
7365 opts = pycompat.byteskwargs(opts)
7362 ui.pager(b'tags')
7366 ui.pager(b'tags')
7363 fm = ui.formatter(b'tags', opts)
7367 fm = ui.formatter(b'tags', opts)
7364 hexfunc = fm.hexfunc
7368 hexfunc = fm.hexfunc
7365
7369
7366 for t, n in reversed(repo.tagslist()):
7370 for t, n in reversed(repo.tagslist()):
7367 hn = hexfunc(n)
7371 hn = hexfunc(n)
7368 label = b'tags.normal'
7372 label = b'tags.normal'
7369 tagtype = b''
7373 tagtype = b''
7370 if repo.tagtype(t) == b'local':
7374 if repo.tagtype(t) == b'local':
7371 label = b'tags.local'
7375 label = b'tags.local'
7372 tagtype = b'local'
7376 tagtype = b'local'
7373
7377
7374 fm.startitem()
7378 fm.startitem()
7375 fm.context(repo=repo)
7379 fm.context(repo=repo)
7376 fm.write(b'tag', b'%s', t, label=label)
7380 fm.write(b'tag', b'%s', t, label=label)
7377 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7381 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7378 fm.condwrite(
7382 fm.condwrite(
7379 not ui.quiet,
7383 not ui.quiet,
7380 b'rev node',
7384 b'rev node',
7381 fmt,
7385 fmt,
7382 repo.changelog.rev(n),
7386 repo.changelog.rev(n),
7383 hn,
7387 hn,
7384 label=label,
7388 label=label,
7385 )
7389 )
7386 fm.condwrite(
7390 fm.condwrite(
7387 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7391 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7388 )
7392 )
7389 fm.plain(b'\n')
7393 fm.plain(b'\n')
7390 fm.end()
7394 fm.end()
7391
7395
7392
7396
7393 @command(
7397 @command(
7394 b'tip',
7398 b'tip',
7395 [
7399 [
7396 (b'p', b'patch', None, _(b'show patch')),
7400 (b'p', b'patch', None, _(b'show patch')),
7397 (b'g', b'git', None, _(b'use git extended diff format')),
7401 (b'g', b'git', None, _(b'use git extended diff format')),
7398 ]
7402 ]
7399 + templateopts,
7403 + templateopts,
7400 _(b'[-p] [-g]'),
7404 _(b'[-p] [-g]'),
7401 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7405 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7402 )
7406 )
7403 def tip(ui, repo, **opts):
7407 def tip(ui, repo, **opts):
7404 """show the tip revision (DEPRECATED)
7408 """show the tip revision (DEPRECATED)
7405
7409
7406 The tip revision (usually just called the tip) is the changeset
7410 The tip revision (usually just called the tip) is the changeset
7407 most recently added to the repository (and therefore the most
7411 most recently added to the repository (and therefore the most
7408 recently changed head).
7412 recently changed head).
7409
7413
7410 If you have just made a commit, that commit will be the tip. If
7414 If you have just made a commit, that commit will be the tip. If
7411 you have just pulled changes from another repository, the tip of
7415 you have just pulled changes from another repository, the tip of
7412 that repository becomes the current tip. The "tip" tag is special
7416 that repository becomes the current tip. The "tip" tag is special
7413 and cannot be renamed or assigned to a different changeset.
7417 and cannot be renamed or assigned to a different changeset.
7414
7418
7415 This command is deprecated, please use :hg:`heads` instead.
7419 This command is deprecated, please use :hg:`heads` instead.
7416
7420
7417 Returns 0 on success.
7421 Returns 0 on success.
7418 """
7422 """
7419 opts = pycompat.byteskwargs(opts)
7423 opts = pycompat.byteskwargs(opts)
7420 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7424 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7421 displayer.show(repo[b'tip'])
7425 displayer.show(repo[b'tip'])
7422 displayer.close()
7426 displayer.close()
7423
7427
7424
7428
7425 @command(
7429 @command(
7426 b'unbundle',
7430 b'unbundle',
7427 [
7431 [
7428 (
7432 (
7429 b'u',
7433 b'u',
7430 b'update',
7434 b'update',
7431 None,
7435 None,
7432 _(b'update to new branch head if changesets were unbundled'),
7436 _(b'update to new branch head if changesets were unbundled'),
7433 )
7437 )
7434 ],
7438 ],
7435 _(b'[-u] FILE...'),
7439 _(b'[-u] FILE...'),
7436 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7440 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7437 )
7441 )
7438 def unbundle(ui, repo, fname1, *fnames, **opts):
7442 def unbundle(ui, repo, fname1, *fnames, **opts):
7439 """apply one or more bundle files
7443 """apply one or more bundle files
7440
7444
7441 Apply one or more bundle files generated by :hg:`bundle`.
7445 Apply one or more bundle files generated by :hg:`bundle`.
7442
7446
7443 Returns 0 on success, 1 if an update has unresolved files.
7447 Returns 0 on success, 1 if an update has unresolved files.
7444 """
7448 """
7445 fnames = (fname1,) + fnames
7449 fnames = (fname1,) + fnames
7446
7450
7447 with repo.lock():
7451 with repo.lock():
7448 for fname in fnames:
7452 for fname in fnames:
7449 f = hg.openpath(ui, fname)
7453 f = hg.openpath(ui, fname)
7450 gen = exchange.readbundle(ui, f, fname)
7454 gen = exchange.readbundle(ui, f, fname)
7451 if isinstance(gen, streamclone.streamcloneapplier):
7455 if isinstance(gen, streamclone.streamcloneapplier):
7452 raise error.Abort(
7456 raise error.Abort(
7453 _(
7457 _(
7454 b'packed bundles cannot be applied with '
7458 b'packed bundles cannot be applied with '
7455 b'"hg unbundle"'
7459 b'"hg unbundle"'
7456 ),
7460 ),
7457 hint=_(b'use "hg debugapplystreamclonebundle"'),
7461 hint=_(b'use "hg debugapplystreamclonebundle"'),
7458 )
7462 )
7459 url = b'bundle:' + fname
7463 url = b'bundle:' + fname
7460 try:
7464 try:
7461 txnname = b'unbundle'
7465 txnname = b'unbundle'
7462 if not isinstance(gen, bundle2.unbundle20):
7466 if not isinstance(gen, bundle2.unbundle20):
7463 txnname = b'unbundle\n%s' % util.hidepassword(url)
7467 txnname = b'unbundle\n%s' % util.hidepassword(url)
7464 with repo.transaction(txnname) as tr:
7468 with repo.transaction(txnname) as tr:
7465 op = bundle2.applybundle(
7469 op = bundle2.applybundle(
7466 repo, gen, tr, source=b'unbundle', url=url
7470 repo, gen, tr, source=b'unbundle', url=url
7467 )
7471 )
7468 except error.BundleUnknownFeatureError as exc:
7472 except error.BundleUnknownFeatureError as exc:
7469 raise error.Abort(
7473 raise error.Abort(
7470 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7474 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7471 hint=_(
7475 hint=_(
7472 b"see https://mercurial-scm.org/"
7476 b"see https://mercurial-scm.org/"
7473 b"wiki/BundleFeature for more "
7477 b"wiki/BundleFeature for more "
7474 b"information"
7478 b"information"
7475 ),
7479 ),
7476 )
7480 )
7477 modheads = bundle2.combinechangegroupresults(op)
7481 modheads = bundle2.combinechangegroupresults(op)
7478
7482
7479 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
7483 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
7480
7484
7481
7485
7482 @command(
7486 @command(
7483 b'unshelve',
7487 b'unshelve',
7484 [
7488 [
7485 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7489 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7486 (
7490 (
7487 b'c',
7491 b'c',
7488 b'continue',
7492 b'continue',
7489 None,
7493 None,
7490 _(b'continue an incomplete unshelve operation'),
7494 _(b'continue an incomplete unshelve operation'),
7491 ),
7495 ),
7492 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7496 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7493 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7497 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7494 (
7498 (
7495 b'n',
7499 b'n',
7496 b'name',
7500 b'name',
7497 b'',
7501 b'',
7498 _(b'restore shelved change with given name'),
7502 _(b'restore shelved change with given name'),
7499 _(b'NAME'),
7503 _(b'NAME'),
7500 ),
7504 ),
7501 (b't', b'tool', b'', _(b'specify merge tool')),
7505 (b't', b'tool', b'', _(b'specify merge tool')),
7502 (
7506 (
7503 b'',
7507 b'',
7504 b'date',
7508 b'date',
7505 b'',
7509 b'',
7506 _(b'set date for temporary commits (DEPRECATED)'),
7510 _(b'set date for temporary commits (DEPRECATED)'),
7507 _(b'DATE'),
7511 _(b'DATE'),
7508 ),
7512 ),
7509 ],
7513 ],
7510 _(b'hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
7514 _(b'hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
7511 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7515 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7512 )
7516 )
7513 def unshelve(ui, repo, *shelved, **opts):
7517 def unshelve(ui, repo, *shelved, **opts):
7514 """restore a shelved change to the working directory
7518 """restore a shelved change to the working directory
7515
7519
7516 This command accepts an optional name of a shelved change to
7520 This command accepts an optional name of a shelved change to
7517 restore. If none is given, the most recent shelved change is used.
7521 restore. If none is given, the most recent shelved change is used.
7518
7522
7519 If a shelved change is applied successfully, the bundle that
7523 If a shelved change is applied successfully, the bundle that
7520 contains the shelved changes is moved to a backup location
7524 contains the shelved changes is moved to a backup location
7521 (.hg/shelve-backup).
7525 (.hg/shelve-backup).
7522
7526
7523 Since you can restore a shelved change on top of an arbitrary
7527 Since you can restore a shelved change on top of an arbitrary
7524 commit, it is possible that unshelving will result in a conflict
7528 commit, it is possible that unshelving will result in a conflict
7525 between your changes and the commits you are unshelving onto. If
7529 between your changes and the commits you are unshelving onto. If
7526 this occurs, you must resolve the conflict, then use
7530 this occurs, you must resolve the conflict, then use
7527 ``--continue`` to complete the unshelve operation. (The bundle
7531 ``--continue`` to complete the unshelve operation. (The bundle
7528 will not be moved until you successfully complete the unshelve.)
7532 will not be moved until you successfully complete the unshelve.)
7529
7533
7530 (Alternatively, you can use ``--abort`` to abandon an unshelve
7534 (Alternatively, you can use ``--abort`` to abandon an unshelve
7531 that causes a conflict. This reverts the unshelved changes, and
7535 that causes a conflict. This reverts the unshelved changes, and
7532 leaves the bundle in place.)
7536 leaves the bundle in place.)
7533
7537
7534 If bare shelved change (when no files are specified, without interactive,
7538 If bare shelved change (when no files are specified, without interactive,
7535 include and exclude option) was done on newly created branch it would
7539 include and exclude option) was done on newly created branch it would
7536 restore branch information to the working directory.
7540 restore branch information to the working directory.
7537
7541
7538 After a successful unshelve, the shelved changes are stored in a
7542 After a successful unshelve, the shelved changes are stored in a
7539 backup directory. Only the N most recent backups are kept. N
7543 backup directory. Only the N most recent backups are kept. N
7540 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7544 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7541 configuration option.
7545 configuration option.
7542
7546
7543 .. container:: verbose
7547 .. container:: verbose
7544
7548
7545 Timestamp in seconds is used to decide order of backups. More
7549 Timestamp in seconds is used to decide order of backups. More
7546 than ``maxbackups`` backups are kept, if same timestamp
7550 than ``maxbackups`` backups are kept, if same timestamp
7547 prevents from deciding exact order of them, for safety.
7551 prevents from deciding exact order of them, for safety.
7548
7552
7549 Selected changes can be unshelved with ``--interactive`` flag.
7553 Selected changes can be unshelved with ``--interactive`` flag.
7550 The working directory is updated with the selected changes, and
7554 The working directory is updated with the selected changes, and
7551 only the unselected changes remain shelved.
7555 only the unselected changes remain shelved.
7552 Note: The whole shelve is applied to working directory first before
7556 Note: The whole shelve is applied to working directory first before
7553 running interactively. So, this will bring up all the conflicts between
7557 running interactively. So, this will bring up all the conflicts between
7554 working directory and the shelve, irrespective of which changes will be
7558 working directory and the shelve, irrespective of which changes will be
7555 unshelved.
7559 unshelved.
7556 """
7560 """
7557 with repo.wlock():
7561 with repo.wlock():
7558 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7562 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7559
7563
7560
7564
7561 statemod.addunfinished(
7565 statemod.addunfinished(
7562 b'unshelve',
7566 b'unshelve',
7563 fname=b'shelvedstate',
7567 fname=b'shelvedstate',
7564 continueflag=True,
7568 continueflag=True,
7565 abortfunc=shelvemod.hgabortunshelve,
7569 abortfunc=shelvemod.hgabortunshelve,
7566 continuefunc=shelvemod.hgcontinueunshelve,
7570 continuefunc=shelvemod.hgcontinueunshelve,
7567 cmdmsg=_(b'unshelve already in progress'),
7571 cmdmsg=_(b'unshelve already in progress'),
7568 )
7572 )
7569
7573
7570
7574
7571 @command(
7575 @command(
7572 b'update|up|checkout|co',
7576 b'update|up|checkout|co',
7573 [
7577 [
7574 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7578 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7575 (b'c', b'check', None, _(b'require clean working directory')),
7579 (b'c', b'check', None, _(b'require clean working directory')),
7576 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7580 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7577 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7581 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7578 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7582 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7579 ]
7583 ]
7580 + mergetoolopts,
7584 + mergetoolopts,
7581 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7585 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7582 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7586 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7583 helpbasic=True,
7587 helpbasic=True,
7584 )
7588 )
7585 def update(ui, repo, node=None, **opts):
7589 def update(ui, repo, node=None, **opts):
7586 """update working directory (or switch revisions)
7590 """update working directory (or switch revisions)
7587
7591
7588 Update the repository's working directory to the specified
7592 Update the repository's working directory to the specified
7589 changeset. If no changeset is specified, update to the tip of the
7593 changeset. If no changeset is specified, update to the tip of the
7590 current named branch and move the active bookmark (see :hg:`help
7594 current named branch and move the active bookmark (see :hg:`help
7591 bookmarks`).
7595 bookmarks`).
7592
7596
7593 Update sets the working directory's parent revision to the specified
7597 Update sets the working directory's parent revision to the specified
7594 changeset (see :hg:`help parents`).
7598 changeset (see :hg:`help parents`).
7595
7599
7596 If the changeset is not a descendant or ancestor of the working
7600 If the changeset is not a descendant or ancestor of the working
7597 directory's parent and there are uncommitted changes, the update is
7601 directory's parent and there are uncommitted changes, the update is
7598 aborted. With the -c/--check option, the working directory is checked
7602 aborted. With the -c/--check option, the working directory is checked
7599 for uncommitted changes; if none are found, the working directory is
7603 for uncommitted changes; if none are found, the working directory is
7600 updated to the specified changeset.
7604 updated to the specified changeset.
7601
7605
7602 .. container:: verbose
7606 .. container:: verbose
7603
7607
7604 The -C/--clean, -c/--check, and -m/--merge options control what
7608 The -C/--clean, -c/--check, and -m/--merge options control what
7605 happens if the working directory contains uncommitted changes.
7609 happens if the working directory contains uncommitted changes.
7606 At most of one of them can be specified.
7610 At most of one of them can be specified.
7607
7611
7608 1. If no option is specified, and if
7612 1. If no option is specified, and if
7609 the requested changeset is an ancestor or descendant of
7613 the requested changeset is an ancestor or descendant of
7610 the working directory's parent, the uncommitted changes
7614 the working directory's parent, the uncommitted changes
7611 are merged into the requested changeset and the merged
7615 are merged into the requested changeset and the merged
7612 result is left uncommitted. If the requested changeset is
7616 result is left uncommitted. If the requested changeset is
7613 not an ancestor or descendant (that is, it is on another
7617 not an ancestor or descendant (that is, it is on another
7614 branch), the update is aborted and the uncommitted changes
7618 branch), the update is aborted and the uncommitted changes
7615 are preserved.
7619 are preserved.
7616
7620
7617 2. With the -m/--merge option, the update is allowed even if the
7621 2. With the -m/--merge option, the update is allowed even if the
7618 requested changeset is not an ancestor or descendant of
7622 requested changeset is not an ancestor or descendant of
7619 the working directory's parent.
7623 the working directory's parent.
7620
7624
7621 3. With the -c/--check option, the update is aborted and the
7625 3. With the -c/--check option, the update is aborted and the
7622 uncommitted changes are preserved.
7626 uncommitted changes are preserved.
7623
7627
7624 4. With the -C/--clean option, uncommitted changes are discarded and
7628 4. With the -C/--clean option, uncommitted changes are discarded and
7625 the working directory is updated to the requested changeset.
7629 the working directory is updated to the requested changeset.
7626
7630
7627 To cancel an uncommitted merge (and lose your changes), use
7631 To cancel an uncommitted merge (and lose your changes), use
7628 :hg:`merge --abort`.
7632 :hg:`merge --abort`.
7629
7633
7630 Use null as the changeset to remove the working directory (like
7634 Use null as the changeset to remove the working directory (like
7631 :hg:`clone -U`).
7635 :hg:`clone -U`).
7632
7636
7633 If you want to revert just one file to an older revision, use
7637 If you want to revert just one file to an older revision, use
7634 :hg:`revert [-r REV] NAME`.
7638 :hg:`revert [-r REV] NAME`.
7635
7639
7636 See :hg:`help dates` for a list of formats valid for -d/--date.
7640 See :hg:`help dates` for a list of formats valid for -d/--date.
7637
7641
7638 Returns 0 on success, 1 if there are unresolved files.
7642 Returns 0 on success, 1 if there are unresolved files.
7639 """
7643 """
7640 rev = opts.get(r'rev')
7644 rev = opts.get(r'rev')
7641 date = opts.get(r'date')
7645 date = opts.get(r'date')
7642 clean = opts.get(r'clean')
7646 clean = opts.get(r'clean')
7643 check = opts.get(r'check')
7647 check = opts.get(r'check')
7644 merge = opts.get(r'merge')
7648 merge = opts.get(r'merge')
7645 if rev and node:
7649 if rev and node:
7646 raise error.Abort(_(b"please specify just one revision"))
7650 raise error.Abort(_(b"please specify just one revision"))
7647
7651
7648 if ui.configbool(b'commands', b'update.requiredest'):
7652 if ui.configbool(b'commands', b'update.requiredest'):
7649 if not node and not rev and not date:
7653 if not node and not rev and not date:
7650 raise error.Abort(
7654 raise error.Abort(
7651 _(b'you must specify a destination'),
7655 _(b'you must specify a destination'),
7652 hint=_(b'for example: hg update ".::"'),
7656 hint=_(b'for example: hg update ".::"'),
7653 )
7657 )
7654
7658
7655 if rev is None or rev == b'':
7659 if rev is None or rev == b'':
7656 rev = node
7660 rev = node
7657
7661
7658 if date and rev is not None:
7662 if date and rev is not None:
7659 raise error.Abort(_(b"you can't specify a revision and a date"))
7663 raise error.Abort(_(b"you can't specify a revision and a date"))
7660
7664
7661 if len([x for x in (clean, check, merge) if x]) > 1:
7665 if len([x for x in (clean, check, merge) if x]) > 1:
7662 raise error.Abort(
7666 raise error.Abort(
7663 _(
7667 _(
7664 b"can only specify one of -C/--clean, -c/--check, "
7668 b"can only specify one of -C/--clean, -c/--check, "
7665 b"or -m/--merge"
7669 b"or -m/--merge"
7666 )
7670 )
7667 )
7671 )
7668
7672
7669 updatecheck = None
7673 updatecheck = None
7670 if check:
7674 if check:
7671 updatecheck = b'abort'
7675 updatecheck = b'abort'
7672 elif merge:
7676 elif merge:
7673 updatecheck = b'none'
7677 updatecheck = b'none'
7674
7678
7675 with repo.wlock():
7679 with repo.wlock():
7676 cmdutil.clearunfinished(repo)
7680 cmdutil.clearunfinished(repo)
7677 if date:
7681 if date:
7678 rev = cmdutil.finddate(ui, repo, date)
7682 rev = cmdutil.finddate(ui, repo, date)
7679
7683
7680 # if we defined a bookmark, we have to remember the original name
7684 # if we defined a bookmark, we have to remember the original name
7681 brev = rev
7685 brev = rev
7682 if rev:
7686 if rev:
7683 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7687 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7684 ctx = scmutil.revsingle(repo, rev, default=None)
7688 ctx = scmutil.revsingle(repo, rev, default=None)
7685 rev = ctx.rev()
7689 rev = ctx.rev()
7686 hidden = ctx.hidden()
7690 hidden = ctx.hidden()
7687 overrides = {(b'ui', b'forcemerge'): opts.get(r'tool', b'')}
7691 overrides = {(b'ui', b'forcemerge'): opts.get(r'tool', b'')}
7688 with ui.configoverride(overrides, b'update'):
7692 with ui.configoverride(overrides, b'update'):
7689 ret = hg.updatetotally(
7693 ret = hg.updatetotally(
7690 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7694 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7691 )
7695 )
7692 if hidden:
7696 if hidden:
7693 ctxstr = ctx.hex()[:12]
7697 ctxstr = ctx.hex()[:12]
7694 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7698 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7695
7699
7696 if ctx.obsolete():
7700 if ctx.obsolete():
7697 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7701 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7698 ui.warn(b"(%s)\n" % obsfatemsg)
7702 ui.warn(b"(%s)\n" % obsfatemsg)
7699 return ret
7703 return ret
7700
7704
7701
7705
7702 @command(
7706 @command(
7703 b'verify',
7707 b'verify',
7704 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7708 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7705 helpcategory=command.CATEGORY_MAINTENANCE,
7709 helpcategory=command.CATEGORY_MAINTENANCE,
7706 )
7710 )
7707 def verify(ui, repo, **opts):
7711 def verify(ui, repo, **opts):
7708 """verify the integrity of the repository
7712 """verify the integrity of the repository
7709
7713
7710 Verify the integrity of the current repository.
7714 Verify the integrity of the current repository.
7711
7715
7712 This will perform an extensive check of the repository's
7716 This will perform an extensive check of the repository's
7713 integrity, validating the hashes and checksums of each entry in
7717 integrity, validating the hashes and checksums of each entry in
7714 the changelog, manifest, and tracked files, as well as the
7718 the changelog, manifest, and tracked files, as well as the
7715 integrity of their crosslinks and indices.
7719 integrity of their crosslinks and indices.
7716
7720
7717 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7721 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7718 for more information about recovery from corruption of the
7722 for more information about recovery from corruption of the
7719 repository.
7723 repository.
7720
7724
7721 Returns 0 on success, 1 if errors are encountered.
7725 Returns 0 on success, 1 if errors are encountered.
7722 """
7726 """
7723 opts = pycompat.byteskwargs(opts)
7727 opts = pycompat.byteskwargs(opts)
7724
7728
7725 level = None
7729 level = None
7726 if opts[b'full']:
7730 if opts[b'full']:
7727 level = verifymod.VERIFY_FULL
7731 level = verifymod.VERIFY_FULL
7728 return hg.verify(repo, level)
7732 return hg.verify(repo, level)
7729
7733
7730
7734
7731 @command(
7735 @command(
7732 b'version',
7736 b'version',
7733 [] + formatteropts,
7737 [] + formatteropts,
7734 helpcategory=command.CATEGORY_HELP,
7738 helpcategory=command.CATEGORY_HELP,
7735 norepo=True,
7739 norepo=True,
7736 intents={INTENT_READONLY},
7740 intents={INTENT_READONLY},
7737 )
7741 )
7738 def version_(ui, **opts):
7742 def version_(ui, **opts):
7739 """output version and copyright information
7743 """output version and copyright information
7740
7744
7741 .. container:: verbose
7745 .. container:: verbose
7742
7746
7743 Template:
7747 Template:
7744
7748
7745 The following keywords are supported. See also :hg:`help templates`.
7749 The following keywords are supported. See also :hg:`help templates`.
7746
7750
7747 :extensions: List of extensions.
7751 :extensions: List of extensions.
7748 :ver: String. Version number.
7752 :ver: String. Version number.
7749
7753
7750 And each entry of ``{extensions}`` provides the following sub-keywords
7754 And each entry of ``{extensions}`` provides the following sub-keywords
7751 in addition to ``{ver}``.
7755 in addition to ``{ver}``.
7752
7756
7753 :bundled: Boolean. True if included in the release.
7757 :bundled: Boolean. True if included in the release.
7754 :name: String. Extension name.
7758 :name: String. Extension name.
7755 """
7759 """
7756 opts = pycompat.byteskwargs(opts)
7760 opts = pycompat.byteskwargs(opts)
7757 if ui.verbose:
7761 if ui.verbose:
7758 ui.pager(b'version')
7762 ui.pager(b'version')
7759 fm = ui.formatter(b"version", opts)
7763 fm = ui.formatter(b"version", opts)
7760 fm.startitem()
7764 fm.startitem()
7761 fm.write(
7765 fm.write(
7762 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7766 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7763 )
7767 )
7764 license = _(
7768 license = _(
7765 b"(see https://mercurial-scm.org for more information)\n"
7769 b"(see https://mercurial-scm.org for more information)\n"
7766 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7770 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7767 b"This is free software; see the source for copying conditions. "
7771 b"This is free software; see the source for copying conditions. "
7768 b"There is NO\nwarranty; "
7772 b"There is NO\nwarranty; "
7769 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7773 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7770 )
7774 )
7771 if not ui.quiet:
7775 if not ui.quiet:
7772 fm.plain(license)
7776 fm.plain(license)
7773
7777
7774 if ui.verbose:
7778 if ui.verbose:
7775 fm.plain(_(b"\nEnabled extensions:\n\n"))
7779 fm.plain(_(b"\nEnabled extensions:\n\n"))
7776 # format names and versions into columns
7780 # format names and versions into columns
7777 names = []
7781 names = []
7778 vers = []
7782 vers = []
7779 isinternals = []
7783 isinternals = []
7780 for name, module in extensions.extensions():
7784 for name, module in extensions.extensions():
7781 names.append(name)
7785 names.append(name)
7782 vers.append(extensions.moduleversion(module) or None)
7786 vers.append(extensions.moduleversion(module) or None)
7783 isinternals.append(extensions.ismoduleinternal(module))
7787 isinternals.append(extensions.ismoduleinternal(module))
7784 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7788 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7785 if names:
7789 if names:
7786 namefmt = b" %%-%ds " % max(len(n) for n in names)
7790 namefmt = b" %%-%ds " % max(len(n) for n in names)
7787 places = [_(b"external"), _(b"internal")]
7791 places = [_(b"external"), _(b"internal")]
7788 for n, v, p in zip(names, vers, isinternals):
7792 for n, v, p in zip(names, vers, isinternals):
7789 fn.startitem()
7793 fn.startitem()
7790 fn.condwrite(ui.verbose, b"name", namefmt, n)
7794 fn.condwrite(ui.verbose, b"name", namefmt, n)
7791 if ui.verbose:
7795 if ui.verbose:
7792 fn.plain(b"%s " % places[p])
7796 fn.plain(b"%s " % places[p])
7793 fn.data(bundled=p)
7797 fn.data(bundled=p)
7794 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7798 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7795 if ui.verbose:
7799 if ui.verbose:
7796 fn.plain(b"\n")
7800 fn.plain(b"\n")
7797 fn.end()
7801 fn.end()
7798 fm.end()
7802 fm.end()
7799
7803
7800
7804
7801 def loadcmdtable(ui, name, cmdtable):
7805 def loadcmdtable(ui, name, cmdtable):
7802 """Load command functions from specified cmdtable
7806 """Load command functions from specified cmdtable
7803 """
7807 """
7804 overrides = [cmd for cmd in cmdtable if cmd in table]
7808 overrides = [cmd for cmd in cmdtable if cmd in table]
7805 if overrides:
7809 if overrides:
7806 ui.warn(
7810 ui.warn(
7807 _(b"extension '%s' overrides commands: %s\n")
7811 _(b"extension '%s' overrides commands: %s\n")
7808 % (name, b" ".join(overrides))
7812 % (name, b" ".join(overrides))
7809 )
7813 )
7810 table.update(cmdtable)
7814 table.update(cmdtable)
@@ -1,390 +1,392 b''
1 hide outer repo
1 hide outer repo
2 $ hg init
2 $ hg init
3
3
4 Invalid syntax: no value
4 Invalid syntax: no value
5
5
6 $ cat > .hg/hgrc << EOF
6 $ cat > .hg/hgrc << EOF
7 > novaluekey
7 > novaluekey
8 > EOF
8 > EOF
9 $ hg showconfig
9 $ hg showconfig
10 hg: parse error at $TESTTMP/.hg/hgrc:1: novaluekey
10 hg: parse error at $TESTTMP/.hg/hgrc:1: novaluekey
11 [255]
11 [255]
12
12
13 Invalid syntax: no key
13 Invalid syntax: no key
14
14
15 $ cat > .hg/hgrc << EOF
15 $ cat > .hg/hgrc << EOF
16 > =nokeyvalue
16 > =nokeyvalue
17 > EOF
17 > EOF
18 $ hg showconfig
18 $ hg showconfig
19 hg: parse error at $TESTTMP/.hg/hgrc:1: =nokeyvalue
19 hg: parse error at $TESTTMP/.hg/hgrc:1: =nokeyvalue
20 [255]
20 [255]
21
21
22 Test hint about invalid syntax from leading white space
22 Test hint about invalid syntax from leading white space
23
23
24 $ cat > .hg/hgrc << EOF
24 $ cat > .hg/hgrc << EOF
25 > key=value
25 > key=value
26 > EOF
26 > EOF
27 $ hg showconfig
27 $ hg showconfig
28 hg: parse error at $TESTTMP/.hg/hgrc:1: key=value
28 hg: parse error at $TESTTMP/.hg/hgrc:1: key=value
29 unexpected leading whitespace
29 unexpected leading whitespace
30 [255]
30 [255]
31
31
32 $ cat > .hg/hgrc << EOF
32 $ cat > .hg/hgrc << EOF
33 > [section]
33 > [section]
34 > key=value
34 > key=value
35 > EOF
35 > EOF
36 $ hg showconfig
36 $ hg showconfig
37 hg: parse error at $TESTTMP/.hg/hgrc:1: [section]
37 hg: parse error at $TESTTMP/.hg/hgrc:1: [section]
38 unexpected leading whitespace
38 unexpected leading whitespace
39 [255]
39 [255]
40
40
41 Reset hgrc
41 Reset hgrc
42
42
43 $ echo > .hg/hgrc
43 $ echo > .hg/hgrc
44
44
45 Test case sensitive configuration
45 Test case sensitive configuration
46
46
47 $ cat <<EOF >> $HGRCPATH
47 $ cat <<EOF >> $HGRCPATH
48 > [Section]
48 > [Section]
49 > KeY = Case Sensitive
49 > KeY = Case Sensitive
50 > key = lower case
50 > key = lower case
51 > EOF
51 > EOF
52
52
53 $ hg showconfig Section
53 $ hg showconfig Section
54 Section.KeY=Case Sensitive
54 Section.KeY=Case Sensitive
55 Section.key=lower case
55 Section.key=lower case
56
56
57 $ hg showconfig Section -Tjson
57 $ hg showconfig Section -Tjson
58 [
58 [
59 {
59 {
60 "defaultvalue": null,
60 "defaultvalue": null,
61 "name": "Section.KeY",
61 "name": "Section.KeY",
62 "source": "*.hgrc:*", (glob)
62 "source": "*.hgrc:*", (glob)
63 "value": "Case Sensitive"
63 "value": "Case Sensitive"
64 },
64 },
65 {
65 {
66 "defaultvalue": null,
66 "defaultvalue": null,
67 "name": "Section.key",
67 "name": "Section.key",
68 "source": "*.hgrc:*", (glob)
68 "source": "*.hgrc:*", (glob)
69 "value": "lower case"
69 "value": "lower case"
70 }
70 }
71 ]
71 ]
72 $ hg showconfig Section.KeY -Tjson
72 $ hg showconfig Section.KeY -Tjson
73 [
73 [
74 {
74 {
75 "defaultvalue": null,
75 "defaultvalue": null,
76 "name": "Section.KeY",
76 "name": "Section.KeY",
77 "source": "*.hgrc:*", (glob)
77 "source": "*.hgrc:*", (glob)
78 "value": "Case Sensitive"
78 "value": "Case Sensitive"
79 }
79 }
80 ]
80 ]
81 $ hg showconfig -Tjson | tail -7
81 $ hg showconfig -Tjson | tail -7
82 {
82 {
83 "defaultvalue": null,
83 "defaultvalue": null,
84 "name": "*", (glob)
84 "name": "*", (glob)
85 "source": "*", (glob)
85 "source": "*", (glob)
86 "value": "*" (glob)
86 "value": "*" (glob)
87 }
87 }
88 ]
88 ]
89
89
90 Test config default of various types:
90 Test config default of various types:
91
91
92 {"defaultvalue": ""} for -T'json(defaultvalue)' looks weird, but that's
92 {"defaultvalue": ""} for -T'json(defaultvalue)' looks weird, but that's
93 how the templater works. Unknown keywords are evaluated to "".
93 how the templater works. Unknown keywords are evaluated to "".
94
94
95 dynamicdefault
95 dynamicdefault
96
96
97 $ hg config --config alias.foo= alias -Tjson
97 $ hg config --config alias.foo= alias -Tjson
98 [
98 [
99 {
99 {
100 "name": "alias.foo",
100 "name": "alias.foo",
101 "source": "--config",
101 "source": "--config",
102 "value": ""
102 "value": ""
103 }
103 }
104 ]
104 ]
105 $ hg config --config alias.foo= alias -T'json(defaultvalue)'
105 $ hg config --config alias.foo= alias -T'json(defaultvalue)'
106 [
106 [
107 {"defaultvalue": ""}
107 {"defaultvalue": ""}
108 ]
108 ]
109 $ hg config --config alias.foo= alias -T'{defaultvalue}\n'
109 $ hg config --config alias.foo= alias -T'{defaultvalue}\n'
110
110
111
111
112 null
112 null
113
113
114 $ hg config --config auth.cookiefile= auth -Tjson
114 $ hg config --config auth.cookiefile= auth -Tjson
115 [
115 [
116 {
116 {
117 "defaultvalue": null,
117 "defaultvalue": null,
118 "name": "auth.cookiefile",
118 "name": "auth.cookiefile",
119 "source": "--config",
119 "source": "--config",
120 "value": ""
120 "value": ""
121 }
121 }
122 ]
122 ]
123 $ hg config --config auth.cookiefile= auth -T'json(defaultvalue)'
123 $ hg config --config auth.cookiefile= auth -T'json(defaultvalue)'
124 [
124 [
125 {"defaultvalue": ""}
125 {"defaultvalue": ""}
126 ]
126 ]
127 $ hg config --config auth.cookiefile= auth -T'{defaultvalue}\n'
127 $ hg config --config auth.cookiefile= auth -T'{defaultvalue}\n'
128
128
129
129
130 false
130 false
131
131
132 $ hg config --config commands.commit.post-status= commands -Tjson
132 $ hg config --config commands.commit.post-status= commands -Tjson
133 [
133 [
134 {
134 {
135 "defaultvalue": false,
135 "defaultvalue": false,
136 "name": "commands.commit.post-status",
136 "name": "commands.commit.post-status",
137 "source": "--config",
137 "source": "--config",
138 "value": ""
138 "value": ""
139 }
139 }
140 ]
140 ]
141 $ hg config --config commands.commit.post-status= commands -T'json(defaultvalue)'
141 $ hg config --config commands.commit.post-status= commands -T'json(defaultvalue)'
142 [
142 [
143 {"defaultvalue": false}
143 {"defaultvalue": false}
144 ]
144 ]
145 $ hg config --config commands.commit.post-status= commands -T'{defaultvalue}\n'
145 $ hg config --config commands.commit.post-status= commands -T'{defaultvalue}\n'
146 False
146 False
147
147
148 true
148 true
149
149
150 $ hg config --config format.dotencode= format -Tjson
150 $ hg config --config format.dotencode= format -Tjson
151 [
151 [
152 {
152 {
153 "defaultvalue": true,
153 "defaultvalue": true,
154 "name": "format.dotencode",
154 "name": "format.dotencode",
155 "source": "--config",
155 "source": "--config",
156 "value": ""
156 "value": ""
157 }
157 }
158 ]
158 ]
159 $ hg config --config format.dotencode= format -T'json(defaultvalue)'
159 $ hg config --config format.dotencode= format -T'json(defaultvalue)'
160 [
160 [
161 {"defaultvalue": true}
161 {"defaultvalue": true}
162 ]
162 ]
163 $ hg config --config format.dotencode= format -T'{defaultvalue}\n'
163 $ hg config --config format.dotencode= format -T'{defaultvalue}\n'
164 True
164 True
165
165
166 bytes
166 bytes
167
167
168 $ hg config --config commands.resolve.mark-check= commands -Tjson
168 $ hg config --config commands.resolve.mark-check= commands -Tjson
169 [
169 [
170 {
170 {
171 "defaultvalue": "none",
171 "defaultvalue": "none",
172 "name": "commands.resolve.mark-check",
172 "name": "commands.resolve.mark-check",
173 "source": "--config",
173 "source": "--config",
174 "value": ""
174 "value": ""
175 }
175 }
176 ]
176 ]
177 $ hg config --config commands.resolve.mark-check= commands -T'json(defaultvalue)'
177 $ hg config --config commands.resolve.mark-check= commands -T'json(defaultvalue)'
178 [
178 [
179 {"defaultvalue": "none"}
179 {"defaultvalue": "none"}
180 ]
180 ]
181 $ hg config --config commands.resolve.mark-check= commands -T'{defaultvalue}\n'
181 $ hg config --config commands.resolve.mark-check= commands -T'{defaultvalue}\n'
182 none
182 none
183
183
184 empty list
184 empty list
185
185
186 $ hg config --config commands.show.aliasprefix= commands -Tjson
186 $ hg config --config commands.show.aliasprefix= commands -Tjson
187 [
187 [
188 {
188 {
189 "defaultvalue": [],
189 "name": "commands.show.aliasprefix",
190 "name": "commands.show.aliasprefix",
190 "source": "--config",
191 "source": "--config",
191 "value": ""
192 "value": ""
192 }
193 }
193 ]
194 ]
194 $ hg config --config commands.show.aliasprefix= commands -T'json(defaultvalue)'
195 $ hg config --config commands.show.aliasprefix= commands -T'json(defaultvalue)'
195 [
196 [
196 {"defaultvalue": ""}
197 {"defaultvalue": []}
197 ]
198 ]
198 $ hg config --config commands.show.aliasprefix= commands -T'{defaultvalue}\n'
199 $ hg config --config commands.show.aliasprefix= commands -T'{defaultvalue}\n'
199
200
200
201
201 nonempty list
202 nonempty list
202
203
203 $ hg config --config progress.format= progress -Tjson
204 $ hg config --config progress.format= progress -Tjson
204 [
205 [
205 {
206 {
207 "defaultvalue": ["topic", "bar", "number", "estimate"],
206 "name": "progress.format",
208 "name": "progress.format",
207 "source": "--config",
209 "source": "--config",
208 "value": ""
210 "value": ""
209 }
211 }
210 ]
212 ]
211 $ hg config --config progress.format= progress -T'json(defaultvalue)'
213 $ hg config --config progress.format= progress -T'json(defaultvalue)'
212 [
214 [
213 {"defaultvalue": ""}
215 {"defaultvalue": ["topic", "bar", "number", "estimate"]}
214 ]
216 ]
215 $ hg config --config progress.format= progress -T'{defaultvalue}\n'
217 $ hg config --config progress.format= progress -T'{defaultvalue}\n'
216
218 topic bar number estimate
217
219
218 int
220 int
219
221
220 $ hg config --config profiling.freq= profiling -Tjson
222 $ hg config --config profiling.freq= profiling -Tjson
221 [
223 [
222 {
224 {
223 "defaultvalue": 1000,
225 "defaultvalue": 1000,
224 "name": "profiling.freq",
226 "name": "profiling.freq",
225 "source": "--config",
227 "source": "--config",
226 "value": ""
228 "value": ""
227 }
229 }
228 ]
230 ]
229 $ hg config --config profiling.freq= profiling -T'json(defaultvalue)'
231 $ hg config --config profiling.freq= profiling -T'json(defaultvalue)'
230 [
232 [
231 {"defaultvalue": 1000}
233 {"defaultvalue": 1000}
232 ]
234 ]
233 $ hg config --config profiling.freq= profiling -T'{defaultvalue}\n'
235 $ hg config --config profiling.freq= profiling -T'{defaultvalue}\n'
234 1000
236 1000
235
237
236 float
238 float
237
239
238 $ hg config --config profiling.showmax= profiling -Tjson
240 $ hg config --config profiling.showmax= profiling -Tjson
239 [
241 [
240 {
242 {
241 "defaultvalue": 0.999,
243 "defaultvalue": 0.999,
242 "name": "profiling.showmax",
244 "name": "profiling.showmax",
243 "source": "--config",
245 "source": "--config",
244 "value": ""
246 "value": ""
245 }
247 }
246 ]
248 ]
247 $ hg config --config profiling.showmax= profiling -T'json(defaultvalue)'
249 $ hg config --config profiling.showmax= profiling -T'json(defaultvalue)'
248 [
250 [
249 {"defaultvalue": 0.999}
251 {"defaultvalue": 0.999}
250 ]
252 ]
251 $ hg config --config profiling.showmax= profiling -T'{defaultvalue}\n'
253 $ hg config --config profiling.showmax= profiling -T'{defaultvalue}\n'
252 0.999
254 0.999
253
255
254 Test empty config source:
256 Test empty config source:
255
257
256 $ cat <<EOF > emptysource.py
258 $ cat <<EOF > emptysource.py
257 > def reposetup(ui, repo):
259 > def reposetup(ui, repo):
258 > ui.setconfig(b'empty', b'source', b'value')
260 > ui.setconfig(b'empty', b'source', b'value')
259 > EOF
261 > EOF
260 $ cp .hg/hgrc .hg/hgrc.orig
262 $ cp .hg/hgrc .hg/hgrc.orig
261 $ cat <<EOF >> .hg/hgrc
263 $ cat <<EOF >> .hg/hgrc
262 > [extensions]
264 > [extensions]
263 > emptysource = `pwd`/emptysource.py
265 > emptysource = `pwd`/emptysource.py
264 > EOF
266 > EOF
265
267
266 $ hg config --debug empty.source
268 $ hg config --debug empty.source
267 read config from: * (glob)
269 read config from: * (glob)
268 none: value
270 none: value
269 $ hg config empty.source -Tjson
271 $ hg config empty.source -Tjson
270 [
272 [
271 {
273 {
272 "defaultvalue": null,
274 "defaultvalue": null,
273 "name": "empty.source",
275 "name": "empty.source",
274 "source": "",
276 "source": "",
275 "value": "value"
277 "value": "value"
276 }
278 }
277 ]
279 ]
278
280
279 $ cp .hg/hgrc.orig .hg/hgrc
281 $ cp .hg/hgrc.orig .hg/hgrc
280
282
281 Test "%unset"
283 Test "%unset"
282
284
283 $ cat >> $HGRCPATH <<EOF
285 $ cat >> $HGRCPATH <<EOF
284 > [unsettest]
286 > [unsettest]
285 > local-hgrcpath = should be unset (HGRCPATH)
287 > local-hgrcpath = should be unset (HGRCPATH)
286 > %unset local-hgrcpath
288 > %unset local-hgrcpath
287 >
289 >
288 > global = should be unset (HGRCPATH)
290 > global = should be unset (HGRCPATH)
289 >
291 >
290 > both = should be unset (HGRCPATH)
292 > both = should be unset (HGRCPATH)
291 >
293 >
292 > set-after-unset = should be unset (HGRCPATH)
294 > set-after-unset = should be unset (HGRCPATH)
293 > EOF
295 > EOF
294
296
295 $ cat >> .hg/hgrc <<EOF
297 $ cat >> .hg/hgrc <<EOF
296 > [unsettest]
298 > [unsettest]
297 > local-hgrc = should be unset (.hg/hgrc)
299 > local-hgrc = should be unset (.hg/hgrc)
298 > %unset local-hgrc
300 > %unset local-hgrc
299 >
301 >
300 > %unset global
302 > %unset global
301 >
303 >
302 > both = should be unset (.hg/hgrc)
304 > both = should be unset (.hg/hgrc)
303 > %unset both
305 > %unset both
304 >
306 >
305 > set-after-unset = should be unset (.hg/hgrc)
307 > set-after-unset = should be unset (.hg/hgrc)
306 > %unset set-after-unset
308 > %unset set-after-unset
307 > set-after-unset = should be set (.hg/hgrc)
309 > set-after-unset = should be set (.hg/hgrc)
308 > EOF
310 > EOF
309
311
310 $ hg showconfig unsettest
312 $ hg showconfig unsettest
311 unsettest.set-after-unset=should be set (.hg/hgrc)
313 unsettest.set-after-unset=should be set (.hg/hgrc)
312
314
313 Test exit code when no config matches
315 Test exit code when no config matches
314
316
315 $ hg config Section.idontexist
317 $ hg config Section.idontexist
316 [1]
318 [1]
317
319
318 sub-options in [paths] aren't expanded
320 sub-options in [paths] aren't expanded
319
321
320 $ cat > .hg/hgrc << EOF
322 $ cat > .hg/hgrc << EOF
321 > [paths]
323 > [paths]
322 > foo = ~/foo
324 > foo = ~/foo
323 > foo:suboption = ~/foo
325 > foo:suboption = ~/foo
324 > EOF
326 > EOF
325
327
326 $ hg showconfig paths
328 $ hg showconfig paths
327 paths.foo:suboption=~/foo
329 paths.foo:suboption=~/foo
328 paths.foo=$TESTTMP/foo
330 paths.foo=$TESTTMP/foo
329
331
330 edit failure
332 edit failure
331
333
332 $ HGEDITOR=false hg config --edit
334 $ HGEDITOR=false hg config --edit
333 abort: edit failed: false exited with status 1
335 abort: edit failed: false exited with status 1
334 [255]
336 [255]
335
337
336 config affected by environment variables
338 config affected by environment variables
337
339
338 $ EDITOR=e1 VISUAL=e2 hg config --debug | grep 'ui\.editor'
340 $ EDITOR=e1 VISUAL=e2 hg config --debug | grep 'ui\.editor'
339 $VISUAL: ui.editor=e2
341 $VISUAL: ui.editor=e2
340
342
341 $ VISUAL=e2 hg config --debug --config ui.editor=e3 | grep 'ui\.editor'
343 $ VISUAL=e2 hg config --debug --config ui.editor=e3 | grep 'ui\.editor'
342 --config: ui.editor=e3
344 --config: ui.editor=e3
343
345
344 $ PAGER=p1 hg config --debug | grep 'pager\.pager'
346 $ PAGER=p1 hg config --debug | grep 'pager\.pager'
345 $PAGER: pager.pager=p1
347 $PAGER: pager.pager=p1
346
348
347 $ PAGER=p1 hg config --debug --config pager.pager=p2 | grep 'pager\.pager'
349 $ PAGER=p1 hg config --debug --config pager.pager=p2 | grep 'pager\.pager'
348 --config: pager.pager=p2
350 --config: pager.pager=p2
349
351
350 verify that aliases are evaluated as well
352 verify that aliases are evaluated as well
351
353
352 $ hg init aliastest
354 $ hg init aliastest
353 $ cd aliastest
355 $ cd aliastest
354 $ cat > .hg/hgrc << EOF
356 $ cat > .hg/hgrc << EOF
355 > [ui]
357 > [ui]
356 > user = repo user
358 > user = repo user
357 > EOF
359 > EOF
358 $ touch index
360 $ touch index
359 $ unset HGUSER
361 $ unset HGUSER
360 $ hg ci -Am test
362 $ hg ci -Am test
361 adding index
363 adding index
362 $ hg log --template '{author}\n'
364 $ hg log --template '{author}\n'
363 repo user
365 repo user
364 $ cd ..
366 $ cd ..
365
367
366 alias has lower priority
368 alias has lower priority
367
369
368 $ hg init aliaspriority
370 $ hg init aliaspriority
369 $ cd aliaspriority
371 $ cd aliaspriority
370 $ cat > .hg/hgrc << EOF
372 $ cat > .hg/hgrc << EOF
371 > [ui]
373 > [ui]
372 > user = alias user
374 > user = alias user
373 > username = repo user
375 > username = repo user
374 > EOF
376 > EOF
375 $ touch index
377 $ touch index
376 $ unset HGUSER
378 $ unset HGUSER
377 $ hg ci -Am test
379 $ hg ci -Am test
378 adding index
380 adding index
379 $ hg log --template '{author}\n'
381 $ hg log --template '{author}\n'
380 repo user
382 repo user
381 $ cd ..
383 $ cd ..
382
384
383 configs should be read in lexicographical order
385 configs should be read in lexicographical order
384
386
385 $ mkdir configs
387 $ mkdir configs
386 $ for i in `$TESTDIR/seq.py 10 99`; do
388 $ for i in `$TESTDIR/seq.py 10 99`; do
387 > printf "[section]\nkey=$i" > configs/$i.rc
389 > printf "[section]\nkey=$i" > configs/$i.rc
388 > done
390 > done
389 $ HGRCPATH=configs hg config section.key
391 $ HGRCPATH=configs hg config section.key
390 99
392 99
General Comments 0
You need to be logged in to leave comments. Login now