##// END OF EJS Templates
debug: add a debug::unbundle command that simulate the unbundle from a push...
marmoute -
r52293:e2dfa403 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,8100 +1,8104 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@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
8
9 import os
9 import os
10 import re
10 import re
11 import sys
11 import sys
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullid,
16 nullid,
17 nullrev,
17 nullrev,
18 short,
18 short,
19 wdirrev,
19 wdirrev,
20 )
20 )
21 from . import (
21 from . import (
22 admin_commands as admin_commands_mod,
22 admin_commands as admin_commands_mod,
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 bundlecaches,
26 bundlecaches,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 diffutil,
32 diffutil,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 filemerge,
38 filemerge,
39 formatter,
39 formatter,
40 graphmod,
40 graphmod,
41 grep as grepmod,
41 grep as grepmod,
42 hbisect,
42 hbisect,
43 help,
43 help,
44 hg,
44 hg,
45 logcmdutil,
45 logcmdutil,
46 merge as mergemod,
46 merge as mergemod,
47 mergestate as mergestatemod,
47 mergestate as mergestatemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 requirements,
56 requirements,
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 vfs as vfsmod,
68 vfs as vfsmod,
69 wireprotoserver,
69 wireprotoserver,
70 )
70 )
71 from .utils import (
71 from .utils import (
72 dateutil,
72 dateutil,
73 procutil,
73 procutil,
74 stringutil,
74 stringutil,
75 urlutil,
75 urlutil,
76 )
76 )
77
77
78 table = {}
78 table = {}
79 table.update(debugcommandsmod.command._table)
79 table.update(debugcommandsmod.command._table)
80 table.update(admin_commands_mod.command._table)
80 table.update(admin_commands_mod.command._table)
81
81
82 command = registrar.command(table)
82 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
83 INTENT_READONLY = registrar.INTENT_READONLY
84
84
85 # common command options
85 # common command options
86
86
87 globalopts = [
87 globalopts = [
88 (
88 (
89 b'R',
89 b'R',
90 b'repository',
90 b'repository',
91 b'',
91 b'',
92 _(b'repository root directory or name of overlay bundle file'),
92 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
93 _(b'REPO'),
94 ),
94 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
96 (
97 b'y',
97 b'y',
98 b'noninteractive',
98 b'noninteractive',
99 None,
99 None,
100 _(
100 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
101 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
102 ),
103 ),
103 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
106 (
107 b'',
107 b'',
108 b'color',
108 b'color',
109 b'',
109 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
111 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
113 _(b'TYPE'),
114 ),
114 ),
115 (
115 (
116 b'',
116 b'',
117 b'config',
117 b'config',
118 [],
118 [],
119 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
120 _(b'CONFIG'),
121 ),
121 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
123 (b'', b'debugger', None, _(b'start debugger')),
124 (
124 (
125 b'',
125 b'',
126 b'encoding',
126 b'encoding',
127 encoding.encoding,
127 encoding.encoding,
128 _(b'set the charset encoding'),
128 _(b'set the charset encoding'),
129 _(b'ENCODE'),
129 _(b'ENCODE'),
130 ),
130 ),
131 (
131 (
132 b'',
132 b'',
133 b'encodingmode',
133 b'encodingmode',
134 encoding.encodingmode,
134 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
135 _(b'set the charset encoding mode'),
136 _(b'MODE'),
136 _(b'MODE'),
137 ),
137 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
141 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
144 (
145 b'',
145 b'',
146 b'pager',
146 b'pager',
147 b'auto',
147 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
149 _(b'TYPE'),
150 ),
150 ),
151 ]
151 ]
152
152
153 dryrunopts = cmdutil.dryrunopts
153 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
154 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
155 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
156 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
157 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
158 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
159 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
160 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
161 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
162 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
163 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
164 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
165 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
166 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
167 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
168 debugrevlogopts = cmdutil.debugrevlogopts
169
169
170 # Commands start here, listed alphabetically
170 # Commands start here, listed alphabetically
171
171
172
172
173 @command(
173 @command(
174 b'abort',
174 b'abort',
175 dryrunopts,
175 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
177 helpbasic=True,
178 )
178 )
179 def abort(ui, repo, **opts):
179 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
180 """abort an unfinished operation (EXPERIMENTAL)
181
181
182 Aborts a multistep operation like graft, histedit, rebase, merge,
182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
183 and unshelve if they are in an unfinished state.
184
184
185 use --dry-run/-n to dry run the command.
185 use --dry-run/-n to dry run the command.
186 """
186 """
187 dryrun = opts.get('dry_run')
187 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
188 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
189 if not abortstate:
190 raise error.StateError(_(b'no operation in progress'))
190 raise error.StateError(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
191 if not abortstate.abortfunc:
192 raise error.InputError(
192 raise error.InputError(
193 (
193 (
194 _(b"%s in progress but does not support 'hg abort'")
194 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
195 % (abortstate._opname)
196 ),
196 ),
197 hint=abortstate.hint(),
197 hint=abortstate.hint(),
198 )
198 )
199 if dryrun:
199 if dryrun:
200 ui.status(
200 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
202 )
203 return
203 return
204 return abortstate.abortfunc(ui, repo)
204 return abortstate.abortfunc(ui, repo)
205
205
206
206
207 @command(
207 @command(
208 b'add',
208 b'add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
210 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
212 helpbasic=True,
213 inferrepo=True,
213 inferrepo=True,
214 )
214 )
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 with repo.wlock(), repo.dirstate.changing_files(repo):
258 with repo.wlock(), repo.dirstate.changing_files(repo):
259 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
260 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
261 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
262 return rejected and 1 or 0
262 return rejected and 1 or 0
263
263
264
264
265 @command(
265 @command(
266 b'addremove',
266 b'addremove',
267 similarityopts + subrepoopts + walkopts + dryrunopts,
267 similarityopts + subrepoopts + walkopts + dryrunopts,
268 _(b'[OPTION]... [FILE]...'),
268 _(b'[OPTION]... [FILE]...'),
269 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
270 inferrepo=True,
270 inferrepo=True,
271 )
271 )
272 def addremove(ui, repo, *pats, **opts):
272 def addremove(ui, repo, *pats, **opts):
273 """add all new files, delete all missing files
273 """add all new files, delete all missing files
274
274
275 Add all new files and remove all missing files from the
275 Add all new files and remove all missing files from the
276 repository.
276 repository.
277
277
278 Unless names are given, new files are ignored if they match any of
278 Unless names are given, new files are ignored if they match any of
279 the patterns in ``.hgignore``. As with add, these changes take
279 the patterns in ``.hgignore``. As with add, these changes take
280 effect at the next commit.
280 effect at the next commit.
281
281
282 Use the -s/--similarity option to detect renamed files. This
282 Use the -s/--similarity option to detect renamed files. This
283 option takes a percentage between 0 (disabled) and 100 (files must
283 option takes a percentage between 0 (disabled) and 100 (files must
284 be identical) as its parameter. With a parameter greater than 0,
284 be identical) as its parameter. With a parameter greater than 0,
285 this compares every removed file with every added file and records
285 this compares every removed file with every added file and records
286 those similar enough as renames. Detecting renamed files this way
286 those similar enough as renames. Detecting renamed files this way
287 can be expensive. After using this option, :hg:`status -C` can be
287 can be expensive. After using this option, :hg:`status -C` can be
288 used to check which files were identified as moved or renamed. If
288 used to check which files were identified as moved or renamed. If
289 not specified, -s/--similarity defaults to 100 and only renames of
289 not specified, -s/--similarity defaults to 100 and only renames of
290 identical files are detected.
290 identical files are detected.
291
291
292 .. container:: verbose
292 .. container:: verbose
293
293
294 Examples:
294 Examples:
295
295
296 - A number of files (bar.c and foo.c) are new,
296 - A number of files (bar.c and foo.c) are new,
297 while foobar.c has been removed (without using :hg:`remove`)
297 while foobar.c has been removed (without using :hg:`remove`)
298 from the repository::
298 from the repository::
299
299
300 $ ls
300 $ ls
301 bar.c foo.c
301 bar.c foo.c
302 $ hg status
302 $ hg status
303 ! foobar.c
303 ! foobar.c
304 ? bar.c
304 ? bar.c
305 ? foo.c
305 ? foo.c
306 $ hg addremove
306 $ hg addremove
307 adding bar.c
307 adding bar.c
308 adding foo.c
308 adding foo.c
309 removing foobar.c
309 removing foobar.c
310 $ hg status
310 $ hg status
311 A bar.c
311 A bar.c
312 A foo.c
312 A foo.c
313 R foobar.c
313 R foobar.c
314
314
315 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 - A file foobar.c was moved to foo.c without using :hg:`rename`.
316 Afterwards, it was edited slightly::
316 Afterwards, it was edited slightly::
317
317
318 $ ls
318 $ ls
319 foo.c
319 foo.c
320 $ hg status
320 $ hg status
321 ! foobar.c
321 ! foobar.c
322 ? foo.c
322 ? foo.c
323 $ hg addremove --similarity 90
323 $ hg addremove --similarity 90
324 removing foobar.c
324 removing foobar.c
325 adding foo.c
325 adding foo.c
326 recording removal of foobar.c as rename to foo.c (94% similar)
326 recording removal of foobar.c as rename to foo.c (94% similar)
327 $ hg status -C
327 $ hg status -C
328 A foo.c
328 A foo.c
329 foobar.c
329 foobar.c
330 R foobar.c
330 R foobar.c
331
331
332 Returns 0 if all files are successfully added.
332 Returns 0 if all files are successfully added.
333 """
333 """
334 opts = pycompat.byteskwargs(opts)
334 opts = pycompat.byteskwargs(opts)
335 if not opts.get(b'similarity'):
335 if not opts.get(b'similarity'):
336 opts[b'similarity'] = b'100'
336 opts[b'similarity'] = b'100'
337 with repo.wlock(), repo.dirstate.changing_files(repo):
337 with repo.wlock(), repo.dirstate.changing_files(repo):
338 matcher = scmutil.match(repo[None], pats, opts)
338 matcher = scmutil.match(repo[None], pats, opts)
339 relative = scmutil.anypats(pats, opts)
339 relative = scmutil.anypats(pats, opts)
340 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
340 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
341 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
341 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
342
342
343
343
344 @command(
344 @command(
345 b'annotate|blame',
345 b'annotate|blame',
346 [
346 [
347 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
347 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
348 (
348 (
349 b'',
349 b'',
350 b'follow',
350 b'follow',
351 None,
351 None,
352 _(b'follow copies/renames and list the filename (DEPRECATED)'),
352 _(b'follow copies/renames and list the filename (DEPRECATED)'),
353 ),
353 ),
354 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
354 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
355 (b'a', b'text', None, _(b'treat all files as text')),
355 (b'a', b'text', None, _(b'treat all files as text')),
356 (b'u', b'user', None, _(b'list the author (long with -v)')),
356 (b'u', b'user', None, _(b'list the author (long with -v)')),
357 (b'f', b'file', None, _(b'list the filename')),
357 (b'f', b'file', None, _(b'list the filename')),
358 (b'd', b'date', None, _(b'list the date (short with -q)')),
358 (b'd', b'date', None, _(b'list the date (short with -q)')),
359 (b'n', b'number', None, _(b'list the revision number (default)')),
359 (b'n', b'number', None, _(b'list the revision number (default)')),
360 (b'c', b'changeset', None, _(b'list the changeset')),
360 (b'c', b'changeset', None, _(b'list the changeset')),
361 (
361 (
362 b'l',
362 b'l',
363 b'line-number',
363 b'line-number',
364 None,
364 None,
365 _(b'show line number at the first appearance'),
365 _(b'show line number at the first appearance'),
366 ),
366 ),
367 (
367 (
368 b'',
368 b'',
369 b'skip',
369 b'skip',
370 [],
370 [],
371 _(b'revset to not display (EXPERIMENTAL)'),
371 _(b'revset to not display (EXPERIMENTAL)'),
372 _(b'REV'),
372 _(b'REV'),
373 ),
373 ),
374 (
374 (
375 b'L',
375 b'L',
376 b'line-range',
376 b'line-range',
377 [],
377 [],
378 _(b'follow line range of specified file (EXPERIMENTAL)'),
378 _(b'follow line range of specified file (EXPERIMENTAL)'),
379 _(b'FILE,RANGE'),
379 _(b'FILE,RANGE'),
380 ),
380 ),
381 ]
381 ]
382 + diffwsopts
382 + diffwsopts
383 + walkopts
383 + walkopts
384 + formatteropts,
384 + formatteropts,
385 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
385 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
386 helpcategory=command.CATEGORY_FILE_CONTENTS,
386 helpcategory=command.CATEGORY_FILE_CONTENTS,
387 helpbasic=True,
387 helpbasic=True,
388 inferrepo=True,
388 inferrepo=True,
389 )
389 )
390 def annotate(ui, repo, *pats, **opts):
390 def annotate(ui, repo, *pats, **opts):
391 """show changeset information by line for each file
391 """show changeset information by line for each file
392
392
393 List changes in files, showing the revision id responsible for
393 List changes in files, showing the revision id responsible for
394 each line.
394 each line.
395
395
396 This command is useful for discovering when a change was made and
396 This command is useful for discovering when a change was made and
397 by whom.
397 by whom.
398
398
399 If you include --file, --user, or --date, the revision number is
399 If you include --file, --user, or --date, the revision number is
400 suppressed unless you also include --number.
400 suppressed unless you also include --number.
401
401
402 Without the -a/--text option, annotate will avoid processing files
402 Without the -a/--text option, annotate will avoid processing files
403 it detects as binary. With -a, annotate will annotate the file
403 it detects as binary. With -a, annotate will annotate the file
404 anyway, although the results will probably be neither useful
404 anyway, although the results will probably be neither useful
405 nor desirable.
405 nor desirable.
406
406
407 .. container:: verbose
407 .. container:: verbose
408
408
409 Use -L/--line-range FILE,M:N options to filter the output to the lines
409 Use -L/--line-range FILE,M:N options to filter the output to the lines
410 from M to N in FILE. This option is incompatible with --no-follow and
410 from M to N in FILE. This option is incompatible with --no-follow and
411 cannot be combined with file pattern arguments. When combined with --rev
411 cannot be combined with file pattern arguments. When combined with --rev
412 the line ranges refer to the state of the file at the requested revision.
412 the line ranges refer to the state of the file at the requested revision.
413
413
414 .. container:: verbose
414 .. container:: verbose
415
415
416 Template:
416 Template:
417
417
418 The following keywords are supported in addition to the common template
418 The following keywords are supported in addition to the common template
419 keywords and functions. See also :hg:`help templates`.
419 keywords and functions. See also :hg:`help templates`.
420
420
421 :lines: List of lines with annotation data.
421 :lines: List of lines with annotation data.
422 :path: String. Repository-absolute path of the specified file.
422 :path: String. Repository-absolute path of the specified file.
423
423
424 And each entry of ``{lines}`` provides the following sub-keywords in
424 And each entry of ``{lines}`` provides the following sub-keywords in
425 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
425 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
426
426
427 :line: String. Line content.
427 :line: String. Line content.
428 :lineno: Integer. Line number at that revision.
428 :lineno: Integer. Line number at that revision.
429 :path: String. Repository-absolute path of the file at that revision.
429 :path: String. Repository-absolute path of the file at that revision.
430
430
431 See :hg:`help templates.operators` for the list expansion syntax.
431 See :hg:`help templates.operators` for the list expansion syntax.
432
432
433 Returns 0 on success.
433 Returns 0 on success.
434 """
434 """
435 opts = pycompat.byteskwargs(opts)
435 opts = pycompat.byteskwargs(opts)
436
436
437 linerange = opts.get(b'line_range')
437 linerange = opts.get(b'line_range')
438
438
439 if linerange and opts.get(b'no_follow'):
439 if linerange and opts.get(b'no_follow'):
440 raise error.InputError(
440 raise error.InputError(
441 _(b'--line-range is incompatible with --no-follow')
441 _(b'--line-range is incompatible with --no-follow')
442 )
442 )
443
443
444 if pats and linerange:
444 if pats and linerange:
445 raise error.InputError(
445 raise error.InputError(
446 _(b'cannot combine filename or pattern and --line-range')
446 _(b'cannot combine filename or pattern and --line-range')
447 )
447 )
448
448
449 if not pats and not linerange:
449 if not pats and not linerange:
450 raise error.InputError(
450 raise error.InputError(
451 _(b'at least one filename or pattern is required')
451 _(b'at least one filename or pattern is required')
452 )
452 )
453
453
454 if opts.get(b'follow'):
454 if opts.get(b'follow'):
455 # --follow is deprecated and now just an alias for -f/--file
455 # --follow is deprecated and now just an alias for -f/--file
456 # to mimic the behavior of Mercurial before version 1.5
456 # to mimic the behavior of Mercurial before version 1.5
457 opts[b'file'] = True
457 opts[b'file'] = True
458
458
459 if (
459 if (
460 not opts.get(b'user')
460 not opts.get(b'user')
461 and not opts.get(b'changeset')
461 and not opts.get(b'changeset')
462 and not opts.get(b'date')
462 and not opts.get(b'date')
463 and not opts.get(b'file')
463 and not opts.get(b'file')
464 ):
464 ):
465 opts[b'number'] = True
465 opts[b'number'] = True
466
466
467 linenumber = opts.get(b'line_number') is not None
467 linenumber = opts.get(b'line_number') is not None
468 if (
468 if (
469 linenumber
469 linenumber
470 and (not opts.get(b'changeset'))
470 and (not opts.get(b'changeset'))
471 and (not opts.get(b'number'))
471 and (not opts.get(b'number'))
472 ):
472 ):
473 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
473 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
474
474
475 rev = opts.get(b'rev')
475 rev = opts.get(b'rev')
476 if rev:
476 if rev:
477 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
477 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
478 ctx = logcmdutil.revsingle(repo, rev)
478 ctx = logcmdutil.revsingle(repo, rev)
479
479
480 if not pats:
480 if not pats:
481 pats = [
481 pats = [
482 fname
482 fname
483 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
483 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
484 ]
484 ]
485
485
486 ui.pager(b'annotate')
486 ui.pager(b'annotate')
487 rootfm = ui.formatter(b'annotate', opts)
487 rootfm = ui.formatter(b'annotate', opts)
488 if ui.debugflag:
488 if ui.debugflag:
489 shorthex = pycompat.identity
489 shorthex = pycompat.identity
490 else:
490 else:
491
491
492 def shorthex(h):
492 def shorthex(h):
493 return h[:12]
493 return h[:12]
494
494
495 if ui.quiet:
495 if ui.quiet:
496 datefunc = dateutil.shortdate
496 datefunc = dateutil.shortdate
497 else:
497 else:
498 datefunc = dateutil.datestr
498 datefunc = dateutil.datestr
499 if ctx.rev() is None:
499 if ctx.rev() is None:
500 if opts.get(b'changeset'):
500 if opts.get(b'changeset'):
501 # omit "+" suffix which is appended to node hex
501 # omit "+" suffix which is appended to node hex
502 def formatrev(rev):
502 def formatrev(rev):
503 if rev == wdirrev:
503 if rev == wdirrev:
504 return b'%d' % ctx.p1().rev()
504 return b'%d' % ctx.p1().rev()
505 else:
505 else:
506 return b'%d' % rev
506 return b'%d' % rev
507
507
508 else:
508 else:
509
509
510 def formatrev(rev):
510 def formatrev(rev):
511 if rev == wdirrev:
511 if rev == wdirrev:
512 return b'%d+' % ctx.p1().rev()
512 return b'%d+' % ctx.p1().rev()
513 else:
513 else:
514 return b'%d ' % rev
514 return b'%d ' % rev
515
515
516 def formathex(h):
516 def formathex(h):
517 if h == repo.nodeconstants.wdirhex:
517 if h == repo.nodeconstants.wdirhex:
518 return b'%s+' % shorthex(hex(ctx.p1().node()))
518 return b'%s+' % shorthex(hex(ctx.p1().node()))
519 else:
519 else:
520 return b'%s ' % shorthex(h)
520 return b'%s ' % shorthex(h)
521
521
522 else:
522 else:
523 formatrev = b'%d'.__mod__
523 formatrev = b'%d'.__mod__
524 formathex = shorthex
524 formathex = shorthex
525
525
526 opmap = [
526 opmap = [
527 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
527 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
528 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
528 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
529 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
529 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
530 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
530 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
531 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
531 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
532 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
532 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
533 ]
533 ]
534 opnamemap = {
534 opnamemap = {
535 b'rev': b'number',
535 b'rev': b'number',
536 b'node': b'changeset',
536 b'node': b'changeset',
537 b'path': b'file',
537 b'path': b'file',
538 b'lineno': b'line_number',
538 b'lineno': b'line_number',
539 }
539 }
540
540
541 if rootfm.isplain():
541 if rootfm.isplain():
542
542
543 def makefunc(get, fmt):
543 def makefunc(get, fmt):
544 return lambda x: fmt(get(x))
544 return lambda x: fmt(get(x))
545
545
546 else:
546 else:
547
547
548 def makefunc(get, fmt):
548 def makefunc(get, fmt):
549 return get
549 return get
550
550
551 datahint = rootfm.datahint()
551 datahint = rootfm.datahint()
552 funcmap = [
552 funcmap = [
553 (makefunc(get, fmt), sep)
553 (makefunc(get, fmt), sep)
554 for fn, sep, get, fmt in opmap
554 for fn, sep, get, fmt in opmap
555 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
555 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
556 ]
556 ]
557 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
557 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
558 fields = b' '.join(
558 fields = b' '.join(
559 fn
559 fn
560 for fn, sep, get, fmt in opmap
560 for fn, sep, get, fmt in opmap
561 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
561 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
562 )
562 )
563
563
564 def bad(x, y):
564 def bad(x, y):
565 raise error.InputError(b"%s: %s" % (x, y))
565 raise error.InputError(b"%s: %s" % (x, y))
566
566
567 m = scmutil.match(ctx, pats, opts, badfn=bad)
567 m = scmutil.match(ctx, pats, opts, badfn=bad)
568
568
569 follow = not opts.get(b'no_follow')
569 follow = not opts.get(b'no_follow')
570 diffopts = patch.difffeatureopts(
570 diffopts = patch.difffeatureopts(
571 ui, opts, section=b'annotate', whitespace=True
571 ui, opts, section=b'annotate', whitespace=True
572 )
572 )
573 skiprevs = opts.get(b'skip')
573 skiprevs = opts.get(b'skip')
574 if skiprevs:
574 if skiprevs:
575 skiprevs = logcmdutil.revrange(repo, skiprevs)
575 skiprevs = logcmdutil.revrange(repo, skiprevs)
576
576
577 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
577 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
578 for abs in ctx.walk(m):
578 for abs in ctx.walk(m):
579 fctx = ctx[abs]
579 fctx = ctx[abs]
580 rootfm.startitem()
580 rootfm.startitem()
581 rootfm.data(path=abs)
581 rootfm.data(path=abs)
582 if not opts.get(b'text') and fctx.isbinary():
582 if not opts.get(b'text') and fctx.isbinary():
583 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
583 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
584 continue
584 continue
585
585
586 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
586 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
587 lines = fctx.annotate(
587 lines = fctx.annotate(
588 follow=follow, skiprevs=skiprevs, diffopts=diffopts
588 follow=follow, skiprevs=skiprevs, diffopts=diffopts
589 )
589 )
590 if linerange:
590 if linerange:
591 _fname, (line_start, line_end) = list(
591 _fname, (line_start, line_end) = list(
592 logcmdutil._parselinerangeopt(repo, opts)
592 logcmdutil._parselinerangeopt(repo, opts)
593 )[0]
593 )[0]
594 lines = [
594 lines = [
595 line
595 line
596 for no, line in enumerate(lines)
596 for no, line in enumerate(lines)
597 if line_start <= no < line_end
597 if line_start <= no < line_end
598 ]
598 ]
599
599
600 if not lines:
600 if not lines:
601 fm.end()
601 fm.end()
602 continue
602 continue
603 formats = []
603 formats = []
604 pieces = []
604 pieces = []
605
605
606 for f, sep in funcmap:
606 for f, sep in funcmap:
607 l = [f(n) for n in lines]
607 l = [f(n) for n in lines]
608 if fm.isplain():
608 if fm.isplain():
609 sizes = [encoding.colwidth(x) for x in l]
609 sizes = [encoding.colwidth(x) for x in l]
610 ml = max(sizes)
610 ml = max(sizes)
611 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
611 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
612 else:
612 else:
613 formats.append([b'%s'] * len(l))
613 formats.append([b'%s'] * len(l))
614 pieces.append(l)
614 pieces.append(l)
615
615
616 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
616 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
617 fm.startitem()
617 fm.startitem()
618 fm.context(fctx=n.fctx)
618 fm.context(fctx=n.fctx)
619 fm.write(fields, b"".join(f), *p)
619 fm.write(fields, b"".join(f), *p)
620 if n.skip:
620 if n.skip:
621 fmt = b"* %s"
621 fmt = b"* %s"
622 else:
622 else:
623 fmt = b": %s"
623 fmt = b": %s"
624 fm.write(b'line', fmt, n.text)
624 fm.write(b'line', fmt, n.text)
625
625
626 if not lines[-1].text.endswith(b'\n'):
626 if not lines[-1].text.endswith(b'\n'):
627 fm.plain(b'\n')
627 fm.plain(b'\n')
628 fm.end()
628 fm.end()
629
629
630 rootfm.end()
630 rootfm.end()
631
631
632
632
633 @command(
633 @command(
634 b'archive',
634 b'archive',
635 [
635 [
636 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
636 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
637 (
637 (
638 b'p',
638 b'p',
639 b'prefix',
639 b'prefix',
640 b'',
640 b'',
641 _(b'directory prefix for files in archive'),
641 _(b'directory prefix for files in archive'),
642 _(b'PREFIX'),
642 _(b'PREFIX'),
643 ),
643 ),
644 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
644 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
645 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
645 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
646 ]
646 ]
647 + subrepoopts
647 + subrepoopts
648 + walkopts,
648 + walkopts,
649 _(b'[OPTION]... DEST'),
649 _(b'[OPTION]... DEST'),
650 helpcategory=command.CATEGORY_IMPORT_EXPORT,
650 helpcategory=command.CATEGORY_IMPORT_EXPORT,
651 )
651 )
652 def archive(ui, repo, dest, **opts):
652 def archive(ui, repo, dest, **opts):
653 """create an unversioned archive of a repository revision
653 """create an unversioned archive of a repository revision
654
654
655 By default, the revision used is the parent of the working
655 By default, the revision used is the parent of the working
656 directory; use -r/--rev to specify a different revision.
656 directory; use -r/--rev to specify a different revision.
657
657
658 The archive type is automatically detected based on file
658 The archive type is automatically detected based on file
659 extension (to override, use -t/--type).
659 extension (to override, use -t/--type).
660
660
661 .. container:: verbose
661 .. container:: verbose
662
662
663 Examples:
663 Examples:
664
664
665 - create a zip file containing the 1.0 release::
665 - create a zip file containing the 1.0 release::
666
666
667 hg archive -r 1.0 project-1.0.zip
667 hg archive -r 1.0 project-1.0.zip
668
668
669 - create a tarball excluding .hg files::
669 - create a tarball excluding .hg files::
670
670
671 hg archive project.tar.gz -X ".hg*"
671 hg archive project.tar.gz -X ".hg*"
672
672
673 Valid types are:
673 Valid types are:
674
674
675 :``files``: a directory full of files (default)
675 :``files``: a directory full of files (default)
676 :``tar``: tar archive, uncompressed
676 :``tar``: tar archive, uncompressed
677 :``tbz2``: tar archive, compressed using bzip2
677 :``tbz2``: tar archive, compressed using bzip2
678 :``tgz``: tar archive, compressed using gzip
678 :``tgz``: tar archive, compressed using gzip
679 :``txz``: tar archive, compressed using lzma (only in Python 3)
679 :``txz``: tar archive, compressed using lzma (only in Python 3)
680 :``uzip``: zip archive, uncompressed
680 :``uzip``: zip archive, uncompressed
681 :``zip``: zip archive, compressed using deflate
681 :``zip``: zip archive, compressed using deflate
682
682
683 The exact name of the destination archive or directory is given
683 The exact name of the destination archive or directory is given
684 using a format string; see :hg:`help export` for details.
684 using a format string; see :hg:`help export` for details.
685
685
686 Each member added to an archive file has a directory prefix
686 Each member added to an archive file has a directory prefix
687 prepended. Use -p/--prefix to specify a format string for the
687 prepended. Use -p/--prefix to specify a format string for the
688 prefix. The default is the basename of the archive, with suffixes
688 prefix. The default is the basename of the archive, with suffixes
689 removed.
689 removed.
690
690
691 Returns 0 on success.
691 Returns 0 on success.
692 """
692 """
693
693
694 rev = opts.get('rev')
694 rev = opts.get('rev')
695 if rev:
695 if rev:
696 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
696 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
697 ctx = logcmdutil.revsingle(repo, rev)
697 ctx = logcmdutil.revsingle(repo, rev)
698 if not ctx:
698 if not ctx:
699 raise error.InputError(
699 raise error.InputError(
700 _(b'no working directory: please specify a revision')
700 _(b'no working directory: please specify a revision')
701 )
701 )
702 node = ctx.node()
702 node = ctx.node()
703 dest = cmdutil.makefilename(ctx, dest)
703 dest = cmdutil.makefilename(ctx, dest)
704 if os.path.realpath(dest) == repo.root:
704 if os.path.realpath(dest) == repo.root:
705 raise error.InputError(_(b'repository root cannot be destination'))
705 raise error.InputError(_(b'repository root cannot be destination'))
706
706
707 kind = opts.get('type') or archival.guesskind(dest) or b'files'
707 kind = opts.get('type') or archival.guesskind(dest) or b'files'
708 prefix = opts.get('prefix')
708 prefix = opts.get('prefix')
709
709
710 if dest == b'-':
710 if dest == b'-':
711 if kind == b'files':
711 if kind == b'files':
712 raise error.InputError(_(b'cannot archive plain files to stdout'))
712 raise error.InputError(_(b'cannot archive plain files to stdout'))
713 dest = cmdutil.makefileobj(ctx, dest)
713 dest = cmdutil.makefileobj(ctx, dest)
714 if not prefix:
714 if not prefix:
715 prefix = os.path.basename(repo.root) + b'-%h'
715 prefix = os.path.basename(repo.root) + b'-%h'
716
716
717 prefix = cmdutil.makefilename(ctx, prefix)
717 prefix = cmdutil.makefilename(ctx, prefix)
718 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
718 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
719 archival.archive(
719 archival.archive(
720 repo,
720 repo,
721 dest,
721 dest,
722 node,
722 node,
723 kind,
723 kind,
724 not opts.get('no_decode'),
724 not opts.get('no_decode'),
725 match,
725 match,
726 prefix,
726 prefix,
727 subrepos=opts.get('subrepos'),
727 subrepos=opts.get('subrepos'),
728 )
728 )
729
729
730
730
731 @command(
731 @command(
732 b'backout',
732 b'backout',
733 [
733 [
734 (
734 (
735 b'',
735 b'',
736 b'merge',
736 b'merge',
737 None,
737 None,
738 _(b'merge with old dirstate parent after backout'),
738 _(b'merge with old dirstate parent after backout'),
739 ),
739 ),
740 (
740 (
741 b'',
741 b'',
742 b'commit',
742 b'commit',
743 None,
743 None,
744 _(b'commit if no conflicts were encountered (DEPRECATED)'),
744 _(b'commit if no conflicts were encountered (DEPRECATED)'),
745 ),
745 ),
746 (b'', b'no-commit', None, _(b'do not commit')),
746 (b'', b'no-commit', None, _(b'do not commit')),
747 (
747 (
748 b'',
748 b'',
749 b'parent',
749 b'parent',
750 b'',
750 b'',
751 _(b'parent to choose when backing out merge (DEPRECATED)'),
751 _(b'parent to choose when backing out merge (DEPRECATED)'),
752 _(b'REV'),
752 _(b'REV'),
753 ),
753 ),
754 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
754 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
755 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
755 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
756 ]
756 ]
757 + mergetoolopts
757 + mergetoolopts
758 + walkopts
758 + walkopts
759 + commitopts
759 + commitopts
760 + commitopts2,
760 + commitopts2,
761 _(b'[OPTION]... [-r] REV'),
761 _(b'[OPTION]... [-r] REV'),
762 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
762 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
763 )
763 )
764 def backout(ui, repo, node=None, rev=None, **opts):
764 def backout(ui, repo, node=None, rev=None, **opts):
765 """reverse effect of earlier changeset
765 """reverse effect of earlier changeset
766
766
767 Prepare a new changeset with the effect of REV undone in the
767 Prepare a new changeset with the effect of REV undone in the
768 current working directory. If no conflicts were encountered,
768 current working directory. If no conflicts were encountered,
769 it will be committed immediately.
769 it will be committed immediately.
770
770
771 If REV is the parent of the working directory, then this new changeset
771 If REV is the parent of the working directory, then this new changeset
772 is committed automatically (unless --no-commit is specified).
772 is committed automatically (unless --no-commit is specified).
773
773
774 .. note::
774 .. note::
775
775
776 :hg:`backout` cannot be used to fix either an unwanted or
776 :hg:`backout` cannot be used to fix either an unwanted or
777 incorrect merge.
777 incorrect merge.
778
778
779 .. container:: verbose
779 .. container:: verbose
780
780
781 Examples:
781 Examples:
782
782
783 - Reverse the effect of the parent of the working directory.
783 - Reverse the effect of the parent of the working directory.
784 This backout will be committed immediately::
784 This backout will be committed immediately::
785
785
786 hg backout -r .
786 hg backout -r .
787
787
788 - Reverse the effect of previous bad revision 23::
788 - Reverse the effect of previous bad revision 23::
789
789
790 hg backout -r 23
790 hg backout -r 23
791
791
792 - Reverse the effect of previous bad revision 23 and
792 - Reverse the effect of previous bad revision 23 and
793 leave changes uncommitted::
793 leave changes uncommitted::
794
794
795 hg backout -r 23 --no-commit
795 hg backout -r 23 --no-commit
796 hg commit -m "Backout revision 23"
796 hg commit -m "Backout revision 23"
797
797
798 By default, the pending changeset will have one parent,
798 By default, the pending changeset will have one parent,
799 maintaining a linear history. With --merge, the pending
799 maintaining a linear history. With --merge, the pending
800 changeset will instead have two parents: the old parent of the
800 changeset will instead have two parents: the old parent of the
801 working directory and a new child of REV that simply undoes REV.
801 working directory and a new child of REV that simply undoes REV.
802
802
803 Before version 1.7, the behavior without --merge was equivalent
803 Before version 1.7, the behavior without --merge was equivalent
804 to specifying --merge followed by :hg:`update --clean .` to
804 to specifying --merge followed by :hg:`update --clean .` to
805 cancel the merge and leave the child of REV as a head to be
805 cancel the merge and leave the child of REV as a head to be
806 merged separately.
806 merged separately.
807
807
808 See :hg:`help dates` for a list of formats valid for -d/--date.
808 See :hg:`help dates` for a list of formats valid for -d/--date.
809
809
810 See :hg:`help revert` for a way to restore files to the state
810 See :hg:`help revert` for a way to restore files to the state
811 of another revision.
811 of another revision.
812
812
813 Returns 0 on success, 1 if nothing to backout or there are unresolved
813 Returns 0 on success, 1 if nothing to backout or there are unresolved
814 files.
814 files.
815 """
815 """
816 with repo.wlock(), repo.lock():
816 with repo.wlock(), repo.lock():
817 return _dobackout(ui, repo, node, rev, **opts)
817 return _dobackout(ui, repo, node, rev, **opts)
818
818
819
819
820 def _dobackout(ui, repo, node=None, rev=None, **opts):
820 def _dobackout(ui, repo, node=None, rev=None, **opts):
821 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
821 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
822
822
823 if rev and node:
823 if rev and node:
824 raise error.InputError(_(b"please specify just one revision"))
824 raise error.InputError(_(b"please specify just one revision"))
825
825
826 if not rev:
826 if not rev:
827 rev = node
827 rev = node
828
828
829 if not rev:
829 if not rev:
830 raise error.InputError(_(b"please specify a revision to backout"))
830 raise error.InputError(_(b"please specify a revision to backout"))
831
831
832 date = opts.get('date')
832 date = opts.get('date')
833 if date:
833 if date:
834 opts['date'] = dateutil.parsedate(date)
834 opts['date'] = dateutil.parsedate(date)
835
835
836 cmdutil.checkunfinished(repo)
836 cmdutil.checkunfinished(repo)
837 cmdutil.bailifchanged(repo)
837 cmdutil.bailifchanged(repo)
838 ctx = logcmdutil.revsingle(repo, rev)
838 ctx = logcmdutil.revsingle(repo, rev)
839 node = ctx.node()
839 node = ctx.node()
840
840
841 op1, op2 = repo.dirstate.parents()
841 op1, op2 = repo.dirstate.parents()
842 if not repo.changelog.isancestor(node, op1):
842 if not repo.changelog.isancestor(node, op1):
843 raise error.InputError(
843 raise error.InputError(
844 _(b'cannot backout change that is not an ancestor')
844 _(b'cannot backout change that is not an ancestor')
845 )
845 )
846
846
847 p1, p2 = repo.changelog.parents(node)
847 p1, p2 = repo.changelog.parents(node)
848 if p1 == repo.nullid:
848 if p1 == repo.nullid:
849 raise error.InputError(_(b'cannot backout a change with no parents'))
849 raise error.InputError(_(b'cannot backout a change with no parents'))
850 if p2 != repo.nullid:
850 if p2 != repo.nullid:
851 if not opts.get('parent'):
851 if not opts.get('parent'):
852 raise error.InputError(_(b'cannot backout a merge changeset'))
852 raise error.InputError(_(b'cannot backout a merge changeset'))
853 p = repo.lookup(opts['parent'])
853 p = repo.lookup(opts['parent'])
854 if p not in (p1, p2):
854 if p not in (p1, p2):
855 raise error.InputError(
855 raise error.InputError(
856 _(b'%s is not a parent of %s') % (short(p), short(node))
856 _(b'%s is not a parent of %s') % (short(p), short(node))
857 )
857 )
858 parent = p
858 parent = p
859 else:
859 else:
860 if opts.get('parent'):
860 if opts.get('parent'):
861 raise error.InputError(
861 raise error.InputError(
862 _(b'cannot use --parent on non-merge changeset')
862 _(b'cannot use --parent on non-merge changeset')
863 )
863 )
864 parent = p1
864 parent = p1
865
865
866 # the backout should appear on the same branch
866 # the backout should appear on the same branch
867 branch = repo.dirstate.branch()
867 branch = repo.dirstate.branch()
868 bheads = repo.branchheads(branch)
868 bheads = repo.branchheads(branch)
869 rctx = scmutil.revsingle(repo, hex(parent))
869 rctx = scmutil.revsingle(repo, hex(parent))
870 if not opts.get('merge') and op1 != node:
870 if not opts.get('merge') and op1 != node:
871 with repo.transaction(b"backout"):
871 with repo.transaction(b"backout"):
872 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
872 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
873 with ui.configoverride(overrides, b'backout'):
873 with ui.configoverride(overrides, b'backout'):
874 stats = mergemod.back_out(ctx, parent=repo[parent])
874 stats = mergemod.back_out(ctx, parent=repo[parent])
875 repo.setparents(op1, op2)
875 repo.setparents(op1, op2)
876 hg._showstats(repo, stats)
876 hg._showstats(repo, stats)
877 if stats.unresolvedcount:
877 if stats.unresolvedcount:
878 repo.ui.status(
878 repo.ui.status(
879 _(b"use 'hg resolve' to retry unresolved file merges\n")
879 _(b"use 'hg resolve' to retry unresolved file merges\n")
880 )
880 )
881 return 1
881 return 1
882 else:
882 else:
883 hg.clean(repo, node, show_stats=False)
883 hg.clean(repo, node, show_stats=False)
884 repo.dirstate.setbranch(branch, repo.currenttransaction())
884 repo.dirstate.setbranch(branch, repo.currenttransaction())
885 cmdutil.revert(ui, repo, rctx)
885 cmdutil.revert(ui, repo, rctx)
886
886
887 if opts.get('no_commit'):
887 if opts.get('no_commit'):
888 msg = _(b"changeset %s backed out, don't forget to commit.\n")
888 msg = _(b"changeset %s backed out, don't forget to commit.\n")
889 ui.status(msg % short(node))
889 ui.status(msg % short(node))
890 return 0
890 return 0
891
891
892 def commitfunc(ui, repo, message, match, opts):
892 def commitfunc(ui, repo, message, match, opts):
893 editform = b'backout'
893 editform = b'backout'
894 e = cmdutil.getcommiteditor(
894 e = cmdutil.getcommiteditor(
895 editform=editform, **pycompat.strkwargs(opts)
895 editform=editform, **pycompat.strkwargs(opts)
896 )
896 )
897 if not message:
897 if not message:
898 # we don't translate commit messages
898 # we don't translate commit messages
899 message = b"Backed out changeset %s" % short(node)
899 message = b"Backed out changeset %s" % short(node)
900 e = cmdutil.getcommiteditor(edit=True, editform=editform)
900 e = cmdutil.getcommiteditor(edit=True, editform=editform)
901 return repo.commit(
901 return repo.commit(
902 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
902 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
903 )
903 )
904
904
905 # save to detect changes
905 # save to detect changes
906 tip = repo.changelog.tip()
906 tip = repo.changelog.tip()
907
907
908 newnode = cmdutil.commit(
908 newnode = cmdutil.commit(
909 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
909 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
910 )
910 )
911 if not newnode:
911 if not newnode:
912 ui.status(_(b"nothing changed\n"))
912 ui.status(_(b"nothing changed\n"))
913 return 1
913 return 1
914 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
914 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
915
915
916 def nice(node):
916 def nice(node):
917 return b'%d:%s' % (repo.changelog.rev(node), short(node))
917 return b'%d:%s' % (repo.changelog.rev(node), short(node))
918
918
919 ui.status(
919 ui.status(
920 _(b'changeset %s backs out changeset %s\n')
920 _(b'changeset %s backs out changeset %s\n')
921 % (nice(newnode), nice(node))
921 % (nice(newnode), nice(node))
922 )
922 )
923 if opts.get('merge') and op1 != node:
923 if opts.get('merge') and op1 != node:
924 hg.clean(repo, op1, show_stats=False)
924 hg.clean(repo, op1, show_stats=False)
925 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
925 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
926 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
926 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
927 with ui.configoverride(overrides, b'backout'):
927 with ui.configoverride(overrides, b'backout'):
928 return hg.merge(repo[b'tip'])
928 return hg.merge(repo[b'tip'])
929 return 0
929 return 0
930
930
931
931
932 @command(
932 @command(
933 b'bisect',
933 b'bisect',
934 [
934 [
935 (b'r', b'reset', False, _(b'reset bisect state')),
935 (b'r', b'reset', False, _(b'reset bisect state')),
936 (b'g', b'good', False, _(b'mark changeset good')),
936 (b'g', b'good', False, _(b'mark changeset good')),
937 (b'b', b'bad', False, _(b'mark changeset bad')),
937 (b'b', b'bad', False, _(b'mark changeset bad')),
938 (b's', b'skip', False, _(b'skip testing changeset')),
938 (b's', b'skip', False, _(b'skip testing changeset')),
939 (b'e', b'extend', False, _(b'extend the bisect range')),
939 (b'e', b'extend', False, _(b'extend the bisect range')),
940 (
940 (
941 b'c',
941 b'c',
942 b'command',
942 b'command',
943 b'',
943 b'',
944 _(b'use command to check changeset state'),
944 _(b'use command to check changeset state'),
945 _(b'CMD'),
945 _(b'CMD'),
946 ),
946 ),
947 (b'U', b'noupdate', False, _(b'do not update to target')),
947 (b'U', b'noupdate', False, _(b'do not update to target')),
948 ],
948 ],
949 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
949 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
950 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
950 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
951 )
951 )
952 def bisect(
952 def bisect(
953 ui,
953 ui,
954 repo,
954 repo,
955 positional_1=None,
955 positional_1=None,
956 positional_2=None,
956 positional_2=None,
957 command=None,
957 command=None,
958 reset=None,
958 reset=None,
959 good=None,
959 good=None,
960 bad=None,
960 bad=None,
961 skip=None,
961 skip=None,
962 extend=None,
962 extend=None,
963 noupdate=None,
963 noupdate=None,
964 ):
964 ):
965 """subdivision search of changesets
965 """subdivision search of changesets
966
966
967 This command helps to find changesets which introduce problems. To
967 This command helps to find changesets which introduce problems. To
968 use, mark the earliest changeset you know exhibits the problem as
968 use, mark the earliest changeset you know exhibits the problem as
969 bad, then mark the latest changeset which is free from the problem
969 bad, then mark the latest changeset which is free from the problem
970 as good. Bisect will update your working directory to a revision
970 as good. Bisect will update your working directory to a revision
971 for testing (unless the -U/--noupdate option is specified). Once
971 for testing (unless the -U/--noupdate option is specified). Once
972 you have performed tests, mark the working directory as good or
972 you have performed tests, mark the working directory as good or
973 bad, and bisect will either update to another candidate changeset
973 bad, and bisect will either update to another candidate changeset
974 or announce that it has found the bad revision.
974 or announce that it has found the bad revision.
975
975
976 As a shortcut, you can also use the revision argument to mark a
976 As a shortcut, you can also use the revision argument to mark a
977 revision as good or bad without checking it out first.
977 revision as good or bad without checking it out first.
978
978
979 If you supply a command, it will be used for automatic bisection.
979 If you supply a command, it will be used for automatic bisection.
980 The environment variable HG_NODE will contain the ID of the
980 The environment variable HG_NODE will contain the ID of the
981 changeset being tested. The exit status of the command will be
981 changeset being tested. The exit status of the command will be
982 used to mark revisions as good or bad: status 0 means good, 125
982 used to mark revisions as good or bad: status 0 means good, 125
983 means to skip the revision, 127 (command not found) will abort the
983 means to skip the revision, 127 (command not found) will abort the
984 bisection, and any other non-zero exit status means the revision
984 bisection, and any other non-zero exit status means the revision
985 is bad.
985 is bad.
986
986
987 .. container:: verbose
987 .. container:: verbose
988
988
989 Some examples:
989 Some examples:
990
990
991 - start a bisection with known bad revision 34, and good revision 12::
991 - start a bisection with known bad revision 34, and good revision 12::
992
992
993 hg bisect --bad 34
993 hg bisect --bad 34
994 hg bisect --good 12
994 hg bisect --good 12
995
995
996 - advance the current bisection by marking current revision as good or
996 - advance the current bisection by marking current revision as good or
997 bad::
997 bad::
998
998
999 hg bisect --good
999 hg bisect --good
1000 hg bisect --bad
1000 hg bisect --bad
1001
1001
1002 - mark the current revision, or a known revision, to be skipped (e.g. if
1002 - mark the current revision, or a known revision, to be skipped (e.g. if
1003 that revision is not usable because of another issue)::
1003 that revision is not usable because of another issue)::
1004
1004
1005 hg bisect --skip
1005 hg bisect --skip
1006 hg bisect --skip 23
1006 hg bisect --skip 23
1007
1007
1008 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1008 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1009
1009
1010 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1010 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1011
1011
1012 - forget the current bisection::
1012 - forget the current bisection::
1013
1013
1014 hg bisect --reset
1014 hg bisect --reset
1015
1015
1016 - use 'make && make tests' to automatically find the first broken
1016 - use 'make && make tests' to automatically find the first broken
1017 revision::
1017 revision::
1018
1018
1019 hg bisect --reset
1019 hg bisect --reset
1020 hg bisect --bad 34
1020 hg bisect --bad 34
1021 hg bisect --good 12
1021 hg bisect --good 12
1022 hg bisect --command "make && make tests"
1022 hg bisect --command "make && make tests"
1023
1023
1024 - see all changesets whose states are already known in the current
1024 - see all changesets whose states are already known in the current
1025 bisection::
1025 bisection::
1026
1026
1027 hg log -r "bisect(pruned)"
1027 hg log -r "bisect(pruned)"
1028
1028
1029 - see the changeset currently being bisected (especially useful
1029 - see the changeset currently being bisected (especially useful
1030 if running with -U/--noupdate)::
1030 if running with -U/--noupdate)::
1031
1031
1032 hg log -r "bisect(current)"
1032 hg log -r "bisect(current)"
1033
1033
1034 - see all changesets that took part in the current bisection::
1034 - see all changesets that took part in the current bisection::
1035
1035
1036 hg log -r "bisect(range)"
1036 hg log -r "bisect(range)"
1037
1037
1038 - you can even get a nice graph::
1038 - you can even get a nice graph::
1039
1039
1040 hg log --graph -r "bisect(range)"
1040 hg log --graph -r "bisect(range)"
1041
1041
1042 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1042 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1043
1043
1044 Returns 0 on success.
1044 Returns 0 on success.
1045 """
1045 """
1046 rev = []
1046 rev = []
1047 # backward compatibility
1047 # backward compatibility
1048 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1048 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1049 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1049 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1050 cmd = positional_1
1050 cmd = positional_1
1051 rev.append(positional_2)
1051 rev.append(positional_2)
1052 if cmd == b"good":
1052 if cmd == b"good":
1053 good = True
1053 good = True
1054 elif cmd == b"bad":
1054 elif cmd == b"bad":
1055 bad = True
1055 bad = True
1056 else:
1056 else:
1057 reset = True
1057 reset = True
1058 elif positional_2:
1058 elif positional_2:
1059 raise error.InputError(_(b'incompatible arguments'))
1059 raise error.InputError(_(b'incompatible arguments'))
1060 elif positional_1 is not None:
1060 elif positional_1 is not None:
1061 rev.append(positional_1)
1061 rev.append(positional_1)
1062
1062
1063 incompatibles = {
1063 incompatibles = {
1064 b'--bad': bad,
1064 b'--bad': bad,
1065 b'--command': bool(command),
1065 b'--command': bool(command),
1066 b'--extend': extend,
1066 b'--extend': extend,
1067 b'--good': good,
1067 b'--good': good,
1068 b'--reset': reset,
1068 b'--reset': reset,
1069 b'--skip': skip,
1069 b'--skip': skip,
1070 }
1070 }
1071
1071
1072 enabled = [x for x in incompatibles if incompatibles[x]]
1072 enabled = [x for x in incompatibles if incompatibles[x]]
1073
1073
1074 if len(enabled) > 1:
1074 if len(enabled) > 1:
1075 raise error.InputError(
1075 raise error.InputError(
1076 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1076 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1077 )
1077 )
1078
1078
1079 if reset:
1079 if reset:
1080 hbisect.resetstate(repo)
1080 hbisect.resetstate(repo)
1081 return
1081 return
1082
1082
1083 state = hbisect.load_state(repo)
1083 state = hbisect.load_state(repo)
1084
1084
1085 if rev:
1085 if rev:
1086 revs = logcmdutil.revrange(repo, rev)
1086 revs = logcmdutil.revrange(repo, rev)
1087 goodnodes = state[b'good']
1087 goodnodes = state[b'good']
1088 badnodes = state[b'bad']
1088 badnodes = state[b'bad']
1089 if goodnodes and badnodes:
1089 if goodnodes and badnodes:
1090 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1090 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1091 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1091 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1092 revs = candidates & revs
1092 revs = candidates & revs
1093 nodes = [repo.changelog.node(i) for i in revs]
1093 nodes = [repo.changelog.node(i) for i in revs]
1094 else:
1094 else:
1095 nodes = [repo.lookup(b'.')]
1095 nodes = [repo.lookup(b'.')]
1096
1096
1097 # update state
1097 # update state
1098 if good or bad or skip:
1098 if good or bad or skip:
1099 if good:
1099 if good:
1100 state[b'good'] += nodes
1100 state[b'good'] += nodes
1101 elif bad:
1101 elif bad:
1102 state[b'bad'] += nodes
1102 state[b'bad'] += nodes
1103 elif skip:
1103 elif skip:
1104 state[b'skip'] += nodes
1104 state[b'skip'] += nodes
1105 hbisect.save_state(repo, state)
1105 hbisect.save_state(repo, state)
1106 if not (state[b'good'] and state[b'bad']):
1106 if not (state[b'good'] and state[b'bad']):
1107 return
1107 return
1108
1108
1109 def mayupdate(repo, node, show_stats=True):
1109 def mayupdate(repo, node, show_stats=True):
1110 """common used update sequence"""
1110 """common used update sequence"""
1111 if noupdate:
1111 if noupdate:
1112 return
1112 return
1113 cmdutil.checkunfinished(repo)
1113 cmdutil.checkunfinished(repo)
1114 cmdutil.bailifchanged(repo)
1114 cmdutil.bailifchanged(repo)
1115 return hg.clean(repo, node, show_stats=show_stats)
1115 return hg.clean(repo, node, show_stats=show_stats)
1116
1116
1117 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1117 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1118
1118
1119 if command:
1119 if command:
1120 changesets = 1
1120 changesets = 1
1121 if noupdate:
1121 if noupdate:
1122 try:
1122 try:
1123 node = state[b'current'][0]
1123 node = state[b'current'][0]
1124 except LookupError:
1124 except LookupError:
1125 raise error.StateError(
1125 raise error.StateError(
1126 _(
1126 _(
1127 b'current bisect revision is unknown - '
1127 b'current bisect revision is unknown - '
1128 b'start a new bisect to fix'
1128 b'start a new bisect to fix'
1129 )
1129 )
1130 )
1130 )
1131 else:
1131 else:
1132 node, p2 = repo.dirstate.parents()
1132 node, p2 = repo.dirstate.parents()
1133 if p2 != repo.nullid:
1133 if p2 != repo.nullid:
1134 raise error.StateError(_(b'current bisect revision is a merge'))
1134 raise error.StateError(_(b'current bisect revision is a merge'))
1135 if rev:
1135 if rev:
1136 if not nodes:
1136 if not nodes:
1137 raise error.InputError(_(b'empty revision set'))
1137 raise error.InputError(_(b'empty revision set'))
1138 node = repo[nodes[-1]].node()
1138 node = repo[nodes[-1]].node()
1139 with hbisect.restore_state(repo, state, node):
1139 with hbisect.restore_state(repo, state, node):
1140 while changesets:
1140 while changesets:
1141 # update state
1141 # update state
1142 state[b'current'] = [node]
1142 state[b'current'] = [node]
1143 hbisect.save_state(repo, state)
1143 hbisect.save_state(repo, state)
1144 status = ui.system(
1144 status = ui.system(
1145 command,
1145 command,
1146 environ={b'HG_NODE': hex(node)},
1146 environ={b'HG_NODE': hex(node)},
1147 blockedtag=b'bisect_check',
1147 blockedtag=b'bisect_check',
1148 )
1148 )
1149 if status == 125:
1149 if status == 125:
1150 transition = b"skip"
1150 transition = b"skip"
1151 elif status == 0:
1151 elif status == 0:
1152 transition = b"good"
1152 transition = b"good"
1153 # status < 0 means process was killed
1153 # status < 0 means process was killed
1154 elif status == 127:
1154 elif status == 127:
1155 raise error.Abort(_(b"failed to execute %s") % command)
1155 raise error.Abort(_(b"failed to execute %s") % command)
1156 elif status < 0:
1156 elif status < 0:
1157 raise error.Abort(_(b"%s killed") % command)
1157 raise error.Abort(_(b"%s killed") % command)
1158 else:
1158 else:
1159 transition = b"bad"
1159 transition = b"bad"
1160 state[transition].append(node)
1160 state[transition].append(node)
1161 ctx = repo[node]
1161 ctx = repo[node]
1162 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1162 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1163 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1163 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1164 hbisect.checkstate(state)
1164 hbisect.checkstate(state)
1165 # bisect
1165 # bisect
1166 nodes, changesets, bgood = hbisect.bisect(repo, state)
1166 nodes, changesets, bgood = hbisect.bisect(repo, state)
1167 # update to next check
1167 # update to next check
1168 node = nodes[0]
1168 node = nodes[0]
1169 mayupdate(repo, node, show_stats=False)
1169 mayupdate(repo, node, show_stats=False)
1170 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1170 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1171 return
1171 return
1172
1172
1173 hbisect.checkstate(state)
1173 hbisect.checkstate(state)
1174
1174
1175 # actually bisect
1175 # actually bisect
1176 nodes, changesets, good = hbisect.bisect(repo, state)
1176 nodes, changesets, good = hbisect.bisect(repo, state)
1177 if extend:
1177 if extend:
1178 if not changesets:
1178 if not changesets:
1179 extendctx = hbisect.extendrange(repo, state, nodes, good)
1179 extendctx = hbisect.extendrange(repo, state, nodes, good)
1180 if extendctx is not None:
1180 if extendctx is not None:
1181 ui.write(
1181 ui.write(
1182 _(b"Extending search to changeset %s\n")
1182 _(b"Extending search to changeset %s\n")
1183 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1183 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1184 )
1184 )
1185 state[b'current'] = [extendctx.node()]
1185 state[b'current'] = [extendctx.node()]
1186 hbisect.save_state(repo, state)
1186 hbisect.save_state(repo, state)
1187 return mayupdate(repo, extendctx.node())
1187 return mayupdate(repo, extendctx.node())
1188 raise error.StateError(_(b"nothing to extend"))
1188 raise error.StateError(_(b"nothing to extend"))
1189
1189
1190 if changesets == 0:
1190 if changesets == 0:
1191 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1191 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1192 else:
1192 else:
1193 assert len(nodes) == 1 # only a single node can be tested next
1193 assert len(nodes) == 1 # only a single node can be tested next
1194 node = nodes[0]
1194 node = nodes[0]
1195 # compute the approximate number of remaining tests
1195 # compute the approximate number of remaining tests
1196 tests, size = 0, 2
1196 tests, size = 0, 2
1197 while size <= changesets:
1197 while size <= changesets:
1198 tests, size = tests + 1, size * 2
1198 tests, size = tests + 1, size * 2
1199 rev = repo.changelog.rev(node)
1199 rev = repo.changelog.rev(node)
1200 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1200 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1201 ui.write(
1201 ui.write(
1202 _(
1202 _(
1203 b"Testing changeset %s "
1203 b"Testing changeset %s "
1204 b"(%d changesets remaining, ~%d tests)\n"
1204 b"(%d changesets remaining, ~%d tests)\n"
1205 )
1205 )
1206 % (summary, changesets, tests)
1206 % (summary, changesets, tests)
1207 )
1207 )
1208 state[b'current'] = [node]
1208 state[b'current'] = [node]
1209 hbisect.save_state(repo, state)
1209 hbisect.save_state(repo, state)
1210 return mayupdate(repo, node)
1210 return mayupdate(repo, node)
1211
1211
1212
1212
1213 @command(
1213 @command(
1214 b'bookmarks|bookmark',
1214 b'bookmarks|bookmark',
1215 [
1215 [
1216 (b'f', b'force', False, _(b'force')),
1216 (b'f', b'force', False, _(b'force')),
1217 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1217 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1218 (b'd', b'delete', False, _(b'delete a given bookmark')),
1218 (b'd', b'delete', False, _(b'delete a given bookmark')),
1219 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1219 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1220 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1220 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1221 (b'l', b'list', False, _(b'list existing bookmarks')),
1221 (b'l', b'list', False, _(b'list existing bookmarks')),
1222 ]
1222 ]
1223 + formatteropts,
1223 + formatteropts,
1224 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1224 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1225 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1225 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1226 )
1226 )
1227 def bookmark(ui, repo, *names, **opts):
1227 def bookmark(ui, repo, *names, **opts):
1228 """create a new bookmark or list existing bookmarks
1228 """create a new bookmark or list existing bookmarks
1229
1229
1230 Bookmarks are labels on changesets to help track lines of development.
1230 Bookmarks are labels on changesets to help track lines of development.
1231 Bookmarks are unversioned and can be moved, renamed and deleted.
1231 Bookmarks are unversioned and can be moved, renamed and deleted.
1232 Deleting or moving a bookmark has no effect on the associated changesets.
1232 Deleting or moving a bookmark has no effect on the associated changesets.
1233
1233
1234 Creating or updating to a bookmark causes it to be marked as 'active'.
1234 Creating or updating to a bookmark causes it to be marked as 'active'.
1235 The active bookmark is indicated with a '*'.
1235 The active bookmark is indicated with a '*'.
1236 When a commit is made, the active bookmark will advance to the new commit.
1236 When a commit is made, the active bookmark will advance to the new commit.
1237 A plain :hg:`update` will also advance an active bookmark, if possible.
1237 A plain :hg:`update` will also advance an active bookmark, if possible.
1238 Updating away from a bookmark will cause it to be deactivated.
1238 Updating away from a bookmark will cause it to be deactivated.
1239
1239
1240 Bookmarks can be pushed and pulled between repositories (see
1240 Bookmarks can be pushed and pulled between repositories (see
1241 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1241 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1242 diverged, a new 'divergent bookmark' of the form 'name@path' will
1242 diverged, a new 'divergent bookmark' of the form 'name@path' will
1243 be created. Using :hg:`merge` will resolve the divergence.
1243 be created. Using :hg:`merge` will resolve the divergence.
1244
1244
1245 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1245 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1246 the active bookmark's name.
1246 the active bookmark's name.
1247
1247
1248 A bookmark named '@' has the special property that :hg:`clone` will
1248 A bookmark named '@' has the special property that :hg:`clone` will
1249 check it out by default if it exists.
1249 check it out by default if it exists.
1250
1250
1251 .. container:: verbose
1251 .. container:: verbose
1252
1252
1253 Template:
1253 Template:
1254
1254
1255 The following keywords are supported in addition to the common template
1255 The following keywords are supported in addition to the common template
1256 keywords and functions such as ``{bookmark}``. See also
1256 keywords and functions such as ``{bookmark}``. See also
1257 :hg:`help templates`.
1257 :hg:`help templates`.
1258
1258
1259 :active: Boolean. True if the bookmark is active.
1259 :active: Boolean. True if the bookmark is active.
1260
1260
1261 Examples:
1261 Examples:
1262
1262
1263 - create an active bookmark for a new line of development::
1263 - create an active bookmark for a new line of development::
1264
1264
1265 hg book new-feature
1265 hg book new-feature
1266
1266
1267 - create an inactive bookmark as a place marker::
1267 - create an inactive bookmark as a place marker::
1268
1268
1269 hg book -i reviewed
1269 hg book -i reviewed
1270
1270
1271 - create an inactive bookmark on another changeset::
1271 - create an inactive bookmark on another changeset::
1272
1272
1273 hg book -r .^ tested
1273 hg book -r .^ tested
1274
1274
1275 - rename bookmark turkey to dinner::
1275 - rename bookmark turkey to dinner::
1276
1276
1277 hg book -m turkey dinner
1277 hg book -m turkey dinner
1278
1278
1279 - move the '@' bookmark from another branch::
1279 - move the '@' bookmark from another branch::
1280
1280
1281 hg book -f @
1281 hg book -f @
1282
1282
1283 - print only the active bookmark name::
1283 - print only the active bookmark name::
1284
1284
1285 hg book -ql .
1285 hg book -ql .
1286 """
1286 """
1287 force = opts.get('force')
1287 force = opts.get('force')
1288 rev = opts.get('rev')
1288 rev = opts.get('rev')
1289 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1289 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1290
1290
1291 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1291 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1292 if action:
1292 if action:
1293 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1293 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1294 elif names or rev:
1294 elif names or rev:
1295 action = 'add'
1295 action = 'add'
1296 elif inactive:
1296 elif inactive:
1297 action = 'inactive' # meaning deactivate
1297 action = 'inactive' # meaning deactivate
1298 else:
1298 else:
1299 action = 'list'
1299 action = 'list'
1300
1300
1301 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1301 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1302 if not names and action in {'add', 'delete'}:
1302 if not names and action in {'add', 'delete'}:
1303 raise error.InputError(_(b"bookmark name required"))
1303 raise error.InputError(_(b"bookmark name required"))
1304
1304
1305 if action in {'add', 'delete', 'rename', 'inactive'}:
1305 if action in {'add', 'delete', 'rename', 'inactive'}:
1306 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1306 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1307 if action == 'delete':
1307 if action == 'delete':
1308 names = pycompat.maplist(repo._bookmarks.expandname, names)
1308 names = pycompat.maplist(repo._bookmarks.expandname, names)
1309 bookmarks.delete(repo, tr, names)
1309 bookmarks.delete(repo, tr, names)
1310 elif action == 'rename':
1310 elif action == 'rename':
1311 if not names:
1311 if not names:
1312 raise error.InputError(_(b"new bookmark name required"))
1312 raise error.InputError(_(b"new bookmark name required"))
1313 elif len(names) > 1:
1313 elif len(names) > 1:
1314 raise error.InputError(
1314 raise error.InputError(
1315 _(b"only one new bookmark name allowed")
1315 _(b"only one new bookmark name allowed")
1316 )
1316 )
1317 oldname = repo._bookmarks.expandname(opts['rename'])
1317 oldname = repo._bookmarks.expandname(opts['rename'])
1318 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1318 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1319 elif action == 'add':
1319 elif action == 'add':
1320 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1320 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1321 elif action == 'inactive':
1321 elif action == 'inactive':
1322 if len(repo._bookmarks) == 0:
1322 if len(repo._bookmarks) == 0:
1323 ui.status(_(b"no bookmarks set\n"))
1323 ui.status(_(b"no bookmarks set\n"))
1324 elif not repo._activebookmark:
1324 elif not repo._activebookmark:
1325 ui.status(_(b"no active bookmark\n"))
1325 ui.status(_(b"no active bookmark\n"))
1326 else:
1326 else:
1327 bookmarks.deactivate(repo)
1327 bookmarks.deactivate(repo)
1328 elif action == 'list':
1328 elif action == 'list':
1329 names = pycompat.maplist(repo._bookmarks.expandname, names)
1329 names = pycompat.maplist(repo._bookmarks.expandname, names)
1330 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1330 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1331 bookmarks.printbookmarks(ui, repo, fm, names)
1331 bookmarks.printbookmarks(ui, repo, fm, names)
1332 else:
1332 else:
1333 raise error.ProgrammingError(
1333 raise error.ProgrammingError(
1334 b'invalid action: %s' % pycompat.sysbytes(action)
1334 b'invalid action: %s' % pycompat.sysbytes(action)
1335 )
1335 )
1336
1336
1337
1337
1338 @command(
1338 @command(
1339 b'branch',
1339 b'branch',
1340 [
1340 [
1341 (
1341 (
1342 b'f',
1342 b'f',
1343 b'force',
1343 b'force',
1344 None,
1344 None,
1345 _(b'set branch name even if it shadows an existing branch'),
1345 _(b'set branch name even if it shadows an existing branch'),
1346 ),
1346 ),
1347 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1347 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1348 (
1348 (
1349 b'r',
1349 b'r',
1350 b'rev',
1350 b'rev',
1351 [],
1351 [],
1352 _(b'change branches of the given revs (EXPERIMENTAL)'),
1352 _(b'change branches of the given revs (EXPERIMENTAL)'),
1353 ),
1353 ),
1354 ],
1354 ],
1355 _(b'[-fC] [NAME]'),
1355 _(b'[-fC] [NAME]'),
1356 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1356 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1357 )
1357 )
1358 def branch(ui, repo, label=None, **opts):
1358 def branch(ui, repo, label=None, **opts):
1359 """set or show the current branch name
1359 """set or show the current branch name
1360
1360
1361 .. note::
1361 .. note::
1362
1362
1363 Branch names are permanent and global. Use :hg:`bookmark` to create a
1363 Branch names are permanent and global. Use :hg:`bookmark` to create a
1364 light-weight bookmark instead. See :hg:`help glossary` for more
1364 light-weight bookmark instead. See :hg:`help glossary` for more
1365 information about named branches and bookmarks.
1365 information about named branches and bookmarks.
1366
1366
1367 With no argument, show the current branch name. With one argument,
1367 With no argument, show the current branch name. With one argument,
1368 set the working directory branch name (the branch will not exist
1368 set the working directory branch name (the branch will not exist
1369 in the repository until the next commit). Standard practice
1369 in the repository until the next commit). Standard practice
1370 recommends that primary development take place on the 'default'
1370 recommends that primary development take place on the 'default'
1371 branch.
1371 branch.
1372
1372
1373 Unless -f/--force is specified, branch will not let you set a
1373 Unless -f/--force is specified, branch will not let you set a
1374 branch name that already exists.
1374 branch name that already exists.
1375
1375
1376 Use -C/--clean to reset the working directory branch to that of
1376 Use -C/--clean to reset the working directory branch to that of
1377 the parent of the working directory, negating a previous branch
1377 the parent of the working directory, negating a previous branch
1378 change.
1378 change.
1379
1379
1380 Use the command :hg:`update` to switch to an existing branch. Use
1380 Use the command :hg:`update` to switch to an existing branch. Use
1381 :hg:`commit --close-branch` to mark this branch head as closed.
1381 :hg:`commit --close-branch` to mark this branch head as closed.
1382 When all heads of a branch are closed, the branch will be
1382 When all heads of a branch are closed, the branch will be
1383 considered closed.
1383 considered closed.
1384
1384
1385 Returns 0 on success.
1385 Returns 0 on success.
1386 """
1386 """
1387 revs = opts.get('rev')
1387 revs = opts.get('rev')
1388 if label:
1388 if label:
1389 label = label.strip()
1389 label = label.strip()
1390
1390
1391 if not opts.get('clean') and not label:
1391 if not opts.get('clean') and not label:
1392 if revs:
1392 if revs:
1393 raise error.InputError(
1393 raise error.InputError(
1394 _(b"no branch name specified for the revisions")
1394 _(b"no branch name specified for the revisions")
1395 )
1395 )
1396 ui.write(b"%s\n" % repo.dirstate.branch())
1396 ui.write(b"%s\n" % repo.dirstate.branch())
1397 return
1397 return
1398
1398
1399 with repo.wlock():
1399 with repo.wlock():
1400 if opts.get('clean'):
1400 if opts.get('clean'):
1401 label = repo[b'.'].branch()
1401 label = repo[b'.'].branch()
1402 repo.dirstate.setbranch(label, repo.currenttransaction())
1402 repo.dirstate.setbranch(label, repo.currenttransaction())
1403 ui.status(_(b'reset working directory to branch %s\n') % label)
1403 ui.status(_(b'reset working directory to branch %s\n') % label)
1404 elif label:
1404 elif label:
1405 scmutil.checknewlabel(repo, label, b'branch')
1405 scmutil.checknewlabel(repo, label, b'branch')
1406 if revs:
1406 if revs:
1407 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1407 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1408
1408
1409 if not opts.get('force') and label in repo.branchmap():
1409 if not opts.get('force') and label in repo.branchmap():
1410 if label not in [p.branch() for p in repo[None].parents()]:
1410 if label not in [p.branch() for p in repo[None].parents()]:
1411 raise error.InputError(
1411 raise error.InputError(
1412 _(b'a branch of the same name already exists'),
1412 _(b'a branch of the same name already exists'),
1413 # i18n: "it" refers to an existing branch
1413 # i18n: "it" refers to an existing branch
1414 hint=_(b"use 'hg update' to switch to it"),
1414 hint=_(b"use 'hg update' to switch to it"),
1415 )
1415 )
1416
1416
1417 repo.dirstate.setbranch(label, repo.currenttransaction())
1417 repo.dirstate.setbranch(label, repo.currenttransaction())
1418 ui.status(_(b'marked working directory as branch %s\n') % label)
1418 ui.status(_(b'marked working directory as branch %s\n') % label)
1419
1419
1420 # find any open named branches aside from default
1420 # find any open named branches aside from default
1421 for n, h, t, c in repo.branchmap().iterbranches():
1421 for n, h, t, c in repo.branchmap().iterbranches():
1422 if n != b"default" and not c:
1422 if n != b"default" and not c:
1423 return 0
1423 return 0
1424 ui.status(
1424 ui.status(
1425 _(
1425 _(
1426 b'(branches are permanent and global, '
1426 b'(branches are permanent and global, '
1427 b'did you want a bookmark?)\n'
1427 b'did you want a bookmark?)\n'
1428 )
1428 )
1429 )
1429 )
1430
1430
1431
1431
1432 @command(
1432 @command(
1433 b'branches',
1433 b'branches',
1434 [
1434 [
1435 (
1435 (
1436 b'a',
1436 b'a',
1437 b'active',
1437 b'active',
1438 False,
1438 False,
1439 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1439 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1440 ),
1440 ),
1441 (b'c', b'closed', False, _(b'show normal and closed branches')),
1441 (b'c', b'closed', False, _(b'show normal and closed branches')),
1442 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1442 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1443 ]
1443 ]
1444 + formatteropts,
1444 + formatteropts,
1445 _(b'[-c]'),
1445 _(b'[-c]'),
1446 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1446 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1447 intents={INTENT_READONLY},
1447 intents={INTENT_READONLY},
1448 )
1448 )
1449 def branches(ui, repo, active=False, closed=False, **opts):
1449 def branches(ui, repo, active=False, closed=False, **opts):
1450 """list repository named branches
1450 """list repository named branches
1451
1451
1452 List the repository's named branches, indicating which ones are
1452 List the repository's named branches, indicating which ones are
1453 inactive. If -c/--closed is specified, also list branches which have
1453 inactive. If -c/--closed is specified, also list branches which have
1454 been marked closed (see :hg:`commit --close-branch`).
1454 been marked closed (see :hg:`commit --close-branch`).
1455
1455
1456 Use the command :hg:`update` to switch to an existing branch.
1456 Use the command :hg:`update` to switch to an existing branch.
1457
1457
1458 .. container:: verbose
1458 .. container:: verbose
1459
1459
1460 Template:
1460 Template:
1461
1461
1462 The following keywords are supported in addition to the common template
1462 The following keywords are supported in addition to the common template
1463 keywords and functions such as ``{branch}``. See also
1463 keywords and functions such as ``{branch}``. See also
1464 :hg:`help templates`.
1464 :hg:`help templates`.
1465
1465
1466 :active: Boolean. True if the branch is active.
1466 :active: Boolean. True if the branch is active.
1467 :closed: Boolean. True if the branch is closed.
1467 :closed: Boolean. True if the branch is closed.
1468 :current: Boolean. True if it is the current branch.
1468 :current: Boolean. True if it is the current branch.
1469
1469
1470 Returns 0.
1470 Returns 0.
1471 """
1471 """
1472
1472
1473 revs = opts.get('rev')
1473 revs = opts.get('rev')
1474 selectedbranches = None
1474 selectedbranches = None
1475 if revs:
1475 if revs:
1476 revs = logcmdutil.revrange(repo, revs)
1476 revs = logcmdutil.revrange(repo, revs)
1477 getbi = repo.revbranchcache().branchinfo
1477 getbi = repo.revbranchcache().branchinfo
1478 selectedbranches = {getbi(r)[0] for r in revs}
1478 selectedbranches = {getbi(r)[0] for r in revs}
1479
1479
1480 ui.pager(b'branches')
1480 ui.pager(b'branches')
1481 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1481 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1482 hexfunc = fm.hexfunc
1482 hexfunc = fm.hexfunc
1483
1483
1484 allheads = set(repo.heads())
1484 allheads = set(repo.heads())
1485 branches = []
1485 branches = []
1486 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1486 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1487 if selectedbranches is not None and tag not in selectedbranches:
1487 if selectedbranches is not None and tag not in selectedbranches:
1488 continue
1488 continue
1489 isactive = False
1489 isactive = False
1490 if not isclosed:
1490 if not isclosed:
1491 openheads = set(repo.branchmap().iteropen(heads))
1491 openheads = set(repo.branchmap().iteropen(heads))
1492 isactive = bool(openheads & allheads)
1492 isactive = bool(openheads & allheads)
1493 branches.append((tag, repo[tip], isactive, not isclosed))
1493 branches.append((tag, repo[tip], isactive, not isclosed))
1494 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1494 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1495
1495
1496 for tag, ctx, isactive, isopen in branches:
1496 for tag, ctx, isactive, isopen in branches:
1497 if active and not isactive:
1497 if active and not isactive:
1498 continue
1498 continue
1499 if isactive:
1499 if isactive:
1500 label = b'branches.active'
1500 label = b'branches.active'
1501 notice = b''
1501 notice = b''
1502 elif not isopen:
1502 elif not isopen:
1503 if not closed:
1503 if not closed:
1504 continue
1504 continue
1505 label = b'branches.closed'
1505 label = b'branches.closed'
1506 notice = _(b' (closed)')
1506 notice = _(b' (closed)')
1507 else:
1507 else:
1508 label = b'branches.inactive'
1508 label = b'branches.inactive'
1509 notice = _(b' (inactive)')
1509 notice = _(b' (inactive)')
1510 current = tag == repo.dirstate.branch()
1510 current = tag == repo.dirstate.branch()
1511 if current:
1511 if current:
1512 label = b'branches.current'
1512 label = b'branches.current'
1513
1513
1514 fm.startitem()
1514 fm.startitem()
1515 fm.write(b'branch', b'%s', tag, label=label)
1515 fm.write(b'branch', b'%s', tag, label=label)
1516 rev = ctx.rev()
1516 rev = ctx.rev()
1517 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1517 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1518 fmt = b' ' * padsize + b' %d:%s'
1518 fmt = b' ' * padsize + b' %d:%s'
1519 fm.condwrite(
1519 fm.condwrite(
1520 not ui.quiet,
1520 not ui.quiet,
1521 b'rev node',
1521 b'rev node',
1522 fmt,
1522 fmt,
1523 rev,
1523 rev,
1524 hexfunc(ctx.node()),
1524 hexfunc(ctx.node()),
1525 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1525 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1526 )
1526 )
1527 fm.context(ctx=ctx)
1527 fm.context(ctx=ctx)
1528 fm.data(active=isactive, closed=not isopen, current=current)
1528 fm.data(active=isactive, closed=not isopen, current=current)
1529 if not ui.quiet:
1529 if not ui.quiet:
1530 fm.plain(notice)
1530 fm.plain(notice)
1531 fm.plain(b'\n')
1531 fm.plain(b'\n')
1532 fm.end()
1532 fm.end()
1533
1533
1534
1534
1535 @command(
1535 @command(
1536 b'bundle',
1536 b'bundle',
1537 [
1537 [
1538 (
1538 (
1539 b'',
1539 b'',
1540 b'exact',
1540 b'exact',
1541 None,
1541 None,
1542 _(b'compute the base from the revision specified'),
1542 _(b'compute the base from the revision specified'),
1543 ),
1543 ),
1544 (
1544 (
1545 b'f',
1545 b'f',
1546 b'force',
1546 b'force',
1547 None,
1547 None,
1548 _(b'run even when the destination is unrelated'),
1548 _(b'run even when the destination is unrelated'),
1549 ),
1549 ),
1550 (
1550 (
1551 b'r',
1551 b'r',
1552 b'rev',
1552 b'rev',
1553 [],
1553 [],
1554 _(b'a changeset intended to be added to the destination'),
1554 _(b'a changeset intended to be added to the destination'),
1555 _(b'REV'),
1555 _(b'REV'),
1556 ),
1556 ),
1557 (
1557 (
1558 b'b',
1558 b'b',
1559 b'branch',
1559 b'branch',
1560 [],
1560 [],
1561 _(b'a specific branch you would like to bundle'),
1561 _(b'a specific branch you would like to bundle'),
1562 _(b'BRANCH'),
1562 _(b'BRANCH'),
1563 ),
1563 ),
1564 (
1564 (
1565 b'',
1565 b'',
1566 b'base',
1566 b'base',
1567 [],
1567 [],
1568 _(b'a base changeset assumed to be available at the destination'),
1568 _(b'a base changeset assumed to be available at the destination'),
1569 _(b'REV'),
1569 _(b'REV'),
1570 ),
1570 ),
1571 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1571 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1572 (
1572 (
1573 b't',
1573 b't',
1574 b'type',
1574 b'type',
1575 b'bzip2',
1575 b'bzip2',
1576 _(b'bundle compression type to use'),
1576 _(b'bundle compression type to use'),
1577 _(b'TYPE'),
1577 _(b'TYPE'),
1578 ),
1578 ),
1579 ]
1579 ]
1580 + remoteopts,
1580 + remoteopts,
1581 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1581 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1582 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1582 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1583 )
1583 )
1584 def bundle(ui, repo, fname, *dests, **opts):
1584 def bundle(ui, repo, fname, *dests, **opts):
1585 """create a bundle file
1585 """create a bundle file
1586
1586
1587 Generate a bundle file containing data to be transferred to another
1587 Generate a bundle file containing data to be transferred to another
1588 repository.
1588 repository.
1589
1589
1590 To create a bundle containing all changesets, use -a/--all
1590 To create a bundle containing all changesets, use -a/--all
1591 (or --base null). Otherwise, hg assumes the destination will have
1591 (or --base null). Otherwise, hg assumes the destination will have
1592 all the nodes you specify with --base parameters. Otherwise, hg
1592 all the nodes you specify with --base parameters. Otherwise, hg
1593 will assume the repository has all the nodes in destination, or
1593 will assume the repository has all the nodes in destination, or
1594 default-push/default if no destination is specified, where destination
1594 default-push/default if no destination is specified, where destination
1595 is the repositories you provide through DEST option.
1595 is the repositories you provide through DEST option.
1596
1596
1597 You can change bundle format with the -t/--type option. See
1597 You can change bundle format with the -t/--type option. See
1598 :hg:`help bundlespec` for documentation on this format. By default,
1598 :hg:`help bundlespec` for documentation on this format. By default,
1599 the most appropriate format is used and compression defaults to
1599 the most appropriate format is used and compression defaults to
1600 bzip2.
1600 bzip2.
1601
1601
1602 The bundle file can then be transferred using conventional means
1602 The bundle file can then be transferred using conventional means
1603 and applied to another repository with the unbundle or pull
1603 and applied to another repository with the unbundle or pull
1604 command. This is useful when direct push and pull are not
1604 command. This is useful when direct push and pull are not
1605 available or when exporting an entire repository is undesirable.
1605 available or when exporting an entire repository is undesirable.
1606
1606
1607 Applying bundles preserves all changeset contents including
1607 Applying bundles preserves all changeset contents including
1608 permissions, copy/rename information, and revision history.
1608 permissions, copy/rename information, and revision history.
1609
1609
1610 Returns 0 on success, 1 if no changes found.
1610 Returns 0 on success, 1 if no changes found.
1611 """
1611 """
1612
1612
1613 revs = None
1613 revs = None
1614 if 'rev' in opts:
1614 if 'rev' in opts:
1615 revstrings = opts['rev']
1615 revstrings = opts['rev']
1616 revs = logcmdutil.revrange(repo, revstrings)
1616 revs = logcmdutil.revrange(repo, revstrings)
1617 if revstrings and not revs:
1617 if revstrings and not revs:
1618 raise error.InputError(_(b'no commits to bundle'))
1618 raise error.InputError(_(b'no commits to bundle'))
1619
1619
1620 bundletype = opts.get('type', b'bzip2').lower()
1620 bundletype = opts.get('type', b'bzip2').lower()
1621 try:
1621 try:
1622 bundlespec = bundlecaches.parsebundlespec(
1622 bundlespec = bundlecaches.parsebundlespec(
1623 repo, bundletype, strict=False
1623 repo, bundletype, strict=False
1624 )
1624 )
1625 except error.UnsupportedBundleSpecification as e:
1625 except error.UnsupportedBundleSpecification as e:
1626 raise error.InputError(
1626 raise error.InputError(
1627 pycompat.bytestr(e),
1627 pycompat.bytestr(e),
1628 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1628 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1629 )
1629 )
1630 cgversion = bundlespec.params[b"cg.version"]
1630 cgversion = bundlespec.params[b"cg.version"]
1631
1631
1632 # Packed bundles are a pseudo bundle format for now.
1632 # Packed bundles are a pseudo bundle format for now.
1633 if cgversion == b's1':
1633 if cgversion == b's1':
1634 raise error.InputError(
1634 raise error.InputError(
1635 _(b'packed bundles cannot be produced by "hg bundle"'),
1635 _(b'packed bundles cannot be produced by "hg bundle"'),
1636 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1636 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1637 )
1637 )
1638 base_opt = opts.get('base')
1638 base_opt = opts.get('base')
1639 if opts.get('all'):
1639 if opts.get('all'):
1640 if dests:
1640 if dests:
1641 raise error.InputError(
1641 raise error.InputError(
1642 _(b"--all is incompatible with specifying destinations")
1642 _(b"--all is incompatible with specifying destinations")
1643 )
1643 )
1644 if base_opt:
1644 if base_opt:
1645 ui.warn(_(b"ignoring --base because --all was specified\n"))
1645 ui.warn(_(b"ignoring --base because --all was specified\n"))
1646 if opts.get('exact'):
1646 if opts.get('exact'):
1647 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1647 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1648 base = [nullrev]
1648 base = [nullrev]
1649 elif opts.get('exact'):
1649 elif opts.get('exact'):
1650 if dests:
1650 if dests:
1651 raise error.InputError(
1651 raise error.InputError(
1652 _(b"--exact is incompatible with specifying destinations")
1652 _(b"--exact is incompatible with specifying destinations")
1653 )
1653 )
1654 if base_opt:
1654 if base_opt:
1655 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1655 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1656 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1656 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1657 if not base:
1657 if not base:
1658 base = [nullrev]
1658 base = [nullrev]
1659 elif base_opt:
1659 elif base_opt:
1660 base = logcmdutil.revrange(repo, base_opt)
1660 base = logcmdutil.revrange(repo, base_opt)
1661 if not base:
1661 if not base:
1662 # base specified, but nothing was selected
1662 # base specified, but nothing was selected
1663 base = [nullrev]
1663 base = [nullrev]
1664 else:
1664 else:
1665 base = None
1665 base = None
1666 if cgversion not in changegroup.supportedoutgoingversions(repo):
1666 if cgversion not in changegroup.supportedoutgoingversions(repo):
1667 raise error.Abort(
1667 raise error.Abort(
1668 _(b"repository does not support bundle version %s") % cgversion
1668 _(b"repository does not support bundle version %s") % cgversion
1669 )
1669 )
1670
1670
1671 if base is not None:
1671 if base is not None:
1672 if dests:
1672 if dests:
1673 raise error.InputError(
1673 raise error.InputError(
1674 _(b"--base is incompatible with specifying destinations")
1674 _(b"--base is incompatible with specifying destinations")
1675 )
1675 )
1676 cl = repo.changelog
1676 cl = repo.changelog
1677 common = [cl.node(rev) for rev in base]
1677 common = [cl.node(rev) for rev in base]
1678 heads = [cl.node(r) for r in revs] if revs else None
1678 heads = [cl.node(r) for r in revs] if revs else None
1679 outgoing = discovery.outgoing(repo, common, heads)
1679 outgoing = discovery.outgoing(repo, common, heads)
1680 missing = outgoing.missing
1680 missing = outgoing.missing
1681 excluded = outgoing.excluded
1681 excluded = outgoing.excluded
1682 else:
1682 else:
1683 missing = set()
1683 missing = set()
1684 excluded = set()
1684 excluded = set()
1685 for path in urlutil.get_push_paths(repo, ui, dests):
1685 for path in urlutil.get_push_paths(repo, ui, dests):
1686 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1686 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1687 if revs is not None:
1687 if revs is not None:
1688 hex_revs = [repo[r].hex() for r in revs]
1688 hex_revs = [repo[r].hex() for r in revs]
1689 else:
1689 else:
1690 hex_revs = None
1690 hex_revs = None
1691 branches = (path.branch, [])
1691 branches = (path.branch, [])
1692 head_revs, checkout = hg.addbranchrevs(
1692 head_revs, checkout = hg.addbranchrevs(
1693 repo, repo, branches, hex_revs
1693 repo, repo, branches, hex_revs
1694 )
1694 )
1695 heads = (
1695 heads = (
1696 head_revs
1696 head_revs
1697 and pycompat.maplist(repo.lookup, head_revs)
1697 and pycompat.maplist(repo.lookup, head_revs)
1698 or head_revs
1698 or head_revs
1699 )
1699 )
1700 outgoing = discovery.findcommonoutgoing(
1700 outgoing = discovery.findcommonoutgoing(
1701 repo,
1701 repo,
1702 other,
1702 other,
1703 onlyheads=heads,
1703 onlyheads=heads,
1704 force=opts.get('force'),
1704 force=opts.get('force'),
1705 portable=True,
1705 portable=True,
1706 )
1706 )
1707 missing.update(outgoing.missing)
1707 missing.update(outgoing.missing)
1708 excluded.update(outgoing.excluded)
1708 excluded.update(outgoing.excluded)
1709
1709
1710 if not missing:
1710 if not missing:
1711 scmutil.nochangesfound(ui, repo, not base and excluded)
1711 scmutil.nochangesfound(ui, repo, not base and excluded)
1712 return 1
1712 return 1
1713
1713
1714 # internal changeset are internal implementation details that should not
1714 # internal changeset are internal implementation details that should not
1715 # leave the repository. Bundling with `hg bundle` create such risk.
1715 # leave the repository. Bundling with `hg bundle` create such risk.
1716 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1716 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1717 if bundled_internal:
1717 if bundled_internal:
1718 msg = _(b"cannot bundle internal changesets")
1718 msg = _(b"cannot bundle internal changesets")
1719 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1719 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1720 raise error.Abort(msg, hint=hint)
1720 raise error.Abort(msg, hint=hint)
1721
1721
1722 if heads:
1722 if heads:
1723 outgoing = discovery.outgoing(
1723 outgoing = discovery.outgoing(
1724 repo, missingroots=missing, ancestorsof=heads
1724 repo, missingroots=missing, ancestorsof=heads
1725 )
1725 )
1726 else:
1726 else:
1727 outgoing = discovery.outgoing(repo, missingroots=missing)
1727 outgoing = discovery.outgoing(repo, missingroots=missing)
1728 outgoing.excluded = sorted(excluded)
1728 outgoing.excluded = sorted(excluded)
1729
1729
1730 if cgversion == b'01': # bundle1
1730 if cgversion == b'01': # bundle1
1731 bversion = b'HG10' + bundlespec.wirecompression
1731 bversion = b'HG10' + bundlespec.wirecompression
1732 bcompression = None
1732 bcompression = None
1733 elif cgversion in (b'02', b'03'):
1733 elif cgversion in (b'02', b'03'):
1734 bversion = b'HG20'
1734 bversion = b'HG20'
1735 bcompression = bundlespec.wirecompression
1735 bcompression = bundlespec.wirecompression
1736 else:
1736 else:
1737 raise error.ProgrammingError(
1737 raise error.ProgrammingError(
1738 b'bundle: unexpected changegroup version %s' % cgversion
1738 b'bundle: unexpected changegroup version %s' % cgversion
1739 )
1739 )
1740
1740
1741 # TODO compression options should be derived from bundlespec parsing.
1741 # TODO compression options should be derived from bundlespec parsing.
1742 # This is a temporary hack to allow adjusting bundle compression
1742 # This is a temporary hack to allow adjusting bundle compression
1743 # level without a) formalizing the bundlespec changes to declare it
1743 # level without a) formalizing the bundlespec changes to declare it
1744 # b) introducing a command flag.
1744 # b) introducing a command flag.
1745 compopts = {}
1745 compopts = {}
1746 complevel = ui.configint(
1746 complevel = ui.configint(
1747 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1747 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1748 )
1748 )
1749 if complevel is None:
1749 if complevel is None:
1750 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1750 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1751 if complevel is not None:
1751 if complevel is not None:
1752 compopts[b'level'] = complevel
1752 compopts[b'level'] = complevel
1753
1753
1754 compthreads = ui.configint(
1754 compthreads = ui.configint(
1755 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1755 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1756 )
1756 )
1757 if compthreads is None:
1757 if compthreads is None:
1758 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1758 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1759 if compthreads is not None:
1759 if compthreads is not None:
1760 compopts[b'threads'] = compthreads
1760 compopts[b'threads'] = compthreads
1761
1761
1762 # Bundling of obsmarker and phases is optional as not all clients
1762 # Bundling of obsmarker and phases is optional as not all clients
1763 # support the necessary features.
1763 # support the necessary features.
1764 cfg = ui.configbool
1764 cfg = ui.configbool
1765 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1765 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1766 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1766 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1767 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1767 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1768 bundlespec.set_param(
1768 bundlespec.set_param(
1769 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1769 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1770 )
1770 )
1771 if not bundlespec.params.get(b'phases', False):
1771 if not bundlespec.params.get(b'phases', False):
1772 phases_cfg = cfg(b'experimental', b'bundle-phases')
1772 phases_cfg = cfg(b'experimental', b'bundle-phases')
1773 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1773 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1774
1774
1775 bundle2.writenewbundle(
1775 bundle2.writenewbundle(
1776 ui,
1776 ui,
1777 repo,
1777 repo,
1778 b'bundle',
1778 b'bundle',
1779 fname,
1779 fname,
1780 bversion,
1780 bversion,
1781 outgoing,
1781 outgoing,
1782 bundlespec.params,
1782 bundlespec.params,
1783 compression=bcompression,
1783 compression=bcompression,
1784 compopts=compopts,
1784 compopts=compopts,
1785 )
1785 )
1786
1786
1787
1787
1788 @command(
1788 @command(
1789 b'cat',
1789 b'cat',
1790 [
1790 [
1791 (
1791 (
1792 b'o',
1792 b'o',
1793 b'output',
1793 b'output',
1794 b'',
1794 b'',
1795 _(b'print output to file with formatted name'),
1795 _(b'print output to file with formatted name'),
1796 _(b'FORMAT'),
1796 _(b'FORMAT'),
1797 ),
1797 ),
1798 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1798 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1799 (b'', b'decode', None, _(b'apply any matching decode filter')),
1799 (b'', b'decode', None, _(b'apply any matching decode filter')),
1800 ]
1800 ]
1801 + walkopts
1801 + walkopts
1802 + formatteropts,
1802 + formatteropts,
1803 _(b'[OPTION]... FILE...'),
1803 _(b'[OPTION]... FILE...'),
1804 helpcategory=command.CATEGORY_FILE_CONTENTS,
1804 helpcategory=command.CATEGORY_FILE_CONTENTS,
1805 inferrepo=True,
1805 inferrepo=True,
1806 intents={INTENT_READONLY},
1806 intents={INTENT_READONLY},
1807 )
1807 )
1808 def cat(ui, repo, file1, *pats, **opts):
1808 def cat(ui, repo, file1, *pats, **opts):
1809 """output the current or given revision of files
1809 """output the current or given revision of files
1810
1810
1811 Print the specified files as they were at the given revision. If
1811 Print the specified files as they were at the given revision. If
1812 no revision is given, the parent of the working directory is used.
1812 no revision is given, the parent of the working directory is used.
1813
1813
1814 Output may be to a file, in which case the name of the file is
1814 Output may be to a file, in which case the name of the file is
1815 given using a template string. See :hg:`help templates`. In addition
1815 given using a template string. See :hg:`help templates`. In addition
1816 to the common template keywords, the following formatting rules are
1816 to the common template keywords, the following formatting rules are
1817 supported:
1817 supported:
1818
1818
1819 :``%%``: literal "%" character
1819 :``%%``: literal "%" character
1820 :``%s``: basename of file being printed
1820 :``%s``: basename of file being printed
1821 :``%d``: dirname of file being printed, or '.' if in repository root
1821 :``%d``: dirname of file being printed, or '.' if in repository root
1822 :``%p``: root-relative path name of file being printed
1822 :``%p``: root-relative path name of file being printed
1823 :``%H``: changeset hash (40 hexadecimal digits)
1823 :``%H``: changeset hash (40 hexadecimal digits)
1824 :``%R``: changeset revision number
1824 :``%R``: changeset revision number
1825 :``%h``: short-form changeset hash (12 hexadecimal digits)
1825 :``%h``: short-form changeset hash (12 hexadecimal digits)
1826 :``%r``: zero-padded changeset revision number
1826 :``%r``: zero-padded changeset revision number
1827 :``%b``: basename of the exporting repository
1827 :``%b``: basename of the exporting repository
1828 :``\\``: literal "\\" character
1828 :``\\``: literal "\\" character
1829
1829
1830 .. container:: verbose
1830 .. container:: verbose
1831
1831
1832 Template:
1832 Template:
1833
1833
1834 The following keywords are supported in addition to the common template
1834 The following keywords are supported in addition to the common template
1835 keywords and functions. See also :hg:`help templates`.
1835 keywords and functions. See also :hg:`help templates`.
1836
1836
1837 :data: String. File content.
1837 :data: String. File content.
1838 :path: String. Repository-absolute path of the file.
1838 :path: String. Repository-absolute path of the file.
1839
1839
1840 Returns 0 on success.
1840 Returns 0 on success.
1841 """
1841 """
1842 rev = opts.get('rev')
1842 rev = opts.get('rev')
1843 if rev:
1843 if rev:
1844 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1844 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1845 ctx = logcmdutil.revsingle(repo, rev)
1845 ctx = logcmdutil.revsingle(repo, rev)
1846 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1846 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1847 fntemplate = opts.pop('output', b'')
1847 fntemplate = opts.pop('output', b'')
1848 if cmdutil.isstdiofilename(fntemplate):
1848 if cmdutil.isstdiofilename(fntemplate):
1849 fntemplate = b''
1849 fntemplate = b''
1850
1850
1851 if fntemplate:
1851 if fntemplate:
1852 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1852 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1853 else:
1853 else:
1854 ui.pager(b'cat')
1854 ui.pager(b'cat')
1855 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1855 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1856 with fm:
1856 with fm:
1857 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1857 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1858
1858
1859
1859
1860 @command(
1860 @command(
1861 b'clone',
1861 b'clone',
1862 [
1862 [
1863 (
1863 (
1864 b'U',
1864 b'U',
1865 b'noupdate',
1865 b'noupdate',
1866 None,
1866 None,
1867 _(
1867 _(
1868 b'the clone will include an empty working '
1868 b'the clone will include an empty working '
1869 b'directory (only a repository)'
1869 b'directory (only a repository)'
1870 ),
1870 ),
1871 ),
1871 ),
1872 (
1872 (
1873 b'u',
1873 b'u',
1874 b'updaterev',
1874 b'updaterev',
1875 b'',
1875 b'',
1876 _(b'revision, tag, or branch to check out'),
1876 _(b'revision, tag, or branch to check out'),
1877 _(b'REV'),
1877 _(b'REV'),
1878 ),
1878 ),
1879 (
1879 (
1880 b'r',
1880 b'r',
1881 b'rev',
1881 b'rev',
1882 [],
1882 [],
1883 _(
1883 _(
1884 b'do not clone everything, but include this changeset'
1884 b'do not clone everything, but include this changeset'
1885 b' and its ancestors'
1885 b' and its ancestors'
1886 ),
1886 ),
1887 _(b'REV'),
1887 _(b'REV'),
1888 ),
1888 ),
1889 (
1889 (
1890 b'b',
1890 b'b',
1891 b'branch',
1891 b'branch',
1892 [],
1892 [],
1893 _(
1893 _(
1894 b'do not clone everything, but include this branch\'s'
1894 b'do not clone everything, but include this branch\'s'
1895 b' changesets and their ancestors'
1895 b' changesets and their ancestors'
1896 ),
1896 ),
1897 _(b'BRANCH'),
1897 _(b'BRANCH'),
1898 ),
1898 ),
1899 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1899 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1900 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1900 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1901 (b'', b'stream', None, _(b'clone with minimal data processing')),
1901 (b'', b'stream', None, _(b'clone with minimal data processing')),
1902 ]
1902 ]
1903 + remoteopts,
1903 + remoteopts,
1904 _(b'[OPTION]... SOURCE [DEST]'),
1904 _(b'[OPTION]... SOURCE [DEST]'),
1905 helpcategory=command.CATEGORY_REPO_CREATION,
1905 helpcategory=command.CATEGORY_REPO_CREATION,
1906 helpbasic=True,
1906 helpbasic=True,
1907 norepo=True,
1907 norepo=True,
1908 )
1908 )
1909 def clone(ui, source, dest=None, **opts):
1909 def clone(ui, source, dest=None, **opts):
1910 """make a copy of an existing repository
1910 """make a copy of an existing repository
1911
1911
1912 Create a copy of an existing repository in a new directory.
1912 Create a copy of an existing repository in a new directory.
1913
1913
1914 If no destination directory name is specified, it defaults to the
1914 If no destination directory name is specified, it defaults to the
1915 basename of the source.
1915 basename of the source.
1916
1916
1917 The location of the source is added to the new repository's
1917 The location of the source is added to the new repository's
1918 ``.hg/hgrc`` file, as the default to be used for future pulls.
1918 ``.hg/hgrc`` file, as the default to be used for future pulls.
1919
1919
1920 Only local paths and ``ssh://`` URLs are supported as
1920 Only local paths and ``ssh://`` URLs are supported as
1921 destinations. For ``ssh://`` destinations, no working directory or
1921 destinations. For ``ssh://`` destinations, no working directory or
1922 ``.hg/hgrc`` will be created on the remote side.
1922 ``.hg/hgrc`` will be created on the remote side.
1923
1923
1924 If the source repository has a bookmark called '@' set, that
1924 If the source repository has a bookmark called '@' set, that
1925 revision will be checked out in the new repository by default.
1925 revision will be checked out in the new repository by default.
1926
1926
1927 To check out a particular version, use -u/--update, or
1927 To check out a particular version, use -u/--update, or
1928 -U/--noupdate to create a clone with no working directory.
1928 -U/--noupdate to create a clone with no working directory.
1929
1929
1930 To pull only a subset of changesets, specify one or more revisions
1930 To pull only a subset of changesets, specify one or more revisions
1931 identifiers with -r/--rev or branches with -b/--branch. The
1931 identifiers with -r/--rev or branches with -b/--branch. The
1932 resulting clone will contain only the specified changesets and
1932 resulting clone will contain only the specified changesets and
1933 their ancestors. These options (or 'clone src#rev dest') imply
1933 their ancestors. These options (or 'clone src#rev dest') imply
1934 --pull, even for local source repositories.
1934 --pull, even for local source repositories.
1935
1935
1936 In normal clone mode, the remote normalizes repository data into a common
1936 In normal clone mode, the remote normalizes repository data into a common
1937 exchange format and the receiving end translates this data into its local
1937 exchange format and the receiving end translates this data into its local
1938 storage format. --stream activates a different clone mode that essentially
1938 storage format. --stream activates a different clone mode that essentially
1939 copies repository files from the remote with minimal data processing. This
1939 copies repository files from the remote with minimal data processing. This
1940 significantly reduces the CPU cost of a clone both remotely and locally.
1940 significantly reduces the CPU cost of a clone both remotely and locally.
1941 However, it often increases the transferred data size by 30-40%. This can
1941 However, it often increases the transferred data size by 30-40%. This can
1942 result in substantially faster clones where I/O throughput is plentiful,
1942 result in substantially faster clones where I/O throughput is plentiful,
1943 especially for larger repositories. A side-effect of --stream clones is
1943 especially for larger repositories. A side-effect of --stream clones is
1944 that storage settings and requirements on the remote are applied locally:
1944 that storage settings and requirements on the remote are applied locally:
1945 a modern client may inherit legacy or inefficient storage used by the
1945 a modern client may inherit legacy or inefficient storage used by the
1946 remote or a legacy Mercurial client may not be able to clone from a
1946 remote or a legacy Mercurial client may not be able to clone from a
1947 modern Mercurial remote.
1947 modern Mercurial remote.
1948
1948
1949 .. note::
1949 .. note::
1950
1950
1951 Specifying a tag will include the tagged changeset but not the
1951 Specifying a tag will include the tagged changeset but not the
1952 changeset containing the tag.
1952 changeset containing the tag.
1953
1953
1954 .. container:: verbose
1954 .. container:: verbose
1955
1955
1956 For efficiency, hardlinks are used for cloning whenever the
1956 For efficiency, hardlinks are used for cloning whenever the
1957 source and destination are on the same filesystem (note this
1957 source and destination are on the same filesystem (note this
1958 applies only to the repository data, not to the working
1958 applies only to the repository data, not to the working
1959 directory). Some filesystems, such as AFS, implement hardlinking
1959 directory). Some filesystems, such as AFS, implement hardlinking
1960 incorrectly, but do not report errors. In these cases, use the
1960 incorrectly, but do not report errors. In these cases, use the
1961 --pull option to avoid hardlinking.
1961 --pull option to avoid hardlinking.
1962
1962
1963 Mercurial will update the working directory to the first applicable
1963 Mercurial will update the working directory to the first applicable
1964 revision from this list:
1964 revision from this list:
1965
1965
1966 a) null if -U or the source repository has no changesets
1966 a) null if -U or the source repository has no changesets
1967 b) if -u . and the source repository is local, the first parent of
1967 b) if -u . and the source repository is local, the first parent of
1968 the source repository's working directory
1968 the source repository's working directory
1969 c) the changeset specified with -u (if a branch name, this means the
1969 c) the changeset specified with -u (if a branch name, this means the
1970 latest head of that branch)
1970 latest head of that branch)
1971 d) the changeset specified with -r
1971 d) the changeset specified with -r
1972 e) the tipmost head specified with -b
1972 e) the tipmost head specified with -b
1973 f) the tipmost head specified with the url#branch source syntax
1973 f) the tipmost head specified with the url#branch source syntax
1974 g) the revision marked with the '@' bookmark, if present
1974 g) the revision marked with the '@' bookmark, if present
1975 h) the tipmost head of the default branch
1975 h) the tipmost head of the default branch
1976 i) tip
1976 i) tip
1977
1977
1978 When cloning from servers that support it, Mercurial may fetch
1978 When cloning from servers that support it, Mercurial may fetch
1979 pre-generated data from a server-advertised URL or inline from the
1979 pre-generated data from a server-advertised URL or inline from the
1980 same stream. When this is done, hooks operating on incoming changesets
1980 same stream. When this is done, hooks operating on incoming changesets
1981 and changegroups may fire more than once, once for each pre-generated
1981 and changegroups may fire more than once, once for each pre-generated
1982 bundle and as well as for any additional remaining data. In addition,
1982 bundle and as well as for any additional remaining data. In addition,
1983 if an error occurs, the repository may be rolled back to a partial
1983 if an error occurs, the repository may be rolled back to a partial
1984 clone. This behavior may change in future releases.
1984 clone. This behavior may change in future releases.
1985 See :hg:`help -e clonebundles` for more.
1985 See :hg:`help -e clonebundles` for more.
1986
1986
1987 Examples:
1987 Examples:
1988
1988
1989 - clone a remote repository to a new directory named hg/::
1989 - clone a remote repository to a new directory named hg/::
1990
1990
1991 hg clone https://www.mercurial-scm.org/repo/hg/
1991 hg clone https://www.mercurial-scm.org/repo/hg/
1992
1992
1993 - create a lightweight local clone::
1993 - create a lightweight local clone::
1994
1994
1995 hg clone project/ project-feature/
1995 hg clone project/ project-feature/
1996
1996
1997 - clone from an absolute path on an ssh server (note double-slash)::
1997 - clone from an absolute path on an ssh server (note double-slash)::
1998
1998
1999 hg clone ssh://user@server//home/projects/alpha/
1999 hg clone ssh://user@server//home/projects/alpha/
2000
2000
2001 - do a streaming clone while checking out a specified version::
2001 - do a streaming clone while checking out a specified version::
2002
2002
2003 hg clone --stream http://server/repo -u 1.5
2003 hg clone --stream http://server/repo -u 1.5
2004
2004
2005 - create a repository without changesets after a particular revision::
2005 - create a repository without changesets after a particular revision::
2006
2006
2007 hg clone -r 04e544 experimental/ good/
2007 hg clone -r 04e544 experimental/ good/
2008
2008
2009 - clone (and track) a particular named branch::
2009 - clone (and track) a particular named branch::
2010
2010
2011 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2011 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2012
2012
2013 See :hg:`help urls` for details on specifying URLs.
2013 See :hg:`help urls` for details on specifying URLs.
2014
2014
2015 Returns 0 on success.
2015 Returns 0 on success.
2016 """
2016 """
2017 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2017 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2018
2018
2019 # --include/--exclude can come from narrow or sparse.
2019 # --include/--exclude can come from narrow or sparse.
2020 includepats, excludepats = None, None
2020 includepats, excludepats = None, None
2021
2021
2022 # hg.clone() differentiates between None and an empty set. So make sure
2022 # hg.clone() differentiates between None and an empty set. So make sure
2023 # patterns are sets if narrow is requested without patterns.
2023 # patterns are sets if narrow is requested without patterns.
2024 if opts.get('narrow'):
2024 if opts.get('narrow'):
2025 includepats = set()
2025 includepats = set()
2026 excludepats = set()
2026 excludepats = set()
2027
2027
2028 if opts.get('include'):
2028 if opts.get('include'):
2029 includepats = narrowspec.parsepatterns(opts.get('include'))
2029 includepats = narrowspec.parsepatterns(opts.get('include'))
2030 if opts.get('exclude'):
2030 if opts.get('exclude'):
2031 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2031 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2032
2032
2033 r = hg.clone(
2033 r = hg.clone(
2034 ui,
2034 ui,
2035 pycompat.byteskwargs(opts),
2035 pycompat.byteskwargs(opts),
2036 source,
2036 source,
2037 dest,
2037 dest,
2038 pull=opts.get('pull'),
2038 pull=opts.get('pull'),
2039 stream=opts.get('stream') or opts.get('uncompressed'),
2039 stream=opts.get('stream') or opts.get('uncompressed'),
2040 revs=opts.get('rev'),
2040 revs=opts.get('rev'),
2041 update=opts.get('updaterev') or not opts.get('noupdate'),
2041 update=opts.get('updaterev') or not opts.get('noupdate'),
2042 branch=opts.get('branch'),
2042 branch=opts.get('branch'),
2043 shareopts=opts.get('shareopts'),
2043 shareopts=opts.get('shareopts'),
2044 storeincludepats=includepats,
2044 storeincludepats=includepats,
2045 storeexcludepats=excludepats,
2045 storeexcludepats=excludepats,
2046 depth=opts.get('depth') or None,
2046 depth=opts.get('depth') or None,
2047 )
2047 )
2048
2048
2049 return r is None
2049 return r is None
2050
2050
2051
2051
2052 @command(
2052 @command(
2053 b'commit|ci',
2053 b'commit|ci',
2054 [
2054 [
2055 (
2055 (
2056 b'A',
2056 b'A',
2057 b'addremove',
2057 b'addremove',
2058 None,
2058 None,
2059 _(b'mark new/missing files as added/removed before committing'),
2059 _(b'mark new/missing files as added/removed before committing'),
2060 ),
2060 ),
2061 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2061 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2062 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2062 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2063 (b's', b'secret', None, _(b'use the secret phase for committing')),
2063 (b's', b'secret', None, _(b'use the secret phase for committing')),
2064 (b'', b'draft', None, _(b'use the draft phase for committing')),
2064 (b'', b'draft', None, _(b'use the draft phase for committing')),
2065 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2065 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2066 (
2066 (
2067 b'',
2067 b'',
2068 b'force-close-branch',
2068 b'force-close-branch',
2069 None,
2069 None,
2070 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2070 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2071 ),
2071 ),
2072 (b'i', b'interactive', None, _(b'use interactive mode')),
2072 (b'i', b'interactive', None, _(b'use interactive mode')),
2073 ]
2073 ]
2074 + walkopts
2074 + walkopts
2075 + commitopts
2075 + commitopts
2076 + commitopts2
2076 + commitopts2
2077 + subrepoopts,
2077 + subrepoopts,
2078 _(b'[OPTION]... [FILE]...'),
2078 _(b'[OPTION]... [FILE]...'),
2079 helpcategory=command.CATEGORY_COMMITTING,
2079 helpcategory=command.CATEGORY_COMMITTING,
2080 helpbasic=True,
2080 helpbasic=True,
2081 inferrepo=True,
2081 inferrepo=True,
2082 )
2082 )
2083 def commit(ui, repo, *pats, **opts):
2083 def commit(ui, repo, *pats, **opts):
2084 """commit the specified files or all outstanding changes
2084 """commit the specified files or all outstanding changes
2085
2085
2086 Commit changes to the given files into the repository. Unlike a
2086 Commit changes to the given files into the repository. Unlike a
2087 centralized SCM, this operation is a local operation. See
2087 centralized SCM, this operation is a local operation. See
2088 :hg:`push` for a way to actively distribute your changes.
2088 :hg:`push` for a way to actively distribute your changes.
2089
2089
2090 If a list of files is omitted, all changes reported by :hg:`status`
2090 If a list of files is omitted, all changes reported by :hg:`status`
2091 will be committed.
2091 will be committed.
2092
2092
2093 If you are committing the result of a merge, do not provide any
2093 If you are committing the result of a merge, do not provide any
2094 filenames or -I/-X filters.
2094 filenames or -I/-X filters.
2095
2095
2096 If no commit message is specified, Mercurial starts your
2096 If no commit message is specified, Mercurial starts your
2097 configured editor where you can enter a message. In case your
2097 configured editor where you can enter a message. In case your
2098 commit fails, you will find a backup of your message in
2098 commit fails, you will find a backup of your message in
2099 ``.hg/last-message.txt``.
2099 ``.hg/last-message.txt``.
2100
2100
2101 The --close-branch flag can be used to mark the current branch
2101 The --close-branch flag can be used to mark the current branch
2102 head closed. When all heads of a branch are closed, the branch
2102 head closed. When all heads of a branch are closed, the branch
2103 will be considered closed and no longer listed.
2103 will be considered closed and no longer listed.
2104
2104
2105 The --amend flag can be used to amend the parent of the
2105 The --amend flag can be used to amend the parent of the
2106 working directory with a new commit that contains the changes
2106 working directory with a new commit that contains the changes
2107 in the parent in addition to those currently reported by :hg:`status`,
2107 in the parent in addition to those currently reported by :hg:`status`,
2108 if there are any. The old commit is stored in a backup bundle in
2108 if there are any. The old commit is stored in a backup bundle in
2109 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2109 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2110 on how to restore it).
2110 on how to restore it).
2111
2111
2112 Message, user and date are taken from the amended commit unless
2112 Message, user and date are taken from the amended commit unless
2113 specified. When a message isn't specified on the command line,
2113 specified. When a message isn't specified on the command line,
2114 the editor will open with the message of the amended commit.
2114 the editor will open with the message of the amended commit.
2115
2115
2116 It is not possible to amend public changesets (see :hg:`help phases`)
2116 It is not possible to amend public changesets (see :hg:`help phases`)
2117 or changesets that have children.
2117 or changesets that have children.
2118
2118
2119 See :hg:`help dates` for a list of formats valid for -d/--date.
2119 See :hg:`help dates` for a list of formats valid for -d/--date.
2120
2120
2121 Returns 0 on success, 1 if nothing changed.
2121 Returns 0 on success, 1 if nothing changed.
2122
2122
2123 .. container:: verbose
2123 .. container:: verbose
2124
2124
2125 Examples:
2125 Examples:
2126
2126
2127 - commit all files ending in .py::
2127 - commit all files ending in .py::
2128
2128
2129 hg commit --include "set:**.py"
2129 hg commit --include "set:**.py"
2130
2130
2131 - commit all non-binary files::
2131 - commit all non-binary files::
2132
2132
2133 hg commit --exclude "set:binary()"
2133 hg commit --exclude "set:binary()"
2134
2134
2135 - amend the current commit and set the date to now::
2135 - amend the current commit and set the date to now::
2136
2136
2137 hg commit --amend --date now
2137 hg commit --amend --date now
2138 """
2138 """
2139 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2139 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2140 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2140 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2141 with repo.wlock(), repo.lock():
2141 with repo.wlock(), repo.lock():
2142 return _docommit(ui, repo, *pats, **opts)
2142 return _docommit(ui, repo, *pats, **opts)
2143
2143
2144
2144
2145 def _docommit(ui, repo, *pats, **opts):
2145 def _docommit(ui, repo, *pats, **opts):
2146 if opts.get('interactive'):
2146 if opts.get('interactive'):
2147 opts.pop('interactive')
2147 opts.pop('interactive')
2148 ret = cmdutil.dorecord(
2148 ret = cmdutil.dorecord(
2149 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2149 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2150 )
2150 )
2151 # ret can be 0 (no changes to record) or the value returned by
2151 # ret can be 0 (no changes to record) or the value returned by
2152 # commit(), 1 if nothing changed or None on success.
2152 # commit(), 1 if nothing changed or None on success.
2153 return 1 if ret == 0 else ret
2153 return 1 if ret == 0 else ret
2154
2154
2155 if opts.get('subrepos'):
2155 if opts.get('subrepos'):
2156 # Let --subrepos on the command line override config setting.
2156 # Let --subrepos on the command line override config setting.
2157 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2157 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2158
2158
2159 cmdutil.checkunfinished(repo, commit=True)
2159 cmdutil.checkunfinished(repo, commit=True)
2160
2160
2161 branch = repo[None].branch()
2161 branch = repo[None].branch()
2162 bheads = repo.branchheads(branch)
2162 bheads = repo.branchheads(branch)
2163 tip = repo.changelog.tip()
2163 tip = repo.changelog.tip()
2164
2164
2165 extra = {}
2165 extra = {}
2166 if opts.get('close_branch') or opts.get('force_close_branch'):
2166 if opts.get('close_branch') or opts.get('force_close_branch'):
2167 extra[b'close'] = b'1'
2167 extra[b'close'] = b'1'
2168
2168
2169 if repo[b'.'].closesbranch():
2169 if repo[b'.'].closesbranch():
2170 # Not ideal, but let us do an extra status early to prevent early
2170 # Not ideal, but let us do an extra status early to prevent early
2171 # bail out.
2171 # bail out.
2172 matcher = scmutil.match(
2172 matcher = scmutil.match(
2173 repo[None], pats, pycompat.byteskwargs(opts)
2173 repo[None], pats, pycompat.byteskwargs(opts)
2174 )
2174 )
2175 s = repo.status(match=matcher)
2175 s = repo.status(match=matcher)
2176 if s.modified or s.added or s.removed:
2176 if s.modified or s.added or s.removed:
2177 bheads = repo.branchheads(branch, closed=True)
2177 bheads = repo.branchheads(branch, closed=True)
2178 else:
2178 else:
2179 msg = _(b'current revision is already a branch closing head')
2179 msg = _(b'current revision is already a branch closing head')
2180 raise error.InputError(msg)
2180 raise error.InputError(msg)
2181
2181
2182 if not bheads:
2182 if not bheads:
2183 raise error.InputError(
2183 raise error.InputError(
2184 _(b'branch "%s" has no heads to close') % branch
2184 _(b'branch "%s" has no heads to close') % branch
2185 )
2185 )
2186 elif (
2186 elif (
2187 branch == repo[b'.'].branch()
2187 branch == repo[b'.'].branch()
2188 and repo[b'.'].node() not in bheads
2188 and repo[b'.'].node() not in bheads
2189 and not opts.get('force_close_branch')
2189 and not opts.get('force_close_branch')
2190 ):
2190 ):
2191 hint = _(
2191 hint = _(
2192 b'use --force-close-branch to close branch from a non-head'
2192 b'use --force-close-branch to close branch from a non-head'
2193 b' changeset'
2193 b' changeset'
2194 )
2194 )
2195 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2195 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2196 elif opts.get('amend'):
2196 elif opts.get('amend'):
2197 if (
2197 if (
2198 repo[b'.'].p1().branch() != branch
2198 repo[b'.'].p1().branch() != branch
2199 and repo[b'.'].p2().branch() != branch
2199 and repo[b'.'].p2().branch() != branch
2200 ):
2200 ):
2201 raise error.InputError(_(b'can only close branch heads'))
2201 raise error.InputError(_(b'can only close branch heads'))
2202
2202
2203 if opts.get('amend'):
2203 if opts.get('amend'):
2204 if ui.configbool(b'ui', b'commitsubrepos'):
2204 if ui.configbool(b'ui', b'commitsubrepos'):
2205 raise error.InputError(
2205 raise error.InputError(
2206 _(b'cannot amend with ui.commitsubrepos enabled')
2206 _(b'cannot amend with ui.commitsubrepos enabled')
2207 )
2207 )
2208
2208
2209 old = repo[b'.']
2209 old = repo[b'.']
2210 rewriteutil.precheck(repo, [old.rev()], b'amend')
2210 rewriteutil.precheck(repo, [old.rev()], b'amend')
2211
2211
2212 # Currently histedit gets confused if an amend happens while histedit
2212 # Currently histedit gets confused if an amend happens while histedit
2213 # is in progress. Since we have a checkunfinished command, we are
2213 # is in progress. Since we have a checkunfinished command, we are
2214 # temporarily honoring it.
2214 # temporarily honoring it.
2215 #
2215 #
2216 # Note: eventually this guard will be removed. Please do not expect
2216 # Note: eventually this guard will be removed. Please do not expect
2217 # this behavior to remain.
2217 # this behavior to remain.
2218 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2218 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2219 cmdutil.checkunfinished(repo)
2219 cmdutil.checkunfinished(repo)
2220
2220
2221 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2221 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2222 if node == old.node():
2222 if node == old.node():
2223 ui.status(_(b"nothing changed\n"))
2223 ui.status(_(b"nothing changed\n"))
2224 return 1
2224 return 1
2225 else:
2225 else:
2226
2226
2227 def commitfunc(ui, repo, message, match, opts):
2227 def commitfunc(ui, repo, message, match, opts):
2228 overrides = {}
2228 overrides = {}
2229 if opts.get(b'secret'):
2229 if opts.get(b'secret'):
2230 overrides[(b'phases', b'new-commit')] = b'secret'
2230 overrides[(b'phases', b'new-commit')] = b'secret'
2231 elif opts.get(b'draft'):
2231 elif opts.get(b'draft'):
2232 overrides[(b'phases', b'new-commit')] = b'draft'
2232 overrides[(b'phases', b'new-commit')] = b'draft'
2233
2233
2234 baseui = repo.baseui
2234 baseui = repo.baseui
2235 with baseui.configoverride(overrides, b'commit'):
2235 with baseui.configoverride(overrides, b'commit'):
2236 with ui.configoverride(overrides, b'commit'):
2236 with ui.configoverride(overrides, b'commit'):
2237 editform = cmdutil.mergeeditform(
2237 editform = cmdutil.mergeeditform(
2238 repo[None], b'commit.normal'
2238 repo[None], b'commit.normal'
2239 )
2239 )
2240 editor = cmdutil.getcommiteditor(
2240 editor = cmdutil.getcommiteditor(
2241 editform=editform, **pycompat.strkwargs(opts)
2241 editform=editform, **pycompat.strkwargs(opts)
2242 )
2242 )
2243 return repo.commit(
2243 return repo.commit(
2244 message,
2244 message,
2245 opts.get(b'user'),
2245 opts.get(b'user'),
2246 opts.get(b'date'),
2246 opts.get(b'date'),
2247 match,
2247 match,
2248 editor=editor,
2248 editor=editor,
2249 extra=extra,
2249 extra=extra,
2250 )
2250 )
2251
2251
2252 node = cmdutil.commit(
2252 node = cmdutil.commit(
2253 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2253 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2254 )
2254 )
2255
2255
2256 if not node:
2256 if not node:
2257 stat = cmdutil.postcommitstatus(
2257 stat = cmdutil.postcommitstatus(
2258 repo, pats, pycompat.byteskwargs(opts)
2258 repo, pats, pycompat.byteskwargs(opts)
2259 )
2259 )
2260 if stat.deleted:
2260 if stat.deleted:
2261 ui.status(
2261 ui.status(
2262 _(
2262 _(
2263 b"nothing changed (%d missing files, see "
2263 b"nothing changed (%d missing files, see "
2264 b"'hg status')\n"
2264 b"'hg status')\n"
2265 )
2265 )
2266 % len(stat.deleted)
2266 % len(stat.deleted)
2267 )
2267 )
2268 else:
2268 else:
2269 ui.status(_(b"nothing changed\n"))
2269 ui.status(_(b"nothing changed\n"))
2270 return 1
2270 return 1
2271
2271
2272 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2272 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2273
2273
2274 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2274 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2275 status(
2275 status(
2276 ui,
2276 ui,
2277 repo,
2277 repo,
2278 modified=True,
2278 modified=True,
2279 added=True,
2279 added=True,
2280 removed=True,
2280 removed=True,
2281 deleted=True,
2281 deleted=True,
2282 unknown=True,
2282 unknown=True,
2283 subrepos=opts.get('subrepos'),
2283 subrepos=opts.get('subrepos'),
2284 )
2284 )
2285
2285
2286
2286
2287 @command(
2287 @command(
2288 b'config|showconfig|debugconfig',
2288 b'config|showconfig|debugconfig',
2289 [
2289 [
2290 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2290 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2291 # This is experimental because we need
2291 # This is experimental because we need
2292 # * reasonable behavior around aliases,
2292 # * reasonable behavior around aliases,
2293 # * decide if we display [debug] [experimental] and [devel] section par
2293 # * decide if we display [debug] [experimental] and [devel] section par
2294 # default
2294 # default
2295 # * some way to display "generic" config entry (the one matching
2295 # * some way to display "generic" config entry (the one matching
2296 # regexp,
2296 # regexp,
2297 # * proper display of the different value type
2297 # * proper display of the different value type
2298 # * a better way to handle <DYNAMIC> values (and variable types),
2298 # * a better way to handle <DYNAMIC> values (and variable types),
2299 # * maybe some type information ?
2299 # * maybe some type information ?
2300 (
2300 (
2301 b'',
2301 b'',
2302 b'exp-all-known',
2302 b'exp-all-known',
2303 None,
2303 None,
2304 _(b'show all known config option (EXPERIMENTAL)'),
2304 _(b'show all known config option (EXPERIMENTAL)'),
2305 ),
2305 ),
2306 (b'e', b'edit', None, _(b'edit user config')),
2306 (b'e', b'edit', None, _(b'edit user config')),
2307 (b'l', b'local', None, _(b'edit repository config')),
2307 (b'l', b'local', None, _(b'edit repository config')),
2308 (b'', b'source', None, _(b'show source of configuration value')),
2308 (b'', b'source', None, _(b'show source of configuration value')),
2309 (
2309 (
2310 b'',
2310 b'',
2311 b'shared',
2311 b'shared',
2312 None,
2312 None,
2313 _(b'edit shared source repository config (EXPERIMENTAL)'),
2313 _(b'edit shared source repository config (EXPERIMENTAL)'),
2314 ),
2314 ),
2315 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2315 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2316 (b'g', b'global', None, _(b'edit global config')),
2316 (b'g', b'global', None, _(b'edit global config')),
2317 ]
2317 ]
2318 + formatteropts,
2318 + formatteropts,
2319 _(b'[-u] [NAME]...'),
2319 _(b'[-u] [NAME]...'),
2320 helpcategory=command.CATEGORY_HELP,
2320 helpcategory=command.CATEGORY_HELP,
2321 optionalrepo=True,
2321 optionalrepo=True,
2322 intents={INTENT_READONLY},
2322 intents={INTENT_READONLY},
2323 )
2323 )
2324 def config(ui, repo, *values, **opts):
2324 def config(ui, repo, *values, **opts):
2325 """show combined config settings from all hgrc files
2325 """show combined config settings from all hgrc files
2326
2326
2327 With no arguments, print names and values of all config items.
2327 With no arguments, print names and values of all config items.
2328
2328
2329 With one argument of the form section.name, print just the value
2329 With one argument of the form section.name, print just the value
2330 of that config item.
2330 of that config item.
2331
2331
2332 With multiple arguments, print names and values of all config
2332 With multiple arguments, print names and values of all config
2333 items with matching section names or section.names.
2333 items with matching section names or section.names.
2334
2334
2335 With --edit, start an editor on the user-level config file. With
2335 With --edit, start an editor on the user-level config file. With
2336 --global, edit the system-wide config file. With --local, edit the
2336 --global, edit the system-wide config file. With --local, edit the
2337 repository-level config file.
2337 repository-level config file.
2338
2338
2339 With --source, the source (filename and line number) is printed
2339 With --source, the source (filename and line number) is printed
2340 for each config item.
2340 for each config item.
2341
2341
2342 See :hg:`help config` for more information about config files.
2342 See :hg:`help config` for more information about config files.
2343
2343
2344 .. container:: verbose
2344 .. container:: verbose
2345
2345
2346 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2346 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2347 This file is not shared across shares when in share-safe mode.
2347 This file is not shared across shares when in share-safe mode.
2348
2348
2349 Template:
2349 Template:
2350
2350
2351 The following keywords are supported. See also :hg:`help templates`.
2351 The following keywords are supported. See also :hg:`help templates`.
2352
2352
2353 :name: String. Config name.
2353 :name: String. Config name.
2354 :source: String. Filename and line number where the item is defined.
2354 :source: String. Filename and line number where the item is defined.
2355 :value: String. Config value.
2355 :value: String. Config value.
2356
2356
2357 The --shared flag can be used to edit the config file of shared source
2357 The --shared flag can be used to edit the config file of shared source
2358 repository. It only works when you have shared using the experimental
2358 repository. It only works when you have shared using the experimental
2359 share safe feature.
2359 share safe feature.
2360
2360
2361 Returns 0 on success, 1 if NAME does not exist.
2361 Returns 0 on success, 1 if NAME does not exist.
2362
2362
2363 """
2363 """
2364
2364
2365 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2365 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2366 if any(opts.get(o) for o in editopts):
2366 if any(opts.get(o) for o in editopts):
2367 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2367 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2368 if opts.get('local'):
2368 if opts.get('local'):
2369 if not repo:
2369 if not repo:
2370 raise error.InputError(
2370 raise error.InputError(
2371 _(b"can't use --local outside a repository")
2371 _(b"can't use --local outside a repository")
2372 )
2372 )
2373 paths = [repo.vfs.join(b'hgrc')]
2373 paths = [repo.vfs.join(b'hgrc')]
2374 elif opts.get('global'):
2374 elif opts.get('global'):
2375 paths = rcutil.systemrcpath()
2375 paths = rcutil.systemrcpath()
2376 elif opts.get('shared'):
2376 elif opts.get('shared'):
2377 if not repo.shared():
2377 if not repo.shared():
2378 raise error.InputError(
2378 raise error.InputError(
2379 _(b"repository is not shared; can't use --shared")
2379 _(b"repository is not shared; can't use --shared")
2380 )
2380 )
2381 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2381 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2382 raise error.InputError(
2382 raise error.InputError(
2383 _(
2383 _(
2384 b"share safe feature not enabled; "
2384 b"share safe feature not enabled; "
2385 b"unable to edit shared source repository config"
2385 b"unable to edit shared source repository config"
2386 )
2386 )
2387 )
2387 )
2388 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2388 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2389 elif opts.get('non_shared'):
2389 elif opts.get('non_shared'):
2390 paths = [repo.vfs.join(b'hgrc-not-shared')]
2390 paths = [repo.vfs.join(b'hgrc-not-shared')]
2391 else:
2391 else:
2392 paths = rcutil.userrcpath()
2392 paths = rcutil.userrcpath()
2393
2393
2394 for f in paths:
2394 for f in paths:
2395 if os.path.exists(f):
2395 if os.path.exists(f):
2396 break
2396 break
2397 else:
2397 else:
2398 if opts.get('global'):
2398 if opts.get('global'):
2399 samplehgrc = uimod.samplehgrcs[b'global']
2399 samplehgrc = uimod.samplehgrcs[b'global']
2400 elif opts.get('local'):
2400 elif opts.get('local'):
2401 samplehgrc = uimod.samplehgrcs[b'local']
2401 samplehgrc = uimod.samplehgrcs[b'local']
2402 else:
2402 else:
2403 samplehgrc = uimod.samplehgrcs[b'user']
2403 samplehgrc = uimod.samplehgrcs[b'user']
2404
2404
2405 f = paths[0]
2405 f = paths[0]
2406 util.writefile(f, util.tonativeeol(samplehgrc))
2406 util.writefile(f, util.tonativeeol(samplehgrc))
2407
2407
2408 editor = ui.geteditor()
2408 editor = ui.geteditor()
2409 ui.system(
2409 ui.system(
2410 b"%s \"%s\"" % (editor, f),
2410 b"%s \"%s\"" % (editor, f),
2411 onerr=error.InputError,
2411 onerr=error.InputError,
2412 errprefix=_(b"edit failed"),
2412 errprefix=_(b"edit failed"),
2413 blockedtag=b'config_edit',
2413 blockedtag=b'config_edit',
2414 )
2414 )
2415 return
2415 return
2416 ui.pager(b'config')
2416 ui.pager(b'config')
2417 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2417 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2418 for t, f in rcutil.rccomponents():
2418 for t, f in rcutil.rccomponents():
2419 if t == b'path':
2419 if t == b'path':
2420 ui.debug(b'read config from: %s\n' % f)
2420 ui.debug(b'read config from: %s\n' % f)
2421 elif t == b'resource':
2421 elif t == b'resource':
2422 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2422 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2423 elif t == b'items':
2423 elif t == b'items':
2424 # Don't print anything for 'items'.
2424 # Don't print anything for 'items'.
2425 pass
2425 pass
2426 else:
2426 else:
2427 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2427 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2428 untrusted = bool(opts.get('untrusted'))
2428 untrusted = bool(opts.get('untrusted'))
2429
2429
2430 selsections = selentries = []
2430 selsections = selentries = []
2431 if values:
2431 if values:
2432 selsections = [v for v in values if b'.' not in v]
2432 selsections = [v for v in values if b'.' not in v]
2433 selentries = [v for v in values if b'.' in v]
2433 selentries = [v for v in values if b'.' in v]
2434 uniquesel = len(selentries) == 1 and not selsections
2434 uniquesel = len(selentries) == 1 and not selsections
2435 selsections = set(selsections)
2435 selsections = set(selsections)
2436 selentries = set(selentries)
2436 selentries = set(selentries)
2437
2437
2438 matched = False
2438 matched = False
2439 all_known = opts['exp_all_known']
2439 all_known = opts['exp_all_known']
2440 show_source = ui.debugflag or opts.get('source')
2440 show_source = ui.debugflag or opts.get('source')
2441 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2441 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2442 for section, name, value in entries:
2442 for section, name, value in entries:
2443 source = ui.configsource(section, name, untrusted)
2443 source = ui.configsource(section, name, untrusted)
2444 value = pycompat.bytestr(value)
2444 value = pycompat.bytestr(value)
2445 defaultvalue = ui.configdefault(section, name)
2445 defaultvalue = ui.configdefault(section, name)
2446 if fm.isplain():
2446 if fm.isplain():
2447 source = source or b'none'
2447 source = source or b'none'
2448 value = value.replace(b'\n', b'\\n')
2448 value = value.replace(b'\n', b'\\n')
2449 entryname = section + b'.' + name
2449 entryname = section + b'.' + name
2450 if values and not (section in selsections or entryname in selentries):
2450 if values and not (section in selsections or entryname in selentries):
2451 continue
2451 continue
2452 fm.startitem()
2452 fm.startitem()
2453 fm.condwrite(show_source, b'source', b'%s: ', source)
2453 fm.condwrite(show_source, b'source', b'%s: ', source)
2454 if uniquesel:
2454 if uniquesel:
2455 fm.data(name=entryname)
2455 fm.data(name=entryname)
2456 fm.write(b'value', b'%s\n', value)
2456 fm.write(b'value', b'%s\n', value)
2457 else:
2457 else:
2458 fm.write(b'name value', b'%s=%s\n', entryname, value)
2458 fm.write(b'name value', b'%s=%s\n', entryname, value)
2459 if formatter.isprintable(defaultvalue):
2459 if formatter.isprintable(defaultvalue):
2460 fm.data(defaultvalue=defaultvalue)
2460 fm.data(defaultvalue=defaultvalue)
2461 elif isinstance(defaultvalue, list) and all(
2461 elif isinstance(defaultvalue, list) and all(
2462 formatter.isprintable(e) for e in defaultvalue
2462 formatter.isprintable(e) for e in defaultvalue
2463 ):
2463 ):
2464 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2464 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2465 # TODO: no idea how to process unsupported defaultvalue types
2465 # TODO: no idea how to process unsupported defaultvalue types
2466 matched = True
2466 matched = True
2467 fm.end()
2467 fm.end()
2468 if matched:
2468 if matched:
2469 return 0
2469 return 0
2470 return 1
2470 return 1
2471
2471
2472
2472
2473 @command(
2473 @command(
2474 b'continue',
2474 b'continue',
2475 dryrunopts,
2475 dryrunopts,
2476 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2476 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2477 helpbasic=True,
2477 helpbasic=True,
2478 )
2478 )
2479 def continuecmd(ui, repo, **opts):
2479 def continuecmd(ui, repo, **opts):
2480 """resumes an interrupted operation (EXPERIMENTAL)
2480 """resumes an interrupted operation (EXPERIMENTAL)
2481
2481
2482 Finishes a multistep operation like graft, histedit, rebase, merge,
2482 Finishes a multistep operation like graft, histedit, rebase, merge,
2483 and unshelve if they are in an interrupted state.
2483 and unshelve if they are in an interrupted state.
2484
2484
2485 use --dry-run/-n to dry run the command.
2485 use --dry-run/-n to dry run the command.
2486 """
2486 """
2487 dryrun = opts.get('dry_run')
2487 dryrun = opts.get('dry_run')
2488 contstate = cmdutil.getunfinishedstate(repo)
2488 contstate = cmdutil.getunfinishedstate(repo)
2489 if not contstate:
2489 if not contstate:
2490 raise error.StateError(_(b'no operation in progress'))
2490 raise error.StateError(_(b'no operation in progress'))
2491 if not contstate.continuefunc:
2491 if not contstate.continuefunc:
2492 raise error.StateError(
2492 raise error.StateError(
2493 (
2493 (
2494 _(b"%s in progress but does not support 'hg continue'")
2494 _(b"%s in progress but does not support 'hg continue'")
2495 % (contstate._opname)
2495 % (contstate._opname)
2496 ),
2496 ),
2497 hint=contstate.continuemsg(),
2497 hint=contstate.continuemsg(),
2498 )
2498 )
2499 if dryrun:
2499 if dryrun:
2500 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2500 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2501 return
2501 return
2502 return contstate.continuefunc(ui, repo)
2502 return contstate.continuefunc(ui, repo)
2503
2503
2504
2504
2505 @command(
2505 @command(
2506 b'copy|cp',
2506 b'copy|cp',
2507 [
2507 [
2508 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2508 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2509 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2509 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2510 (
2510 (
2511 b'',
2511 b'',
2512 b'at-rev',
2512 b'at-rev',
2513 b'',
2513 b'',
2514 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2514 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2515 _(b'REV'),
2515 _(b'REV'),
2516 ),
2516 ),
2517 (
2517 (
2518 b'f',
2518 b'f',
2519 b'force',
2519 b'force',
2520 None,
2520 None,
2521 _(b'forcibly copy over an existing managed file'),
2521 _(b'forcibly copy over an existing managed file'),
2522 ),
2522 ),
2523 ]
2523 ]
2524 + walkopts
2524 + walkopts
2525 + dryrunopts,
2525 + dryrunopts,
2526 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2526 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2527 helpcategory=command.CATEGORY_FILE_CONTENTS,
2527 helpcategory=command.CATEGORY_FILE_CONTENTS,
2528 )
2528 )
2529 def copy(ui, repo, *pats, **opts):
2529 def copy(ui, repo, *pats, **opts):
2530 """mark files as copied for the next commit
2530 """mark files as copied for the next commit
2531
2531
2532 Mark dest as having copies of source files. If dest is a
2532 Mark dest as having copies of source files. If dest is a
2533 directory, copies are put in that directory. If dest is a file,
2533 directory, copies are put in that directory. If dest is a file,
2534 the source must be a single file.
2534 the source must be a single file.
2535
2535
2536 By default, this command copies the contents of files as they
2536 By default, this command copies the contents of files as they
2537 exist in the working directory. If invoked with -A/--after, the
2537 exist in the working directory. If invoked with -A/--after, the
2538 operation is recorded, but no copying is performed.
2538 operation is recorded, but no copying is performed.
2539
2539
2540 To undo marking a destination file as copied, use --forget. With that
2540 To undo marking a destination file as copied, use --forget. With that
2541 option, all given (positional) arguments are unmarked as copies. The
2541 option, all given (positional) arguments are unmarked as copies. The
2542 destination file(s) will be left in place (still tracked). Note that
2542 destination file(s) will be left in place (still tracked). Note that
2543 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2543 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2544
2544
2545 This command takes effect with the next commit by default.
2545 This command takes effect with the next commit by default.
2546
2546
2547 Returns 0 on success, 1 if errors are encountered.
2547 Returns 0 on success, 1 if errors are encountered.
2548 """
2548 """
2549
2549
2550 context = lambda repo: repo.dirstate.changing_files(repo)
2550 context = lambda repo: repo.dirstate.changing_files(repo)
2551 rev = opts.get('at_rev')
2551 rev = opts.get('at_rev')
2552
2552
2553 if rev:
2553 if rev:
2554 ctx = logcmdutil.revsingle(repo, rev)
2554 ctx = logcmdutil.revsingle(repo, rev)
2555 if ctx.rev() is not None:
2555 if ctx.rev() is not None:
2556
2556
2557 def context(repo):
2557 def context(repo):
2558 return util.nullcontextmanager()
2558 return util.nullcontextmanager()
2559
2559
2560 opts['at_rev'] = ctx.rev()
2560 opts['at_rev'] = ctx.rev()
2561 with repo.wlock(), context(repo):
2561 with repo.wlock(), context(repo):
2562 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2562 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2563
2563
2564
2564
2565 @command(
2565 @command(
2566 b'debugcommands',
2566 b'debugcommands',
2567 [],
2567 [],
2568 _(b'[COMMAND]'),
2568 _(b'[COMMAND]'),
2569 helpcategory=command.CATEGORY_HELP,
2569 helpcategory=command.CATEGORY_HELP,
2570 norepo=True,
2570 norepo=True,
2571 )
2571 )
2572 def debugcommands(ui, cmd=b'', *args):
2572 def debugcommands(ui, cmd=b'', *args):
2573 """list all available commands and options"""
2573 """list all available commands and options"""
2574 for cmd, vals in sorted(table.items()):
2574 for cmd, vals in sorted(table.items()):
2575 cmd = cmd.split(b'|')[0]
2575 cmd = cmd.split(b'|')[0]
2576 opts = b', '.join([i[1] for i in vals[1]])
2576 opts = b', '.join([i[1] for i in vals[1]])
2577 ui.write(b'%s: %s\n' % (cmd, opts))
2577 ui.write(b'%s: %s\n' % (cmd, opts))
2578
2578
2579
2579
2580 @command(
2580 @command(
2581 b'debugcomplete',
2581 b'debugcomplete',
2582 [(b'o', b'options', None, _(b'show the command options'))],
2582 [(b'o', b'options', None, _(b'show the command options'))],
2583 _(b'[-o] CMD'),
2583 _(b'[-o] CMD'),
2584 helpcategory=command.CATEGORY_HELP,
2584 helpcategory=command.CATEGORY_HELP,
2585 norepo=True,
2585 norepo=True,
2586 )
2586 )
2587 def debugcomplete(ui, cmd=b'', **opts):
2587 def debugcomplete(ui, cmd=b'', **opts):
2588 """returns the completion list associated with the given command"""
2588 """returns the completion list associated with the given command"""
2589
2589
2590 if opts.get('options'):
2590 if opts.get('options'):
2591 options = []
2591 options = []
2592 otables = [globalopts]
2592 otables = [globalopts]
2593 if cmd:
2593 if cmd:
2594 aliases, entry = cmdutil.findcmd(cmd, table, False)
2594 aliases, entry = cmdutil.findcmd(cmd, table, False)
2595 otables.append(entry[1])
2595 otables.append(entry[1])
2596 for t in otables:
2596 for t in otables:
2597 for o in t:
2597 for o in t:
2598 if b"(DEPRECATED)" in o[3]:
2598 if b"(DEPRECATED)" in o[3]:
2599 continue
2599 continue
2600 if o[0]:
2600 if o[0]:
2601 options.append(b'-%s' % o[0])
2601 options.append(b'-%s' % o[0])
2602 options.append(b'--%s' % o[1])
2602 options.append(b'--%s' % o[1])
2603 ui.write(b"%s\n" % b"\n".join(options))
2603 ui.write(b"%s\n" % b"\n".join(options))
2604 return
2604 return
2605
2605
2606 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2606 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2607 if ui.verbose:
2607 if ui.verbose:
2608 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2608 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2609 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2609 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2610
2610
2611
2611
2612 @command(
2612 @command(
2613 b'diff',
2613 b'diff',
2614 [
2614 [
2615 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2615 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2616 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2616 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2617 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2617 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2618 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2618 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2619 ]
2619 ]
2620 + diffopts
2620 + diffopts
2621 + diffopts2
2621 + diffopts2
2622 + walkopts
2622 + walkopts
2623 + subrepoopts,
2623 + subrepoopts,
2624 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2624 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2625 helpcategory=command.CATEGORY_FILE_CONTENTS,
2625 helpcategory=command.CATEGORY_FILE_CONTENTS,
2626 helpbasic=True,
2626 helpbasic=True,
2627 inferrepo=True,
2627 inferrepo=True,
2628 intents={INTENT_READONLY},
2628 intents={INTENT_READONLY},
2629 )
2629 )
2630 def diff(ui, repo, *pats, **opts):
2630 def diff(ui, repo, *pats, **opts):
2631 """diff repository (or selected files)
2631 """diff repository (or selected files)
2632
2632
2633 Show differences between revisions for the specified files.
2633 Show differences between revisions for the specified files.
2634
2634
2635 Differences between files are shown using the unified diff format.
2635 Differences between files are shown using the unified diff format.
2636
2636
2637 .. note::
2637 .. note::
2638
2638
2639 :hg:`diff` may generate unexpected results for merges, as it will
2639 :hg:`diff` may generate unexpected results for merges, as it will
2640 default to comparing against the working directory's first
2640 default to comparing against the working directory's first
2641 parent changeset if no revisions are specified. To diff against the
2641 parent changeset if no revisions are specified. To diff against the
2642 conflict regions, you can use `--config diff.merge=yes`.
2642 conflict regions, you can use `--config diff.merge=yes`.
2643
2643
2644 By default, the working directory files are compared to its first parent. To
2644 By default, the working directory files are compared to its first parent. To
2645 see the differences from another revision, use --from. To see the difference
2645 see the differences from another revision, use --from. To see the difference
2646 to another revision, use --to. For example, :hg:`diff --from .^` will show
2646 to another revision, use --to. For example, :hg:`diff --from .^` will show
2647 the differences from the working copy's grandparent to the working copy,
2647 the differences from the working copy's grandparent to the working copy,
2648 :hg:`diff --to .` will show the diff from the working copy to its parent
2648 :hg:`diff --to .` will show the diff from the working copy to its parent
2649 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2649 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2650 show the diff between those two revisions.
2650 show the diff between those two revisions.
2651
2651
2652 Alternatively you can specify -c/--change with a revision to see the changes
2652 Alternatively you can specify -c/--change with a revision to see the changes
2653 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2653 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2654 equivalent to :hg:`diff --from 42^ --to 42`)
2654 equivalent to :hg:`diff --from 42^ --to 42`)
2655
2655
2656 Without the -a/--text option, diff will avoid generating diffs of
2656 Without the -a/--text option, diff will avoid generating diffs of
2657 files it detects as binary. With -a, diff will generate a diff
2657 files it detects as binary. With -a, diff will generate a diff
2658 anyway, probably with undesirable results.
2658 anyway, probably with undesirable results.
2659
2659
2660 Use the -g/--git option to generate diffs in the git extended diff
2660 Use the -g/--git option to generate diffs in the git extended diff
2661 format. For more information, read :hg:`help diffs`.
2661 format. For more information, read :hg:`help diffs`.
2662
2662
2663 .. container:: verbose
2663 .. container:: verbose
2664
2664
2665 Examples:
2665 Examples:
2666
2666
2667 - compare a file in the current working directory to its parent::
2667 - compare a file in the current working directory to its parent::
2668
2668
2669 hg diff foo.c
2669 hg diff foo.c
2670
2670
2671 - compare two historical versions of a directory, with rename info::
2671 - compare two historical versions of a directory, with rename info::
2672
2672
2673 hg diff --git --from 1.0 --to 1.2 lib/
2673 hg diff --git --from 1.0 --to 1.2 lib/
2674
2674
2675 - get change stats relative to the last change on some date::
2675 - get change stats relative to the last change on some date::
2676
2676
2677 hg diff --stat --from "date('may 2')"
2677 hg diff --stat --from "date('may 2')"
2678
2678
2679 - diff all newly-added files that contain a keyword::
2679 - diff all newly-added files that contain a keyword::
2680
2680
2681 hg diff "set:added() and grep(GNU)"
2681 hg diff "set:added() and grep(GNU)"
2682
2682
2683 - compare a revision and its parents::
2683 - compare a revision and its parents::
2684
2684
2685 hg diff -c 9353 # compare against first parent
2685 hg diff -c 9353 # compare against first parent
2686 hg diff --from 9353^ --to 9353 # same using revset syntax
2686 hg diff --from 9353^ --to 9353 # same using revset syntax
2687 hg diff --from 9353^2 --to 9353 # compare against the second parent
2687 hg diff --from 9353^2 --to 9353 # compare against the second parent
2688
2688
2689 Returns 0 on success.
2689 Returns 0 on success.
2690 """
2690 """
2691
2691
2692 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2692 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2693 opts = pycompat.byteskwargs(opts)
2693 opts = pycompat.byteskwargs(opts)
2694 revs = opts.get(b'rev')
2694 revs = opts.get(b'rev')
2695 change = opts.get(b'change')
2695 change = opts.get(b'change')
2696 from_rev = opts.get(b'from')
2696 from_rev = opts.get(b'from')
2697 to_rev = opts.get(b'to')
2697 to_rev = opts.get(b'to')
2698 stat = opts.get(b'stat')
2698 stat = opts.get(b'stat')
2699 reverse = opts.get(b'reverse')
2699 reverse = opts.get(b'reverse')
2700
2700
2701 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2701 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2702 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2702 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2703 if change:
2703 if change:
2704 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2704 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2705 ctx2 = logcmdutil.revsingle(repo, change, None)
2705 ctx2 = logcmdutil.revsingle(repo, change, None)
2706 ctx1 = diffutil.diff_parent(ctx2)
2706 ctx1 = diffutil.diff_parent(ctx2)
2707 elif from_rev or to_rev:
2707 elif from_rev or to_rev:
2708 repo = scmutil.unhidehashlikerevs(
2708 repo = scmutil.unhidehashlikerevs(
2709 repo, [from_rev] + [to_rev], b'nowarn'
2709 repo, [from_rev] + [to_rev], b'nowarn'
2710 )
2710 )
2711 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2711 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2712 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2712 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2713 else:
2713 else:
2714 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2714 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2715 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2715 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2716
2716
2717 if reverse:
2717 if reverse:
2718 ctxleft = ctx2
2718 ctxleft = ctx2
2719 ctxright = ctx1
2719 ctxright = ctx1
2720 else:
2720 else:
2721 ctxleft = ctx1
2721 ctxleft = ctx1
2722 ctxright = ctx2
2722 ctxright = ctx2
2723
2723
2724 diffopts = patch.diffallopts(ui, opts)
2724 diffopts = patch.diffallopts(ui, opts)
2725 m = scmutil.match(ctx2, pats, opts)
2725 m = scmutil.match(ctx2, pats, opts)
2726 m = repo.narrowmatch(m)
2726 m = repo.narrowmatch(m)
2727 ui.pager(b'diff')
2727 ui.pager(b'diff')
2728 logcmdutil.diffordiffstat(
2728 logcmdutil.diffordiffstat(
2729 ui,
2729 ui,
2730 repo,
2730 repo,
2731 diffopts,
2731 diffopts,
2732 ctxleft,
2732 ctxleft,
2733 ctxright,
2733 ctxright,
2734 m,
2734 m,
2735 stat=stat,
2735 stat=stat,
2736 listsubrepos=opts.get(b'subrepos'),
2736 listsubrepos=opts.get(b'subrepos'),
2737 root=opts.get(b'root'),
2737 root=opts.get(b'root'),
2738 )
2738 )
2739
2739
2740
2740
2741 @command(
2741 @command(
2742 b'export',
2742 b'export',
2743 [
2743 [
2744 (
2744 (
2745 b'B',
2745 b'B',
2746 b'bookmark',
2746 b'bookmark',
2747 b'',
2747 b'',
2748 _(b'export changes only reachable by given bookmark'),
2748 _(b'export changes only reachable by given bookmark'),
2749 _(b'BOOKMARK'),
2749 _(b'BOOKMARK'),
2750 ),
2750 ),
2751 (
2751 (
2752 b'o',
2752 b'o',
2753 b'output',
2753 b'output',
2754 b'',
2754 b'',
2755 _(b'print output to file with formatted name'),
2755 _(b'print output to file with formatted name'),
2756 _(b'FORMAT'),
2756 _(b'FORMAT'),
2757 ),
2757 ),
2758 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2758 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2759 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2759 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2760 ]
2760 ]
2761 + diffopts
2761 + diffopts
2762 + formatteropts,
2762 + formatteropts,
2763 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2763 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2764 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2764 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2765 helpbasic=True,
2765 helpbasic=True,
2766 intents={INTENT_READONLY},
2766 intents={INTENT_READONLY},
2767 )
2767 )
2768 def export(ui, repo, *changesets, **opts):
2768 def export(ui, repo, *changesets, **opts):
2769 """dump the header and diffs for one or more changesets
2769 """dump the header and diffs for one or more changesets
2770
2770
2771 Print the changeset header and diffs for one or more revisions.
2771 Print the changeset header and diffs for one or more revisions.
2772 If no revision is given, the parent of the working directory is used.
2772 If no revision is given, the parent of the working directory is used.
2773
2773
2774 The information shown in the changeset header is: author, date,
2774 The information shown in the changeset header is: author, date,
2775 branch name (if non-default), changeset hash, parent(s) and commit
2775 branch name (if non-default), changeset hash, parent(s) and commit
2776 comment.
2776 comment.
2777
2777
2778 .. note::
2778 .. note::
2779
2779
2780 :hg:`export` may generate unexpected diff output for merge
2780 :hg:`export` may generate unexpected diff output for merge
2781 changesets, as it will compare the merge changeset against its
2781 changesets, as it will compare the merge changeset against its
2782 first parent only.
2782 first parent only.
2783
2783
2784 Output may be to a file, in which case the name of the file is
2784 Output may be to a file, in which case the name of the file is
2785 given using a template string. See :hg:`help templates`. In addition
2785 given using a template string. See :hg:`help templates`. In addition
2786 to the common template keywords, the following formatting rules are
2786 to the common template keywords, the following formatting rules are
2787 supported:
2787 supported:
2788
2788
2789 :``%%``: literal "%" character
2789 :``%%``: literal "%" character
2790 :``%H``: changeset hash (40 hexadecimal digits)
2790 :``%H``: changeset hash (40 hexadecimal digits)
2791 :``%N``: number of patches being generated
2791 :``%N``: number of patches being generated
2792 :``%R``: changeset revision number
2792 :``%R``: changeset revision number
2793 :``%b``: basename of the exporting repository
2793 :``%b``: basename of the exporting repository
2794 :``%h``: short-form changeset hash (12 hexadecimal digits)
2794 :``%h``: short-form changeset hash (12 hexadecimal digits)
2795 :``%m``: first line of the commit message (only alphanumeric characters)
2795 :``%m``: first line of the commit message (only alphanumeric characters)
2796 :``%n``: zero-padded sequence number, starting at 1
2796 :``%n``: zero-padded sequence number, starting at 1
2797 :``%r``: zero-padded changeset revision number
2797 :``%r``: zero-padded changeset revision number
2798 :``\\``: literal "\\" character
2798 :``\\``: literal "\\" character
2799
2799
2800 Without the -a/--text option, export will avoid generating diffs
2800 Without the -a/--text option, export will avoid generating diffs
2801 of files it detects as binary. With -a, export will generate a
2801 of files it detects as binary. With -a, export will generate a
2802 diff anyway, probably with undesirable results.
2802 diff anyway, probably with undesirable results.
2803
2803
2804 With -B/--bookmark changesets reachable by the given bookmark are
2804 With -B/--bookmark changesets reachable by the given bookmark are
2805 selected.
2805 selected.
2806
2806
2807 Use the -g/--git option to generate diffs in the git extended diff
2807 Use the -g/--git option to generate diffs in the git extended diff
2808 format. See :hg:`help diffs` for more information.
2808 format. See :hg:`help diffs` for more information.
2809
2809
2810 With the --switch-parent option, the diff will be against the
2810 With the --switch-parent option, the diff will be against the
2811 second parent. It can be useful to review a merge.
2811 second parent. It can be useful to review a merge.
2812
2812
2813 .. container:: verbose
2813 .. container:: verbose
2814
2814
2815 Template:
2815 Template:
2816
2816
2817 The following keywords are supported in addition to the common template
2817 The following keywords are supported in addition to the common template
2818 keywords and functions. See also :hg:`help templates`.
2818 keywords and functions. See also :hg:`help templates`.
2819
2819
2820 :diff: String. Diff content.
2820 :diff: String. Diff content.
2821 :parents: List of strings. Parent nodes of the changeset.
2821 :parents: List of strings. Parent nodes of the changeset.
2822
2822
2823 Examples:
2823 Examples:
2824
2824
2825 - use export and import to transplant a bugfix to the current
2825 - use export and import to transplant a bugfix to the current
2826 branch::
2826 branch::
2827
2827
2828 hg export -r 9353 | hg import -
2828 hg export -r 9353 | hg import -
2829
2829
2830 - export all the changesets between two revisions to a file with
2830 - export all the changesets between two revisions to a file with
2831 rename information::
2831 rename information::
2832
2832
2833 hg export --git -r 123:150 > changes.txt
2833 hg export --git -r 123:150 > changes.txt
2834
2834
2835 - split outgoing changes into a series of patches with
2835 - split outgoing changes into a series of patches with
2836 descriptive names::
2836 descriptive names::
2837
2837
2838 hg export -r "outgoing()" -o "%n-%m.patch"
2838 hg export -r "outgoing()" -o "%n-%m.patch"
2839
2839
2840 Returns 0 on success.
2840 Returns 0 on success.
2841 """
2841 """
2842 opts = pycompat.byteskwargs(opts)
2842 opts = pycompat.byteskwargs(opts)
2843 bookmark = opts.get(b'bookmark')
2843 bookmark = opts.get(b'bookmark')
2844 changesets += tuple(opts.get(b'rev', []))
2844 changesets += tuple(opts.get(b'rev', []))
2845
2845
2846 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2846 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2847
2847
2848 if bookmark:
2848 if bookmark:
2849 if bookmark not in repo._bookmarks:
2849 if bookmark not in repo._bookmarks:
2850 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2850 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2851
2851
2852 revs = scmutil.bookmarkrevs(repo, bookmark)
2852 revs = scmutil.bookmarkrevs(repo, bookmark)
2853 else:
2853 else:
2854 if not changesets:
2854 if not changesets:
2855 changesets = [b'.']
2855 changesets = [b'.']
2856
2856
2857 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2857 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2858 revs = logcmdutil.revrange(repo, changesets)
2858 revs = logcmdutil.revrange(repo, changesets)
2859
2859
2860 if not revs:
2860 if not revs:
2861 raise error.InputError(_(b"export requires at least one changeset"))
2861 raise error.InputError(_(b"export requires at least one changeset"))
2862 if len(revs) > 1:
2862 if len(revs) > 1:
2863 ui.note(_(b'exporting patches:\n'))
2863 ui.note(_(b'exporting patches:\n'))
2864 else:
2864 else:
2865 ui.note(_(b'exporting patch:\n'))
2865 ui.note(_(b'exporting patch:\n'))
2866
2866
2867 fntemplate = opts.get(b'output')
2867 fntemplate = opts.get(b'output')
2868 if cmdutil.isstdiofilename(fntemplate):
2868 if cmdutil.isstdiofilename(fntemplate):
2869 fntemplate = b''
2869 fntemplate = b''
2870
2870
2871 if fntemplate:
2871 if fntemplate:
2872 fm = formatter.nullformatter(ui, b'export', opts)
2872 fm = formatter.nullformatter(ui, b'export', opts)
2873 else:
2873 else:
2874 ui.pager(b'export')
2874 ui.pager(b'export')
2875 fm = ui.formatter(b'export', opts)
2875 fm = ui.formatter(b'export', opts)
2876 with fm:
2876 with fm:
2877 cmdutil.export(
2877 cmdutil.export(
2878 repo,
2878 repo,
2879 revs,
2879 revs,
2880 fm,
2880 fm,
2881 fntemplate=fntemplate,
2881 fntemplate=fntemplate,
2882 switch_parent=opts.get(b'switch_parent'),
2882 switch_parent=opts.get(b'switch_parent'),
2883 opts=patch.diffallopts(ui, opts),
2883 opts=patch.diffallopts(ui, opts),
2884 )
2884 )
2885
2885
2886
2886
2887 @command(
2887 @command(
2888 b'files',
2888 b'files',
2889 [
2889 [
2890 (
2890 (
2891 b'r',
2891 b'r',
2892 b'rev',
2892 b'rev',
2893 b'',
2893 b'',
2894 _(b'search the repository as it is in REV'),
2894 _(b'search the repository as it is in REV'),
2895 _(b'REV'),
2895 _(b'REV'),
2896 ),
2896 ),
2897 (
2897 (
2898 b'0',
2898 b'0',
2899 b'print0',
2899 b'print0',
2900 None,
2900 None,
2901 _(b'end filenames with NUL, for use with xargs'),
2901 _(b'end filenames with NUL, for use with xargs'),
2902 ),
2902 ),
2903 ]
2903 ]
2904 + walkopts
2904 + walkopts
2905 + formatteropts
2905 + formatteropts
2906 + subrepoopts,
2906 + subrepoopts,
2907 _(b'[OPTION]... [FILE]...'),
2907 _(b'[OPTION]... [FILE]...'),
2908 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2908 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2909 intents={INTENT_READONLY},
2909 intents={INTENT_READONLY},
2910 )
2910 )
2911 def files(ui, repo, *pats, **opts):
2911 def files(ui, repo, *pats, **opts):
2912 """list tracked files
2912 """list tracked files
2913
2913
2914 Print files under Mercurial control in the working directory or
2914 Print files under Mercurial control in the working directory or
2915 specified revision for given files (excluding removed files).
2915 specified revision for given files (excluding removed files).
2916 Files can be specified as filenames or filesets.
2916 Files can be specified as filenames or filesets.
2917
2917
2918 If no files are given to match, this command prints the names
2918 If no files are given to match, this command prints the names
2919 of all files under Mercurial control.
2919 of all files under Mercurial control.
2920
2920
2921 .. container:: verbose
2921 .. container:: verbose
2922
2922
2923 Template:
2923 Template:
2924
2924
2925 The following keywords are supported in addition to the common template
2925 The following keywords are supported in addition to the common template
2926 keywords and functions. See also :hg:`help templates`.
2926 keywords and functions. See also :hg:`help templates`.
2927
2927
2928 :flags: String. Character denoting file's symlink and executable bits.
2928 :flags: String. Character denoting file's symlink and executable bits.
2929 :path: String. Repository-absolute path of the file.
2929 :path: String. Repository-absolute path of the file.
2930 :size: Integer. Size of the file in bytes.
2930 :size: Integer. Size of the file in bytes.
2931
2931
2932 Examples:
2932 Examples:
2933
2933
2934 - list all files under the current directory::
2934 - list all files under the current directory::
2935
2935
2936 hg files .
2936 hg files .
2937
2937
2938 - shows sizes and flags for current revision::
2938 - shows sizes and flags for current revision::
2939
2939
2940 hg files -vr .
2940 hg files -vr .
2941
2941
2942 - list all files named README::
2942 - list all files named README::
2943
2943
2944 hg files -I "**/README"
2944 hg files -I "**/README"
2945
2945
2946 - list all binary files::
2946 - list all binary files::
2947
2947
2948 hg files "set:binary()"
2948 hg files "set:binary()"
2949
2949
2950 - find files containing a regular expression::
2950 - find files containing a regular expression::
2951
2951
2952 hg files "set:grep('bob')"
2952 hg files "set:grep('bob')"
2953
2953
2954 - search tracked file contents with xargs and grep::
2954 - search tracked file contents with xargs and grep::
2955
2955
2956 hg files -0 | xargs -0 grep foo
2956 hg files -0 | xargs -0 grep foo
2957
2957
2958 See :hg:`help patterns` and :hg:`help filesets` for more information
2958 See :hg:`help patterns` and :hg:`help filesets` for more information
2959 on specifying file patterns.
2959 on specifying file patterns.
2960
2960
2961 Returns 0 if a match is found, 1 otherwise.
2961 Returns 0 if a match is found, 1 otherwise.
2962
2962
2963 """
2963 """
2964
2964
2965 opts = pycompat.byteskwargs(opts)
2965 opts = pycompat.byteskwargs(opts)
2966 rev = opts.get(b'rev')
2966 rev = opts.get(b'rev')
2967 if rev:
2967 if rev:
2968 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2968 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2969 ctx = logcmdutil.revsingle(repo, rev, None)
2969 ctx = logcmdutil.revsingle(repo, rev, None)
2970
2970
2971 end = b'\n'
2971 end = b'\n'
2972 if opts.get(b'print0'):
2972 if opts.get(b'print0'):
2973 end = b'\0'
2973 end = b'\0'
2974 fmt = b'%s' + end
2974 fmt = b'%s' + end
2975
2975
2976 m = scmutil.match(ctx, pats, opts)
2976 m = scmutil.match(ctx, pats, opts)
2977 ui.pager(b'files')
2977 ui.pager(b'files')
2978 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2978 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2979 with ui.formatter(b'files', opts) as fm:
2979 with ui.formatter(b'files', opts) as fm:
2980 return cmdutil.files(
2980 return cmdutil.files(
2981 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2981 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2982 )
2982 )
2983
2983
2984
2984
2985 @command(
2985 @command(
2986 b'forget',
2986 b'forget',
2987 [
2987 [
2988 (b'i', b'interactive', None, _(b'use interactive mode')),
2988 (b'i', b'interactive', None, _(b'use interactive mode')),
2989 ]
2989 ]
2990 + walkopts
2990 + walkopts
2991 + dryrunopts,
2991 + dryrunopts,
2992 _(b'[OPTION]... FILE...'),
2992 _(b'[OPTION]... FILE...'),
2993 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2993 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2994 helpbasic=True,
2994 helpbasic=True,
2995 inferrepo=True,
2995 inferrepo=True,
2996 )
2996 )
2997 def forget(ui, repo, *pats, **opts):
2997 def forget(ui, repo, *pats, **opts):
2998 """forget the specified files on the next commit
2998 """forget the specified files on the next commit
2999
2999
3000 Mark the specified files so they will no longer be tracked
3000 Mark the specified files so they will no longer be tracked
3001 after the next commit.
3001 after the next commit.
3002
3002
3003 This only removes files from the current branch, not from the
3003 This only removes files from the current branch, not from the
3004 entire project history, and it does not delete them from the
3004 entire project history, and it does not delete them from the
3005 working directory.
3005 working directory.
3006
3006
3007 To delete the file from the working directory, see :hg:`remove`.
3007 To delete the file from the working directory, see :hg:`remove`.
3008
3008
3009 To undo a forget before the next commit, see :hg:`add`.
3009 To undo a forget before the next commit, see :hg:`add`.
3010
3010
3011 .. container:: verbose
3011 .. container:: verbose
3012
3012
3013 Examples:
3013 Examples:
3014
3014
3015 - forget newly-added binary files::
3015 - forget newly-added binary files::
3016
3016
3017 hg forget "set:added() and binary()"
3017 hg forget "set:added() and binary()"
3018
3018
3019 - forget files that would be excluded by .hgignore::
3019 - forget files that would be excluded by .hgignore::
3020
3020
3021 hg forget "set:hgignore()"
3021 hg forget "set:hgignore()"
3022
3022
3023 Returns 0 on success.
3023 Returns 0 on success.
3024 """
3024 """
3025
3025
3026 if not pats:
3026 if not pats:
3027 raise error.InputError(_(b'no files specified'))
3027 raise error.InputError(_(b'no files specified'))
3028
3028
3029 with repo.wlock(), repo.dirstate.changing_files(repo):
3029 with repo.wlock(), repo.dirstate.changing_files(repo):
3030 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3030 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3031 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3031 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3032 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3032 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3033 rejected = cmdutil.forget(
3033 rejected = cmdutil.forget(
3034 ui,
3034 ui,
3035 repo,
3035 repo,
3036 m,
3036 m,
3037 prefix=b"",
3037 prefix=b"",
3038 uipathfn=uipathfn,
3038 uipathfn=uipathfn,
3039 explicitonly=False,
3039 explicitonly=False,
3040 dryrun=dryrun,
3040 dryrun=dryrun,
3041 interactive=interactive,
3041 interactive=interactive,
3042 )[0]
3042 )[0]
3043 return rejected and 1 or 0
3043 return rejected and 1 or 0
3044
3044
3045
3045
3046 @command(
3046 @command(
3047 b'graft',
3047 b'graft',
3048 [
3048 [
3049 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3049 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3050 (
3050 (
3051 b'',
3051 b'',
3052 b'base',
3052 b'base',
3053 b'',
3053 b'',
3054 _(b'base revision when doing the graft merge (ADVANCED)'),
3054 _(b'base revision when doing the graft merge (ADVANCED)'),
3055 _(b'REV'),
3055 _(b'REV'),
3056 ),
3056 ),
3057 (b'c', b'continue', False, _(b'resume interrupted graft')),
3057 (b'c', b'continue', False, _(b'resume interrupted graft')),
3058 (b'', b'stop', False, _(b'stop interrupted graft')),
3058 (b'', b'stop', False, _(b'stop interrupted graft')),
3059 (b'', b'abort', False, _(b'abort interrupted graft')),
3059 (b'', b'abort', False, _(b'abort interrupted graft')),
3060 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3060 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3061 (b'', b'log', None, _(b'append graft info to log message')),
3061 (b'', b'log', None, _(b'append graft info to log message')),
3062 (
3062 (
3063 b'',
3063 b'',
3064 b'no-commit',
3064 b'no-commit',
3065 None,
3065 None,
3066 _(b"don't commit, just apply the changes in working directory"),
3066 _(b"don't commit, just apply the changes in working directory"),
3067 ),
3067 ),
3068 (b'f', b'force', False, _(b'force graft')),
3068 (b'f', b'force', False, _(b'force graft')),
3069 (
3069 (
3070 b'D',
3070 b'D',
3071 b'currentdate',
3071 b'currentdate',
3072 False,
3072 False,
3073 _(b'record the current date as commit date'),
3073 _(b'record the current date as commit date'),
3074 ),
3074 ),
3075 (
3075 (
3076 b'U',
3076 b'U',
3077 b'currentuser',
3077 b'currentuser',
3078 False,
3078 False,
3079 _(b'record the current user as committer'),
3079 _(b'record the current user as committer'),
3080 ),
3080 ),
3081 ]
3081 ]
3082 + commitopts2
3082 + commitopts2
3083 + mergetoolopts
3083 + mergetoolopts
3084 + dryrunopts,
3084 + dryrunopts,
3085 _(b'[OPTION]... [-r REV]... REV...'),
3085 _(b'[OPTION]... [-r REV]... REV...'),
3086 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3086 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3087 )
3087 )
3088 def graft(ui, repo, *revs, **opts):
3088 def graft(ui, repo, *revs, **opts):
3089 """copy changes from other branches onto the current branch
3089 """copy changes from other branches onto the current branch
3090
3090
3091 This command uses Mercurial's merge logic to copy individual
3091 This command uses Mercurial's merge logic to copy individual
3092 changes from other branches without merging branches in the
3092 changes from other branches without merging branches in the
3093 history graph. This is sometimes known as 'backporting' or
3093 history graph. This is sometimes known as 'backporting' or
3094 'cherry-picking'. By default, graft will copy user, date, and
3094 'cherry-picking'. By default, graft will copy user, date, and
3095 description from the source changesets.
3095 description from the source changesets.
3096
3096
3097 Changesets that are ancestors of the current revision, that have
3097 Changesets that are ancestors of the current revision, that have
3098 already been grafted, or that are merges will be skipped.
3098 already been grafted, or that are merges will be skipped.
3099
3099
3100 If --log is specified, log messages will have a comment appended
3100 If --log is specified, log messages will have a comment appended
3101 of the form::
3101 of the form::
3102
3102
3103 (grafted from CHANGESETHASH)
3103 (grafted from CHANGESETHASH)
3104
3104
3105 If --force is specified, revisions will be grafted even if they
3105 If --force is specified, revisions will be grafted even if they
3106 are already ancestors of, or have been grafted to, the destination.
3106 are already ancestors of, or have been grafted to, the destination.
3107 This is useful when the revisions have since been backed out.
3107 This is useful when the revisions have since been backed out.
3108
3108
3109 If a graft merge results in conflicts, the graft process is
3109 If a graft merge results in conflicts, the graft process is
3110 interrupted so that the current merge can be manually resolved.
3110 interrupted so that the current merge can be manually resolved.
3111 Once all conflicts are addressed, the graft process can be
3111 Once all conflicts are addressed, the graft process can be
3112 continued with the -c/--continue option.
3112 continued with the -c/--continue option.
3113
3113
3114 The -c/--continue option reapplies all the earlier options.
3114 The -c/--continue option reapplies all the earlier options.
3115
3115
3116 .. container:: verbose
3116 .. container:: verbose
3117
3117
3118 The --base option exposes more of how graft internally uses merge with a
3118 The --base option exposes more of how graft internally uses merge with a
3119 custom base revision. --base can be used to specify another ancestor than
3119 custom base revision. --base can be used to specify another ancestor than
3120 the first and only parent.
3120 the first and only parent.
3121
3121
3122 The command::
3122 The command::
3123
3123
3124 hg graft -r 345 --base 234
3124 hg graft -r 345 --base 234
3125
3125
3126 is thus pretty much the same as::
3126 is thus pretty much the same as::
3127
3127
3128 hg diff --from 234 --to 345 | hg import
3128 hg diff --from 234 --to 345 | hg import
3129
3129
3130 but using merge to resolve conflicts and track moved files.
3130 but using merge to resolve conflicts and track moved files.
3131
3131
3132 The result of a merge can thus be backported as a single commit by
3132 The result of a merge can thus be backported as a single commit by
3133 specifying one of the merge parents as base, and thus effectively
3133 specifying one of the merge parents as base, and thus effectively
3134 grafting the changes from the other side.
3134 grafting the changes from the other side.
3135
3135
3136 It is also possible to collapse multiple changesets and clean up history
3136 It is also possible to collapse multiple changesets and clean up history
3137 by specifying another ancestor as base, much like rebase --collapse
3137 by specifying another ancestor as base, much like rebase --collapse
3138 --keep.
3138 --keep.
3139
3139
3140 The commit message can be tweaked after the fact using commit --amend .
3140 The commit message can be tweaked after the fact using commit --amend .
3141
3141
3142 For using non-ancestors as the base to backout changes, see the backout
3142 For using non-ancestors as the base to backout changes, see the backout
3143 command and the hidden --parent option.
3143 command and the hidden --parent option.
3144
3144
3145 .. container:: verbose
3145 .. container:: verbose
3146
3146
3147 Examples:
3147 Examples:
3148
3148
3149 - copy a single change to the stable branch and edit its description::
3149 - copy a single change to the stable branch and edit its description::
3150
3150
3151 hg update stable
3151 hg update stable
3152 hg graft --edit 9393
3152 hg graft --edit 9393
3153
3153
3154 - graft a range of changesets with one exception, updating dates::
3154 - graft a range of changesets with one exception, updating dates::
3155
3155
3156 hg graft -D "2085::2093 and not 2091"
3156 hg graft -D "2085::2093 and not 2091"
3157
3157
3158 - continue a graft after resolving conflicts::
3158 - continue a graft after resolving conflicts::
3159
3159
3160 hg graft -c
3160 hg graft -c
3161
3161
3162 - show the source of a grafted changeset::
3162 - show the source of a grafted changeset::
3163
3163
3164 hg log --debug -r .
3164 hg log --debug -r .
3165
3165
3166 - show revisions sorted by date::
3166 - show revisions sorted by date::
3167
3167
3168 hg log -r "sort(all(), date)"
3168 hg log -r "sort(all(), date)"
3169
3169
3170 - backport the result of a merge as a single commit::
3170 - backport the result of a merge as a single commit::
3171
3171
3172 hg graft -r 123 --base 123^
3172 hg graft -r 123 --base 123^
3173
3173
3174 - land a feature branch as one changeset::
3174 - land a feature branch as one changeset::
3175
3175
3176 hg up -cr default
3176 hg up -cr default
3177 hg graft -r featureX --base "ancestor('featureX', 'default')"
3177 hg graft -r featureX --base "ancestor('featureX', 'default')"
3178
3178
3179 See :hg:`help revisions` for more about specifying revisions.
3179 See :hg:`help revisions` for more about specifying revisions.
3180
3180
3181 Returns 0 on successful completion, 1 if there are unresolved files.
3181 Returns 0 on successful completion, 1 if there are unresolved files.
3182 """
3182 """
3183 with repo.wlock():
3183 with repo.wlock():
3184 return _dograft(ui, repo, *revs, **opts)
3184 return _dograft(ui, repo, *revs, **opts)
3185
3185
3186
3186
3187 def _dograft(ui, repo, *revs, **opts):
3187 def _dograft(ui, repo, *revs, **opts):
3188 if revs and opts.get('rev'):
3188 if revs and opts.get('rev'):
3189 ui.warn(
3189 ui.warn(
3190 _(
3190 _(
3191 b'warning: inconsistent use of --rev might give unexpected '
3191 b'warning: inconsistent use of --rev might give unexpected '
3192 b'revision ordering!\n'
3192 b'revision ordering!\n'
3193 )
3193 )
3194 )
3194 )
3195
3195
3196 revs = list(revs)
3196 revs = list(revs)
3197 revs.extend(opts.get('rev'))
3197 revs.extend(opts.get('rev'))
3198 # a dict of data to be stored in state file
3198 # a dict of data to be stored in state file
3199 statedata = {}
3199 statedata = {}
3200 # list of new nodes created by ongoing graft
3200 # list of new nodes created by ongoing graft
3201 statedata[b'newnodes'] = []
3201 statedata[b'newnodes'] = []
3202
3202
3203 cmdutil.resolve_commit_options(ui, opts)
3203 cmdutil.resolve_commit_options(ui, opts)
3204
3204
3205 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3205 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3206
3206
3207 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3207 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3208
3208
3209 cont = False
3209 cont = False
3210 if opts.get('no_commit'):
3210 if opts.get('no_commit'):
3211 cmdutil.check_incompatible_arguments(
3211 cmdutil.check_incompatible_arguments(
3212 opts,
3212 opts,
3213 'no_commit',
3213 'no_commit',
3214 ['edit', 'currentuser', 'currentdate', 'log'],
3214 ['edit', 'currentuser', 'currentdate', 'log'],
3215 )
3215 )
3216
3216
3217 graftstate = statemod.cmdstate(repo, b'graftstate')
3217 graftstate = statemod.cmdstate(repo, b'graftstate')
3218
3218
3219 if opts.get('stop'):
3219 if opts.get('stop'):
3220 cmdutil.check_incompatible_arguments(
3220 cmdutil.check_incompatible_arguments(
3221 opts,
3221 opts,
3222 'stop',
3222 'stop',
3223 [
3223 [
3224 'edit',
3224 'edit',
3225 'log',
3225 'log',
3226 'user',
3226 'user',
3227 'date',
3227 'date',
3228 'currentdate',
3228 'currentdate',
3229 'currentuser',
3229 'currentuser',
3230 'rev',
3230 'rev',
3231 ],
3231 ],
3232 )
3232 )
3233 return _stopgraft(ui, repo, graftstate)
3233 return _stopgraft(ui, repo, graftstate)
3234 elif opts.get('abort'):
3234 elif opts.get('abort'):
3235 cmdutil.check_incompatible_arguments(
3235 cmdutil.check_incompatible_arguments(
3236 opts,
3236 opts,
3237 'abort',
3237 'abort',
3238 [
3238 [
3239 'edit',
3239 'edit',
3240 'log',
3240 'log',
3241 'user',
3241 'user',
3242 'date',
3242 'date',
3243 'currentdate',
3243 'currentdate',
3244 'currentuser',
3244 'currentuser',
3245 'rev',
3245 'rev',
3246 ],
3246 ],
3247 )
3247 )
3248 return cmdutil.abortgraft(ui, repo, graftstate)
3248 return cmdutil.abortgraft(ui, repo, graftstate)
3249 elif opts.get('continue'):
3249 elif opts.get('continue'):
3250 cont = True
3250 cont = True
3251 if revs:
3251 if revs:
3252 raise error.InputError(_(b"can't specify --continue and revisions"))
3252 raise error.InputError(_(b"can't specify --continue and revisions"))
3253 # read in unfinished revisions
3253 # read in unfinished revisions
3254 if graftstate.exists():
3254 if graftstate.exists():
3255 statedata = cmdutil.readgraftstate(repo, graftstate)
3255 statedata = cmdutil.readgraftstate(repo, graftstate)
3256 if statedata.get(b'date'):
3256 if statedata.get(b'date'):
3257 opts['date'] = statedata[b'date']
3257 opts['date'] = statedata[b'date']
3258 if statedata.get(b'user'):
3258 if statedata.get(b'user'):
3259 opts['user'] = statedata[b'user']
3259 opts['user'] = statedata[b'user']
3260 if statedata.get(b'log'):
3260 if statedata.get(b'log'):
3261 opts['log'] = True
3261 opts['log'] = True
3262 if statedata.get(b'no_commit'):
3262 if statedata.get(b'no_commit'):
3263 opts['no_commit'] = statedata.get(b'no_commit')
3263 opts['no_commit'] = statedata.get(b'no_commit')
3264 if statedata.get(b'base'):
3264 if statedata.get(b'base'):
3265 opts['base'] = statedata.get(b'base')
3265 opts['base'] = statedata.get(b'base')
3266 nodes = statedata[b'nodes']
3266 nodes = statedata[b'nodes']
3267 revs = [repo[node].rev() for node in nodes]
3267 revs = [repo[node].rev() for node in nodes]
3268 else:
3268 else:
3269 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3269 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3270 else:
3270 else:
3271 if not revs:
3271 if not revs:
3272 raise error.InputError(_(b'no revisions specified'))
3272 raise error.InputError(_(b'no revisions specified'))
3273 cmdutil.checkunfinished(repo)
3273 cmdutil.checkunfinished(repo)
3274 cmdutil.bailifchanged(repo)
3274 cmdutil.bailifchanged(repo)
3275 revs = logcmdutil.revrange(repo, revs)
3275 revs = logcmdutil.revrange(repo, revs)
3276
3276
3277 skipped = set()
3277 skipped = set()
3278 basectx = None
3278 basectx = None
3279 if opts.get('base'):
3279 if opts.get('base'):
3280 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3280 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3281 if basectx is None:
3281 if basectx is None:
3282 # check for merges
3282 # check for merges
3283 for rev in repo.revs(b'%ld and merge()', revs):
3283 for rev in repo.revs(b'%ld and merge()', revs):
3284 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3284 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3285 skipped.add(rev)
3285 skipped.add(rev)
3286 revs = [r for r in revs if r not in skipped]
3286 revs = [r for r in revs if r not in skipped]
3287 if not revs:
3287 if not revs:
3288 return -1
3288 return -1
3289 if basectx is not None and len(revs) != 1:
3289 if basectx is not None and len(revs) != 1:
3290 raise error.InputError(_(b'only one revision allowed with --base '))
3290 raise error.InputError(_(b'only one revision allowed with --base '))
3291
3291
3292 # Don't check in the --continue case, in effect retaining --force across
3292 # Don't check in the --continue case, in effect retaining --force across
3293 # --continues. That's because without --force, any revisions we decided to
3293 # --continues. That's because without --force, any revisions we decided to
3294 # skip would have been filtered out here, so they wouldn't have made their
3294 # skip would have been filtered out here, so they wouldn't have made their
3295 # way to the graftstate. With --force, any revisions we would have otherwise
3295 # way to the graftstate. With --force, any revisions we would have otherwise
3296 # skipped would not have been filtered out, and if they hadn't been applied
3296 # skipped would not have been filtered out, and if they hadn't been applied
3297 # already, they'd have been in the graftstate.
3297 # already, they'd have been in the graftstate.
3298 if not (cont or opts.get('force')) and basectx is None:
3298 if not (cont or opts.get('force')) and basectx is None:
3299 # check for ancestors of dest branch
3299 # check for ancestors of dest branch
3300 ancestors = repo.revs(b'%ld & (::.)', revs)
3300 ancestors = repo.revs(b'%ld & (::.)', revs)
3301 for rev in ancestors:
3301 for rev in ancestors:
3302 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3302 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3303
3303
3304 revs = [r for r in revs if r not in ancestors]
3304 revs = [r for r in revs if r not in ancestors]
3305
3305
3306 if not revs:
3306 if not revs:
3307 return -1
3307 return -1
3308
3308
3309 # analyze revs for earlier grafts
3309 # analyze revs for earlier grafts
3310 ids = {}
3310 ids = {}
3311 for ctx in repo.set(b"%ld", revs):
3311 for ctx in repo.set(b"%ld", revs):
3312 ids[ctx.hex()] = ctx.rev()
3312 ids[ctx.hex()] = ctx.rev()
3313 n = ctx.extra().get(b'source')
3313 n = ctx.extra().get(b'source')
3314 if n:
3314 if n:
3315 ids[n] = ctx.rev()
3315 ids[n] = ctx.rev()
3316
3316
3317 # check ancestors for earlier grafts
3317 # check ancestors for earlier grafts
3318 ui.debug(b'scanning for duplicate grafts\n')
3318 ui.debug(b'scanning for duplicate grafts\n')
3319
3319
3320 # The only changesets we can be sure doesn't contain grafts of any
3320 # The only changesets we can be sure doesn't contain grafts of any
3321 # revs, are the ones that are common ancestors of *all* revs:
3321 # revs, are the ones that are common ancestors of *all* revs:
3322 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3322 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3323 ctx = repo[rev]
3323 ctx = repo[rev]
3324 n = ctx.extra().get(b'source')
3324 n = ctx.extra().get(b'source')
3325 if n in ids:
3325 if n in ids:
3326 try:
3326 try:
3327 r = repo[n].rev()
3327 r = repo[n].rev()
3328 except error.RepoLookupError:
3328 except error.RepoLookupError:
3329 r = None
3329 r = None
3330 if r in revs:
3330 if r in revs:
3331 ui.warn(
3331 ui.warn(
3332 _(
3332 _(
3333 b'skipping revision %d:%s '
3333 b'skipping revision %d:%s '
3334 b'(already grafted to %d:%s)\n'
3334 b'(already grafted to %d:%s)\n'
3335 )
3335 )
3336 % (r, repo[r], rev, ctx)
3336 % (r, repo[r], rev, ctx)
3337 )
3337 )
3338 revs.remove(r)
3338 revs.remove(r)
3339 elif ids[n] in revs:
3339 elif ids[n] in revs:
3340 if r is None:
3340 if r is None:
3341 ui.warn(
3341 ui.warn(
3342 _(
3342 _(
3343 b'skipping already grafted revision %d:%s '
3343 b'skipping already grafted revision %d:%s '
3344 b'(%d:%s also has unknown origin %s)\n'
3344 b'(%d:%s also has unknown origin %s)\n'
3345 )
3345 )
3346 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3346 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3347 )
3347 )
3348 else:
3348 else:
3349 ui.warn(
3349 ui.warn(
3350 _(
3350 _(
3351 b'skipping already grafted revision %d:%s '
3351 b'skipping already grafted revision %d:%s '
3352 b'(%d:%s also has origin %d:%s)\n'
3352 b'(%d:%s also has origin %d:%s)\n'
3353 )
3353 )
3354 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3354 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3355 )
3355 )
3356 revs.remove(ids[n])
3356 revs.remove(ids[n])
3357 elif ctx.hex() in ids:
3357 elif ctx.hex() in ids:
3358 r = ids[ctx.hex()]
3358 r = ids[ctx.hex()]
3359 if r in revs:
3359 if r in revs:
3360 ui.warn(
3360 ui.warn(
3361 _(
3361 _(
3362 b'skipping already grafted revision %d:%s '
3362 b'skipping already grafted revision %d:%s '
3363 b'(was grafted from %d:%s)\n'
3363 b'(was grafted from %d:%s)\n'
3364 )
3364 )
3365 % (r, repo[r], rev, ctx)
3365 % (r, repo[r], rev, ctx)
3366 )
3366 )
3367 revs.remove(r)
3367 revs.remove(r)
3368 if not revs:
3368 if not revs:
3369 return -1
3369 return -1
3370
3370
3371 if opts.get('no_commit'):
3371 if opts.get('no_commit'):
3372 statedata[b'no_commit'] = True
3372 statedata[b'no_commit'] = True
3373 if opts.get('base'):
3373 if opts.get('base'):
3374 statedata[b'base'] = opts['base']
3374 statedata[b'base'] = opts['base']
3375 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3375 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3376 desc = b'%d:%s "%s"' % (
3376 desc = b'%d:%s "%s"' % (
3377 ctx.rev(),
3377 ctx.rev(),
3378 ctx,
3378 ctx,
3379 ctx.description().split(b'\n', 1)[0],
3379 ctx.description().split(b'\n', 1)[0],
3380 )
3380 )
3381 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3381 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3382 if names:
3382 if names:
3383 desc += b' (%s)' % b' '.join(names)
3383 desc += b' (%s)' % b' '.join(names)
3384 ui.status(_(b'grafting %s\n') % desc)
3384 ui.status(_(b'grafting %s\n') % desc)
3385 if opts.get('dry_run'):
3385 if opts.get('dry_run'):
3386 continue
3386 continue
3387
3387
3388 source = ctx.extra().get(b'source')
3388 source = ctx.extra().get(b'source')
3389 extra = {}
3389 extra = {}
3390 if source:
3390 if source:
3391 extra[b'source'] = source
3391 extra[b'source'] = source
3392 extra[b'intermediate-source'] = ctx.hex()
3392 extra[b'intermediate-source'] = ctx.hex()
3393 else:
3393 else:
3394 extra[b'source'] = ctx.hex()
3394 extra[b'source'] = ctx.hex()
3395 user = ctx.user()
3395 user = ctx.user()
3396 if opts.get('user'):
3396 if opts.get('user'):
3397 user = opts['user']
3397 user = opts['user']
3398 statedata[b'user'] = user
3398 statedata[b'user'] = user
3399 date = ctx.date()
3399 date = ctx.date()
3400 if opts.get('date'):
3400 if opts.get('date'):
3401 date = opts['date']
3401 date = opts['date']
3402 statedata[b'date'] = date
3402 statedata[b'date'] = date
3403 message = ctx.description()
3403 message = ctx.description()
3404 if opts.get('log'):
3404 if opts.get('log'):
3405 message += b'\n(grafted from %s)' % ctx.hex()
3405 message += b'\n(grafted from %s)' % ctx.hex()
3406 statedata[b'log'] = True
3406 statedata[b'log'] = True
3407
3407
3408 # we don't merge the first commit when continuing
3408 # we don't merge the first commit when continuing
3409 if not cont:
3409 if not cont:
3410 # perform the graft merge with p1(rev) as 'ancestor'
3410 # perform the graft merge with p1(rev) as 'ancestor'
3411 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3411 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3412 base = ctx.p1() if basectx is None else basectx
3412 base = ctx.p1() if basectx is None else basectx
3413 with ui.configoverride(overrides, b'graft'):
3413 with ui.configoverride(overrides, b'graft'):
3414 stats = mergemod.graft(
3414 stats = mergemod.graft(
3415 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3415 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3416 )
3416 )
3417 # report any conflicts
3417 # report any conflicts
3418 if stats.unresolvedcount > 0:
3418 if stats.unresolvedcount > 0:
3419 # write out state for --continue
3419 # write out state for --continue
3420 nodes = [repo[rev].hex() for rev in revs[pos:]]
3420 nodes = [repo[rev].hex() for rev in revs[pos:]]
3421 statedata[b'nodes'] = nodes
3421 statedata[b'nodes'] = nodes
3422 stateversion = 1
3422 stateversion = 1
3423 graftstate.save(stateversion, statedata)
3423 graftstate.save(stateversion, statedata)
3424 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3424 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3425 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3425 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3426 return 1
3426 return 1
3427 else:
3427 else:
3428 cont = False
3428 cont = False
3429
3429
3430 # commit if --no-commit is false
3430 # commit if --no-commit is false
3431 if not opts.get('no_commit'):
3431 if not opts.get('no_commit'):
3432 node = repo.commit(
3432 node = repo.commit(
3433 text=message, user=user, date=date, extra=extra, editor=editor
3433 text=message, user=user, date=date, extra=extra, editor=editor
3434 )
3434 )
3435 if node is None:
3435 if node is None:
3436 ui.warn(
3436 ui.warn(
3437 _(b'note: graft of %d:%s created no changes to commit\n')
3437 _(b'note: graft of %d:%s created no changes to commit\n')
3438 % (ctx.rev(), ctx)
3438 % (ctx.rev(), ctx)
3439 )
3439 )
3440 # checking that newnodes exist because old state files won't have it
3440 # checking that newnodes exist because old state files won't have it
3441 elif statedata.get(b'newnodes') is not None:
3441 elif statedata.get(b'newnodes') is not None:
3442 nn = statedata[b'newnodes']
3442 nn = statedata[b'newnodes']
3443 assert isinstance(nn, list) # list of bytes
3443 assert isinstance(nn, list) # list of bytes
3444 nn.append(node)
3444 nn.append(node)
3445
3445
3446 # remove state when we complete successfully
3446 # remove state when we complete successfully
3447 if not opts.get('dry_run'):
3447 if not opts.get('dry_run'):
3448 graftstate.delete()
3448 graftstate.delete()
3449
3449
3450 return 0
3450 return 0
3451
3451
3452
3452
3453 def _stopgraft(ui, repo, graftstate):
3453 def _stopgraft(ui, repo, graftstate):
3454 """stop the interrupted graft"""
3454 """stop the interrupted graft"""
3455 if not graftstate.exists():
3455 if not graftstate.exists():
3456 raise error.StateError(_(b"no interrupted graft found"))
3456 raise error.StateError(_(b"no interrupted graft found"))
3457 pctx = repo[b'.']
3457 pctx = repo[b'.']
3458 mergemod.clean_update(pctx)
3458 mergemod.clean_update(pctx)
3459 graftstate.delete()
3459 graftstate.delete()
3460 ui.status(_(b"stopped the interrupted graft\n"))
3460 ui.status(_(b"stopped the interrupted graft\n"))
3461 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3461 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3462 return 0
3462 return 0
3463
3463
3464
3464
3465 statemod.addunfinished(
3465 statemod.addunfinished(
3466 b'graft',
3466 b'graft',
3467 fname=b'graftstate',
3467 fname=b'graftstate',
3468 clearable=True,
3468 clearable=True,
3469 stopflag=True,
3469 stopflag=True,
3470 continueflag=True,
3470 continueflag=True,
3471 abortfunc=cmdutil.hgabortgraft,
3471 abortfunc=cmdutil.hgabortgraft,
3472 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3472 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3473 )
3473 )
3474
3474
3475
3475
3476 @command(
3476 @command(
3477 b'grep',
3477 b'grep',
3478 [
3478 [
3479 (b'0', b'print0', None, _(b'end fields with NUL')),
3479 (b'0', b'print0', None, _(b'end fields with NUL')),
3480 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3480 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3481 (
3481 (
3482 b'',
3482 b'',
3483 b'diff',
3483 b'diff',
3484 None,
3484 None,
3485 _(
3485 _(
3486 b'search revision differences for when the pattern was added '
3486 b'search revision differences for when the pattern was added '
3487 b'or removed'
3487 b'or removed'
3488 ),
3488 ),
3489 ),
3489 ),
3490 (b'a', b'text', None, _(b'treat all files as text')),
3490 (b'a', b'text', None, _(b'treat all files as text')),
3491 (
3491 (
3492 b'f',
3492 b'f',
3493 b'follow',
3493 b'follow',
3494 None,
3494 None,
3495 _(
3495 _(
3496 b'follow changeset history,'
3496 b'follow changeset history,'
3497 b' or file history across copies and renames'
3497 b' or file history across copies and renames'
3498 ),
3498 ),
3499 ),
3499 ),
3500 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3500 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3501 (
3501 (
3502 b'l',
3502 b'l',
3503 b'files-with-matches',
3503 b'files-with-matches',
3504 None,
3504 None,
3505 _(b'print only filenames and revisions that match'),
3505 _(b'print only filenames and revisions that match'),
3506 ),
3506 ),
3507 (b'n', b'line-number', None, _(b'print matching line numbers')),
3507 (b'n', b'line-number', None, _(b'print matching line numbers')),
3508 (
3508 (
3509 b'r',
3509 b'r',
3510 b'rev',
3510 b'rev',
3511 [],
3511 [],
3512 _(b'search files changed within revision range'),
3512 _(b'search files changed within revision range'),
3513 _(b'REV'),
3513 _(b'REV'),
3514 ),
3514 ),
3515 (
3515 (
3516 b'',
3516 b'',
3517 b'all-files',
3517 b'all-files',
3518 None,
3518 None,
3519 _(
3519 _(
3520 b'include all files in the changeset while grepping (DEPRECATED)'
3520 b'include all files in the changeset while grepping (DEPRECATED)'
3521 ),
3521 ),
3522 ),
3522 ),
3523 (b'u', b'user', None, _(b'list the author (long with -v)')),
3523 (b'u', b'user', None, _(b'list the author (long with -v)')),
3524 (b'd', b'date', None, _(b'list the date (short with -q)')),
3524 (b'd', b'date', None, _(b'list the date (short with -q)')),
3525 ]
3525 ]
3526 + formatteropts
3526 + formatteropts
3527 + walkopts,
3527 + walkopts,
3528 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3528 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3529 helpcategory=command.CATEGORY_FILE_CONTENTS,
3529 helpcategory=command.CATEGORY_FILE_CONTENTS,
3530 inferrepo=True,
3530 inferrepo=True,
3531 intents={INTENT_READONLY},
3531 intents={INTENT_READONLY},
3532 )
3532 )
3533 def grep(ui, repo, pattern, *pats, **opts):
3533 def grep(ui, repo, pattern, *pats, **opts):
3534 """search for a pattern in specified files
3534 """search for a pattern in specified files
3535
3535
3536 Search the working directory or revision history for a regular
3536 Search the working directory or revision history for a regular
3537 expression in the specified files for the entire repository.
3537 expression in the specified files for the entire repository.
3538
3538
3539 By default, grep searches the repository files in the working
3539 By default, grep searches the repository files in the working
3540 directory and prints the files where it finds a match. To specify
3540 directory and prints the files where it finds a match. To specify
3541 historical revisions instead of the working directory, use the
3541 historical revisions instead of the working directory, use the
3542 --rev flag.
3542 --rev flag.
3543
3543
3544 To search instead historical revision differences that contains a
3544 To search instead historical revision differences that contains a
3545 change in match status ("-" for a match that becomes a non-match,
3545 change in match status ("-" for a match that becomes a non-match,
3546 or "+" for a non-match that becomes a match), use the --diff flag.
3546 or "+" for a non-match that becomes a match), use the --diff flag.
3547
3547
3548 PATTERN can be any Python (roughly Perl-compatible) regular
3548 PATTERN can be any Python (roughly Perl-compatible) regular
3549 expression.
3549 expression.
3550
3550
3551 If no FILEs are specified and the --rev flag isn't supplied, all
3551 If no FILEs are specified and the --rev flag isn't supplied, all
3552 files in the working directory are searched. When using the --rev
3552 files in the working directory are searched. When using the --rev
3553 flag and specifying FILEs, use the --follow argument to also
3553 flag and specifying FILEs, use the --follow argument to also
3554 follow the specified FILEs across renames and copies.
3554 follow the specified FILEs across renames and copies.
3555
3555
3556 .. container:: verbose
3556 .. container:: verbose
3557
3557
3558 Template:
3558 Template:
3559
3559
3560 The following keywords are supported in addition to the common template
3560 The following keywords are supported in addition to the common template
3561 keywords and functions. See also :hg:`help templates`.
3561 keywords and functions. See also :hg:`help templates`.
3562
3562
3563 :change: String. Character denoting insertion ``+`` or removal ``-``.
3563 :change: String. Character denoting insertion ``+`` or removal ``-``.
3564 Available if ``--diff`` is specified.
3564 Available if ``--diff`` is specified.
3565 :lineno: Integer. Line number of the match.
3565 :lineno: Integer. Line number of the match.
3566 :path: String. Repository-absolute path of the file.
3566 :path: String. Repository-absolute path of the file.
3567 :texts: List of text chunks.
3567 :texts: List of text chunks.
3568
3568
3569 And each entry of ``{texts}`` provides the following sub-keywords.
3569 And each entry of ``{texts}`` provides the following sub-keywords.
3570
3570
3571 :matched: Boolean. True if the chunk matches the specified pattern.
3571 :matched: Boolean. True if the chunk matches the specified pattern.
3572 :text: String. Chunk content.
3572 :text: String. Chunk content.
3573
3573
3574 See :hg:`help templates.operators` for the list expansion syntax.
3574 See :hg:`help templates.operators` for the list expansion syntax.
3575
3575
3576 Returns 0 if a match is found, 1 otherwise.
3576 Returns 0 if a match is found, 1 otherwise.
3577
3577
3578 """
3578 """
3579 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3579 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3580
3580
3581 diff = opts.get('all') or opts.get('diff')
3581 diff = opts.get('all') or opts.get('diff')
3582 follow = opts.get('follow')
3582 follow = opts.get('follow')
3583 if opts.get('all_files') is None and not diff:
3583 if opts.get('all_files') is None and not diff:
3584 opts['all_files'] = True
3584 opts['all_files'] = True
3585 plaingrep = (
3585 plaingrep = (
3586 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3586 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3587 )
3587 )
3588 all_files = opts.get('all_files')
3588 all_files = opts.get('all_files')
3589 if plaingrep:
3589 if plaingrep:
3590 opts['rev'] = [b'wdir()']
3590 opts['rev'] = [b'wdir()']
3591
3591
3592 reflags = re.M
3592 reflags = re.M
3593 if opts.get('ignore_case'):
3593 if opts.get('ignore_case'):
3594 reflags |= re.I
3594 reflags |= re.I
3595 try:
3595 try:
3596 regexp = util.re.compile(pattern, reflags)
3596 regexp = util.re.compile(pattern, reflags)
3597 except re.error as inst:
3597 except re.error as inst:
3598 ui.warn(
3598 ui.warn(
3599 _(b"grep: invalid match pattern: %s\n")
3599 _(b"grep: invalid match pattern: %s\n")
3600 % stringutil.forcebytestr(inst)
3600 % stringutil.forcebytestr(inst)
3601 )
3601 )
3602 return 1
3602 return 1
3603 sep, eol = b':', b'\n'
3603 sep, eol = b':', b'\n'
3604 if opts.get('print0'):
3604 if opts.get('print0'):
3605 sep = eol = b'\0'
3605 sep = eol = b'\0'
3606
3606
3607 searcher = grepmod.grepsearcher(
3607 searcher = grepmod.grepsearcher(
3608 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3608 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3609 )
3609 )
3610
3610
3611 getfile = searcher._getfile
3611 getfile = searcher._getfile
3612
3612
3613 uipathfn = scmutil.getuipathfn(repo)
3613 uipathfn = scmutil.getuipathfn(repo)
3614
3614
3615 def display(fm, fn, ctx, pstates, states):
3615 def display(fm, fn, ctx, pstates, states):
3616 rev = scmutil.intrev(ctx)
3616 rev = scmutil.intrev(ctx)
3617 if fm.isplain():
3617 if fm.isplain():
3618 formatuser = ui.shortuser
3618 formatuser = ui.shortuser
3619 else:
3619 else:
3620 formatuser = pycompat.bytestr
3620 formatuser = pycompat.bytestr
3621 if ui.quiet:
3621 if ui.quiet:
3622 datefmt = b'%Y-%m-%d'
3622 datefmt = b'%Y-%m-%d'
3623 else:
3623 else:
3624 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3624 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3625 found = False
3625 found = False
3626
3626
3627 @util.cachefunc
3627 @util.cachefunc
3628 def binary():
3628 def binary():
3629 flog = getfile(fn)
3629 flog = getfile(fn)
3630 try:
3630 try:
3631 return stringutil.binary(flog.read(ctx.filenode(fn)))
3631 return stringutil.binary(flog.read(ctx.filenode(fn)))
3632 except error.WdirUnsupported:
3632 except error.WdirUnsupported:
3633 return ctx[fn].isbinary()
3633 return ctx[fn].isbinary()
3634
3634
3635 fieldnamemap = {b'linenumber': b'lineno'}
3635 fieldnamemap = {b'linenumber': b'lineno'}
3636 if diff:
3636 if diff:
3637 iter = grepmod.difflinestates(pstates, states)
3637 iter = grepmod.difflinestates(pstates, states)
3638 else:
3638 else:
3639 iter = [(b'', l) for l in states]
3639 iter = [(b'', l) for l in states]
3640 for change, l in iter:
3640 for change, l in iter:
3641 fm.startitem()
3641 fm.startitem()
3642 fm.context(ctx=ctx)
3642 fm.context(ctx=ctx)
3643 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3643 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3644 fm.plain(uipathfn(fn), label=b'grep.filename')
3644 fm.plain(uipathfn(fn), label=b'grep.filename')
3645
3645
3646 cols = [
3646 cols = [
3647 (b'rev', b'%d', rev, not plaingrep, b''),
3647 (b'rev', b'%d', rev, not plaingrep, b''),
3648 (
3648 (
3649 b'linenumber',
3649 b'linenumber',
3650 b'%d',
3650 b'%d',
3651 l.linenum,
3651 l.linenum,
3652 opts.get('line_number'),
3652 opts.get('line_number'),
3653 b'',
3653 b'',
3654 ),
3654 ),
3655 ]
3655 ]
3656 if diff:
3656 if diff:
3657 cols.append(
3657 cols.append(
3658 (
3658 (
3659 b'change',
3659 b'change',
3660 b'%s',
3660 b'%s',
3661 change,
3661 change,
3662 True,
3662 True,
3663 b'grep.inserted '
3663 b'grep.inserted '
3664 if change == b'+'
3664 if change == b'+'
3665 else b'grep.deleted ',
3665 else b'grep.deleted ',
3666 )
3666 )
3667 )
3667 )
3668 cols.extend(
3668 cols.extend(
3669 [
3669 [
3670 (
3670 (
3671 b'user',
3671 b'user',
3672 b'%s',
3672 b'%s',
3673 formatuser(ctx.user()),
3673 formatuser(ctx.user()),
3674 opts.get('user'),
3674 opts.get('user'),
3675 b'',
3675 b'',
3676 ),
3676 ),
3677 (
3677 (
3678 b'date',
3678 b'date',
3679 b'%s',
3679 b'%s',
3680 fm.formatdate(ctx.date(), datefmt),
3680 fm.formatdate(ctx.date(), datefmt),
3681 opts.get('date'),
3681 opts.get('date'),
3682 b'',
3682 b'',
3683 ),
3683 ),
3684 ]
3684 ]
3685 )
3685 )
3686 for name, fmt, data, cond, extra_label in cols:
3686 for name, fmt, data, cond, extra_label in cols:
3687 if cond:
3687 if cond:
3688 fm.plain(sep, label=b'grep.sep')
3688 fm.plain(sep, label=b'grep.sep')
3689 field = fieldnamemap.get(name, name)
3689 field = fieldnamemap.get(name, name)
3690 label = extra_label + (b'grep.%s' % name)
3690 label = extra_label + (b'grep.%s' % name)
3691 fm.condwrite(cond, field, fmt, data, label=label)
3691 fm.condwrite(cond, field, fmt, data, label=label)
3692 if not opts.get('files_with_matches'):
3692 if not opts.get('files_with_matches'):
3693 fm.plain(sep, label=b'grep.sep')
3693 fm.plain(sep, label=b'grep.sep')
3694 if not opts.get('text') and binary():
3694 if not opts.get('text') and binary():
3695 fm.plain(_(b" Binary file matches"))
3695 fm.plain(_(b" Binary file matches"))
3696 else:
3696 else:
3697 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3697 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3698 fm.plain(eol)
3698 fm.plain(eol)
3699 found = True
3699 found = True
3700 if opts.get('files_with_matches'):
3700 if opts.get('files_with_matches'):
3701 break
3701 break
3702 return found
3702 return found
3703
3703
3704 def displaymatches(fm, l):
3704 def displaymatches(fm, l):
3705 p = 0
3705 p = 0
3706 for s, e in l.findpos(regexp):
3706 for s, e in l.findpos(regexp):
3707 if p < s:
3707 if p < s:
3708 fm.startitem()
3708 fm.startitem()
3709 fm.write(b'text', b'%s', l.line[p:s])
3709 fm.write(b'text', b'%s', l.line[p:s])
3710 fm.data(matched=False)
3710 fm.data(matched=False)
3711 fm.startitem()
3711 fm.startitem()
3712 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3712 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3713 fm.data(matched=True)
3713 fm.data(matched=True)
3714 p = e
3714 p = e
3715 if p < len(l.line):
3715 if p < len(l.line):
3716 fm.startitem()
3716 fm.startitem()
3717 fm.write(b'text', b'%s', l.line[p:])
3717 fm.write(b'text', b'%s', l.line[p:])
3718 fm.data(matched=False)
3718 fm.data(matched=False)
3719 fm.end()
3719 fm.end()
3720
3720
3721 found = False
3721 found = False
3722
3722
3723 wopts = logcmdutil.walkopts(
3723 wopts = logcmdutil.walkopts(
3724 pats=pats,
3724 pats=pats,
3725 opts=pycompat.byteskwargs(opts),
3725 opts=pycompat.byteskwargs(opts),
3726 revspec=opts['rev'],
3726 revspec=opts['rev'],
3727 include_pats=opts['include'],
3727 include_pats=opts['include'],
3728 exclude_pats=opts['exclude'],
3728 exclude_pats=opts['exclude'],
3729 follow=follow,
3729 follow=follow,
3730 force_changelog_traversal=all_files,
3730 force_changelog_traversal=all_files,
3731 filter_revisions_by_pats=not all_files,
3731 filter_revisions_by_pats=not all_files,
3732 )
3732 )
3733 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3733 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3734
3734
3735 ui.pager(b'grep')
3735 ui.pager(b'grep')
3736 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3736 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3737 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3737 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3738 r = display(fm, fn, ctx, pstates, states)
3738 r = display(fm, fn, ctx, pstates, states)
3739 found = found or r
3739 found = found or r
3740 if r and not diff and not all_files:
3740 if r and not diff and not all_files:
3741 searcher.skipfile(fn, ctx.rev())
3741 searcher.skipfile(fn, ctx.rev())
3742 fm.end()
3742 fm.end()
3743
3743
3744 return not found
3744 return not found
3745
3745
3746
3746
3747 @command(
3747 @command(
3748 b'heads',
3748 b'heads',
3749 [
3749 [
3750 (
3750 (
3751 b'r',
3751 b'r',
3752 b'rev',
3752 b'rev',
3753 b'',
3753 b'',
3754 _(b'show only heads which are descendants of STARTREV'),
3754 _(b'show only heads which are descendants of STARTREV'),
3755 _(b'STARTREV'),
3755 _(b'STARTREV'),
3756 ),
3756 ),
3757 (b't', b'topo', False, _(b'show topological heads only')),
3757 (b't', b'topo', False, _(b'show topological heads only')),
3758 (
3758 (
3759 b'a',
3759 b'a',
3760 b'active',
3760 b'active',
3761 False,
3761 False,
3762 _(b'show active branchheads only (DEPRECATED)'),
3762 _(b'show active branchheads only (DEPRECATED)'),
3763 ),
3763 ),
3764 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3764 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3765 ]
3765 ]
3766 + templateopts,
3766 + templateopts,
3767 _(b'[-ct] [-r STARTREV] [REV]...'),
3767 _(b'[-ct] [-r STARTREV] [REV]...'),
3768 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3768 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3769 intents={INTENT_READONLY},
3769 intents={INTENT_READONLY},
3770 )
3770 )
3771 def heads(ui, repo, *branchrevs, **opts):
3771 def heads(ui, repo, *branchrevs, **opts):
3772 """show branch heads
3772 """show branch heads
3773
3773
3774 With no arguments, show all open branch heads in the repository.
3774 With no arguments, show all open branch heads in the repository.
3775 Branch heads are changesets that have no descendants on the
3775 Branch heads are changesets that have no descendants on the
3776 same branch. They are where development generally takes place and
3776 same branch. They are where development generally takes place and
3777 are the usual targets for update and merge operations.
3777 are the usual targets for update and merge operations.
3778
3778
3779 If one or more REVs are given, only open branch heads on the
3779 If one or more REVs are given, only open branch heads on the
3780 branches associated with the specified changesets are shown. This
3780 branches associated with the specified changesets are shown. This
3781 means that you can use :hg:`heads .` to see the heads on the
3781 means that you can use :hg:`heads .` to see the heads on the
3782 currently checked-out branch.
3782 currently checked-out branch.
3783
3783
3784 If -c/--closed is specified, also show branch heads marked closed
3784 If -c/--closed is specified, also show branch heads marked closed
3785 (see :hg:`commit --close-branch`).
3785 (see :hg:`commit --close-branch`).
3786
3786
3787 If STARTREV is specified, only those heads that are descendants of
3787 If STARTREV is specified, only those heads that are descendants of
3788 STARTREV will be displayed.
3788 STARTREV will be displayed.
3789
3789
3790 If -t/--topo is specified, named branch mechanics will be ignored and only
3790 If -t/--topo is specified, named branch mechanics will be ignored and only
3791 topological heads (changesets with no children) will be shown.
3791 topological heads (changesets with no children) will be shown.
3792
3792
3793 Returns 0 if matching heads are found, 1 if not.
3793 Returns 0 if matching heads are found, 1 if not.
3794 """
3794 """
3795
3795
3796 start = None
3796 start = None
3797 rev = opts.get('rev')
3797 rev = opts.get('rev')
3798 if rev:
3798 if rev:
3799 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3799 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3800 start = logcmdutil.revsingle(repo, rev, None).node()
3800 start = logcmdutil.revsingle(repo, rev, None).node()
3801
3801
3802 if opts.get('topo'):
3802 if opts.get('topo'):
3803 heads = [repo[h] for h in repo.heads(start)]
3803 heads = [repo[h] for h in repo.heads(start)]
3804 else:
3804 else:
3805 heads = []
3805 heads = []
3806 for branch in repo.branchmap():
3806 for branch in repo.branchmap():
3807 heads += repo.branchheads(branch, start, opts.get('closed'))
3807 heads += repo.branchheads(branch, start, opts.get('closed'))
3808 heads = [repo[h] for h in heads]
3808 heads = [repo[h] for h in heads]
3809
3809
3810 if branchrevs:
3810 if branchrevs:
3811 branches = {
3811 branches = {
3812 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3812 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3813 }
3813 }
3814 heads = [h for h in heads if h.branch() in branches]
3814 heads = [h for h in heads if h.branch() in branches]
3815
3815
3816 if opts.get('active') and branchrevs:
3816 if opts.get('active') and branchrevs:
3817 dagheads = repo.heads(start)
3817 dagheads = repo.heads(start)
3818 heads = [h for h in heads if h.node() in dagheads]
3818 heads = [h for h in heads if h.node() in dagheads]
3819
3819
3820 if branchrevs:
3820 if branchrevs:
3821 haveheads = {h.branch() for h in heads}
3821 haveheads = {h.branch() for h in heads}
3822 if branches - haveheads:
3822 if branches - haveheads:
3823 headless = b', '.join(b for b in branches - haveheads)
3823 headless = b', '.join(b for b in branches - haveheads)
3824 msg = _(b'no open branch heads found on branches %s')
3824 msg = _(b'no open branch heads found on branches %s')
3825 if opts.get('rev'):
3825 if opts.get('rev'):
3826 msg += _(b' (started at %s)') % opts['rev']
3826 msg += _(b' (started at %s)') % opts['rev']
3827 ui.warn((msg + b'\n') % headless)
3827 ui.warn((msg + b'\n') % headless)
3828
3828
3829 if not heads:
3829 if not heads:
3830 return 1
3830 return 1
3831
3831
3832 ui.pager(b'heads')
3832 ui.pager(b'heads')
3833 heads = sorted(heads, key=lambda x: -(x.rev()))
3833 heads = sorted(heads, key=lambda x: -(x.rev()))
3834 displayer = logcmdutil.changesetdisplayer(
3834 displayer = logcmdutil.changesetdisplayer(
3835 ui, repo, pycompat.byteskwargs(opts)
3835 ui, repo, pycompat.byteskwargs(opts)
3836 )
3836 )
3837 for ctx in heads:
3837 for ctx in heads:
3838 displayer.show(ctx)
3838 displayer.show(ctx)
3839 displayer.close()
3839 displayer.close()
3840
3840
3841
3841
3842 @command(
3842 @command(
3843 b'help',
3843 b'help',
3844 [
3844 [
3845 (b'e', b'extension', None, _(b'show only help for extensions')),
3845 (b'e', b'extension', None, _(b'show only help for extensions')),
3846 (b'c', b'command', None, _(b'show only help for commands')),
3846 (b'c', b'command', None, _(b'show only help for commands')),
3847 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3847 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3848 (
3848 (
3849 b's',
3849 b's',
3850 b'system',
3850 b'system',
3851 [],
3851 [],
3852 _(b'show help for specific platform(s)'),
3852 _(b'show help for specific platform(s)'),
3853 _(b'PLATFORM'),
3853 _(b'PLATFORM'),
3854 ),
3854 ),
3855 ],
3855 ],
3856 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3856 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3857 helpcategory=command.CATEGORY_HELP,
3857 helpcategory=command.CATEGORY_HELP,
3858 norepo=True,
3858 norepo=True,
3859 intents={INTENT_READONLY},
3859 intents={INTENT_READONLY},
3860 )
3860 )
3861 def help_(ui, name=None, **opts):
3861 def help_(ui, name=None, **opts):
3862 """show help for a given topic or a help overview
3862 """show help for a given topic or a help overview
3863
3863
3864 With no arguments, print a list of commands with short help messages.
3864 With no arguments, print a list of commands with short help messages.
3865
3865
3866 Given a topic, extension, or command name, print help for that
3866 Given a topic, extension, or command name, print help for that
3867 topic.
3867 topic.
3868
3868
3869 Returns 0 if successful.
3869 Returns 0 if successful.
3870 """
3870 """
3871
3871
3872 keep = opts.get('system') or []
3872 keep = opts.get('system') or []
3873 if len(keep) == 0:
3873 if len(keep) == 0:
3874 if pycompat.sysplatform.startswith(b'win'):
3874 if pycompat.sysplatform.startswith(b'win'):
3875 keep.append(b'windows')
3875 keep.append(b'windows')
3876 elif pycompat.sysplatform == b'OpenVMS':
3876 elif pycompat.sysplatform == b'OpenVMS':
3877 keep.append(b'vms')
3877 keep.append(b'vms')
3878 elif pycompat.sysplatform == b'plan9':
3878 elif pycompat.sysplatform == b'plan9':
3879 keep.append(b'plan9')
3879 keep.append(b'plan9')
3880 else:
3880 else:
3881 keep.append(b'unix')
3881 keep.append(b'unix')
3882 keep.append(pycompat.sysplatform.lower())
3882 keep.append(pycompat.sysplatform.lower())
3883 if ui.verbose:
3883 if ui.verbose:
3884 keep.append(b'verbose')
3884 keep.append(b'verbose')
3885
3885
3886 commands = sys.modules[__name__]
3886 commands = sys.modules[__name__]
3887 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3887 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3888 ui.pager(b'help')
3888 ui.pager(b'help')
3889 ui.write(formatted)
3889 ui.write(formatted)
3890
3890
3891
3891
3892 @command(
3892 @command(
3893 b'identify|id',
3893 b'identify|id',
3894 [
3894 [
3895 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3895 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3896 (b'n', b'num', None, _(b'show local revision number')),
3896 (b'n', b'num', None, _(b'show local revision number')),
3897 (b'i', b'id', None, _(b'show global revision id')),
3897 (b'i', b'id', None, _(b'show global revision id')),
3898 (b'b', b'branch', None, _(b'show branch')),
3898 (b'b', b'branch', None, _(b'show branch')),
3899 (b't', b'tags', None, _(b'show tags')),
3899 (b't', b'tags', None, _(b'show tags')),
3900 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3900 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3901 ]
3901 ]
3902 + remoteopts
3902 + remoteopts
3903 + formatteropts,
3903 + formatteropts,
3904 _(b'[-nibtB] [-r REV] [SOURCE]'),
3904 _(b'[-nibtB] [-r REV] [SOURCE]'),
3905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3906 optionalrepo=True,
3906 optionalrepo=True,
3907 intents={INTENT_READONLY},
3907 intents={INTENT_READONLY},
3908 )
3908 )
3909 def identify(
3909 def identify(
3910 ui,
3910 ui,
3911 repo,
3911 repo,
3912 source=None,
3912 source=None,
3913 rev=None,
3913 rev=None,
3914 num=None,
3914 num=None,
3915 id=None,
3915 id=None,
3916 branch=None,
3916 branch=None,
3917 tags=None,
3917 tags=None,
3918 bookmarks=None,
3918 bookmarks=None,
3919 **opts
3919 **opts
3920 ):
3920 ):
3921 """identify the working directory or specified revision
3921 """identify the working directory or specified revision
3922
3922
3923 Print a summary identifying the repository state at REV using one or
3923 Print a summary identifying the repository state at REV using one or
3924 two parent hash identifiers, followed by a "+" if the working
3924 two parent hash identifiers, followed by a "+" if the working
3925 directory has uncommitted changes, the branch name (if not default),
3925 directory has uncommitted changes, the branch name (if not default),
3926 a list of tags, and a list of bookmarks.
3926 a list of tags, and a list of bookmarks.
3927
3927
3928 When REV is not given, print a summary of the current state of the
3928 When REV is not given, print a summary of the current state of the
3929 repository including the working directory. Specify -r. to get information
3929 repository including the working directory. Specify -r. to get information
3930 of the working directory parent without scanning uncommitted changes.
3930 of the working directory parent without scanning uncommitted changes.
3931
3931
3932 Specifying a path to a repository root or Mercurial bundle will
3932 Specifying a path to a repository root or Mercurial bundle will
3933 cause lookup to operate on that repository/bundle.
3933 cause lookup to operate on that repository/bundle.
3934
3934
3935 .. container:: verbose
3935 .. container:: verbose
3936
3936
3937 Template:
3937 Template:
3938
3938
3939 The following keywords are supported in addition to the common template
3939 The following keywords are supported in addition to the common template
3940 keywords and functions. See also :hg:`help templates`.
3940 keywords and functions. See also :hg:`help templates`.
3941
3941
3942 :dirty: String. Character ``+`` denoting if the working directory has
3942 :dirty: String. Character ``+`` denoting if the working directory has
3943 uncommitted changes.
3943 uncommitted changes.
3944 :id: String. One or two nodes, optionally followed by ``+``.
3944 :id: String. One or two nodes, optionally followed by ``+``.
3945 :parents: List of strings. Parent nodes of the changeset.
3945 :parents: List of strings. Parent nodes of the changeset.
3946
3946
3947 Examples:
3947 Examples:
3948
3948
3949 - generate a build identifier for the working directory::
3949 - generate a build identifier for the working directory::
3950
3950
3951 hg id --id > build-id.dat
3951 hg id --id > build-id.dat
3952
3952
3953 - find the revision corresponding to a tag::
3953 - find the revision corresponding to a tag::
3954
3954
3955 hg id -n -r 1.3
3955 hg id -n -r 1.3
3956
3956
3957 - check the most recent revision of a remote repository::
3957 - check the most recent revision of a remote repository::
3958
3958
3959 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3959 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3960
3960
3961 See :hg:`log` for generating more information about specific revisions,
3961 See :hg:`log` for generating more information about specific revisions,
3962 including full hash identifiers.
3962 including full hash identifiers.
3963
3963
3964 Returns 0 if successful.
3964 Returns 0 if successful.
3965 """
3965 """
3966
3966
3967 opts = pycompat.byteskwargs(opts)
3967 opts = pycompat.byteskwargs(opts)
3968 if not repo and not source:
3968 if not repo and not source:
3969 raise error.InputError(
3969 raise error.InputError(
3970 _(b"there is no Mercurial repository here (.hg not found)")
3970 _(b"there is no Mercurial repository here (.hg not found)")
3971 )
3971 )
3972
3972
3973 default = not (num or id or branch or tags or bookmarks)
3973 default = not (num or id or branch or tags or bookmarks)
3974 output = []
3974 output = []
3975 revs = []
3975 revs = []
3976
3976
3977 peer = None
3977 peer = None
3978 try:
3978 try:
3979 if source:
3979 if source:
3980 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3980 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3981 # only pass ui when no repo
3981 # only pass ui when no repo
3982 peer = hg.peer(repo or ui, opts, path)
3982 peer = hg.peer(repo or ui, opts, path)
3983 repo = peer.local()
3983 repo = peer.local()
3984 branches = (path.branch, [])
3984 branches = (path.branch, [])
3985 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3985 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3986
3986
3987 fm = ui.formatter(b'identify', opts)
3987 fm = ui.formatter(b'identify', opts)
3988 fm.startitem()
3988 fm.startitem()
3989
3989
3990 if not repo:
3990 if not repo:
3991 if num or branch or tags:
3991 if num or branch or tags:
3992 raise error.InputError(
3992 raise error.InputError(
3993 _(b"can't query remote revision number, branch, or tags")
3993 _(b"can't query remote revision number, branch, or tags")
3994 )
3994 )
3995 if not rev and revs:
3995 if not rev and revs:
3996 rev = revs[0]
3996 rev = revs[0]
3997 if not rev:
3997 if not rev:
3998 rev = b"tip"
3998 rev = b"tip"
3999
3999
4000 remoterev = peer.lookup(rev)
4000 remoterev = peer.lookup(rev)
4001 hexrev = fm.hexfunc(remoterev)
4001 hexrev = fm.hexfunc(remoterev)
4002 if default or id:
4002 if default or id:
4003 output = [hexrev]
4003 output = [hexrev]
4004 fm.data(id=hexrev)
4004 fm.data(id=hexrev)
4005
4005
4006 @util.cachefunc
4006 @util.cachefunc
4007 def getbms():
4007 def getbms():
4008 bms = []
4008 bms = []
4009
4009
4010 if b'bookmarks' in peer.listkeys(b'namespaces'):
4010 if b'bookmarks' in peer.listkeys(b'namespaces'):
4011 hexremoterev = hex(remoterev)
4011 hexremoterev = hex(remoterev)
4012 bms = [
4012 bms = [
4013 bm
4013 bm
4014 for bm, bmr in peer.listkeys(b'bookmarks').items()
4014 for bm, bmr in peer.listkeys(b'bookmarks').items()
4015 if bmr == hexremoterev
4015 if bmr == hexremoterev
4016 ]
4016 ]
4017
4017
4018 return sorted(bms)
4018 return sorted(bms)
4019
4019
4020 if fm.isplain():
4020 if fm.isplain():
4021 if bookmarks:
4021 if bookmarks:
4022 output.extend(getbms())
4022 output.extend(getbms())
4023 elif default and not ui.quiet:
4023 elif default and not ui.quiet:
4024 # multiple bookmarks for a single parent separated by '/'
4024 # multiple bookmarks for a single parent separated by '/'
4025 bm = b'/'.join(getbms())
4025 bm = b'/'.join(getbms())
4026 if bm:
4026 if bm:
4027 output.append(bm)
4027 output.append(bm)
4028 else:
4028 else:
4029 fm.data(node=hex(remoterev))
4029 fm.data(node=hex(remoterev))
4030 if bookmarks or b'bookmarks' in fm.datahint():
4030 if bookmarks or b'bookmarks' in fm.datahint():
4031 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
4031 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
4032 else:
4032 else:
4033 if rev:
4033 if rev:
4034 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4034 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4035 ctx = logcmdutil.revsingle(repo, rev, None)
4035 ctx = logcmdutil.revsingle(repo, rev, None)
4036
4036
4037 if ctx.rev() is None:
4037 if ctx.rev() is None:
4038 ctx = repo[None]
4038 ctx = repo[None]
4039 parents = ctx.parents()
4039 parents = ctx.parents()
4040 taglist = []
4040 taglist = []
4041 for p in parents:
4041 for p in parents:
4042 taglist.extend(p.tags())
4042 taglist.extend(p.tags())
4043
4043
4044 dirty = b""
4044 dirty = b""
4045 if ctx.dirty(missing=True, merge=False, branch=False):
4045 if ctx.dirty(missing=True, merge=False, branch=False):
4046 dirty = b'+'
4046 dirty = b'+'
4047 fm.data(dirty=dirty)
4047 fm.data(dirty=dirty)
4048
4048
4049 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4049 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4050 if default or id:
4050 if default or id:
4051 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4051 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4052 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4052 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4053
4053
4054 if num:
4054 if num:
4055 numoutput = [b"%d" % p.rev() for p in parents]
4055 numoutput = [b"%d" % p.rev() for p in parents]
4056 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4056 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4057
4057
4058 fm.data(
4058 fm.data(
4059 parents=fm.formatlist(
4059 parents=fm.formatlist(
4060 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4060 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4061 )
4061 )
4062 )
4062 )
4063 else:
4063 else:
4064 hexoutput = fm.hexfunc(ctx.node())
4064 hexoutput = fm.hexfunc(ctx.node())
4065 if default or id:
4065 if default or id:
4066 output = [hexoutput]
4066 output = [hexoutput]
4067 fm.data(id=hexoutput)
4067 fm.data(id=hexoutput)
4068
4068
4069 if num:
4069 if num:
4070 output.append(pycompat.bytestr(ctx.rev()))
4070 output.append(pycompat.bytestr(ctx.rev()))
4071 taglist = ctx.tags()
4071 taglist = ctx.tags()
4072
4072
4073 if default and not ui.quiet:
4073 if default and not ui.quiet:
4074 b = ctx.branch()
4074 b = ctx.branch()
4075 if b != b'default':
4075 if b != b'default':
4076 output.append(b"(%s)" % b)
4076 output.append(b"(%s)" % b)
4077
4077
4078 # multiple tags for a single parent separated by '/'
4078 # multiple tags for a single parent separated by '/'
4079 t = b'/'.join(taglist)
4079 t = b'/'.join(taglist)
4080 if t:
4080 if t:
4081 output.append(t)
4081 output.append(t)
4082
4082
4083 # multiple bookmarks for a single parent separated by '/'
4083 # multiple bookmarks for a single parent separated by '/'
4084 bm = b'/'.join(ctx.bookmarks())
4084 bm = b'/'.join(ctx.bookmarks())
4085 if bm:
4085 if bm:
4086 output.append(bm)
4086 output.append(bm)
4087 else:
4087 else:
4088 if branch:
4088 if branch:
4089 output.append(ctx.branch())
4089 output.append(ctx.branch())
4090
4090
4091 if tags:
4091 if tags:
4092 output.extend(taglist)
4092 output.extend(taglist)
4093
4093
4094 if bookmarks:
4094 if bookmarks:
4095 output.extend(ctx.bookmarks())
4095 output.extend(ctx.bookmarks())
4096
4096
4097 fm.data(node=ctx.hex())
4097 fm.data(node=ctx.hex())
4098 fm.data(branch=ctx.branch())
4098 fm.data(branch=ctx.branch())
4099 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4099 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4100 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4100 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4101 fm.context(ctx=ctx)
4101 fm.context(ctx=ctx)
4102
4102
4103 fm.plain(b"%s\n" % b' '.join(output))
4103 fm.plain(b"%s\n" % b' '.join(output))
4104 fm.end()
4104 fm.end()
4105 finally:
4105 finally:
4106 if peer:
4106 if peer:
4107 peer.close()
4107 peer.close()
4108
4108
4109
4109
4110 @command(
4110 @command(
4111 b'import|patch',
4111 b'import|patch',
4112 [
4112 [
4113 (
4113 (
4114 b'p',
4114 b'p',
4115 b'strip',
4115 b'strip',
4116 1,
4116 1,
4117 _(
4117 _(
4118 b'directory strip option for patch. This has the same '
4118 b'directory strip option for patch. This has the same '
4119 b'meaning as the corresponding patch option'
4119 b'meaning as the corresponding patch option'
4120 ),
4120 ),
4121 _(b'NUM'),
4121 _(b'NUM'),
4122 ),
4122 ),
4123 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4123 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4124 (b'', b'secret', None, _(b'use the secret phase for committing')),
4124 (b'', b'secret', None, _(b'use the secret phase for committing')),
4125 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4125 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4126 (
4126 (
4127 b'f',
4127 b'f',
4128 b'force',
4128 b'force',
4129 None,
4129 None,
4130 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4130 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4131 ),
4131 ),
4132 (
4132 (
4133 b'',
4133 b'',
4134 b'no-commit',
4134 b'no-commit',
4135 None,
4135 None,
4136 _(b"don't commit, just update the working directory"),
4136 _(b"don't commit, just update the working directory"),
4137 ),
4137 ),
4138 (
4138 (
4139 b'',
4139 b'',
4140 b'bypass',
4140 b'bypass',
4141 None,
4141 None,
4142 _(b"apply patch without touching the working directory"),
4142 _(b"apply patch without touching the working directory"),
4143 ),
4143 ),
4144 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4144 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4145 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4145 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4146 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4146 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4147 (
4147 (
4148 b'',
4148 b'',
4149 b'import-branch',
4149 b'import-branch',
4150 None,
4150 None,
4151 _(b'use any branch information in patch (implied by --exact)'),
4151 _(b'use any branch information in patch (implied by --exact)'),
4152 ),
4152 ),
4153 ]
4153 ]
4154 + commitopts
4154 + commitopts
4155 + commitopts2
4155 + commitopts2
4156 + similarityopts,
4156 + similarityopts,
4157 _(b'[OPTION]... PATCH...'),
4157 _(b'[OPTION]... PATCH...'),
4158 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4158 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4159 )
4159 )
4160 def import_(ui, repo, patch1=None, *patches, **opts):
4160 def import_(ui, repo, patch1=None, *patches, **opts):
4161 """import an ordered set of patches
4161 """import an ordered set of patches
4162
4162
4163 Import a list of patches and commit them individually (unless
4163 Import a list of patches and commit them individually (unless
4164 --no-commit is specified).
4164 --no-commit is specified).
4165
4165
4166 To read a patch from standard input (stdin), use "-" as the patch
4166 To read a patch from standard input (stdin), use "-" as the patch
4167 name. If a URL is specified, the patch will be downloaded from
4167 name. If a URL is specified, the patch will be downloaded from
4168 there.
4168 there.
4169
4169
4170 Import first applies changes to the working directory (unless
4170 Import first applies changes to the working directory (unless
4171 --bypass is specified), import will abort if there are outstanding
4171 --bypass is specified), import will abort if there are outstanding
4172 changes.
4172 changes.
4173
4173
4174 Use --bypass to apply and commit patches directly to the
4174 Use --bypass to apply and commit patches directly to the
4175 repository, without affecting the working directory. Without
4175 repository, without affecting the working directory. Without
4176 --exact, patches will be applied on top of the working directory
4176 --exact, patches will be applied on top of the working directory
4177 parent revision.
4177 parent revision.
4178
4178
4179 You can import a patch straight from a mail message. Even patches
4179 You can import a patch straight from a mail message. Even patches
4180 as attachments work (to use the body part, it must have type
4180 as attachments work (to use the body part, it must have type
4181 text/plain or text/x-patch). From and Subject headers of email
4181 text/plain or text/x-patch). From and Subject headers of email
4182 message are used as default committer and commit message. All
4182 message are used as default committer and commit message. All
4183 text/plain body parts before first diff are added to the commit
4183 text/plain body parts before first diff are added to the commit
4184 message.
4184 message.
4185
4185
4186 If the imported patch was generated by :hg:`export`, user and
4186 If the imported patch was generated by :hg:`export`, user and
4187 description from patch override values from message headers and
4187 description from patch override values from message headers and
4188 body. Values given on command line with -m/--message and -u/--user
4188 body. Values given on command line with -m/--message and -u/--user
4189 override these.
4189 override these.
4190
4190
4191 If --exact is specified, import will set the working directory to
4191 If --exact is specified, import will set the working directory to
4192 the parent of each patch before applying it, and will abort if the
4192 the parent of each patch before applying it, and will abort if the
4193 resulting changeset has a different ID than the one recorded in
4193 resulting changeset has a different ID than the one recorded in
4194 the patch. This will guard against various ways that portable
4194 the patch. This will guard against various ways that portable
4195 patch formats and mail systems might fail to transfer Mercurial
4195 patch formats and mail systems might fail to transfer Mercurial
4196 data or metadata. See :hg:`bundle` for lossless transmission.
4196 data or metadata. See :hg:`bundle` for lossless transmission.
4197
4197
4198 Use --partial to ensure a changeset will be created from the patch
4198 Use --partial to ensure a changeset will be created from the patch
4199 even if some hunks fail to apply. Hunks that fail to apply will be
4199 even if some hunks fail to apply. Hunks that fail to apply will be
4200 written to a <target-file>.rej file. Conflicts can then be resolved
4200 written to a <target-file>.rej file. Conflicts can then be resolved
4201 by hand before :hg:`commit --amend` is run to update the created
4201 by hand before :hg:`commit --amend` is run to update the created
4202 changeset. This flag exists to let people import patches that
4202 changeset. This flag exists to let people import patches that
4203 partially apply without losing the associated metadata (author,
4203 partially apply without losing the associated metadata (author,
4204 date, description, ...).
4204 date, description, ...).
4205
4205
4206 .. note::
4206 .. note::
4207
4207
4208 When no hunks apply cleanly, :hg:`import --partial` will create
4208 When no hunks apply cleanly, :hg:`import --partial` will create
4209 an empty changeset, importing only the patch metadata.
4209 an empty changeset, importing only the patch metadata.
4210
4210
4211 With -s/--similarity, hg will attempt to discover renames and
4211 With -s/--similarity, hg will attempt to discover renames and
4212 copies in the patch in the same way as :hg:`addremove`.
4212 copies in the patch in the same way as :hg:`addremove`.
4213
4213
4214 It is possible to use external patch programs to perform the patch
4214 It is possible to use external patch programs to perform the patch
4215 by setting the ``ui.patch`` configuration option. For the default
4215 by setting the ``ui.patch`` configuration option. For the default
4216 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4216 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4217 See :hg:`help config` for more information about configuration
4217 See :hg:`help config` for more information about configuration
4218 files and how to use these options.
4218 files and how to use these options.
4219
4219
4220 See :hg:`help dates` for a list of formats valid for -d/--date.
4220 See :hg:`help dates` for a list of formats valid for -d/--date.
4221
4221
4222 .. container:: verbose
4222 .. container:: verbose
4223
4223
4224 Examples:
4224 Examples:
4225
4225
4226 - import a traditional patch from a website and detect renames::
4226 - import a traditional patch from a website and detect renames::
4227
4227
4228 hg import -s 80 http://example.com/bugfix.patch
4228 hg import -s 80 http://example.com/bugfix.patch
4229
4229
4230 - import a changeset from an hgweb server::
4230 - import a changeset from an hgweb server::
4231
4231
4232 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4232 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4233
4233
4234 - import all the patches in an Unix-style mbox::
4234 - import all the patches in an Unix-style mbox::
4235
4235
4236 hg import incoming-patches.mbox
4236 hg import incoming-patches.mbox
4237
4237
4238 - import patches from stdin::
4238 - import patches from stdin::
4239
4239
4240 hg import -
4240 hg import -
4241
4241
4242 - attempt to exactly restore an exported changeset (not always
4242 - attempt to exactly restore an exported changeset (not always
4243 possible)::
4243 possible)::
4244
4244
4245 hg import --exact proposed-fix.patch
4245 hg import --exact proposed-fix.patch
4246
4246
4247 - use an external tool to apply a patch which is too fuzzy for
4247 - use an external tool to apply a patch which is too fuzzy for
4248 the default internal tool.
4248 the default internal tool.
4249
4249
4250 hg import --config ui.patch="patch --merge" fuzzy.patch
4250 hg import --config ui.patch="patch --merge" fuzzy.patch
4251
4251
4252 - change the default fuzzing from 2 to a less strict 7
4252 - change the default fuzzing from 2 to a less strict 7
4253
4253
4254 hg import --config ui.fuzz=7 fuzz.patch
4254 hg import --config ui.fuzz=7 fuzz.patch
4255
4255
4256 Returns 0 on success, 1 on partial success (see --partial).
4256 Returns 0 on success, 1 on partial success (see --partial).
4257 """
4257 """
4258
4258
4259 cmdutil.check_incompatible_arguments(
4259 cmdutil.check_incompatible_arguments(
4260 opts, 'no_commit', ['bypass', 'secret']
4260 opts, 'no_commit', ['bypass', 'secret']
4261 )
4261 )
4262 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4262 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4263
4263
4264 if not patch1:
4264 if not patch1:
4265 raise error.InputError(_(b'need at least one patch to import'))
4265 raise error.InputError(_(b'need at least one patch to import'))
4266
4266
4267 patches = (patch1,) + patches
4267 patches = (patch1,) + patches
4268
4268
4269 date = opts.get('date')
4269 date = opts.get('date')
4270 if date:
4270 if date:
4271 opts['date'] = dateutil.parsedate(date)
4271 opts['date'] = dateutil.parsedate(date)
4272
4272
4273 exact = opts.get('exact')
4273 exact = opts.get('exact')
4274 update = not opts.get('bypass')
4274 update = not opts.get('bypass')
4275 try:
4275 try:
4276 sim = float(opts.get('similarity') or 0)
4276 sim = float(opts.get('similarity') or 0)
4277 except ValueError:
4277 except ValueError:
4278 raise error.InputError(_(b'similarity must be a number'))
4278 raise error.InputError(_(b'similarity must be a number'))
4279 if sim < 0 or sim > 100:
4279 if sim < 0 or sim > 100:
4280 raise error.InputError(_(b'similarity must be between 0 and 100'))
4280 raise error.InputError(_(b'similarity must be between 0 and 100'))
4281 if sim and not update:
4281 if sim and not update:
4282 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4282 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4283
4283
4284 base = opts["base"]
4284 base = opts["base"]
4285 msgs = []
4285 msgs = []
4286 ret = 0
4286 ret = 0
4287
4287
4288 with repo.wlock():
4288 with repo.wlock():
4289 if update:
4289 if update:
4290 cmdutil.checkunfinished(repo)
4290 cmdutil.checkunfinished(repo)
4291 if exact or not opts.get('force'):
4291 if exact or not opts.get('force'):
4292 cmdutil.bailifchanged(repo)
4292 cmdutil.bailifchanged(repo)
4293
4293
4294 if not opts.get('no_commit'):
4294 if not opts.get('no_commit'):
4295 lock = repo.lock
4295 lock = repo.lock
4296 tr = lambda: repo.transaction(b'import')
4296 tr = lambda: repo.transaction(b'import')
4297 else:
4297 else:
4298 lock = util.nullcontextmanager
4298 lock = util.nullcontextmanager
4299 tr = util.nullcontextmanager
4299 tr = util.nullcontextmanager
4300 with lock(), tr():
4300 with lock(), tr():
4301 parents = repo[None].parents()
4301 parents = repo[None].parents()
4302 for patchurl in patches:
4302 for patchurl in patches:
4303 if patchurl == b'-':
4303 if patchurl == b'-':
4304 ui.status(_(b'applying patch from stdin\n'))
4304 ui.status(_(b'applying patch from stdin\n'))
4305 patchfile = ui.fin
4305 patchfile = ui.fin
4306 patchurl = b'stdin' # for error message
4306 patchurl = b'stdin' # for error message
4307 else:
4307 else:
4308 patchurl = os.path.join(base, patchurl)
4308 patchurl = os.path.join(base, patchurl)
4309 ui.status(_(b'applying %s\n') % patchurl)
4309 ui.status(_(b'applying %s\n') % patchurl)
4310 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4310 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4311
4311
4312 haspatch = False
4312 haspatch = False
4313 for hunk in patch.split(patchfile):
4313 for hunk in patch.split(patchfile):
4314 with patch.extract(ui, hunk) as patchdata:
4314 with patch.extract(ui, hunk) as patchdata:
4315 msg, node, rej = cmdutil.tryimportone(
4315 msg, node, rej = cmdutil.tryimportone(
4316 ui,
4316 ui,
4317 repo,
4317 repo,
4318 patchdata,
4318 patchdata,
4319 parents,
4319 parents,
4320 pycompat.byteskwargs(opts),
4320 pycompat.byteskwargs(opts),
4321 msgs,
4321 msgs,
4322 hg.clean,
4322 hg.clean,
4323 )
4323 )
4324 if msg:
4324 if msg:
4325 haspatch = True
4325 haspatch = True
4326 ui.note(msg + b'\n')
4326 ui.note(msg + b'\n')
4327 if update or exact:
4327 if update or exact:
4328 parents = repo[None].parents()
4328 parents = repo[None].parents()
4329 else:
4329 else:
4330 parents = [repo[node]]
4330 parents = [repo[node]]
4331 if rej:
4331 if rej:
4332 ui.write_err(_(b"patch applied partially\n"))
4332 ui.write_err(_(b"patch applied partially\n"))
4333 ui.write_err(
4333 ui.write_err(
4334 _(
4334 _(
4335 b"(fix the .rej files and run "
4335 b"(fix the .rej files and run "
4336 b"`hg commit --amend`)\n"
4336 b"`hg commit --amend`)\n"
4337 )
4337 )
4338 )
4338 )
4339 ret = 1
4339 ret = 1
4340 break
4340 break
4341
4341
4342 if not haspatch:
4342 if not haspatch:
4343 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4343 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4344
4344
4345 if msgs:
4345 if msgs:
4346 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4346 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4347 return ret
4347 return ret
4348
4348
4349
4349
4350 @command(
4350 @command(
4351 b'incoming|in',
4351 b'incoming|in',
4352 [
4352 [
4353 (
4353 (
4354 b'f',
4354 b'f',
4355 b'force',
4355 b'force',
4356 None,
4356 None,
4357 _(b'run even if remote repository is unrelated'),
4357 _(b'run even if remote repository is unrelated'),
4358 ),
4358 ),
4359 (b'n', b'newest-first', None, _(b'show newest record first')),
4359 (b'n', b'newest-first', None, _(b'show newest record first')),
4360 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4360 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4361 (
4361 (
4362 b'r',
4362 b'r',
4363 b'rev',
4363 b'rev',
4364 [],
4364 [],
4365 _(b'a remote changeset intended to be added'),
4365 _(b'a remote changeset intended to be added'),
4366 _(b'REV'),
4366 _(b'REV'),
4367 ),
4367 ),
4368 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4368 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4369 (
4369 (
4370 b'b',
4370 b'b',
4371 b'branch',
4371 b'branch',
4372 [],
4372 [],
4373 _(b'a specific branch you would like to pull'),
4373 _(b'a specific branch you would like to pull'),
4374 _(b'BRANCH'),
4374 _(b'BRANCH'),
4375 ),
4375 ),
4376 ]
4376 ]
4377 + logopts
4377 + logopts
4378 + remoteopts
4378 + remoteopts
4379 + subrepoopts,
4379 + subrepoopts,
4380 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4380 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4381 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4381 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4382 )
4382 )
4383 def incoming(ui, repo, source=b"default", **opts):
4383 def incoming(ui, repo, source=b"default", **opts):
4384 """show new changesets found in source
4384 """show new changesets found in source
4385
4385
4386 Show new changesets found in the specified path/URL or the default
4386 Show new changesets found in the specified path/URL or the default
4387 pull location. These are the changesets that would have been pulled
4387 pull location. These are the changesets that would have been pulled
4388 by :hg:`pull` at the time you issued this command.
4388 by :hg:`pull` at the time you issued this command.
4389
4389
4390 See pull for valid source format details.
4390 See pull for valid source format details.
4391
4391
4392 .. container:: verbose
4392 .. container:: verbose
4393
4393
4394 With -B/--bookmarks, the result of bookmark comparison between
4394 With -B/--bookmarks, the result of bookmark comparison between
4395 local and remote repositories is displayed. With -v/--verbose,
4395 local and remote repositories is displayed. With -v/--verbose,
4396 status is also displayed for each bookmark like below::
4396 status is also displayed for each bookmark like below::
4397
4397
4398 BM1 01234567890a added
4398 BM1 01234567890a added
4399 BM2 1234567890ab advanced
4399 BM2 1234567890ab advanced
4400 BM3 234567890abc diverged
4400 BM3 234567890abc diverged
4401 BM4 34567890abcd changed
4401 BM4 34567890abcd changed
4402
4402
4403 The action taken locally when pulling depends on the
4403 The action taken locally when pulling depends on the
4404 status of each bookmark:
4404 status of each bookmark:
4405
4405
4406 :``added``: pull will create it
4406 :``added``: pull will create it
4407 :``advanced``: pull will update it
4407 :``advanced``: pull will update it
4408 :``diverged``: pull will create a divergent bookmark
4408 :``diverged``: pull will create a divergent bookmark
4409 :``changed``: result depends on remote changesets
4409 :``changed``: result depends on remote changesets
4410
4410
4411 From the point of view of pulling behavior, bookmark
4411 From the point of view of pulling behavior, bookmark
4412 existing only in the remote repository are treated as ``added``,
4412 existing only in the remote repository are treated as ``added``,
4413 even if it is in fact locally deleted.
4413 even if it is in fact locally deleted.
4414
4414
4415 .. container:: verbose
4415 .. container:: verbose
4416
4416
4417 For remote repository, using --bundle avoids downloading the
4417 For remote repository, using --bundle avoids downloading the
4418 changesets twice if the incoming is followed by a pull.
4418 changesets twice if the incoming is followed by a pull.
4419
4419
4420 Examples:
4420 Examples:
4421
4421
4422 - show incoming changes with patches and full description::
4422 - show incoming changes with patches and full description::
4423
4423
4424 hg incoming -vp
4424 hg incoming -vp
4425
4425
4426 - show incoming changes excluding merges, store a bundle::
4426 - show incoming changes excluding merges, store a bundle::
4427
4427
4428 hg in -vpM --bundle incoming.hg
4428 hg in -vpM --bundle incoming.hg
4429 hg pull incoming.hg
4429 hg pull incoming.hg
4430
4430
4431 - briefly list changes inside a bundle::
4431 - briefly list changes inside a bundle::
4432
4432
4433 hg in changes.hg -T "{desc|firstline}\\n"
4433 hg in changes.hg -T "{desc|firstline}\\n"
4434
4434
4435 Returns 0 if there are incoming changes, 1 otherwise.
4435 Returns 0 if there are incoming changes, 1 otherwise.
4436 """
4436 """
4437 opts = pycompat.byteskwargs(opts)
4437 opts = pycompat.byteskwargs(opts)
4438 if opts.get(b'graph'):
4438 if opts.get(b'graph'):
4439 logcmdutil.checkunsupportedgraphflags([], opts)
4439 logcmdutil.checkunsupportedgraphflags([], opts)
4440
4440
4441 def display(other, chlist, displayer):
4441 def display(other, chlist, displayer):
4442 revdag = logcmdutil.graphrevs(other, chlist, opts)
4442 revdag = logcmdutil.graphrevs(other, chlist, opts)
4443 logcmdutil.displaygraph(
4443 logcmdutil.displaygraph(
4444 ui, repo, revdag, displayer, graphmod.asciiedges
4444 ui, repo, revdag, displayer, graphmod.asciiedges
4445 )
4445 )
4446
4446
4447 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4447 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4448 return 0
4448 return 0
4449
4449
4450 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4450 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4451
4451
4452 if opts.get(b'bookmarks'):
4452 if opts.get(b'bookmarks'):
4453 srcs = urlutil.get_pull_paths(repo, ui, [source])
4453 srcs = urlutil.get_pull_paths(repo, ui, [source])
4454 for path in srcs:
4454 for path in srcs:
4455 # XXX the "branches" options are not used. Should it be used?
4455 # XXX the "branches" options are not used. Should it be used?
4456 other = hg.peer(repo, opts, path)
4456 other = hg.peer(repo, opts, path)
4457 try:
4457 try:
4458 if b'bookmarks' not in other.listkeys(b'namespaces'):
4458 if b'bookmarks' not in other.listkeys(b'namespaces'):
4459 ui.warn(_(b"remote doesn't support bookmarks\n"))
4459 ui.warn(_(b"remote doesn't support bookmarks\n"))
4460 return 0
4460 return 0
4461 ui.pager(b'incoming')
4461 ui.pager(b'incoming')
4462 ui.status(
4462 ui.status(
4463 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4463 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4464 )
4464 )
4465 return bookmarks.incoming(
4465 return bookmarks.incoming(
4466 ui, repo, other, mode=path.bookmarks_mode
4466 ui, repo, other, mode=path.bookmarks_mode
4467 )
4467 )
4468 finally:
4468 finally:
4469 other.close()
4469 other.close()
4470
4470
4471 return hg.incoming(ui, repo, source, opts)
4471 return hg.incoming(ui, repo, source, opts)
4472
4472
4473
4473
4474 @command(
4474 @command(
4475 b'init',
4475 b'init',
4476 remoteopts,
4476 remoteopts,
4477 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4477 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4478 helpcategory=command.CATEGORY_REPO_CREATION,
4478 helpcategory=command.CATEGORY_REPO_CREATION,
4479 helpbasic=True,
4479 helpbasic=True,
4480 norepo=True,
4480 norepo=True,
4481 )
4481 )
4482 def init(ui, dest=b".", **opts):
4482 def init(ui, dest=b".", **opts):
4483 """create a new repository in the given directory
4483 """create a new repository in the given directory
4484
4484
4485 Initialize a new repository in the given directory. If the given
4485 Initialize a new repository in the given directory. If the given
4486 directory does not exist, it will be created.
4486 directory does not exist, it will be created.
4487
4487
4488 If no directory is given, the current directory is used.
4488 If no directory is given, the current directory is used.
4489
4489
4490 It is possible to specify an ``ssh://`` URL as the destination.
4490 It is possible to specify an ``ssh://`` URL as the destination.
4491 See :hg:`help urls` for more information.
4491 See :hg:`help urls` for more information.
4492
4492
4493 Returns 0 on success.
4493 Returns 0 on success.
4494 """
4494 """
4495 opts = pycompat.byteskwargs(opts)
4495 opts = pycompat.byteskwargs(opts)
4496 path = urlutil.get_clone_path_obj(ui, dest)
4496 path = urlutil.get_clone_path_obj(ui, dest)
4497 peer = hg.peer(ui, opts, path, create=True)
4497 peer = hg.peer(ui, opts, path, create=True)
4498 peer.close()
4498 peer.close()
4499
4499
4500
4500
4501 @command(
4501 @command(
4502 b'locate',
4502 b'locate',
4503 [
4503 [
4504 (
4504 (
4505 b'r',
4505 b'r',
4506 b'rev',
4506 b'rev',
4507 b'',
4507 b'',
4508 _(b'search the repository as it is in REV'),
4508 _(b'search the repository as it is in REV'),
4509 _(b'REV'),
4509 _(b'REV'),
4510 ),
4510 ),
4511 (
4511 (
4512 b'0',
4512 b'0',
4513 b'print0',
4513 b'print0',
4514 None,
4514 None,
4515 _(b'end filenames with NUL, for use with xargs'),
4515 _(b'end filenames with NUL, for use with xargs'),
4516 ),
4516 ),
4517 (
4517 (
4518 b'f',
4518 b'f',
4519 b'fullpath',
4519 b'fullpath',
4520 None,
4520 None,
4521 _(b'print complete paths from the filesystem root'),
4521 _(b'print complete paths from the filesystem root'),
4522 ),
4522 ),
4523 ]
4523 ]
4524 + walkopts,
4524 + walkopts,
4525 _(b'[OPTION]... [PATTERN]...'),
4525 _(b'[OPTION]... [PATTERN]...'),
4526 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4526 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4527 )
4527 )
4528 def locate(ui, repo, *pats, **opts):
4528 def locate(ui, repo, *pats, **opts):
4529 """locate files matching specific patterns (DEPRECATED)
4529 """locate files matching specific patterns (DEPRECATED)
4530
4530
4531 Print files under Mercurial control in the working directory whose
4531 Print files under Mercurial control in the working directory whose
4532 names match the given patterns.
4532 names match the given patterns.
4533
4533
4534 By default, this command searches all directories in the working
4534 By default, this command searches all directories in the working
4535 directory. To search just the current directory and its
4535 directory. To search just the current directory and its
4536 subdirectories, use "--include .".
4536 subdirectories, use "--include .".
4537
4537
4538 If no patterns are given to match, this command prints the names
4538 If no patterns are given to match, this command prints the names
4539 of all files under Mercurial control in the working directory.
4539 of all files under Mercurial control in the working directory.
4540
4540
4541 If you want to feed the output of this command into the "xargs"
4541 If you want to feed the output of this command into the "xargs"
4542 command, use the -0 option to both this command and "xargs". This
4542 command, use the -0 option to both this command and "xargs". This
4543 will avoid the problem of "xargs" treating single filenames that
4543 will avoid the problem of "xargs" treating single filenames that
4544 contain whitespace as multiple filenames.
4544 contain whitespace as multiple filenames.
4545
4545
4546 See :hg:`help files` for a more versatile command.
4546 See :hg:`help files` for a more versatile command.
4547
4547
4548 Returns 0 if a match is found, 1 otherwise.
4548 Returns 0 if a match is found, 1 otherwise.
4549 """
4549 """
4550 if opts.get('print0'):
4550 if opts.get('print0'):
4551 end = b'\0'
4551 end = b'\0'
4552 else:
4552 else:
4553 end = b'\n'
4553 end = b'\n'
4554 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4554 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4555
4555
4556 ret = 1
4556 ret = 1
4557 m = scmutil.match(
4557 m = scmutil.match(
4558 ctx,
4558 ctx,
4559 pats,
4559 pats,
4560 pycompat.byteskwargs(opts),
4560 pycompat.byteskwargs(opts),
4561 default=b'relglob',
4561 default=b'relglob',
4562 badfn=lambda x, y: False,
4562 badfn=lambda x, y: False,
4563 )
4563 )
4564
4564
4565 ui.pager(b'locate')
4565 ui.pager(b'locate')
4566 if ctx.rev() is None:
4566 if ctx.rev() is None:
4567 # When run on the working copy, "locate" includes removed files, so
4567 # When run on the working copy, "locate" includes removed files, so
4568 # we get the list of files from the dirstate.
4568 # we get the list of files from the dirstate.
4569 filesgen = sorted(repo.dirstate.matches(m))
4569 filesgen = sorted(repo.dirstate.matches(m))
4570 else:
4570 else:
4571 filesgen = ctx.matches(m)
4571 filesgen = ctx.matches(m)
4572 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4572 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4573 for abs in filesgen:
4573 for abs in filesgen:
4574 if opts.get('fullpath'):
4574 if opts.get('fullpath'):
4575 ui.write(repo.wjoin(abs), end)
4575 ui.write(repo.wjoin(abs), end)
4576 else:
4576 else:
4577 ui.write(uipathfn(abs), end)
4577 ui.write(uipathfn(abs), end)
4578 ret = 0
4578 ret = 0
4579
4579
4580 return ret
4580 return ret
4581
4581
4582
4582
4583 @command(
4583 @command(
4584 b'log|history',
4584 b'log|history',
4585 [
4585 [
4586 (
4586 (
4587 b'f',
4587 b'f',
4588 b'follow',
4588 b'follow',
4589 None,
4589 None,
4590 _(
4590 _(
4591 b'follow changeset history, or file history across copies and renames'
4591 b'follow changeset history, or file history across copies and renames'
4592 ),
4592 ),
4593 ),
4593 ),
4594 (
4594 (
4595 b'',
4595 b'',
4596 b'follow-first',
4596 b'follow-first',
4597 None,
4597 None,
4598 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4598 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4599 ),
4599 ),
4600 (
4600 (
4601 b'd',
4601 b'd',
4602 b'date',
4602 b'date',
4603 b'',
4603 b'',
4604 _(b'show revisions matching date spec'),
4604 _(b'show revisions matching date spec'),
4605 _(b'DATE'),
4605 _(b'DATE'),
4606 ),
4606 ),
4607 (b'C', b'copies', None, _(b'show copied files')),
4607 (b'C', b'copies', None, _(b'show copied files')),
4608 (
4608 (
4609 b'k',
4609 b'k',
4610 b'keyword',
4610 b'keyword',
4611 [],
4611 [],
4612 _(b'do case-insensitive search for a given text'),
4612 _(b'do case-insensitive search for a given text'),
4613 _(b'TEXT'),
4613 _(b'TEXT'),
4614 ),
4614 ),
4615 (
4615 (
4616 b'r',
4616 b'r',
4617 b'rev',
4617 b'rev',
4618 [],
4618 [],
4619 _(b'revisions to select or follow from'),
4619 _(b'revisions to select or follow from'),
4620 _(b'REV'),
4620 _(b'REV'),
4621 ),
4621 ),
4622 (
4622 (
4623 b'L',
4623 b'L',
4624 b'line-range',
4624 b'line-range',
4625 [],
4625 [],
4626 _(b'follow line range of specified file (EXPERIMENTAL)'),
4626 _(b'follow line range of specified file (EXPERIMENTAL)'),
4627 _(b'FILE,RANGE'),
4627 _(b'FILE,RANGE'),
4628 ),
4628 ),
4629 (
4629 (
4630 b'',
4630 b'',
4631 b'removed',
4631 b'removed',
4632 None,
4632 None,
4633 _(b'include revisions where files were removed'),
4633 _(b'include revisions where files were removed'),
4634 ),
4634 ),
4635 (
4635 (
4636 b'm',
4636 b'm',
4637 b'only-merges',
4637 b'only-merges',
4638 None,
4638 None,
4639 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4639 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4640 ),
4640 ),
4641 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4641 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4642 (
4642 (
4643 b'',
4643 b'',
4644 b'only-branch',
4644 b'only-branch',
4645 [],
4645 [],
4646 _(
4646 _(
4647 b'show only changesets within the given named branch (DEPRECATED)'
4647 b'show only changesets within the given named branch (DEPRECATED)'
4648 ),
4648 ),
4649 _(b'BRANCH'),
4649 _(b'BRANCH'),
4650 ),
4650 ),
4651 (
4651 (
4652 b'b',
4652 b'b',
4653 b'branch',
4653 b'branch',
4654 [],
4654 [],
4655 _(b'show changesets within the given named branch'),
4655 _(b'show changesets within the given named branch'),
4656 _(b'BRANCH'),
4656 _(b'BRANCH'),
4657 ),
4657 ),
4658 (
4658 (
4659 b'B',
4659 b'B',
4660 b'bookmark',
4660 b'bookmark',
4661 [],
4661 [],
4662 _(b"show changesets within the given bookmark"),
4662 _(b"show changesets within the given bookmark"),
4663 _(b'BOOKMARK'),
4663 _(b'BOOKMARK'),
4664 ),
4664 ),
4665 (
4665 (
4666 b'P',
4666 b'P',
4667 b'prune',
4667 b'prune',
4668 [],
4668 [],
4669 _(b'do not display revision or any of its ancestors'),
4669 _(b'do not display revision or any of its ancestors'),
4670 _(b'REV'),
4670 _(b'REV'),
4671 ),
4671 ),
4672 ]
4672 ]
4673 + logopts
4673 + logopts
4674 + walkopts,
4674 + walkopts,
4675 _(b'[OPTION]... [FILE]'),
4675 _(b'[OPTION]... [FILE]'),
4676 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4676 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4677 helpbasic=True,
4677 helpbasic=True,
4678 inferrepo=True,
4678 inferrepo=True,
4679 intents={INTENT_READONLY},
4679 intents={INTENT_READONLY},
4680 )
4680 )
4681 def log(ui, repo, *pats, **opts):
4681 def log(ui, repo, *pats, **opts):
4682 """show revision history of entire repository or files
4682 """show revision history of entire repository or files
4683
4683
4684 Print the revision history of the specified files or the entire
4684 Print the revision history of the specified files or the entire
4685 project.
4685 project.
4686
4686
4687 If no revision range is specified, the default is ``tip:0`` unless
4687 If no revision range is specified, the default is ``tip:0`` unless
4688 --follow is set.
4688 --follow is set.
4689
4689
4690 File history is shown without following rename or copy history of
4690 File history is shown without following rename or copy history of
4691 files. Use -f/--follow with a filename to follow history across
4691 files. Use -f/--follow with a filename to follow history across
4692 renames and copies. --follow without a filename will only show
4692 renames and copies. --follow without a filename will only show
4693 ancestors of the starting revisions. The starting revisions can be
4693 ancestors of the starting revisions. The starting revisions can be
4694 specified by -r/--rev, which default to the working directory parent.
4694 specified by -r/--rev, which default to the working directory parent.
4695
4695
4696 By default this command prints revision number and changeset id,
4696 By default this command prints revision number and changeset id,
4697 tags, non-trivial parents, user, date and time, and a summary for
4697 tags, non-trivial parents, user, date and time, and a summary for
4698 each commit. When the -v/--verbose switch is used, the list of
4698 each commit. When the -v/--verbose switch is used, the list of
4699 changed files and full commit message are shown.
4699 changed files and full commit message are shown.
4700
4700
4701 With --graph the revisions are shown as an ASCII art DAG with the most
4701 With --graph the revisions are shown as an ASCII art DAG with the most
4702 recent changeset at the top.
4702 recent changeset at the top.
4703 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4703 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4704 involved in an unresolved merge conflict, '_' closes a branch,
4704 involved in an unresolved merge conflict, '_' closes a branch,
4705 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4705 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4706 changeset from the lines below is a parent of the 'o' merge on the same
4706 changeset from the lines below is a parent of the 'o' merge on the same
4707 line.
4707 line.
4708 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4708 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4709 of a '|' indicates one or more revisions in a path are omitted.
4709 of a '|' indicates one or more revisions in a path are omitted.
4710
4710
4711 .. container:: verbose
4711 .. container:: verbose
4712
4712
4713 Use -L/--line-range FILE,M:N options to follow the history of lines
4713 Use -L/--line-range FILE,M:N options to follow the history of lines
4714 from M to N in FILE. With -p/--patch only diff hunks affecting
4714 from M to N in FILE. With -p/--patch only diff hunks affecting
4715 specified line range will be shown. This option requires --follow;
4715 specified line range will be shown. This option requires --follow;
4716 it can be specified multiple times. Currently, this option is not
4716 it can be specified multiple times. Currently, this option is not
4717 compatible with --graph. This option is experimental.
4717 compatible with --graph. This option is experimental.
4718
4718
4719 .. note::
4719 .. note::
4720
4720
4721 :hg:`log --patch` may generate unexpected diff output for merge
4721 :hg:`log --patch` may generate unexpected diff output for merge
4722 changesets, as it will only compare the merge changeset against
4722 changesets, as it will only compare the merge changeset against
4723 its first parent. Also, only files different from BOTH parents
4723 its first parent. Also, only files different from BOTH parents
4724 will appear in files:.
4724 will appear in files:.
4725
4725
4726 .. note::
4726 .. note::
4727
4727
4728 For performance reasons, :hg:`log FILE` may omit duplicate changes
4728 For performance reasons, :hg:`log FILE` may omit duplicate changes
4729 made on branches and will not show removals or mode changes. To
4729 made on branches and will not show removals or mode changes. To
4730 see all such changes, use the --removed switch.
4730 see all such changes, use the --removed switch.
4731
4731
4732 .. container:: verbose
4732 .. container:: verbose
4733
4733
4734 .. note::
4734 .. note::
4735
4735
4736 The history resulting from -L/--line-range options depends on diff
4736 The history resulting from -L/--line-range options depends on diff
4737 options; for instance if white-spaces are ignored, respective changes
4737 options; for instance if white-spaces are ignored, respective changes
4738 with only white-spaces in specified line range will not be listed.
4738 with only white-spaces in specified line range will not be listed.
4739
4739
4740 .. container:: verbose
4740 .. container:: verbose
4741
4741
4742 Some examples:
4742 Some examples:
4743
4743
4744 - changesets with full descriptions and file lists::
4744 - changesets with full descriptions and file lists::
4745
4745
4746 hg log -v
4746 hg log -v
4747
4747
4748 - changesets ancestral to the working directory::
4748 - changesets ancestral to the working directory::
4749
4749
4750 hg log -f
4750 hg log -f
4751
4751
4752 - last 10 commits on the current branch::
4752 - last 10 commits on the current branch::
4753
4753
4754 hg log -l 10 -b .
4754 hg log -l 10 -b .
4755
4755
4756 - changesets showing all modifications of a file, including removals::
4756 - changesets showing all modifications of a file, including removals::
4757
4757
4758 hg log --removed file.c
4758 hg log --removed file.c
4759
4759
4760 - all changesets that touch a directory, with diffs, excluding merges::
4760 - all changesets that touch a directory, with diffs, excluding merges::
4761
4761
4762 hg log -Mp lib/
4762 hg log -Mp lib/
4763
4763
4764 - all revision numbers that match a keyword::
4764 - all revision numbers that match a keyword::
4765
4765
4766 hg log -k bug --template "{rev}\\n"
4766 hg log -k bug --template "{rev}\\n"
4767
4767
4768 - the full hash identifier of the working directory parent::
4768 - the full hash identifier of the working directory parent::
4769
4769
4770 hg log -r . --template "{node}\\n"
4770 hg log -r . --template "{node}\\n"
4771
4771
4772 - list available log templates::
4772 - list available log templates::
4773
4773
4774 hg log -T list
4774 hg log -T list
4775
4775
4776 - check if a given changeset is included in a tagged release::
4776 - check if a given changeset is included in a tagged release::
4777
4777
4778 hg log -r "a21ccf and ancestor(1.9)"
4778 hg log -r "a21ccf and ancestor(1.9)"
4779
4779
4780 - find all changesets by some user in a date range::
4780 - find all changesets by some user in a date range::
4781
4781
4782 hg log -k alice -d "may 2008 to jul 2008"
4782 hg log -k alice -d "may 2008 to jul 2008"
4783
4783
4784 - summary of all changesets after the last tag::
4784 - summary of all changesets after the last tag::
4785
4785
4786 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4786 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4787
4787
4788 - changesets touching lines 13 to 23 for file.c::
4788 - changesets touching lines 13 to 23 for file.c::
4789
4789
4790 hg log -L file.c,13:23
4790 hg log -L file.c,13:23
4791
4791
4792 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4792 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4793 main.c with patch::
4793 main.c with patch::
4794
4794
4795 hg log -L file.c,13:23 -L main.c,2:6 -p
4795 hg log -L file.c,13:23 -L main.c,2:6 -p
4796
4796
4797 See :hg:`help dates` for a list of formats valid for -d/--date.
4797 See :hg:`help dates` for a list of formats valid for -d/--date.
4798
4798
4799 See :hg:`help revisions` for more about specifying and ordering
4799 See :hg:`help revisions` for more about specifying and ordering
4800 revisions.
4800 revisions.
4801
4801
4802 See :hg:`help templates` for more about pre-packaged styles and
4802 See :hg:`help templates` for more about pre-packaged styles and
4803 specifying custom templates. The default template used by the log
4803 specifying custom templates. The default template used by the log
4804 command can be customized via the ``command-templates.log`` configuration
4804 command can be customized via the ``command-templates.log`` configuration
4805 setting.
4805 setting.
4806
4806
4807 Returns 0 on success.
4807 Returns 0 on success.
4808
4808
4809 """
4809 """
4810 opts = pycompat.byteskwargs(opts)
4810 opts = pycompat.byteskwargs(opts)
4811 linerange = opts.get(b'line_range')
4811 linerange = opts.get(b'line_range')
4812
4812
4813 if linerange and not opts.get(b'follow'):
4813 if linerange and not opts.get(b'follow'):
4814 raise error.InputError(_(b'--line-range requires --follow'))
4814 raise error.InputError(_(b'--line-range requires --follow'))
4815
4815
4816 if linerange and pats:
4816 if linerange and pats:
4817 # TODO: take pats as patterns with no line-range filter
4817 # TODO: take pats as patterns with no line-range filter
4818 raise error.InputError(
4818 raise error.InputError(
4819 _(b'FILE arguments are not compatible with --line-range option')
4819 _(b'FILE arguments are not compatible with --line-range option')
4820 )
4820 )
4821
4821
4822 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4822 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4823 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4823 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4824 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4824 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4825 if linerange:
4825 if linerange:
4826 # TODO: should follow file history from logcmdutil._initialrevs(),
4826 # TODO: should follow file history from logcmdutil._initialrevs(),
4827 # then filter the result by logcmdutil._makerevset() and --limit
4827 # then filter the result by logcmdutil._makerevset() and --limit
4828 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4828 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4829
4829
4830 getcopies = None
4830 getcopies = None
4831 if opts.get(b'copies'):
4831 if opts.get(b'copies'):
4832 endrev = None
4832 endrev = None
4833 if revs:
4833 if revs:
4834 endrev = revs.max() + 1
4834 endrev = revs.max() + 1
4835 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4835 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4836
4836
4837 ui.pager(b'log')
4837 ui.pager(b'log')
4838 displayer = logcmdutil.changesetdisplayer(
4838 displayer = logcmdutil.changesetdisplayer(
4839 ui, repo, opts, differ, buffered=True
4839 ui, repo, opts, differ, buffered=True
4840 )
4840 )
4841 if opts.get(b'graph'):
4841 if opts.get(b'graph'):
4842 displayfn = logcmdutil.displaygraphrevs
4842 displayfn = logcmdutil.displaygraphrevs
4843 else:
4843 else:
4844 displayfn = logcmdutil.displayrevs
4844 displayfn = logcmdutil.displayrevs
4845 displayfn(ui, repo, revs, displayer, getcopies)
4845 displayfn(ui, repo, revs, displayer, getcopies)
4846
4846
4847
4847
4848 @command(
4848 @command(
4849 b'manifest',
4849 b'manifest',
4850 [
4850 [
4851 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4851 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4852 (b'', b'all', False, _(b"list files from all revisions")),
4852 (b'', b'all', False, _(b"list files from all revisions")),
4853 ]
4853 ]
4854 + formatteropts,
4854 + formatteropts,
4855 _(b'[-r REV]'),
4855 _(b'[-r REV]'),
4856 helpcategory=command.CATEGORY_MAINTENANCE,
4856 helpcategory=command.CATEGORY_MAINTENANCE,
4857 intents={INTENT_READONLY},
4857 intents={INTENT_READONLY},
4858 )
4858 )
4859 def manifest(ui, repo, node=None, rev=None, **opts):
4859 def manifest(ui, repo, node=None, rev=None, **opts):
4860 """output the current or given revision of the project manifest
4860 """output the current or given revision of the project manifest
4861
4861
4862 Print a list of version controlled files for the given revision.
4862 Print a list of version controlled files for the given revision.
4863 If no revision is given, the first parent of the working directory
4863 If no revision is given, the first parent of the working directory
4864 is used, or the null revision if no revision is checked out.
4864 is used, or the null revision if no revision is checked out.
4865
4865
4866 With -v, print file permissions, symlink and executable bits.
4866 With -v, print file permissions, symlink and executable bits.
4867 With --debug, print file revision hashes.
4867 With --debug, print file revision hashes.
4868
4868
4869 If option --all is specified, the list of all files from all revisions
4869 If option --all is specified, the list of all files from all revisions
4870 is printed. This includes deleted and renamed files.
4870 is printed. This includes deleted and renamed files.
4871
4871
4872 Returns 0 on success.
4872 Returns 0 on success.
4873 """
4873 """
4874 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4874 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4875
4875
4876 if opts.get('all'):
4876 if opts.get('all'):
4877 if rev or node:
4877 if rev or node:
4878 raise error.InputError(_(b"can't specify a revision with --all"))
4878 raise error.InputError(_(b"can't specify a revision with --all"))
4879
4879
4880 res = set()
4880 res = set()
4881 for rev in repo:
4881 for rev in repo:
4882 ctx = repo[rev]
4882 ctx = repo[rev]
4883 res |= set(ctx.files())
4883 res |= set(ctx.files())
4884
4884
4885 ui.pager(b'manifest')
4885 ui.pager(b'manifest')
4886 for f in sorted(res):
4886 for f in sorted(res):
4887 fm.startitem()
4887 fm.startitem()
4888 fm.write(b"path", b'%s\n', f)
4888 fm.write(b"path", b'%s\n', f)
4889 fm.end()
4889 fm.end()
4890 return
4890 return
4891
4891
4892 if rev and node:
4892 if rev and node:
4893 raise error.InputError(_(b"please specify just one revision"))
4893 raise error.InputError(_(b"please specify just one revision"))
4894
4894
4895 if not node:
4895 if not node:
4896 node = rev
4896 node = rev
4897
4897
4898 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4898 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4899 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4899 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4900 if node:
4900 if node:
4901 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4901 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4902 ctx = logcmdutil.revsingle(repo, node)
4902 ctx = logcmdutil.revsingle(repo, node)
4903 mf = ctx.manifest()
4903 mf = ctx.manifest()
4904 ui.pager(b'manifest')
4904 ui.pager(b'manifest')
4905 for f in ctx:
4905 for f in ctx:
4906 fm.startitem()
4906 fm.startitem()
4907 fm.context(ctx=ctx)
4907 fm.context(ctx=ctx)
4908 fl = ctx[f].flags()
4908 fl = ctx[f].flags()
4909 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4909 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4910 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4910 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4911 fm.write(b'path', b'%s\n', f)
4911 fm.write(b'path', b'%s\n', f)
4912 fm.end()
4912 fm.end()
4913
4913
4914
4914
4915 @command(
4915 @command(
4916 b'merge',
4916 b'merge',
4917 [
4917 [
4918 (
4918 (
4919 b'f',
4919 b'f',
4920 b'force',
4920 b'force',
4921 None,
4921 None,
4922 _(b'force a merge including outstanding changes (DEPRECATED)'),
4922 _(b'force a merge including outstanding changes (DEPRECATED)'),
4923 ),
4923 ),
4924 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4924 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4925 (
4925 (
4926 b'P',
4926 b'P',
4927 b'preview',
4927 b'preview',
4928 None,
4928 None,
4929 _(b'review revisions to merge (no merge is performed)'),
4929 _(b'review revisions to merge (no merge is performed)'),
4930 ),
4930 ),
4931 (b'', b'abort', None, _(b'abort the ongoing merge')),
4931 (b'', b'abort', None, _(b'abort the ongoing merge')),
4932 ]
4932 ]
4933 + mergetoolopts,
4933 + mergetoolopts,
4934 _(b'[-P] [[-r] REV]'),
4934 _(b'[-P] [[-r] REV]'),
4935 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4935 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4936 helpbasic=True,
4936 helpbasic=True,
4937 )
4937 )
4938 def merge(ui, repo, node=None, **opts):
4938 def merge(ui, repo, node=None, **opts):
4939 """merge another revision into working directory
4939 """merge another revision into working directory
4940
4940
4941 The current working directory is updated with all changes made in
4941 The current working directory is updated with all changes made in
4942 the requested revision since the last common predecessor revision.
4942 the requested revision since the last common predecessor revision.
4943
4943
4944 Files that changed between either parent are marked as changed for
4944 Files that changed between either parent are marked as changed for
4945 the next commit and a commit must be performed before any further
4945 the next commit and a commit must be performed before any further
4946 updates to the repository are allowed. The next commit will have
4946 updates to the repository are allowed. The next commit will have
4947 two parents.
4947 two parents.
4948
4948
4949 ``--tool`` can be used to specify the merge tool used for file
4949 ``--tool`` can be used to specify the merge tool used for file
4950 merges. It overrides the HGMERGE environment variable and your
4950 merges. It overrides the HGMERGE environment variable and your
4951 configuration files. See :hg:`help merge-tools` for options.
4951 configuration files. See :hg:`help merge-tools` for options.
4952
4952
4953 If no revision is specified, the working directory's parent is a
4953 If no revision is specified, the working directory's parent is a
4954 head revision, and the current branch contains exactly one other
4954 head revision, and the current branch contains exactly one other
4955 head, the other head is merged with by default. Otherwise, an
4955 head, the other head is merged with by default. Otherwise, an
4956 explicit revision with which to merge must be provided.
4956 explicit revision with which to merge must be provided.
4957
4957
4958 See :hg:`help resolve` for information on handling file conflicts.
4958 See :hg:`help resolve` for information on handling file conflicts.
4959
4959
4960 To undo an uncommitted merge, use :hg:`merge --abort` which
4960 To undo an uncommitted merge, use :hg:`merge --abort` which
4961 will check out a clean copy of the original merge parent, losing
4961 will check out a clean copy of the original merge parent, losing
4962 all changes.
4962 all changes.
4963
4963
4964 Returns 0 on success, 1 if there are unresolved files.
4964 Returns 0 on success, 1 if there are unresolved files.
4965 """
4965 """
4966
4966
4967 abort = opts.get('abort')
4967 abort = opts.get('abort')
4968 if abort and repo.dirstate.p2() == repo.nullid:
4968 if abort and repo.dirstate.p2() == repo.nullid:
4969 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4969 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4970 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4970 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4971 if abort:
4971 if abort:
4972 state = cmdutil.getunfinishedstate(repo)
4972 state = cmdutil.getunfinishedstate(repo)
4973 if state and state._opname != b'merge':
4973 if state and state._opname != b'merge':
4974 raise error.StateError(
4974 raise error.StateError(
4975 _(b'cannot abort merge with %s in progress') % (state._opname),
4975 _(b'cannot abort merge with %s in progress') % (state._opname),
4976 hint=state.hint(),
4976 hint=state.hint(),
4977 )
4977 )
4978 if node:
4978 if node:
4979 raise error.InputError(_(b"cannot specify a node with --abort"))
4979 raise error.InputError(_(b"cannot specify a node with --abort"))
4980 return hg.abortmerge(repo.ui, repo)
4980 return hg.abortmerge(repo.ui, repo)
4981
4981
4982 if opts.get('rev') and node:
4982 if opts.get('rev') and node:
4983 raise error.InputError(_(b"please specify just one revision"))
4983 raise error.InputError(_(b"please specify just one revision"))
4984 if not node:
4984 if not node:
4985 node = opts.get('rev')
4985 node = opts.get('rev')
4986
4986
4987 if node:
4987 if node:
4988 ctx = logcmdutil.revsingle(repo, node)
4988 ctx = logcmdutil.revsingle(repo, node)
4989 else:
4989 else:
4990 if ui.configbool(b'commands', b'merge.require-rev'):
4990 if ui.configbool(b'commands', b'merge.require-rev'):
4991 raise error.InputError(
4991 raise error.InputError(
4992 _(
4992 _(
4993 b'configuration requires specifying revision to merge '
4993 b'configuration requires specifying revision to merge '
4994 b'with'
4994 b'with'
4995 )
4995 )
4996 )
4996 )
4997 ctx = repo[destutil.destmerge(repo)]
4997 ctx = repo[destutil.destmerge(repo)]
4998
4998
4999 if ctx.node() is None:
4999 if ctx.node() is None:
5000 raise error.InputError(
5000 raise error.InputError(
5001 _(b'merging with the working copy has no effect')
5001 _(b'merging with the working copy has no effect')
5002 )
5002 )
5003
5003
5004 if opts.get('preview'):
5004 if opts.get('preview'):
5005 # find nodes that are ancestors of p2 but not of p1
5005 # find nodes that are ancestors of p2 but not of p1
5006 p1 = repo[b'.'].node()
5006 p1 = repo[b'.'].node()
5007 p2 = ctx.node()
5007 p2 = ctx.node()
5008 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5008 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5009
5009
5010 displayer = logcmdutil.changesetdisplayer(
5010 displayer = logcmdutil.changesetdisplayer(
5011 ui, repo, pycompat.byteskwargs(opts)
5011 ui, repo, pycompat.byteskwargs(opts)
5012 )
5012 )
5013 for node in nodes:
5013 for node in nodes:
5014 displayer.show(repo[node])
5014 displayer.show(repo[node])
5015 displayer.close()
5015 displayer.close()
5016 return 0
5016 return 0
5017
5017
5018 # ui.forcemerge is an internal variable, do not document
5018 # ui.forcemerge is an internal variable, do not document
5019 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
5019 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
5020 with ui.configoverride(overrides, b'merge'):
5020 with ui.configoverride(overrides, b'merge'):
5021 force = opts.get('force')
5021 force = opts.get('force')
5022 labels = [b'working copy', b'merge rev', b'common ancestor']
5022 labels = [b'working copy', b'merge rev', b'common ancestor']
5023 return hg.merge(ctx, force=force, labels=labels)
5023 return hg.merge(ctx, force=force, labels=labels)
5024
5024
5025
5025
5026 statemod.addunfinished(
5026 statemod.addunfinished(
5027 b'merge',
5027 b'merge',
5028 fname=None,
5028 fname=None,
5029 clearable=True,
5029 clearable=True,
5030 allowcommit=True,
5030 allowcommit=True,
5031 cmdmsg=_(b'outstanding uncommitted merge'),
5031 cmdmsg=_(b'outstanding uncommitted merge'),
5032 abortfunc=hg.abortmerge,
5032 abortfunc=hg.abortmerge,
5033 statushint=_(
5033 statushint=_(
5034 b'To continue: hg commit\nTo abort: hg merge --abort'
5034 b'To continue: hg commit\nTo abort: hg merge --abort'
5035 ),
5035 ),
5036 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
5036 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
5037 )
5037 )
5038
5038
5039
5039
5040 @command(
5040 @command(
5041 b'outgoing|out',
5041 b'outgoing|out',
5042 [
5042 [
5043 (
5043 (
5044 b'f',
5044 b'f',
5045 b'force',
5045 b'force',
5046 None,
5046 None,
5047 _(b'run even when the destination is unrelated'),
5047 _(b'run even when the destination is unrelated'),
5048 ),
5048 ),
5049 (
5049 (
5050 b'r',
5050 b'r',
5051 b'rev',
5051 b'rev',
5052 [],
5052 [],
5053 _(b'a changeset intended to be included in the destination'),
5053 _(b'a changeset intended to be included in the destination'),
5054 _(b'REV'),
5054 _(b'REV'),
5055 ),
5055 ),
5056 (b'n', b'newest-first', None, _(b'show newest record first')),
5056 (b'n', b'newest-first', None, _(b'show newest record first')),
5057 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5057 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5058 (
5058 (
5059 b'b',
5059 b'b',
5060 b'branch',
5060 b'branch',
5061 [],
5061 [],
5062 _(b'a specific branch you would like to push'),
5062 _(b'a specific branch you would like to push'),
5063 _(b'BRANCH'),
5063 _(b'BRANCH'),
5064 ),
5064 ),
5065 ]
5065 ]
5066 + logopts
5066 + logopts
5067 + remoteopts
5067 + remoteopts
5068 + subrepoopts,
5068 + subrepoopts,
5069 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5069 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5070 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5070 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5071 )
5071 )
5072 def outgoing(ui, repo, *dests, **opts):
5072 def outgoing(ui, repo, *dests, **opts):
5073 """show changesets not found in the destination
5073 """show changesets not found in the destination
5074
5074
5075 Show changesets not found in the specified destination repository
5075 Show changesets not found in the specified destination repository
5076 or the default push location. These are the changesets that would
5076 or the default push location. These are the changesets that would
5077 be pushed if a push was requested.
5077 be pushed if a push was requested.
5078
5078
5079 See pull for details of valid destination formats.
5079 See pull for details of valid destination formats.
5080
5080
5081 .. container:: verbose
5081 .. container:: verbose
5082
5082
5083 With -B/--bookmarks, the result of bookmark comparison between
5083 With -B/--bookmarks, the result of bookmark comparison between
5084 local and remote repositories is displayed. With -v/--verbose,
5084 local and remote repositories is displayed. With -v/--verbose,
5085 status is also displayed for each bookmark like below::
5085 status is also displayed for each bookmark like below::
5086
5086
5087 BM1 01234567890a added
5087 BM1 01234567890a added
5088 BM2 deleted
5088 BM2 deleted
5089 BM3 234567890abc advanced
5089 BM3 234567890abc advanced
5090 BM4 34567890abcd diverged
5090 BM4 34567890abcd diverged
5091 BM5 4567890abcde changed
5091 BM5 4567890abcde changed
5092
5092
5093 The action taken when pushing depends on the
5093 The action taken when pushing depends on the
5094 status of each bookmark:
5094 status of each bookmark:
5095
5095
5096 :``added``: push with ``-B`` will create it
5096 :``added``: push with ``-B`` will create it
5097 :``deleted``: push with ``-B`` will delete it
5097 :``deleted``: push with ``-B`` will delete it
5098 :``advanced``: push will update it
5098 :``advanced``: push will update it
5099 :``diverged``: push with ``-B`` will update it
5099 :``diverged``: push with ``-B`` will update it
5100 :``changed``: push with ``-B`` will update it
5100 :``changed``: push with ``-B`` will update it
5101
5101
5102 From the point of view of pushing behavior, bookmarks
5102 From the point of view of pushing behavior, bookmarks
5103 existing only in the remote repository are treated as
5103 existing only in the remote repository are treated as
5104 ``deleted``, even if it is in fact added remotely.
5104 ``deleted``, even if it is in fact added remotely.
5105
5105
5106 Returns 0 if there are outgoing changes, 1 otherwise.
5106 Returns 0 if there are outgoing changes, 1 otherwise.
5107 """
5107 """
5108 opts = pycompat.byteskwargs(opts)
5108 opts = pycompat.byteskwargs(opts)
5109 if opts.get(b'bookmarks'):
5109 if opts.get(b'bookmarks'):
5110 for path in urlutil.get_push_paths(repo, ui, dests):
5110 for path in urlutil.get_push_paths(repo, ui, dests):
5111 other = hg.peer(repo, opts, path)
5111 other = hg.peer(repo, opts, path)
5112 try:
5112 try:
5113 if b'bookmarks' not in other.listkeys(b'namespaces'):
5113 if b'bookmarks' not in other.listkeys(b'namespaces'):
5114 ui.warn(_(b"remote doesn't support bookmarks\n"))
5114 ui.warn(_(b"remote doesn't support bookmarks\n"))
5115 return 0
5115 return 0
5116 ui.status(
5116 ui.status(
5117 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5117 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5118 )
5118 )
5119 ui.pager(b'outgoing')
5119 ui.pager(b'outgoing')
5120 return bookmarks.outgoing(ui, repo, other)
5120 return bookmarks.outgoing(ui, repo, other)
5121 finally:
5121 finally:
5122 other.close()
5122 other.close()
5123
5123
5124 return hg.outgoing(ui, repo, dests, opts)
5124 return hg.outgoing(ui, repo, dests, opts)
5125
5125
5126
5126
5127 @command(
5127 @command(
5128 b'parents',
5128 b'parents',
5129 [
5129 [
5130 (
5130 (
5131 b'r',
5131 b'r',
5132 b'rev',
5132 b'rev',
5133 b'',
5133 b'',
5134 _(b'show parents of the specified revision'),
5134 _(b'show parents of the specified revision'),
5135 _(b'REV'),
5135 _(b'REV'),
5136 ),
5136 ),
5137 ]
5137 ]
5138 + templateopts,
5138 + templateopts,
5139 _(b'[-r REV] [FILE]'),
5139 _(b'[-r REV] [FILE]'),
5140 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5140 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5141 inferrepo=True,
5141 inferrepo=True,
5142 )
5142 )
5143 def parents(ui, repo, file_=None, **opts):
5143 def parents(ui, repo, file_=None, **opts):
5144 """show the parents of the working directory or revision (DEPRECATED)
5144 """show the parents of the working directory or revision (DEPRECATED)
5145
5145
5146 Print the working directory's parent revisions. If a revision is
5146 Print the working directory's parent revisions. If a revision is
5147 given via -r/--rev, the parent of that revision will be printed.
5147 given via -r/--rev, the parent of that revision will be printed.
5148 If a file argument is given, the revision in which the file was
5148 If a file argument is given, the revision in which the file was
5149 last changed (before the working directory revision or the
5149 last changed (before the working directory revision or the
5150 argument to --rev if given) is printed.
5150 argument to --rev if given) is printed.
5151
5151
5152 This command is equivalent to::
5152 This command is equivalent to::
5153
5153
5154 hg log -r "p1()+p2()" or
5154 hg log -r "p1()+p2()" or
5155 hg log -r "p1(REV)+p2(REV)" or
5155 hg log -r "p1(REV)+p2(REV)" or
5156 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5156 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5157 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5157 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5158
5158
5159 See :hg:`summary` and :hg:`help revsets` for related information.
5159 See :hg:`summary` and :hg:`help revsets` for related information.
5160
5160
5161 Returns 0 on success.
5161 Returns 0 on success.
5162 """
5162 """
5163
5163
5164 opts = pycompat.byteskwargs(opts)
5164 opts = pycompat.byteskwargs(opts)
5165 rev = opts.get(b'rev')
5165 rev = opts.get(b'rev')
5166 if rev:
5166 if rev:
5167 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5167 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5168 ctx = logcmdutil.revsingle(repo, rev, None)
5168 ctx = logcmdutil.revsingle(repo, rev, None)
5169
5169
5170 if file_:
5170 if file_:
5171 m = scmutil.match(ctx, (file_,), opts)
5171 m = scmutil.match(ctx, (file_,), opts)
5172 if m.anypats() or len(m.files()) != 1:
5172 if m.anypats() or len(m.files()) != 1:
5173 raise error.InputError(_(b'can only specify an explicit filename'))
5173 raise error.InputError(_(b'can only specify an explicit filename'))
5174 file_ = m.files()[0]
5174 file_ = m.files()[0]
5175 filenodes = []
5175 filenodes = []
5176 for cp in ctx.parents():
5176 for cp in ctx.parents():
5177 if not cp:
5177 if not cp:
5178 continue
5178 continue
5179 try:
5179 try:
5180 filenodes.append(cp.filenode(file_))
5180 filenodes.append(cp.filenode(file_))
5181 except error.LookupError:
5181 except error.LookupError:
5182 pass
5182 pass
5183 if not filenodes:
5183 if not filenodes:
5184 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5184 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5185 p = []
5185 p = []
5186 for fn in filenodes:
5186 for fn in filenodes:
5187 fctx = repo.filectx(file_, fileid=fn)
5187 fctx = repo.filectx(file_, fileid=fn)
5188 p.append(fctx.node())
5188 p.append(fctx.node())
5189 else:
5189 else:
5190 p = [cp.node() for cp in ctx.parents()]
5190 p = [cp.node() for cp in ctx.parents()]
5191
5191
5192 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5192 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5193 for n in p:
5193 for n in p:
5194 if n != repo.nullid:
5194 if n != repo.nullid:
5195 displayer.show(repo[n])
5195 displayer.show(repo[n])
5196 displayer.close()
5196 displayer.close()
5197
5197
5198
5198
5199 @command(
5199 @command(
5200 b'paths',
5200 b'paths',
5201 formatteropts,
5201 formatteropts,
5202 _(b'[NAME]'),
5202 _(b'[NAME]'),
5203 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5203 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5204 optionalrepo=True,
5204 optionalrepo=True,
5205 intents={INTENT_READONLY},
5205 intents={INTENT_READONLY},
5206 )
5206 )
5207 def paths(ui, repo, search=None, **opts):
5207 def paths(ui, repo, search=None, **opts):
5208 """show aliases for remote repositories
5208 """show aliases for remote repositories
5209
5209
5210 Show definition of symbolic path name NAME. If no name is given,
5210 Show definition of symbolic path name NAME. If no name is given,
5211 show definition of all available names.
5211 show definition of all available names.
5212
5212
5213 Option -q/--quiet suppresses all output when searching for NAME
5213 Option -q/--quiet suppresses all output when searching for NAME
5214 and shows only the path names when listing all definitions.
5214 and shows only the path names when listing all definitions.
5215
5215
5216 Path names are defined in the [paths] section of your
5216 Path names are defined in the [paths] section of your
5217 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5217 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5218 repository, ``.hg/hgrc`` is used, too.
5218 repository, ``.hg/hgrc`` is used, too.
5219
5219
5220 The path names ``default`` and ``default-push`` have a special
5220 The path names ``default`` and ``default-push`` have a special
5221 meaning. When performing a push or pull operation, they are used
5221 meaning. When performing a push or pull operation, they are used
5222 as fallbacks if no location is specified on the command-line.
5222 as fallbacks if no location is specified on the command-line.
5223 When ``default-push`` is set, it will be used for push and
5223 When ``default-push`` is set, it will be used for push and
5224 ``default`` will be used for pull; otherwise ``default`` is used
5224 ``default`` will be used for pull; otherwise ``default`` is used
5225 as the fallback for both. When cloning a repository, the clone
5225 as the fallback for both. When cloning a repository, the clone
5226 source is written as ``default`` in ``.hg/hgrc``.
5226 source is written as ``default`` in ``.hg/hgrc``.
5227
5227
5228 .. note::
5228 .. note::
5229
5229
5230 ``default`` and ``default-push`` apply to all inbound (e.g.
5230 ``default`` and ``default-push`` apply to all inbound (e.g.
5231 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5231 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5232 and :hg:`bundle`) operations.
5232 and :hg:`bundle`) operations.
5233
5233
5234 See :hg:`help urls` for more information.
5234 See :hg:`help urls` for more information.
5235
5235
5236 .. container:: verbose
5236 .. container:: verbose
5237
5237
5238 Template:
5238 Template:
5239
5239
5240 The following keywords are supported. See also :hg:`help templates`.
5240 The following keywords are supported. See also :hg:`help templates`.
5241
5241
5242 :name: String. Symbolic name of the path alias.
5242 :name: String. Symbolic name of the path alias.
5243 :pushurl: String. URL for push operations.
5243 :pushurl: String. URL for push operations.
5244 :url: String. URL or directory path for the other operations.
5244 :url: String. URL or directory path for the other operations.
5245
5245
5246 Returns 0 on success.
5246 Returns 0 on success.
5247 """
5247 """
5248
5248
5249 pathitems = urlutil.list_paths(ui, search)
5249 pathitems = urlutil.list_paths(ui, search)
5250 ui.pager(b'paths')
5250 ui.pager(b'paths')
5251
5251
5252 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5252 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5253 if fm.isplain():
5253 if fm.isplain():
5254 hidepassword = urlutil.hidepassword
5254 hidepassword = urlutil.hidepassword
5255 else:
5255 else:
5256 hidepassword = bytes
5256 hidepassword = bytes
5257 if ui.quiet:
5257 if ui.quiet:
5258 namefmt = b'%s\n'
5258 namefmt = b'%s\n'
5259 else:
5259 else:
5260 namefmt = b'%s = '
5260 namefmt = b'%s = '
5261 showsubopts = not search and not ui.quiet
5261 showsubopts = not search and not ui.quiet
5262
5262
5263 for name, path in pathitems:
5263 for name, path in pathitems:
5264 fm.startitem()
5264 fm.startitem()
5265 fm.condwrite(not search, b'name', namefmt, name)
5265 fm.condwrite(not search, b'name', namefmt, name)
5266 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5266 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5267 for subopt, value in sorted(path.suboptions.items()):
5267 for subopt, value in sorted(path.suboptions.items()):
5268 assert subopt not in (b'name', b'url')
5268 assert subopt not in (b'name', b'url')
5269 if showsubopts:
5269 if showsubopts:
5270 fm.plain(b'%s:%s = ' % (name, subopt))
5270 fm.plain(b'%s:%s = ' % (name, subopt))
5271 display = urlutil.path_suboptions_display[subopt]
5271 display = urlutil.path_suboptions_display[subopt]
5272 value = display(value)
5272 value = display(value)
5273 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5273 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5274
5274
5275 fm.end()
5275 fm.end()
5276
5276
5277 if search and not pathitems:
5277 if search and not pathitems:
5278 if not ui.quiet:
5278 if not ui.quiet:
5279 ui.warn(_(b"not found!\n"))
5279 ui.warn(_(b"not found!\n"))
5280 return 1
5280 return 1
5281 else:
5281 else:
5282 return 0
5282 return 0
5283
5283
5284
5284
5285 @command(
5285 @command(
5286 b'phase',
5286 b'phase',
5287 [
5287 [
5288 (b'p', b'public', False, _(b'set changeset phase to public')),
5288 (b'p', b'public', False, _(b'set changeset phase to public')),
5289 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5289 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5290 (b's', b'secret', False, _(b'set changeset phase to secret')),
5290 (b's', b'secret', False, _(b'set changeset phase to secret')),
5291 (b'f', b'force', False, _(b'allow to move boundary backward')),
5291 (b'f', b'force', False, _(b'allow to move boundary backward')),
5292 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5292 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5293 ],
5293 ],
5294 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5294 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5295 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5295 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5296 )
5296 )
5297 def phase(ui, repo, *revs, **opts):
5297 def phase(ui, repo, *revs, **opts):
5298 """set or show the current phase name
5298 """set or show the current phase name
5299
5299
5300 With no argument, show the phase name of the current revision(s).
5300 With no argument, show the phase name of the current revision(s).
5301
5301
5302 With one of -p/--public, -d/--draft or -s/--secret, change the
5302 With one of -p/--public, -d/--draft or -s/--secret, change the
5303 phase value of the specified revisions.
5303 phase value of the specified revisions.
5304
5304
5305 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5305 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5306 lower phase to a higher phase. Phases are ordered as follows::
5306 lower phase to a higher phase. Phases are ordered as follows::
5307
5307
5308 public < draft < secret
5308 public < draft < secret
5309
5309
5310 Returns 0 on success, 1 if some phases could not be changed.
5310 Returns 0 on success, 1 if some phases could not be changed.
5311
5311
5312 (For more information about the phases concept, see :hg:`help phases`.)
5312 (For more information about the phases concept, see :hg:`help phases`.)
5313 """
5313 """
5314 opts = pycompat.byteskwargs(opts)
5314 opts = pycompat.byteskwargs(opts)
5315 # search for a unique phase argument
5315 # search for a unique phase argument
5316 targetphase = None
5316 targetphase = None
5317 for idx, name in enumerate(phases.cmdphasenames):
5317 for idx, name in enumerate(phases.cmdphasenames):
5318 if opts[name]:
5318 if opts[name]:
5319 if targetphase is not None:
5319 if targetphase is not None:
5320 raise error.InputError(_(b'only one phase can be specified'))
5320 raise error.InputError(_(b'only one phase can be specified'))
5321 targetphase = idx
5321 targetphase = idx
5322
5322
5323 # look for specified revision
5323 # look for specified revision
5324 revs = list(revs)
5324 revs = list(revs)
5325 revs.extend(opts[b'rev'])
5325 revs.extend(opts[b'rev'])
5326 if revs:
5326 if revs:
5327 revs = logcmdutil.revrange(repo, revs)
5327 revs = logcmdutil.revrange(repo, revs)
5328 else:
5328 else:
5329 # display both parents as the second parent phase can influence
5329 # display both parents as the second parent phase can influence
5330 # the phase of a merge commit
5330 # the phase of a merge commit
5331 revs = [c.rev() for c in repo[None].parents()]
5331 revs = [c.rev() for c in repo[None].parents()]
5332
5332
5333 ret = 0
5333 ret = 0
5334 if targetphase is None:
5334 if targetphase is None:
5335 # display
5335 # display
5336 for r in revs:
5336 for r in revs:
5337 ctx = repo[r]
5337 ctx = repo[r]
5338 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5338 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5339 else:
5339 else:
5340 with repo.lock(), repo.transaction(b"phase") as tr:
5340 with repo.lock(), repo.transaction(b"phase") as tr:
5341 # set phase
5341 # set phase
5342 if not revs:
5342 if not revs:
5343 raise error.InputError(_(b'empty revision set'))
5343 raise error.InputError(_(b'empty revision set'))
5344 nodes = [repo[r].node() for r in revs]
5344 nodes = [repo[r].node() for r in revs]
5345 # moving revision from public to draft may hide them
5345 # moving revision from public to draft may hide them
5346 # We have to check result on an unfiltered repository
5346 # We have to check result on an unfiltered repository
5347 unfi = repo.unfiltered()
5347 unfi = repo.unfiltered()
5348 getphase = unfi._phasecache.phase
5348 getphase = unfi._phasecache.phase
5349 olddata = [getphase(unfi, r) for r in unfi]
5349 olddata = [getphase(unfi, r) for r in unfi]
5350 phases.advanceboundary(repo, tr, targetphase, nodes)
5350 phases.advanceboundary(repo, tr, targetphase, nodes)
5351 if opts[b'force']:
5351 if opts[b'force']:
5352 phases.retractboundary(repo, tr, targetphase, nodes)
5352 phases.retractboundary(repo, tr, targetphase, nodes)
5353 getphase = unfi._phasecache.phase
5353 getphase = unfi._phasecache.phase
5354 newdata = [getphase(unfi, r) for r in unfi]
5354 newdata = [getphase(unfi, r) for r in unfi]
5355 changes = sum(newdata[r] != olddata[r] for r in unfi)
5355 changes = sum(newdata[r] != olddata[r] for r in unfi)
5356 cl = unfi.changelog
5356 cl = unfi.changelog
5357 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5357 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5358 if rejected:
5358 if rejected:
5359 ui.warn(
5359 ui.warn(
5360 _(
5360 _(
5361 b'cannot move %i changesets to a higher '
5361 b'cannot move %i changesets to a higher '
5362 b'phase, use --force\n'
5362 b'phase, use --force\n'
5363 )
5363 )
5364 % len(rejected)
5364 % len(rejected)
5365 )
5365 )
5366 ret = 1
5366 ret = 1
5367 if changes:
5367 if changes:
5368 msg = _(b'phase changed for %i changesets\n') % changes
5368 msg = _(b'phase changed for %i changesets\n') % changes
5369 if ret:
5369 if ret:
5370 ui.status(msg)
5370 ui.status(msg)
5371 else:
5371 else:
5372 ui.note(msg)
5372 ui.note(msg)
5373 else:
5373 else:
5374 ui.warn(_(b'no phases changed\n'))
5374 ui.warn(_(b'no phases changed\n'))
5375 return ret
5375 return ret
5376
5376
5377
5377
5378 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5378 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5379 """Run after a changegroup has been added via pull/unbundle
5379 """Run after a changegroup has been added via pull/unbundle
5380
5380
5381 This takes arguments below:
5381 This takes arguments below:
5382
5382
5383 :modheads: change of heads by pull/unbundle
5383 :modheads: change of heads by pull/unbundle
5384 :optupdate: updating working directory is needed or not
5384 :optupdate: updating working directory is needed or not
5385 :checkout: update destination revision (or None to default destination)
5385 :checkout: update destination revision (or None to default destination)
5386 :brev: a name, which might be a bookmark to be activated after updating
5386 :brev: a name, which might be a bookmark to be activated after updating
5387
5387
5388 return True if update raise any conflict, False otherwise.
5388 return True if update raise any conflict, False otherwise.
5389 """
5389 """
5390 if modheads == 0:
5390 if modheads == 0:
5391 return False
5391 return False
5392 if optupdate:
5392 if optupdate:
5393 try:
5393 try:
5394 return hg.updatetotally(ui, repo, checkout, brev)
5394 return hg.updatetotally(ui, repo, checkout, brev)
5395 except error.UpdateAbort as inst:
5395 except error.UpdateAbort as inst:
5396 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5396 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5397 hint = inst.hint
5397 hint = inst.hint
5398 raise error.UpdateAbort(msg, hint=hint)
5398 raise error.UpdateAbort(msg, hint=hint)
5399 if modheads is not None and modheads > 1:
5399 if modheads is not None and modheads > 1:
5400 currentbranchheads = len(repo.branchheads())
5400 currentbranchheads = len(repo.branchheads())
5401 if currentbranchheads == modheads:
5401 if currentbranchheads == modheads:
5402 ui.status(
5402 ui.status(
5403 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5403 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5404 )
5404 )
5405 elif currentbranchheads > 1:
5405 elif currentbranchheads > 1:
5406 ui.status(
5406 ui.status(
5407 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5407 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5408 )
5408 )
5409 else:
5409 else:
5410 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5410 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5411 elif not ui.configbool(b'commands', b'update.requiredest'):
5411 elif not ui.configbool(b'commands', b'update.requiredest'):
5412 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5412 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5413 return False
5413 return False
5414
5414
5415
5415
5416 @command(
5416 @command(
5417 b'pull',
5417 b'pull',
5418 [
5418 [
5419 (
5419 (
5420 b'u',
5420 b'u',
5421 b'update',
5421 b'update',
5422 None,
5422 None,
5423 _(b'update to new branch head if new descendants were pulled'),
5423 _(b'update to new branch head if new descendants were pulled'),
5424 ),
5424 ),
5425 (
5425 (
5426 b'f',
5426 b'f',
5427 b'force',
5427 b'force',
5428 None,
5428 None,
5429 _(b'run even when remote repository is unrelated'),
5429 _(b'run even when remote repository is unrelated'),
5430 ),
5430 ),
5431 (
5431 (
5432 b'',
5432 b'',
5433 b'confirm',
5433 b'confirm',
5434 None,
5434 None,
5435 _(b'confirm pull before applying changes'),
5435 _(b'confirm pull before applying changes'),
5436 ),
5436 ),
5437 (
5437 (
5438 b'r',
5438 b'r',
5439 b'rev',
5439 b'rev',
5440 [],
5440 [],
5441 _(b'a remote changeset intended to be added'),
5441 _(b'a remote changeset intended to be added'),
5442 _(b'REV'),
5442 _(b'REV'),
5443 ),
5443 ),
5444 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5444 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5445 (
5445 (
5446 b'b',
5446 b'b',
5447 b'branch',
5447 b'branch',
5448 [],
5448 [],
5449 _(b'a specific branch you would like to pull'),
5449 _(b'a specific branch you would like to pull'),
5450 _(b'BRANCH'),
5450 _(b'BRANCH'),
5451 ),
5451 ),
5452 (
5452 (
5453 b'',
5453 b'',
5454 b'remote-hidden',
5454 b'remote-hidden',
5455 False,
5455 False,
5456 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5456 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5457 ),
5457 ),
5458 ]
5458 ]
5459 + remoteopts,
5459 + remoteopts,
5460 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5460 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5461 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5461 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5462 helpbasic=True,
5462 helpbasic=True,
5463 )
5463 )
5464 def pull(ui, repo, *sources, **opts):
5464 def pull(ui, repo, *sources, **opts):
5465 """pull changes from the specified source
5465 """pull changes from the specified source
5466
5466
5467 Pull changes from a remote repository to a local one.
5467 Pull changes from a remote repository to a local one.
5468
5468
5469 This finds all changes from the repository at the specified path
5469 This finds all changes from the repository at the specified path
5470 or URL and adds them to a local repository (the current one unless
5470 or URL and adds them to a local repository (the current one unless
5471 -R is specified). By default, this does not update the copy of the
5471 -R is specified). By default, this does not update the copy of the
5472 project in the working directory.
5472 project in the working directory.
5473
5473
5474 When cloning from servers that support it, Mercurial may fetch
5474 When cloning from servers that support it, Mercurial may fetch
5475 pre-generated data. When this is done, hooks operating on incoming
5475 pre-generated data. When this is done, hooks operating on incoming
5476 changesets and changegroups may fire more than once, once for each
5476 changesets and changegroups may fire more than once, once for each
5477 pre-generated bundle and as well as for any additional remaining
5477 pre-generated bundle and as well as for any additional remaining
5478 data. See :hg:`help -e clonebundles` for more.
5478 data. See :hg:`help -e clonebundles` for more.
5479
5479
5480 Use :hg:`incoming` if you want to see what would have been added
5480 Use :hg:`incoming` if you want to see what would have been added
5481 by a pull at the time you issued this command. If you then decide
5481 by a pull at the time you issued this command. If you then decide
5482 to add those changes to the repository, you should use :hg:`pull
5482 to add those changes to the repository, you should use :hg:`pull
5483 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5483 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5484
5484
5485 If SOURCE is omitted, the 'default' path will be used.
5485 If SOURCE is omitted, the 'default' path will be used.
5486 See :hg:`help urls` for more information.
5486 See :hg:`help urls` for more information.
5487
5487
5488 If multiple sources are specified, they will be pulled sequentially as if
5488 If multiple sources are specified, they will be pulled sequentially as if
5489 the command was run multiple time. If --update is specify and the command
5489 the command was run multiple time. If --update is specify and the command
5490 will stop at the first failed --update.
5490 will stop at the first failed --update.
5491
5491
5492 Specifying bookmark as ``.`` is equivalent to specifying the active
5492 Specifying bookmark as ``.`` is equivalent to specifying the active
5493 bookmark's name.
5493 bookmark's name.
5494
5494
5495 .. container:: verbose
5495 .. container:: verbose
5496
5496
5497 One can use the `--remote-hidden` flag to pull changesets
5497 One can use the `--remote-hidden` flag to pull changesets
5498 hidden on the remote. This flag is "best effort", and will only
5498 hidden on the remote. This flag is "best effort", and will only
5499 work if the server supports the feature and is configured to
5499 work if the server supports the feature and is configured to
5500 allow the user to access hidden changesets. This option is
5500 allow the user to access hidden changesets. This option is
5501 experimental and backwards compatibility is not garanteed.
5501 experimental and backwards compatibility is not garanteed.
5502
5502
5503 Returns 0 on success, 1 if an update had unresolved files.
5503 Returns 0 on success, 1 if an update had unresolved files.
5504 """
5504 """
5505
5505
5506 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5506 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5507 msg = _(b'update destination required by configuration')
5507 msg = _(b'update destination required by configuration')
5508 hint = _(b'use hg pull followed by hg update DEST')
5508 hint = _(b'use hg pull followed by hg update DEST')
5509 raise error.InputError(msg, hint=hint)
5509 raise error.InputError(msg, hint=hint)
5510
5510
5511 update_conflict = None
5511 update_conflict = None
5512
5512
5513 for path in urlutil.get_pull_paths(repo, ui, sources):
5513 for path in urlutil.get_pull_paths(repo, ui, sources):
5514 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5514 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5515 ui.flush()
5515 ui.flush()
5516 other = hg.peer(
5516 other = hg.peer(
5517 repo,
5517 repo,
5518 pycompat.byteskwargs(opts),
5518 pycompat.byteskwargs(opts),
5519 path,
5519 path,
5520 remotehidden=opts['remote_hidden'],
5520 remotehidden=opts['remote_hidden'],
5521 )
5521 )
5522 update_conflict = None
5522 update_conflict = None
5523 try:
5523 try:
5524 branches = (path.branch, opts.get('branch', []))
5524 branches = (path.branch, opts.get('branch', []))
5525 revs, checkout = hg.addbranchrevs(
5525 revs, checkout = hg.addbranchrevs(
5526 repo,
5526 repo,
5527 other,
5527 other,
5528 branches,
5528 branches,
5529 opts.get('rev'),
5529 opts.get('rev'),
5530 remotehidden=opts['remote_hidden'],
5530 remotehidden=opts['remote_hidden'],
5531 )
5531 )
5532
5532
5533 pullopargs = {}
5533 pullopargs = {}
5534
5534
5535 nodes = None
5535 nodes = None
5536 if opts.get('bookmark') or revs:
5536 if opts.get('bookmark') or revs:
5537 # The list of bookmark used here is the same used to actually update
5537 # The list of bookmark used here is the same used to actually update
5538 # the bookmark names, to avoid the race from issue 4689 and we do
5538 # the bookmark names, to avoid the race from issue 4689 and we do
5539 # all lookup and bookmark queries in one go so they see the same
5539 # all lookup and bookmark queries in one go so they see the same
5540 # version of the server state (issue 4700).
5540 # version of the server state (issue 4700).
5541 nodes = []
5541 nodes = []
5542 fnodes = []
5542 fnodes = []
5543 revs = revs or []
5543 revs = revs or []
5544 if revs and not other.capable(b'lookup'):
5544 if revs and not other.capable(b'lookup'):
5545 err = _(
5545 err = _(
5546 b"other repository doesn't support revision lookup, "
5546 b"other repository doesn't support revision lookup, "
5547 b"so a rev cannot be specified."
5547 b"so a rev cannot be specified."
5548 )
5548 )
5549 raise error.Abort(err)
5549 raise error.Abort(err)
5550 with other.commandexecutor() as e:
5550 with other.commandexecutor() as e:
5551 fremotebookmarks = e.callcommand(
5551 fremotebookmarks = e.callcommand(
5552 b'listkeys', {b'namespace': b'bookmarks'}
5552 b'listkeys', {b'namespace': b'bookmarks'}
5553 )
5553 )
5554 for r in revs:
5554 for r in revs:
5555 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5555 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5556 remotebookmarks = fremotebookmarks.result()
5556 remotebookmarks = fremotebookmarks.result()
5557 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5557 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5558 pullopargs[b'remotebookmarks'] = remotebookmarks
5558 pullopargs[b'remotebookmarks'] = remotebookmarks
5559 for b in opts.get('bookmark', []):
5559 for b in opts.get('bookmark', []):
5560 b = repo._bookmarks.expandname(b)
5560 b = repo._bookmarks.expandname(b)
5561 if b not in remotebookmarks:
5561 if b not in remotebookmarks:
5562 raise error.InputError(
5562 raise error.InputError(
5563 _(b'remote bookmark %s not found!') % b
5563 _(b'remote bookmark %s not found!') % b
5564 )
5564 )
5565 nodes.append(remotebookmarks[b])
5565 nodes.append(remotebookmarks[b])
5566 for i, rev in enumerate(revs):
5566 for i, rev in enumerate(revs):
5567 node = fnodes[i].result()
5567 node = fnodes[i].result()
5568 nodes.append(node)
5568 nodes.append(node)
5569 if rev == checkout:
5569 if rev == checkout:
5570 checkout = node
5570 checkout = node
5571
5571
5572 wlock = util.nullcontextmanager()
5572 wlock = util.nullcontextmanager()
5573 if opts.get('update'):
5573 if opts.get('update'):
5574 wlock = repo.wlock()
5574 wlock = repo.wlock()
5575 with wlock:
5575 with wlock:
5576 pullopargs.update(opts.get('opargs', {}))
5576 pullopargs.update(opts.get('opargs', {}))
5577 modheads = exchange.pull(
5577 modheads = exchange.pull(
5578 repo,
5578 repo,
5579 other,
5579 other,
5580 path=path,
5580 path=path,
5581 heads=nodes,
5581 heads=nodes,
5582 force=opts.get('force'),
5582 force=opts.get('force'),
5583 bookmarks=opts.get('bookmark', ()),
5583 bookmarks=opts.get('bookmark', ()),
5584 opargs=pullopargs,
5584 opargs=pullopargs,
5585 confirm=opts.get('confirm'),
5585 confirm=opts.get('confirm'),
5586 ).cgresult
5586 ).cgresult
5587
5587
5588 # brev is a name, which might be a bookmark to be activated at
5588 # brev is a name, which might be a bookmark to be activated at
5589 # the end of the update. In other words, it is an explicit
5589 # the end of the update. In other words, it is an explicit
5590 # destination of the update
5590 # destination of the update
5591 brev = None
5591 brev = None
5592
5592
5593 if checkout:
5593 if checkout:
5594 checkout = repo.unfiltered().changelog.rev(checkout)
5594 checkout = repo.unfiltered().changelog.rev(checkout)
5595
5595
5596 # order below depends on implementation of
5596 # order below depends on implementation of
5597 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5597 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5598 # because 'checkout' is determined without it.
5598 # because 'checkout' is determined without it.
5599 if opts.get('rev'):
5599 if opts.get('rev'):
5600 brev = opts['rev'][0]
5600 brev = opts['rev'][0]
5601 elif opts.get('branch'):
5601 elif opts.get('branch'):
5602 brev = opts['branch'][0]
5602 brev = opts['branch'][0]
5603 else:
5603 else:
5604 brev = path.branch
5604 brev = path.branch
5605
5605
5606 # XXX path: we are losing the `path` object here. Keeping it
5606 # XXX path: we are losing the `path` object here. Keeping it
5607 # would be valuable. For example as a "variant" as we do
5607 # would be valuable. For example as a "variant" as we do
5608 # for pushes.
5608 # for pushes.
5609 repo._subtoppath = path.loc
5609 repo._subtoppath = path.loc
5610 try:
5610 try:
5611 update_conflict = postincoming(
5611 update_conflict = postincoming(
5612 ui, repo, modheads, opts.get('update'), checkout, brev
5612 ui, repo, modheads, opts.get('update'), checkout, brev
5613 )
5613 )
5614 except error.FilteredRepoLookupError as exc:
5614 except error.FilteredRepoLookupError as exc:
5615 msg = _(b'cannot update to target: %s') % exc.args[0]
5615 msg = _(b'cannot update to target: %s') % exc.args[0]
5616 exc.args = (msg,) + exc.args[1:]
5616 exc.args = (msg,) + exc.args[1:]
5617 raise
5617 raise
5618 finally:
5618 finally:
5619 del repo._subtoppath
5619 del repo._subtoppath
5620
5620
5621 finally:
5621 finally:
5622 other.close()
5622 other.close()
5623 # skip the remaining pull source if they are some conflict.
5623 # skip the remaining pull source if they are some conflict.
5624 if update_conflict:
5624 if update_conflict:
5625 break
5625 break
5626 if update_conflict:
5626 if update_conflict:
5627 return 1
5627 return 1
5628 else:
5628 else:
5629 return 0
5629 return 0
5630
5630
5631
5631
5632 @command(
5632 @command(
5633 b'purge|clean',
5633 b'purge|clean',
5634 [
5634 [
5635 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5635 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5636 (b'', b'all', None, _(b'purge ignored files too')),
5636 (b'', b'all', None, _(b'purge ignored files too')),
5637 (b'i', b'ignored', None, _(b'purge only ignored files')),
5637 (b'i', b'ignored', None, _(b'purge only ignored files')),
5638 (b'', b'dirs', None, _(b'purge empty directories')),
5638 (b'', b'dirs', None, _(b'purge empty directories')),
5639 (b'', b'files', None, _(b'purge files')),
5639 (b'', b'files', None, _(b'purge files')),
5640 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5640 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5641 (
5641 (
5642 b'0',
5642 b'0',
5643 b'print0',
5643 b'print0',
5644 None,
5644 None,
5645 _(
5645 _(
5646 b'end filenames with NUL, for use with xargs'
5646 b'end filenames with NUL, for use with xargs'
5647 b' (implies -p/--print)'
5647 b' (implies -p/--print)'
5648 ),
5648 ),
5649 ),
5649 ),
5650 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5650 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5651 ]
5651 ]
5652 + cmdutil.walkopts,
5652 + cmdutil.walkopts,
5653 _(b'hg purge [OPTION]... [DIR]...'),
5653 _(b'hg purge [OPTION]... [DIR]...'),
5654 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5654 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5655 )
5655 )
5656 def purge(ui, repo, *dirs, **opts):
5656 def purge(ui, repo, *dirs, **opts):
5657 """removes files not tracked by Mercurial
5657 """removes files not tracked by Mercurial
5658
5658
5659 Delete files not known to Mercurial. This is useful to test local
5659 Delete files not known to Mercurial. This is useful to test local
5660 and uncommitted changes in an otherwise-clean source tree.
5660 and uncommitted changes in an otherwise-clean source tree.
5661
5661
5662 This means that purge will delete the following by default:
5662 This means that purge will delete the following by default:
5663
5663
5664 - Unknown files: files marked with "?" by :hg:`status`
5664 - Unknown files: files marked with "?" by :hg:`status`
5665 - Empty directories: in fact Mercurial ignores directories unless
5665 - Empty directories: in fact Mercurial ignores directories unless
5666 they contain files under source control management
5666 they contain files under source control management
5667
5667
5668 But it will leave untouched:
5668 But it will leave untouched:
5669
5669
5670 - Modified and unmodified tracked files
5670 - Modified and unmodified tracked files
5671 - Ignored files (unless -i or --all is specified)
5671 - Ignored files (unless -i or --all is specified)
5672 - New files added to the repository (with :hg:`add`)
5672 - New files added to the repository (with :hg:`add`)
5673
5673
5674 The --files and --dirs options can be used to direct purge to delete
5674 The --files and --dirs options can be used to direct purge to delete
5675 only files, only directories, or both. If neither option is given,
5675 only files, only directories, or both. If neither option is given,
5676 both will be deleted.
5676 both will be deleted.
5677
5677
5678 If directories are given on the command line, only files in these
5678 If directories are given on the command line, only files in these
5679 directories are considered.
5679 directories are considered.
5680
5680
5681 Be careful with purge, as you could irreversibly delete some files
5681 Be careful with purge, as you could irreversibly delete some files
5682 you forgot to add to the repository. If you only want to print the
5682 you forgot to add to the repository. If you only want to print the
5683 list of files that this program would delete, use the --print
5683 list of files that this program would delete, use the --print
5684 option.
5684 option.
5685 """
5685 """
5686 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5686 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5687
5687
5688 act = not opts.get('print')
5688 act = not opts.get('print')
5689 eol = b'\n'
5689 eol = b'\n'
5690 if opts.get('print0'):
5690 if opts.get('print0'):
5691 eol = b'\0'
5691 eol = b'\0'
5692 act = False # --print0 implies --print
5692 act = False # --print0 implies --print
5693 if opts.get('all', False):
5693 if opts.get('all', False):
5694 ignored = True
5694 ignored = True
5695 unknown = True
5695 unknown = True
5696 else:
5696 else:
5697 ignored = opts.get('ignored', False)
5697 ignored = opts.get('ignored', False)
5698 unknown = not ignored
5698 unknown = not ignored
5699
5699
5700 removefiles = opts.get('files')
5700 removefiles = opts.get('files')
5701 removedirs = opts.get('dirs')
5701 removedirs = opts.get('dirs')
5702 confirm = opts.get('confirm')
5702 confirm = opts.get('confirm')
5703 if confirm is None:
5703 if confirm is None:
5704 try:
5704 try:
5705 extensions.find(b'purge')
5705 extensions.find(b'purge')
5706 confirm = False
5706 confirm = False
5707 except KeyError:
5707 except KeyError:
5708 confirm = True
5708 confirm = True
5709
5709
5710 if not removefiles and not removedirs:
5710 if not removefiles and not removedirs:
5711 removefiles = True
5711 removefiles = True
5712 removedirs = True
5712 removedirs = True
5713
5713
5714 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5714 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5715
5715
5716 paths = mergemod.purge(
5716 paths = mergemod.purge(
5717 repo,
5717 repo,
5718 match,
5718 match,
5719 unknown=unknown,
5719 unknown=unknown,
5720 ignored=ignored,
5720 ignored=ignored,
5721 removeemptydirs=removedirs,
5721 removeemptydirs=removedirs,
5722 removefiles=removefiles,
5722 removefiles=removefiles,
5723 abortonerror=opts.get('abort_on_err'),
5723 abortonerror=opts.get('abort_on_err'),
5724 noop=not act,
5724 noop=not act,
5725 confirm=confirm,
5725 confirm=confirm,
5726 )
5726 )
5727
5727
5728 for path in paths:
5728 for path in paths:
5729 if not act:
5729 if not act:
5730 ui.write(b'%s%s' % (path, eol))
5730 ui.write(b'%s%s' % (path, eol))
5731
5731
5732
5732
5733 @command(
5733 @command(
5734 b'push',
5734 b'push',
5735 [
5735 [
5736 (b'f', b'force', None, _(b'force push')),
5736 (b'f', b'force', None, _(b'force push')),
5737 (
5737 (
5738 b'r',
5738 b'r',
5739 b'rev',
5739 b'rev',
5740 [],
5740 [],
5741 _(b'a changeset intended to be included in the destination'),
5741 _(b'a changeset intended to be included in the destination'),
5742 _(b'REV'),
5742 _(b'REV'),
5743 ),
5743 ),
5744 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5744 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5745 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5745 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5746 (
5746 (
5747 b'b',
5747 b'b',
5748 b'branch',
5748 b'branch',
5749 [],
5749 [],
5750 _(b'a specific branch you would like to push'),
5750 _(b'a specific branch you would like to push'),
5751 _(b'BRANCH'),
5751 _(b'BRANCH'),
5752 ),
5752 ),
5753 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5753 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5754 (
5754 (
5755 b'',
5755 b'',
5756 b'pushvars',
5756 b'pushvars',
5757 [],
5757 [],
5758 _(b'variables that can be sent to server (ADVANCED)'),
5758 _(b'variables that can be sent to server (ADVANCED)'),
5759 ),
5759 ),
5760 (
5760 (
5761 b'',
5761 b'',
5762 b'publish',
5762 b'publish',
5763 False,
5763 False,
5764 _(b'push the changeset as public (EXPERIMENTAL)'),
5764 _(b'push the changeset as public (EXPERIMENTAL)'),
5765 ),
5765 ),
5766 ]
5766 ]
5767 + remoteopts,
5767 + remoteopts,
5768 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5768 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5769 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5769 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5770 helpbasic=True,
5770 helpbasic=True,
5771 )
5771 )
5772 def push(ui, repo, *dests, **opts):
5772 def push(ui, repo, *dests, **opts):
5773 """push changes to the specified destination
5773 """push changes to the specified destination
5774
5774
5775 Push changesets from the local repository to the specified
5775 Push changesets from the local repository to the specified
5776 destination.
5776 destination.
5777
5777
5778 This operation is symmetrical to pull: it is identical to a pull
5778 This operation is symmetrical to pull: it is identical to a pull
5779 in the destination repository from the current one.
5779 in the destination repository from the current one.
5780
5780
5781 By default, push will not allow creation of new heads at the
5781 By default, push will not allow creation of new heads at the
5782 destination, since multiple heads would make it unclear which head
5782 destination, since multiple heads would make it unclear which head
5783 to use. In this situation, it is recommended to pull and merge
5783 to use. In this situation, it is recommended to pull and merge
5784 before pushing.
5784 before pushing.
5785
5785
5786 Use --new-branch if you want to allow push to create a new named
5786 Use --new-branch if you want to allow push to create a new named
5787 branch that is not present at the destination. This allows you to
5787 branch that is not present at the destination. This allows you to
5788 only create a new branch without forcing other changes.
5788 only create a new branch without forcing other changes.
5789
5789
5790 .. note::
5790 .. note::
5791
5791
5792 Extra care should be taken with the -f/--force option,
5792 Extra care should be taken with the -f/--force option,
5793 which will push all new heads on all branches, an action which will
5793 which will push all new heads on all branches, an action which will
5794 almost always cause confusion for collaborators.
5794 almost always cause confusion for collaborators.
5795
5795
5796 If -r/--rev is used, the specified revision and all its ancestors
5796 If -r/--rev is used, the specified revision and all its ancestors
5797 will be pushed to the remote repository.
5797 will be pushed to the remote repository.
5798
5798
5799 If -B/--bookmark is used, the specified bookmarked revision, its
5799 If -B/--bookmark is used, the specified bookmarked revision, its
5800 ancestors, and the bookmark will be pushed to the remote
5800 ancestors, and the bookmark will be pushed to the remote
5801 repository. Specifying ``.`` is equivalent to specifying the active
5801 repository. Specifying ``.`` is equivalent to specifying the active
5802 bookmark's name. Use the --all-bookmarks option for pushing all
5802 bookmark's name. Use the --all-bookmarks option for pushing all
5803 current bookmarks.
5803 current bookmarks.
5804
5804
5805 Please see :hg:`help urls` for important details about ``ssh://``
5805 Please see :hg:`help urls` for important details about ``ssh://``
5806 URLs. If DESTINATION is omitted, a default path will be used.
5806 URLs. If DESTINATION is omitted, a default path will be used.
5807
5807
5808 When passed multiple destinations, push will process them one after the
5808 When passed multiple destinations, push will process them one after the
5809 other, but stop should an error occur.
5809 other, but stop should an error occur.
5810
5810
5811 .. container:: verbose
5811 .. container:: verbose
5812
5812
5813 The --pushvars option sends strings to the server that become
5813 The --pushvars option sends strings to the server that become
5814 environment variables prepended with ``HG_USERVAR_``. For example,
5814 environment variables prepended with ``HG_USERVAR_``. For example,
5815 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5815 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5816 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5816 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5817
5817
5818 pushvars can provide for user-overridable hooks as well as set debug
5818 pushvars can provide for user-overridable hooks as well as set debug
5819 levels. One example is having a hook that blocks commits containing
5819 levels. One example is having a hook that blocks commits containing
5820 conflict markers, but enables the user to override the hook if the file
5820 conflict markers, but enables the user to override the hook if the file
5821 is using conflict markers for testing purposes or the file format has
5821 is using conflict markers for testing purposes or the file format has
5822 strings that look like conflict markers.
5822 strings that look like conflict markers.
5823
5823
5824 By default, servers will ignore `--pushvars`. To enable it add the
5824 By default, servers will ignore `--pushvars`. To enable it add the
5825 following to your configuration file::
5825 following to your configuration file::
5826
5826
5827 [push]
5827 [push]
5828 pushvars.server = true
5828 pushvars.server = true
5829
5829
5830 Returns 0 if push was successful, 1 if nothing to push.
5830 Returns 0 if push was successful, 1 if nothing to push.
5831 """
5831 """
5832
5832
5833 opts = pycompat.byteskwargs(opts)
5833 opts = pycompat.byteskwargs(opts)
5834
5834
5835 if opts.get(b'all_bookmarks'):
5835 if opts.get(b'all_bookmarks'):
5836 cmdutil.check_incompatible_arguments(
5836 cmdutil.check_incompatible_arguments(
5837 opts,
5837 opts,
5838 b'all_bookmarks',
5838 b'all_bookmarks',
5839 [b'bookmark', b'rev'],
5839 [b'bookmark', b'rev'],
5840 )
5840 )
5841 opts[b'bookmark'] = list(repo._bookmarks)
5841 opts[b'bookmark'] = list(repo._bookmarks)
5842
5842
5843 if opts.get(b'bookmark'):
5843 if opts.get(b'bookmark'):
5844 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5844 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5845 for b in opts[b'bookmark']:
5845 for b in opts[b'bookmark']:
5846 # translate -B options to -r so changesets get pushed
5846 # translate -B options to -r so changesets get pushed
5847 b = repo._bookmarks.expandname(b)
5847 b = repo._bookmarks.expandname(b)
5848 if b in repo._bookmarks:
5848 if b in repo._bookmarks:
5849 opts.setdefault(b'rev', []).append(b)
5849 opts.setdefault(b'rev', []).append(b)
5850 else:
5850 else:
5851 # if we try to push a deleted bookmark, translate it to null
5851 # if we try to push a deleted bookmark, translate it to null
5852 # this lets simultaneous -r, -b options continue working
5852 # this lets simultaneous -r, -b options continue working
5853 opts.setdefault(b'rev', []).append(b"null")
5853 opts.setdefault(b'rev', []).append(b"null")
5854
5854
5855 some_pushed = False
5855 some_pushed = False
5856 result = 0
5856 result = 0
5857 for path in urlutil.get_push_paths(repo, ui, dests):
5857 for path in urlutil.get_push_paths(repo, ui, dests):
5858 dest = path.loc
5858 dest = path.loc
5859 branches = (path.branch, opts.get(b'branch') or [])
5859 branches = (path.branch, opts.get(b'branch') or [])
5860 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5860 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5861 revs, checkout = hg.addbranchrevs(
5861 revs, checkout = hg.addbranchrevs(
5862 repo, repo, branches, opts.get(b'rev')
5862 repo, repo, branches, opts.get(b'rev')
5863 )
5863 )
5864 other = hg.peer(repo, opts, dest)
5864 other = hg.peer(repo, opts, dest)
5865
5865
5866 try:
5866 try:
5867 if revs:
5867 if revs:
5868 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5868 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5869 if not revs:
5869 if not revs:
5870 raise error.InputError(
5870 raise error.InputError(
5871 _(b"specified revisions evaluate to an empty set"),
5871 _(b"specified revisions evaluate to an empty set"),
5872 hint=_(b"use different revision arguments"),
5872 hint=_(b"use different revision arguments"),
5873 )
5873 )
5874 elif path.pushrev:
5874 elif path.pushrev:
5875 # It doesn't make any sense to specify ancestor revisions. So limit
5875 # It doesn't make any sense to specify ancestor revisions. So limit
5876 # to DAG heads to make discovery simpler.
5876 # to DAG heads to make discovery simpler.
5877 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5877 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5878 revs = scmutil.revrange(repo, [expr])
5878 revs = scmutil.revrange(repo, [expr])
5879 revs = [repo[rev].node() for rev in revs]
5879 revs = [repo[rev].node() for rev in revs]
5880 if not revs:
5880 if not revs:
5881 raise error.InputError(
5881 raise error.InputError(
5882 _(
5882 _(
5883 b'default push revset for path evaluates to an empty set'
5883 b'default push revset for path evaluates to an empty set'
5884 )
5884 )
5885 )
5885 )
5886 elif ui.configbool(b'commands', b'push.require-revs'):
5886 elif ui.configbool(b'commands', b'push.require-revs'):
5887 raise error.InputError(
5887 raise error.InputError(
5888 _(b'no revisions specified to push'),
5888 _(b'no revisions specified to push'),
5889 hint=_(b'did you mean "hg push -r ."?'),
5889 hint=_(b'did you mean "hg push -r ."?'),
5890 )
5890 )
5891
5891
5892 repo._subtoppath = dest
5892 repo._subtoppath = dest
5893 try:
5893 try:
5894 # push subrepos depth-first for coherent ordering
5894 # push subrepos depth-first for coherent ordering
5895 c = repo[b'.']
5895 c = repo[b'.']
5896 subs = c.substate # only repos that are committed
5896 subs = c.substate # only repos that are committed
5897 for s in sorted(subs):
5897 for s in sorted(subs):
5898 sub_result = c.sub(s).push(opts)
5898 sub_result = c.sub(s).push(opts)
5899 if sub_result == 0:
5899 if sub_result == 0:
5900 return 1
5900 return 1
5901 finally:
5901 finally:
5902 del repo._subtoppath
5902 del repo._subtoppath
5903
5903
5904 opargs = dict(
5904 opargs = dict(
5905 opts.get(b'opargs', {})
5905 opts.get(b'opargs', {})
5906 ) # copy opargs since we may mutate it
5906 ) # copy opargs since we may mutate it
5907 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5907 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5908
5908
5909 pushop = exchange.push(
5909 pushop = exchange.push(
5910 repo,
5910 repo,
5911 other,
5911 other,
5912 opts.get(b'force'),
5912 opts.get(b'force'),
5913 revs=revs,
5913 revs=revs,
5914 newbranch=opts.get(b'new_branch'),
5914 newbranch=opts.get(b'new_branch'),
5915 bookmarks=opts.get(b'bookmark', ()),
5915 bookmarks=opts.get(b'bookmark', ()),
5916 publish=opts.get(b'publish'),
5916 publish=opts.get(b'publish'),
5917 opargs=opargs,
5917 opargs=opargs,
5918 )
5918 )
5919
5919
5920 if pushop.cgresult == 0:
5920 if pushop.cgresult == 0:
5921 result = 1
5921 result = 1
5922 elif pushop.cgresult is not None:
5922 elif pushop.cgresult is not None:
5923 some_pushed = True
5923 some_pushed = True
5924
5924
5925 if pushop.bkresult is not None:
5925 if pushop.bkresult is not None:
5926 if pushop.bkresult == 2:
5926 if pushop.bkresult == 2:
5927 result = 2
5927 result = 2
5928 elif not result and pushop.bkresult:
5928 elif not result and pushop.bkresult:
5929 result = 2
5929 result = 2
5930
5930
5931 if result:
5931 if result:
5932 break
5932 break
5933
5933
5934 finally:
5934 finally:
5935 other.close()
5935 other.close()
5936 if result == 0 and not some_pushed:
5936 if result == 0 and not some_pushed:
5937 result = 1
5937 result = 1
5938 return result
5938 return result
5939
5939
5940
5940
5941 @command(
5941 @command(
5942 b'recover',
5942 b'recover',
5943 [
5943 [
5944 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5944 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5945 ],
5945 ],
5946 helpcategory=command.CATEGORY_MAINTENANCE,
5946 helpcategory=command.CATEGORY_MAINTENANCE,
5947 )
5947 )
5948 def recover(ui, repo, **opts):
5948 def recover(ui, repo, **opts):
5949 """roll back an interrupted transaction
5949 """roll back an interrupted transaction
5950
5950
5951 Recover from an interrupted commit or pull.
5951 Recover from an interrupted commit or pull.
5952
5952
5953 This command tries to fix the repository status after an
5953 This command tries to fix the repository status after an
5954 interrupted operation. It should only be necessary when Mercurial
5954 interrupted operation. It should only be necessary when Mercurial
5955 suggests it.
5955 suggests it.
5956
5956
5957 Returns 0 if successful, 1 if nothing to recover or verify fails.
5957 Returns 0 if successful, 1 if nothing to recover or verify fails.
5958 """
5958 """
5959 ret = repo.recover()
5959 ret = repo.recover()
5960 if ret:
5960 if ret:
5961 if opts['verify']:
5961 if opts['verify']:
5962 return hg.verify(repo)
5962 return hg.verify(repo)
5963 else:
5963 else:
5964 msg = _(
5964 msg = _(
5965 b"(verify step skipped, run `hg verify` to check your "
5965 b"(verify step skipped, run `hg verify` to check your "
5966 b"repository content)\n"
5966 b"repository content)\n"
5967 )
5967 )
5968 ui.warn(msg)
5968 ui.warn(msg)
5969 return 0
5969 return 0
5970 return 1
5970 return 1
5971
5971
5972
5972
5973 @command(
5973 @command(
5974 b'remove|rm',
5974 b'remove|rm',
5975 [
5975 [
5976 (b'A', b'after', None, _(b'record delete for missing files')),
5976 (b'A', b'after', None, _(b'record delete for missing files')),
5977 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5977 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5978 ]
5978 ]
5979 + subrepoopts
5979 + subrepoopts
5980 + walkopts
5980 + walkopts
5981 + dryrunopts,
5981 + dryrunopts,
5982 _(b'[OPTION]... FILE...'),
5982 _(b'[OPTION]... FILE...'),
5983 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5983 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5984 helpbasic=True,
5984 helpbasic=True,
5985 inferrepo=True,
5985 inferrepo=True,
5986 )
5986 )
5987 def remove(ui, repo, *pats, **opts):
5987 def remove(ui, repo, *pats, **opts):
5988 """remove the specified files on the next commit
5988 """remove the specified files on the next commit
5989
5989
5990 Schedule the indicated files for removal from the current branch.
5990 Schedule the indicated files for removal from the current branch.
5991
5991
5992 This command schedules the files to be removed at the next commit.
5992 This command schedules the files to be removed at the next commit.
5993 To undo a remove before that, see :hg:`revert`. To undo added
5993 To undo a remove before that, see :hg:`revert`. To undo added
5994 files, see :hg:`forget`.
5994 files, see :hg:`forget`.
5995
5995
5996 .. container:: verbose
5996 .. container:: verbose
5997
5997
5998 -A/--after can be used to remove only files that have already
5998 -A/--after can be used to remove only files that have already
5999 been deleted, -f/--force can be used to force deletion, and -Af
5999 been deleted, -f/--force can be used to force deletion, and -Af
6000 can be used to remove files from the next revision without
6000 can be used to remove files from the next revision without
6001 deleting them from the working directory.
6001 deleting them from the working directory.
6002
6002
6003 The following table details the behavior of remove for different
6003 The following table details the behavior of remove for different
6004 file states (columns) and option combinations (rows). The file
6004 file states (columns) and option combinations (rows). The file
6005 states are Added [A], Clean [C], Modified [M] and Missing [!]
6005 states are Added [A], Clean [C], Modified [M] and Missing [!]
6006 (as reported by :hg:`status`). The actions are Warn, Remove
6006 (as reported by :hg:`status`). The actions are Warn, Remove
6007 (from branch) and Delete (from disk):
6007 (from branch) and Delete (from disk):
6008
6008
6009 ========= == == == ==
6009 ========= == == == ==
6010 opt/state A C M !
6010 opt/state A C M !
6011 ========= == == == ==
6011 ========= == == == ==
6012 none W RD W R
6012 none W RD W R
6013 -f R RD RD R
6013 -f R RD RD R
6014 -A W W W R
6014 -A W W W R
6015 -Af R R R R
6015 -Af R R R R
6016 ========= == == == ==
6016 ========= == == == ==
6017
6017
6018 .. note::
6018 .. note::
6019
6019
6020 :hg:`remove` never deletes files in Added [A] state from the
6020 :hg:`remove` never deletes files in Added [A] state from the
6021 working directory, not even if ``--force`` is specified.
6021 working directory, not even if ``--force`` is specified.
6022
6022
6023 Returns 0 on success, 1 if any warnings encountered.
6023 Returns 0 on success, 1 if any warnings encountered.
6024 """
6024 """
6025
6025
6026 after, force = opts.get('after'), opts.get('force')
6026 after, force = opts.get('after'), opts.get('force')
6027 dryrun = opts.get('dry_run')
6027 dryrun = opts.get('dry_run')
6028 if not pats and not after:
6028 if not pats and not after:
6029 raise error.InputError(_(b'no files specified'))
6029 raise error.InputError(_(b'no files specified'))
6030
6030
6031 with repo.wlock(), repo.dirstate.changing_files(repo):
6031 with repo.wlock(), repo.dirstate.changing_files(repo):
6032 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
6032 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
6033 subrepos = opts.get('subrepos')
6033 subrepos = opts.get('subrepos')
6034 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
6034 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
6035 return cmdutil.remove(
6035 return cmdutil.remove(
6036 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
6036 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
6037 )
6037 )
6038
6038
6039
6039
6040 @command(
6040 @command(
6041 b'rename|move|mv',
6041 b'rename|move|mv',
6042 [
6042 [
6043 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6043 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6044 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6044 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6045 (
6045 (
6046 b'',
6046 b'',
6047 b'at-rev',
6047 b'at-rev',
6048 b'',
6048 b'',
6049 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6049 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6050 _(b'REV'),
6050 _(b'REV'),
6051 ),
6051 ),
6052 (
6052 (
6053 b'f',
6053 b'f',
6054 b'force',
6054 b'force',
6055 None,
6055 None,
6056 _(b'forcibly move over an existing managed file'),
6056 _(b'forcibly move over an existing managed file'),
6057 ),
6057 ),
6058 ]
6058 ]
6059 + walkopts
6059 + walkopts
6060 + dryrunopts,
6060 + dryrunopts,
6061 _(b'[OPTION]... SOURCE... DEST'),
6061 _(b'[OPTION]... SOURCE... DEST'),
6062 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6062 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6063 )
6063 )
6064 def rename(ui, repo, *pats, **opts):
6064 def rename(ui, repo, *pats, **opts):
6065 """rename files; equivalent of copy + remove
6065 """rename files; equivalent of copy + remove
6066
6066
6067 Mark dest as copies of sources; mark sources for deletion. If dest
6067 Mark dest as copies of sources; mark sources for deletion. If dest
6068 is a directory, copies are put in that directory. If dest is a
6068 is a directory, copies are put in that directory. If dest is a
6069 file, there can only be one source.
6069 file, there can only be one source.
6070
6070
6071 By default, this command copies the contents of files as they
6071 By default, this command copies the contents of files as they
6072 exist in the working directory. If invoked with -A/--after, the
6072 exist in the working directory. If invoked with -A/--after, the
6073 operation is recorded, but no copying is performed.
6073 operation is recorded, but no copying is performed.
6074
6074
6075 To undo marking a destination file as renamed, use --forget. With that
6075 To undo marking a destination file as renamed, use --forget. With that
6076 option, all given (positional) arguments are unmarked as renames. The
6076 option, all given (positional) arguments are unmarked as renames. The
6077 destination file(s) will be left in place (still tracked). The source
6077 destination file(s) will be left in place (still tracked). The source
6078 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6078 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6079 the same way as :hg:`copy --forget`.
6079 the same way as :hg:`copy --forget`.
6080
6080
6081 This command takes effect with the next commit by default.
6081 This command takes effect with the next commit by default.
6082
6082
6083 Returns 0 on success, 1 if errors are encountered.
6083 Returns 0 on success, 1 if errors are encountered.
6084 """
6084 """
6085 context = lambda repo: repo.dirstate.changing_files(repo)
6085 context = lambda repo: repo.dirstate.changing_files(repo)
6086 rev = opts.get('at_rev')
6086 rev = opts.get('at_rev')
6087
6087
6088 if rev:
6088 if rev:
6089 ctx = logcmdutil.revsingle(repo, rev)
6089 ctx = logcmdutil.revsingle(repo, rev)
6090 if ctx.rev() is not None:
6090 if ctx.rev() is not None:
6091
6091
6092 def context(repo):
6092 def context(repo):
6093 return util.nullcontextmanager()
6093 return util.nullcontextmanager()
6094
6094
6095 opts['at_rev'] = ctx.rev()
6095 opts['at_rev'] = ctx.rev()
6096 with repo.wlock(), context(repo):
6096 with repo.wlock(), context(repo):
6097 return cmdutil.copy(
6097 return cmdutil.copy(
6098 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6098 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6099 )
6099 )
6100
6100
6101
6101
6102 @command(
6102 @command(
6103 b'resolve',
6103 b'resolve',
6104 [
6104 [
6105 (b'a', b'all', None, _(b'select all unresolved files')),
6105 (b'a', b'all', None, _(b'select all unresolved files')),
6106 (b'l', b'list', None, _(b'list state of files needing merge')),
6106 (b'l', b'list', None, _(b'list state of files needing merge')),
6107 (b'm', b'mark', None, _(b'mark files as resolved')),
6107 (b'm', b'mark', None, _(b'mark files as resolved')),
6108 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6108 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6109 (b'n', b'no-status', None, _(b'hide status prefix')),
6109 (b'n', b'no-status', None, _(b'hide status prefix')),
6110 (b'', b're-merge', None, _(b're-merge files')),
6110 (b'', b're-merge', None, _(b're-merge files')),
6111 ]
6111 ]
6112 + mergetoolopts
6112 + mergetoolopts
6113 + walkopts
6113 + walkopts
6114 + formatteropts,
6114 + formatteropts,
6115 _(b'[OPTION]... [FILE]...'),
6115 _(b'[OPTION]... [FILE]...'),
6116 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6116 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6117 inferrepo=True,
6117 inferrepo=True,
6118 )
6118 )
6119 def resolve(ui, repo, *pats, **opts):
6119 def resolve(ui, repo, *pats, **opts):
6120 """redo merges or set/view the merge status of files
6120 """redo merges or set/view the merge status of files
6121
6121
6122 Merges with unresolved conflicts are often the result of
6122 Merges with unresolved conflicts are often the result of
6123 non-interactive merging using the ``internal:merge`` configuration
6123 non-interactive merging using the ``internal:merge`` configuration
6124 setting, or a command-line merge tool like ``diff3``. The resolve
6124 setting, or a command-line merge tool like ``diff3``. The resolve
6125 command is used to manage the files involved in a merge, after
6125 command is used to manage the files involved in a merge, after
6126 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6126 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6127 working directory must have two parents). See :hg:`help
6127 working directory must have two parents). See :hg:`help
6128 merge-tools` for information on configuring merge tools.
6128 merge-tools` for information on configuring merge tools.
6129
6129
6130 The resolve command can be used in the following ways:
6130 The resolve command can be used in the following ways:
6131
6131
6132 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6132 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6133 the specified files, discarding any previous merge attempts. Re-merging
6133 the specified files, discarding any previous merge attempts. Re-merging
6134 is not performed for files already marked as resolved. Use ``--all/-a``
6134 is not performed for files already marked as resolved. Use ``--all/-a``
6135 to select all unresolved files. ``--tool`` can be used to specify
6135 to select all unresolved files. ``--tool`` can be used to specify
6136 the merge tool used for the given files. It overrides the HGMERGE
6136 the merge tool used for the given files. It overrides the HGMERGE
6137 environment variable and your configuration files. Previous file
6137 environment variable and your configuration files. Previous file
6138 contents are saved with a ``.orig`` suffix.
6138 contents are saved with a ``.orig`` suffix.
6139
6139
6140 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6140 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6141 (e.g. after having manually fixed-up the files). The default is
6141 (e.g. after having manually fixed-up the files). The default is
6142 to mark all unresolved files.
6142 to mark all unresolved files.
6143
6143
6144 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6144 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6145 default is to mark all resolved files.
6145 default is to mark all resolved files.
6146
6146
6147 - :hg:`resolve -l`: list files which had or still have conflicts.
6147 - :hg:`resolve -l`: list files which had or still have conflicts.
6148 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6148 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6149 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6149 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6150 the list. See :hg:`help filesets` for details.
6150 the list. See :hg:`help filesets` for details.
6151
6151
6152 .. note::
6152 .. note::
6153
6153
6154 Mercurial will not let you commit files with unresolved merge
6154 Mercurial will not let you commit files with unresolved merge
6155 conflicts. You must use :hg:`resolve -m ...` before you can
6155 conflicts. You must use :hg:`resolve -m ...` before you can
6156 commit after a conflicting merge.
6156 commit after a conflicting merge.
6157
6157
6158 .. container:: verbose
6158 .. container:: verbose
6159
6159
6160 Template:
6160 Template:
6161
6161
6162 The following keywords are supported in addition to the common template
6162 The following keywords are supported in addition to the common template
6163 keywords and functions. See also :hg:`help templates`.
6163 keywords and functions. See also :hg:`help templates`.
6164
6164
6165 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6165 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6166 :path: String. Repository-absolute path of the file.
6166 :path: String. Repository-absolute path of the file.
6167
6167
6168 Returns 0 on success, 1 if any files fail a resolve attempt.
6168 Returns 0 on success, 1 if any files fail a resolve attempt.
6169 """
6169 """
6170
6170
6171 opts = pycompat.byteskwargs(opts)
6171 opts = pycompat.byteskwargs(opts)
6172 confirm = ui.configbool(b'commands', b'resolve.confirm')
6172 confirm = ui.configbool(b'commands', b'resolve.confirm')
6173 flaglist = b'all mark unmark list no_status re_merge'.split()
6173 flaglist = b'all mark unmark list no_status re_merge'.split()
6174 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6174 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6175
6175
6176 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6176 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6177 if actioncount > 1:
6177 if actioncount > 1:
6178 raise error.InputError(_(b"too many actions specified"))
6178 raise error.InputError(_(b"too many actions specified"))
6179 elif actioncount == 0 and ui.configbool(
6179 elif actioncount == 0 and ui.configbool(
6180 b'commands', b'resolve.explicit-re-merge'
6180 b'commands', b'resolve.explicit-re-merge'
6181 ):
6181 ):
6182 hint = _(b'use --mark, --unmark, --list or --re-merge')
6182 hint = _(b'use --mark, --unmark, --list or --re-merge')
6183 raise error.InputError(_(b'no action specified'), hint=hint)
6183 raise error.InputError(_(b'no action specified'), hint=hint)
6184 if pats and all:
6184 if pats and all:
6185 raise error.InputError(_(b"can't specify --all and patterns"))
6185 raise error.InputError(_(b"can't specify --all and patterns"))
6186 if not (all or pats or show or mark or unmark):
6186 if not (all or pats or show or mark or unmark):
6187 raise error.InputError(
6187 raise error.InputError(
6188 _(b'no files or directories specified'),
6188 _(b'no files or directories specified'),
6189 hint=b'use --all to re-merge all unresolved files',
6189 hint=b'use --all to re-merge all unresolved files',
6190 )
6190 )
6191
6191
6192 if confirm:
6192 if confirm:
6193 if all:
6193 if all:
6194 if ui.promptchoice(
6194 if ui.promptchoice(
6195 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6195 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6196 ):
6196 ):
6197 raise error.CanceledError(_(b'user quit'))
6197 raise error.CanceledError(_(b'user quit'))
6198 if mark and not pats:
6198 if mark and not pats:
6199 if ui.promptchoice(
6199 if ui.promptchoice(
6200 _(
6200 _(
6201 b'mark all unresolved files as resolved (yn)?'
6201 b'mark all unresolved files as resolved (yn)?'
6202 b'$$ &Yes $$ &No'
6202 b'$$ &Yes $$ &No'
6203 )
6203 )
6204 ):
6204 ):
6205 raise error.CanceledError(_(b'user quit'))
6205 raise error.CanceledError(_(b'user quit'))
6206 if unmark and not pats:
6206 if unmark and not pats:
6207 if ui.promptchoice(
6207 if ui.promptchoice(
6208 _(
6208 _(
6209 b'mark all resolved files as unresolved (yn)?'
6209 b'mark all resolved files as unresolved (yn)?'
6210 b'$$ &Yes $$ &No'
6210 b'$$ &Yes $$ &No'
6211 )
6211 )
6212 ):
6212 ):
6213 raise error.CanceledError(_(b'user quit'))
6213 raise error.CanceledError(_(b'user quit'))
6214
6214
6215 uipathfn = scmutil.getuipathfn(repo)
6215 uipathfn = scmutil.getuipathfn(repo)
6216
6216
6217 if show:
6217 if show:
6218 ui.pager(b'resolve')
6218 ui.pager(b'resolve')
6219 fm = ui.formatter(b'resolve', opts)
6219 fm = ui.formatter(b'resolve', opts)
6220 ms = mergestatemod.mergestate.read(repo)
6220 ms = mergestatemod.mergestate.read(repo)
6221 wctx = repo[None]
6221 wctx = repo[None]
6222 m = scmutil.match(wctx, pats, opts)
6222 m = scmutil.match(wctx, pats, opts)
6223
6223
6224 # Labels and keys based on merge state. Unresolved path conflicts show
6224 # Labels and keys based on merge state. Unresolved path conflicts show
6225 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6225 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6226 # resolved conflicts.
6226 # resolved conflicts.
6227 mergestateinfo = {
6227 mergestateinfo = {
6228 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6228 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6229 b'resolve.unresolved',
6229 b'resolve.unresolved',
6230 b'U',
6230 b'U',
6231 ),
6231 ),
6232 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6232 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6233 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6233 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6234 b'resolve.unresolved',
6234 b'resolve.unresolved',
6235 b'P',
6235 b'P',
6236 ),
6236 ),
6237 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6237 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6238 b'resolve.resolved',
6238 b'resolve.resolved',
6239 b'R',
6239 b'R',
6240 ),
6240 ),
6241 }
6241 }
6242
6242
6243 for f in ms:
6243 for f in ms:
6244 if not m(f):
6244 if not m(f):
6245 continue
6245 continue
6246
6246
6247 label, key = mergestateinfo[ms[f]]
6247 label, key = mergestateinfo[ms[f]]
6248 fm.startitem()
6248 fm.startitem()
6249 fm.context(ctx=wctx)
6249 fm.context(ctx=wctx)
6250 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6250 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6251 fm.data(path=f)
6251 fm.data(path=f)
6252 fm.plain(b'%s\n' % uipathfn(f), label=label)
6252 fm.plain(b'%s\n' % uipathfn(f), label=label)
6253 fm.end()
6253 fm.end()
6254 return 0
6254 return 0
6255
6255
6256 with repo.wlock():
6256 with repo.wlock():
6257 ms = mergestatemod.mergestate.read(repo)
6257 ms = mergestatemod.mergestate.read(repo)
6258
6258
6259 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6259 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6260 raise error.StateError(
6260 raise error.StateError(
6261 _(b'resolve command not applicable when not merging')
6261 _(b'resolve command not applicable when not merging')
6262 )
6262 )
6263
6263
6264 wctx = repo[None]
6264 wctx = repo[None]
6265 m = scmutil.match(wctx, pats, opts)
6265 m = scmutil.match(wctx, pats, opts)
6266 ret = 0
6266 ret = 0
6267 didwork = False
6267 didwork = False
6268
6268
6269 hasconflictmarkers = []
6269 hasconflictmarkers = []
6270 if mark:
6270 if mark:
6271 markcheck = ui.config(b'commands', b'resolve.mark-check')
6271 markcheck = ui.config(b'commands', b'resolve.mark-check')
6272 if markcheck not in [b'warn', b'abort']:
6272 if markcheck not in [b'warn', b'abort']:
6273 # Treat all invalid / unrecognized values as 'none'.
6273 # Treat all invalid / unrecognized values as 'none'.
6274 markcheck = False
6274 markcheck = False
6275 for f in ms:
6275 for f in ms:
6276 if not m(f):
6276 if not m(f):
6277 continue
6277 continue
6278
6278
6279 didwork = True
6279 didwork = True
6280
6280
6281 # path conflicts must be resolved manually
6281 # path conflicts must be resolved manually
6282 if ms[f] in (
6282 if ms[f] in (
6283 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6283 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6284 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6284 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6285 ):
6285 ):
6286 if mark:
6286 if mark:
6287 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6287 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6288 elif unmark:
6288 elif unmark:
6289 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6289 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6290 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6290 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6291 ui.warn(
6291 ui.warn(
6292 _(b'%s: path conflict must be resolved manually\n')
6292 _(b'%s: path conflict must be resolved manually\n')
6293 % uipathfn(f)
6293 % uipathfn(f)
6294 )
6294 )
6295 continue
6295 continue
6296
6296
6297 if mark:
6297 if mark:
6298 if markcheck:
6298 if markcheck:
6299 fdata = repo.wvfs.tryread(f)
6299 fdata = repo.wvfs.tryread(f)
6300 if (
6300 if (
6301 filemerge.hasconflictmarkers(fdata)
6301 filemerge.hasconflictmarkers(fdata)
6302 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6302 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6303 ):
6303 ):
6304 hasconflictmarkers.append(f)
6304 hasconflictmarkers.append(f)
6305 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6305 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6306 elif unmark:
6306 elif unmark:
6307 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6307 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6308 else:
6308 else:
6309 # backup pre-resolve (merge uses .orig for its own purposes)
6309 # backup pre-resolve (merge uses .orig for its own purposes)
6310 a = repo.wjoin(f)
6310 a = repo.wjoin(f)
6311 try:
6311 try:
6312 util.copyfile(a, a + b".resolve")
6312 util.copyfile(a, a + b".resolve")
6313 except FileNotFoundError:
6313 except FileNotFoundError:
6314 pass
6314 pass
6315
6315
6316 try:
6316 try:
6317 # preresolve file
6317 # preresolve file
6318 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6318 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6319 with ui.configoverride(overrides, b'resolve'):
6319 with ui.configoverride(overrides, b'resolve'):
6320 r = ms.resolve(f, wctx)
6320 r = ms.resolve(f, wctx)
6321 if r:
6321 if r:
6322 ret = 1
6322 ret = 1
6323 finally:
6323 finally:
6324 ms.commit()
6324 ms.commit()
6325
6325
6326 # replace filemerge's .orig file with our resolve file
6326 # replace filemerge's .orig file with our resolve file
6327 try:
6327 try:
6328 util.rename(
6328 util.rename(
6329 a + b".resolve", scmutil.backuppath(ui, repo, f)
6329 a + b".resolve", scmutil.backuppath(ui, repo, f)
6330 )
6330 )
6331 except FileNotFoundError:
6331 except FileNotFoundError:
6332 pass
6332 pass
6333
6333
6334 if hasconflictmarkers:
6334 if hasconflictmarkers:
6335 ui.warn(
6335 ui.warn(
6336 _(
6336 _(
6337 b'warning: the following files still have conflict '
6337 b'warning: the following files still have conflict '
6338 b'markers:\n'
6338 b'markers:\n'
6339 )
6339 )
6340 + b''.join(
6340 + b''.join(
6341 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6341 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6342 )
6342 )
6343 )
6343 )
6344 if markcheck == b'abort' and not all and not pats:
6344 if markcheck == b'abort' and not all and not pats:
6345 raise error.StateError(
6345 raise error.StateError(
6346 _(b'conflict markers detected'),
6346 _(b'conflict markers detected'),
6347 hint=_(b'use --all to mark anyway'),
6347 hint=_(b'use --all to mark anyway'),
6348 )
6348 )
6349
6349
6350 ms.commit()
6350 ms.commit()
6351 branchmerge = repo.dirstate.p2() != repo.nullid
6351 branchmerge = repo.dirstate.p2() != repo.nullid
6352 # resolve is not doing a parent change here, however, `record updates`
6352 # resolve is not doing a parent change here, however, `record updates`
6353 # will call some dirstate API that at intended for parent changes call.
6353 # will call some dirstate API that at intended for parent changes call.
6354 # Ideally we would not need this and could implement a lighter version
6354 # Ideally we would not need this and could implement a lighter version
6355 # of the recordupdateslogic that will not have to deal with the part
6355 # of the recordupdateslogic that will not have to deal with the part
6356 # related to parent changes. However this would requires that:
6356 # related to parent changes. However this would requires that:
6357 # - we are sure we passed around enough information at update/merge
6357 # - we are sure we passed around enough information at update/merge
6358 # time to no longer needs it at `hg resolve time`
6358 # time to no longer needs it at `hg resolve time`
6359 # - we are sure we store that information well enough to be able to reuse it
6359 # - we are sure we store that information well enough to be able to reuse it
6360 # - we are the necessary logic to reuse it right.
6360 # - we are the necessary logic to reuse it right.
6361 #
6361 #
6362 # All this should eventually happens, but in the mean time, we use this
6362 # All this should eventually happens, but in the mean time, we use this
6363 # context manager slightly out of the context it should be.
6363 # context manager slightly out of the context it should be.
6364 with repo.dirstate.changing_parents(repo):
6364 with repo.dirstate.changing_parents(repo):
6365 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6365 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6366
6366
6367 if not didwork and pats:
6367 if not didwork and pats:
6368 hint = None
6368 hint = None
6369 if not any([p for p in pats if p.find(b':') >= 0]):
6369 if not any([p for p in pats if p.find(b':') >= 0]):
6370 pats = [b'path:%s' % p for p in pats]
6370 pats = [b'path:%s' % p for p in pats]
6371 m = scmutil.match(wctx, pats, opts)
6371 m = scmutil.match(wctx, pats, opts)
6372 for f in ms:
6372 for f in ms:
6373 if not m(f):
6373 if not m(f):
6374 continue
6374 continue
6375
6375
6376 def flag(o):
6376 def flag(o):
6377 if o == b're_merge':
6377 if o == b're_merge':
6378 return b'--re-merge '
6378 return b'--re-merge '
6379 return b'-%s ' % o[0:1]
6379 return b'-%s ' % o[0:1]
6380
6380
6381 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6381 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6382 hint = _(b"(try: hg resolve %s%s)\n") % (
6382 hint = _(b"(try: hg resolve %s%s)\n") % (
6383 flags,
6383 flags,
6384 b' '.join(pats),
6384 b' '.join(pats),
6385 )
6385 )
6386 break
6386 break
6387 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6387 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6388 if hint:
6388 if hint:
6389 ui.warn(hint)
6389 ui.warn(hint)
6390
6390
6391 unresolvedf = ms.unresolvedcount()
6391 unresolvedf = ms.unresolvedcount()
6392 if not unresolvedf:
6392 if not unresolvedf:
6393 ui.status(_(b'(no more unresolved files)\n'))
6393 ui.status(_(b'(no more unresolved files)\n'))
6394 cmdutil.checkafterresolved(repo)
6394 cmdutil.checkafterresolved(repo)
6395
6395
6396 return ret
6396 return ret
6397
6397
6398
6398
6399 @command(
6399 @command(
6400 b'revert',
6400 b'revert',
6401 [
6401 [
6402 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6402 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6403 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6403 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6404 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6404 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6405 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6405 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6406 (b'i', b'interactive', None, _(b'interactively select the changes')),
6406 (b'i', b'interactive', None, _(b'interactively select the changes')),
6407 ]
6407 ]
6408 + walkopts
6408 + walkopts
6409 + dryrunopts,
6409 + dryrunopts,
6410 _(b'[OPTION]... [-r REV] [NAME]...'),
6410 _(b'[OPTION]... [-r REV] [NAME]...'),
6411 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6411 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6412 )
6412 )
6413 def revert(ui, repo, *pats, **opts):
6413 def revert(ui, repo, *pats, **opts):
6414 """restore files to their checkout state
6414 """restore files to their checkout state
6415
6415
6416 .. note::
6416 .. note::
6417
6417
6418 To check out earlier revisions, you should use :hg:`update REV`.
6418 To check out earlier revisions, you should use :hg:`update REV`.
6419 To cancel an uncommitted merge (and lose your changes),
6419 To cancel an uncommitted merge (and lose your changes),
6420 use :hg:`merge --abort`.
6420 use :hg:`merge --abort`.
6421
6421
6422 With no revision specified, revert the specified files or directories
6422 With no revision specified, revert the specified files or directories
6423 to the contents they had in the parent of the working directory.
6423 to the contents they had in the parent of the working directory.
6424 This restores the contents of files to an unmodified
6424 This restores the contents of files to an unmodified
6425 state and unschedules adds, removes, copies, and renames. If the
6425 state and unschedules adds, removes, copies, and renames. If the
6426 working directory has two parents, you must explicitly specify a
6426 working directory has two parents, you must explicitly specify a
6427 revision.
6427 revision.
6428
6428
6429 Using the -r/--rev or -d/--date options, revert the given files or
6429 Using the -r/--rev or -d/--date options, revert the given files or
6430 directories to their states as of a specific revision. Because
6430 directories to their states as of a specific revision. Because
6431 revert does not change the working directory parents, this will
6431 revert does not change the working directory parents, this will
6432 cause these files to appear modified. This can be helpful to "back
6432 cause these files to appear modified. This can be helpful to "back
6433 out" some or all of an earlier change. See :hg:`backout` for a
6433 out" some or all of an earlier change. See :hg:`backout` for a
6434 related method.
6434 related method.
6435
6435
6436 Modified files are saved with a .orig suffix before reverting.
6436 Modified files are saved with a .orig suffix before reverting.
6437 To disable these backups, use --no-backup. It is possible to store
6437 To disable these backups, use --no-backup. It is possible to store
6438 the backup files in a custom directory relative to the root of the
6438 the backup files in a custom directory relative to the root of the
6439 repository by setting the ``ui.origbackuppath`` configuration
6439 repository by setting the ``ui.origbackuppath`` configuration
6440 option.
6440 option.
6441
6441
6442 See :hg:`help dates` for a list of formats valid for -d/--date.
6442 See :hg:`help dates` for a list of formats valid for -d/--date.
6443
6443
6444 See :hg:`help backout` for a way to reverse the effect of an
6444 See :hg:`help backout` for a way to reverse the effect of an
6445 earlier changeset.
6445 earlier changeset.
6446
6446
6447 Returns 0 on success.
6447 Returns 0 on success.
6448 """
6448 """
6449
6449
6450 if opts.get("date"):
6450 if opts.get("date"):
6451 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6451 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6452 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6452 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6453
6453
6454 parent, p2 = repo.dirstate.parents()
6454 parent, p2 = repo.dirstate.parents()
6455 if not opts.get('rev') and p2 != repo.nullid:
6455 if not opts.get('rev') and p2 != repo.nullid:
6456 # revert after merge is a trap for new users (issue2915)
6456 # revert after merge is a trap for new users (issue2915)
6457 raise error.InputError(
6457 raise error.InputError(
6458 _(b'uncommitted merge with no revision specified'),
6458 _(b'uncommitted merge with no revision specified'),
6459 hint=_(b"use 'hg update' or see 'hg help revert'"),
6459 hint=_(b"use 'hg update' or see 'hg help revert'"),
6460 )
6460 )
6461
6461
6462 rev = opts.get('rev')
6462 rev = opts.get('rev')
6463 if rev:
6463 if rev:
6464 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6464 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6465 ctx = logcmdutil.revsingle(repo, rev)
6465 ctx = logcmdutil.revsingle(repo, rev)
6466
6466
6467 if not (
6467 if not (
6468 pats
6468 pats
6469 or opts.get('include')
6469 or opts.get('include')
6470 or opts.get('exclude')
6470 or opts.get('exclude')
6471 or opts.get('all')
6471 or opts.get('all')
6472 or opts.get('interactive')
6472 or opts.get('interactive')
6473 ):
6473 ):
6474 msg = _(b"no files or directories specified")
6474 msg = _(b"no files or directories specified")
6475 if p2 != repo.nullid:
6475 if p2 != repo.nullid:
6476 hint = _(
6476 hint = _(
6477 b"uncommitted merge, use --all to discard all changes,"
6477 b"uncommitted merge, use --all to discard all changes,"
6478 b" or 'hg update -C .' to abort the merge"
6478 b" or 'hg update -C .' to abort the merge"
6479 )
6479 )
6480 raise error.InputError(msg, hint=hint)
6480 raise error.InputError(msg, hint=hint)
6481 dirty = any(repo.status())
6481 dirty = any(repo.status())
6482 node = ctx.node()
6482 node = ctx.node()
6483 if node != parent:
6483 if node != parent:
6484 if dirty:
6484 if dirty:
6485 hint = (
6485 hint = (
6486 _(
6486 _(
6487 b"uncommitted changes, use --all to discard all"
6487 b"uncommitted changes, use --all to discard all"
6488 b" changes, or 'hg update %d' to update"
6488 b" changes, or 'hg update %d' to update"
6489 )
6489 )
6490 % ctx.rev()
6490 % ctx.rev()
6491 )
6491 )
6492 else:
6492 else:
6493 hint = (
6493 hint = (
6494 _(
6494 _(
6495 b"use --all to revert all files,"
6495 b"use --all to revert all files,"
6496 b" or 'hg update %d' to update"
6496 b" or 'hg update %d' to update"
6497 )
6497 )
6498 % ctx.rev()
6498 % ctx.rev()
6499 )
6499 )
6500 elif dirty:
6500 elif dirty:
6501 hint = _(b"uncommitted changes, use --all to discard all changes")
6501 hint = _(b"uncommitted changes, use --all to discard all changes")
6502 else:
6502 else:
6503 hint = _(b"use --all to revert all files")
6503 hint = _(b"use --all to revert all files")
6504 raise error.InputError(msg, hint=hint)
6504 raise error.InputError(msg, hint=hint)
6505
6505
6506 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6506 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6507
6507
6508
6508
6509 @command(
6509 @command(
6510 b'rollback',
6510 b'rollback',
6511 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6511 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6512 helpcategory=command.CATEGORY_MAINTENANCE,
6512 helpcategory=command.CATEGORY_MAINTENANCE,
6513 )
6513 )
6514 def rollback(ui, repo, **opts):
6514 def rollback(ui, repo, **opts):
6515 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6515 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6516
6516
6517 Please use :hg:`commit --amend` instead of rollback to correct
6517 Please use :hg:`commit --amend` instead of rollback to correct
6518 mistakes in the last commit.
6518 mistakes in the last commit.
6519
6519
6520 This command should be used with care. There is only one level of
6520 This command should be used with care. There is only one level of
6521 rollback, and there is no way to undo a rollback. It will also
6521 rollback, and there is no way to undo a rollback. It will also
6522 restore the dirstate at the time of the last transaction, losing
6522 restore the dirstate at the time of the last transaction, losing
6523 any dirstate changes since that time. This command does not alter
6523 any dirstate changes since that time. This command does not alter
6524 the working directory.
6524 the working directory.
6525
6525
6526 Transactions are used to encapsulate the effects of all commands
6526 Transactions are used to encapsulate the effects of all commands
6527 that create new changesets or propagate existing changesets into a
6527 that create new changesets or propagate existing changesets into a
6528 repository.
6528 repository.
6529
6529
6530 .. container:: verbose
6530 .. container:: verbose
6531
6531
6532 For example, the following commands are transactional, and their
6532 For example, the following commands are transactional, and their
6533 effects can be rolled back:
6533 effects can be rolled back:
6534
6534
6535 - commit
6535 - commit
6536 - import
6536 - import
6537 - pull
6537 - pull
6538 - push (with this repository as the destination)
6538 - push (with this repository as the destination)
6539 - unbundle
6539 - unbundle
6540
6540
6541 To avoid permanent data loss, rollback will refuse to rollback a
6541 To avoid permanent data loss, rollback will refuse to rollback a
6542 commit transaction if it isn't checked out. Use --force to
6542 commit transaction if it isn't checked out. Use --force to
6543 override this protection.
6543 override this protection.
6544
6544
6545 The rollback command can be entirely disabled by setting the
6545 The rollback command can be entirely disabled by setting the
6546 ``ui.rollback`` configuration setting to false. If you're here
6546 ``ui.rollback`` configuration setting to false. If you're here
6547 because you want to use rollback and it's disabled, you can
6547 because you want to use rollback and it's disabled, you can
6548 re-enable the command by setting ``ui.rollback`` to true.
6548 re-enable the command by setting ``ui.rollback`` to true.
6549
6549
6550 This command is not intended for use on public repositories. Once
6550 This command is not intended for use on public repositories. Once
6551 changes are visible for pull by other users, rolling a transaction
6551 changes are visible for pull by other users, rolling a transaction
6552 back locally is ineffective (someone else may already have pulled
6552 back locally is ineffective (someone else may already have pulled
6553 the changes). Furthermore, a race is possible with readers of the
6553 the changes). Furthermore, a race is possible with readers of the
6554 repository; for example an in-progress pull from the repository
6554 repository; for example an in-progress pull from the repository
6555 may fail if a rollback is performed.
6555 may fail if a rollback is performed.
6556
6556
6557 Returns 0 on success, 1 if no rollback data is available.
6557 Returns 0 on success, 1 if no rollback data is available.
6558 """
6558 """
6559 if not ui.configbool(b'ui', b'rollback'):
6559 if not ui.configbool(b'ui', b'rollback'):
6560 raise error.Abort(
6560 raise error.Abort(
6561 _(b'rollback is disabled because it is unsafe'),
6561 _(b'rollback is disabled because it is unsafe'),
6562 hint=b'see `hg help -v rollback` for information',
6562 hint=b'see `hg help -v rollback` for information',
6563 )
6563 )
6564 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6564 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6565
6565
6566
6566
6567 @command(
6567 @command(
6568 b'root',
6568 b'root',
6569 [] + formatteropts,
6569 [] + formatteropts,
6570 intents={INTENT_READONLY},
6570 intents={INTENT_READONLY},
6571 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6571 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6572 )
6572 )
6573 def root(ui, repo, **opts):
6573 def root(ui, repo, **opts):
6574 """print the root (top) of the current working directory
6574 """print the root (top) of the current working directory
6575
6575
6576 Print the root directory of the current repository.
6576 Print the root directory of the current repository.
6577
6577
6578 .. container:: verbose
6578 .. container:: verbose
6579
6579
6580 Template:
6580 Template:
6581
6581
6582 The following keywords are supported in addition to the common template
6582 The following keywords are supported in addition to the common template
6583 keywords and functions. See also :hg:`help templates`.
6583 keywords and functions. See also :hg:`help templates`.
6584
6584
6585 :hgpath: String. Path to the .hg directory.
6585 :hgpath: String. Path to the .hg directory.
6586 :storepath: String. Path to the directory holding versioned data.
6586 :storepath: String. Path to the directory holding versioned data.
6587
6587
6588 Returns 0 on success.
6588 Returns 0 on success.
6589 """
6589 """
6590 opts = pycompat.byteskwargs(opts)
6590 opts = pycompat.byteskwargs(opts)
6591 with ui.formatter(b'root', opts) as fm:
6591 with ui.formatter(b'root', opts) as fm:
6592 fm.startitem()
6592 fm.startitem()
6593 fm.write(b'reporoot', b'%s\n', repo.root)
6593 fm.write(b'reporoot', b'%s\n', repo.root)
6594 fm.data(hgpath=repo.path, storepath=repo.spath)
6594 fm.data(hgpath=repo.path, storepath=repo.spath)
6595
6595
6596
6596
6597 @command(
6597 @command(
6598 b'serve',
6598 b'serve',
6599 [
6599 [
6600 (
6600 (
6601 b'A',
6601 b'A',
6602 b'accesslog',
6602 b'accesslog',
6603 b'',
6603 b'',
6604 _(b'name of access log file to write to'),
6604 _(b'name of access log file to write to'),
6605 _(b'FILE'),
6605 _(b'FILE'),
6606 ),
6606 ),
6607 (b'd', b'daemon', None, _(b'run server in background')),
6607 (b'd', b'daemon', None, _(b'run server in background')),
6608 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6608 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6609 (
6609 (
6610 b'E',
6610 b'E',
6611 b'errorlog',
6611 b'errorlog',
6612 b'',
6612 b'',
6613 _(b'name of error log file to write to'),
6613 _(b'name of error log file to write to'),
6614 _(b'FILE'),
6614 _(b'FILE'),
6615 ),
6615 ),
6616 # use string type, then we can check if something was passed
6616 # use string type, then we can check if something was passed
6617 (
6617 (
6618 b'p',
6618 b'p',
6619 b'port',
6619 b'port',
6620 b'',
6620 b'',
6621 _(b'port to listen on (default: 8000)'),
6621 _(b'port to listen on (default: 8000)'),
6622 _(b'PORT'),
6622 _(b'PORT'),
6623 ),
6623 ),
6624 (
6624 (
6625 b'a',
6625 b'a',
6626 b'address',
6626 b'address',
6627 b'',
6627 b'',
6628 _(b'address to listen on (default: all interfaces)'),
6628 _(b'address to listen on (default: all interfaces)'),
6629 _(b'ADDR'),
6629 _(b'ADDR'),
6630 ),
6630 ),
6631 (
6631 (
6632 b'',
6632 b'',
6633 b'prefix',
6633 b'prefix',
6634 b'',
6634 b'',
6635 _(b'prefix path to serve from (default: server root)'),
6635 _(b'prefix path to serve from (default: server root)'),
6636 _(b'PREFIX'),
6636 _(b'PREFIX'),
6637 ),
6637 ),
6638 (
6638 (
6639 b'n',
6639 b'n',
6640 b'name',
6640 b'name',
6641 b'',
6641 b'',
6642 _(b'name to show in web pages (default: working directory)'),
6642 _(b'name to show in web pages (default: working directory)'),
6643 _(b'NAME'),
6643 _(b'NAME'),
6644 ),
6644 ),
6645 (
6645 (
6646 b'',
6646 b'',
6647 b'web-conf',
6647 b'web-conf',
6648 b'',
6648 b'',
6649 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6649 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6650 _(b'FILE'),
6650 _(b'FILE'),
6651 ),
6651 ),
6652 (
6652 (
6653 b'',
6653 b'',
6654 b'webdir-conf',
6654 b'webdir-conf',
6655 b'',
6655 b'',
6656 _(b'name of the hgweb config file (DEPRECATED)'),
6656 _(b'name of the hgweb config file (DEPRECATED)'),
6657 _(b'FILE'),
6657 _(b'FILE'),
6658 ),
6658 ),
6659 (
6659 (
6660 b'',
6660 b'',
6661 b'pid-file',
6661 b'pid-file',
6662 b'',
6662 b'',
6663 _(b'name of file to write process ID to'),
6663 _(b'name of file to write process ID to'),
6664 _(b'FILE'),
6664 _(b'FILE'),
6665 ),
6665 ),
6666 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6666 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6667 (
6667 (
6668 b'',
6668 b'',
6669 b'cmdserver',
6669 b'cmdserver',
6670 b'',
6670 b'',
6671 _(b'for remote clients (ADVANCED)'),
6671 _(b'for remote clients (ADVANCED)'),
6672 _(b'MODE'),
6672 _(b'MODE'),
6673 ),
6673 ),
6674 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6674 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6675 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6675 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6676 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6676 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6677 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6677 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6678 (b'', b'print-url', None, _(b'start and print only the URL')),
6678 (b'', b'print-url', None, _(b'start and print only the URL')),
6679 ]
6679 ]
6680 + subrepoopts,
6680 + subrepoopts,
6681 _(b'[OPTION]...'),
6681 _(b'[OPTION]...'),
6682 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6682 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6683 helpbasic=True,
6683 helpbasic=True,
6684 optionalrepo=True,
6684 optionalrepo=True,
6685 )
6685 )
6686 def serve(ui, repo, **opts):
6686 def serve(ui, repo, **opts):
6687 """start stand-alone webserver
6687 """start stand-alone webserver
6688
6688
6689 Start a local HTTP repository browser and pull server. You can use
6689 Start a local HTTP repository browser and pull server. You can use
6690 this for ad-hoc sharing and browsing of repositories. It is
6690 this for ad-hoc sharing and browsing of repositories. It is
6691 recommended to use a real web server to serve a repository for
6691 recommended to use a real web server to serve a repository for
6692 longer periods of time.
6692 longer periods of time.
6693
6693
6694 Please note that the server does not implement access control.
6694 Please note that the server does not implement access control.
6695 This means that, by default, anybody can read from the server and
6695 This means that, by default, anybody can read from the server and
6696 nobody can write to it by default. Set the ``web.allow-push``
6696 nobody can write to it by default. Set the ``web.allow-push``
6697 option to ``*`` to allow everybody to push to the server. You
6697 option to ``*`` to allow everybody to push to the server. You
6698 should use a real web server if you need to authenticate users.
6698 should use a real web server if you need to authenticate users.
6699
6699
6700 By default, the server logs accesses to stdout and errors to
6700 By default, the server logs accesses to stdout and errors to
6701 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6701 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6702 files.
6702 files.
6703
6703
6704 To have the server choose a free port number to listen on, specify
6704 To have the server choose a free port number to listen on, specify
6705 a port number of 0; in this case, the server will print the port
6705 a port number of 0; in this case, the server will print the port
6706 number it uses.
6706 number it uses.
6707
6707
6708 Returns 0 on success.
6708 Returns 0 on success.
6709 """
6709 """
6710
6710
6711 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6711 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6712 opts = pycompat.byteskwargs(opts)
6712 opts = pycompat.byteskwargs(opts)
6713 if opts[b"print_url"] and ui.verbose:
6713 if opts[b"print_url"] and ui.verbose:
6714 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6714 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6715
6715
6716 if opts[b"stdio"]:
6716 if opts[b"stdio"]:
6717 if repo is None:
6717 if repo is None:
6718 raise error.RepoError(
6718 raise error.RepoError(
6719 _(b"there is no Mercurial repository here (.hg not found)")
6719 _(b"there is no Mercurial repository here (.hg not found)")
6720 )
6720 )
6721 accesshidden = False
6721 accesshidden = False
6722 if repo.filtername is None:
6722 if repo.filtername is None:
6723 allow = ui.configlist(
6723 allow = ui.configlist(
6724 b'experimental', b'server.allow-hidden-access'
6724 b'experimental', b'server.allow-hidden-access'
6725 )
6725 )
6726 user = procutil.getuser()
6726 user = procutil.getuser()
6727 if allow and scmutil.ismember(ui, user, allow):
6727 if allow and scmutil.ismember(ui, user, allow):
6728 accesshidden = True
6728 accesshidden = True
6729 else:
6729 else:
6730 msg = (
6730 msg = (
6731 _(
6731 _(
6732 b'ignoring request to access hidden changeset by '
6732 b'ignoring request to access hidden changeset by '
6733 b'unauthorized user: %s\n'
6733 b'unauthorized user: %s\n'
6734 )
6734 )
6735 % user
6735 % user
6736 )
6736 )
6737 ui.warn(msg)
6737 ui.warn(msg)
6738
6738
6739 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6739 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6740 s.serve_forever()
6740 s.serve_forever()
6741 return
6741 return
6742
6742
6743 service = server.createservice(ui, repo, opts)
6743 service = server.createservice(ui, repo, opts)
6744 return server.runservice(opts, initfn=service.init, runfn=service.run)
6744 return server.runservice(opts, initfn=service.init, runfn=service.run)
6745
6745
6746
6746
6747 @command(
6747 @command(
6748 b'shelve',
6748 b'shelve',
6749 [
6749 [
6750 (
6750 (
6751 b'A',
6751 b'A',
6752 b'addremove',
6752 b'addremove',
6753 None,
6753 None,
6754 _(b'mark new/missing files as added/removed before shelving'),
6754 _(b'mark new/missing files as added/removed before shelving'),
6755 ),
6755 ),
6756 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6756 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6757 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6757 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6758 (
6758 (
6759 b'',
6759 b'',
6760 b'date',
6760 b'date',
6761 b'',
6761 b'',
6762 _(b'shelve with the specified commit date'),
6762 _(b'shelve with the specified commit date'),
6763 _(b'DATE'),
6763 _(b'DATE'),
6764 ),
6764 ),
6765 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6765 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6766 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6766 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6767 (
6767 (
6768 b'k',
6768 b'k',
6769 b'keep',
6769 b'keep',
6770 False,
6770 False,
6771 _(b'shelve, but keep changes in the working directory'),
6771 _(b'shelve, but keep changes in the working directory'),
6772 ),
6772 ),
6773 (b'l', b'list', None, _(b'list current shelves')),
6773 (b'l', b'list', None, _(b'list current shelves')),
6774 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6774 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6775 (
6775 (
6776 b'n',
6776 b'n',
6777 b'name',
6777 b'name',
6778 b'',
6778 b'',
6779 _(b'use the given name for the shelved commit'),
6779 _(b'use the given name for the shelved commit'),
6780 _(b'NAME'),
6780 _(b'NAME'),
6781 ),
6781 ),
6782 (
6782 (
6783 b'p',
6783 b'p',
6784 b'patch',
6784 b'patch',
6785 None,
6785 None,
6786 _(
6786 _(
6787 b'output patches for changes (provide the names of the shelved '
6787 b'output patches for changes (provide the names of the shelved '
6788 b'changes as positional arguments)'
6788 b'changes as positional arguments)'
6789 ),
6789 ),
6790 ),
6790 ),
6791 (b'i', b'interactive', None, _(b'interactive mode')),
6791 (b'i', b'interactive', None, _(b'interactive mode')),
6792 (
6792 (
6793 b'',
6793 b'',
6794 b'stat',
6794 b'stat',
6795 None,
6795 None,
6796 _(
6796 _(
6797 b'output diffstat-style summary of changes (provide the names of '
6797 b'output diffstat-style summary of changes (provide the names of '
6798 b'the shelved changes as positional arguments)'
6798 b'the shelved changes as positional arguments)'
6799 ),
6799 ),
6800 ),
6800 ),
6801 ]
6801 ]
6802 + cmdutil.walkopts,
6802 + cmdutil.walkopts,
6803 _(b'hg shelve [OPTION]... [FILE]...'),
6803 _(b'hg shelve [OPTION]... [FILE]...'),
6804 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6804 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6805 )
6805 )
6806 def shelve(ui, repo, *pats, **opts):
6806 def shelve(ui, repo, *pats, **opts):
6807 """save and set aside changes from the working directory
6807 """save and set aside changes from the working directory
6808
6808
6809 Shelving takes files that "hg status" reports as not clean, saves
6809 Shelving takes files that "hg status" reports as not clean, saves
6810 the modifications to a bundle (a shelved change), and reverts the
6810 the modifications to a bundle (a shelved change), and reverts the
6811 files so that their state in the working directory becomes clean.
6811 files so that their state in the working directory becomes clean.
6812
6812
6813 To restore these changes to the working directory, using "hg
6813 To restore these changes to the working directory, using "hg
6814 unshelve"; this will work even if you switch to a different
6814 unshelve"; this will work even if you switch to a different
6815 commit.
6815 commit.
6816
6816
6817 When no files are specified, "hg shelve" saves all not-clean
6817 When no files are specified, "hg shelve" saves all not-clean
6818 files. If specific files or directories are named, only changes to
6818 files. If specific files or directories are named, only changes to
6819 those files are shelved.
6819 those files are shelved.
6820
6820
6821 In bare shelve (when no files are specified, without interactive,
6821 In bare shelve (when no files are specified, without interactive,
6822 include and exclude option), shelving remembers information if the
6822 include and exclude option), shelving remembers information if the
6823 working directory was on newly created branch, in other words working
6823 working directory was on newly created branch, in other words working
6824 directory was on different branch than its first parent. In this
6824 directory was on different branch than its first parent. In this
6825 situation unshelving restores branch information to the working directory.
6825 situation unshelving restores branch information to the working directory.
6826
6826
6827 Each shelved change has a name that makes it easier to find later.
6827 Each shelved change has a name that makes it easier to find later.
6828 The name of a shelved change defaults to being based on the active
6828 The name of a shelved change defaults to being based on the active
6829 bookmark, or if there is no active bookmark, the current named
6829 bookmark, or if there is no active bookmark, the current named
6830 branch. To specify a different name, use ``--name``.
6830 branch. To specify a different name, use ``--name``.
6831
6831
6832 To see a list of existing shelved changes, use the ``--list``
6832 To see a list of existing shelved changes, use the ``--list``
6833 option. For each shelved change, this will print its name, age,
6833 option. For each shelved change, this will print its name, age,
6834 and description; use ``--patch`` or ``--stat`` for more details.
6834 and description; use ``--patch`` or ``--stat`` for more details.
6835
6835
6836 To delete specific shelved changes, use ``--delete``. To delete
6836 To delete specific shelved changes, use ``--delete``. To delete
6837 all shelved changes, use ``--cleanup``.
6837 all shelved changes, use ``--cleanup``.
6838 """
6838 """
6839 opts = pycompat.byteskwargs(opts)
6839 opts = pycompat.byteskwargs(opts)
6840 allowables = [
6840 allowables = [
6841 (b'addremove', {b'create'}), # 'create' is pseudo action
6841 (b'addremove', {b'create'}), # 'create' is pseudo action
6842 (b'unknown', {b'create'}),
6842 (b'unknown', {b'create'}),
6843 (b'cleanup', {b'cleanup'}),
6843 (b'cleanup', {b'cleanup'}),
6844 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6844 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6845 (b'delete', {b'delete'}),
6845 (b'delete', {b'delete'}),
6846 (b'edit', {b'create'}),
6846 (b'edit', {b'create'}),
6847 (b'keep', {b'create'}),
6847 (b'keep', {b'create'}),
6848 (b'list', {b'list'}),
6848 (b'list', {b'list'}),
6849 (b'message', {b'create'}),
6849 (b'message', {b'create'}),
6850 (b'name', {b'create'}),
6850 (b'name', {b'create'}),
6851 (b'patch', {b'patch', b'list'}),
6851 (b'patch', {b'patch', b'list'}),
6852 (b'stat', {b'stat', b'list'}),
6852 (b'stat', {b'stat', b'list'}),
6853 ]
6853 ]
6854
6854
6855 def checkopt(opt):
6855 def checkopt(opt):
6856 if opts.get(opt):
6856 if opts.get(opt):
6857 for i, allowable in allowables:
6857 for i, allowable in allowables:
6858 if opts[i] and opt not in allowable:
6858 if opts[i] and opt not in allowable:
6859 raise error.InputError(
6859 raise error.InputError(
6860 _(
6860 _(
6861 b"options '--%s' and '--%s' may not be "
6861 b"options '--%s' and '--%s' may not be "
6862 b"used together"
6862 b"used together"
6863 )
6863 )
6864 % (opt, i)
6864 % (opt, i)
6865 )
6865 )
6866 return True
6866 return True
6867
6867
6868 if checkopt(b'cleanup'):
6868 if checkopt(b'cleanup'):
6869 if pats:
6869 if pats:
6870 raise error.InputError(
6870 raise error.InputError(
6871 _(b"cannot specify names when using '--cleanup'")
6871 _(b"cannot specify names when using '--cleanup'")
6872 )
6872 )
6873 return shelvemod.cleanupcmd(ui, repo)
6873 return shelvemod.cleanupcmd(ui, repo)
6874 elif checkopt(b'delete'):
6874 elif checkopt(b'delete'):
6875 return shelvemod.deletecmd(ui, repo, pats)
6875 return shelvemod.deletecmd(ui, repo, pats)
6876 elif checkopt(b'list'):
6876 elif checkopt(b'list'):
6877 return shelvemod.listcmd(ui, repo, pats, opts)
6877 return shelvemod.listcmd(ui, repo, pats, opts)
6878 elif checkopt(b'patch') or checkopt(b'stat'):
6878 elif checkopt(b'patch') or checkopt(b'stat'):
6879 return shelvemod.patchcmds(ui, repo, pats, opts)
6879 return shelvemod.patchcmds(ui, repo, pats, opts)
6880 else:
6880 else:
6881 return shelvemod.createcmd(ui, repo, pats, opts)
6881 return shelvemod.createcmd(ui, repo, pats, opts)
6882
6882
6883
6883
6884 _NOTTERSE = b'nothing'
6884 _NOTTERSE = b'nothing'
6885
6885
6886
6886
6887 @command(
6887 @command(
6888 b'status|st',
6888 b'status|st',
6889 [
6889 [
6890 (b'A', b'all', None, _(b'show status of all files')),
6890 (b'A', b'all', None, _(b'show status of all files')),
6891 (b'm', b'modified', None, _(b'show only modified files')),
6891 (b'm', b'modified', None, _(b'show only modified files')),
6892 (b'a', b'added', None, _(b'show only added files')),
6892 (b'a', b'added', None, _(b'show only added files')),
6893 (b'r', b'removed', None, _(b'show only removed files')),
6893 (b'r', b'removed', None, _(b'show only removed files')),
6894 (b'd', b'deleted', None, _(b'show only missing files')),
6894 (b'd', b'deleted', None, _(b'show only missing files')),
6895 (b'c', b'clean', None, _(b'show only files without changes')),
6895 (b'c', b'clean', None, _(b'show only files without changes')),
6896 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6896 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6897 (b'i', b'ignored', None, _(b'show only ignored files')),
6897 (b'i', b'ignored', None, _(b'show only ignored files')),
6898 (b'n', b'no-status', None, _(b'hide status prefix')),
6898 (b'n', b'no-status', None, _(b'hide status prefix')),
6899 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6899 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6900 (
6900 (
6901 b'C',
6901 b'C',
6902 b'copies',
6902 b'copies',
6903 None,
6903 None,
6904 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6904 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6905 ),
6905 ),
6906 (
6906 (
6907 b'0',
6907 b'0',
6908 b'print0',
6908 b'print0',
6909 None,
6909 None,
6910 _(b'end filenames with NUL, for use with xargs'),
6910 _(b'end filenames with NUL, for use with xargs'),
6911 ),
6911 ),
6912 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6912 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6913 (
6913 (
6914 b'',
6914 b'',
6915 b'change',
6915 b'change',
6916 b'',
6916 b'',
6917 _(b'list the changed files of a revision'),
6917 _(b'list the changed files of a revision'),
6918 _(b'REV'),
6918 _(b'REV'),
6919 ),
6919 ),
6920 ]
6920 ]
6921 + walkopts
6921 + walkopts
6922 + subrepoopts
6922 + subrepoopts
6923 + formatteropts,
6923 + formatteropts,
6924 _(b'[OPTION]... [FILE]...'),
6924 _(b'[OPTION]... [FILE]...'),
6925 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6925 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6926 helpbasic=True,
6926 helpbasic=True,
6927 inferrepo=True,
6927 inferrepo=True,
6928 intents={INTENT_READONLY},
6928 intents={INTENT_READONLY},
6929 )
6929 )
6930 def status(ui, repo, *pats, **opts):
6930 def status(ui, repo, *pats, **opts):
6931 """show changed files in the working directory
6931 """show changed files in the working directory
6932
6932
6933 Show status of files in the repository. If names are given, only
6933 Show status of files in the repository. If names are given, only
6934 files that match are shown. Files that are clean or ignored or
6934 files that match are shown. Files that are clean or ignored or
6935 the source of a copy/move operation, are not listed unless
6935 the source of a copy/move operation, are not listed unless
6936 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6936 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6937 Unless options described with "show only ..." are given, the
6937 Unless options described with "show only ..." are given, the
6938 options -mardu are used.
6938 options -mardu are used.
6939
6939
6940 Option -q/--quiet hides untracked (unknown and ignored) files
6940 Option -q/--quiet hides untracked (unknown and ignored) files
6941 unless explicitly requested with -u/--unknown or -i/--ignored.
6941 unless explicitly requested with -u/--unknown or -i/--ignored.
6942
6942
6943 .. note::
6943 .. note::
6944
6944
6945 :hg:`status` may appear to disagree with diff if permissions have
6945 :hg:`status` may appear to disagree with diff if permissions have
6946 changed or a merge has occurred. The standard diff format does
6946 changed or a merge has occurred. The standard diff format does
6947 not report permission changes and diff only reports changes
6947 not report permission changes and diff only reports changes
6948 relative to one merge parent.
6948 relative to one merge parent.
6949
6949
6950 If one revision is given, it is used as the base revision.
6950 If one revision is given, it is used as the base revision.
6951 If two revisions are given, the differences between them are
6951 If two revisions are given, the differences between them are
6952 shown. The --change option can also be used as a shortcut to list
6952 shown. The --change option can also be used as a shortcut to list
6953 the changed files of a revision from its first parent.
6953 the changed files of a revision from its first parent.
6954
6954
6955 The codes used to show the status of files are::
6955 The codes used to show the status of files are::
6956
6956
6957 M = modified
6957 M = modified
6958 A = added
6958 A = added
6959 R = removed
6959 R = removed
6960 C = clean
6960 C = clean
6961 ! = missing (deleted by non-hg command, but still tracked)
6961 ! = missing (deleted by non-hg command, but still tracked)
6962 ? = not tracked
6962 ? = not tracked
6963 I = ignored
6963 I = ignored
6964 = origin of the previous file (with --copies)
6964 = origin of the previous file (with --copies)
6965
6965
6966 .. container:: verbose
6966 .. container:: verbose
6967
6967
6968 The -t/--terse option abbreviates the output by showing only the directory
6968 The -t/--terse option abbreviates the output by showing only the directory
6969 name if all the files in it share the same status. The option takes an
6969 name if all the files in it share the same status. The option takes an
6970 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6970 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6971 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6971 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6972 for 'ignored' and 'c' for clean.
6972 for 'ignored' and 'c' for clean.
6973
6973
6974 It abbreviates only those statuses which are passed. Note that clean and
6974 It abbreviates only those statuses which are passed. Note that clean and
6975 ignored files are not displayed with '--terse ic' unless the -c/--clean
6975 ignored files are not displayed with '--terse ic' unless the -c/--clean
6976 and -i/--ignored options are also used.
6976 and -i/--ignored options are also used.
6977
6977
6978 The -v/--verbose option shows information when the repository is in an
6978 The -v/--verbose option shows information when the repository is in an
6979 unfinished merge, shelve, rebase state etc. You can have this behavior
6979 unfinished merge, shelve, rebase state etc. You can have this behavior
6980 turned on by default by enabling the ``commands.status.verbose`` option.
6980 turned on by default by enabling the ``commands.status.verbose`` option.
6981
6981
6982 You can skip displaying some of these states by setting
6982 You can skip displaying some of these states by setting
6983 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6983 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6984 'histedit', 'merge', 'rebase', or 'unshelve'.
6984 'histedit', 'merge', 'rebase', or 'unshelve'.
6985
6985
6986 Template:
6986 Template:
6987
6987
6988 The following keywords are supported in addition to the common template
6988 The following keywords are supported in addition to the common template
6989 keywords and functions. See also :hg:`help templates`.
6989 keywords and functions. See also :hg:`help templates`.
6990
6990
6991 :path: String. Repository-absolute path of the file.
6991 :path: String. Repository-absolute path of the file.
6992 :source: String. Repository-absolute path of the file originated from.
6992 :source: String. Repository-absolute path of the file originated from.
6993 Available if ``--copies`` is specified.
6993 Available if ``--copies`` is specified.
6994 :status: String. Character denoting file's status.
6994 :status: String. Character denoting file's status.
6995
6995
6996 Examples:
6996 Examples:
6997
6997
6998 - show changes in the working directory relative to a
6998 - show changes in the working directory relative to a
6999 changeset::
6999 changeset::
7000
7000
7001 hg status --rev 9353
7001 hg status --rev 9353
7002
7002
7003 - show changes in the working directory relative to the
7003 - show changes in the working directory relative to the
7004 current directory (see :hg:`help patterns` for more information)::
7004 current directory (see :hg:`help patterns` for more information)::
7005
7005
7006 hg status re:
7006 hg status re:
7007
7007
7008 - show all changes including copies in an existing changeset::
7008 - show all changes including copies in an existing changeset::
7009
7009
7010 hg status --copies --change 9353
7010 hg status --copies --change 9353
7011
7011
7012 - get a NUL separated list of added files, suitable for xargs::
7012 - get a NUL separated list of added files, suitable for xargs::
7013
7013
7014 hg status -an0
7014 hg status -an0
7015
7015
7016 - show more information about the repository status, abbreviating
7016 - show more information about the repository status, abbreviating
7017 added, removed, modified, deleted, and untracked paths::
7017 added, removed, modified, deleted, and untracked paths::
7018
7018
7019 hg status -v -t mardu
7019 hg status -v -t mardu
7020
7020
7021 Returns 0 on success.
7021 Returns 0 on success.
7022
7022
7023 """
7023 """
7024
7024
7025 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
7025 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
7026 opts = pycompat.byteskwargs(opts)
7026 opts = pycompat.byteskwargs(opts)
7027 revs = opts.get(b'rev', [])
7027 revs = opts.get(b'rev', [])
7028 change = opts.get(b'change', b'')
7028 change = opts.get(b'change', b'')
7029 terse = opts.get(b'terse', _NOTTERSE)
7029 terse = opts.get(b'terse', _NOTTERSE)
7030 if terse is _NOTTERSE:
7030 if terse is _NOTTERSE:
7031 if revs:
7031 if revs:
7032 terse = b''
7032 terse = b''
7033 else:
7033 else:
7034 terse = ui.config(b'commands', b'status.terse')
7034 terse = ui.config(b'commands', b'status.terse')
7035
7035
7036 if revs and terse:
7036 if revs and terse:
7037 msg = _(b'cannot use --terse with --rev')
7037 msg = _(b'cannot use --terse with --rev')
7038 raise error.InputError(msg)
7038 raise error.InputError(msg)
7039 elif change:
7039 elif change:
7040 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
7040 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
7041 ctx2 = logcmdutil.revsingle(repo, change, None)
7041 ctx2 = logcmdutil.revsingle(repo, change, None)
7042 ctx1 = ctx2.p1()
7042 ctx1 = ctx2.p1()
7043 else:
7043 else:
7044 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7044 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7045 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7045 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7046
7046
7047 forcerelativevalue = None
7047 forcerelativevalue = None
7048 if ui.hasconfig(b'commands', b'status.relative'):
7048 if ui.hasconfig(b'commands', b'status.relative'):
7049 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7049 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7050 uipathfn = scmutil.getuipathfn(
7050 uipathfn = scmutil.getuipathfn(
7051 repo,
7051 repo,
7052 legacyrelativevalue=bool(pats),
7052 legacyrelativevalue=bool(pats),
7053 forcerelativevalue=forcerelativevalue,
7053 forcerelativevalue=forcerelativevalue,
7054 )
7054 )
7055
7055
7056 if opts.get(b'print0'):
7056 if opts.get(b'print0'):
7057 end = b'\0'
7057 end = b'\0'
7058 else:
7058 else:
7059 end = b'\n'
7059 end = b'\n'
7060 states = b'modified added removed deleted unknown ignored clean'.split()
7060 states = b'modified added removed deleted unknown ignored clean'.split()
7061 show = [k for k in states if opts.get(k)]
7061 show = [k for k in states if opts.get(k)]
7062 if opts.get(b'all'):
7062 if opts.get(b'all'):
7063 show += ui.quiet and (states[:4] + [b'clean']) or states
7063 show += ui.quiet and (states[:4] + [b'clean']) or states
7064
7064
7065 if not show:
7065 if not show:
7066 if ui.quiet:
7066 if ui.quiet:
7067 show = states[:4]
7067 show = states[:4]
7068 else:
7068 else:
7069 show = states[:5]
7069 show = states[:5]
7070
7070
7071 m = scmutil.match(ctx2, pats, opts)
7071 m = scmutil.match(ctx2, pats, opts)
7072 if terse:
7072 if terse:
7073 # we need to compute clean and unknown to terse
7073 # we need to compute clean and unknown to terse
7074 stat = repo.status(
7074 stat = repo.status(
7075 ctx1.node(),
7075 ctx1.node(),
7076 ctx2.node(),
7076 ctx2.node(),
7077 m,
7077 m,
7078 b'ignored' in show or b'i' in terse,
7078 b'ignored' in show or b'i' in terse,
7079 clean=True,
7079 clean=True,
7080 unknown=True,
7080 unknown=True,
7081 listsubrepos=opts.get(b'subrepos'),
7081 listsubrepos=opts.get(b'subrepos'),
7082 )
7082 )
7083
7083
7084 stat = cmdutil.tersedir(stat, terse)
7084 stat = cmdutil.tersedir(stat, terse)
7085 else:
7085 else:
7086 stat = repo.status(
7086 stat = repo.status(
7087 ctx1.node(),
7087 ctx1.node(),
7088 ctx2.node(),
7088 ctx2.node(),
7089 m,
7089 m,
7090 b'ignored' in show,
7090 b'ignored' in show,
7091 b'clean' in show,
7091 b'clean' in show,
7092 b'unknown' in show,
7092 b'unknown' in show,
7093 opts.get(b'subrepos'),
7093 opts.get(b'subrepos'),
7094 )
7094 )
7095
7095
7096 changestates = zip(
7096 changestates = zip(
7097 states,
7097 states,
7098 pycompat.iterbytestr(b'MAR!?IC'),
7098 pycompat.iterbytestr(b'MAR!?IC'),
7099 [getattr(stat, s.decode('utf8')) for s in states],
7099 [getattr(stat, s.decode('utf8')) for s in states],
7100 )
7100 )
7101
7101
7102 copy = {}
7102 copy = {}
7103 show_copies = ui.configbool(b'ui', b'statuscopies')
7103 show_copies = ui.configbool(b'ui', b'statuscopies')
7104 if opts.get(b'copies') is not None:
7104 if opts.get(b'copies') is not None:
7105 show_copies = opts.get(b'copies')
7105 show_copies = opts.get(b'copies')
7106 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7106 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7107 b'no_status'
7107 b'no_status'
7108 )
7108 )
7109 if show_copies:
7109 if show_copies:
7110 copy = copies.pathcopies(ctx1, ctx2, m)
7110 copy = copies.pathcopies(ctx1, ctx2, m)
7111
7111
7112 morestatus = None
7112 morestatus = None
7113 if (
7113 if (
7114 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7114 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7115 and not ui.plain()
7115 and not ui.plain()
7116 and not opts.get(b'print0')
7116 and not opts.get(b'print0')
7117 ):
7117 ):
7118 morestatus = cmdutil.readmorestatus(repo)
7118 morestatus = cmdutil.readmorestatus(repo)
7119
7119
7120 ui.pager(b'status')
7120 ui.pager(b'status')
7121 fm = ui.formatter(b'status', opts)
7121 fm = ui.formatter(b'status', opts)
7122 fmt = b'%s' + end
7122 fmt = b'%s' + end
7123 showchar = not opts.get(b'no_status')
7123 showchar = not opts.get(b'no_status')
7124
7124
7125 for state, char, files in changestates:
7125 for state, char, files in changestates:
7126 if state in show:
7126 if state in show:
7127 label = b'status.' + state
7127 label = b'status.' + state
7128 for f in files:
7128 for f in files:
7129 fm.startitem()
7129 fm.startitem()
7130 fm.context(ctx=ctx2)
7130 fm.context(ctx=ctx2)
7131 fm.data(itemtype=b'file', path=f)
7131 fm.data(itemtype=b'file', path=f)
7132 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7132 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7133 fm.plain(fmt % uipathfn(f), label=label)
7133 fm.plain(fmt % uipathfn(f), label=label)
7134 if f in copy:
7134 if f in copy:
7135 fm.data(source=copy[f])
7135 fm.data(source=copy[f])
7136 fm.plain(
7136 fm.plain(
7137 (b' %s' + end) % uipathfn(copy[f]),
7137 (b' %s' + end) % uipathfn(copy[f]),
7138 label=b'status.copied',
7138 label=b'status.copied',
7139 )
7139 )
7140 if morestatus:
7140 if morestatus:
7141 morestatus.formatfile(f, fm)
7141 morestatus.formatfile(f, fm)
7142
7142
7143 if morestatus:
7143 if morestatus:
7144 morestatus.formatfooter(fm)
7144 morestatus.formatfooter(fm)
7145 fm.end()
7145 fm.end()
7146
7146
7147
7147
7148 @command(
7148 @command(
7149 b'summary|sum',
7149 b'summary|sum',
7150 [(b'', b'remote', None, _(b'check for push and pull'))],
7150 [(b'', b'remote', None, _(b'check for push and pull'))],
7151 b'[--remote]',
7151 b'[--remote]',
7152 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7152 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7153 helpbasic=True,
7153 helpbasic=True,
7154 intents={INTENT_READONLY},
7154 intents={INTENT_READONLY},
7155 )
7155 )
7156 def summary(ui, repo, **opts):
7156 def summary(ui, repo, **opts):
7157 """summarize working directory state
7157 """summarize working directory state
7158
7158
7159 This generates a brief summary of the working directory state,
7159 This generates a brief summary of the working directory state,
7160 including parents, branch, commit status, phase and available updates.
7160 including parents, branch, commit status, phase and available updates.
7161
7161
7162 With the --remote option, this will check the default paths for
7162 With the --remote option, this will check the default paths for
7163 incoming and outgoing changes. This can be time-consuming.
7163 incoming and outgoing changes. This can be time-consuming.
7164
7164
7165 Returns 0 on success.
7165 Returns 0 on success.
7166 """
7166 """
7167
7167
7168 ui.pager(b'summary')
7168 ui.pager(b'summary')
7169 ctx = repo[None]
7169 ctx = repo[None]
7170 parents = ctx.parents()
7170 parents = ctx.parents()
7171 pnode = parents[0].node()
7171 pnode = parents[0].node()
7172 marks = []
7172 marks = []
7173
7173
7174 try:
7174 try:
7175 ms = mergestatemod.mergestate.read(repo)
7175 ms = mergestatemod.mergestate.read(repo)
7176 except error.UnsupportedMergeRecords as e:
7176 except error.UnsupportedMergeRecords as e:
7177 s = b' '.join(e.recordtypes)
7177 s = b' '.join(e.recordtypes)
7178 ui.warn(
7178 ui.warn(
7179 _(b'warning: merge state has unsupported record types: %s\n') % s
7179 _(b'warning: merge state has unsupported record types: %s\n') % s
7180 )
7180 )
7181 unresolved = []
7181 unresolved = []
7182 else:
7182 else:
7183 unresolved = list(ms.unresolved())
7183 unresolved = list(ms.unresolved())
7184
7184
7185 for p in parents:
7185 for p in parents:
7186 # label with log.changeset (instead of log.parent) since this
7186 # label with log.changeset (instead of log.parent) since this
7187 # shows a working directory parent *changeset*:
7187 # shows a working directory parent *changeset*:
7188 # i18n: column positioning for "hg summary"
7188 # i18n: column positioning for "hg summary"
7189 ui.write(
7189 ui.write(
7190 _(b'parent: %d:%s ') % (p.rev(), p),
7190 _(b'parent: %d:%s ') % (p.rev(), p),
7191 label=logcmdutil.changesetlabels(p),
7191 label=logcmdutil.changesetlabels(p),
7192 )
7192 )
7193 ui.write(b' '.join(p.tags()), label=b'log.tag')
7193 ui.write(b' '.join(p.tags()), label=b'log.tag')
7194 if p.bookmarks():
7194 if p.bookmarks():
7195 marks.extend(p.bookmarks())
7195 marks.extend(p.bookmarks())
7196 if p.rev() == -1:
7196 if p.rev() == -1:
7197 if not len(repo):
7197 if not len(repo):
7198 ui.write(_(b' (empty repository)'))
7198 ui.write(_(b' (empty repository)'))
7199 else:
7199 else:
7200 ui.write(_(b' (no revision checked out)'))
7200 ui.write(_(b' (no revision checked out)'))
7201 if p.obsolete():
7201 if p.obsolete():
7202 ui.write(_(b' (obsolete)'))
7202 ui.write(_(b' (obsolete)'))
7203 if p.isunstable():
7203 if p.isunstable():
7204 instabilities = (
7204 instabilities = (
7205 ui.label(instability, b'trouble.%s' % instability)
7205 ui.label(instability, b'trouble.%s' % instability)
7206 for instability in p.instabilities()
7206 for instability in p.instabilities()
7207 )
7207 )
7208 ui.write(b' (' + b', '.join(instabilities) + b')')
7208 ui.write(b' (' + b', '.join(instabilities) + b')')
7209 ui.write(b'\n')
7209 ui.write(b'\n')
7210 if p.description():
7210 if p.description():
7211 ui.status(
7211 ui.status(
7212 b' ' + p.description().splitlines()[0].strip() + b'\n',
7212 b' ' + p.description().splitlines()[0].strip() + b'\n',
7213 label=b'log.summary',
7213 label=b'log.summary',
7214 )
7214 )
7215
7215
7216 branch = ctx.branch()
7216 branch = ctx.branch()
7217 bheads = repo.branchheads(branch)
7217 bheads = repo.branchheads(branch)
7218 # i18n: column positioning for "hg summary"
7218 # i18n: column positioning for "hg summary"
7219 m = _(b'branch: %s\n') % branch
7219 m = _(b'branch: %s\n') % branch
7220 if branch != b'default':
7220 if branch != b'default':
7221 ui.write(m, label=b'log.branch')
7221 ui.write(m, label=b'log.branch')
7222 else:
7222 else:
7223 ui.status(m, label=b'log.branch')
7223 ui.status(m, label=b'log.branch')
7224
7224
7225 if marks:
7225 if marks:
7226 active = repo._activebookmark
7226 active = repo._activebookmark
7227 # i18n: column positioning for "hg summary"
7227 # i18n: column positioning for "hg summary"
7228 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7228 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7229 if active is not None:
7229 if active is not None:
7230 if active in marks:
7230 if active in marks:
7231 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7231 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7232 marks.remove(active)
7232 marks.remove(active)
7233 else:
7233 else:
7234 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7234 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7235 for m in marks:
7235 for m in marks:
7236 ui.write(b' ' + m, label=b'log.bookmark')
7236 ui.write(b' ' + m, label=b'log.bookmark')
7237 ui.write(b'\n', label=b'log.bookmark')
7237 ui.write(b'\n', label=b'log.bookmark')
7238
7238
7239 status = repo.status(unknown=True)
7239 status = repo.status(unknown=True)
7240
7240
7241 c = repo.dirstate.copies()
7241 c = repo.dirstate.copies()
7242 copied, renamed = [], []
7242 copied, renamed = [], []
7243 for d, s in c.items():
7243 for d, s in c.items():
7244 if s in status.removed:
7244 if s in status.removed:
7245 status.removed.remove(s)
7245 status.removed.remove(s)
7246 renamed.append(d)
7246 renamed.append(d)
7247 else:
7247 else:
7248 copied.append(d)
7248 copied.append(d)
7249 if d in status.added:
7249 if d in status.added:
7250 status.added.remove(d)
7250 status.added.remove(d)
7251
7251
7252 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7252 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7253
7253
7254 labels = [
7254 labels = [
7255 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7255 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7256 (ui.label(_(b'%d added'), b'status.added'), status.added),
7256 (ui.label(_(b'%d added'), b'status.added'), status.added),
7257 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7257 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7258 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7258 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7259 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7259 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7260 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7260 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7261 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7261 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7262 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7262 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7263 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7263 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7264 ]
7264 ]
7265 t = []
7265 t = []
7266 for l, s in labels:
7266 for l, s in labels:
7267 if s:
7267 if s:
7268 t.append(l % len(s))
7268 t.append(l % len(s))
7269
7269
7270 t = b', '.join(t)
7270 t = b', '.join(t)
7271 cleanworkdir = False
7271 cleanworkdir = False
7272
7272
7273 if repo.vfs.exists(b'graftstate'):
7273 if repo.vfs.exists(b'graftstate'):
7274 t += _(b' (graft in progress)')
7274 t += _(b' (graft in progress)')
7275 if repo.vfs.exists(b'updatestate'):
7275 if repo.vfs.exists(b'updatestate'):
7276 t += _(b' (interrupted update)')
7276 t += _(b' (interrupted update)')
7277 elif len(parents) > 1:
7277 elif len(parents) > 1:
7278 t += _(b' (merge)')
7278 t += _(b' (merge)')
7279 elif branch != parents[0].branch():
7279 elif branch != parents[0].branch():
7280 t += _(b' (new branch)')
7280 t += _(b' (new branch)')
7281 elif parents[0].closesbranch() and pnode in repo.branchheads(
7281 elif parents[0].closesbranch() and pnode in repo.branchheads(
7282 branch, closed=True
7282 branch, closed=True
7283 ):
7283 ):
7284 t += _(b' (head closed)')
7284 t += _(b' (head closed)')
7285 elif not (
7285 elif not (
7286 status.modified
7286 status.modified
7287 or status.added
7287 or status.added
7288 or status.removed
7288 or status.removed
7289 or renamed
7289 or renamed
7290 or copied
7290 or copied
7291 or subs
7291 or subs
7292 ):
7292 ):
7293 t += _(b' (clean)')
7293 t += _(b' (clean)')
7294 cleanworkdir = True
7294 cleanworkdir = True
7295 elif pnode not in bheads:
7295 elif pnode not in bheads:
7296 t += _(b' (new branch head)')
7296 t += _(b' (new branch head)')
7297
7297
7298 if parents:
7298 if parents:
7299 pendingphase = max(p.phase() for p in parents)
7299 pendingphase = max(p.phase() for p in parents)
7300 else:
7300 else:
7301 pendingphase = phases.public
7301 pendingphase = phases.public
7302
7302
7303 if pendingphase > phases.newcommitphase(ui):
7303 if pendingphase > phases.newcommitphase(ui):
7304 t += b' (%s)' % phases.phasenames[pendingphase]
7304 t += b' (%s)' % phases.phasenames[pendingphase]
7305
7305
7306 if cleanworkdir:
7306 if cleanworkdir:
7307 # i18n: column positioning for "hg summary"
7307 # i18n: column positioning for "hg summary"
7308 ui.status(_(b'commit: %s\n') % t.strip())
7308 ui.status(_(b'commit: %s\n') % t.strip())
7309 else:
7309 else:
7310 # i18n: column positioning for "hg summary"
7310 # i18n: column positioning for "hg summary"
7311 ui.write(_(b'commit: %s\n') % t.strip())
7311 ui.write(_(b'commit: %s\n') % t.strip())
7312
7312
7313 # all ancestors of branch heads - all ancestors of parent = new csets
7313 # all ancestors of branch heads - all ancestors of parent = new csets
7314 new = len(
7314 new = len(
7315 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7315 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7316 )
7316 )
7317
7317
7318 if new == 0:
7318 if new == 0:
7319 # i18n: column positioning for "hg summary"
7319 # i18n: column positioning for "hg summary"
7320 ui.status(_(b'update: (current)\n'))
7320 ui.status(_(b'update: (current)\n'))
7321 elif pnode not in bheads:
7321 elif pnode not in bheads:
7322 # i18n: column positioning for "hg summary"
7322 # i18n: column positioning for "hg summary"
7323 ui.write(_(b'update: %d new changesets (update)\n') % new)
7323 ui.write(_(b'update: %d new changesets (update)\n') % new)
7324 else:
7324 else:
7325 # i18n: column positioning for "hg summary"
7325 # i18n: column positioning for "hg summary"
7326 ui.write(
7326 ui.write(
7327 _(b'update: %d new changesets, %d branch heads (merge)\n')
7327 _(b'update: %d new changesets, %d branch heads (merge)\n')
7328 % (new, len(bheads))
7328 % (new, len(bheads))
7329 )
7329 )
7330
7330
7331 t = []
7331 t = []
7332 draft = len(repo.revs(b'draft()'))
7332 draft = len(repo.revs(b'draft()'))
7333 if draft:
7333 if draft:
7334 t.append(_(b'%d draft') % draft)
7334 t.append(_(b'%d draft') % draft)
7335 secret = len(repo.revs(b'secret()'))
7335 secret = len(repo.revs(b'secret()'))
7336 if secret:
7336 if secret:
7337 t.append(_(b'%d secret') % secret)
7337 t.append(_(b'%d secret') % secret)
7338
7338
7339 if draft or secret:
7339 if draft or secret:
7340 ui.status(_(b'phases: %s\n') % b', '.join(t))
7340 ui.status(_(b'phases: %s\n') % b', '.join(t))
7341
7341
7342 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7342 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7343 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7343 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7344 numtrouble = len(repo.revs(trouble + b"()"))
7344 numtrouble = len(repo.revs(trouble + b"()"))
7345 # We write all the possibilities to ease translation
7345 # We write all the possibilities to ease translation
7346 troublemsg = {
7346 troublemsg = {
7347 b"orphan": _(b"orphan: %d changesets"),
7347 b"orphan": _(b"orphan: %d changesets"),
7348 b"contentdivergent": _(b"content-divergent: %d changesets"),
7348 b"contentdivergent": _(b"content-divergent: %d changesets"),
7349 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7349 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7350 }
7350 }
7351 if numtrouble > 0:
7351 if numtrouble > 0:
7352 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7352 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7353
7353
7354 cmdutil.summaryhooks(ui, repo)
7354 cmdutil.summaryhooks(ui, repo)
7355
7355
7356 if opts.get('remote'):
7356 if opts.get('remote'):
7357 needsincoming, needsoutgoing = True, True
7357 needsincoming, needsoutgoing = True, True
7358 else:
7358 else:
7359 needsincoming, needsoutgoing = False, False
7359 needsincoming, needsoutgoing = False, False
7360 for i, o in cmdutil.summaryremotehooks(
7360 for i, o in cmdutil.summaryremotehooks(
7361 ui, repo, pycompat.byteskwargs(opts), None
7361 ui, repo, pycompat.byteskwargs(opts), None
7362 ):
7362 ):
7363 if i:
7363 if i:
7364 needsincoming = True
7364 needsincoming = True
7365 if o:
7365 if o:
7366 needsoutgoing = True
7366 needsoutgoing = True
7367 if not needsincoming and not needsoutgoing:
7367 if not needsincoming and not needsoutgoing:
7368 return
7368 return
7369
7369
7370 def getincoming():
7370 def getincoming():
7371 # XXX We should actually skip this if no default is specified, instead
7371 # XXX We should actually skip this if no default is specified, instead
7372 # of passing "default" which will resolve as "./default/" if no default
7372 # of passing "default" which will resolve as "./default/" if no default
7373 # path is defined.
7373 # path is defined.
7374 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7374 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7375 sbranch = path.branch
7375 sbranch = path.branch
7376 try:
7376 try:
7377 other = hg.peer(repo, {}, path)
7377 other = hg.peer(repo, {}, path)
7378 except error.RepoError:
7378 except error.RepoError:
7379 if opts.get('remote'):
7379 if opts.get('remote'):
7380 raise
7380 raise
7381 return path.loc, sbranch, None, None, None
7381 return path.loc, sbranch, None, None, None
7382 branches = (path.branch, [])
7382 branches = (path.branch, [])
7383 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7383 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7384 if revs:
7384 if revs:
7385 revs = [other.lookup(rev) for rev in revs]
7385 revs = [other.lookup(rev) for rev in revs]
7386 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7386 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7387 with repo.ui.silent():
7387 with repo.ui.silent():
7388 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7388 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7389 return path.loc, sbranch, other, commoninc, commoninc[1]
7389 return path.loc, sbranch, other, commoninc, commoninc[1]
7390
7390
7391 if needsincoming:
7391 if needsincoming:
7392 source, sbranch, sother, commoninc, incoming = getincoming()
7392 source, sbranch, sother, commoninc, incoming = getincoming()
7393 else:
7393 else:
7394 source = sbranch = sother = commoninc = incoming = None
7394 source = sbranch = sother = commoninc = incoming = None
7395
7395
7396 def getoutgoing():
7396 def getoutgoing():
7397 # XXX We should actually skip this if no default is specified, instead
7397 # XXX We should actually skip this if no default is specified, instead
7398 # of passing "default" which will resolve as "./default/" if no default
7398 # of passing "default" which will resolve as "./default/" if no default
7399 # path is defined.
7399 # path is defined.
7400 d = None
7400 d = None
7401 if b'default-push' in ui.paths:
7401 if b'default-push' in ui.paths:
7402 d = b'default-push'
7402 d = b'default-push'
7403 elif b'default' in ui.paths:
7403 elif b'default' in ui.paths:
7404 d = b'default'
7404 d = b'default'
7405 path = None
7405 path = None
7406 if d is not None:
7406 if d is not None:
7407 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7407 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7408 dest = path.loc
7408 dest = path.loc
7409 dbranch = path.branch
7409 dbranch = path.branch
7410 else:
7410 else:
7411 dest = b'default'
7411 dest = b'default'
7412 dbranch = None
7412 dbranch = None
7413 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7413 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7414 if source != dest:
7414 if source != dest:
7415 try:
7415 try:
7416 dother = hg.peer(repo, {}, path if path is not None else dest)
7416 dother = hg.peer(repo, {}, path if path is not None else dest)
7417 except error.RepoError:
7417 except error.RepoError:
7418 if opts.get('remote'):
7418 if opts.get('remote'):
7419 raise
7419 raise
7420 return dest, dbranch, None, None
7420 return dest, dbranch, None, None
7421 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7421 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7422 elif sother is None:
7422 elif sother is None:
7423 # there is no explicit destination peer, but source one is invalid
7423 # there is no explicit destination peer, but source one is invalid
7424 return dest, dbranch, None, None
7424 return dest, dbranch, None, None
7425 else:
7425 else:
7426 dother = sother
7426 dother = sother
7427 if source != dest or (sbranch is not None and sbranch != dbranch):
7427 if source != dest or (sbranch is not None and sbranch != dbranch):
7428 common = None
7428 common = None
7429 else:
7429 else:
7430 common = commoninc
7430 common = commoninc
7431 if revs:
7431 if revs:
7432 revs = [repo.lookup(rev) for rev in revs]
7432 revs = [repo.lookup(rev) for rev in revs]
7433 with repo.ui.silent():
7433 with repo.ui.silent():
7434 outgoing = discovery.findcommonoutgoing(
7434 outgoing = discovery.findcommonoutgoing(
7435 repo, dother, onlyheads=revs, commoninc=common
7435 repo, dother, onlyheads=revs, commoninc=common
7436 )
7436 )
7437 return dest, dbranch, dother, outgoing
7437 return dest, dbranch, dother, outgoing
7438
7438
7439 if needsoutgoing:
7439 if needsoutgoing:
7440 dest, dbranch, dother, outgoing = getoutgoing()
7440 dest, dbranch, dother, outgoing = getoutgoing()
7441 else:
7441 else:
7442 dest = dbranch = dother = outgoing = None
7442 dest = dbranch = dother = outgoing = None
7443
7443
7444 if opts.get('remote'):
7444 if opts.get('remote'):
7445 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7445 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7446 # The former always sets `sother` (or raises an exception if it can't);
7446 # The former always sets `sother` (or raises an exception if it can't);
7447 # the latter always sets `outgoing`.
7447 # the latter always sets `outgoing`.
7448 assert sother is not None
7448 assert sother is not None
7449 assert outgoing is not None
7449 assert outgoing is not None
7450
7450
7451 t = []
7451 t = []
7452 if incoming:
7452 if incoming:
7453 t.append(_(b'1 or more incoming'))
7453 t.append(_(b'1 or more incoming'))
7454 o = outgoing.missing
7454 o = outgoing.missing
7455 if o:
7455 if o:
7456 t.append(_(b'%d outgoing') % len(o))
7456 t.append(_(b'%d outgoing') % len(o))
7457 other = dother or sother
7457 other = dother or sother
7458 if b'bookmarks' in other.listkeys(b'namespaces'):
7458 if b'bookmarks' in other.listkeys(b'namespaces'):
7459 counts = bookmarks.summary(repo, other)
7459 counts = bookmarks.summary(repo, other)
7460 if counts[0] > 0:
7460 if counts[0] > 0:
7461 t.append(_(b'%d incoming bookmarks') % counts[0])
7461 t.append(_(b'%d incoming bookmarks') % counts[0])
7462 if counts[1] > 0:
7462 if counts[1] > 0:
7463 t.append(_(b'%d outgoing bookmarks') % counts[1])
7463 t.append(_(b'%d outgoing bookmarks') % counts[1])
7464
7464
7465 if t:
7465 if t:
7466 # i18n: column positioning for "hg summary"
7466 # i18n: column positioning for "hg summary"
7467 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7467 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7468 else:
7468 else:
7469 # i18n: column positioning for "hg summary"
7469 # i18n: column positioning for "hg summary"
7470 ui.status(_(b'remote: (synced)\n'))
7470 ui.status(_(b'remote: (synced)\n'))
7471
7471
7472 cmdutil.summaryremotehooks(
7472 cmdutil.summaryremotehooks(
7473 ui,
7473 ui,
7474 repo,
7474 repo,
7475 pycompat.byteskwargs(opts),
7475 pycompat.byteskwargs(opts),
7476 (
7476 (
7477 (source, sbranch, sother, commoninc),
7477 (source, sbranch, sother, commoninc),
7478 (dest, dbranch, dother, outgoing),
7478 (dest, dbranch, dother, outgoing),
7479 ),
7479 ),
7480 )
7480 )
7481
7481
7482
7482
7483 @command(
7483 @command(
7484 b'tag',
7484 b'tag',
7485 [
7485 [
7486 (b'f', b'force', None, _(b'force tag')),
7486 (b'f', b'force', None, _(b'force tag')),
7487 (b'l', b'local', None, _(b'make the tag local')),
7487 (b'l', b'local', None, _(b'make the tag local')),
7488 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7488 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7489 (b'', b'remove', None, _(b'remove a tag')),
7489 (b'', b'remove', None, _(b'remove a tag')),
7490 # -l/--local is already there, commitopts cannot be used
7490 # -l/--local is already there, commitopts cannot be used
7491 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7491 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7492 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7492 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7493 ]
7493 ]
7494 + commitopts2,
7494 + commitopts2,
7495 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7495 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7496 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7496 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7497 )
7497 )
7498 def tag(ui, repo, name1, *names, **opts):
7498 def tag(ui, repo, name1, *names, **opts):
7499 """add one or more tags for the current or given revision
7499 """add one or more tags for the current or given revision
7500
7500
7501 Name a particular revision using <name>.
7501 Name a particular revision using <name>.
7502
7502
7503 Tags are used to name particular revisions of the repository and are
7503 Tags are used to name particular revisions of the repository and are
7504 very useful to compare different revisions, to go back to significant
7504 very useful to compare different revisions, to go back to significant
7505 earlier versions or to mark branch points as releases, etc. Changing
7505 earlier versions or to mark branch points as releases, etc. Changing
7506 an existing tag is normally disallowed; use -f/--force to override.
7506 an existing tag is normally disallowed; use -f/--force to override.
7507
7507
7508 If no revision is given, the parent of the working directory is
7508 If no revision is given, the parent of the working directory is
7509 used.
7509 used.
7510
7510
7511 To facilitate version control, distribution, and merging of tags,
7511 To facilitate version control, distribution, and merging of tags,
7512 they are stored as a file named ".hgtags" which is managed similarly
7512 they are stored as a file named ".hgtags" which is managed similarly
7513 to other project files and can be hand-edited if necessary. This
7513 to other project files and can be hand-edited if necessary. This
7514 also means that tagging creates a new commit. The file
7514 also means that tagging creates a new commit. The file
7515 ".hg/localtags" is used for local tags (not shared among
7515 ".hg/localtags" is used for local tags (not shared among
7516 repositories).
7516 repositories).
7517
7517
7518 Tag commits are usually made at the head of a branch. If the parent
7518 Tag commits are usually made at the head of a branch. If the parent
7519 of the working directory is not a branch head, :hg:`tag` aborts; use
7519 of the working directory is not a branch head, :hg:`tag` aborts; use
7520 -f/--force to force the tag commit to be based on a non-head
7520 -f/--force to force the tag commit to be based on a non-head
7521 changeset.
7521 changeset.
7522
7522
7523 See :hg:`help dates` for a list of formats valid for -d/--date.
7523 See :hg:`help dates` for a list of formats valid for -d/--date.
7524
7524
7525 Since tag names have priority over branch names during revision
7525 Since tag names have priority over branch names during revision
7526 lookup, using an existing branch name as a tag name is discouraged.
7526 lookup, using an existing branch name as a tag name is discouraged.
7527
7527
7528 Returns 0 on success.
7528 Returns 0 on success.
7529 """
7529 """
7530 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7530 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7531
7531
7532 with repo.wlock(), repo.lock():
7532 with repo.wlock(), repo.lock():
7533 rev_ = b"."
7533 rev_ = b"."
7534 names = [t.strip() for t in (name1,) + names]
7534 names = [t.strip() for t in (name1,) + names]
7535 if len(names) != len(set(names)):
7535 if len(names) != len(set(names)):
7536 raise error.InputError(_(b'tag names must be unique'))
7536 raise error.InputError(_(b'tag names must be unique'))
7537 for n in names:
7537 for n in names:
7538 scmutil.checknewlabel(repo, n, b'tag')
7538 scmutil.checknewlabel(repo, n, b'tag')
7539 if not n:
7539 if not n:
7540 raise error.InputError(
7540 raise error.InputError(
7541 _(b'tag names cannot consist entirely of whitespace')
7541 _(b'tag names cannot consist entirely of whitespace')
7542 )
7542 )
7543 if opts.get('rev'):
7543 if opts.get('rev'):
7544 rev_ = opts['rev']
7544 rev_ = opts['rev']
7545 message = opts.get('message')
7545 message = opts.get('message')
7546 if opts.get('remove'):
7546 if opts.get('remove'):
7547 if opts.get('local'):
7547 if opts.get('local'):
7548 expectedtype = b'local'
7548 expectedtype = b'local'
7549 else:
7549 else:
7550 expectedtype = b'global'
7550 expectedtype = b'global'
7551
7551
7552 for n in names:
7552 for n in names:
7553 if repo.tagtype(n) == b'global':
7553 if repo.tagtype(n) == b'global':
7554 alltags = tagsmod.findglobaltags(ui, repo)
7554 alltags = tagsmod.findglobaltags(ui, repo)
7555 if alltags[n][0] == repo.nullid:
7555 if alltags[n][0] == repo.nullid:
7556 raise error.InputError(
7556 raise error.InputError(
7557 _(b"tag '%s' is already removed") % n
7557 _(b"tag '%s' is already removed") % n
7558 )
7558 )
7559 if not repo.tagtype(n):
7559 if not repo.tagtype(n):
7560 raise error.InputError(_(b"tag '%s' does not exist") % n)
7560 raise error.InputError(_(b"tag '%s' does not exist") % n)
7561 if repo.tagtype(n) != expectedtype:
7561 if repo.tagtype(n) != expectedtype:
7562 if expectedtype == b'global':
7562 if expectedtype == b'global':
7563 raise error.InputError(
7563 raise error.InputError(
7564 _(b"tag '%s' is not a global tag") % n
7564 _(b"tag '%s' is not a global tag") % n
7565 )
7565 )
7566 else:
7566 else:
7567 raise error.InputError(
7567 raise error.InputError(
7568 _(b"tag '%s' is not a local tag") % n
7568 _(b"tag '%s' is not a local tag") % n
7569 )
7569 )
7570 rev_ = b'null'
7570 rev_ = b'null'
7571 if not message:
7571 if not message:
7572 # we don't translate commit messages
7572 # we don't translate commit messages
7573 message = b'Removed tag %s' % b', '.join(names)
7573 message = b'Removed tag %s' % b', '.join(names)
7574 elif not opts.get('force'):
7574 elif not opts.get('force'):
7575 for n in names:
7575 for n in names:
7576 if n in repo.tags():
7576 if n in repo.tags():
7577 raise error.InputError(
7577 raise error.InputError(
7578 _(b"tag '%s' already exists (use -f to force)") % n
7578 _(b"tag '%s' already exists (use -f to force)") % n
7579 )
7579 )
7580 if not opts.get('local'):
7580 if not opts.get('local'):
7581 p1, p2 = repo.dirstate.parents()
7581 p1, p2 = repo.dirstate.parents()
7582 if p2 != repo.nullid:
7582 if p2 != repo.nullid:
7583 raise error.StateError(_(b'uncommitted merge'))
7583 raise error.StateError(_(b'uncommitted merge'))
7584 bheads = repo.branchheads()
7584 bheads = repo.branchheads()
7585 if not opts.get('force') and bheads and p1 not in bheads:
7585 if not opts.get('force') and bheads and p1 not in bheads:
7586 raise error.InputError(
7586 raise error.InputError(
7587 _(
7587 _(
7588 b'working directory is not at a branch head '
7588 b'working directory is not at a branch head '
7589 b'(use -f to force)'
7589 b'(use -f to force)'
7590 )
7590 )
7591 )
7591 )
7592 node = logcmdutil.revsingle(repo, rev_).node()
7592 node = logcmdutil.revsingle(repo, rev_).node()
7593
7593
7594 # don't allow tagging the null rev or the working directory
7594 # don't allow tagging the null rev or the working directory
7595 if node is None:
7595 if node is None:
7596 raise error.InputError(_(b"cannot tag working directory"))
7596 raise error.InputError(_(b"cannot tag working directory"))
7597 elif not opts.get('remove') and node == nullid:
7597 elif not opts.get('remove') and node == nullid:
7598 raise error.InputError(_(b"cannot tag null revision"))
7598 raise error.InputError(_(b"cannot tag null revision"))
7599
7599
7600 if not message:
7600 if not message:
7601 # we don't translate commit messages
7601 # we don't translate commit messages
7602 message = b'Added tag %s for changeset %s' % (
7602 message = b'Added tag %s for changeset %s' % (
7603 b', '.join(names),
7603 b', '.join(names),
7604 short(node),
7604 short(node),
7605 )
7605 )
7606
7606
7607 date = opts.get('date')
7607 date = opts.get('date')
7608 if date:
7608 if date:
7609 date = dateutil.parsedate(date)
7609 date = dateutil.parsedate(date)
7610
7610
7611 if opts.get('remove'):
7611 if opts.get('remove'):
7612 editform = b'tag.remove'
7612 editform = b'tag.remove'
7613 else:
7613 else:
7614 editform = b'tag.add'
7614 editform = b'tag.add'
7615 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7615 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7616
7616
7617 tagsmod.tag(
7617 tagsmod.tag(
7618 repo,
7618 repo,
7619 names,
7619 names,
7620 node,
7620 node,
7621 message,
7621 message,
7622 opts.get('local'),
7622 opts.get('local'),
7623 opts.get('user'),
7623 opts.get('user'),
7624 date,
7624 date,
7625 editor=editor,
7625 editor=editor,
7626 )
7626 )
7627
7627
7628
7628
7629 @command(
7629 @command(
7630 b'tags',
7630 b'tags',
7631 formatteropts,
7631 formatteropts,
7632 b'',
7632 b'',
7633 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7633 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7634 intents={INTENT_READONLY},
7634 intents={INTENT_READONLY},
7635 )
7635 )
7636 def tags(ui, repo, **opts):
7636 def tags(ui, repo, **opts):
7637 """list repository tags
7637 """list repository tags
7638
7638
7639 This lists both regular and local tags. When the -v/--verbose
7639 This lists both regular and local tags. When the -v/--verbose
7640 switch is used, a third column "local" is printed for local tags.
7640 switch is used, a third column "local" is printed for local tags.
7641 When the -q/--quiet switch is used, only the tag name is printed.
7641 When the -q/--quiet switch is used, only the tag name is printed.
7642
7642
7643 .. container:: verbose
7643 .. container:: verbose
7644
7644
7645 Template:
7645 Template:
7646
7646
7647 The following keywords are supported in addition to the common template
7647 The following keywords are supported in addition to the common template
7648 keywords and functions such as ``{tag}``. See also
7648 keywords and functions such as ``{tag}``. See also
7649 :hg:`help templates`.
7649 :hg:`help templates`.
7650
7650
7651 :type: String. ``local`` for local tags.
7651 :type: String. ``local`` for local tags.
7652
7652
7653 Returns 0 on success.
7653 Returns 0 on success.
7654 """
7654 """
7655
7655
7656 ui.pager(b'tags')
7656 ui.pager(b'tags')
7657 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7657 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7658 hexfunc = fm.hexfunc
7658 hexfunc = fm.hexfunc
7659
7659
7660 for t, n in reversed(repo.tagslist()):
7660 for t, n in reversed(repo.tagslist()):
7661 hn = hexfunc(n)
7661 hn = hexfunc(n)
7662 label = b'tags.normal'
7662 label = b'tags.normal'
7663 tagtype = repo.tagtype(t)
7663 tagtype = repo.tagtype(t)
7664 if not tagtype or tagtype == b'global':
7664 if not tagtype or tagtype == b'global':
7665 tagtype = b''
7665 tagtype = b''
7666 else:
7666 else:
7667 label = b'tags.' + tagtype
7667 label = b'tags.' + tagtype
7668
7668
7669 fm.startitem()
7669 fm.startitem()
7670 fm.context(repo=repo)
7670 fm.context(repo=repo)
7671 fm.write(b'tag', b'%s', t, label=label)
7671 fm.write(b'tag', b'%s', t, label=label)
7672 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7672 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7673 fm.condwrite(
7673 fm.condwrite(
7674 not ui.quiet,
7674 not ui.quiet,
7675 b'rev node',
7675 b'rev node',
7676 fmt,
7676 fmt,
7677 repo.changelog.rev(n),
7677 repo.changelog.rev(n),
7678 hn,
7678 hn,
7679 label=label,
7679 label=label,
7680 )
7680 )
7681 fm.condwrite(
7681 fm.condwrite(
7682 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7682 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7683 )
7683 )
7684 fm.plain(b'\n')
7684 fm.plain(b'\n')
7685 fm.end()
7685 fm.end()
7686
7686
7687
7687
7688 @command(
7688 @command(
7689 b'tip',
7689 b'tip',
7690 [
7690 [
7691 (b'p', b'patch', None, _(b'show patch')),
7691 (b'p', b'patch', None, _(b'show patch')),
7692 (b'g', b'git', None, _(b'use git extended diff format')),
7692 (b'g', b'git', None, _(b'use git extended diff format')),
7693 ]
7693 ]
7694 + templateopts,
7694 + templateopts,
7695 _(b'[-p] [-g]'),
7695 _(b'[-p] [-g]'),
7696 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7696 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7697 )
7697 )
7698 def tip(ui, repo, **opts):
7698 def tip(ui, repo, **opts):
7699 """show the tip revision (DEPRECATED)
7699 """show the tip revision (DEPRECATED)
7700
7700
7701 The tip revision (usually just called the tip) is the changeset
7701 The tip revision (usually just called the tip) is the changeset
7702 most recently added to the repository (and therefore the most
7702 most recently added to the repository (and therefore the most
7703 recently changed head).
7703 recently changed head).
7704
7704
7705 If you have just made a commit, that commit will be the tip. If
7705 If you have just made a commit, that commit will be the tip. If
7706 you have just pulled changes from another repository, the tip of
7706 you have just pulled changes from another repository, the tip of
7707 that repository becomes the current tip. The "tip" tag is special
7707 that repository becomes the current tip. The "tip" tag is special
7708 and cannot be renamed or assigned to a different changeset.
7708 and cannot be renamed or assigned to a different changeset.
7709
7709
7710 This command is deprecated, please use :hg:`heads` instead.
7710 This command is deprecated, please use :hg:`heads` instead.
7711
7711
7712 Returns 0 on success.
7712 Returns 0 on success.
7713 """
7713 """
7714 opts = pycompat.byteskwargs(opts)
7714 opts = pycompat.byteskwargs(opts)
7715 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7715 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7716 displayer.show(repo[b'tip'])
7716 displayer.show(repo[b'tip'])
7717 displayer.close()
7717 displayer.close()
7718
7718
7719
7719
7720 @command(
7720 @command(
7721 b'unbundle',
7721 b'unbundle',
7722 [
7722 [
7723 (
7723 (
7724 b'u',
7724 b'u',
7725 b'update',
7725 b'update',
7726 None,
7726 None,
7727 _(b'update to new branch head if changesets were unbundled'),
7727 _(b'update to new branch head if changesets were unbundled'),
7728 )
7728 )
7729 ],
7729 ],
7730 _(b'[-u] FILE...'),
7730 _(b'[-u] FILE...'),
7731 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7731 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7732 )
7732 )
7733 def unbundle(ui, repo, fname1, *fnames, **opts):
7733 def unbundle(ui, repo, fname1, *fnames, _unbundle_source=b'unbundle', **opts):
7734 """apply one or more bundle files
7734 """apply one or more bundle files
7735
7735
7736 Apply one or more bundle files generated by :hg:`bundle`.
7736 Apply one or more bundle files generated by :hg:`bundle`.
7737
7737
7738 Returns 0 on success, 1 if an update has unresolved files.
7738 Returns 0 on success, 1 if an update has unresolved files.
7739 """
7739 """
7740 fnames = (fname1,) + fnames
7740 fnames = (fname1,) + fnames
7741
7741
7742 with repo.lock():
7742 with repo.lock():
7743 for fname in fnames:
7743 for fname in fnames:
7744 f = hg.openpath(ui, fname)
7744 f = hg.openpath(ui, fname)
7745 gen = exchange.readbundle(ui, f, fname)
7745 gen = exchange.readbundle(ui, f, fname)
7746 if isinstance(gen, streamclone.streamcloneapplier):
7746 if isinstance(gen, streamclone.streamcloneapplier):
7747 raise error.InputError(
7747 raise error.InputError(
7748 _(
7748 _(
7749 b'packed bundles cannot be applied with '
7749 b'packed bundles cannot be applied with '
7750 b'"hg unbundle"'
7750 b'"hg unbundle"'
7751 ),
7751 ),
7752 hint=_(b'use "hg debugapplystreamclonebundle"'),
7752 hint=_(b'use "hg debugapplystreamclonebundle"'),
7753 )
7753 )
7754 url = b'bundle:' + fname
7754 url = b'bundle:' + fname
7755 try:
7755 try:
7756 txnname = b'unbundle'
7756 txnname = b'unbundle'
7757 if not isinstance(gen, bundle2.unbundle20):
7757 if not isinstance(gen, bundle2.unbundle20):
7758 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7758 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7759 with repo.transaction(txnname) as tr:
7759 with repo.transaction(txnname) as tr:
7760 op = bundle2.applybundle(
7760 op = bundle2.applybundle(
7761 repo, gen, tr, source=b'unbundle', url=url
7761 repo,
7762 gen,
7763 tr,
7764 source=_unbundle_source, # used by debug::unbundle
7765 url=url,
7762 )
7766 )
7763 except error.BundleUnknownFeatureError as exc:
7767 except error.BundleUnknownFeatureError as exc:
7764 raise error.Abort(
7768 raise error.Abort(
7765 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7769 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7766 hint=_(
7770 hint=_(
7767 b"see https://mercurial-scm.org/"
7771 b"see https://mercurial-scm.org/"
7768 b"wiki/BundleFeature for more "
7772 b"wiki/BundleFeature for more "
7769 b"information"
7773 b"information"
7770 ),
7774 ),
7771 )
7775 )
7772 modheads = bundle2.combinechangegroupresults(op)
7776 modheads = bundle2.combinechangegroupresults(op)
7773
7777
7774 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7778 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7775 return 1
7779 return 1
7776 else:
7780 else:
7777 return 0
7781 return 0
7778
7782
7779
7783
7780 @command(
7784 @command(
7781 b'unshelve',
7785 b'unshelve',
7782 [
7786 [
7783 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7787 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7784 (
7788 (
7785 b'c',
7789 b'c',
7786 b'continue',
7790 b'continue',
7787 None,
7791 None,
7788 _(b'continue an incomplete unshelve operation'),
7792 _(b'continue an incomplete unshelve operation'),
7789 ),
7793 ),
7790 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7794 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7791 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7795 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7792 (
7796 (
7793 b'n',
7797 b'n',
7794 b'name',
7798 b'name',
7795 b'',
7799 b'',
7796 _(b'restore shelved change with given name'),
7800 _(b'restore shelved change with given name'),
7797 _(b'NAME'),
7801 _(b'NAME'),
7798 ),
7802 ),
7799 (b't', b'tool', b'', _(b'specify merge tool')),
7803 (b't', b'tool', b'', _(b'specify merge tool')),
7800 (
7804 (
7801 b'',
7805 b'',
7802 b'date',
7806 b'date',
7803 b'',
7807 b'',
7804 _(b'set date for temporary commits (DEPRECATED)'),
7808 _(b'set date for temporary commits (DEPRECATED)'),
7805 _(b'DATE'),
7809 _(b'DATE'),
7806 ),
7810 ),
7807 ],
7811 ],
7808 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7812 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7809 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7810 )
7814 )
7811 def unshelve(ui, repo, *shelved, **opts):
7815 def unshelve(ui, repo, *shelved, **opts):
7812 """restore a shelved change to the working directory
7816 """restore a shelved change to the working directory
7813
7817
7814 This command accepts an optional name of a shelved change to
7818 This command accepts an optional name of a shelved change to
7815 restore. If none is given, the most recent shelved change is used.
7819 restore. If none is given, the most recent shelved change is used.
7816
7820
7817 If a shelved change is applied successfully, the bundle that
7821 If a shelved change is applied successfully, the bundle that
7818 contains the shelved changes is moved to a backup location
7822 contains the shelved changes is moved to a backup location
7819 (.hg/shelve-backup).
7823 (.hg/shelve-backup).
7820
7824
7821 Since you can restore a shelved change on top of an arbitrary
7825 Since you can restore a shelved change on top of an arbitrary
7822 commit, it is possible that unshelving will result in a conflict
7826 commit, it is possible that unshelving will result in a conflict
7823 between your changes and the commits you are unshelving onto. If
7827 between your changes and the commits you are unshelving onto. If
7824 this occurs, you must resolve the conflict, then use
7828 this occurs, you must resolve the conflict, then use
7825 ``--continue`` to complete the unshelve operation. (The bundle
7829 ``--continue`` to complete the unshelve operation. (The bundle
7826 will not be moved until you successfully complete the unshelve.)
7830 will not be moved until you successfully complete the unshelve.)
7827
7831
7828 (Alternatively, you can use ``--abort`` to abandon an unshelve
7832 (Alternatively, you can use ``--abort`` to abandon an unshelve
7829 that causes a conflict. This reverts the unshelved changes, and
7833 that causes a conflict. This reverts the unshelved changes, and
7830 leaves the bundle in place.)
7834 leaves the bundle in place.)
7831
7835
7832 If bare shelved change (without interactive, include and exclude
7836 If bare shelved change (without interactive, include and exclude
7833 option) was done on newly created branch it would restore branch
7837 option) was done on newly created branch it would restore branch
7834 information to the working directory.
7838 information to the working directory.
7835
7839
7836 After a successful unshelve, the shelved changes are stored in a
7840 After a successful unshelve, the shelved changes are stored in a
7837 backup directory. Only the N most recent backups are kept. N
7841 backup directory. Only the N most recent backups are kept. N
7838 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7842 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7839 configuration option.
7843 configuration option.
7840
7844
7841 .. container:: verbose
7845 .. container:: verbose
7842
7846
7843 Timestamp in seconds is used to decide order of backups. More
7847 Timestamp in seconds is used to decide order of backups. More
7844 than ``maxbackups`` backups are kept, if same timestamp
7848 than ``maxbackups`` backups are kept, if same timestamp
7845 prevents from deciding exact order of them, for safety.
7849 prevents from deciding exact order of them, for safety.
7846
7850
7847 Selected changes can be unshelved with ``--interactive`` flag.
7851 Selected changes can be unshelved with ``--interactive`` flag.
7848 The working directory is updated with the selected changes, and
7852 The working directory is updated with the selected changes, and
7849 only the unselected changes remain shelved.
7853 only the unselected changes remain shelved.
7850 Note: The whole shelve is applied to working directory first before
7854 Note: The whole shelve is applied to working directory first before
7851 running interactively. So, this will bring up all the conflicts between
7855 running interactively. So, this will bring up all the conflicts between
7852 working directory and the shelve, irrespective of which changes will be
7856 working directory and the shelve, irrespective of which changes will be
7853 unshelved.
7857 unshelved.
7854 """
7858 """
7855 with repo.wlock():
7859 with repo.wlock():
7856 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7860 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7857
7861
7858
7862
7859 statemod.addunfinished(
7863 statemod.addunfinished(
7860 b'unshelve',
7864 b'unshelve',
7861 fname=b'shelvedstate',
7865 fname=b'shelvedstate',
7862 continueflag=True,
7866 continueflag=True,
7863 abortfunc=shelvemod.hgabortunshelve,
7867 abortfunc=shelvemod.hgabortunshelve,
7864 continuefunc=shelvemod.hgcontinueunshelve,
7868 continuefunc=shelvemod.hgcontinueunshelve,
7865 cmdmsg=_(b'unshelve already in progress'),
7869 cmdmsg=_(b'unshelve already in progress'),
7866 )
7870 )
7867
7871
7868
7872
7869 @command(
7873 @command(
7870 b'update|up|checkout|co',
7874 b'update|up|checkout|co',
7871 [
7875 [
7872 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7876 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7873 (b'c', b'check', None, _(b'require clean working directory')),
7877 (b'c', b'check', None, _(b'require clean working directory')),
7874 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7878 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7875 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7879 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7876 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7880 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7877 ]
7881 ]
7878 + mergetoolopts,
7882 + mergetoolopts,
7879 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7883 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7880 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7884 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7881 helpbasic=True,
7885 helpbasic=True,
7882 )
7886 )
7883 def update(ui, repo, node=None, **opts):
7887 def update(ui, repo, node=None, **opts):
7884 """update working directory (or switch revisions)
7888 """update working directory (or switch revisions)
7885
7889
7886 Update the repository's working directory to the specified
7890 Update the repository's working directory to the specified
7887 changeset. If no changeset is specified, update to the tip of the
7891 changeset. If no changeset is specified, update to the tip of the
7888 current named branch and move the active bookmark (see :hg:`help
7892 current named branch and move the active bookmark (see :hg:`help
7889 bookmarks`).
7893 bookmarks`).
7890
7894
7891 Update sets the working directory's parent revision to the specified
7895 Update sets the working directory's parent revision to the specified
7892 changeset (see :hg:`help parents`).
7896 changeset (see :hg:`help parents`).
7893
7897
7894 If the changeset is not a descendant or ancestor of the working
7898 If the changeset is not a descendant or ancestor of the working
7895 directory's parent and there are uncommitted changes, the update is
7899 directory's parent and there are uncommitted changes, the update is
7896 aborted. With the -c/--check option, the working directory is checked
7900 aborted. With the -c/--check option, the working directory is checked
7897 for uncommitted changes; if none are found, the working directory is
7901 for uncommitted changes; if none are found, the working directory is
7898 updated to the specified changeset.
7902 updated to the specified changeset.
7899
7903
7900 .. container:: verbose
7904 .. container:: verbose
7901
7905
7902 The -C/--clean, -c/--check, and -m/--merge options control what
7906 The -C/--clean, -c/--check, and -m/--merge options control what
7903 happens if the working directory contains uncommitted changes.
7907 happens if the working directory contains uncommitted changes.
7904 At most of one of them can be specified.
7908 At most of one of them can be specified.
7905
7909
7906 1. If no option is specified, and if
7910 1. If no option is specified, and if
7907 the requested changeset is an ancestor or descendant of
7911 the requested changeset is an ancestor or descendant of
7908 the working directory's parent, the uncommitted changes
7912 the working directory's parent, the uncommitted changes
7909 are merged into the requested changeset and the merged
7913 are merged into the requested changeset and the merged
7910 result is left uncommitted. If the requested changeset is
7914 result is left uncommitted. If the requested changeset is
7911 not an ancestor or descendant (that is, it is on another
7915 not an ancestor or descendant (that is, it is on another
7912 branch), the update is aborted and the uncommitted changes
7916 branch), the update is aborted and the uncommitted changes
7913 are preserved.
7917 are preserved.
7914
7918
7915 2. With the -m/--merge option, the update is allowed even if the
7919 2. With the -m/--merge option, the update is allowed even if the
7916 requested changeset is not an ancestor or descendant of
7920 requested changeset is not an ancestor or descendant of
7917 the working directory's parent.
7921 the working directory's parent.
7918
7922
7919 3. With the -c/--check option, the update is aborted and the
7923 3. With the -c/--check option, the update is aborted and the
7920 uncommitted changes are preserved.
7924 uncommitted changes are preserved.
7921
7925
7922 4. With the -C/--clean option, uncommitted changes are discarded and
7926 4. With the -C/--clean option, uncommitted changes are discarded and
7923 the working directory is updated to the requested changeset.
7927 the working directory is updated to the requested changeset.
7924
7928
7925 To cancel an uncommitted merge (and lose your changes), use
7929 To cancel an uncommitted merge (and lose your changes), use
7926 :hg:`merge --abort`.
7930 :hg:`merge --abort`.
7927
7931
7928 Use null as the changeset to remove the working directory (like
7932 Use null as the changeset to remove the working directory (like
7929 :hg:`clone -U`).
7933 :hg:`clone -U`).
7930
7934
7931 If you want to revert just one file to an older revision, use
7935 If you want to revert just one file to an older revision, use
7932 :hg:`revert [-r REV] NAME`.
7936 :hg:`revert [-r REV] NAME`.
7933
7937
7934 See :hg:`help dates` for a list of formats valid for -d/--date.
7938 See :hg:`help dates` for a list of formats valid for -d/--date.
7935
7939
7936 Returns 0 on success, 1 if there are unresolved files.
7940 Returns 0 on success, 1 if there are unresolved files.
7937 """
7941 """
7938 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7942 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7939 rev = opts.get('rev')
7943 rev = opts.get('rev')
7940 date = opts.get('date')
7944 date = opts.get('date')
7941 clean = opts.get('clean')
7945 clean = opts.get('clean')
7942 check = opts.get('check')
7946 check = opts.get('check')
7943 merge = opts.get('merge')
7947 merge = opts.get('merge')
7944 if rev and node:
7948 if rev and node:
7945 raise error.InputError(_(b"please specify just one revision"))
7949 raise error.InputError(_(b"please specify just one revision"))
7946
7950
7947 if ui.configbool(b'commands', b'update.requiredest'):
7951 if ui.configbool(b'commands', b'update.requiredest'):
7948 if not node and not rev and not date:
7952 if not node and not rev and not date:
7949 raise error.InputError(
7953 raise error.InputError(
7950 _(b'you must specify a destination'),
7954 _(b'you must specify a destination'),
7951 hint=_(b'for example: hg update ".::"'),
7955 hint=_(b'for example: hg update ".::"'),
7952 )
7956 )
7953
7957
7954 if rev is None or rev == b'':
7958 if rev is None or rev == b'':
7955 rev = node
7959 rev = node
7956
7960
7957 if date and rev is not None:
7961 if date and rev is not None:
7958 raise error.InputError(_(b"you can't specify a revision and a date"))
7962 raise error.InputError(_(b"you can't specify a revision and a date"))
7959
7963
7960 updatecheck = None
7964 updatecheck = None
7961 if check or merge is not None and not merge:
7965 if check or merge is not None and not merge:
7962 updatecheck = b'abort'
7966 updatecheck = b'abort'
7963 elif merge or check is not None and not check:
7967 elif merge or check is not None and not check:
7964 updatecheck = b'none'
7968 updatecheck = b'none'
7965
7969
7966 with repo.wlock():
7970 with repo.wlock():
7967 cmdutil.clearunfinished(repo)
7971 cmdutil.clearunfinished(repo)
7968 if date:
7972 if date:
7969 rev = cmdutil.finddate(ui, repo, date)
7973 rev = cmdutil.finddate(ui, repo, date)
7970
7974
7971 # if we defined a bookmark, we have to remember the original name
7975 # if we defined a bookmark, we have to remember the original name
7972 brev = rev
7976 brev = rev
7973 if rev:
7977 if rev:
7974 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7978 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7975 ctx = logcmdutil.revsingle(repo, rev, default=None)
7979 ctx = logcmdutil.revsingle(repo, rev, default=None)
7976 rev = ctx.rev()
7980 rev = ctx.rev()
7977 hidden = ctx.hidden()
7981 hidden = ctx.hidden()
7978 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7982 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7979 with ui.configoverride(overrides, b'update'):
7983 with ui.configoverride(overrides, b'update'):
7980 ret = hg.updatetotally(
7984 ret = hg.updatetotally(
7981 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7985 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7982 )
7986 )
7983 if hidden:
7987 if hidden:
7984 ctxstr = ctx.hex()[:12]
7988 ctxstr = ctx.hex()[:12]
7985 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7989 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7986
7990
7987 if ctx.obsolete():
7991 if ctx.obsolete():
7988 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7992 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7989 ui.warn(b"(%s)\n" % obsfatemsg)
7993 ui.warn(b"(%s)\n" % obsfatemsg)
7990 return ret
7994 return ret
7991
7995
7992
7996
7993 @command(
7997 @command(
7994 b'verify',
7998 b'verify',
7995 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7999 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7996 helpcategory=command.CATEGORY_MAINTENANCE,
8000 helpcategory=command.CATEGORY_MAINTENANCE,
7997 )
8001 )
7998 def verify(ui, repo, **opts):
8002 def verify(ui, repo, **opts):
7999 """verify the integrity of the repository
8003 """verify the integrity of the repository
8000
8004
8001 Verify the integrity of the current repository.
8005 Verify the integrity of the current repository.
8002
8006
8003 This will perform an extensive check of the repository's
8007 This will perform an extensive check of the repository's
8004 integrity, validating the hashes and checksums of each entry in
8008 integrity, validating the hashes and checksums of each entry in
8005 the changelog, manifest, and tracked files, as well as the
8009 the changelog, manifest, and tracked files, as well as the
8006 integrity of their crosslinks and indices.
8010 integrity of their crosslinks and indices.
8007
8011
8008 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
8012 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
8009 for more information about recovery from corruption of the
8013 for more information about recovery from corruption of the
8010 repository.
8014 repository.
8011
8015
8012 For an alternative UI with a lot more control over the verification
8016 For an alternative UI with a lot more control over the verification
8013 process and better error reporting, try `hg help admin::verify`.
8017 process and better error reporting, try `hg help admin::verify`.
8014
8018
8015 Returns 0 on success, 1 if errors are encountered.
8019 Returns 0 on success, 1 if errors are encountered.
8016 """
8020 """
8017 level = None
8021 level = None
8018 if opts['full']:
8022 if opts['full']:
8019 level = verifymod.VERIFY_FULL
8023 level = verifymod.VERIFY_FULL
8020 return hg.verify(repo, level)
8024 return hg.verify(repo, level)
8021
8025
8022
8026
8023 @command(
8027 @command(
8024 b'version',
8028 b'version',
8025 [] + formatteropts,
8029 [] + formatteropts,
8026 helpcategory=command.CATEGORY_HELP,
8030 helpcategory=command.CATEGORY_HELP,
8027 norepo=True,
8031 norepo=True,
8028 intents={INTENT_READONLY},
8032 intents={INTENT_READONLY},
8029 )
8033 )
8030 def version_(ui, **opts):
8034 def version_(ui, **opts):
8031 """output version and copyright information
8035 """output version and copyright information
8032
8036
8033 .. container:: verbose
8037 .. container:: verbose
8034
8038
8035 Template:
8039 Template:
8036
8040
8037 The following keywords are supported. See also :hg:`help templates`.
8041 The following keywords are supported. See also :hg:`help templates`.
8038
8042
8039 :extensions: List of extensions.
8043 :extensions: List of extensions.
8040 :ver: String. Version number.
8044 :ver: String. Version number.
8041
8045
8042 And each entry of ``{extensions}`` provides the following sub-keywords
8046 And each entry of ``{extensions}`` provides the following sub-keywords
8043 in addition to ``{ver}``.
8047 in addition to ``{ver}``.
8044
8048
8045 :bundled: Boolean. True if included in the release.
8049 :bundled: Boolean. True if included in the release.
8046 :name: String. Extension name.
8050 :name: String. Extension name.
8047 """
8051 """
8048 if ui.verbose:
8052 if ui.verbose:
8049 ui.pager(b'version')
8053 ui.pager(b'version')
8050 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
8054 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
8051 fm.startitem()
8055 fm.startitem()
8052 fm.write(
8056 fm.write(
8053 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
8057 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
8054 )
8058 )
8055 license = _(
8059 license = _(
8056 b"(see https://mercurial-scm.org for more information)\n"
8060 b"(see https://mercurial-scm.org for more information)\n"
8057 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
8061 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
8058 b"This is free software; see the source for copying conditions. "
8062 b"This is free software; see the source for copying conditions. "
8059 b"There is NO\nwarranty; "
8063 b"There is NO\nwarranty; "
8060 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
8064 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
8061 )
8065 )
8062 if not ui.quiet:
8066 if not ui.quiet:
8063 fm.plain(license)
8067 fm.plain(license)
8064
8068
8065 if ui.verbose:
8069 if ui.verbose:
8066 fm.plain(_(b"\nEnabled extensions:\n\n"))
8070 fm.plain(_(b"\nEnabled extensions:\n\n"))
8067 # format names and versions into columns
8071 # format names and versions into columns
8068 names = []
8072 names = []
8069 vers = []
8073 vers = []
8070 isinternals = []
8074 isinternals = []
8071 for name, module in sorted(extensions.extensions()):
8075 for name, module in sorted(extensions.extensions()):
8072 names.append(name)
8076 names.append(name)
8073 vers.append(extensions.moduleversion(module) or None)
8077 vers.append(extensions.moduleversion(module) or None)
8074 isinternals.append(extensions.ismoduleinternal(module))
8078 isinternals.append(extensions.ismoduleinternal(module))
8075 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8079 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8076 if names:
8080 if names:
8077 namefmt = b" %%-%ds " % max(len(n) for n in names)
8081 namefmt = b" %%-%ds " % max(len(n) for n in names)
8078 places = [_(b"external"), _(b"internal")]
8082 places = [_(b"external"), _(b"internal")]
8079 for n, v, p in zip(names, vers, isinternals):
8083 for n, v, p in zip(names, vers, isinternals):
8080 fn.startitem()
8084 fn.startitem()
8081 fn.condwrite(ui.verbose, b"name", namefmt, n)
8085 fn.condwrite(ui.verbose, b"name", namefmt, n)
8082 if ui.verbose:
8086 if ui.verbose:
8083 fn.plain(b"%s " % places[p])
8087 fn.plain(b"%s " % places[p])
8084 fn.data(bundled=p)
8088 fn.data(bundled=p)
8085 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8089 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8086 if ui.verbose:
8090 if ui.verbose:
8087 fn.plain(b"\n")
8091 fn.plain(b"\n")
8088 fn.end()
8092 fn.end()
8089 fm.end()
8093 fm.end()
8090
8094
8091
8095
8092 def loadcmdtable(ui, name, cmdtable):
8096 def loadcmdtable(ui, name, cmdtable):
8093 """Load command functions from specified cmdtable"""
8097 """Load command functions from specified cmdtable"""
8094 overrides = [cmd for cmd in cmdtable if cmd in table]
8098 overrides = [cmd for cmd in cmdtable if cmd in table]
8095 if overrides:
8099 if overrides:
8096 ui.warn(
8100 ui.warn(
8097 _(b"extension '%s' overrides commands: %s\n")
8101 _(b"extension '%s' overrides commands: %s\n")
8098 % (name, b" ".join(overrides))
8102 % (name, b" ".join(overrides))
8099 )
8103 )
8100 table.update(cmdtable)
8104 table.update(cmdtable)
@@ -1,4751 +1,4775 b''
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2016 Olivia Mackall <olivia@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
8
9 import binascii
9 import binascii
10 import codecs
10 import codecs
11 import collections
11 import collections
12 import contextlib
12 import contextlib
13 import difflib
13 import difflib
14 import errno
14 import errno
15 import glob
15 import glob
16 import operator
16 import operator
17 import os
17 import os
18 import platform
18 import platform
19 import random
19 import random
20 import re
20 import re
21 import socket
21 import socket
22 import ssl
22 import ssl
23 import stat
23 import stat
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import time
26 import time
27
27
28 from .i18n import _
28 from .i18n import _
29 from .node import (
29 from .node import (
30 bin,
30 bin,
31 hex,
31 hex,
32 nullrev,
32 nullrev,
33 short,
33 short,
34 )
34 )
35 from .pycompat import (
35 from .pycompat import (
36 open,
36 open,
37 )
37 )
38 from . import (
38 from . import (
39 bundle2,
39 bundle2,
40 bundlerepo,
40 bundlerepo,
41 changegroup,
41 changegroup,
42 cmdutil,
42 cmdutil,
43 color,
43 color,
44 context,
44 context,
45 copies,
45 copies,
46 dagparser,
46 dagparser,
47 dirstateutils,
47 dirstateutils,
48 encoding,
48 encoding,
49 error,
49 error,
50 exchange,
50 exchange,
51 extensions,
51 extensions,
52 filelog,
52 filelog,
53 filemerge,
53 filemerge,
54 filesetlang,
54 filesetlang,
55 formatter,
55 formatter,
56 hg,
56 hg,
57 httppeer,
57 httppeer,
58 localrepo,
58 localrepo,
59 lock as lockmod,
59 lock as lockmod,
60 logcmdutil,
60 logcmdutil,
61 manifest,
61 manifest,
62 mergestate as mergestatemod,
62 mergestate as mergestatemod,
63 metadata,
63 metadata,
64 obsolete,
64 obsolete,
65 obsutil,
65 obsutil,
66 pathutil,
66 pathutil,
67 phases,
67 phases,
68 policy,
68 policy,
69 pvec,
69 pvec,
70 pycompat,
70 pycompat,
71 registrar,
71 registrar,
72 repair,
72 repair,
73 repoview,
73 repoview,
74 requirements,
74 requirements,
75 revlog,
75 revlog,
76 revset,
76 revset,
77 revsetlang,
77 revsetlang,
78 scmutil,
78 scmutil,
79 setdiscovery,
79 setdiscovery,
80 simplemerge,
80 simplemerge,
81 sshpeer,
81 sshpeer,
82 sslutil,
82 sslutil,
83 streamclone,
83 streamclone,
84 strip,
84 strip,
85 tags as tagsmod,
85 tags as tagsmod,
86 templater,
86 templater,
87 treediscovery,
87 treediscovery,
88 upgrade,
88 upgrade,
89 url as urlmod,
89 url as urlmod,
90 util,
90 util,
91 verify,
91 verify,
92 vfs as vfsmod,
92 vfs as vfsmod,
93 wireprotoframing,
93 wireprotoframing,
94 wireprotoserver,
94 wireprotoserver,
95 )
95 )
96 from .interfaces import repository
96 from .interfaces import repository
97 from .stabletailgraph import stabletailsort
97 from .stabletailgraph import stabletailsort
98 from .utils import (
98 from .utils import (
99 cborutil,
99 cborutil,
100 compression,
100 compression,
101 dateutil,
101 dateutil,
102 procutil,
102 procutil,
103 stringutil,
103 stringutil,
104 urlutil,
104 urlutil,
105 )
105 )
106
106
107 from .revlogutils import (
107 from .revlogutils import (
108 debug as revlog_debug,
108 debug as revlog_debug,
109 nodemap,
109 nodemap,
110 rewrite,
110 rewrite,
111 sidedata,
111 sidedata,
112 )
112 )
113
113
114 release = lockmod.release
114 release = lockmod.release
115
115
116 table = {}
116 table = {}
117 table.update(strip.command._table)
117 table.update(strip.command._table)
118 command = registrar.command(table)
118 command = registrar.command(table)
119
119
120
120
121 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
121 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
122 def debugancestor(ui, repo, *args):
122 def debugancestor(ui, repo, *args):
123 """find the ancestor revision of two revisions in a given index"""
123 """find the ancestor revision of two revisions in a given index"""
124 if len(args) == 3:
124 if len(args) == 3:
125 index, rev1, rev2 = args
125 index, rev1, rev2 = args
126 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
126 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
127 lookup = r.lookup
127 lookup = r.lookup
128 elif len(args) == 2:
128 elif len(args) == 2:
129 if not repo:
129 if not repo:
130 raise error.Abort(
130 raise error.Abort(
131 _(b'there is no Mercurial repository here (.hg not found)')
131 _(b'there is no Mercurial repository here (.hg not found)')
132 )
132 )
133 rev1, rev2 = args
133 rev1, rev2 = args
134 r = repo.changelog
134 r = repo.changelog
135 lookup = repo.lookup
135 lookup = repo.lookup
136 else:
136 else:
137 raise error.Abort(_(b'either two or three arguments required'))
137 raise error.Abort(_(b'either two or three arguments required'))
138 a = r.ancestor(lookup(rev1), lookup(rev2))
138 a = r.ancestor(lookup(rev1), lookup(rev2))
139 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
139 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
140
140
141
141
142 @command(b'debugantivirusrunning', [])
142 @command(b'debugantivirusrunning', [])
143 def debugantivirusrunning(ui, repo):
143 def debugantivirusrunning(ui, repo):
144 """attempt to trigger an antivirus scanner to see if one is active"""
144 """attempt to trigger an antivirus scanner to see if one is active"""
145 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
145 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
146 f.write(
146 f.write(
147 util.b85decode(
147 util.b85decode(
148 # This is a base85-armored version of the EICAR test file. See
148 # This is a base85-armored version of the EICAR test file. See
149 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
149 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
150 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
150 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
151 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
151 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
152 )
152 )
153 )
153 )
154 # Give an AV engine time to scan the file.
154 # Give an AV engine time to scan the file.
155 time.sleep(2)
155 time.sleep(2)
156 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
156 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
157
157
158
158
159 @command(b'debugapplystreamclonebundle', [], b'FILE')
159 @command(b'debugapplystreamclonebundle', [], b'FILE')
160 def debugapplystreamclonebundle(ui, repo, fname):
160 def debugapplystreamclonebundle(ui, repo, fname):
161 """apply a stream clone bundle file"""
161 """apply a stream clone bundle file"""
162 f = hg.openpath(ui, fname)
162 f = hg.openpath(ui, fname)
163 gen = exchange.readbundle(ui, f, fname)
163 gen = exchange.readbundle(ui, f, fname)
164 gen.apply(repo)
164 gen.apply(repo)
165
165
166
166
167 @command(
167 @command(
168 b'debugbuilddag',
168 b'debugbuilddag',
169 [
169 [
170 (
170 (
171 b'm',
171 b'm',
172 b'mergeable-file',
172 b'mergeable-file',
173 None,
173 None,
174 _(b'add single file mergeable changes'),
174 _(b'add single file mergeable changes'),
175 ),
175 ),
176 (
176 (
177 b'o',
177 b'o',
178 b'overwritten-file',
178 b'overwritten-file',
179 None,
179 None,
180 _(b'add single file all revs overwrite'),
180 _(b'add single file all revs overwrite'),
181 ),
181 ),
182 (b'n', b'new-file', None, _(b'add new file at each rev')),
182 (b'n', b'new-file', None, _(b'add new file at each rev')),
183 (
183 (
184 b'',
184 b'',
185 b'from-existing',
185 b'from-existing',
186 None,
186 None,
187 _(b'continue from a non-empty repository'),
187 _(b'continue from a non-empty repository'),
188 ),
188 ),
189 ],
189 ],
190 _(b'[OPTION]... [TEXT]'),
190 _(b'[OPTION]... [TEXT]'),
191 )
191 )
192 def debugbuilddag(
192 def debugbuilddag(
193 ui,
193 ui,
194 repo,
194 repo,
195 text=None,
195 text=None,
196 mergeable_file=False,
196 mergeable_file=False,
197 overwritten_file=False,
197 overwritten_file=False,
198 new_file=False,
198 new_file=False,
199 from_existing=False,
199 from_existing=False,
200 ):
200 ):
201 """builds a repo with a given DAG from scratch in the current empty repo
201 """builds a repo with a given DAG from scratch in the current empty repo
202
202
203 The description of the DAG is read from stdin if not given on the
203 The description of the DAG is read from stdin if not given on the
204 command line.
204 command line.
205
205
206 Elements:
206 Elements:
207
207
208 - "+n" is a linear run of n nodes based on the current default parent
208 - "+n" is a linear run of n nodes based on the current default parent
209 - "." is a single node based on the current default parent
209 - "." is a single node based on the current default parent
210 - "$" resets the default parent to null (implied at the start);
210 - "$" resets the default parent to null (implied at the start);
211 otherwise the default parent is always the last node created
211 otherwise the default parent is always the last node created
212 - "<p" sets the default parent to the backref p
212 - "<p" sets the default parent to the backref p
213 - "*p" is a fork at parent p, which is a backref
213 - "*p" is a fork at parent p, which is a backref
214 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
214 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
215 - "/p2" is a merge of the preceding node and p2
215 - "/p2" is a merge of the preceding node and p2
216 - ":tag" defines a local tag for the preceding node
216 - ":tag" defines a local tag for the preceding node
217 - "@branch" sets the named branch for subsequent nodes
217 - "@branch" sets the named branch for subsequent nodes
218 - "#...\\n" is a comment up to the end of the line
218 - "#...\\n" is a comment up to the end of the line
219
219
220 Whitespace between the above elements is ignored.
220 Whitespace between the above elements is ignored.
221
221
222 A backref is either
222 A backref is either
223
223
224 - a number n, which references the node curr-n, where curr is the current
224 - a number n, which references the node curr-n, where curr is the current
225 node, or
225 node, or
226 - the name of a local tag you placed earlier using ":tag", or
226 - the name of a local tag you placed earlier using ":tag", or
227 - empty to denote the default parent.
227 - empty to denote the default parent.
228
228
229 All string valued-elements are either strictly alphanumeric, or must
229 All string valued-elements are either strictly alphanumeric, or must
230 be enclosed in double quotes ("..."), with "\\" as escape character.
230 be enclosed in double quotes ("..."), with "\\" as escape character.
231 """
231 """
232
232
233 if text is None:
233 if text is None:
234 ui.status(_(b"reading DAG from stdin\n"))
234 ui.status(_(b"reading DAG from stdin\n"))
235 text = ui.fin.read()
235 text = ui.fin.read()
236
236
237 cl = repo.changelog
237 cl = repo.changelog
238 if len(cl) > 0 and not from_existing:
238 if len(cl) > 0 and not from_existing:
239 raise error.Abort(_(b'repository is not empty'))
239 raise error.Abort(_(b'repository is not empty'))
240
240
241 # determine number of revs in DAG
241 # determine number of revs in DAG
242 total = 0
242 total = 0
243 for type, data in dagparser.parsedag(text):
243 for type, data in dagparser.parsedag(text):
244 if type == b'n':
244 if type == b'n':
245 total += 1
245 total += 1
246
246
247 if mergeable_file:
247 if mergeable_file:
248 linesperrev = 2
248 linesperrev = 2
249 # make a file with k lines per rev
249 # make a file with k lines per rev
250 initialmergedlines = [b'%d' % i for i in range(0, total * linesperrev)]
250 initialmergedlines = [b'%d' % i for i in range(0, total * linesperrev)]
251 initialmergedlines.append(b"")
251 initialmergedlines.append(b"")
252
252
253 tags = []
253 tags = []
254 progress = ui.makeprogress(
254 progress = ui.makeprogress(
255 _(b'building'), unit=_(b'revisions'), total=total
255 _(b'building'), unit=_(b'revisions'), total=total
256 )
256 )
257 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
257 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
258 at = -1
258 at = -1
259 atbranch = b'default'
259 atbranch = b'default'
260 nodeids = []
260 nodeids = []
261 id = 0
261 id = 0
262 progress.update(id)
262 progress.update(id)
263 for type, data in dagparser.parsedag(text):
263 for type, data in dagparser.parsedag(text):
264 if type == b'n':
264 if type == b'n':
265 ui.note((b'node %s\n' % pycompat.bytestr(data)))
265 ui.note((b'node %s\n' % pycompat.bytestr(data)))
266 id, ps = data
266 id, ps = data
267
267
268 files = []
268 files = []
269 filecontent = {}
269 filecontent = {}
270
270
271 p2 = None
271 p2 = None
272 if mergeable_file:
272 if mergeable_file:
273 fn = b"mf"
273 fn = b"mf"
274 p1 = repo[ps[0]]
274 p1 = repo[ps[0]]
275 if len(ps) > 1:
275 if len(ps) > 1:
276 p2 = repo[ps[1]]
276 p2 = repo[ps[1]]
277 pa = p1.ancestor(p2)
277 pa = p1.ancestor(p2)
278 base, local, other = [
278 base, local, other = [
279 x[fn].data() for x in (pa, p1, p2)
279 x[fn].data() for x in (pa, p1, p2)
280 ]
280 ]
281 m3 = simplemerge.Merge3Text(base, local, other)
281 m3 = simplemerge.Merge3Text(base, local, other)
282 ml = [
282 ml = [
283 l.strip()
283 l.strip()
284 for l in simplemerge.render_minimized(m3)[0]
284 for l in simplemerge.render_minimized(m3)[0]
285 ]
285 ]
286 ml.append(b"")
286 ml.append(b"")
287 elif at > 0:
287 elif at > 0:
288 ml = p1[fn].data().split(b"\n")
288 ml = p1[fn].data().split(b"\n")
289 else:
289 else:
290 ml = initialmergedlines
290 ml = initialmergedlines
291 ml[id * linesperrev] += b" r%i" % id
291 ml[id * linesperrev] += b" r%i" % id
292 mergedtext = b"\n".join(ml)
292 mergedtext = b"\n".join(ml)
293 files.append(fn)
293 files.append(fn)
294 filecontent[fn] = mergedtext
294 filecontent[fn] = mergedtext
295
295
296 if overwritten_file:
296 if overwritten_file:
297 fn = b"of"
297 fn = b"of"
298 files.append(fn)
298 files.append(fn)
299 filecontent[fn] = b"r%i\n" % id
299 filecontent[fn] = b"r%i\n" % id
300
300
301 if new_file:
301 if new_file:
302 fn = b"nf%i" % id
302 fn = b"nf%i" % id
303 files.append(fn)
303 files.append(fn)
304 filecontent[fn] = b"r%i\n" % id
304 filecontent[fn] = b"r%i\n" % id
305 if len(ps) > 1:
305 if len(ps) > 1:
306 if not p2:
306 if not p2:
307 p2 = repo[ps[1]]
307 p2 = repo[ps[1]]
308 for fn in p2:
308 for fn in p2:
309 if fn.startswith(b"nf"):
309 if fn.startswith(b"nf"):
310 files.append(fn)
310 files.append(fn)
311 filecontent[fn] = p2[fn].data()
311 filecontent[fn] = p2[fn].data()
312
312
313 def fctxfn(repo, cx, path):
313 def fctxfn(repo, cx, path):
314 if path in filecontent:
314 if path in filecontent:
315 return context.memfilectx(
315 return context.memfilectx(
316 repo, cx, path, filecontent[path]
316 repo, cx, path, filecontent[path]
317 )
317 )
318 return None
318 return None
319
319
320 if len(ps) == 0 or ps[0] < 0:
320 if len(ps) == 0 or ps[0] < 0:
321 pars = [None, None]
321 pars = [None, None]
322 elif len(ps) == 1:
322 elif len(ps) == 1:
323 pars = [nodeids[ps[0]], None]
323 pars = [nodeids[ps[0]], None]
324 else:
324 else:
325 pars = [nodeids[p] for p in ps]
325 pars = [nodeids[p] for p in ps]
326 cx = context.memctx(
326 cx = context.memctx(
327 repo,
327 repo,
328 pars,
328 pars,
329 b"r%i" % id,
329 b"r%i" % id,
330 files,
330 files,
331 fctxfn,
331 fctxfn,
332 date=(id, 0),
332 date=(id, 0),
333 user=b"debugbuilddag",
333 user=b"debugbuilddag",
334 extra={b'branch': atbranch},
334 extra={b'branch': atbranch},
335 )
335 )
336 nodeid = repo.commitctx(cx)
336 nodeid = repo.commitctx(cx)
337 nodeids.append(nodeid)
337 nodeids.append(nodeid)
338 at = id
338 at = id
339 elif type == b'l':
339 elif type == b'l':
340 id, name = data
340 id, name = data
341 ui.note((b'tag %s\n' % name))
341 ui.note((b'tag %s\n' % name))
342 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
342 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
343 elif type == b'a':
343 elif type == b'a':
344 ui.note((b'branch %s\n' % data))
344 ui.note((b'branch %s\n' % data))
345 atbranch = data
345 atbranch = data
346 progress.update(id)
346 progress.update(id)
347
347
348 if tags:
348 if tags:
349 repo.vfs.write(b"localtags", b"".join(tags))
349 repo.vfs.write(b"localtags", b"".join(tags))
350
350
351
351
352 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
352 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
353 indent_string = b' ' * indent
353 indent_string = b' ' * indent
354 if all:
354 if all:
355 ui.writenoi18n(
355 ui.writenoi18n(
356 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
356 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
357 % indent_string
357 % indent_string
358 )
358 )
359
359
360 def showchunks(named):
360 def showchunks(named):
361 ui.write(b"\n%s%s\n" % (indent_string, named))
361 ui.write(b"\n%s%s\n" % (indent_string, named))
362 for deltadata in gen.deltaiter():
362 for deltadata in gen.deltaiter():
363 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
363 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
364 ui.write(
364 ui.write(
365 b"%s%s %s %s %s %s %d\n"
365 b"%s%s %s %s %s %s %d\n"
366 % (
366 % (
367 indent_string,
367 indent_string,
368 hex(node),
368 hex(node),
369 hex(p1),
369 hex(p1),
370 hex(p2),
370 hex(p2),
371 hex(cs),
371 hex(cs),
372 hex(deltabase),
372 hex(deltabase),
373 len(delta),
373 len(delta),
374 )
374 )
375 )
375 )
376
376
377 gen.changelogheader()
377 gen.changelogheader()
378 showchunks(b"changelog")
378 showchunks(b"changelog")
379 gen.manifestheader()
379 gen.manifestheader()
380 showchunks(b"manifest")
380 showchunks(b"manifest")
381 for chunkdata in iter(gen.filelogheader, {}):
381 for chunkdata in iter(gen.filelogheader, {}):
382 fname = chunkdata[b'filename']
382 fname = chunkdata[b'filename']
383 showchunks(fname)
383 showchunks(fname)
384 else:
384 else:
385 if isinstance(gen, bundle2.unbundle20):
385 if isinstance(gen, bundle2.unbundle20):
386 raise error.Abort(_(b'use debugbundle2 for this file'))
386 raise error.Abort(_(b'use debugbundle2 for this file'))
387 gen.changelogheader()
387 gen.changelogheader()
388 for deltadata in gen.deltaiter():
388 for deltadata in gen.deltaiter():
389 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
389 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
390 ui.write(b"%s%s\n" % (indent_string, hex(node)))
390 ui.write(b"%s%s\n" % (indent_string, hex(node)))
391
391
392
392
393 def _debugobsmarkers(ui, part, indent=0, **opts):
393 def _debugobsmarkers(ui, part, indent=0, **opts):
394 """display version and markers contained in 'data'"""
394 """display version and markers contained in 'data'"""
395 data = part.read()
395 data = part.read()
396 indent_string = b' ' * indent
396 indent_string = b' ' * indent
397 try:
397 try:
398 version, markers = obsolete._readmarkers(data)
398 version, markers = obsolete._readmarkers(data)
399 except error.UnknownVersion as exc:
399 except error.UnknownVersion as exc:
400 msg = b"%sunsupported version: %s (%d bytes)\n"
400 msg = b"%sunsupported version: %s (%d bytes)\n"
401 msg %= indent_string, exc.version, len(data)
401 msg %= indent_string, exc.version, len(data)
402 ui.write(msg)
402 ui.write(msg)
403 else:
403 else:
404 msg = b"%sversion: %d (%d bytes)\n"
404 msg = b"%sversion: %d (%d bytes)\n"
405 msg %= indent_string, version, len(data)
405 msg %= indent_string, version, len(data)
406 ui.write(msg)
406 ui.write(msg)
407 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
407 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
408 for rawmarker in sorted(markers):
408 for rawmarker in sorted(markers):
409 m = obsutil.marker(None, rawmarker)
409 m = obsutil.marker(None, rawmarker)
410 fm.startitem()
410 fm.startitem()
411 fm.plain(indent_string)
411 fm.plain(indent_string)
412 cmdutil.showmarker(fm, m)
412 cmdutil.showmarker(fm, m)
413 fm.end()
413 fm.end()
414
414
415
415
416 def _debugphaseheads(ui, data, indent=0):
416 def _debugphaseheads(ui, data, indent=0):
417 """display version and markers contained in 'data'"""
417 """display version and markers contained in 'data'"""
418 indent_string = b' ' * indent
418 indent_string = b' ' * indent
419 headsbyphase = phases.binarydecode(data)
419 headsbyphase = phases.binarydecode(data)
420 for phase in phases.allphases:
420 for phase in phases.allphases:
421 for head in headsbyphase[phase]:
421 for head in headsbyphase[phase]:
422 ui.write(indent_string)
422 ui.write(indent_string)
423 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
423 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
424
424
425
425
426 def _quasirepr(thing):
426 def _quasirepr(thing):
427 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
427 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
428 return b'{%s}' % (
428 return b'{%s}' % (
429 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
429 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
430 )
430 )
431 return pycompat.bytestr(repr(thing))
431 return pycompat.bytestr(repr(thing))
432
432
433
433
434 def _debugbundle2(ui, gen, all=None, **opts):
434 def _debugbundle2(ui, gen, all=None, **opts):
435 """lists the contents of a bundle2"""
435 """lists the contents of a bundle2"""
436 if not isinstance(gen, bundle2.unbundle20):
436 if not isinstance(gen, bundle2.unbundle20):
437 raise error.Abort(_(b'not a bundle2 file'))
437 raise error.Abort(_(b'not a bundle2 file'))
438 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
438 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
439 parttypes = opts.get('part_type', [])
439 parttypes = opts.get('part_type', [])
440 for part in gen.iterparts():
440 for part in gen.iterparts():
441 if parttypes and part.type not in parttypes:
441 if parttypes and part.type not in parttypes:
442 continue
442 continue
443 msg = b'%s -- %s (mandatory: %r)\n'
443 msg = b'%s -- %s (mandatory: %r)\n'
444 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
444 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
445 if part.type == b'changegroup':
445 if part.type == b'changegroup':
446 version = part.params.get(b'version', b'01')
446 version = part.params.get(b'version', b'01')
447 cg = changegroup.getunbundler(version, part, b'UN')
447 cg = changegroup.getunbundler(version, part, b'UN')
448 if not ui.quiet:
448 if not ui.quiet:
449 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
449 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
450 if part.type == b'obsmarkers':
450 if part.type == b'obsmarkers':
451 if not ui.quiet:
451 if not ui.quiet:
452 _debugobsmarkers(ui, part, indent=4, **opts)
452 _debugobsmarkers(ui, part, indent=4, **opts)
453 if part.type == b'phase-heads':
453 if part.type == b'phase-heads':
454 if not ui.quiet:
454 if not ui.quiet:
455 _debugphaseheads(ui, part, indent=4)
455 _debugphaseheads(ui, part, indent=4)
456
456
457
457
458 @command(
458 @command(
459 b'debugbundle',
459 b'debugbundle',
460 [
460 [
461 (b'a', b'all', None, _(b'show all details')),
461 (b'a', b'all', None, _(b'show all details')),
462 (b'', b'part-type', [], _(b'show only the named part type')),
462 (b'', b'part-type', [], _(b'show only the named part type')),
463 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
463 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
464 ],
464 ],
465 _(b'FILE'),
465 _(b'FILE'),
466 norepo=True,
466 norepo=True,
467 )
467 )
468 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
468 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
469 """lists the contents of a bundle"""
469 """lists the contents of a bundle"""
470 with hg.openpath(ui, bundlepath) as f:
470 with hg.openpath(ui, bundlepath) as f:
471 if spec:
471 if spec:
472 spec = exchange.getbundlespec(ui, f)
472 spec = exchange.getbundlespec(ui, f)
473 ui.write(b'%s\n' % spec)
473 ui.write(b'%s\n' % spec)
474 return
474 return
475
475
476 gen = exchange.readbundle(ui, f, bundlepath)
476 gen = exchange.readbundle(ui, f, bundlepath)
477 if isinstance(gen, bundle2.unbundle20):
477 if isinstance(gen, bundle2.unbundle20):
478 return _debugbundle2(ui, gen, all=all, **opts)
478 return _debugbundle2(ui, gen, all=all, **opts)
479 _debugchangegroup(ui, gen, all=all, **opts)
479 _debugchangegroup(ui, gen, all=all, **opts)
480
480
481
481
482 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
482 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
483 def debugcapabilities(ui, path, **opts):
483 def debugcapabilities(ui, path, **opts):
484 """lists the capabilities of a remote peer"""
484 """lists the capabilities of a remote peer"""
485 peer = hg.peer(ui, pycompat.byteskwargs(opts), path)
485 peer = hg.peer(ui, pycompat.byteskwargs(opts), path)
486 try:
486 try:
487 caps = peer.capabilities()
487 caps = peer.capabilities()
488 ui.writenoi18n(b'Main capabilities:\n')
488 ui.writenoi18n(b'Main capabilities:\n')
489 for c in sorted(caps):
489 for c in sorted(caps):
490 ui.write(b' %s\n' % c)
490 ui.write(b' %s\n' % c)
491 b2caps = bundle2.bundle2caps(peer)
491 b2caps = bundle2.bundle2caps(peer)
492 if b2caps:
492 if b2caps:
493 ui.writenoi18n(b'Bundle2 capabilities:\n')
493 ui.writenoi18n(b'Bundle2 capabilities:\n')
494 for key, values in sorted(b2caps.items()):
494 for key, values in sorted(b2caps.items()):
495 ui.write(b' %s\n' % key)
495 ui.write(b' %s\n' % key)
496 for v in values:
496 for v in values:
497 ui.write(b' %s\n' % v)
497 ui.write(b' %s\n' % v)
498 finally:
498 finally:
499 peer.close()
499 peer.close()
500
500
501
501
502 @command(
502 @command(
503 b'debugchangedfiles',
503 b'debugchangedfiles',
504 [
504 [
505 (
505 (
506 b'',
506 b'',
507 b'compute',
507 b'compute',
508 False,
508 False,
509 b"compute information instead of reading it from storage",
509 b"compute information instead of reading it from storage",
510 ),
510 ),
511 ],
511 ],
512 b'REV',
512 b'REV',
513 )
513 )
514 def debugchangedfiles(ui, repo, rev, **opts):
514 def debugchangedfiles(ui, repo, rev, **opts):
515 """list the stored files changes for a revision"""
515 """list the stored files changes for a revision"""
516 ctx = logcmdutil.revsingle(repo, rev, None)
516 ctx = logcmdutil.revsingle(repo, rev, None)
517 files = None
517 files = None
518
518
519 if opts['compute']:
519 if opts['compute']:
520 files = metadata.compute_all_files_changes(ctx)
520 files = metadata.compute_all_files_changes(ctx)
521 else:
521 else:
522 sd = repo.changelog.sidedata(ctx.rev())
522 sd = repo.changelog.sidedata(ctx.rev())
523 files_block = sd.get(sidedata.SD_FILES)
523 files_block = sd.get(sidedata.SD_FILES)
524 if files_block is not None:
524 if files_block is not None:
525 files = metadata.decode_files_sidedata(sd)
525 files = metadata.decode_files_sidedata(sd)
526 if files is not None:
526 if files is not None:
527 for f in sorted(files.touched):
527 for f in sorted(files.touched):
528 if f in files.added:
528 if f in files.added:
529 action = b"added"
529 action = b"added"
530 elif f in files.removed:
530 elif f in files.removed:
531 action = b"removed"
531 action = b"removed"
532 elif f in files.merged:
532 elif f in files.merged:
533 action = b"merged"
533 action = b"merged"
534 elif f in files.salvaged:
534 elif f in files.salvaged:
535 action = b"salvaged"
535 action = b"salvaged"
536 else:
536 else:
537 action = b"touched"
537 action = b"touched"
538
538
539 copy_parent = b""
539 copy_parent = b""
540 copy_source = b""
540 copy_source = b""
541 if f in files.copied_from_p1:
541 if f in files.copied_from_p1:
542 copy_parent = b"p1"
542 copy_parent = b"p1"
543 copy_source = files.copied_from_p1[f]
543 copy_source = files.copied_from_p1[f]
544 elif f in files.copied_from_p2:
544 elif f in files.copied_from_p2:
545 copy_parent = b"p2"
545 copy_parent = b"p2"
546 copy_source = files.copied_from_p2[f]
546 copy_source = files.copied_from_p2[f]
547
547
548 data = (action, copy_parent, f, copy_source)
548 data = (action, copy_parent, f, copy_source)
549 template = b"%-8s %2s: %s, %s;\n"
549 template = b"%-8s %2s: %s, %s;\n"
550 ui.write(template % data)
550 ui.write(template % data)
551
551
552
552
553 @command(b'debugcheckstate', [], b'')
553 @command(b'debugcheckstate', [], b'')
554 def debugcheckstate(ui, repo):
554 def debugcheckstate(ui, repo):
555 """validate the correctness of the current dirstate"""
555 """validate the correctness of the current dirstate"""
556 errors = verify.verifier(repo)._verify_dirstate()
556 errors = verify.verifier(repo)._verify_dirstate()
557 if errors:
557 if errors:
558 errstr = _(b"dirstate inconsistent with current parent's manifest")
558 errstr = _(b"dirstate inconsistent with current parent's manifest")
559 raise error.Abort(errstr)
559 raise error.Abort(errstr)
560
560
561
561
562 @command(
562 @command(
563 b'debugcolor',
563 b'debugcolor',
564 [(b'', b'style', None, _(b'show all configured styles'))],
564 [(b'', b'style', None, _(b'show all configured styles'))],
565 b'hg debugcolor',
565 b'hg debugcolor',
566 )
566 )
567 def debugcolor(ui, repo, **opts):
567 def debugcolor(ui, repo, **opts):
568 """show available color, effects or style"""
568 """show available color, effects or style"""
569 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
569 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
570 if opts.get('style'):
570 if opts.get('style'):
571 return _debugdisplaystyle(ui)
571 return _debugdisplaystyle(ui)
572 else:
572 else:
573 return _debugdisplaycolor(ui)
573 return _debugdisplaycolor(ui)
574
574
575
575
576 def _debugdisplaycolor(ui):
576 def _debugdisplaycolor(ui):
577 ui = ui.copy()
577 ui = ui.copy()
578 ui._styles.clear()
578 ui._styles.clear()
579 for effect in color._activeeffects(ui).keys():
579 for effect in color._activeeffects(ui).keys():
580 ui._styles[effect] = effect
580 ui._styles[effect] = effect
581 if ui._terminfoparams:
581 if ui._terminfoparams:
582 for k, v in ui.configitems(b'color'):
582 for k, v in ui.configitems(b'color'):
583 if k.startswith(b'color.'):
583 if k.startswith(b'color.'):
584 ui._styles[k] = k[6:]
584 ui._styles[k] = k[6:]
585 elif k.startswith(b'terminfo.'):
585 elif k.startswith(b'terminfo.'):
586 ui._styles[k] = k[9:]
586 ui._styles[k] = k[9:]
587 ui.write(_(b'available colors:\n'))
587 ui.write(_(b'available colors:\n'))
588 # sort label with a '_' after the other to group '_background' entry.
588 # sort label with a '_' after the other to group '_background' entry.
589 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
589 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
590 for colorname, label in items:
590 for colorname, label in items:
591 ui.write(b'%s\n' % colorname, label=label)
591 ui.write(b'%s\n' % colorname, label=label)
592
592
593
593
594 def _debugdisplaystyle(ui):
594 def _debugdisplaystyle(ui):
595 ui.write(_(b'available style:\n'))
595 ui.write(_(b'available style:\n'))
596 if not ui._styles:
596 if not ui._styles:
597 return
597 return
598 width = max(len(s) for s in ui._styles)
598 width = max(len(s) for s in ui._styles)
599 for label, effects in sorted(ui._styles.items()):
599 for label, effects in sorted(ui._styles.items()):
600 ui.write(b'%s' % label, label=label)
600 ui.write(b'%s' % label, label=label)
601 if effects:
601 if effects:
602 # 50
602 # 50
603 ui.write(b': ')
603 ui.write(b': ')
604 ui.write(b' ' * (max(0, width - len(label))))
604 ui.write(b' ' * (max(0, width - len(label))))
605 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
605 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
606 ui.write(b'\n')
606 ui.write(b'\n')
607
607
608
608
609 @command(b'debugcreatestreamclonebundle', [], b'FILE')
609 @command(b'debugcreatestreamclonebundle', [], b'FILE')
610 def debugcreatestreamclonebundle(ui, repo, fname):
610 def debugcreatestreamclonebundle(ui, repo, fname):
611 """create a stream clone bundle file
611 """create a stream clone bundle file
612
612
613 Stream bundles are special bundles that are essentially archives of
613 Stream bundles are special bundles that are essentially archives of
614 revlog files. They are commonly used for cloning very quickly.
614 revlog files. They are commonly used for cloning very quickly.
615
615
616 This command creates a "version 1" stream clone, which is deprecated in
616 This command creates a "version 1" stream clone, which is deprecated in
617 favor of newer versions of the stream protocol. Bundles using such newer
617 favor of newer versions of the stream protocol. Bundles using such newer
618 versions can be generated using the `hg bundle` command.
618 versions can be generated using the `hg bundle` command.
619 """
619 """
620 # TODO we may want to turn this into an abort when this functionality
620 # TODO we may want to turn this into an abort when this functionality
621 # is moved into `hg bundle`.
621 # is moved into `hg bundle`.
622 if phases.hassecret(repo):
622 if phases.hassecret(repo):
623 ui.warn(
623 ui.warn(
624 _(
624 _(
625 b'(warning: stream clone bundle will contain secret '
625 b'(warning: stream clone bundle will contain secret '
626 b'revisions)\n'
626 b'revisions)\n'
627 )
627 )
628 )
628 )
629
629
630 requirements, gen = streamclone.generatebundlev1(repo)
630 requirements, gen = streamclone.generatebundlev1(repo)
631 changegroup.writechunks(ui, gen, fname)
631 changegroup.writechunks(ui, gen, fname)
632
632
633 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
633 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
634
634
635
635
636 @command(
636 @command(
637 b'debugdag',
637 b'debugdag',
638 [
638 [
639 (b't', b'tags', None, _(b'use tags as labels')),
639 (b't', b'tags', None, _(b'use tags as labels')),
640 (b'b', b'branches', None, _(b'annotate with branch names')),
640 (b'b', b'branches', None, _(b'annotate with branch names')),
641 (b'', b'dots', None, _(b'use dots for runs')),
641 (b'', b'dots', None, _(b'use dots for runs')),
642 (b's', b'spaces', None, _(b'separate elements by spaces')),
642 (b's', b'spaces', None, _(b'separate elements by spaces')),
643 ],
643 ],
644 _(b'[OPTION]... [FILE [REV]...]'),
644 _(b'[OPTION]... [FILE [REV]...]'),
645 optionalrepo=True,
645 optionalrepo=True,
646 )
646 )
647 def debugdag(ui, repo, file_=None, *revs, **opts):
647 def debugdag(ui, repo, file_=None, *revs, **opts):
648 """format the changelog or an index DAG as a concise textual description
648 """format the changelog or an index DAG as a concise textual description
649
649
650 If you pass a revlog index, the revlog's DAG is emitted. If you list
650 If you pass a revlog index, the revlog's DAG is emitted. If you list
651 revision numbers, they get labeled in the output as rN.
651 revision numbers, they get labeled in the output as rN.
652
652
653 Otherwise, the changelog DAG of the current repo is emitted.
653 Otherwise, the changelog DAG of the current repo is emitted.
654 """
654 """
655 spaces = opts.get('spaces')
655 spaces = opts.get('spaces')
656 dots = opts.get('dots')
656 dots = opts.get('dots')
657 if file_:
657 if file_:
658 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
658 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
659 revs = {int(r) for r in revs}
659 revs = {int(r) for r in revs}
660
660
661 def events():
661 def events():
662 for r in rlog:
662 for r in rlog:
663 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
663 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
664 if r in revs:
664 if r in revs:
665 yield b'l', (r, b"r%i" % r)
665 yield b'l', (r, b"r%i" % r)
666
666
667 elif repo:
667 elif repo:
668 cl = repo.changelog
668 cl = repo.changelog
669 tags = opts.get('tags')
669 tags = opts.get('tags')
670 branches = opts.get('branches')
670 branches = opts.get('branches')
671 if tags:
671 if tags:
672 labels = {}
672 labels = {}
673 for l, n in repo.tags().items():
673 for l, n in repo.tags().items():
674 labels.setdefault(cl.rev(n), []).append(l)
674 labels.setdefault(cl.rev(n), []).append(l)
675
675
676 def events():
676 def events():
677 b = b"default"
677 b = b"default"
678 for r in cl:
678 for r in cl:
679 if branches:
679 if branches:
680 newb = cl.read(cl.node(r))[5][b'branch']
680 newb = cl.read(cl.node(r))[5][b'branch']
681 if newb != b:
681 if newb != b:
682 yield b'a', newb
682 yield b'a', newb
683 b = newb
683 b = newb
684 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
684 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
685 if tags:
685 if tags:
686 ls = labels.get(r)
686 ls = labels.get(r)
687 if ls:
687 if ls:
688 for l in ls:
688 for l in ls:
689 yield b'l', (r, l)
689 yield b'l', (r, l)
690
690
691 else:
691 else:
692 raise error.Abort(_(b'need repo for changelog dag'))
692 raise error.Abort(_(b'need repo for changelog dag'))
693
693
694 for line in dagparser.dagtextlines(
694 for line in dagparser.dagtextlines(
695 events(),
695 events(),
696 addspaces=spaces,
696 addspaces=spaces,
697 wraplabels=True,
697 wraplabels=True,
698 wrapannotations=True,
698 wrapannotations=True,
699 wrapnonlinear=dots,
699 wrapnonlinear=dots,
700 usedots=dots,
700 usedots=dots,
701 maxlinewidth=70,
701 maxlinewidth=70,
702 ):
702 ):
703 ui.write(line)
703 ui.write(line)
704 ui.write(b"\n")
704 ui.write(b"\n")
705
705
706
706
707 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
707 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
708 def debugdata(ui, repo, file_, rev=None, **opts):
708 def debugdata(ui, repo, file_, rev=None, **opts):
709 """dump the contents of a data file revision"""
709 """dump the contents of a data file revision"""
710 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
710 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
711 if rev is not None:
711 if rev is not None:
712 raise error.InputError(
712 raise error.InputError(
713 _(b'cannot specify a revision with other arguments')
713 _(b'cannot specify a revision with other arguments')
714 )
714 )
715 file_, rev = None, file_
715 file_, rev = None, file_
716 elif rev is None:
716 elif rev is None:
717 raise error.InputError(_(b'please specify a revision'))
717 raise error.InputError(_(b'please specify a revision'))
718 r = cmdutil.openstorage(
718 r = cmdutil.openstorage(
719 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
719 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
720 )
720 )
721 try:
721 try:
722 ui.write(r.rawdata(r.lookup(rev)))
722 ui.write(r.rawdata(r.lookup(rev)))
723 except KeyError:
723 except KeyError:
724 raise error.Abort(_(b'invalid revision identifier %s') % rev)
724 raise error.Abort(_(b'invalid revision identifier %s') % rev)
725
725
726
726
727 @command(
727 @command(
728 b'debugdate',
728 b'debugdate',
729 [(b'e', b'extended', None, _(b'try extended date formats'))],
729 [(b'e', b'extended', None, _(b'try extended date formats'))],
730 _(b'[-e] DATE [RANGE]'),
730 _(b'[-e] DATE [RANGE]'),
731 norepo=True,
731 norepo=True,
732 optionalrepo=True,
732 optionalrepo=True,
733 )
733 )
734 def debugdate(ui, date, range=None, **opts):
734 def debugdate(ui, date, range=None, **opts):
735 """parse and display a date"""
735 """parse and display a date"""
736 if opts["extended"]:
736 if opts["extended"]:
737 d = dateutil.parsedate(date, dateutil.extendeddateformats)
737 d = dateutil.parsedate(date, dateutil.extendeddateformats)
738 else:
738 else:
739 d = dateutil.parsedate(date)
739 d = dateutil.parsedate(date)
740 ui.writenoi18n(b"internal: %d %d\n" % d)
740 ui.writenoi18n(b"internal: %d %d\n" % d)
741 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
741 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
742 if range:
742 if range:
743 m = dateutil.matchdate(range)
743 m = dateutil.matchdate(range)
744 ui.writenoi18n(b"match: %s\n" % m(d[0]))
744 ui.writenoi18n(b"match: %s\n" % m(d[0]))
745
745
746
746
747 @command(
747 @command(
748 b'debugdeltachain',
748 b'debugdeltachain',
749 [
749 [
750 (
750 (
751 b'r',
751 b'r',
752 b'rev',
752 b'rev',
753 [],
753 [],
754 _('restrict processing to these revlog revisions'),
754 _('restrict processing to these revlog revisions'),
755 ),
755 ),
756 (
756 (
757 b'',
757 b'',
758 b'all-info',
758 b'all-info',
759 False,
759 False,
760 _('compute all information unless specified otherwise'),
760 _('compute all information unless specified otherwise'),
761 ),
761 ),
762 (
762 (
763 b'',
763 b'',
764 b'size-info',
764 b'size-info',
765 None,
765 None,
766 _('compute information related to deltas size'),
766 _('compute information related to deltas size'),
767 ),
767 ),
768 (
768 (
769 b'',
769 b'',
770 b'dist-info',
770 b'dist-info',
771 None,
771 None,
772 _('compute information related to base distance'),
772 _('compute information related to base distance'),
773 ),
773 ),
774 (
774 (
775 b'',
775 b'',
776 b'sparse-info',
776 b'sparse-info',
777 None,
777 None,
778 _('compute information related to sparse read'),
778 _('compute information related to sparse read'),
779 ),
779 ),
780 ]
780 ]
781 + cmdutil.debugrevlogopts
781 + cmdutil.debugrevlogopts
782 + cmdutil.formatteropts,
782 + cmdutil.formatteropts,
783 _(b'-c|-m|FILE'),
783 _(b'-c|-m|FILE'),
784 optionalrepo=True,
784 optionalrepo=True,
785 )
785 )
786 def debugdeltachain(ui, repo, file_=None, **opts):
786 def debugdeltachain(ui, repo, file_=None, **opts):
787 """dump information about delta chains in a revlog
787 """dump information about delta chains in a revlog
788
788
789 Output can be templatized. Available template keywords are:
789 Output can be templatized. Available template keywords are:
790
790
791 :``rev``: revision number
791 :``rev``: revision number
792 :``p1``: parent 1 revision number (for reference)
792 :``p1``: parent 1 revision number (for reference)
793 :``p2``: parent 2 revision number (for reference)
793 :``p2``: parent 2 revision number (for reference)
794
794
795 :``chainid``: delta chain identifier (numbered by unique base)
795 :``chainid``: delta chain identifier (numbered by unique base)
796 :``chainlen``: delta chain length to this revision
796 :``chainlen``: delta chain length to this revision
797
797
798 :``prevrev``: previous revision in delta chain
798 :``prevrev``: previous revision in delta chain
799 :``deltatype``: role of delta / how it was computed
799 :``deltatype``: role of delta / how it was computed
800 - base: a full snapshot
800 - base: a full snapshot
801 - snap: an intermediate snapshot
801 - snap: an intermediate snapshot
802 - p1: a delta against the first parent
802 - p1: a delta against the first parent
803 - p2: a delta against the second parent
803 - p2: a delta against the second parent
804 - skip1: a delta against the same base as p1
804 - skip1: a delta against the same base as p1
805 (when p1 has empty delta
805 (when p1 has empty delta
806 - skip2: a delta against the same base as p2
806 - skip2: a delta against the same base as p2
807 (when p2 has empty delta
807 (when p2 has empty delta
808 - prev: a delta against the previous revision
808 - prev: a delta against the previous revision
809 - other: a delta against an arbitrary revision
809 - other: a delta against an arbitrary revision
810
810
811 :``compsize``: compressed size of revision
811 :``compsize``: compressed size of revision
812 :``uncompsize``: uncompressed size of revision
812 :``uncompsize``: uncompressed size of revision
813 :``chainsize``: total size of compressed revisions in chain
813 :``chainsize``: total size of compressed revisions in chain
814 :``chainratio``: total chain size divided by uncompressed revision size
814 :``chainratio``: total chain size divided by uncompressed revision size
815 (new delta chains typically start at ratio 2.00)
815 (new delta chains typically start at ratio 2.00)
816
816
817 :``lindist``: linear distance from base revision in delta chain to end
817 :``lindist``: linear distance from base revision in delta chain to end
818 of this revision
818 of this revision
819 :``extradist``: total size of revisions not part of this delta chain from
819 :``extradist``: total size of revisions not part of this delta chain from
820 base of delta chain to end of this revision; a measurement
820 base of delta chain to end of this revision; a measurement
821 of how much extra data we need to read/seek across to read
821 of how much extra data we need to read/seek across to read
822 the delta chain for this revision
822 the delta chain for this revision
823 :``extraratio``: extradist divided by chainsize; another representation of
823 :``extraratio``: extradist divided by chainsize; another representation of
824 how much unrelated data is needed to load this delta chain
824 how much unrelated data is needed to load this delta chain
825
825
826 If the repository is configured to use the sparse read, additional keywords
826 If the repository is configured to use the sparse read, additional keywords
827 are available:
827 are available:
828
828
829 :``readsize``: total size of data read from the disk for a revision
829 :``readsize``: total size of data read from the disk for a revision
830 (sum of the sizes of all the blocks)
830 (sum of the sizes of all the blocks)
831 :``largestblock``: size of the largest block of data read from the disk
831 :``largestblock``: size of the largest block of data read from the disk
832 :``readdensity``: density of useful bytes in the data read from the disk
832 :``readdensity``: density of useful bytes in the data read from the disk
833 :``srchunks``: in how many data hunks the whole revision would be read
833 :``srchunks``: in how many data hunks the whole revision would be read
834
834
835 It is possible to select the information to be computed, this can provide a
835 It is possible to select the information to be computed, this can provide a
836 noticeable speedup to the command in some cases.
836 noticeable speedup to the command in some cases.
837
837
838 Always computed:
838 Always computed:
839
839
840 - ``rev``
840 - ``rev``
841 - ``p1``
841 - ``p1``
842 - ``p2``
842 - ``p2``
843 - ``chainid``
843 - ``chainid``
844 - ``chainlen``
844 - ``chainlen``
845 - ``prevrev``
845 - ``prevrev``
846 - ``deltatype``
846 - ``deltatype``
847
847
848 Computed with --no-size-info
848 Computed with --no-size-info
849
849
850 - ``compsize``
850 - ``compsize``
851 - ``uncompsize``
851 - ``uncompsize``
852 - ``chainsize``
852 - ``chainsize``
853 - ``chainratio``
853 - ``chainratio``
854
854
855 Computed with --no-dist-info
855 Computed with --no-dist-info
856
856
857 - ``lindist``
857 - ``lindist``
858 - ``extradist``
858 - ``extradist``
859 - ``extraratio``
859 - ``extraratio``
860
860
861 Skipped with --no-sparse-info
861 Skipped with --no-sparse-info
862
862
863 - ``readsize``
863 - ``readsize``
864 - ``largestblock``
864 - ``largestblock``
865 - ``readdensity``
865 - ``readdensity``
866 - ``srchunks``
866 - ``srchunks``
867
867
868 --
868 --
869
869
870 The sparse read can be enabled with experimental.sparse-read = True
870 The sparse read can be enabled with experimental.sparse-read = True
871 """
871 """
872 revs = None
872 revs = None
873 revs_opt = opts.pop('rev', [])
873 revs_opt = opts.pop('rev', [])
874 if revs_opt:
874 if revs_opt:
875 revs = [int(r) for r in revs_opt]
875 revs = [int(r) for r in revs_opt]
876
876
877 all_info = opts.pop('all_info', False)
877 all_info = opts.pop('all_info', False)
878 size_info = opts.pop('size_info', None)
878 size_info = opts.pop('size_info', None)
879 if size_info is None:
879 if size_info is None:
880 size_info = all_info
880 size_info = all_info
881 dist_info = opts.pop('dist_info', None)
881 dist_info = opts.pop('dist_info', None)
882 if dist_info is None:
882 if dist_info is None:
883 dist_info = all_info
883 dist_info = all_info
884 sparse_info = opts.pop('sparse_info', None)
884 sparse_info = opts.pop('sparse_info', None)
885 if sparse_info is None:
885 if sparse_info is None:
886 sparse_info = all_info
886 sparse_info = all_info
887
887
888 revlog = cmdutil.openrevlog(
888 revlog = cmdutil.openrevlog(
889 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
889 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
890 )
890 )
891 fm = ui.formatter(b'debugdeltachain', pycompat.byteskwargs(opts))
891 fm = ui.formatter(b'debugdeltachain', pycompat.byteskwargs(opts))
892
892
893 lines = revlog_debug.debug_delta_chain(
893 lines = revlog_debug.debug_delta_chain(
894 revlog,
894 revlog,
895 revs=revs,
895 revs=revs,
896 size_info=size_info,
896 size_info=size_info,
897 dist_info=dist_info,
897 dist_info=dist_info,
898 sparse_info=sparse_info,
898 sparse_info=sparse_info,
899 )
899 )
900 # first entry is the header
900 # first entry is the header
901 header = next(lines)
901 header = next(lines)
902 fm.plain(header)
902 fm.plain(header)
903 for entry in lines:
903 for entry in lines:
904 label = b' '.join(e[0] for e in entry)
904 label = b' '.join(e[0] for e in entry)
905 format = b' '.join(e[1] for e in entry)
905 format = b' '.join(e[1] for e in entry)
906 values = [e[3] for e in entry]
906 values = [e[3] for e in entry]
907 data = dict((e[2], e[3]) for e in entry)
907 data = dict((e[2], e[3]) for e in entry)
908 fm.startitem()
908 fm.startitem()
909 fm.write(label, format, *values, **data)
909 fm.write(label, format, *values, **data)
910 fm.plain(b'\n')
910 fm.plain(b'\n')
911 fm.end()
911 fm.end()
912
912
913
913
914 @command(
914 @command(
915 b'debug-delta-find',
915 b'debug-delta-find',
916 cmdutil.debugrevlogopts
916 cmdutil.debugrevlogopts
917 + cmdutil.formatteropts
917 + cmdutil.formatteropts
918 + [
918 + [
919 (
919 (
920 b'',
920 b'',
921 b'source',
921 b'source',
922 b'full',
922 b'full',
923 _(b'input data feed to the process (full, storage, p1, p2, prev)'),
923 _(b'input data feed to the process (full, storage, p1, p2, prev)'),
924 ),
924 ),
925 ],
925 ],
926 _(b'-c|-m|FILE REV'),
926 _(b'-c|-m|FILE REV'),
927 optionalrepo=True,
927 optionalrepo=True,
928 )
928 )
929 def debugdeltafind(ui, repo, arg_1, arg_2=None, source=b'full', **opts):
929 def debugdeltafind(ui, repo, arg_1, arg_2=None, source=b'full', **opts):
930 """display the computation to get to a valid delta for storing REV
930 """display the computation to get to a valid delta for storing REV
931
931
932 This command will replay the process used to find the "best" delta to store
932 This command will replay the process used to find the "best" delta to store
933 a revision and display information about all the steps used to get to that
933 a revision and display information about all the steps used to get to that
934 result.
934 result.
935
935
936 By default, the process is fed with a the full-text for the revision. This
936 By default, the process is fed with a the full-text for the revision. This
937 can be controlled with the --source flag.
937 can be controlled with the --source flag.
938
938
939 The revision use the revision number of the target storage (not changelog
939 The revision use the revision number of the target storage (not changelog
940 revision number).
940 revision number).
941
941
942 note: the process is initiated from a full text of the revision to store.
942 note: the process is initiated from a full text of the revision to store.
943 """
943 """
944 if arg_2 is None:
944 if arg_2 is None:
945 file_ = None
945 file_ = None
946 rev = arg_1
946 rev = arg_1
947 else:
947 else:
948 file_ = arg_1
948 file_ = arg_1
949 rev = arg_2
949 rev = arg_2
950
950
951 rev = int(rev)
951 rev = int(rev)
952
952
953 revlog = cmdutil.openrevlog(
953 revlog = cmdutil.openrevlog(
954 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
954 repo, b'debugdeltachain', file_, pycompat.byteskwargs(opts)
955 )
955 )
956 p1r, p2r = revlog.parentrevs(rev)
956 p1r, p2r = revlog.parentrevs(rev)
957
957
958 if source == b'full':
958 if source == b'full':
959 base_rev = nullrev
959 base_rev = nullrev
960 elif source == b'storage':
960 elif source == b'storage':
961 base_rev = revlog.deltaparent(rev)
961 base_rev = revlog.deltaparent(rev)
962 elif source == b'p1':
962 elif source == b'p1':
963 base_rev = p1r
963 base_rev = p1r
964 elif source == b'p2':
964 elif source == b'p2':
965 base_rev = p2r
965 base_rev = p2r
966 elif source == b'prev':
966 elif source == b'prev':
967 base_rev = rev - 1
967 base_rev = rev - 1
968 else:
968 else:
969 raise error.InputError(b"invalid --source value: %s" % source)
969 raise error.InputError(b"invalid --source value: %s" % source)
970
970
971 revlog_debug.debug_delta_find(ui, revlog, rev, base_rev=base_rev)
971 revlog_debug.debug_delta_find(ui, revlog, rev, base_rev=base_rev)
972
972
973
973
974 @command(
974 @command(
975 b'debugdirstate|debugstate',
975 b'debugdirstate|debugstate',
976 [
976 [
977 (
977 (
978 b'',
978 b'',
979 b'nodates',
979 b'nodates',
980 None,
980 None,
981 _(b'do not display the saved mtime (DEPRECATED)'),
981 _(b'do not display the saved mtime (DEPRECATED)'),
982 ),
982 ),
983 (b'', b'dates', True, _(b'display the saved mtime')),
983 (b'', b'dates', True, _(b'display the saved mtime')),
984 (b'', b'datesort', None, _(b'sort by saved mtime')),
984 (b'', b'datesort', None, _(b'sort by saved mtime')),
985 (
985 (
986 b'',
986 b'',
987 b'docket',
987 b'docket',
988 False,
988 False,
989 _(b'display the docket (metadata file) instead'),
989 _(b'display the docket (metadata file) instead'),
990 ),
990 ),
991 (
991 (
992 b'',
992 b'',
993 b'all',
993 b'all',
994 False,
994 False,
995 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
995 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
996 ),
996 ),
997 ],
997 ],
998 _(b'[OPTION]...'),
998 _(b'[OPTION]...'),
999 )
999 )
1000 def debugstate(ui, repo, **opts):
1000 def debugstate(ui, repo, **opts):
1001 """show the contents of the current dirstate"""
1001 """show the contents of the current dirstate"""
1002
1002
1003 if opts.get("docket"):
1003 if opts.get("docket"):
1004 if not repo.dirstate._use_dirstate_v2:
1004 if not repo.dirstate._use_dirstate_v2:
1005 raise error.Abort(_(b'dirstate v1 does not have a docket'))
1005 raise error.Abort(_(b'dirstate v1 does not have a docket'))
1006
1006
1007 docket = repo.dirstate._map.docket
1007 docket = repo.dirstate._map.docket
1008 (
1008 (
1009 start_offset,
1009 start_offset,
1010 root_nodes,
1010 root_nodes,
1011 nodes_with_entry,
1011 nodes_with_entry,
1012 nodes_with_copy,
1012 nodes_with_copy,
1013 unused_bytes,
1013 unused_bytes,
1014 _unused,
1014 _unused,
1015 ignore_pattern,
1015 ignore_pattern,
1016 ) = dirstateutils.v2.TREE_METADATA.unpack(docket.tree_metadata)
1016 ) = dirstateutils.v2.TREE_METADATA.unpack(docket.tree_metadata)
1017
1017
1018 ui.write(_(b"size of dirstate data: %d\n") % docket.data_size)
1018 ui.write(_(b"size of dirstate data: %d\n") % docket.data_size)
1019 ui.write(_(b"data file uuid: %s\n") % docket.uuid)
1019 ui.write(_(b"data file uuid: %s\n") % docket.uuid)
1020 ui.write(_(b"start offset of root nodes: %d\n") % start_offset)
1020 ui.write(_(b"start offset of root nodes: %d\n") % start_offset)
1021 ui.write(_(b"number of root nodes: %d\n") % root_nodes)
1021 ui.write(_(b"number of root nodes: %d\n") % root_nodes)
1022 ui.write(_(b"nodes with entries: %d\n") % nodes_with_entry)
1022 ui.write(_(b"nodes with entries: %d\n") % nodes_with_entry)
1023 ui.write(_(b"nodes with copies: %d\n") % nodes_with_copy)
1023 ui.write(_(b"nodes with copies: %d\n") % nodes_with_copy)
1024 ui.write(_(b"number of unused bytes: %d\n") % unused_bytes)
1024 ui.write(_(b"number of unused bytes: %d\n") % unused_bytes)
1025 ui.write(
1025 ui.write(
1026 _(b"ignore pattern hash: %s\n") % binascii.hexlify(ignore_pattern)
1026 _(b"ignore pattern hash: %s\n") % binascii.hexlify(ignore_pattern)
1027 )
1027 )
1028 return
1028 return
1029
1029
1030 nodates = not opts['dates']
1030 nodates = not opts['dates']
1031 if opts.get('nodates') is not None:
1031 if opts.get('nodates') is not None:
1032 nodates = True
1032 nodates = True
1033 datesort = opts.get('datesort')
1033 datesort = opts.get('datesort')
1034
1034
1035 if datesort:
1035 if datesort:
1036
1036
1037 def keyfunc(entry):
1037 def keyfunc(entry):
1038 filename, _state, _mode, _size, mtime = entry
1038 filename, _state, _mode, _size, mtime = entry
1039 return (mtime, filename)
1039 return (mtime, filename)
1040
1040
1041 else:
1041 else:
1042 keyfunc = None # sort by filename
1042 keyfunc = None # sort by filename
1043 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
1043 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
1044 entries.sort(key=keyfunc)
1044 entries.sort(key=keyfunc)
1045 for entry in entries:
1045 for entry in entries:
1046 filename, state, mode, size, mtime = entry
1046 filename, state, mode, size, mtime = entry
1047 if mtime == -1:
1047 if mtime == -1:
1048 timestr = b'unset '
1048 timestr = b'unset '
1049 elif nodates:
1049 elif nodates:
1050 timestr = b'set '
1050 timestr = b'set '
1051 else:
1051 else:
1052 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
1052 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
1053 timestr = encoding.strtolocal(timestr)
1053 timestr = encoding.strtolocal(timestr)
1054 if mode & 0o20000:
1054 if mode & 0o20000:
1055 mode = b'lnk'
1055 mode = b'lnk'
1056 else:
1056 else:
1057 mode = b'%3o' % (mode & 0o777 & ~util.umask)
1057 mode = b'%3o' % (mode & 0o777 & ~util.umask)
1058 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
1058 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
1059 for f in repo.dirstate.copies():
1059 for f in repo.dirstate.copies():
1060 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1060 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1061
1061
1062
1062
1063 @command(
1063 @command(
1064 b'debugdirstateignorepatternshash',
1064 b'debugdirstateignorepatternshash',
1065 [],
1065 [],
1066 _(b''),
1066 _(b''),
1067 )
1067 )
1068 def debugdirstateignorepatternshash(ui, repo, **opts):
1068 def debugdirstateignorepatternshash(ui, repo, **opts):
1069 """show the hash of ignore patterns stored in dirstate if v2,
1069 """show the hash of ignore patterns stored in dirstate if v2,
1070 or nothing for dirstate-v2
1070 or nothing for dirstate-v2
1071 """
1071 """
1072 if repo.dirstate._use_dirstate_v2:
1072 if repo.dirstate._use_dirstate_v2:
1073 docket = repo.dirstate._map.docket
1073 docket = repo.dirstate._map.docket
1074 hash_len = 20 # 160 bits for SHA-1
1074 hash_len = 20 # 160 bits for SHA-1
1075 hash_bytes = docket.tree_metadata[-hash_len:]
1075 hash_bytes = docket.tree_metadata[-hash_len:]
1076 ui.write(binascii.hexlify(hash_bytes) + b'\n')
1076 ui.write(binascii.hexlify(hash_bytes) + b'\n')
1077
1077
1078
1078
1079 @command(
1079 @command(
1080 b'debugdiscovery',
1080 b'debugdiscovery',
1081 [
1081 [
1082 (b'', b'old', None, _(b'use old-style discovery')),
1082 (b'', b'old', None, _(b'use old-style discovery')),
1083 (
1083 (
1084 b'',
1084 b'',
1085 b'nonheads',
1085 b'nonheads',
1086 None,
1086 None,
1087 _(b'use old-style discovery with non-heads included'),
1087 _(b'use old-style discovery with non-heads included'),
1088 ),
1088 ),
1089 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1089 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1090 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1090 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1091 (
1091 (
1092 b'',
1092 b'',
1093 b'local-as-revs',
1093 b'local-as-revs',
1094 b"",
1094 b"",
1095 b'treat local has having these revisions only',
1095 b'treat local has having these revisions only',
1096 ),
1096 ),
1097 (
1097 (
1098 b'',
1098 b'',
1099 b'remote-as-revs',
1099 b'remote-as-revs',
1100 b"",
1100 b"",
1101 b'use local as remote, with only these revisions',
1101 b'use local as remote, with only these revisions',
1102 ),
1102 ),
1103 ]
1103 ]
1104 + cmdutil.remoteopts
1104 + cmdutil.remoteopts
1105 + cmdutil.formatteropts,
1105 + cmdutil.formatteropts,
1106 _(b'[--rev REV] [OTHER]'),
1106 _(b'[--rev REV] [OTHER]'),
1107 )
1107 )
1108 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1108 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1109 """runs the changeset discovery protocol in isolation
1109 """runs the changeset discovery protocol in isolation
1110
1110
1111 The local peer can be "replaced" by a subset of the local repository by
1111 The local peer can be "replaced" by a subset of the local repository by
1112 using the `--local-as-revs` flag. In the same way, the usual `remote` peer
1112 using the `--local-as-revs` flag. In the same way, the usual `remote` peer
1113 can be "replaced" by a subset of the local repository using the
1113 can be "replaced" by a subset of the local repository using the
1114 `--remote-as-revs` flag. This is useful to efficiently debug pathological
1114 `--remote-as-revs` flag. This is useful to efficiently debug pathological
1115 discovery situations.
1115 discovery situations.
1116
1116
1117 The following developer oriented config are relevant for people playing with this command:
1117 The following developer oriented config are relevant for people playing with this command:
1118
1118
1119 * devel.discovery.exchange-heads=True
1119 * devel.discovery.exchange-heads=True
1120
1120
1121 If False, the discovery will not start with
1121 If False, the discovery will not start with
1122 remote head fetching and local head querying.
1122 remote head fetching and local head querying.
1123
1123
1124 * devel.discovery.grow-sample=True
1124 * devel.discovery.grow-sample=True
1125
1125
1126 If False, the sample size used in set discovery will not be increased
1126 If False, the sample size used in set discovery will not be increased
1127 through the process
1127 through the process
1128
1128
1129 * devel.discovery.grow-sample.dynamic=True
1129 * devel.discovery.grow-sample.dynamic=True
1130
1130
1131 When discovery.grow-sample.dynamic is True, the default, the sample size is
1131 When discovery.grow-sample.dynamic is True, the default, the sample size is
1132 adapted to the shape of the undecided set (it is set to the max of:
1132 adapted to the shape of the undecided set (it is set to the max of:
1133 <target-size>, len(roots(undecided)), len(heads(undecided)
1133 <target-size>, len(roots(undecided)), len(heads(undecided)
1134
1134
1135 * devel.discovery.grow-sample.rate=1.05
1135 * devel.discovery.grow-sample.rate=1.05
1136
1136
1137 the rate at which the sample grow
1137 the rate at which the sample grow
1138
1138
1139 * devel.discovery.randomize=True
1139 * devel.discovery.randomize=True
1140
1140
1141 If andom sampling during discovery are deterministic. It is meant for
1141 If andom sampling during discovery are deterministic. It is meant for
1142 integration tests.
1142 integration tests.
1143
1143
1144 * devel.discovery.sample-size=200
1144 * devel.discovery.sample-size=200
1145
1145
1146 Control the initial size of the discovery sample
1146 Control the initial size of the discovery sample
1147
1147
1148 * devel.discovery.sample-size.initial=100
1148 * devel.discovery.sample-size.initial=100
1149
1149
1150 Control the initial size of the discovery for initial change
1150 Control the initial size of the discovery for initial change
1151 """
1151 """
1152 unfi = repo.unfiltered()
1152 unfi = repo.unfiltered()
1153
1153
1154 # setup potential extra filtering
1154 # setup potential extra filtering
1155 local_revs = opts["local_as_revs"]
1155 local_revs = opts["local_as_revs"]
1156 remote_revs = opts["remote_as_revs"]
1156 remote_revs = opts["remote_as_revs"]
1157
1157
1158 # make sure tests are repeatable
1158 # make sure tests are repeatable
1159 random.seed(int(opts['seed']))
1159 random.seed(int(opts['seed']))
1160
1160
1161 if not remote_revs:
1161 if not remote_revs:
1162 path = urlutil.get_unique_pull_path_obj(
1162 path = urlutil.get_unique_pull_path_obj(
1163 b'debugdiscovery', ui, remoteurl
1163 b'debugdiscovery', ui, remoteurl
1164 )
1164 )
1165 branches = (path.branch, [])
1165 branches = (path.branch, [])
1166 remote = hg.peer(repo, pycompat.byteskwargs(opts), path)
1166 remote = hg.peer(repo, pycompat.byteskwargs(opts), path)
1167 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
1167 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(path.loc))
1168 else:
1168 else:
1169 branches = (None, [])
1169 branches = (None, [])
1170 remote_filtered_revs = logcmdutil.revrange(
1170 remote_filtered_revs = logcmdutil.revrange(
1171 unfi, [b"not (::(%s))" % remote_revs]
1171 unfi, [b"not (::(%s))" % remote_revs]
1172 )
1172 )
1173 remote_filtered_revs = frozenset(remote_filtered_revs)
1173 remote_filtered_revs = frozenset(remote_filtered_revs)
1174
1174
1175 def remote_func(x):
1175 def remote_func(x):
1176 return remote_filtered_revs
1176 return remote_filtered_revs
1177
1177
1178 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1178 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1179
1179
1180 remote = repo.peer()
1180 remote = repo.peer()
1181 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1181 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1182
1182
1183 if local_revs:
1183 if local_revs:
1184 local_filtered_revs = logcmdutil.revrange(
1184 local_filtered_revs = logcmdutil.revrange(
1185 unfi, [b"not (::(%s))" % local_revs]
1185 unfi, [b"not (::(%s))" % local_revs]
1186 )
1186 )
1187 local_filtered_revs = frozenset(local_filtered_revs)
1187 local_filtered_revs = frozenset(local_filtered_revs)
1188
1188
1189 def local_func(x):
1189 def local_func(x):
1190 return local_filtered_revs
1190 return local_filtered_revs
1191
1191
1192 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1192 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1193 repo = repo.filtered(b'debug-discovery-local-filter')
1193 repo = repo.filtered(b'debug-discovery-local-filter')
1194
1194
1195 data = {}
1195 data = {}
1196 if opts.get('old'):
1196 if opts.get('old'):
1197
1197
1198 def doit(pushedrevs, remoteheads, remote=remote):
1198 def doit(pushedrevs, remoteheads, remote=remote):
1199 if not hasattr(remote, 'branches'):
1199 if not hasattr(remote, 'branches'):
1200 # enable in-client legacy support
1200 # enable in-client legacy support
1201 remote = localrepo.locallegacypeer(remote.local())
1201 remote = localrepo.locallegacypeer(remote.local())
1202 if remote_revs:
1202 if remote_revs:
1203 r = remote._repo.filtered(b'debug-discovery-remote-filter')
1203 r = remote._repo.filtered(b'debug-discovery-remote-filter')
1204 remote._repo = r
1204 remote._repo = r
1205 common, _in, hds = treediscovery.findcommonincoming(
1205 common, _in, hds = treediscovery.findcommonincoming(
1206 repo, remote, force=True, audit=data
1206 repo, remote, force=True, audit=data
1207 )
1207 )
1208 common = set(common)
1208 common = set(common)
1209 if not opts.get('nonheads'):
1209 if not opts.get('nonheads'):
1210 ui.writenoi18n(
1210 ui.writenoi18n(
1211 b"unpruned common: %s\n"
1211 b"unpruned common: %s\n"
1212 % b" ".join(sorted(short(n) for n in common))
1212 % b" ".join(sorted(short(n) for n in common))
1213 )
1213 )
1214
1214
1215 clnode = repo.changelog.node
1215 clnode = repo.changelog.node
1216 common = repo.revs(b'heads(::%ln)', common)
1216 common = repo.revs(b'heads(::%ln)', common)
1217 common = {clnode(r) for r in common}
1217 common = {clnode(r) for r in common}
1218 return common, hds
1218 return common, hds
1219
1219
1220 else:
1220 else:
1221
1221
1222 def doit(pushedrevs, remoteheads, remote=remote):
1222 def doit(pushedrevs, remoteheads, remote=remote):
1223 nodes = None
1223 nodes = None
1224 if pushedrevs:
1224 if pushedrevs:
1225 revs = logcmdutil.revrange(repo, pushedrevs)
1225 revs = logcmdutil.revrange(repo, pushedrevs)
1226 nodes = [repo[r].node() for r in revs]
1226 nodes = [repo[r].node() for r in revs]
1227 common, any, hds = setdiscovery.findcommonheads(
1227 common, any, hds = setdiscovery.findcommonheads(
1228 ui,
1228 ui,
1229 repo,
1229 repo,
1230 remote,
1230 remote,
1231 ancestorsof=nodes,
1231 ancestorsof=nodes,
1232 audit=data,
1232 audit=data,
1233 abortwhenunrelated=False,
1233 abortwhenunrelated=False,
1234 )
1234 )
1235 return common, hds
1235 return common, hds
1236
1236
1237 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1237 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1238 localrevs = opts['rev']
1238 localrevs = opts['rev']
1239
1239
1240 fm = ui.formatter(b'debugdiscovery', pycompat.byteskwargs(opts))
1240 fm = ui.formatter(b'debugdiscovery', pycompat.byteskwargs(opts))
1241 if fm.strict_format:
1241 if fm.strict_format:
1242
1242
1243 @contextlib.contextmanager
1243 @contextlib.contextmanager
1244 def may_capture_output():
1244 def may_capture_output():
1245 ui.pushbuffer()
1245 ui.pushbuffer()
1246 yield
1246 yield
1247 data[b'output'] = ui.popbuffer()
1247 data[b'output'] = ui.popbuffer()
1248
1248
1249 else:
1249 else:
1250 may_capture_output = util.nullcontextmanager
1250 may_capture_output = util.nullcontextmanager
1251 with may_capture_output():
1251 with may_capture_output():
1252 with util.timedcm('debug-discovery') as t:
1252 with util.timedcm('debug-discovery') as t:
1253 common, hds = doit(localrevs, remoterevs)
1253 common, hds = doit(localrevs, remoterevs)
1254
1254
1255 # compute all statistics
1255 # compute all statistics
1256 if len(common) == 1 and repo.nullid in common:
1256 if len(common) == 1 and repo.nullid in common:
1257 common = set()
1257 common = set()
1258 heads_common = set(common)
1258 heads_common = set(common)
1259 heads_remote = set(hds)
1259 heads_remote = set(hds)
1260 heads_local = set(repo.heads())
1260 heads_local = set(repo.heads())
1261 # note: they cannot be a local or remote head that is in common and not
1261 # note: they cannot be a local or remote head that is in common and not
1262 # itself a head of common.
1262 # itself a head of common.
1263 heads_common_local = heads_common & heads_local
1263 heads_common_local = heads_common & heads_local
1264 heads_common_remote = heads_common & heads_remote
1264 heads_common_remote = heads_common & heads_remote
1265 heads_common_both = heads_common & heads_remote & heads_local
1265 heads_common_both = heads_common & heads_remote & heads_local
1266
1266
1267 all = repo.revs(b'all()')
1267 all = repo.revs(b'all()')
1268 common = repo.revs(b'::%ln', common)
1268 common = repo.revs(b'::%ln', common)
1269 roots_common = repo.revs(b'roots(::%ld)', common)
1269 roots_common = repo.revs(b'roots(::%ld)', common)
1270 missing = repo.revs(b'not ::%ld', common)
1270 missing = repo.revs(b'not ::%ld', common)
1271 heads_missing = repo.revs(b'heads(%ld)', missing)
1271 heads_missing = repo.revs(b'heads(%ld)', missing)
1272 roots_missing = repo.revs(b'roots(%ld)', missing)
1272 roots_missing = repo.revs(b'roots(%ld)', missing)
1273 assert len(common) + len(missing) == len(all)
1273 assert len(common) + len(missing) == len(all)
1274
1274
1275 initial_undecided = repo.revs(
1275 initial_undecided = repo.revs(
1276 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1276 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1277 )
1277 )
1278 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1278 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1279 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1279 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1280 common_initial_undecided = initial_undecided & common
1280 common_initial_undecided = initial_undecided & common
1281 missing_initial_undecided = initial_undecided & missing
1281 missing_initial_undecided = initial_undecided & missing
1282
1282
1283 data[b'elapsed'] = t.elapsed
1283 data[b'elapsed'] = t.elapsed
1284 data[b'nb-common-heads'] = len(heads_common)
1284 data[b'nb-common-heads'] = len(heads_common)
1285 data[b'nb-common-heads-local'] = len(heads_common_local)
1285 data[b'nb-common-heads-local'] = len(heads_common_local)
1286 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1286 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1287 data[b'nb-common-heads-both'] = len(heads_common_both)
1287 data[b'nb-common-heads-both'] = len(heads_common_both)
1288 data[b'nb-common-roots'] = len(roots_common)
1288 data[b'nb-common-roots'] = len(roots_common)
1289 data[b'nb-head-local'] = len(heads_local)
1289 data[b'nb-head-local'] = len(heads_local)
1290 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1290 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1291 data[b'nb-head-remote'] = len(heads_remote)
1291 data[b'nb-head-remote'] = len(heads_remote)
1292 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1292 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1293 heads_common_remote
1293 heads_common_remote
1294 )
1294 )
1295 data[b'nb-revs'] = len(all)
1295 data[b'nb-revs'] = len(all)
1296 data[b'nb-revs-common'] = len(common)
1296 data[b'nb-revs-common'] = len(common)
1297 data[b'nb-revs-missing'] = len(missing)
1297 data[b'nb-revs-missing'] = len(missing)
1298 data[b'nb-missing-heads'] = len(heads_missing)
1298 data[b'nb-missing-heads'] = len(heads_missing)
1299 data[b'nb-missing-roots'] = len(roots_missing)
1299 data[b'nb-missing-roots'] = len(roots_missing)
1300 data[b'nb-ini_und'] = len(initial_undecided)
1300 data[b'nb-ini_und'] = len(initial_undecided)
1301 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1301 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1302 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1302 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1303 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1303 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1304 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1304 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1305
1305
1306 fm.startitem()
1306 fm.startitem()
1307 fm.data(**pycompat.strkwargs(data))
1307 fm.data(**pycompat.strkwargs(data))
1308 # display discovery summary
1308 # display discovery summary
1309 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1309 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1310 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1310 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1311 if b'total-round-trips-heads' in data:
1311 if b'total-round-trips-heads' in data:
1312 fm.plain(
1312 fm.plain(
1313 b" round-trips-heads: %(total-round-trips-heads)9d\n" % data
1313 b" round-trips-heads: %(total-round-trips-heads)9d\n" % data
1314 )
1314 )
1315 if b'total-round-trips-branches' in data:
1315 if b'total-round-trips-branches' in data:
1316 fm.plain(
1316 fm.plain(
1317 b" round-trips-branches: %(total-round-trips-branches)9d\n"
1317 b" round-trips-branches: %(total-round-trips-branches)9d\n"
1318 % data
1318 % data
1319 )
1319 )
1320 if b'total-round-trips-between' in data:
1320 if b'total-round-trips-between' in data:
1321 fm.plain(
1321 fm.plain(
1322 b" round-trips-between: %(total-round-trips-between)9d\n" % data
1322 b" round-trips-between: %(total-round-trips-between)9d\n" % data
1323 )
1323 )
1324 fm.plain(b"queries: %(total-queries)9d\n" % data)
1324 fm.plain(b"queries: %(total-queries)9d\n" % data)
1325 if b'total-queries-branches' in data:
1325 if b'total-queries-branches' in data:
1326 fm.plain(b" queries-branches: %(total-queries-branches)9d\n" % data)
1326 fm.plain(b" queries-branches: %(total-queries-branches)9d\n" % data)
1327 if b'total-queries-between' in data:
1327 if b'total-queries-between' in data:
1328 fm.plain(b" queries-between: %(total-queries-between)9d\n" % data)
1328 fm.plain(b" queries-between: %(total-queries-between)9d\n" % data)
1329 fm.plain(b"heads summary:\n")
1329 fm.plain(b"heads summary:\n")
1330 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1330 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1331 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1331 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1332 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1332 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1333 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1333 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1334 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1334 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1335 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1335 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1336 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1336 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1337 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1337 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1338 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1338 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1339 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1339 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1340 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1340 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1341 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1341 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1342 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1342 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1343 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1343 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1344 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1344 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1345 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1345 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1346 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1346 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1347 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1347 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1348 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1348 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1349 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1349 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1350 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1350 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1351 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1351 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1352
1352
1353 if ui.verbose:
1353 if ui.verbose:
1354 fm.plain(
1354 fm.plain(
1355 b"common heads: %s\n"
1355 b"common heads: %s\n"
1356 % b" ".join(sorted(short(n) for n in heads_common))
1356 % b" ".join(sorted(short(n) for n in heads_common))
1357 )
1357 )
1358 fm.end()
1358 fm.end()
1359
1359
1360
1360
1361 _chunksize = 4 << 10
1361 _chunksize = 4 << 10
1362
1362
1363
1363
1364 @command(
1364 @command(
1365 b'debugdownload',
1365 b'debugdownload',
1366 [
1366 [
1367 (b'o', b'output', b'', _(b'path')),
1367 (b'o', b'output', b'', _(b'path')),
1368 ],
1368 ],
1369 optionalrepo=True,
1369 optionalrepo=True,
1370 )
1370 )
1371 def debugdownload(ui, repo, url, output=None, **opts):
1371 def debugdownload(ui, repo, url, output=None, **opts):
1372 """download a resource using Mercurial logic and config"""
1372 """download a resource using Mercurial logic and config"""
1373 fh = urlmod.open(ui, url, output)
1373 fh = urlmod.open(ui, url, output)
1374
1374
1375 dest = ui
1375 dest = ui
1376 if output:
1376 if output:
1377 dest = open(output, b"wb", _chunksize)
1377 dest = open(output, b"wb", _chunksize)
1378 try:
1378 try:
1379 data = fh.read(_chunksize)
1379 data = fh.read(_chunksize)
1380 while data:
1380 while data:
1381 dest.write(data)
1381 dest.write(data)
1382 data = fh.read(_chunksize)
1382 data = fh.read(_chunksize)
1383 finally:
1383 finally:
1384 if output:
1384 if output:
1385 dest.close()
1385 dest.close()
1386
1386
1387
1387
1388 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1388 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1389 def debugextensions(ui, repo, **opts):
1389 def debugextensions(ui, repo, **opts):
1390 '''show information about active extensions'''
1390 '''show information about active extensions'''
1391 exts = extensions.extensions(ui)
1391 exts = extensions.extensions(ui)
1392 hgver = util.version()
1392 hgver = util.version()
1393 fm = ui.formatter(b'debugextensions', pycompat.byteskwargs(opts))
1393 fm = ui.formatter(b'debugextensions', pycompat.byteskwargs(opts))
1394 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1394 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1395 isinternal = extensions.ismoduleinternal(extmod)
1395 isinternal = extensions.ismoduleinternal(extmod)
1396 extsource = None
1396 extsource = None
1397
1397
1398 if hasattr(extmod, '__file__'):
1398 if hasattr(extmod, '__file__'):
1399 extsource = pycompat.fsencode(extmod.__file__)
1399 extsource = pycompat.fsencode(extmod.__file__)
1400 elif getattr(sys, 'oxidized', False):
1400 elif getattr(sys, 'oxidized', False):
1401 extsource = pycompat.sysexecutable
1401 extsource = pycompat.sysexecutable
1402 if isinternal:
1402 if isinternal:
1403 exttestedwith = [] # never expose magic string to users
1403 exttestedwith = [] # never expose magic string to users
1404 else:
1404 else:
1405 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1405 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1406 extbuglink = getattr(extmod, 'buglink', None)
1406 extbuglink = getattr(extmod, 'buglink', None)
1407
1407
1408 fm.startitem()
1408 fm.startitem()
1409
1409
1410 if ui.quiet or ui.verbose:
1410 if ui.quiet or ui.verbose:
1411 fm.write(b'name', b'%s\n', extname)
1411 fm.write(b'name', b'%s\n', extname)
1412 else:
1412 else:
1413 fm.write(b'name', b'%s', extname)
1413 fm.write(b'name', b'%s', extname)
1414 if isinternal or hgver in exttestedwith:
1414 if isinternal or hgver in exttestedwith:
1415 fm.plain(b'\n')
1415 fm.plain(b'\n')
1416 elif not exttestedwith:
1416 elif not exttestedwith:
1417 fm.plain(_(b' (untested!)\n'))
1417 fm.plain(_(b' (untested!)\n'))
1418 else:
1418 else:
1419 lasttestedversion = exttestedwith[-1]
1419 lasttestedversion = exttestedwith[-1]
1420 fm.plain(b' (%s!)\n' % lasttestedversion)
1420 fm.plain(b' (%s!)\n' % lasttestedversion)
1421
1421
1422 fm.condwrite(
1422 fm.condwrite(
1423 ui.verbose and extsource,
1423 ui.verbose and extsource,
1424 b'source',
1424 b'source',
1425 _(b' location: %s\n'),
1425 _(b' location: %s\n'),
1426 extsource or b"",
1426 extsource or b"",
1427 )
1427 )
1428
1428
1429 if ui.verbose:
1429 if ui.verbose:
1430 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1430 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1431 fm.data(bundled=isinternal)
1431 fm.data(bundled=isinternal)
1432
1432
1433 fm.condwrite(
1433 fm.condwrite(
1434 ui.verbose and exttestedwith,
1434 ui.verbose and exttestedwith,
1435 b'testedwith',
1435 b'testedwith',
1436 _(b' tested with: %s\n'),
1436 _(b' tested with: %s\n'),
1437 fm.formatlist(exttestedwith, name=b'ver'),
1437 fm.formatlist(exttestedwith, name=b'ver'),
1438 )
1438 )
1439
1439
1440 fm.condwrite(
1440 fm.condwrite(
1441 ui.verbose and extbuglink,
1441 ui.verbose and extbuglink,
1442 b'buglink',
1442 b'buglink',
1443 _(b' bug reporting: %s\n'),
1443 _(b' bug reporting: %s\n'),
1444 extbuglink or b"",
1444 extbuglink or b"",
1445 )
1445 )
1446
1446
1447 fm.end()
1447 fm.end()
1448
1448
1449
1449
1450 @command(
1450 @command(
1451 b'debugfileset',
1451 b'debugfileset',
1452 [
1452 [
1453 (
1453 (
1454 b'r',
1454 b'r',
1455 b'rev',
1455 b'rev',
1456 b'',
1456 b'',
1457 _(b'apply the filespec on this revision'),
1457 _(b'apply the filespec on this revision'),
1458 _(b'REV'),
1458 _(b'REV'),
1459 ),
1459 ),
1460 (
1460 (
1461 b'',
1461 b'',
1462 b'all-files',
1462 b'all-files',
1463 False,
1463 False,
1464 _(b'test files from all revisions and working directory'),
1464 _(b'test files from all revisions and working directory'),
1465 ),
1465 ),
1466 (
1466 (
1467 b's',
1467 b's',
1468 b'show-matcher',
1468 b'show-matcher',
1469 None,
1469 None,
1470 _(b'print internal representation of matcher'),
1470 _(b'print internal representation of matcher'),
1471 ),
1471 ),
1472 (
1472 (
1473 b'p',
1473 b'p',
1474 b'show-stage',
1474 b'show-stage',
1475 [],
1475 [],
1476 _(b'print parsed tree at the given stage'),
1476 _(b'print parsed tree at the given stage'),
1477 _(b'NAME'),
1477 _(b'NAME'),
1478 ),
1478 ),
1479 ],
1479 ],
1480 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1480 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1481 )
1481 )
1482 def debugfileset(ui, repo, expr, **opts):
1482 def debugfileset(ui, repo, expr, **opts):
1483 '''parse and apply a fileset specification'''
1483 '''parse and apply a fileset specification'''
1484 from . import fileset
1484 from . import fileset
1485
1485
1486 fileset.symbols # force import of fileset so we have predicates to optimize
1486 fileset.symbols # force import of fileset so we have predicates to optimize
1487
1487
1488 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
1488 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
1489
1489
1490 stages = [
1490 stages = [
1491 (b'parsed', pycompat.identity),
1491 (b'parsed', pycompat.identity),
1492 (b'analyzed', filesetlang.analyze),
1492 (b'analyzed', filesetlang.analyze),
1493 (b'optimized', filesetlang.optimize),
1493 (b'optimized', filesetlang.optimize),
1494 ]
1494 ]
1495 stagenames = {n for n, f in stages}
1495 stagenames = {n for n, f in stages}
1496
1496
1497 showalways = set()
1497 showalways = set()
1498 if ui.verbose and not opts['show_stage']:
1498 if ui.verbose and not opts['show_stage']:
1499 # show parsed tree by --verbose (deprecated)
1499 # show parsed tree by --verbose (deprecated)
1500 showalways.add(b'parsed')
1500 showalways.add(b'parsed')
1501 if opts['show_stage'] == [b'all']:
1501 if opts['show_stage'] == [b'all']:
1502 showalways.update(stagenames)
1502 showalways.update(stagenames)
1503 else:
1503 else:
1504 for n in opts['show_stage']:
1504 for n in opts['show_stage']:
1505 if n not in stagenames:
1505 if n not in stagenames:
1506 raise error.Abort(_(b'invalid stage name: %s') % n)
1506 raise error.Abort(_(b'invalid stage name: %s') % n)
1507 showalways.update(opts['show_stage'])
1507 showalways.update(opts['show_stage'])
1508
1508
1509 tree = filesetlang.parse(expr)
1509 tree = filesetlang.parse(expr)
1510 for n, f in stages:
1510 for n, f in stages:
1511 tree = f(tree)
1511 tree = f(tree)
1512 if n in showalways:
1512 if n in showalways:
1513 if opts['show_stage'] or n != b'parsed':
1513 if opts['show_stage'] or n != b'parsed':
1514 ui.write(b"* %s:\n" % n)
1514 ui.write(b"* %s:\n" % n)
1515 ui.write(filesetlang.prettyformat(tree), b"\n")
1515 ui.write(filesetlang.prettyformat(tree), b"\n")
1516
1516
1517 files = set()
1517 files = set()
1518 if opts['all_files']:
1518 if opts['all_files']:
1519 for r in repo:
1519 for r in repo:
1520 c = repo[r]
1520 c = repo[r]
1521 files.update(c.files())
1521 files.update(c.files())
1522 files.update(c.substate)
1522 files.update(c.substate)
1523 if opts['all_files'] or ctx.rev() is None:
1523 if opts['all_files'] or ctx.rev() is None:
1524 wctx = repo[None]
1524 wctx = repo[None]
1525 files.update(
1525 files.update(
1526 repo.dirstate.walk(
1526 repo.dirstate.walk(
1527 scmutil.matchall(repo),
1527 scmutil.matchall(repo),
1528 subrepos=list(wctx.substate),
1528 subrepos=list(wctx.substate),
1529 unknown=True,
1529 unknown=True,
1530 ignored=True,
1530 ignored=True,
1531 )
1531 )
1532 )
1532 )
1533 files.update(wctx.substate)
1533 files.update(wctx.substate)
1534 else:
1534 else:
1535 files.update(ctx.files())
1535 files.update(ctx.files())
1536 files.update(ctx.substate)
1536 files.update(ctx.substate)
1537
1537
1538 m = ctx.matchfileset(repo.getcwd(), expr)
1538 m = ctx.matchfileset(repo.getcwd(), expr)
1539 if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
1539 if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
1540 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1540 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1541 for f in sorted(files):
1541 for f in sorted(files):
1542 if not m(f):
1542 if not m(f):
1543 continue
1543 continue
1544 ui.write(b"%s\n" % f)
1544 ui.write(b"%s\n" % f)
1545
1545
1546
1546
1547 @command(
1547 @command(
1548 b"debug-repair-issue6528",
1548 b"debug-repair-issue6528",
1549 [
1549 [
1550 (
1550 (
1551 b'',
1551 b'',
1552 b'to-report',
1552 b'to-report',
1553 b'',
1553 b'',
1554 _(b'build a report of affected revisions to this file'),
1554 _(b'build a report of affected revisions to this file'),
1555 _(b'FILE'),
1555 _(b'FILE'),
1556 ),
1556 ),
1557 (
1557 (
1558 b'',
1558 b'',
1559 b'from-report',
1559 b'from-report',
1560 b'',
1560 b'',
1561 _(b'repair revisions listed in this report file'),
1561 _(b'repair revisions listed in this report file'),
1562 _(b'FILE'),
1562 _(b'FILE'),
1563 ),
1563 ),
1564 (
1564 (
1565 b'',
1565 b'',
1566 b'paranoid',
1566 b'paranoid',
1567 False,
1567 False,
1568 _(b'check that both detection methods do the same thing'),
1568 _(b'check that both detection methods do the same thing'),
1569 ),
1569 ),
1570 ]
1570 ]
1571 + cmdutil.dryrunopts,
1571 + cmdutil.dryrunopts,
1572 )
1572 )
1573 def debug_repair_issue6528(ui, repo, **opts):
1573 def debug_repair_issue6528(ui, repo, **opts):
1574 """find affected revisions and repair them. See issue6528 for more details.
1574 """find affected revisions and repair them. See issue6528 for more details.
1575
1575
1576 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1576 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1577 computation of affected revisions for a given repository across clones.
1577 computation of affected revisions for a given repository across clones.
1578 The report format is line-based (with empty lines ignored):
1578 The report format is line-based (with empty lines ignored):
1579
1579
1580 ```
1580 ```
1581 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1581 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1582 ```
1582 ```
1583
1583
1584 There can be multiple broken revisions per filelog, they are separated by
1584 There can be multiple broken revisions per filelog, they are separated by
1585 a comma with no spaces. The only space is between the revision(s) and the
1585 a comma with no spaces. The only space is between the revision(s) and the
1586 filename.
1586 filename.
1587
1587
1588 Note that this does *not* mean that this repairs future affected revisions,
1588 Note that this does *not* mean that this repairs future affected revisions,
1589 that needs a separate fix at the exchange level that was introduced in
1589 that needs a separate fix at the exchange level that was introduced in
1590 Mercurial 5.9.1.
1590 Mercurial 5.9.1.
1591
1591
1592 There is a `--paranoid` flag to test that the fast implementation is correct
1592 There is a `--paranoid` flag to test that the fast implementation is correct
1593 by checking it against the slow implementation. Since this matter is quite
1593 by checking it against the slow implementation. Since this matter is quite
1594 urgent and testing every edge-case is probably quite costly, we use this
1594 urgent and testing every edge-case is probably quite costly, we use this
1595 method to test on large repositories as a fuzzing method of sorts.
1595 method to test on large repositories as a fuzzing method of sorts.
1596 """
1596 """
1597 cmdutil.check_incompatible_arguments(
1597 cmdutil.check_incompatible_arguments(
1598 opts, 'to_report', ['from_report', 'dry_run']
1598 opts, 'to_report', ['from_report', 'dry_run']
1599 )
1599 )
1600 dry_run = opts.get('dry_run')
1600 dry_run = opts.get('dry_run')
1601 to_report = opts.get('to_report')
1601 to_report = opts.get('to_report')
1602 from_report = opts.get('from_report')
1602 from_report = opts.get('from_report')
1603 paranoid = opts.get('paranoid')
1603 paranoid = opts.get('paranoid')
1604 # TODO maybe add filelog pattern and revision pattern parameters to help
1604 # TODO maybe add filelog pattern and revision pattern parameters to help
1605 # narrow down the search for users that know what they're looking for?
1605 # narrow down the search for users that know what they're looking for?
1606
1606
1607 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1607 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1608 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1608 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1609 raise error.Abort(_(msg))
1609 raise error.Abort(_(msg))
1610
1610
1611 rewrite.repair_issue6528(
1611 rewrite.repair_issue6528(
1612 ui,
1612 ui,
1613 repo,
1613 repo,
1614 dry_run=dry_run,
1614 dry_run=dry_run,
1615 to_report=to_report,
1615 to_report=to_report,
1616 from_report=from_report,
1616 from_report=from_report,
1617 paranoid=paranoid,
1617 paranoid=paranoid,
1618 )
1618 )
1619
1619
1620
1620
1621 @command(b'debugformat', [] + cmdutil.formatteropts)
1621 @command(b'debugformat', [] + cmdutil.formatteropts)
1622 def debugformat(ui, repo, **opts):
1622 def debugformat(ui, repo, **opts):
1623 """display format information about the current repository
1623 """display format information about the current repository
1624
1624
1625 Use --verbose to get extra information about current config value and
1625 Use --verbose to get extra information about current config value and
1626 Mercurial default."""
1626 Mercurial default."""
1627 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1627 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1628 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1628 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1629
1629
1630 def makeformatname(name):
1630 def makeformatname(name):
1631 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1631 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1632
1632
1633 fm = ui.formatter(b'debugformat', pycompat.byteskwargs(opts))
1633 fm = ui.formatter(b'debugformat', pycompat.byteskwargs(opts))
1634 if fm.isplain():
1634 if fm.isplain():
1635
1635
1636 def formatvalue(value):
1636 def formatvalue(value):
1637 if hasattr(value, 'startswith'):
1637 if hasattr(value, 'startswith'):
1638 return value
1638 return value
1639 if value:
1639 if value:
1640 return b'yes'
1640 return b'yes'
1641 else:
1641 else:
1642 return b'no'
1642 return b'no'
1643
1643
1644 else:
1644 else:
1645 formatvalue = pycompat.identity
1645 formatvalue = pycompat.identity
1646
1646
1647 fm.plain(b'format-variant')
1647 fm.plain(b'format-variant')
1648 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1648 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1649 fm.plain(b' repo')
1649 fm.plain(b' repo')
1650 if ui.verbose:
1650 if ui.verbose:
1651 fm.plain(b' config default')
1651 fm.plain(b' config default')
1652 fm.plain(b'\n')
1652 fm.plain(b'\n')
1653 for fv in upgrade.allformatvariant:
1653 for fv in upgrade.allformatvariant:
1654 fm.startitem()
1654 fm.startitem()
1655 repovalue = fv.fromrepo(repo)
1655 repovalue = fv.fromrepo(repo)
1656 configvalue = fv.fromconfig(repo)
1656 configvalue = fv.fromconfig(repo)
1657
1657
1658 if repovalue != configvalue:
1658 if repovalue != configvalue:
1659 namelabel = b'formatvariant.name.mismatchconfig'
1659 namelabel = b'formatvariant.name.mismatchconfig'
1660 repolabel = b'formatvariant.repo.mismatchconfig'
1660 repolabel = b'formatvariant.repo.mismatchconfig'
1661 elif repovalue != fv.default:
1661 elif repovalue != fv.default:
1662 namelabel = b'formatvariant.name.mismatchdefault'
1662 namelabel = b'formatvariant.name.mismatchdefault'
1663 repolabel = b'formatvariant.repo.mismatchdefault'
1663 repolabel = b'formatvariant.repo.mismatchdefault'
1664 else:
1664 else:
1665 namelabel = b'formatvariant.name.uptodate'
1665 namelabel = b'formatvariant.name.uptodate'
1666 repolabel = b'formatvariant.repo.uptodate'
1666 repolabel = b'formatvariant.repo.uptodate'
1667
1667
1668 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1668 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1669 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1669 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1670 if fv.default != configvalue:
1670 if fv.default != configvalue:
1671 configlabel = b'formatvariant.config.special'
1671 configlabel = b'formatvariant.config.special'
1672 else:
1672 else:
1673 configlabel = b'formatvariant.config.default'
1673 configlabel = b'formatvariant.config.default'
1674 fm.condwrite(
1674 fm.condwrite(
1675 ui.verbose,
1675 ui.verbose,
1676 b'config',
1676 b'config',
1677 b' %6s',
1677 b' %6s',
1678 formatvalue(configvalue),
1678 formatvalue(configvalue),
1679 label=configlabel,
1679 label=configlabel,
1680 )
1680 )
1681 fm.condwrite(
1681 fm.condwrite(
1682 ui.verbose,
1682 ui.verbose,
1683 b'default',
1683 b'default',
1684 b' %7s',
1684 b' %7s',
1685 formatvalue(fv.default),
1685 formatvalue(fv.default),
1686 label=b'formatvariant.default',
1686 label=b'formatvariant.default',
1687 )
1687 )
1688 fm.plain(b'\n')
1688 fm.plain(b'\n')
1689 fm.end()
1689 fm.end()
1690
1690
1691
1691
1692 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1692 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1693 def debugfsinfo(ui, path=b"."):
1693 def debugfsinfo(ui, path=b"."):
1694 """show information detected about current filesystem"""
1694 """show information detected about current filesystem"""
1695 ui.writenoi18n(b'path: %s\n' % path)
1695 ui.writenoi18n(b'path: %s\n' % path)
1696 ui.writenoi18n(
1696 ui.writenoi18n(
1697 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1697 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1698 )
1698 )
1699 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1699 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1700 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1700 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1701 ui.writenoi18n(
1701 ui.writenoi18n(
1702 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1702 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1703 )
1703 )
1704 ui.writenoi18n(
1704 ui.writenoi18n(
1705 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1705 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1706 )
1706 )
1707 casesensitive = b'(unknown)'
1707 casesensitive = b'(unknown)'
1708 try:
1708 try:
1709 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1709 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1710 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1710 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1711 except OSError:
1711 except OSError:
1712 pass
1712 pass
1713 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1713 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1714
1714
1715
1715
1716 @command(
1716 @command(
1717 b'debuggetbundle',
1717 b'debuggetbundle',
1718 [
1718 [
1719 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1719 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1720 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1720 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1721 (
1721 (
1722 b't',
1722 b't',
1723 b'type',
1723 b'type',
1724 b'bzip2',
1724 b'bzip2',
1725 _(b'bundle compression type to use'),
1725 _(b'bundle compression type to use'),
1726 _(b'TYPE'),
1726 _(b'TYPE'),
1727 ),
1727 ),
1728 ],
1728 ],
1729 _(b'REPO FILE [-H|-C ID]...'),
1729 _(b'REPO FILE [-H|-C ID]...'),
1730 norepo=True,
1730 norepo=True,
1731 )
1731 )
1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1732 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1733 """retrieves a bundle from a repo
1733 """retrieves a bundle from a repo
1734
1734
1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1735 Every ID must be a full-length hex node id string. Saves the bundle to the
1736 given file.
1736 given file.
1737 """
1737 """
1738 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
1738 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
1739 if not repo.capable(b'getbundle'):
1739 if not repo.capable(b'getbundle'):
1740 raise error.Abort(b"getbundle() not supported by target repository")
1740 raise error.Abort(b"getbundle() not supported by target repository")
1741 args = {}
1741 args = {}
1742 if common:
1742 if common:
1743 args['common'] = [bin(s) for s in common]
1743 args['common'] = [bin(s) for s in common]
1744 if head:
1744 if head:
1745 args['heads'] = [bin(s) for s in head]
1745 args['heads'] = [bin(s) for s in head]
1746 # TODO: get desired bundlecaps from command line.
1746 # TODO: get desired bundlecaps from command line.
1747 args['bundlecaps'] = None
1747 args['bundlecaps'] = None
1748 bundle = repo.getbundle(b'debug', **args)
1748 bundle = repo.getbundle(b'debug', **args)
1749
1749
1750 bundletype = opts.get('type', b'bzip2').lower()
1750 bundletype = opts.get('type', b'bzip2').lower()
1751 btypes = {
1751 btypes = {
1752 b'none': b'HG10UN',
1752 b'none': b'HG10UN',
1753 b'bzip2': b'HG10BZ',
1753 b'bzip2': b'HG10BZ',
1754 b'gzip': b'HG10GZ',
1754 b'gzip': b'HG10GZ',
1755 b'bundle2': b'HG20',
1755 b'bundle2': b'HG20',
1756 }
1756 }
1757 bundletype = btypes.get(bundletype)
1757 bundletype = btypes.get(bundletype)
1758 if bundletype not in bundle2.bundletypes:
1758 if bundletype not in bundle2.bundletypes:
1759 raise error.Abort(_(b'unknown bundle type specified with --type'))
1759 raise error.Abort(_(b'unknown bundle type specified with --type'))
1760 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1760 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1761
1761
1762
1762
1763 @command(b'debugignore', [], b'[FILE]...')
1763 @command(b'debugignore', [], b'[FILE]...')
1764 def debugignore(ui, repo, *files, **opts):
1764 def debugignore(ui, repo, *files, **opts):
1765 """display the combined ignore pattern and information about ignored files
1765 """display the combined ignore pattern and information about ignored files
1766
1766
1767 With no argument display the combined ignore pattern.
1767 With no argument display the combined ignore pattern.
1768
1768
1769 Given space separated file names, shows if the given file is ignored and
1769 Given space separated file names, shows if the given file is ignored and
1770 if so, show the ignore rule (file and line number) that matched it.
1770 if so, show the ignore rule (file and line number) that matched it.
1771 """
1771 """
1772 ignore = repo.dirstate._ignore
1772 ignore = repo.dirstate._ignore
1773 if not files:
1773 if not files:
1774 # Show all the patterns
1774 # Show all the patterns
1775 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1775 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1776 else:
1776 else:
1777 m = scmutil.match(repo[None], pats=files)
1777 m = scmutil.match(repo[None], pats=files)
1778 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1778 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1779 for f in m.files():
1779 for f in m.files():
1780 nf = util.normpath(f)
1780 nf = util.normpath(f)
1781 ignored = None
1781 ignored = None
1782 ignoredata = None
1782 ignoredata = None
1783 if nf != b'.':
1783 if nf != b'.':
1784 if ignore(nf):
1784 if ignore(nf):
1785 ignored = nf
1785 ignored = nf
1786 ignoredata = repo.dirstate._ignorefileandline(nf)
1786 ignoredata = repo.dirstate._ignorefileandline(nf)
1787 else:
1787 else:
1788 for p in pathutil.finddirs(nf):
1788 for p in pathutil.finddirs(nf):
1789 if ignore(p):
1789 if ignore(p):
1790 ignored = p
1790 ignored = p
1791 ignoredata = repo.dirstate._ignorefileandline(p)
1791 ignoredata = repo.dirstate._ignorefileandline(p)
1792 break
1792 break
1793 if ignored:
1793 if ignored:
1794 if ignored == nf:
1794 if ignored == nf:
1795 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1795 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1796 else:
1796 else:
1797 ui.write(
1797 ui.write(
1798 _(
1798 _(
1799 b"%s is ignored because of "
1799 b"%s is ignored because of "
1800 b"containing directory %s\n"
1800 b"containing directory %s\n"
1801 )
1801 )
1802 % (uipathfn(f), ignored)
1802 % (uipathfn(f), ignored)
1803 )
1803 )
1804 ignorefile, lineno, line = ignoredata
1804 ignorefile, lineno, line = ignoredata
1805 ui.write(
1805 ui.write(
1806 _(b"(ignore rule in %s, line %d: '%s')\n")
1806 _(b"(ignore rule in %s, line %d: '%s')\n")
1807 % (ignorefile, lineno, line)
1807 % (ignorefile, lineno, line)
1808 )
1808 )
1809 else:
1809 else:
1810 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1810 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1811
1811
1812
1812
1813 @command(
1813 @command(
1814 b'debug-revlog-index|debugindex',
1814 b'debug-revlog-index|debugindex',
1815 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1815 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1816 _(b'-c|-m|FILE'),
1816 _(b'-c|-m|FILE'),
1817 )
1817 )
1818 def debugindex(ui, repo, file_=None, **opts):
1818 def debugindex(ui, repo, file_=None, **opts):
1819 """dump index data for a revlog"""
1819 """dump index data for a revlog"""
1820 opts = pycompat.byteskwargs(opts)
1820 opts = pycompat.byteskwargs(opts)
1821 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1821 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1822
1822
1823 fm = ui.formatter(b'debugindex', opts)
1823 fm = ui.formatter(b'debugindex', opts)
1824
1824
1825 revlog = getattr(store, '_revlog', store)
1825 revlog = getattr(store, '_revlog', store)
1826
1826
1827 return revlog_debug.debug_index(
1827 return revlog_debug.debug_index(
1828 ui,
1828 ui,
1829 repo,
1829 repo,
1830 formatter=fm,
1830 formatter=fm,
1831 revlog=revlog,
1831 revlog=revlog,
1832 full_node=ui.debugflag,
1832 full_node=ui.debugflag,
1833 )
1833 )
1834
1834
1835
1835
1836 @command(
1836 @command(
1837 b'debugindexdot',
1837 b'debugindexdot',
1838 cmdutil.debugrevlogopts,
1838 cmdutil.debugrevlogopts,
1839 _(b'-c|-m|FILE'),
1839 _(b'-c|-m|FILE'),
1840 optionalrepo=True,
1840 optionalrepo=True,
1841 )
1841 )
1842 def debugindexdot(ui, repo, file_=None, **opts):
1842 def debugindexdot(ui, repo, file_=None, **opts):
1843 """dump an index DAG as a graphviz dot file"""
1843 """dump an index DAG as a graphviz dot file"""
1844 r = cmdutil.openstorage(
1844 r = cmdutil.openstorage(
1845 repo, b'debugindexdot', file_, pycompat.byteskwargs(opts)
1845 repo, b'debugindexdot', file_, pycompat.byteskwargs(opts)
1846 )
1846 )
1847 ui.writenoi18n(b"digraph G {\n")
1847 ui.writenoi18n(b"digraph G {\n")
1848 for i in r:
1848 for i in r:
1849 node = r.node(i)
1849 node = r.node(i)
1850 pp = r.parents(node)
1850 pp = r.parents(node)
1851 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1851 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1852 if pp[1] != repo.nullid:
1852 if pp[1] != repo.nullid:
1853 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1853 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1854 ui.write(b"}\n")
1854 ui.write(b"}\n")
1855
1855
1856
1856
1857 @command(b'debugindexstats', [])
1857 @command(b'debugindexstats', [])
1858 def debugindexstats(ui, repo):
1858 def debugindexstats(ui, repo):
1859 """show stats related to the changelog index"""
1859 """show stats related to the changelog index"""
1860 repo.changelog.shortest(repo.nullid, 1)
1860 repo.changelog.shortest(repo.nullid, 1)
1861 index = repo.changelog.index
1861 index = repo.changelog.index
1862 if not hasattr(index, 'stats'):
1862 if not hasattr(index, 'stats'):
1863 raise error.Abort(_(b'debugindexstats only works with native C code'))
1863 raise error.Abort(_(b'debugindexstats only works with native C code'))
1864 for k, v in sorted(index.stats().items()):
1864 for k, v in sorted(index.stats().items()):
1865 ui.write(b'%s: %d\n' % (k, v))
1865 ui.write(b'%s: %d\n' % (k, v))
1866
1866
1867
1867
1868 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1868 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1869 def debuginstall(ui, **opts):
1869 def debuginstall(ui, **opts):
1870 """test Mercurial installation
1870 """test Mercurial installation
1871
1871
1872 Returns 0 on success.
1872 Returns 0 on success.
1873 """
1873 """
1874 problems = 0
1874 problems = 0
1875
1875
1876 fm = ui.formatter(b'debuginstall', pycompat.byteskwargs(opts))
1876 fm = ui.formatter(b'debuginstall', pycompat.byteskwargs(opts))
1877 fm.startitem()
1877 fm.startitem()
1878
1878
1879 # encoding might be unknown or wrong. don't translate these messages.
1879 # encoding might be unknown or wrong. don't translate these messages.
1880 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1880 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1881 err = None
1881 err = None
1882 try:
1882 try:
1883 codecs.lookup(pycompat.sysstr(encoding.encoding))
1883 codecs.lookup(pycompat.sysstr(encoding.encoding))
1884 except LookupError as inst:
1884 except LookupError as inst:
1885 err = stringutil.forcebytestr(inst)
1885 err = stringutil.forcebytestr(inst)
1886 problems += 1
1886 problems += 1
1887 fm.condwrite(
1887 fm.condwrite(
1888 err,
1888 err,
1889 b'encodingerror',
1889 b'encodingerror',
1890 b" %s\n (check that your locale is properly set)\n",
1890 b" %s\n (check that your locale is properly set)\n",
1891 err,
1891 err,
1892 )
1892 )
1893
1893
1894 # Python
1894 # Python
1895 pythonlib = None
1895 pythonlib = None
1896 if hasattr(os, '__file__'):
1896 if hasattr(os, '__file__'):
1897 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1897 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1898 elif getattr(sys, 'oxidized', False):
1898 elif getattr(sys, 'oxidized', False):
1899 pythonlib = pycompat.sysexecutable
1899 pythonlib = pycompat.sysexecutable
1900
1900
1901 fm.write(
1901 fm.write(
1902 b'pythonexe',
1902 b'pythonexe',
1903 _(b"checking Python executable (%s)\n"),
1903 _(b"checking Python executable (%s)\n"),
1904 pycompat.sysexecutable or _(b"unknown"),
1904 pycompat.sysexecutable or _(b"unknown"),
1905 )
1905 )
1906 fm.write(
1906 fm.write(
1907 b'pythonimplementation',
1907 b'pythonimplementation',
1908 _(b"checking Python implementation (%s)\n"),
1908 _(b"checking Python implementation (%s)\n"),
1909 pycompat.sysbytes(platform.python_implementation()),
1909 pycompat.sysbytes(platform.python_implementation()),
1910 )
1910 )
1911 fm.write(
1911 fm.write(
1912 b'pythonver',
1912 b'pythonver',
1913 _(b"checking Python version (%s)\n"),
1913 _(b"checking Python version (%s)\n"),
1914 (b"%d.%d.%d" % sys.version_info[:3]),
1914 (b"%d.%d.%d" % sys.version_info[:3]),
1915 )
1915 )
1916 fm.write(
1916 fm.write(
1917 b'pythonlib',
1917 b'pythonlib',
1918 _(b"checking Python lib (%s)...\n"),
1918 _(b"checking Python lib (%s)...\n"),
1919 pythonlib or _(b"unknown"),
1919 pythonlib or _(b"unknown"),
1920 )
1920 )
1921
1921
1922 try:
1922 try:
1923 from . import rustext # pytype: disable=import-error
1923 from . import rustext # pytype: disable=import-error
1924
1924
1925 rustext.__doc__ # trigger lazy import
1925 rustext.__doc__ # trigger lazy import
1926 except ImportError:
1926 except ImportError:
1927 rustext = None
1927 rustext = None
1928
1928
1929 security = set(sslutil.supportedprotocols)
1929 security = set(sslutil.supportedprotocols)
1930 if sslutil.hassni:
1930 if sslutil.hassni:
1931 security.add(b'sni')
1931 security.add(b'sni')
1932
1932
1933 fm.write(
1933 fm.write(
1934 b'pythonsecurity',
1934 b'pythonsecurity',
1935 _(b"checking Python security support (%s)\n"),
1935 _(b"checking Python security support (%s)\n"),
1936 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1936 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1937 )
1937 )
1938
1938
1939 # These are warnings, not errors. So don't increment problem count. This
1939 # These are warnings, not errors. So don't increment problem count. This
1940 # may change in the future.
1940 # may change in the future.
1941 if b'tls1.2' not in security:
1941 if b'tls1.2' not in security:
1942 fm.plain(
1942 fm.plain(
1943 _(
1943 _(
1944 b' TLS 1.2 not supported by Python install; '
1944 b' TLS 1.2 not supported by Python install; '
1945 b'network connections lack modern security\n'
1945 b'network connections lack modern security\n'
1946 )
1946 )
1947 )
1947 )
1948 if b'sni' not in security:
1948 if b'sni' not in security:
1949 fm.plain(
1949 fm.plain(
1950 _(
1950 _(
1951 b' SNI not supported by Python install; may have '
1951 b' SNI not supported by Python install; may have '
1952 b'connectivity issues with some servers\n'
1952 b'connectivity issues with some servers\n'
1953 )
1953 )
1954 )
1954 )
1955
1955
1956 fm.plain(
1956 fm.plain(
1957 _(
1957 _(
1958 b"checking Rust extensions (%s)\n"
1958 b"checking Rust extensions (%s)\n"
1959 % (b'missing' if rustext is None else b'installed')
1959 % (b'missing' if rustext is None else b'installed')
1960 ),
1960 ),
1961 )
1961 )
1962
1962
1963 # TODO print CA cert info
1963 # TODO print CA cert info
1964
1964
1965 # hg version
1965 # hg version
1966 hgver = util.version()
1966 hgver = util.version()
1967 fm.write(
1967 fm.write(
1968 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1968 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1969 )
1969 )
1970 fm.write(
1970 fm.write(
1971 b'hgverextra',
1971 b'hgverextra',
1972 _(b"checking Mercurial custom build (%s)\n"),
1972 _(b"checking Mercurial custom build (%s)\n"),
1973 b'+'.join(hgver.split(b'+')[1:]),
1973 b'+'.join(hgver.split(b'+')[1:]),
1974 )
1974 )
1975
1975
1976 # compiled modules
1976 # compiled modules
1977 hgmodules = None
1977 hgmodules = None
1978 if hasattr(sys.modules[__name__], '__file__'):
1978 if hasattr(sys.modules[__name__], '__file__'):
1979 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1979 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1980 elif getattr(sys, 'oxidized', False):
1980 elif getattr(sys, 'oxidized', False):
1981 hgmodules = pycompat.sysexecutable
1981 hgmodules = pycompat.sysexecutable
1982
1982
1983 fm.write(
1983 fm.write(
1984 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1984 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1985 )
1985 )
1986 fm.write(
1986 fm.write(
1987 b'hgmodules',
1987 b'hgmodules',
1988 _(b"checking installed modules (%s)...\n"),
1988 _(b"checking installed modules (%s)...\n"),
1989 hgmodules or _(b"unknown"),
1989 hgmodules or _(b"unknown"),
1990 )
1990 )
1991
1991
1992 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1992 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1993 rustext = rustandc # for now, that's the only case
1993 rustext = rustandc # for now, that's the only case
1994 cext = policy.policy in (b'c', b'allow') or rustandc
1994 cext = policy.policy in (b'c', b'allow') or rustandc
1995 nopure = cext or rustext
1995 nopure = cext or rustext
1996 if nopure:
1996 if nopure:
1997 err = None
1997 err = None
1998 try:
1998 try:
1999 if cext:
1999 if cext:
2000 from .cext import ( # pytype: disable=import-error
2000 from .cext import ( # pytype: disable=import-error
2001 base85,
2001 base85,
2002 bdiff,
2002 bdiff,
2003 mpatch,
2003 mpatch,
2004 osutil,
2004 osutil,
2005 )
2005 )
2006
2006
2007 # quiet pyflakes
2007 # quiet pyflakes
2008 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
2008 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
2009 if rustext:
2009 if rustext:
2010 from .rustext import ( # pytype: disable=import-error
2010 from .rustext import ( # pytype: disable=import-error
2011 ancestor,
2011 ancestor,
2012 dirstate,
2012 dirstate,
2013 )
2013 )
2014
2014
2015 dir(ancestor), dir(dirstate) # quiet pyflakes
2015 dir(ancestor), dir(dirstate) # quiet pyflakes
2016 except Exception as inst:
2016 except Exception as inst:
2017 err = stringutil.forcebytestr(inst)
2017 err = stringutil.forcebytestr(inst)
2018 problems += 1
2018 problems += 1
2019 fm.condwrite(err, b'extensionserror', b" %s\n", err)
2019 fm.condwrite(err, b'extensionserror', b" %s\n", err)
2020
2020
2021 compengines = util.compengines._engines.values()
2021 compengines = util.compengines._engines.values()
2022 fm.write(
2022 fm.write(
2023 b'compengines',
2023 b'compengines',
2024 _(b'checking registered compression engines (%s)\n'),
2024 _(b'checking registered compression engines (%s)\n'),
2025 fm.formatlist(
2025 fm.formatlist(
2026 sorted(e.name() for e in compengines),
2026 sorted(e.name() for e in compengines),
2027 name=b'compengine',
2027 name=b'compengine',
2028 fmt=b'%s',
2028 fmt=b'%s',
2029 sep=b', ',
2029 sep=b', ',
2030 ),
2030 ),
2031 )
2031 )
2032 fm.write(
2032 fm.write(
2033 b'compenginesavail',
2033 b'compenginesavail',
2034 _(b'checking available compression engines (%s)\n'),
2034 _(b'checking available compression engines (%s)\n'),
2035 fm.formatlist(
2035 fm.formatlist(
2036 sorted(e.name() for e in compengines if e.available()),
2036 sorted(e.name() for e in compengines if e.available()),
2037 name=b'compengine',
2037 name=b'compengine',
2038 fmt=b'%s',
2038 fmt=b'%s',
2039 sep=b', ',
2039 sep=b', ',
2040 ),
2040 ),
2041 )
2041 )
2042 wirecompengines = compression.compengines.supportedwireengines(
2042 wirecompengines = compression.compengines.supportedwireengines(
2043 compression.SERVERROLE
2043 compression.SERVERROLE
2044 )
2044 )
2045 fm.write(
2045 fm.write(
2046 b'compenginesserver',
2046 b'compenginesserver',
2047 _(
2047 _(
2048 b'checking available compression engines '
2048 b'checking available compression engines '
2049 b'for wire protocol (%s)\n'
2049 b'for wire protocol (%s)\n'
2050 ),
2050 ),
2051 fm.formatlist(
2051 fm.formatlist(
2052 [e.name() for e in wirecompengines if e.wireprotosupport()],
2052 [e.name() for e in wirecompengines if e.wireprotosupport()],
2053 name=b'compengine',
2053 name=b'compengine',
2054 fmt=b'%s',
2054 fmt=b'%s',
2055 sep=b', ',
2055 sep=b', ',
2056 ),
2056 ),
2057 )
2057 )
2058 re2 = b'missing'
2058 re2 = b'missing'
2059 if util.has_re2():
2059 if util.has_re2():
2060 re2 = b'available'
2060 re2 = b'available'
2061 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
2061 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
2062 fm.data(re2=bool(util._re2))
2062 fm.data(re2=bool(util._re2))
2063
2063
2064 # templates
2064 # templates
2065 p = templater.templatedir()
2065 p = templater.templatedir()
2066 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
2066 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
2067 fm.condwrite(not p, b'', _(b" no template directories found\n"))
2067 fm.condwrite(not p, b'', _(b" no template directories found\n"))
2068 if p:
2068 if p:
2069 (m, fp) = templater.try_open_template(b"map-cmdline.default")
2069 (m, fp) = templater.try_open_template(b"map-cmdline.default")
2070 if m:
2070 if m:
2071 # template found, check if it is working
2071 # template found, check if it is working
2072 err = None
2072 err = None
2073 try:
2073 try:
2074 templater.templater.frommapfile(m)
2074 templater.templater.frommapfile(m)
2075 except Exception as inst:
2075 except Exception as inst:
2076 err = stringutil.forcebytestr(inst)
2076 err = stringutil.forcebytestr(inst)
2077 p = None
2077 p = None
2078 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
2078 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
2079 else:
2079 else:
2080 p = None
2080 p = None
2081 fm.condwrite(
2081 fm.condwrite(
2082 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
2082 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
2083 )
2083 )
2084 fm.condwrite(
2084 fm.condwrite(
2085 not m,
2085 not m,
2086 b'defaulttemplatenotfound',
2086 b'defaulttemplatenotfound',
2087 _(b" template '%s' not found\n"),
2087 _(b" template '%s' not found\n"),
2088 b"default",
2088 b"default",
2089 )
2089 )
2090 if not p:
2090 if not p:
2091 problems += 1
2091 problems += 1
2092 fm.condwrite(
2092 fm.condwrite(
2093 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2093 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2094 )
2094 )
2095
2095
2096 # editor
2096 # editor
2097 editor = ui.geteditor()
2097 editor = ui.geteditor()
2098 editor = util.expandpath(editor)
2098 editor = util.expandpath(editor)
2099 editorbin = procutil.shellsplit(editor)[0]
2099 editorbin = procutil.shellsplit(editor)[0]
2100 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2100 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2101 cmdpath = procutil.findexe(editorbin)
2101 cmdpath = procutil.findexe(editorbin)
2102 fm.condwrite(
2102 fm.condwrite(
2103 not cmdpath and editor == b'vi',
2103 not cmdpath and editor == b'vi',
2104 b'vinotfound',
2104 b'vinotfound',
2105 _(
2105 _(
2106 b" No commit editor set and can't find %s in PATH\n"
2106 b" No commit editor set and can't find %s in PATH\n"
2107 b" (specify a commit editor in your configuration"
2107 b" (specify a commit editor in your configuration"
2108 b" file)\n"
2108 b" file)\n"
2109 ),
2109 ),
2110 not cmdpath and editor == b'vi' and editorbin,
2110 not cmdpath and editor == b'vi' and editorbin,
2111 )
2111 )
2112 fm.condwrite(
2112 fm.condwrite(
2113 not cmdpath and editor != b'vi',
2113 not cmdpath and editor != b'vi',
2114 b'editornotfound',
2114 b'editornotfound',
2115 _(
2115 _(
2116 b" Can't find editor '%s' in PATH\n"
2116 b" Can't find editor '%s' in PATH\n"
2117 b" (specify a commit editor in your configuration"
2117 b" (specify a commit editor in your configuration"
2118 b" file)\n"
2118 b" file)\n"
2119 ),
2119 ),
2120 not cmdpath and editorbin,
2120 not cmdpath and editorbin,
2121 )
2121 )
2122 if not cmdpath and editor != b'vi':
2122 if not cmdpath and editor != b'vi':
2123 problems += 1
2123 problems += 1
2124
2124
2125 # check username
2125 # check username
2126 username = None
2126 username = None
2127 err = None
2127 err = None
2128 try:
2128 try:
2129 username = ui.username()
2129 username = ui.username()
2130 except error.Abort as e:
2130 except error.Abort as e:
2131 err = e.message
2131 err = e.message
2132 problems += 1
2132 problems += 1
2133
2133
2134 fm.condwrite(
2134 fm.condwrite(
2135 username, b'username', _(b"checking username (%s)\n"), username
2135 username, b'username', _(b"checking username (%s)\n"), username
2136 )
2136 )
2137 fm.condwrite(
2137 fm.condwrite(
2138 err,
2138 err,
2139 b'usernameerror',
2139 b'usernameerror',
2140 _(
2140 _(
2141 b"checking username...\n %s\n"
2141 b"checking username...\n %s\n"
2142 b" (specify a username in your configuration file)\n"
2142 b" (specify a username in your configuration file)\n"
2143 ),
2143 ),
2144 err,
2144 err,
2145 )
2145 )
2146
2146
2147 for name, mod in extensions.extensions():
2147 for name, mod in extensions.extensions():
2148 handler = getattr(mod, 'debuginstall', None)
2148 handler = getattr(mod, 'debuginstall', None)
2149 if handler is not None:
2149 if handler is not None:
2150 problems += handler(ui, fm)
2150 problems += handler(ui, fm)
2151
2151
2152 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2152 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2153 if not problems:
2153 if not problems:
2154 fm.data(problems=problems)
2154 fm.data(problems=problems)
2155 fm.condwrite(
2155 fm.condwrite(
2156 problems,
2156 problems,
2157 b'problems',
2157 b'problems',
2158 _(b"%d problems detected, please check your install!\n"),
2158 _(b"%d problems detected, please check your install!\n"),
2159 problems,
2159 problems,
2160 )
2160 )
2161 fm.end()
2161 fm.end()
2162
2162
2163 return problems
2163 return problems
2164
2164
2165
2165
2166 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2166 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2167 def debugknown(ui, repopath, *ids, **opts):
2167 def debugknown(ui, repopath, *ids, **opts):
2168 """test whether node ids are known to a repo
2168 """test whether node ids are known to a repo
2169
2169
2170 Every ID must be a full-length hex node id string. Returns a list of 0s
2170 Every ID must be a full-length hex node id string. Returns a list of 0s
2171 and 1s indicating unknown/known.
2171 and 1s indicating unknown/known.
2172 """
2172 """
2173 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
2173 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
2174 if not repo.capable(b'known'):
2174 if not repo.capable(b'known'):
2175 raise error.Abort(b"known() not supported by target repository")
2175 raise error.Abort(b"known() not supported by target repository")
2176 flags = repo.known([bin(s) for s in ids])
2176 flags = repo.known([bin(s) for s in ids])
2177 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2177 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2178
2178
2179
2179
2180 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2180 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2181 def debuglabelcomplete(ui, repo, *args):
2181 def debuglabelcomplete(ui, repo, *args):
2182 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2182 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2183 debugnamecomplete(ui, repo, *args)
2183 debugnamecomplete(ui, repo, *args)
2184
2184
2185
2185
2186 @command(
2186 @command(
2187 b'debuglocks',
2187 b'debuglocks',
2188 [
2188 [
2189 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2189 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2190 (
2190 (
2191 b'W',
2191 b'W',
2192 b'force-free-wlock',
2192 b'force-free-wlock',
2193 None,
2193 None,
2194 _(b'free the working state lock (DANGEROUS)'),
2194 _(b'free the working state lock (DANGEROUS)'),
2195 ),
2195 ),
2196 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2196 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2197 (
2197 (
2198 b'S',
2198 b'S',
2199 b'set-wlock',
2199 b'set-wlock',
2200 None,
2200 None,
2201 _(b'set the working state lock until stopped'),
2201 _(b'set the working state lock until stopped'),
2202 ),
2202 ),
2203 ],
2203 ],
2204 _(b'[OPTION]...'),
2204 _(b'[OPTION]...'),
2205 )
2205 )
2206 def debuglocks(ui, repo, **opts):
2206 def debuglocks(ui, repo, **opts):
2207 """show or modify state of locks
2207 """show or modify state of locks
2208
2208
2209 By default, this command will show which locks are held. This
2209 By default, this command will show which locks are held. This
2210 includes the user and process holding the lock, the amount of time
2210 includes the user and process holding the lock, the amount of time
2211 the lock has been held, and the machine name where the process is
2211 the lock has been held, and the machine name where the process is
2212 running if it's not local.
2212 running if it's not local.
2213
2213
2214 Locks protect the integrity of Mercurial's data, so should be
2214 Locks protect the integrity of Mercurial's data, so should be
2215 treated with care. System crashes or other interruptions may cause
2215 treated with care. System crashes or other interruptions may cause
2216 locks to not be properly released, though Mercurial will usually
2216 locks to not be properly released, though Mercurial will usually
2217 detect and remove such stale locks automatically.
2217 detect and remove such stale locks automatically.
2218
2218
2219 However, detecting stale locks may not always be possible (for
2219 However, detecting stale locks may not always be possible (for
2220 instance, on a shared filesystem). Removing locks may also be
2220 instance, on a shared filesystem). Removing locks may also be
2221 blocked by filesystem permissions.
2221 blocked by filesystem permissions.
2222
2222
2223 Setting a lock will prevent other commands from changing the data.
2223 Setting a lock will prevent other commands from changing the data.
2224 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2224 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2225 The set locks are removed when the command exits.
2225 The set locks are removed when the command exits.
2226
2226
2227 Returns 0 if no locks are held.
2227 Returns 0 if no locks are held.
2228
2228
2229 """
2229 """
2230
2230
2231 if opts.get('force_free_lock'):
2231 if opts.get('force_free_lock'):
2232 repo.svfs.tryunlink(b'lock')
2232 repo.svfs.tryunlink(b'lock')
2233 if opts.get('force_free_wlock'):
2233 if opts.get('force_free_wlock'):
2234 repo.vfs.tryunlink(b'wlock')
2234 repo.vfs.tryunlink(b'wlock')
2235 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2235 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2236 return 0
2236 return 0
2237
2237
2238 locks = []
2238 locks = []
2239 try:
2239 try:
2240 if opts.get('set_wlock'):
2240 if opts.get('set_wlock'):
2241 try:
2241 try:
2242 locks.append(repo.wlock(False))
2242 locks.append(repo.wlock(False))
2243 except error.LockHeld:
2243 except error.LockHeld:
2244 raise error.Abort(_(b'wlock is already held'))
2244 raise error.Abort(_(b'wlock is already held'))
2245 if opts.get('set_lock'):
2245 if opts.get('set_lock'):
2246 try:
2246 try:
2247 locks.append(repo.lock(False))
2247 locks.append(repo.lock(False))
2248 except error.LockHeld:
2248 except error.LockHeld:
2249 raise error.Abort(_(b'lock is already held'))
2249 raise error.Abort(_(b'lock is already held'))
2250 if len(locks):
2250 if len(locks):
2251 try:
2251 try:
2252 if ui.interactive():
2252 if ui.interactive():
2253 prompt = _(b"ready to release the lock (y)? $$ &Yes")
2253 prompt = _(b"ready to release the lock (y)? $$ &Yes")
2254 ui.promptchoice(prompt)
2254 ui.promptchoice(prompt)
2255 else:
2255 else:
2256 msg = b"%d locks held, waiting for signal\n"
2256 msg = b"%d locks held, waiting for signal\n"
2257 msg %= len(locks)
2257 msg %= len(locks)
2258 ui.status(msg)
2258 ui.status(msg)
2259 while True: # XXX wait for a signal
2259 while True: # XXX wait for a signal
2260 time.sleep(0.1)
2260 time.sleep(0.1)
2261 except KeyboardInterrupt:
2261 except KeyboardInterrupt:
2262 msg = b"signal-received releasing locks\n"
2262 msg = b"signal-received releasing locks\n"
2263 ui.status(msg)
2263 ui.status(msg)
2264 return 0
2264 return 0
2265 finally:
2265 finally:
2266 release(*locks)
2266 release(*locks)
2267
2267
2268 now = time.time()
2268 now = time.time()
2269 held = 0
2269 held = 0
2270
2270
2271 def report(vfs, name, method):
2271 def report(vfs, name, method):
2272 # this causes stale locks to get reaped for more accurate reporting
2272 # this causes stale locks to get reaped for more accurate reporting
2273 try:
2273 try:
2274 l = method(False)
2274 l = method(False)
2275 except error.LockHeld:
2275 except error.LockHeld:
2276 l = None
2276 l = None
2277
2277
2278 if l:
2278 if l:
2279 l.release()
2279 l.release()
2280 else:
2280 else:
2281 try:
2281 try:
2282 st = vfs.lstat(name)
2282 st = vfs.lstat(name)
2283 age = now - st[stat.ST_MTIME]
2283 age = now - st[stat.ST_MTIME]
2284 user = util.username(st.st_uid)
2284 user = util.username(st.st_uid)
2285 locker = vfs.readlock(name)
2285 locker = vfs.readlock(name)
2286 if b":" in locker:
2286 if b":" in locker:
2287 host, pid = locker.split(b':')
2287 host, pid = locker.split(b':')
2288 if host == socket.gethostname():
2288 if host == socket.gethostname():
2289 locker = b'user %s, process %s' % (user or b'None', pid)
2289 locker = b'user %s, process %s' % (user or b'None', pid)
2290 else:
2290 else:
2291 locker = b'user %s, process %s, host %s' % (
2291 locker = b'user %s, process %s, host %s' % (
2292 user or b'None',
2292 user or b'None',
2293 pid,
2293 pid,
2294 host,
2294 host,
2295 )
2295 )
2296 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2296 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2297 return 1
2297 return 1
2298 except FileNotFoundError:
2298 except FileNotFoundError:
2299 pass
2299 pass
2300
2300
2301 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2301 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2302 return 0
2302 return 0
2303
2303
2304 held += report(repo.svfs, b"lock", repo.lock)
2304 held += report(repo.svfs, b"lock", repo.lock)
2305 held += report(repo.vfs, b"wlock", repo.wlock)
2305 held += report(repo.vfs, b"wlock", repo.wlock)
2306
2306
2307 return held
2307 return held
2308
2308
2309
2309
2310 @command(
2310 @command(
2311 b'debugmanifestfulltextcache',
2311 b'debugmanifestfulltextcache',
2312 [
2312 [
2313 (b'', b'clear', False, _(b'clear the cache')),
2313 (b'', b'clear', False, _(b'clear the cache')),
2314 (
2314 (
2315 b'a',
2315 b'a',
2316 b'add',
2316 b'add',
2317 [],
2317 [],
2318 _(b'add the given manifest nodes to the cache'),
2318 _(b'add the given manifest nodes to the cache'),
2319 _(b'NODE'),
2319 _(b'NODE'),
2320 ),
2320 ),
2321 ],
2321 ],
2322 b'',
2322 b'',
2323 )
2323 )
2324 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2324 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2325 """show, clear or amend the contents of the manifest fulltext cache"""
2325 """show, clear or amend the contents of the manifest fulltext cache"""
2326
2326
2327 def getcache():
2327 def getcache():
2328 r = repo.manifestlog.getstorage(b'')
2328 r = repo.manifestlog.getstorage(b'')
2329 try:
2329 try:
2330 return r._fulltextcache
2330 return r._fulltextcache
2331 except AttributeError:
2331 except AttributeError:
2332 msg = _(
2332 msg = _(
2333 b"Current revlog implementation doesn't appear to have a "
2333 b"Current revlog implementation doesn't appear to have a "
2334 b"manifest fulltext cache\n"
2334 b"manifest fulltext cache\n"
2335 )
2335 )
2336 raise error.Abort(msg)
2336 raise error.Abort(msg)
2337
2337
2338 if opts.get('clear'):
2338 if opts.get('clear'):
2339 with repo.wlock():
2339 with repo.wlock():
2340 cache = getcache()
2340 cache = getcache()
2341 cache.clear(clear_persisted_data=True)
2341 cache.clear(clear_persisted_data=True)
2342 return
2342 return
2343
2343
2344 if add:
2344 if add:
2345 with repo.wlock():
2345 with repo.wlock():
2346 m = repo.manifestlog
2346 m = repo.manifestlog
2347 store = m.getstorage(b'')
2347 store = m.getstorage(b'')
2348 for n in add:
2348 for n in add:
2349 try:
2349 try:
2350 manifest = m[store.lookup(n)]
2350 manifest = m[store.lookup(n)]
2351 except error.LookupError as e:
2351 except error.LookupError as e:
2352 raise error.Abort(
2352 raise error.Abort(
2353 bytes(e), hint=b"Check your manifest node id"
2353 bytes(e), hint=b"Check your manifest node id"
2354 )
2354 )
2355 manifest.read() # stores revisision in cache too
2355 manifest.read() # stores revisision in cache too
2356 return
2356 return
2357
2357
2358 cache = getcache()
2358 cache = getcache()
2359 if not len(cache):
2359 if not len(cache):
2360 ui.write(_(b'cache empty\n'))
2360 ui.write(_(b'cache empty\n'))
2361 else:
2361 else:
2362 ui.write(
2362 ui.write(
2363 _(
2363 _(
2364 b'cache contains %d manifest entries, in order of most to '
2364 b'cache contains %d manifest entries, in order of most to '
2365 b'least recent:\n'
2365 b'least recent:\n'
2366 )
2366 )
2367 % (len(cache),)
2367 % (len(cache),)
2368 )
2368 )
2369 totalsize = 0
2369 totalsize = 0
2370 for nodeid in cache:
2370 for nodeid in cache:
2371 # Use cache.get to not update the LRU order
2371 # Use cache.get to not update the LRU order
2372 data = cache.peek(nodeid)
2372 data = cache.peek(nodeid)
2373 size = len(data)
2373 size = len(data)
2374 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2374 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2375 ui.write(
2375 ui.write(
2376 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2376 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2377 )
2377 )
2378 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2378 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2379 ui.write(
2379 ui.write(
2380 _(b'total cache data size %s, on-disk %s\n')
2380 _(b'total cache data size %s, on-disk %s\n')
2381 % (util.bytecount(totalsize), util.bytecount(ondisk))
2381 % (util.bytecount(totalsize), util.bytecount(ondisk))
2382 )
2382 )
2383
2383
2384
2384
2385 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2385 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2386 def debugmergestate(ui, repo, *args, **opts):
2386 def debugmergestate(ui, repo, *args, **opts):
2387 """print merge state
2387 """print merge state
2388
2388
2389 Use --verbose to print out information about whether v1 or v2 merge state
2389 Use --verbose to print out information about whether v1 or v2 merge state
2390 was chosen."""
2390 was chosen."""
2391
2391
2392 if ui.verbose:
2392 if ui.verbose:
2393 ms = mergestatemod.mergestate(repo)
2393 ms = mergestatemod.mergestate(repo)
2394
2394
2395 # sort so that reasonable information is on top
2395 # sort so that reasonable information is on top
2396 v1records = ms._readrecordsv1()
2396 v1records = ms._readrecordsv1()
2397 v2records = ms._readrecordsv2()
2397 v2records = ms._readrecordsv2()
2398
2398
2399 if not v1records and not v2records:
2399 if not v1records and not v2records:
2400 pass
2400 pass
2401 elif not v2records:
2401 elif not v2records:
2402 ui.writenoi18n(b'no version 2 merge state\n')
2402 ui.writenoi18n(b'no version 2 merge state\n')
2403 elif ms._v1v2match(v1records, v2records):
2403 elif ms._v1v2match(v1records, v2records):
2404 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2404 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2405 else:
2405 else:
2406 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2406 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2407
2407
2408 if not opts['template']:
2408 if not opts['template']:
2409 opts['template'] = (
2409 opts['template'] = (
2410 b'{if(commits, "", "no merge state found\n")}'
2410 b'{if(commits, "", "no merge state found\n")}'
2411 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2411 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2412 b'{files % "file: {path} (state \\"{state}\\")\n'
2412 b'{files % "file: {path} (state \\"{state}\\")\n'
2413 b'{if(local_path, "'
2413 b'{if(local_path, "'
2414 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2414 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2415 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2415 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2416 b' other path: {other_path} (node {other_node})\n'
2416 b' other path: {other_path} (node {other_node})\n'
2417 b'")}'
2417 b'")}'
2418 b'{if(rename_side, "'
2418 b'{if(rename_side, "'
2419 b' rename side: {rename_side}\n'
2419 b' rename side: {rename_side}\n'
2420 b' renamed path: {renamed_path}\n'
2420 b' renamed path: {renamed_path}\n'
2421 b'")}'
2421 b'")}'
2422 b'{extras % " extra: {key} = {value}\n"}'
2422 b'{extras % " extra: {key} = {value}\n"}'
2423 b'"}'
2423 b'"}'
2424 b'{extras % "extra: {file} ({key} = {value})\n"}'
2424 b'{extras % "extra: {file} ({key} = {value})\n"}'
2425 )
2425 )
2426
2426
2427 ms = mergestatemod.mergestate.read(repo)
2427 ms = mergestatemod.mergestate.read(repo)
2428
2428
2429 fm = ui.formatter(b'debugmergestate', pycompat.byteskwargs(opts))
2429 fm = ui.formatter(b'debugmergestate', pycompat.byteskwargs(opts))
2430 fm.startitem()
2430 fm.startitem()
2431
2431
2432 fm_commits = fm.nested(b'commits')
2432 fm_commits = fm.nested(b'commits')
2433 if ms.active():
2433 if ms.active():
2434 for name, node, label_index in (
2434 for name, node, label_index in (
2435 (b'local', ms.local, 0),
2435 (b'local', ms.local, 0),
2436 (b'other', ms.other, 1),
2436 (b'other', ms.other, 1),
2437 ):
2437 ):
2438 fm_commits.startitem()
2438 fm_commits.startitem()
2439 fm_commits.data(name=name)
2439 fm_commits.data(name=name)
2440 fm_commits.data(node=hex(node))
2440 fm_commits.data(node=hex(node))
2441 if ms._labels and len(ms._labels) > label_index:
2441 if ms._labels and len(ms._labels) > label_index:
2442 fm_commits.data(label=ms._labels[label_index])
2442 fm_commits.data(label=ms._labels[label_index])
2443 fm_commits.end()
2443 fm_commits.end()
2444
2444
2445 fm_files = fm.nested(b'files')
2445 fm_files = fm.nested(b'files')
2446 if ms.active():
2446 if ms.active():
2447 for f in ms:
2447 for f in ms:
2448 fm_files.startitem()
2448 fm_files.startitem()
2449 fm_files.data(path=f)
2449 fm_files.data(path=f)
2450 state = ms._state[f]
2450 state = ms._state[f]
2451 fm_files.data(state=state[0])
2451 fm_files.data(state=state[0])
2452 if state[0] in (
2452 if state[0] in (
2453 mergestatemod.MERGE_RECORD_UNRESOLVED,
2453 mergestatemod.MERGE_RECORD_UNRESOLVED,
2454 mergestatemod.MERGE_RECORD_RESOLVED,
2454 mergestatemod.MERGE_RECORD_RESOLVED,
2455 ):
2455 ):
2456 fm_files.data(local_key=state[1])
2456 fm_files.data(local_key=state[1])
2457 fm_files.data(local_path=state[2])
2457 fm_files.data(local_path=state[2])
2458 fm_files.data(ancestor_path=state[3])
2458 fm_files.data(ancestor_path=state[3])
2459 fm_files.data(ancestor_node=state[4])
2459 fm_files.data(ancestor_node=state[4])
2460 fm_files.data(other_path=state[5])
2460 fm_files.data(other_path=state[5])
2461 fm_files.data(other_node=state[6])
2461 fm_files.data(other_node=state[6])
2462 fm_files.data(local_flags=state[7])
2462 fm_files.data(local_flags=state[7])
2463 elif state[0] in (
2463 elif state[0] in (
2464 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2464 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2465 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2465 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2466 ):
2466 ):
2467 fm_files.data(renamed_path=state[1])
2467 fm_files.data(renamed_path=state[1])
2468 fm_files.data(rename_side=state[2])
2468 fm_files.data(rename_side=state[2])
2469 fm_extras = fm_files.nested(b'extras')
2469 fm_extras = fm_files.nested(b'extras')
2470 for k, v in sorted(ms.extras(f).items()):
2470 for k, v in sorted(ms.extras(f).items()):
2471 fm_extras.startitem()
2471 fm_extras.startitem()
2472 fm_extras.data(key=k)
2472 fm_extras.data(key=k)
2473 fm_extras.data(value=v)
2473 fm_extras.data(value=v)
2474 fm_extras.end()
2474 fm_extras.end()
2475
2475
2476 fm_files.end()
2476 fm_files.end()
2477
2477
2478 fm_extras = fm.nested(b'extras')
2478 fm_extras = fm.nested(b'extras')
2479 for f, d in sorted(ms.allextras().items()):
2479 for f, d in sorted(ms.allextras().items()):
2480 if f in ms:
2480 if f in ms:
2481 # If file is in mergestate, we have already processed it's extras
2481 # If file is in mergestate, we have already processed it's extras
2482 continue
2482 continue
2483 for k, v in d.items():
2483 for k, v in d.items():
2484 fm_extras.startitem()
2484 fm_extras.startitem()
2485 fm_extras.data(file=f)
2485 fm_extras.data(file=f)
2486 fm_extras.data(key=k)
2486 fm_extras.data(key=k)
2487 fm_extras.data(value=v)
2487 fm_extras.data(value=v)
2488 fm_extras.end()
2488 fm_extras.end()
2489
2489
2490 fm.end()
2490 fm.end()
2491
2491
2492
2492
2493 @command(b'debugnamecomplete', [], _(b'NAME...'))
2493 @command(b'debugnamecomplete', [], _(b'NAME...'))
2494 def debugnamecomplete(ui, repo, *args):
2494 def debugnamecomplete(ui, repo, *args):
2495 '''complete "names" - tags, open branch names, bookmark names'''
2495 '''complete "names" - tags, open branch names, bookmark names'''
2496
2496
2497 names = set()
2497 names = set()
2498 # since we previously only listed open branches, we will handle that
2498 # since we previously only listed open branches, we will handle that
2499 # specially (after this for loop)
2499 # specially (after this for loop)
2500 for name, ns in repo.names.items():
2500 for name, ns in repo.names.items():
2501 if name != b'branches':
2501 if name != b'branches':
2502 names.update(ns.listnames(repo))
2502 names.update(ns.listnames(repo))
2503 names.update(
2503 names.update(
2504 tag
2504 tag
2505 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2505 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2506 if not closed
2506 if not closed
2507 )
2507 )
2508 completions = set()
2508 completions = set()
2509 if not args:
2509 if not args:
2510 args = [b'']
2510 args = [b'']
2511 for a in args:
2511 for a in args:
2512 completions.update(n for n in names if n.startswith(a))
2512 completions.update(n for n in names if n.startswith(a))
2513 ui.write(b'\n'.join(sorted(completions)))
2513 ui.write(b'\n'.join(sorted(completions)))
2514 ui.write(b'\n')
2514 ui.write(b'\n')
2515
2515
2516
2516
2517 @command(
2517 @command(
2518 b'debugnodemap',
2518 b'debugnodemap',
2519 (
2519 (
2520 cmdutil.debugrevlogopts
2520 cmdutil.debugrevlogopts
2521 + [
2521 + [
2522 (
2522 (
2523 b'',
2523 b'',
2524 b'dump-new',
2524 b'dump-new',
2525 False,
2525 False,
2526 _(b'write a (new) persistent binary nodemap on stdout'),
2526 _(b'write a (new) persistent binary nodemap on stdout'),
2527 ),
2527 ),
2528 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2528 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2529 (
2529 (
2530 b'',
2530 b'',
2531 b'check',
2531 b'check',
2532 False,
2532 False,
2533 _(b'check that the data on disk data are correct.'),
2533 _(b'check that the data on disk data are correct.'),
2534 ),
2534 ),
2535 (
2535 (
2536 b'',
2536 b'',
2537 b'metadata',
2537 b'metadata',
2538 False,
2538 False,
2539 _(b'display the on disk meta data for the nodemap'),
2539 _(b'display the on disk meta data for the nodemap'),
2540 ),
2540 ),
2541 ]
2541 ]
2542 ),
2542 ),
2543 _(b'-c|-m|FILE'),
2543 _(b'-c|-m|FILE'),
2544 )
2544 )
2545 def debugnodemap(ui, repo, file_=None, **opts):
2545 def debugnodemap(ui, repo, file_=None, **opts):
2546 """write and inspect on disk nodemap"""
2546 """write and inspect on disk nodemap"""
2547 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2547 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2548 if file_ is not None:
2548 if file_ is not None:
2549 raise error.InputError(
2549 raise error.InputError(
2550 _(b'cannot specify a file with other arguments')
2550 _(b'cannot specify a file with other arguments')
2551 )
2551 )
2552 elif file_ is None:
2552 elif file_ is None:
2553 opts['changelog'] = True
2553 opts['changelog'] = True
2554 r = cmdutil.openstorage(
2554 r = cmdutil.openstorage(
2555 repo.unfiltered(), b'debugnodemap', file_, pycompat.byteskwargs(opts)
2555 repo.unfiltered(), b'debugnodemap', file_, pycompat.byteskwargs(opts)
2556 )
2556 )
2557 if isinstance(r, (manifest.manifestrevlog, filelog.filelog)):
2557 if isinstance(r, (manifest.manifestrevlog, filelog.filelog)):
2558 r = r._revlog
2558 r = r._revlog
2559 if opts['dump_new']:
2559 if opts['dump_new']:
2560 if hasattr(r.index, "nodemap_data_all"):
2560 if hasattr(r.index, "nodemap_data_all"):
2561 data = r.index.nodemap_data_all()
2561 data = r.index.nodemap_data_all()
2562 else:
2562 else:
2563 data = nodemap.persistent_data(r.index)
2563 data = nodemap.persistent_data(r.index)
2564 ui.write(data)
2564 ui.write(data)
2565 elif opts['dump_disk']:
2565 elif opts['dump_disk']:
2566 nm_data = nodemap.persisted_data(r)
2566 nm_data = nodemap.persisted_data(r)
2567 if nm_data is not None:
2567 if nm_data is not None:
2568 docket, data = nm_data
2568 docket, data = nm_data
2569 ui.write(data[:])
2569 ui.write(data[:])
2570 elif opts['check']:
2570 elif opts['check']:
2571 nm_data = nodemap.persisted_data(r)
2571 nm_data = nodemap.persisted_data(r)
2572 if nm_data is not None:
2572 if nm_data is not None:
2573 docket, data = nm_data
2573 docket, data = nm_data
2574 return nodemap.check_data(ui, r.index, data)
2574 return nodemap.check_data(ui, r.index, data)
2575 elif opts['metadata']:
2575 elif opts['metadata']:
2576 nm_data = nodemap.persisted_data(r)
2576 nm_data = nodemap.persisted_data(r)
2577 if nm_data is not None:
2577 if nm_data is not None:
2578 docket, data = nm_data
2578 docket, data = nm_data
2579 ui.write((b"uid: %s\n") % docket.uid)
2579 ui.write((b"uid: %s\n") % docket.uid)
2580 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2580 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2581 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2581 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2582 ui.write((b"data-length: %d\n") % docket.data_length)
2582 ui.write((b"data-length: %d\n") % docket.data_length)
2583 ui.write((b"data-unused: %d\n") % docket.data_unused)
2583 ui.write((b"data-unused: %d\n") % docket.data_unused)
2584 unused_perc = docket.data_unused * 100.0 / docket.data_length
2584 unused_perc = docket.data_unused * 100.0 / docket.data_length
2585 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2585 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2586
2586
2587
2587
2588 @command(
2588 @command(
2589 b'debugobsolete',
2589 b'debugobsolete',
2590 [
2590 [
2591 (b'', b'flags', 0, _(b'markers flag')),
2591 (b'', b'flags', 0, _(b'markers flag')),
2592 (
2592 (
2593 b'',
2593 b'',
2594 b'record-parents',
2594 b'record-parents',
2595 False,
2595 False,
2596 _(b'record parent information for the precursor'),
2596 _(b'record parent information for the precursor'),
2597 ),
2597 ),
2598 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2598 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2599 (
2599 (
2600 b'',
2600 b'',
2601 b'exclusive',
2601 b'exclusive',
2602 False,
2602 False,
2603 _(b'restrict display to markers only relevant to REV'),
2603 _(b'restrict display to markers only relevant to REV'),
2604 ),
2604 ),
2605 (b'', b'index', False, _(b'display index of the marker')),
2605 (b'', b'index', False, _(b'display index of the marker')),
2606 (b'', b'delete', [], _(b'delete markers specified by indices')),
2606 (b'', b'delete', [], _(b'delete markers specified by indices')),
2607 ]
2607 ]
2608 + cmdutil.commitopts2
2608 + cmdutil.commitopts2
2609 + cmdutil.formatteropts,
2609 + cmdutil.formatteropts,
2610 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2610 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2611 )
2611 )
2612 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2612 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2613 """create arbitrary obsolete marker
2613 """create arbitrary obsolete marker
2614
2614
2615 With no arguments, displays the list of obsolescence markers."""
2615 With no arguments, displays the list of obsolescence markers."""
2616
2616
2617 def parsenodeid(s):
2617 def parsenodeid(s):
2618 try:
2618 try:
2619 # We do not use revsingle/revrange functions here to accept
2619 # We do not use revsingle/revrange functions here to accept
2620 # arbitrary node identifiers, possibly not present in the
2620 # arbitrary node identifiers, possibly not present in the
2621 # local repository.
2621 # local repository.
2622 n = bin(s)
2622 n = bin(s)
2623 if len(n) != repo.nodeconstants.nodelen:
2623 if len(n) != repo.nodeconstants.nodelen:
2624 raise ValueError
2624 raise ValueError
2625 return n
2625 return n
2626 except ValueError:
2626 except ValueError:
2627 raise error.InputError(
2627 raise error.InputError(
2628 b'changeset references must be full hexadecimal '
2628 b'changeset references must be full hexadecimal '
2629 b'node identifiers'
2629 b'node identifiers'
2630 )
2630 )
2631
2631
2632 if opts.get('delete'):
2632 if opts.get('delete'):
2633 indices = []
2633 indices = []
2634 for v in opts.get('delete'):
2634 for v in opts.get('delete'):
2635 try:
2635 try:
2636 indices.append(int(v))
2636 indices.append(int(v))
2637 except ValueError:
2637 except ValueError:
2638 raise error.InputError(
2638 raise error.InputError(
2639 _(b'invalid index value: %r') % v,
2639 _(b'invalid index value: %r') % v,
2640 hint=_(b'use integers for indices'),
2640 hint=_(b'use integers for indices'),
2641 )
2641 )
2642
2642
2643 if repo.currenttransaction():
2643 if repo.currenttransaction():
2644 raise error.Abort(
2644 raise error.Abort(
2645 _(b'cannot delete obsmarkers in the middle of transaction.')
2645 _(b'cannot delete obsmarkers in the middle of transaction.')
2646 )
2646 )
2647
2647
2648 with repo.lock():
2648 with repo.lock():
2649 n = repair.deleteobsmarkers(repo.obsstore, indices)
2649 n = repair.deleteobsmarkers(repo.obsstore, indices)
2650 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2650 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2651
2651
2652 return
2652 return
2653
2653
2654 if precursor is not None:
2654 if precursor is not None:
2655 if opts['rev']:
2655 if opts['rev']:
2656 raise error.InputError(
2656 raise error.InputError(
2657 b'cannot select revision when creating marker'
2657 b'cannot select revision when creating marker'
2658 )
2658 )
2659 metadata = {}
2659 metadata = {}
2660 metadata[b'user'] = encoding.fromlocal(opts['user'] or ui.username())
2660 metadata[b'user'] = encoding.fromlocal(opts['user'] or ui.username())
2661 succs = tuple(parsenodeid(succ) for succ in successors)
2661 succs = tuple(parsenodeid(succ) for succ in successors)
2662 l = repo.lock()
2662 l = repo.lock()
2663 try:
2663 try:
2664 tr = repo.transaction(b'debugobsolete')
2664 tr = repo.transaction(b'debugobsolete')
2665 try:
2665 try:
2666 date = opts.get('date')
2666 date = opts.get('date')
2667 if date:
2667 if date:
2668 date = dateutil.parsedate(date)
2668 date = dateutil.parsedate(date)
2669 else:
2669 else:
2670 date = None
2670 date = None
2671 prec = parsenodeid(precursor)
2671 prec = parsenodeid(precursor)
2672 parents = None
2672 parents = None
2673 if opts['record_parents']:
2673 if opts['record_parents']:
2674 if prec not in repo.unfiltered():
2674 if prec not in repo.unfiltered():
2675 raise error.Abort(
2675 raise error.Abort(
2676 b'cannot used --record-parents on '
2676 b'cannot used --record-parents on '
2677 b'unknown changesets'
2677 b'unknown changesets'
2678 )
2678 )
2679 parents = repo.unfiltered()[prec].parents()
2679 parents = repo.unfiltered()[prec].parents()
2680 parents = tuple(p.node() for p in parents)
2680 parents = tuple(p.node() for p in parents)
2681 repo.obsstore.create(
2681 repo.obsstore.create(
2682 tr,
2682 tr,
2683 prec,
2683 prec,
2684 succs,
2684 succs,
2685 opts['flags'],
2685 opts['flags'],
2686 parents=parents,
2686 parents=parents,
2687 date=date,
2687 date=date,
2688 metadata=metadata,
2688 metadata=metadata,
2689 ui=ui,
2689 ui=ui,
2690 )
2690 )
2691 tr.close()
2691 tr.close()
2692 except ValueError as exc:
2692 except ValueError as exc:
2693 raise error.Abort(
2693 raise error.Abort(
2694 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2694 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2695 )
2695 )
2696 finally:
2696 finally:
2697 tr.release()
2697 tr.release()
2698 finally:
2698 finally:
2699 l.release()
2699 l.release()
2700 else:
2700 else:
2701 if opts['rev']:
2701 if opts['rev']:
2702 revs = logcmdutil.revrange(repo, opts['rev'])
2702 revs = logcmdutil.revrange(repo, opts['rev'])
2703 nodes = [repo[r].node() for r in revs]
2703 nodes = [repo[r].node() for r in revs]
2704 markers = list(
2704 markers = list(
2705 obsutil.getmarkers(
2705 obsutil.getmarkers(
2706 repo, nodes=nodes, exclusive=opts['exclusive']
2706 repo, nodes=nodes, exclusive=opts['exclusive']
2707 )
2707 )
2708 )
2708 )
2709 markers.sort(key=lambda x: x._data)
2709 markers.sort(key=lambda x: x._data)
2710 else:
2710 else:
2711 markers = obsutil.getmarkers(repo)
2711 markers = obsutil.getmarkers(repo)
2712
2712
2713 markerstoiter = markers
2713 markerstoiter = markers
2714 isrelevant = lambda m: True
2714 isrelevant = lambda m: True
2715 if opts.get('rev') and opts.get('index'):
2715 if opts.get('rev') and opts.get('index'):
2716 markerstoiter = obsutil.getmarkers(repo)
2716 markerstoiter = obsutil.getmarkers(repo)
2717 markerset = set(markers)
2717 markerset = set(markers)
2718 isrelevant = lambda m: m in markerset
2718 isrelevant = lambda m: m in markerset
2719
2719
2720 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
2720 fm = ui.formatter(b'debugobsolete', pycompat.byteskwargs(opts))
2721 for i, m in enumerate(markerstoiter):
2721 for i, m in enumerate(markerstoiter):
2722 if not isrelevant(m):
2722 if not isrelevant(m):
2723 # marker can be irrelevant when we're iterating over a set
2723 # marker can be irrelevant when we're iterating over a set
2724 # of markers (markerstoiter) which is bigger than the set
2724 # of markers (markerstoiter) which is bigger than the set
2725 # of markers we want to display (markers)
2725 # of markers we want to display (markers)
2726 # this can happen if both --index and --rev options are
2726 # this can happen if both --index and --rev options are
2727 # provided and thus we need to iterate over all of the markers
2727 # provided and thus we need to iterate over all of the markers
2728 # to get the correct indices, but only display the ones that
2728 # to get the correct indices, but only display the ones that
2729 # are relevant to --rev value
2729 # are relevant to --rev value
2730 continue
2730 continue
2731 fm.startitem()
2731 fm.startitem()
2732 ind = i if opts.get('index') else None
2732 ind = i if opts.get('index') else None
2733 cmdutil.showmarker(fm, m, index=ind)
2733 cmdutil.showmarker(fm, m, index=ind)
2734 fm.end()
2734 fm.end()
2735
2735
2736
2736
2737 @command(
2737 @command(
2738 b'debugp1copies',
2738 b'debugp1copies',
2739 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2739 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2740 _(b'[-r REV]'),
2740 _(b'[-r REV]'),
2741 )
2741 )
2742 def debugp1copies(ui, repo, **opts):
2742 def debugp1copies(ui, repo, **opts):
2743 """dump copy information compared to p1"""
2743 """dump copy information compared to p1"""
2744
2744
2745 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2745 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2746 for dst, src in ctx.p1copies().items():
2746 for dst, src in ctx.p1copies().items():
2747 ui.write(b'%s -> %s\n' % (src, dst))
2747 ui.write(b'%s -> %s\n' % (src, dst))
2748
2748
2749
2749
2750 @command(
2750 @command(
2751 b'debugp2copies',
2751 b'debugp2copies',
2752 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2752 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2753 _(b'[-r REV]'),
2753 _(b'[-r REV]'),
2754 )
2754 )
2755 def debugp2copies(ui, repo, **opts):
2755 def debugp2copies(ui, repo, **opts):
2756 """dump copy information compared to p2"""
2756 """dump copy information compared to p2"""
2757
2757
2758 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2758 ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
2759 for dst, src in ctx.p2copies().items():
2759 for dst, src in ctx.p2copies().items():
2760 ui.write(b'%s -> %s\n' % (src, dst))
2760 ui.write(b'%s -> %s\n' % (src, dst))
2761
2761
2762
2762
2763 @command(
2763 @command(
2764 b'debugpathcomplete',
2764 b'debugpathcomplete',
2765 [
2765 [
2766 (b'f', b'full', None, _(b'complete an entire path')),
2766 (b'f', b'full', None, _(b'complete an entire path')),
2767 (b'n', b'normal', None, _(b'show only normal files')),
2767 (b'n', b'normal', None, _(b'show only normal files')),
2768 (b'a', b'added', None, _(b'show only added files')),
2768 (b'a', b'added', None, _(b'show only added files')),
2769 (b'r', b'removed', None, _(b'show only removed files')),
2769 (b'r', b'removed', None, _(b'show only removed files')),
2770 ],
2770 ],
2771 _(b'FILESPEC...'),
2771 _(b'FILESPEC...'),
2772 )
2772 )
2773 def debugpathcomplete(ui, repo, *specs, **opts):
2773 def debugpathcomplete(ui, repo, *specs, **opts):
2774 """complete part or all of a tracked path
2774 """complete part or all of a tracked path
2775
2775
2776 This command supports shells that offer path name completion. It
2776 This command supports shells that offer path name completion. It
2777 currently completes only files already known to the dirstate.
2777 currently completes only files already known to the dirstate.
2778
2778
2779 Completion extends only to the next path segment unless
2779 Completion extends only to the next path segment unless
2780 --full is specified, in which case entire paths are used."""
2780 --full is specified, in which case entire paths are used."""
2781
2781
2782 def complete(path, acceptable):
2782 def complete(path, acceptable):
2783 dirstate = repo.dirstate
2783 dirstate = repo.dirstate
2784 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2784 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2785 rootdir = repo.root + pycompat.ossep
2785 rootdir = repo.root + pycompat.ossep
2786 if spec != repo.root and not spec.startswith(rootdir):
2786 if spec != repo.root and not spec.startswith(rootdir):
2787 return [], []
2787 return [], []
2788 if os.path.isdir(spec):
2788 if os.path.isdir(spec):
2789 spec += b'/'
2789 spec += b'/'
2790 spec = spec[len(rootdir) :]
2790 spec = spec[len(rootdir) :]
2791 fixpaths = pycompat.ossep != b'/'
2791 fixpaths = pycompat.ossep != b'/'
2792 if fixpaths:
2792 if fixpaths:
2793 spec = spec.replace(pycompat.ossep, b'/')
2793 spec = spec.replace(pycompat.ossep, b'/')
2794 speclen = len(spec)
2794 speclen = len(spec)
2795 fullpaths = opts['full']
2795 fullpaths = opts['full']
2796 files, dirs = set(), set()
2796 files, dirs = set(), set()
2797 adddir, addfile = dirs.add, files.add
2797 adddir, addfile = dirs.add, files.add
2798 for f, st in dirstate.items():
2798 for f, st in dirstate.items():
2799 if f.startswith(spec) and st.state in acceptable:
2799 if f.startswith(spec) and st.state in acceptable:
2800 if fixpaths:
2800 if fixpaths:
2801 f = f.replace(b'/', pycompat.ossep)
2801 f = f.replace(b'/', pycompat.ossep)
2802 if fullpaths:
2802 if fullpaths:
2803 addfile(f)
2803 addfile(f)
2804 continue
2804 continue
2805 s = f.find(pycompat.ossep, speclen)
2805 s = f.find(pycompat.ossep, speclen)
2806 if s >= 0:
2806 if s >= 0:
2807 adddir(f[:s])
2807 adddir(f[:s])
2808 else:
2808 else:
2809 addfile(f)
2809 addfile(f)
2810 return files, dirs
2810 return files, dirs
2811
2811
2812 acceptable = b''
2812 acceptable = b''
2813 if opts['normal']:
2813 if opts['normal']:
2814 acceptable += b'nm'
2814 acceptable += b'nm'
2815 if opts['added']:
2815 if opts['added']:
2816 acceptable += b'a'
2816 acceptable += b'a'
2817 if opts['removed']:
2817 if opts['removed']:
2818 acceptable += b'r'
2818 acceptable += b'r'
2819 cwd = repo.getcwd()
2819 cwd = repo.getcwd()
2820 if not specs:
2820 if not specs:
2821 specs = [b'.']
2821 specs = [b'.']
2822
2822
2823 files, dirs = set(), set()
2823 files, dirs = set(), set()
2824 for spec in specs:
2824 for spec in specs:
2825 f, d = complete(spec, acceptable or b'nmar')
2825 f, d = complete(spec, acceptable or b'nmar')
2826 files.update(f)
2826 files.update(f)
2827 dirs.update(d)
2827 dirs.update(d)
2828 files.update(dirs)
2828 files.update(dirs)
2829 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2829 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2830 ui.write(b'\n')
2830 ui.write(b'\n')
2831
2831
2832
2832
2833 @command(
2833 @command(
2834 b'debugpathcopies',
2834 b'debugpathcopies',
2835 cmdutil.walkopts,
2835 cmdutil.walkopts,
2836 b'hg debugpathcopies REV1 REV2 [FILE]',
2836 b'hg debugpathcopies REV1 REV2 [FILE]',
2837 inferrepo=True,
2837 inferrepo=True,
2838 )
2838 )
2839 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2839 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2840 """show copies between two revisions"""
2840 """show copies between two revisions"""
2841 ctx1 = scmutil.revsingle(repo, rev1)
2841 ctx1 = scmutil.revsingle(repo, rev1)
2842 ctx2 = scmutil.revsingle(repo, rev2)
2842 ctx2 = scmutil.revsingle(repo, rev2)
2843 m = scmutil.match(ctx1, pats, opts)
2843 m = scmutil.match(ctx1, pats, opts)
2844 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2844 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2845 ui.write(b'%s -> %s\n' % (src, dst))
2845 ui.write(b'%s -> %s\n' % (src, dst))
2846
2846
2847
2847
2848 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2848 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2849 def debugpeer(ui, path):
2849 def debugpeer(ui, path):
2850 """establish a connection to a peer repository"""
2850 """establish a connection to a peer repository"""
2851 # Always enable peer request logging. Requires --debug to display
2851 # Always enable peer request logging. Requires --debug to display
2852 # though.
2852 # though.
2853 overrides = {
2853 overrides = {
2854 (b'devel', b'debug.peer-request'): True,
2854 (b'devel', b'debug.peer-request'): True,
2855 }
2855 }
2856
2856
2857 with ui.configoverride(overrides):
2857 with ui.configoverride(overrides):
2858 peer = hg.peer(ui, {}, path)
2858 peer = hg.peer(ui, {}, path)
2859
2859
2860 try:
2860 try:
2861 local = peer.local() is not None
2861 local = peer.local() is not None
2862 canpush = peer.canpush()
2862 canpush = peer.canpush()
2863
2863
2864 ui.write(_(b'url: %s\n') % peer.url())
2864 ui.write(_(b'url: %s\n') % peer.url())
2865 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2865 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2866 ui.write(
2866 ui.write(
2867 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2867 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2868 )
2868 )
2869 finally:
2869 finally:
2870 peer.close()
2870 peer.close()
2871
2871
2872
2872
2873 @command(
2873 @command(
2874 b'debugpickmergetool',
2874 b'debugpickmergetool',
2875 [
2875 [
2876 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2876 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2877 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2877 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2878 ]
2878 ]
2879 + cmdutil.walkopts
2879 + cmdutil.walkopts
2880 + cmdutil.mergetoolopts,
2880 + cmdutil.mergetoolopts,
2881 _(b'[PATTERN]...'),
2881 _(b'[PATTERN]...'),
2882 inferrepo=True,
2882 inferrepo=True,
2883 )
2883 )
2884 def debugpickmergetool(ui, repo, *pats, **opts):
2884 def debugpickmergetool(ui, repo, *pats, **opts):
2885 """examine which merge tool is chosen for specified file
2885 """examine which merge tool is chosen for specified file
2886
2886
2887 As described in :hg:`help merge-tools`, Mercurial examines
2887 As described in :hg:`help merge-tools`, Mercurial examines
2888 configurations below in this order to decide which merge tool is
2888 configurations below in this order to decide which merge tool is
2889 chosen for specified file.
2889 chosen for specified file.
2890
2890
2891 1. ``--tool`` option
2891 1. ``--tool`` option
2892 2. ``HGMERGE`` environment variable
2892 2. ``HGMERGE`` environment variable
2893 3. configurations in ``merge-patterns`` section
2893 3. configurations in ``merge-patterns`` section
2894 4. configuration of ``ui.merge``
2894 4. configuration of ``ui.merge``
2895 5. configurations in ``merge-tools`` section
2895 5. configurations in ``merge-tools`` section
2896 6. ``hgmerge`` tool (for historical reason only)
2896 6. ``hgmerge`` tool (for historical reason only)
2897 7. default tool for fallback (``:merge`` or ``:prompt``)
2897 7. default tool for fallback (``:merge`` or ``:prompt``)
2898
2898
2899 This command writes out examination result in the style below::
2899 This command writes out examination result in the style below::
2900
2900
2901 FILE = MERGETOOL
2901 FILE = MERGETOOL
2902
2902
2903 By default, all files known in the first parent context of the
2903 By default, all files known in the first parent context of the
2904 working directory are examined. Use file patterns and/or -I/-X
2904 working directory are examined. Use file patterns and/or -I/-X
2905 options to limit target files. -r/--rev is also useful to examine
2905 options to limit target files. -r/--rev is also useful to examine
2906 files in another context without actual updating to it.
2906 files in another context without actual updating to it.
2907
2907
2908 With --debug, this command shows warning messages while matching
2908 With --debug, this command shows warning messages while matching
2909 against ``merge-patterns`` and so on, too. It is recommended to
2909 against ``merge-patterns`` and so on, too. It is recommended to
2910 use this option with explicit file patterns and/or -I/-X options,
2910 use this option with explicit file patterns and/or -I/-X options,
2911 because this option increases amount of output per file according
2911 because this option increases amount of output per file according
2912 to configurations in hgrc.
2912 to configurations in hgrc.
2913
2913
2914 With -v/--verbose, this command shows configurations below at
2914 With -v/--verbose, this command shows configurations below at
2915 first (only if specified).
2915 first (only if specified).
2916
2916
2917 - ``--tool`` option
2917 - ``--tool`` option
2918 - ``HGMERGE`` environment variable
2918 - ``HGMERGE`` environment variable
2919 - configuration of ``ui.merge``
2919 - configuration of ``ui.merge``
2920
2920
2921 If merge tool is chosen before matching against
2921 If merge tool is chosen before matching against
2922 ``merge-patterns``, this command can't show any helpful
2922 ``merge-patterns``, this command can't show any helpful
2923 information, even with --debug. In such case, information above is
2923 information, even with --debug. In such case, information above is
2924 useful to know why a merge tool is chosen.
2924 useful to know why a merge tool is chosen.
2925 """
2925 """
2926 overrides = {}
2926 overrides = {}
2927 if opts['tool']:
2927 if opts['tool']:
2928 overrides[(b'ui', b'forcemerge')] = opts['tool']
2928 overrides[(b'ui', b'forcemerge')] = opts['tool']
2929 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts['tool'])))
2929 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts['tool'])))
2930
2930
2931 with ui.configoverride(overrides, b'debugmergepatterns'):
2931 with ui.configoverride(overrides, b'debugmergepatterns'):
2932 hgmerge = encoding.environ.get(b"HGMERGE")
2932 hgmerge = encoding.environ.get(b"HGMERGE")
2933 if hgmerge is not None:
2933 if hgmerge is not None:
2934 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2934 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2935 uimerge = ui.config(b"ui", b"merge")
2935 uimerge = ui.config(b"ui", b"merge")
2936 if uimerge:
2936 if uimerge:
2937 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2937 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2938
2938
2939 ctx = scmutil.revsingle(repo, opts.get('rev'))
2939 ctx = scmutil.revsingle(repo, opts.get('rev'))
2940 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
2940 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
2941 changedelete = opts['changedelete']
2941 changedelete = opts['changedelete']
2942 for path in ctx.walk(m):
2942 for path in ctx.walk(m):
2943 fctx = ctx[path]
2943 fctx = ctx[path]
2944 with ui.silent(
2944 with ui.silent(
2945 error=True
2945 error=True
2946 ) if not ui.debugflag else util.nullcontextmanager():
2946 ) if not ui.debugflag else util.nullcontextmanager():
2947 tool, toolpath = filemerge._picktool(
2947 tool, toolpath = filemerge._picktool(
2948 repo,
2948 repo,
2949 ui,
2949 ui,
2950 path,
2950 path,
2951 fctx.isbinary(),
2951 fctx.isbinary(),
2952 b'l' in fctx.flags(),
2952 b'l' in fctx.flags(),
2953 changedelete,
2953 changedelete,
2954 )
2954 )
2955 ui.write(b'%s = %s\n' % (path, tool))
2955 ui.write(b'%s = %s\n' % (path, tool))
2956
2956
2957
2957
2958 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2958 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2959 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2959 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2960 """access the pushkey key/value protocol
2960 """access the pushkey key/value protocol
2961
2961
2962 With two args, list the keys in the given namespace.
2962 With two args, list the keys in the given namespace.
2963
2963
2964 With five args, set a key to new if it currently is set to old.
2964 With five args, set a key to new if it currently is set to old.
2965 Reports success or failure.
2965 Reports success or failure.
2966 """
2966 """
2967
2967
2968 target = hg.peer(ui, {}, repopath)
2968 target = hg.peer(ui, {}, repopath)
2969 try:
2969 try:
2970 if keyinfo:
2970 if keyinfo:
2971 key, old, new = keyinfo
2971 key, old, new = keyinfo
2972 with target.commandexecutor() as e:
2972 with target.commandexecutor() as e:
2973 r = e.callcommand(
2973 r = e.callcommand(
2974 b'pushkey',
2974 b'pushkey',
2975 {
2975 {
2976 b'namespace': namespace,
2976 b'namespace': namespace,
2977 b'key': key,
2977 b'key': key,
2978 b'old': old,
2978 b'old': old,
2979 b'new': new,
2979 b'new': new,
2980 },
2980 },
2981 ).result()
2981 ).result()
2982
2982
2983 ui.status(pycompat.bytestr(r) + b'\n')
2983 ui.status(pycompat.bytestr(r) + b'\n')
2984 return not r
2984 return not r
2985 else:
2985 else:
2986 for k, v in sorted(target.listkeys(namespace).items()):
2986 for k, v in sorted(target.listkeys(namespace).items()):
2987 ui.write(
2987 ui.write(
2988 b"%s\t%s\n"
2988 b"%s\t%s\n"
2989 % (stringutil.escapestr(k), stringutil.escapestr(v))
2989 % (stringutil.escapestr(k), stringutil.escapestr(v))
2990 )
2990 )
2991 finally:
2991 finally:
2992 target.close()
2992 target.close()
2993
2993
2994
2994
2995 @command(b'debugpvec', [], _(b'A B'))
2995 @command(b'debugpvec', [], _(b'A B'))
2996 def debugpvec(ui, repo, a, b=None):
2996 def debugpvec(ui, repo, a, b=None):
2997 ca = scmutil.revsingle(repo, a)
2997 ca = scmutil.revsingle(repo, a)
2998 cb = scmutil.revsingle(repo, b)
2998 cb = scmutil.revsingle(repo, b)
2999 pa = pvec.ctxpvec(ca)
2999 pa = pvec.ctxpvec(ca)
3000 pb = pvec.ctxpvec(cb)
3000 pb = pvec.ctxpvec(cb)
3001 if pa == pb:
3001 if pa == pb:
3002 rel = b"="
3002 rel = b"="
3003 elif pa > pb:
3003 elif pa > pb:
3004 rel = b">"
3004 rel = b">"
3005 elif pa < pb:
3005 elif pa < pb:
3006 rel = b"<"
3006 rel = b"<"
3007 elif pa | pb:
3007 elif pa | pb:
3008 rel = b"|"
3008 rel = b"|"
3009 ui.write(_(b"a: %s\n") % pa)
3009 ui.write(_(b"a: %s\n") % pa)
3010 ui.write(_(b"b: %s\n") % pb)
3010 ui.write(_(b"b: %s\n") % pb)
3011 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3011 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3012 ui.write(
3012 ui.write(
3013 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
3013 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
3014 % (
3014 % (
3015 abs(pa._depth - pb._depth),
3015 abs(pa._depth - pb._depth),
3016 pvec._hamming(pa._vec, pb._vec),
3016 pvec._hamming(pa._vec, pb._vec),
3017 pa.distance(pb),
3017 pa.distance(pb),
3018 rel,
3018 rel,
3019 )
3019 )
3020 )
3020 )
3021
3021
3022
3022
3023 @command(
3023 @command(
3024 b'debugrebuilddirstate|debugrebuildstate',
3024 b'debugrebuilddirstate|debugrebuildstate',
3025 [
3025 [
3026 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
3026 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
3027 (
3027 (
3028 b'',
3028 b'',
3029 b'minimal',
3029 b'minimal',
3030 None,
3030 None,
3031 _(
3031 _(
3032 b'only rebuild files that are inconsistent with '
3032 b'only rebuild files that are inconsistent with '
3033 b'the working copy parent'
3033 b'the working copy parent'
3034 ),
3034 ),
3035 ),
3035 ),
3036 ],
3036 ],
3037 _(b'[-r REV]'),
3037 _(b'[-r REV]'),
3038 )
3038 )
3039 def debugrebuilddirstate(ui, repo, rev, **opts):
3039 def debugrebuilddirstate(ui, repo, rev, **opts):
3040 """rebuild the dirstate as it would look like for the given revision
3040 """rebuild the dirstate as it would look like for the given revision
3041
3041
3042 If no revision is specified the first current parent will be used.
3042 If no revision is specified the first current parent will be used.
3043
3043
3044 The dirstate will be set to the files of the given revision.
3044 The dirstate will be set to the files of the given revision.
3045 The actual working directory content or existing dirstate
3045 The actual working directory content or existing dirstate
3046 information such as adds or removes is not considered.
3046 information such as adds or removes is not considered.
3047
3047
3048 ``minimal`` will only rebuild the dirstate status for files that claim to be
3048 ``minimal`` will only rebuild the dirstate status for files that claim to be
3049 tracked but are not in the parent manifest, or that exist in the parent
3049 tracked but are not in the parent manifest, or that exist in the parent
3050 manifest but are not in the dirstate. It will not change adds, removes, or
3050 manifest but are not in the dirstate. It will not change adds, removes, or
3051 modified files that are in the working copy parent.
3051 modified files that are in the working copy parent.
3052
3052
3053 One use of this command is to make the next :hg:`status` invocation
3053 One use of this command is to make the next :hg:`status` invocation
3054 check the actual file content.
3054 check the actual file content.
3055 """
3055 """
3056 ctx = scmutil.revsingle(repo, rev)
3056 ctx = scmutil.revsingle(repo, rev)
3057 with repo.wlock():
3057 with repo.wlock():
3058 if repo.currenttransaction() is not None:
3058 if repo.currenttransaction() is not None:
3059 msg = b'rebuild the dirstate outside of a transaction'
3059 msg = b'rebuild the dirstate outside of a transaction'
3060 raise error.ProgrammingError(msg)
3060 raise error.ProgrammingError(msg)
3061 dirstate = repo.dirstate
3061 dirstate = repo.dirstate
3062 changedfiles = None
3062 changedfiles = None
3063 # See command doc for what minimal does.
3063 # See command doc for what minimal does.
3064 if opts.get('minimal'):
3064 if opts.get('minimal'):
3065 manifestfiles = set(ctx.manifest().keys())
3065 manifestfiles = set(ctx.manifest().keys())
3066 dirstatefiles = set(dirstate)
3066 dirstatefiles = set(dirstate)
3067 manifestonly = manifestfiles - dirstatefiles
3067 manifestonly = manifestfiles - dirstatefiles
3068 dsonly = dirstatefiles - manifestfiles
3068 dsonly = dirstatefiles - manifestfiles
3069 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
3069 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
3070 changedfiles = manifestonly | dsnotadded
3070 changedfiles = manifestonly | dsnotadded
3071
3071
3072 with dirstate.changing_parents(repo):
3072 with dirstate.changing_parents(repo):
3073 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3073 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3074
3074
3075
3075
3076 @command(
3076 @command(
3077 b'debugrebuildfncache',
3077 b'debugrebuildfncache',
3078 [
3078 [
3079 (
3079 (
3080 b'',
3080 b'',
3081 b'only-data',
3081 b'only-data',
3082 False,
3082 False,
3083 _(b'only look for wrong .d files (much faster)'),
3083 _(b'only look for wrong .d files (much faster)'),
3084 )
3084 )
3085 ],
3085 ],
3086 b'',
3086 b'',
3087 )
3087 )
3088 def debugrebuildfncache(ui, repo, **opts):
3088 def debugrebuildfncache(ui, repo, **opts):
3089 """rebuild the fncache file"""
3089 """rebuild the fncache file"""
3090 repair.rebuildfncache(ui, repo, opts.get("only_data"))
3090 repair.rebuildfncache(ui, repo, opts.get("only_data"))
3091
3091
3092
3092
3093 @command(
3093 @command(
3094 b'debugrename',
3094 b'debugrename',
3095 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
3095 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
3096 _(b'[-r REV] [FILE]...'),
3096 _(b'[-r REV] [FILE]...'),
3097 )
3097 )
3098 def debugrename(ui, repo, *pats, **opts):
3098 def debugrename(ui, repo, *pats, **opts):
3099 """dump rename information"""
3099 """dump rename information"""
3100
3100
3101 ctx = scmutil.revsingle(repo, opts.get('rev'))
3101 ctx = scmutil.revsingle(repo, opts.get('rev'))
3102 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
3102 m = scmutil.match(ctx, pats, pycompat.byteskwargs(opts))
3103 for abs in ctx.walk(m):
3103 for abs in ctx.walk(m):
3104 fctx = ctx[abs]
3104 fctx = ctx[abs]
3105 o = fctx.filelog().renamed(fctx.filenode())
3105 o = fctx.filelog().renamed(fctx.filenode())
3106 rel = repo.pathto(abs)
3106 rel = repo.pathto(abs)
3107 if o:
3107 if o:
3108 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3108 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3109 else:
3109 else:
3110 ui.write(_(b"%s not renamed\n") % rel)
3110 ui.write(_(b"%s not renamed\n") % rel)
3111
3111
3112
3112
3113 @command(b'debugrequires|debugrequirements', [], b'')
3113 @command(b'debugrequires|debugrequirements', [], b'')
3114 def debugrequirements(ui, repo):
3114 def debugrequirements(ui, repo):
3115 """print the current repo requirements"""
3115 """print the current repo requirements"""
3116 for r in sorted(repo.requirements):
3116 for r in sorted(repo.requirements):
3117 ui.write(b"%s\n" % r)
3117 ui.write(b"%s\n" % r)
3118
3118
3119
3119
3120 @command(
3120 @command(
3121 b'debugrevlog',
3121 b'debugrevlog',
3122 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3122 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3123 _(b'-c|-m|FILE'),
3123 _(b'-c|-m|FILE'),
3124 optionalrepo=True,
3124 optionalrepo=True,
3125 )
3125 )
3126 def debugrevlog(ui, repo, file_=None, **opts):
3126 def debugrevlog(ui, repo, file_=None, **opts):
3127 """show data and statistics about a revlog"""
3127 """show data and statistics about a revlog"""
3128 r = cmdutil.openrevlog(
3128 r = cmdutil.openrevlog(
3129 repo, b'debugrevlog', file_, pycompat.byteskwargs(opts)
3129 repo, b'debugrevlog', file_, pycompat.byteskwargs(opts)
3130 )
3130 )
3131
3131
3132 if opts.get("dump"):
3132 if opts.get("dump"):
3133 revlog_debug.dump(ui, r)
3133 revlog_debug.dump(ui, r)
3134 else:
3134 else:
3135 revlog_debug.debug_revlog(ui, r)
3135 revlog_debug.debug_revlog(ui, r)
3136 return 0
3136 return 0
3137
3137
3138
3138
3139 @command(
3139 @command(
3140 b'debugrevlogindex',
3140 b'debugrevlogindex',
3141 cmdutil.debugrevlogopts
3141 cmdutil.debugrevlogopts
3142 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3142 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3143 _(b'[-f FORMAT] -c|-m|FILE'),
3143 _(b'[-f FORMAT] -c|-m|FILE'),
3144 optionalrepo=True,
3144 optionalrepo=True,
3145 )
3145 )
3146 def debugrevlogindex(ui, repo, file_=None, **opts):
3146 def debugrevlogindex(ui, repo, file_=None, **opts):
3147 """dump the contents of a revlog index"""
3147 """dump the contents of a revlog index"""
3148 r = cmdutil.openrevlog(
3148 r = cmdutil.openrevlog(
3149 repo, b'debugrevlogindex', file_, pycompat.byteskwargs(opts)
3149 repo, b'debugrevlogindex', file_, pycompat.byteskwargs(opts)
3150 )
3150 )
3151 format = opts.get('format', 0)
3151 format = opts.get('format', 0)
3152 if format not in (0, 1):
3152 if format not in (0, 1):
3153 raise error.Abort(_(b"unknown format %d") % format)
3153 raise error.Abort(_(b"unknown format %d") % format)
3154
3154
3155 if ui.debugflag:
3155 if ui.debugflag:
3156 shortfn = hex
3156 shortfn = hex
3157 else:
3157 else:
3158 shortfn = short
3158 shortfn = short
3159
3159
3160 # There might not be anything in r, so have a sane default
3160 # There might not be anything in r, so have a sane default
3161 idlen = 12
3161 idlen = 12
3162 for i in r:
3162 for i in r:
3163 idlen = len(shortfn(r.node(i)))
3163 idlen = len(shortfn(r.node(i)))
3164 break
3164 break
3165
3165
3166 if format == 0:
3166 if format == 0:
3167 if ui.verbose:
3167 if ui.verbose:
3168 ui.writenoi18n(
3168 ui.writenoi18n(
3169 b" rev offset length linkrev %s %s p2\n"
3169 b" rev offset length linkrev %s %s p2\n"
3170 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3170 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3171 )
3171 )
3172 else:
3172 else:
3173 ui.writenoi18n(
3173 ui.writenoi18n(
3174 b" rev linkrev %s %s p2\n"
3174 b" rev linkrev %s %s p2\n"
3175 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3175 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3176 )
3176 )
3177 elif format == 1:
3177 elif format == 1:
3178 if ui.verbose:
3178 if ui.verbose:
3179 ui.writenoi18n(
3179 ui.writenoi18n(
3180 (
3180 (
3181 b" rev flag offset length size link p1"
3181 b" rev flag offset length size link p1"
3182 b" p2 %s\n"
3182 b" p2 %s\n"
3183 )
3183 )
3184 % b"nodeid".rjust(idlen)
3184 % b"nodeid".rjust(idlen)
3185 )
3185 )
3186 else:
3186 else:
3187 ui.writenoi18n(
3187 ui.writenoi18n(
3188 b" rev flag size link p1 p2 %s\n"
3188 b" rev flag size link p1 p2 %s\n"
3189 % b"nodeid".rjust(idlen)
3189 % b"nodeid".rjust(idlen)
3190 )
3190 )
3191
3191
3192 for i in r:
3192 for i in r:
3193 node = r.node(i)
3193 node = r.node(i)
3194 if format == 0:
3194 if format == 0:
3195 try:
3195 try:
3196 pp = r.parents(node)
3196 pp = r.parents(node)
3197 except Exception:
3197 except Exception:
3198 pp = [repo.nullid, repo.nullid]
3198 pp = [repo.nullid, repo.nullid]
3199 if ui.verbose:
3199 if ui.verbose:
3200 ui.write(
3200 ui.write(
3201 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3201 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3202 % (
3202 % (
3203 i,
3203 i,
3204 r.start(i),
3204 r.start(i),
3205 r.length(i),
3205 r.length(i),
3206 r.linkrev(i),
3206 r.linkrev(i),
3207 shortfn(node),
3207 shortfn(node),
3208 shortfn(pp[0]),
3208 shortfn(pp[0]),
3209 shortfn(pp[1]),
3209 shortfn(pp[1]),
3210 )
3210 )
3211 )
3211 )
3212 else:
3212 else:
3213 ui.write(
3213 ui.write(
3214 b"% 6d % 7d %s %s %s\n"
3214 b"% 6d % 7d %s %s %s\n"
3215 % (
3215 % (
3216 i,
3216 i,
3217 r.linkrev(i),
3217 r.linkrev(i),
3218 shortfn(node),
3218 shortfn(node),
3219 shortfn(pp[0]),
3219 shortfn(pp[0]),
3220 shortfn(pp[1]),
3220 shortfn(pp[1]),
3221 )
3221 )
3222 )
3222 )
3223 elif format == 1:
3223 elif format == 1:
3224 pr = r.parentrevs(i)
3224 pr = r.parentrevs(i)
3225 if ui.verbose:
3225 if ui.verbose:
3226 ui.write(
3226 ui.write(
3227 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3227 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3228 % (
3228 % (
3229 i,
3229 i,
3230 r.flags(i),
3230 r.flags(i),
3231 r.start(i),
3231 r.start(i),
3232 r.length(i),
3232 r.length(i),
3233 r.rawsize(i),
3233 r.rawsize(i),
3234 r.linkrev(i),
3234 r.linkrev(i),
3235 pr[0],
3235 pr[0],
3236 pr[1],
3236 pr[1],
3237 shortfn(node),
3237 shortfn(node),
3238 )
3238 )
3239 )
3239 )
3240 else:
3240 else:
3241 ui.write(
3241 ui.write(
3242 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3242 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3243 % (
3243 % (
3244 i,
3244 i,
3245 r.flags(i),
3245 r.flags(i),
3246 r.rawsize(i),
3246 r.rawsize(i),
3247 r.linkrev(i),
3247 r.linkrev(i),
3248 pr[0],
3248 pr[0],
3249 pr[1],
3249 pr[1],
3250 shortfn(node),
3250 shortfn(node),
3251 )
3251 )
3252 )
3252 )
3253
3253
3254
3254
3255 @command(
3255 @command(
3256 b'debugrevspec',
3256 b'debugrevspec',
3257 [
3257 [
3258 (
3258 (
3259 b'',
3259 b'',
3260 b'optimize',
3260 b'optimize',
3261 None,
3261 None,
3262 _(b'print parsed tree after optimizing (DEPRECATED)'),
3262 _(b'print parsed tree after optimizing (DEPRECATED)'),
3263 ),
3263 ),
3264 (
3264 (
3265 b'',
3265 b'',
3266 b'show-revs',
3266 b'show-revs',
3267 True,
3267 True,
3268 _(b'print list of result revisions (default)'),
3268 _(b'print list of result revisions (default)'),
3269 ),
3269 ),
3270 (
3270 (
3271 b's',
3271 b's',
3272 b'show-set',
3272 b'show-set',
3273 None,
3273 None,
3274 _(b'print internal representation of result set'),
3274 _(b'print internal representation of result set'),
3275 ),
3275 ),
3276 (
3276 (
3277 b'p',
3277 b'p',
3278 b'show-stage',
3278 b'show-stage',
3279 [],
3279 [],
3280 _(b'print parsed tree at the given stage'),
3280 _(b'print parsed tree at the given stage'),
3281 _(b'NAME'),
3281 _(b'NAME'),
3282 ),
3282 ),
3283 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3283 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3284 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3284 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3285 ],
3285 ],
3286 b'REVSPEC',
3286 b'REVSPEC',
3287 )
3287 )
3288 def debugrevspec(ui, repo, expr, **opts):
3288 def debugrevspec(ui, repo, expr, **opts):
3289 """parse and apply a revision specification
3289 """parse and apply a revision specification
3290
3290
3291 Use -p/--show-stage option to print the parsed tree at the given stages.
3291 Use -p/--show-stage option to print the parsed tree at the given stages.
3292 Use -p all to print tree at every stage.
3292 Use -p all to print tree at every stage.
3293
3293
3294 Use --no-show-revs option with -s or -p to print only the set
3294 Use --no-show-revs option with -s or -p to print only the set
3295 representation or the parsed tree respectively.
3295 representation or the parsed tree respectively.
3296
3296
3297 Use --verify-optimized to compare the optimized result with the unoptimized
3297 Use --verify-optimized to compare the optimized result with the unoptimized
3298 one. Returns 1 if the optimized result differs.
3298 one. Returns 1 if the optimized result differs.
3299 """
3299 """
3300 aliases = ui.configitems(b'revsetalias')
3300 aliases = ui.configitems(b'revsetalias')
3301 stages = [
3301 stages = [
3302 (b'parsed', lambda tree: tree),
3302 (b'parsed', lambda tree: tree),
3303 (
3303 (
3304 b'expanded',
3304 b'expanded',
3305 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3305 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3306 ),
3306 ),
3307 (b'concatenated', revsetlang.foldconcat),
3307 (b'concatenated', revsetlang.foldconcat),
3308 (b'analyzed', revsetlang.analyze),
3308 (b'analyzed', revsetlang.analyze),
3309 (b'optimized', revsetlang.optimize),
3309 (b'optimized', revsetlang.optimize),
3310 ]
3310 ]
3311 if opts['no_optimized']:
3311 if opts['no_optimized']:
3312 stages = stages[:-1]
3312 stages = stages[:-1]
3313 if opts['verify_optimized'] and opts['no_optimized']:
3313 if opts['verify_optimized'] and opts['no_optimized']:
3314 raise error.Abort(
3314 raise error.Abort(
3315 _(b'cannot use --verify-optimized with --no-optimized')
3315 _(b'cannot use --verify-optimized with --no-optimized')
3316 )
3316 )
3317 stagenames = {n for n, f in stages}
3317 stagenames = {n for n, f in stages}
3318
3318
3319 showalways = set()
3319 showalways = set()
3320 showchanged = set()
3320 showchanged = set()
3321 if ui.verbose and not opts['show_stage']:
3321 if ui.verbose and not opts['show_stage']:
3322 # show parsed tree by --verbose (deprecated)
3322 # show parsed tree by --verbose (deprecated)
3323 showalways.add(b'parsed')
3323 showalways.add(b'parsed')
3324 showchanged.update([b'expanded', b'concatenated'])
3324 showchanged.update([b'expanded', b'concatenated'])
3325 if opts['optimize']:
3325 if opts['optimize']:
3326 showalways.add(b'optimized')
3326 showalways.add(b'optimized')
3327 if opts['show_stage'] and opts['optimize']:
3327 if opts['show_stage'] and opts['optimize']:
3328 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3328 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3329 if opts['show_stage'] == [b'all']:
3329 if opts['show_stage'] == [b'all']:
3330 showalways.update(stagenames)
3330 showalways.update(stagenames)
3331 else:
3331 else:
3332 for n in opts['show_stage']:
3332 for n in opts['show_stage']:
3333 if n not in stagenames:
3333 if n not in stagenames:
3334 raise error.Abort(_(b'invalid stage name: %s') % n)
3334 raise error.Abort(_(b'invalid stage name: %s') % n)
3335 showalways.update(opts['show_stage'])
3335 showalways.update(opts['show_stage'])
3336
3336
3337 treebystage = {}
3337 treebystage = {}
3338 printedtree = None
3338 printedtree = None
3339 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3339 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3340 for n, f in stages:
3340 for n, f in stages:
3341 treebystage[n] = tree = f(tree)
3341 treebystage[n] = tree = f(tree)
3342 if n in showalways or (n in showchanged and tree != printedtree):
3342 if n in showalways or (n in showchanged and tree != printedtree):
3343 if opts['show_stage'] or n != b'parsed':
3343 if opts['show_stage'] or n != b'parsed':
3344 ui.write(b"* %s:\n" % n)
3344 ui.write(b"* %s:\n" % n)
3345 ui.write(revsetlang.prettyformat(tree), b"\n")
3345 ui.write(revsetlang.prettyformat(tree), b"\n")
3346 printedtree = tree
3346 printedtree = tree
3347
3347
3348 if opts['verify_optimized']:
3348 if opts['verify_optimized']:
3349 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3349 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3350 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3350 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3351 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3351 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3352 ui.writenoi18n(
3352 ui.writenoi18n(
3353 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3353 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3354 )
3354 )
3355 ui.writenoi18n(
3355 ui.writenoi18n(
3356 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3356 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3357 )
3357 )
3358 arevs = list(arevs)
3358 arevs = list(arevs)
3359 brevs = list(brevs)
3359 brevs = list(brevs)
3360 if arevs == brevs:
3360 if arevs == brevs:
3361 return 0
3361 return 0
3362 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3362 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3363 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3363 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3364 sm = difflib.SequenceMatcher(None, arevs, brevs)
3364 sm = difflib.SequenceMatcher(None, arevs, brevs)
3365 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3365 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3366 if tag in ('delete', 'replace'):
3366 if tag in ('delete', 'replace'):
3367 for c in arevs[alo:ahi]:
3367 for c in arevs[alo:ahi]:
3368 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3368 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3369 if tag in ('insert', 'replace'):
3369 if tag in ('insert', 'replace'):
3370 for c in brevs[blo:bhi]:
3370 for c in brevs[blo:bhi]:
3371 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3371 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3372 if tag == 'equal':
3372 if tag == 'equal':
3373 for c in arevs[alo:ahi]:
3373 for c in arevs[alo:ahi]:
3374 ui.write(b' %d\n' % c)
3374 ui.write(b' %d\n' % c)
3375 return 1
3375 return 1
3376
3376
3377 func = revset.makematcher(tree)
3377 func = revset.makematcher(tree)
3378 revs = func(repo)
3378 revs = func(repo)
3379 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3379 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
3380 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3380 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3381 if not opts['show_revs']:
3381 if not opts['show_revs']:
3382 return
3382 return
3383 for c in revs:
3383 for c in revs:
3384 ui.write(b"%d\n" % c)
3384 ui.write(b"%d\n" % c)
3385
3385
3386
3386
3387 @command(
3387 @command(
3388 b'debugserve',
3388 b'debugserve',
3389 [
3389 [
3390 (
3390 (
3391 b'',
3391 b'',
3392 b'sshstdio',
3392 b'sshstdio',
3393 False,
3393 False,
3394 _(b'run an SSH server bound to process handles'),
3394 _(b'run an SSH server bound to process handles'),
3395 ),
3395 ),
3396 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3396 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3397 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3397 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3398 ],
3398 ],
3399 b'',
3399 b'',
3400 )
3400 )
3401 def debugserve(ui, repo, **opts):
3401 def debugserve(ui, repo, **opts):
3402 """run a server with advanced settings
3402 """run a server with advanced settings
3403
3403
3404 This command is similar to :hg:`serve`. It exists partially as a
3404 This command is similar to :hg:`serve`. It exists partially as a
3405 workaround to the fact that ``hg serve --stdio`` must have specific
3405 workaround to the fact that ``hg serve --stdio`` must have specific
3406 arguments for security reasons.
3406 arguments for security reasons.
3407 """
3407 """
3408 if not opts['sshstdio']:
3408 if not opts['sshstdio']:
3409 raise error.Abort(_(b'only --sshstdio is currently supported'))
3409 raise error.Abort(_(b'only --sshstdio is currently supported'))
3410
3410
3411 logfh = None
3411 logfh = None
3412
3412
3413 if opts['logiofd'] and opts['logiofile']:
3413 if opts['logiofd'] and opts['logiofile']:
3414 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3414 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3415
3415
3416 if opts['logiofd']:
3416 if opts['logiofd']:
3417 # Ideally we would be line buffered. But line buffering in binary
3417 # Ideally we would be line buffered. But line buffering in binary
3418 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3418 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3419 # buffering could have performance impacts. But since this isn't
3419 # buffering could have performance impacts. But since this isn't
3420 # performance critical code, it should be fine.
3420 # performance critical code, it should be fine.
3421 try:
3421 try:
3422 logfh = os.fdopen(int(opts['logiofd']), 'ab', 0)
3422 logfh = os.fdopen(int(opts['logiofd']), 'ab', 0)
3423 except OSError as e:
3423 except OSError as e:
3424 if e.errno != errno.ESPIPE:
3424 if e.errno != errno.ESPIPE:
3425 raise
3425 raise
3426 # can't seek a pipe, so `ab` mode fails on py3
3426 # can't seek a pipe, so `ab` mode fails on py3
3427 logfh = os.fdopen(int(opts['logiofd']), 'wb', 0)
3427 logfh = os.fdopen(int(opts['logiofd']), 'wb', 0)
3428 elif opts['logiofile']:
3428 elif opts['logiofile']:
3429 logfh = open(opts['logiofile'], b'ab', 0)
3429 logfh = open(opts['logiofile'], b'ab', 0)
3430
3430
3431 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3431 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3432 s.serve_forever()
3432 s.serve_forever()
3433
3433
3434
3434
3435 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3435 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3436 def debugsetparents(ui, repo, rev1, rev2=None):
3436 def debugsetparents(ui, repo, rev1, rev2=None):
3437 """manually set the parents of the current working directory (DANGEROUS)
3437 """manually set the parents of the current working directory (DANGEROUS)
3438
3438
3439 This command is not what you are looking for and should not be used. Using
3439 This command is not what you are looking for and should not be used. Using
3440 this command will most certainly results in slight corruption of the file
3440 this command will most certainly results in slight corruption of the file
3441 level histories within your repository. DO NOT USE THIS COMMAND.
3441 level histories within your repository. DO NOT USE THIS COMMAND.
3442
3442
3443 The command updates the p1 and p2 fields in the dirstate, without touching
3443 The command updates the p1 and p2 fields in the dirstate, without touching
3444 anything else. This useful for writing repository conversion tools, but
3444 anything else. This useful for writing repository conversion tools, but
3445 should be used with extreme care. For example, neither the working
3445 should be used with extreme care. For example, neither the working
3446 directory nor the dirstate is updated, so file statuses may be incorrect
3446 directory nor the dirstate is updated, so file statuses may be incorrect
3447 after running this command. Use it only if you are one of the few people who
3447 after running this command. Use it only if you are one of the few people who
3448 deeply understands both conversion tools and file level histories. If you are
3448 deeply understands both conversion tools and file level histories. If you are
3449 reading this help, you are not one of those people (most of them sailed west
3449 reading this help, you are not one of those people (most of them sailed west
3450 from Mithlond anyway).
3450 from Mithlond anyway).
3451
3451
3452 So, one more time, DO NOT USE THIS COMMAND.
3452 So, one more time, DO NOT USE THIS COMMAND.
3453
3453
3454 Returns 0 on success.
3454 Returns 0 on success.
3455 """
3455 """
3456
3456
3457 node1 = scmutil.revsingle(repo, rev1).node()
3457 node1 = scmutil.revsingle(repo, rev1).node()
3458 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3458 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3459
3459
3460 with repo.wlock():
3460 with repo.wlock():
3461 repo.setparents(node1, node2)
3461 repo.setparents(node1, node2)
3462
3462
3463
3463
3464 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3464 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3465 def debugsidedata(ui, repo, file_, rev=None, **opts):
3465 def debugsidedata(ui, repo, file_, rev=None, **opts):
3466 """dump the side data for a cl/manifest/file revision
3466 """dump the side data for a cl/manifest/file revision
3467
3467
3468 Use --verbose to dump the sidedata content."""
3468 Use --verbose to dump the sidedata content."""
3469 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
3469 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
3470 if rev is not None:
3470 if rev is not None:
3471 raise error.InputError(
3471 raise error.InputError(
3472 _(b'cannot specify a revision with other arguments')
3472 _(b'cannot specify a revision with other arguments')
3473 )
3473 )
3474 file_, rev = None, file_
3474 file_, rev = None, file_
3475 elif rev is None:
3475 elif rev is None:
3476 raise error.InputError(_(b'please specify a revision'))
3476 raise error.InputError(_(b'please specify a revision'))
3477 r = cmdutil.openstorage(
3477 r = cmdutil.openstorage(
3478 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
3478 repo, b'debugdata', file_, pycompat.byteskwargs(opts)
3479 )
3479 )
3480 r = getattr(r, '_revlog', r)
3480 r = getattr(r, '_revlog', r)
3481 try:
3481 try:
3482 sidedata = r.sidedata(r.lookup(rev))
3482 sidedata = r.sidedata(r.lookup(rev))
3483 except KeyError:
3483 except KeyError:
3484 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3484 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3485 if sidedata:
3485 if sidedata:
3486 sidedata = list(sidedata.items())
3486 sidedata = list(sidedata.items())
3487 sidedata.sort()
3487 sidedata.sort()
3488 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3488 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3489 for key, value in sidedata:
3489 for key, value in sidedata:
3490 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3490 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3491 if ui.verbose:
3491 if ui.verbose:
3492 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3492 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3493
3493
3494
3494
3495 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3495 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3496 def debugssl(ui, repo, source=None, **opts):
3496 def debugssl(ui, repo, source=None, **opts):
3497 """test a secure connection to a server
3497 """test a secure connection to a server
3498
3498
3499 This builds the certificate chain for the server on Windows, installing the
3499 This builds the certificate chain for the server on Windows, installing the
3500 missing intermediates and trusted root via Windows Update if necessary. It
3500 missing intermediates and trusted root via Windows Update if necessary. It
3501 does nothing on other platforms.
3501 does nothing on other platforms.
3502
3502
3503 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3503 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3504 that server is used. See :hg:`help urls` for more information.
3504 that server is used. See :hg:`help urls` for more information.
3505
3505
3506 If the update succeeds, retry the original operation. Otherwise, the cause
3506 If the update succeeds, retry the original operation. Otherwise, the cause
3507 of the SSL error is likely another issue.
3507 of the SSL error is likely another issue.
3508 """
3508 """
3509 if not pycompat.iswindows:
3509 if not pycompat.iswindows:
3510 raise error.Abort(
3510 raise error.Abort(
3511 _(b'certificate chain building is only possible on Windows')
3511 _(b'certificate chain building is only possible on Windows')
3512 )
3512 )
3513
3513
3514 if not source:
3514 if not source:
3515 if not repo:
3515 if not repo:
3516 raise error.Abort(
3516 raise error.Abort(
3517 _(
3517 _(
3518 b"there is no Mercurial repository here, and no "
3518 b"there is no Mercurial repository here, and no "
3519 b"server specified"
3519 b"server specified"
3520 )
3520 )
3521 )
3521 )
3522 source = b"default"
3522 source = b"default"
3523
3523
3524 path = urlutil.get_unique_pull_path_obj(b'debugssl', ui, source)
3524 path = urlutil.get_unique_pull_path_obj(b'debugssl', ui, source)
3525 url = path.url
3525 url = path.url
3526
3526
3527 defaultport = {b'https': 443, b'ssh': 22}
3527 defaultport = {b'https': 443, b'ssh': 22}
3528 if url.scheme in defaultport:
3528 if url.scheme in defaultport:
3529 try:
3529 try:
3530 addr = (url.host, int(url.port or defaultport[url.scheme]))
3530 addr = (url.host, int(url.port or defaultport[url.scheme]))
3531 except ValueError:
3531 except ValueError:
3532 raise error.Abort(_(b"malformed port number in URL"))
3532 raise error.Abort(_(b"malformed port number in URL"))
3533 else:
3533 else:
3534 raise error.Abort(_(b"only https and ssh connections are supported"))
3534 raise error.Abort(_(b"only https and ssh connections are supported"))
3535
3535
3536 from . import win32
3536 from . import win32
3537
3537
3538 s = ssl.wrap_socket(
3538 s = ssl.wrap_socket(
3539 socket.socket(),
3539 socket.socket(),
3540 ssl_version=ssl.PROTOCOL_TLS,
3540 ssl_version=ssl.PROTOCOL_TLS,
3541 cert_reqs=ssl.CERT_NONE,
3541 cert_reqs=ssl.CERT_NONE,
3542 ca_certs=None,
3542 ca_certs=None,
3543 )
3543 )
3544
3544
3545 try:
3545 try:
3546 s.connect(addr)
3546 s.connect(addr)
3547 cert = s.getpeercert(True)
3547 cert = s.getpeercert(True)
3548
3548
3549 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3549 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3550
3550
3551 complete = win32.checkcertificatechain(cert, build=False)
3551 complete = win32.checkcertificatechain(cert, build=False)
3552
3552
3553 if not complete:
3553 if not complete:
3554 ui.status(_(b'certificate chain is incomplete, updating... '))
3554 ui.status(_(b'certificate chain is incomplete, updating... '))
3555
3555
3556 if not win32.checkcertificatechain(cert):
3556 if not win32.checkcertificatechain(cert):
3557 ui.status(_(b'failed.\n'))
3557 ui.status(_(b'failed.\n'))
3558 else:
3558 else:
3559 ui.status(_(b'done.\n'))
3559 ui.status(_(b'done.\n'))
3560 else:
3560 else:
3561 ui.status(_(b'full certificate chain is available\n'))
3561 ui.status(_(b'full certificate chain is available\n'))
3562 finally:
3562 finally:
3563 s.close()
3563 s.close()
3564
3564
3565
3565
3566 @command(
3566 @command(
3567 b'debug::stable-tail-sort',
3567 b'debug::stable-tail-sort',
3568 [
3568 [
3569 (
3569 (
3570 b'T',
3570 b'T',
3571 b'template',
3571 b'template',
3572 b'{rev}\n',
3572 b'{rev}\n',
3573 _(b'display with template'),
3573 _(b'display with template'),
3574 _(b'TEMPLATE'),
3574 _(b'TEMPLATE'),
3575 ),
3575 ),
3576 ],
3576 ],
3577 b'REV',
3577 b'REV',
3578 )
3578 )
3579 def debug_stable_tail_sort(ui, repo, revspec, template, **opts):
3579 def debug_stable_tail_sort(ui, repo, revspec, template, **opts):
3580 """display the stable-tail sort of the ancestors of a given node"""
3580 """display the stable-tail sort of the ancestors of a given node"""
3581 rev = logcmdutil.revsingle(repo, revspec).rev()
3581 rev = logcmdutil.revsingle(repo, revspec).rev()
3582 cl = repo.changelog
3582 cl = repo.changelog
3583
3583
3584 displayer = logcmdutil.maketemplater(ui, repo, template)
3584 displayer = logcmdutil.maketemplater(ui, repo, template)
3585 sorted_revs = stabletailsort._stable_tail_sort_naive(cl, rev)
3585 sorted_revs = stabletailsort._stable_tail_sort_naive(cl, rev)
3586 for ancestor_rev in sorted_revs:
3586 for ancestor_rev in sorted_revs:
3587 displayer.show(repo[ancestor_rev])
3587 displayer.show(repo[ancestor_rev])
3588
3588
3589
3589
3590 @command(
3590 @command(
3591 b'debug::stable-tail-sort-leaps',
3591 b'debug::stable-tail-sort-leaps',
3592 [
3592 [
3593 (
3593 (
3594 b'T',
3594 b'T',
3595 b'template',
3595 b'template',
3596 b'{rev}',
3596 b'{rev}',
3597 _(b'display with template'),
3597 _(b'display with template'),
3598 _(b'TEMPLATE'),
3598 _(b'TEMPLATE'),
3599 ),
3599 ),
3600 (b's', b'specific', False, _(b'restrict to specific leaps')),
3600 (b's', b'specific', False, _(b'restrict to specific leaps')),
3601 ],
3601 ],
3602 b'REV',
3602 b'REV',
3603 )
3603 )
3604 def debug_stable_tail_sort_leaps(ui, repo, rspec, template, specific, **opts):
3604 def debug_stable_tail_sort_leaps(ui, repo, rspec, template, specific, **opts):
3605 """display the leaps in the stable-tail sort of a node, one per line"""
3605 """display the leaps in the stable-tail sort of a node, one per line"""
3606 rev = logcmdutil.revsingle(repo, rspec).rev()
3606 rev = logcmdutil.revsingle(repo, rspec).rev()
3607
3607
3608 if specific:
3608 if specific:
3609 get_leaps = stabletailsort._find_specific_leaps_naive
3609 get_leaps = stabletailsort._find_specific_leaps_naive
3610 else:
3610 else:
3611 get_leaps = stabletailsort._find_all_leaps_naive
3611 get_leaps = stabletailsort._find_all_leaps_naive
3612
3612
3613 displayer = logcmdutil.maketemplater(ui, repo, template)
3613 displayer = logcmdutil.maketemplater(ui, repo, template)
3614 for source, target in get_leaps(repo.changelog, rev):
3614 for source, target in get_leaps(repo.changelog, rev):
3615 displayer.show(repo[source])
3615 displayer.show(repo[source])
3616 displayer.show(repo[target])
3616 displayer.show(repo[target])
3617 ui.write(b'\n')
3617 ui.write(b'\n')
3618
3618
3619
3619
3620 @command(
3620 @command(
3621 b"debugbackupbundle",
3621 b"debugbackupbundle",
3622 [
3622 [
3623 (
3623 (
3624 b"",
3624 b"",
3625 b"recover",
3625 b"recover",
3626 b"",
3626 b"",
3627 b"brings the specified changeset back into the repository",
3627 b"brings the specified changeset back into the repository",
3628 )
3628 )
3629 ]
3629 ]
3630 + cmdutil.logopts,
3630 + cmdutil.logopts,
3631 _(b"hg debugbackupbundle [--recover HASH]"),
3631 _(b"hg debugbackupbundle [--recover HASH]"),
3632 )
3632 )
3633 def debugbackupbundle(ui, repo, *pats, **opts):
3633 def debugbackupbundle(ui, repo, *pats, **opts):
3634 """lists the changesets available in backup bundles
3634 """lists the changesets available in backup bundles
3635
3635
3636 Without any arguments, this command prints a list of the changesets in each
3636 Without any arguments, this command prints a list of the changesets in each
3637 backup bundle.
3637 backup bundle.
3638
3638
3639 --recover takes a changeset hash and unbundles the first bundle that
3639 --recover takes a changeset hash and unbundles the first bundle that
3640 contains that hash, which puts that changeset back in your repository.
3640 contains that hash, which puts that changeset back in your repository.
3641
3641
3642 --verbose will print the entire commit message and the bundle path for that
3642 --verbose will print the entire commit message and the bundle path for that
3643 backup.
3643 backup.
3644 """
3644 """
3645 backups = list(
3645 backups = list(
3646 filter(
3646 filter(
3647 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3647 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3648 )
3648 )
3649 )
3649 )
3650 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3650 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3651
3651
3652 opts["bundle"] = b""
3652 opts["bundle"] = b""
3653 opts["force"] = None
3653 opts["force"] = None
3654 limit = logcmdutil.getlimit(pycompat.byteskwargs(opts))
3654 limit = logcmdutil.getlimit(pycompat.byteskwargs(opts))
3655
3655
3656 def display(other, chlist, displayer):
3656 def display(other, chlist, displayer):
3657 if opts.get("newest_first"):
3657 if opts.get("newest_first"):
3658 chlist.reverse()
3658 chlist.reverse()
3659 count = 0
3659 count = 0
3660 for n in chlist:
3660 for n in chlist:
3661 if limit is not None and count >= limit:
3661 if limit is not None and count >= limit:
3662 break
3662 break
3663 parents = [
3663 parents = [
3664 True for p in other.changelog.parents(n) if p != repo.nullid
3664 True for p in other.changelog.parents(n) if p != repo.nullid
3665 ]
3665 ]
3666 if opts.get("no_merges") and len(parents) == 2:
3666 if opts.get("no_merges") and len(parents) == 2:
3667 continue
3667 continue
3668 count += 1
3668 count += 1
3669 displayer.show(other[n])
3669 displayer.show(other[n])
3670
3670
3671 recovernode = opts.get("recover")
3671 recovernode = opts.get("recover")
3672 if recovernode:
3672 if recovernode:
3673 if scmutil.isrevsymbol(repo, recovernode):
3673 if scmutil.isrevsymbol(repo, recovernode):
3674 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3674 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3675 return
3675 return
3676 elif backups:
3676 elif backups:
3677 msg = _(
3677 msg = _(
3678 b"Recover changesets using: hg debugbackupbundle --recover "
3678 b"Recover changesets using: hg debugbackupbundle --recover "
3679 b"<changeset hash>\n\nAvailable backup changesets:"
3679 b"<changeset hash>\n\nAvailable backup changesets:"
3680 )
3680 )
3681 ui.status(msg, label=b"status.removed")
3681 ui.status(msg, label=b"status.removed")
3682 else:
3682 else:
3683 ui.status(_(b"no backup changesets found\n"))
3683 ui.status(_(b"no backup changesets found\n"))
3684 return
3684 return
3685
3685
3686 for backup in backups:
3686 for backup in backups:
3687 # Much of this is copied from the hg incoming logic
3687 # Much of this is copied from the hg incoming logic
3688 source = os.path.relpath(backup, encoding.getcwd())
3688 source = os.path.relpath(backup, encoding.getcwd())
3689 path = urlutil.get_unique_pull_path_obj(
3689 path = urlutil.get_unique_pull_path_obj(
3690 b'debugbackupbundle',
3690 b'debugbackupbundle',
3691 ui,
3691 ui,
3692 source,
3692 source,
3693 )
3693 )
3694 try:
3694 try:
3695 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
3695 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
3696 except error.LookupError as ex:
3696 except error.LookupError as ex:
3697 msg = _(b"\nwarning: unable to open bundle %s") % path.loc
3697 msg = _(b"\nwarning: unable to open bundle %s") % path.loc
3698 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3698 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3699 ui.warn(msg, hint=hint)
3699 ui.warn(msg, hint=hint)
3700 continue
3700 continue
3701 branches = (path.branch, opts.get('branch', []))
3701 branches = (path.branch, opts.get('branch', []))
3702 revs, checkout = hg.addbranchrevs(
3702 revs, checkout = hg.addbranchrevs(
3703 repo, other, branches, opts.get("rev")
3703 repo, other, branches, opts.get("rev")
3704 )
3704 )
3705
3705
3706 if revs:
3706 if revs:
3707 revs = [other.lookup(rev) for rev in revs]
3707 revs = [other.lookup(rev) for rev in revs]
3708
3708
3709 with ui.silent():
3709 with ui.silent():
3710 try:
3710 try:
3711 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3711 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3712 ui, repo, other, revs, opts["bundle"], opts["force"]
3712 ui, repo, other, revs, opts["bundle"], opts["force"]
3713 )
3713 )
3714 except error.LookupError:
3714 except error.LookupError:
3715 continue
3715 continue
3716
3716
3717 try:
3717 try:
3718 if not chlist:
3718 if not chlist:
3719 continue
3719 continue
3720 if recovernode:
3720 if recovernode:
3721 with repo.lock(), repo.transaction(b"unbundle") as tr:
3721 with repo.lock(), repo.transaction(b"unbundle") as tr:
3722 if scmutil.isrevsymbol(other, recovernode):
3722 if scmutil.isrevsymbol(other, recovernode):
3723 ui.status(_(b"Unbundling %s\n") % (recovernode))
3723 ui.status(_(b"Unbundling %s\n") % (recovernode))
3724 f = hg.openpath(ui, path.loc)
3724 f = hg.openpath(ui, path.loc)
3725 gen = exchange.readbundle(ui, f, path.loc)
3725 gen = exchange.readbundle(ui, f, path.loc)
3726 if isinstance(gen, bundle2.unbundle20):
3726 if isinstance(gen, bundle2.unbundle20):
3727 bundle2.applybundle(
3727 bundle2.applybundle(
3728 repo,
3728 repo,
3729 gen,
3729 gen,
3730 tr,
3730 tr,
3731 source=b"unbundle",
3731 source=b"unbundle",
3732 url=b"bundle:" + path.loc,
3732 url=b"bundle:" + path.loc,
3733 )
3733 )
3734 else:
3734 else:
3735 gen.apply(repo, b"unbundle", b"bundle:" + path.loc)
3735 gen.apply(repo, b"unbundle", b"bundle:" + path.loc)
3736 break
3736 break
3737 else:
3737 else:
3738 backupdate = encoding.strtolocal(
3738 backupdate = encoding.strtolocal(
3739 time.strftime(
3739 time.strftime(
3740 "%a %H:%M, %Y-%m-%d",
3740 "%a %H:%M, %Y-%m-%d",
3741 time.localtime(os.path.getmtime(path.loc)),
3741 time.localtime(os.path.getmtime(path.loc)),
3742 )
3742 )
3743 )
3743 )
3744 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3744 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3745 if ui.verbose:
3745 if ui.verbose:
3746 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), path.loc))
3746 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), path.loc))
3747 else:
3747 else:
3748 opts[
3748 opts[
3749 "template"
3749 "template"
3750 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3750 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3751 displayer = logcmdutil.changesetdisplayer(
3751 displayer = logcmdutil.changesetdisplayer(
3752 ui, other, pycompat.byteskwargs(opts), False
3752 ui, other, pycompat.byteskwargs(opts), False
3753 )
3753 )
3754 display(other, chlist, displayer)
3754 display(other, chlist, displayer)
3755 displayer.close()
3755 displayer.close()
3756 finally:
3756 finally:
3757 cleanupfn()
3757 cleanupfn()
3758
3758
3759
3759
3760 @command(
3760 @command(
3761 b'debugsub',
3761 b'debugsub',
3762 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3762 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3763 _(b'[-r REV] [REV]'),
3763 _(b'[-r REV] [REV]'),
3764 )
3764 )
3765 def debugsub(ui, repo, rev=None):
3765 def debugsub(ui, repo, rev=None):
3766 ctx = scmutil.revsingle(repo, rev, None)
3766 ctx = scmutil.revsingle(repo, rev, None)
3767 for k, v in sorted(ctx.substate.items()):
3767 for k, v in sorted(ctx.substate.items()):
3768 ui.writenoi18n(b'path %s\n' % k)
3768 ui.writenoi18n(b'path %s\n' % k)
3769 ui.writenoi18n(b' source %s\n' % v[0])
3769 ui.writenoi18n(b' source %s\n' % v[0])
3770 ui.writenoi18n(b' revision %s\n' % v[1])
3770 ui.writenoi18n(b' revision %s\n' % v[1])
3771
3771
3772
3772
3773 @command(
3773 @command(
3774 b'debugshell',
3774 b'debugshell',
3775 [
3775 [
3776 (
3776 (
3777 b'c',
3777 b'c',
3778 b'command',
3778 b'command',
3779 b'',
3779 b'',
3780 _(b'program passed in as a string'),
3780 _(b'program passed in as a string'),
3781 _(b'COMMAND'),
3781 _(b'COMMAND'),
3782 )
3782 )
3783 ],
3783 ],
3784 _(b'[-c COMMAND]'),
3784 _(b'[-c COMMAND]'),
3785 optionalrepo=True,
3785 optionalrepo=True,
3786 )
3786 )
3787 def debugshell(ui, repo, **opts):
3787 def debugshell(ui, repo, **opts):
3788 """run an interactive Python interpreter
3788 """run an interactive Python interpreter
3789
3789
3790 The local namespace is provided with a reference to the ui and
3790 The local namespace is provided with a reference to the ui and
3791 the repo instance (if available).
3791 the repo instance (if available).
3792 """
3792 """
3793 import code
3793 import code
3794
3794
3795 imported_objects = {
3795 imported_objects = {
3796 'ui': ui,
3796 'ui': ui,
3797 'repo': repo,
3797 'repo': repo,
3798 }
3798 }
3799
3799
3800 # py2exe disables initialization of the site module, which is responsible
3800 # py2exe disables initialization of the site module, which is responsible
3801 # for arranging for ``quit()`` to exit the interpreter. Manually initialize
3801 # for arranging for ``quit()`` to exit the interpreter. Manually initialize
3802 # the stuff that site normally does here, so that the interpreter can be
3802 # the stuff that site normally does here, so that the interpreter can be
3803 # quit in a consistent manner, whether run with pyoxidizer, exewrapper.c,
3803 # quit in a consistent manner, whether run with pyoxidizer, exewrapper.c,
3804 # py.exe, or py2exe.
3804 # py.exe, or py2exe.
3805 if getattr(sys, "frozen", None) == 'console_exe':
3805 if getattr(sys, "frozen", None) == 'console_exe':
3806 try:
3806 try:
3807 import site
3807 import site
3808
3808
3809 site.setcopyright()
3809 site.setcopyright()
3810 site.sethelper()
3810 site.sethelper()
3811 site.setquit()
3811 site.setquit()
3812 except ImportError:
3812 except ImportError:
3813 site = None # Keep PyCharm happy
3813 site = None # Keep PyCharm happy
3814
3814
3815 command = opts.get('command')
3815 command = opts.get('command')
3816 if command:
3816 if command:
3817 compiled = code.compile_command(encoding.strfromlocal(command))
3817 compiled = code.compile_command(encoding.strfromlocal(command))
3818 code.InteractiveInterpreter(locals=imported_objects).runcode(compiled)
3818 code.InteractiveInterpreter(locals=imported_objects).runcode(compiled)
3819 return
3819 return
3820
3820
3821 code.interact(local=imported_objects)
3821 code.interact(local=imported_objects)
3822
3822
3823
3823
3824 @command(
3824 @command(
3825 b'debug-revlog-stats',
3825 b'debug-revlog-stats',
3826 [
3826 [
3827 (b'c', b'changelog', None, _(b'Display changelog statistics')),
3827 (b'c', b'changelog', None, _(b'Display changelog statistics')),
3828 (b'm', b'manifest', None, _(b'Display manifest statistics')),
3828 (b'm', b'manifest', None, _(b'Display manifest statistics')),
3829 (b'f', b'filelogs', None, _(b'Display filelogs statistics')),
3829 (b'f', b'filelogs', None, _(b'Display filelogs statistics')),
3830 ]
3830 ]
3831 + cmdutil.formatteropts,
3831 + cmdutil.formatteropts,
3832 )
3832 )
3833 def debug_revlog_stats(ui, repo, **opts):
3833 def debug_revlog_stats(ui, repo, **opts):
3834 """display statistics about revlogs in the store"""
3834 """display statistics about revlogs in the store"""
3835 changelog = opts["changelog"]
3835 changelog = opts["changelog"]
3836 manifest = opts["manifest"]
3836 manifest = opts["manifest"]
3837 filelogs = opts["filelogs"]
3837 filelogs = opts["filelogs"]
3838
3838
3839 if changelog is None and manifest is None and filelogs is None:
3839 if changelog is None and manifest is None and filelogs is None:
3840 changelog = True
3840 changelog = True
3841 manifest = True
3841 manifest = True
3842 filelogs = True
3842 filelogs = True
3843
3843
3844 repo = repo.unfiltered()
3844 repo = repo.unfiltered()
3845 fm = ui.formatter(b'debug-revlog-stats', pycompat.byteskwargs(opts))
3845 fm = ui.formatter(b'debug-revlog-stats', pycompat.byteskwargs(opts))
3846 revlog_debug.debug_revlog_stats(repo, fm, changelog, manifest, filelogs)
3846 revlog_debug.debug_revlog_stats(repo, fm, changelog, manifest, filelogs)
3847 fm.end()
3847 fm.end()
3848
3848
3849
3849
3850 @command(
3850 @command(
3851 b'debugsuccessorssets',
3851 b'debugsuccessorssets',
3852 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3852 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3853 _(b'[REV]'),
3853 _(b'[REV]'),
3854 )
3854 )
3855 def debugsuccessorssets(ui, repo, *revs, **opts):
3855 def debugsuccessorssets(ui, repo, *revs, **opts):
3856 """show set of successors for revision
3856 """show set of successors for revision
3857
3857
3858 A successors set of changeset A is a consistent group of revisions that
3858 A successors set of changeset A is a consistent group of revisions that
3859 succeed A. It contains non-obsolete changesets only unless closests
3859 succeed A. It contains non-obsolete changesets only unless closests
3860 successors set is set.
3860 successors set is set.
3861
3861
3862 In most cases a changeset A has a single successors set containing a single
3862 In most cases a changeset A has a single successors set containing a single
3863 successor (changeset A replaced by A').
3863 successor (changeset A replaced by A').
3864
3864
3865 A changeset that is made obsolete with no successors are called "pruned".
3865 A changeset that is made obsolete with no successors are called "pruned".
3866 Such changesets have no successors sets at all.
3866 Such changesets have no successors sets at all.
3867
3867
3868 A changeset that has been "split" will have a successors set containing
3868 A changeset that has been "split" will have a successors set containing
3869 more than one successor.
3869 more than one successor.
3870
3870
3871 A changeset that has been rewritten in multiple different ways is called
3871 A changeset that has been rewritten in multiple different ways is called
3872 "divergent". Such changesets have multiple successor sets (each of which
3872 "divergent". Such changesets have multiple successor sets (each of which
3873 may also be split, i.e. have multiple successors).
3873 may also be split, i.e. have multiple successors).
3874
3874
3875 Results are displayed as follows::
3875 Results are displayed as follows::
3876
3876
3877 <rev1>
3877 <rev1>
3878 <successors-1A>
3878 <successors-1A>
3879 <rev2>
3879 <rev2>
3880 <successors-2A>
3880 <successors-2A>
3881 <successors-2B1> <successors-2B2> <successors-2B3>
3881 <successors-2B1> <successors-2B2> <successors-2B3>
3882
3882
3883 Here rev2 has two possible (i.e. divergent) successors sets. The first
3883 Here rev2 has two possible (i.e. divergent) successors sets. The first
3884 holds one element, whereas the second holds three (i.e. the changeset has
3884 holds one element, whereas the second holds three (i.e. the changeset has
3885 been split).
3885 been split).
3886 """
3886 """
3887 # passed to successorssets caching computation from one call to another
3887 # passed to successorssets caching computation from one call to another
3888 cache = {}
3888 cache = {}
3889 ctx2str = bytes
3889 ctx2str = bytes
3890 node2str = short
3890 node2str = short
3891 for rev in logcmdutil.revrange(repo, revs):
3891 for rev in logcmdutil.revrange(repo, revs):
3892 ctx = repo[rev]
3892 ctx = repo[rev]
3893 ui.write(b'%s\n' % ctx2str(ctx))
3893 ui.write(b'%s\n' % ctx2str(ctx))
3894 for succsset in obsutil.successorssets(
3894 for succsset in obsutil.successorssets(
3895 repo, ctx.node(), closest=opts['closest'], cache=cache
3895 repo, ctx.node(), closest=opts['closest'], cache=cache
3896 ):
3896 ):
3897 if succsset:
3897 if succsset:
3898 ui.write(b' ')
3898 ui.write(b' ')
3899 ui.write(node2str(succsset[0]))
3899 ui.write(node2str(succsset[0]))
3900 for node in succsset[1:]:
3900 for node in succsset[1:]:
3901 ui.write(b' ')
3901 ui.write(b' ')
3902 ui.write(node2str(node))
3902 ui.write(node2str(node))
3903 ui.write(b'\n')
3903 ui.write(b'\n')
3904
3904
3905
3905
3906 @command(b'debugtagscache', [])
3906 @command(b'debugtagscache', [])
3907 def debugtagscache(ui, repo):
3907 def debugtagscache(ui, repo):
3908 """display the contents of .hg/cache/hgtagsfnodes1"""
3908 """display the contents of .hg/cache/hgtagsfnodes1"""
3909 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3909 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3910 flog = repo.file(b'.hgtags')
3910 flog = repo.file(b'.hgtags')
3911 for r in repo:
3911 for r in repo:
3912 node = repo[r].node()
3912 node = repo[r].node()
3913 tagsnode = cache.getfnode(node, computemissing=False)
3913 tagsnode = cache.getfnode(node, computemissing=False)
3914 if tagsnode:
3914 if tagsnode:
3915 tagsnodedisplay = hex(tagsnode)
3915 tagsnodedisplay = hex(tagsnode)
3916 if not flog.hasnode(tagsnode):
3916 if not flog.hasnode(tagsnode):
3917 tagsnodedisplay += b' (unknown node)'
3917 tagsnodedisplay += b' (unknown node)'
3918 elif tagsnode is None:
3918 elif tagsnode is None:
3919 tagsnodedisplay = b'missing'
3919 tagsnodedisplay = b'missing'
3920 else:
3920 else:
3921 tagsnodedisplay = b'invalid'
3921 tagsnodedisplay = b'invalid'
3922
3922
3923 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3923 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3924
3924
3925
3925
3926 @command(
3926 @command(
3927 b'debugtemplate',
3927 b'debugtemplate',
3928 [
3928 [
3929 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3929 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3930 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3930 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3931 ],
3931 ],
3932 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3932 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3933 optionalrepo=True,
3933 optionalrepo=True,
3934 )
3934 )
3935 def debugtemplate(ui, repo, tmpl, **opts):
3935 def debugtemplate(ui, repo, tmpl, **opts):
3936 """parse and apply a template
3936 """parse and apply a template
3937
3937
3938 If -r/--rev is given, the template is processed as a log template and
3938 If -r/--rev is given, the template is processed as a log template and
3939 applied to the given changesets. Otherwise, it is processed as a generic
3939 applied to the given changesets. Otherwise, it is processed as a generic
3940 template.
3940 template.
3941
3941
3942 Use --verbose to print the parsed tree.
3942 Use --verbose to print the parsed tree.
3943 """
3943 """
3944 revs = None
3944 revs = None
3945 if opts['rev']:
3945 if opts['rev']:
3946 if repo is None:
3946 if repo is None:
3947 raise error.RepoError(
3947 raise error.RepoError(
3948 _(b'there is no Mercurial repository here (.hg not found)')
3948 _(b'there is no Mercurial repository here (.hg not found)')
3949 )
3949 )
3950 revs = logcmdutil.revrange(repo, opts['rev'])
3950 revs = logcmdutil.revrange(repo, opts['rev'])
3951
3951
3952 props = {}
3952 props = {}
3953 for d in opts['define']:
3953 for d in opts['define']:
3954 try:
3954 try:
3955 k, v = (e.strip() for e in d.split(b'=', 1))
3955 k, v = (e.strip() for e in d.split(b'=', 1))
3956 if not k or k == b'ui':
3956 if not k or k == b'ui':
3957 raise ValueError
3957 raise ValueError
3958 props[k] = v
3958 props[k] = v
3959 except ValueError:
3959 except ValueError:
3960 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3960 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3961
3961
3962 if ui.verbose:
3962 if ui.verbose:
3963 aliases = ui.configitems(b'templatealias')
3963 aliases = ui.configitems(b'templatealias')
3964 tree = templater.parse(tmpl)
3964 tree = templater.parse(tmpl)
3965 ui.note(templater.prettyformat(tree), b'\n')
3965 ui.note(templater.prettyformat(tree), b'\n')
3966 newtree = templater.expandaliases(tree, aliases)
3966 newtree = templater.expandaliases(tree, aliases)
3967 if newtree != tree:
3967 if newtree != tree:
3968 ui.notenoi18n(
3968 ui.notenoi18n(
3969 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3969 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3970 )
3970 )
3971
3971
3972 if revs is None:
3972 if revs is None:
3973 tres = formatter.templateresources(ui, repo)
3973 tres = formatter.templateresources(ui, repo)
3974 t = formatter.maketemplater(ui, tmpl, resources=tres)
3974 t = formatter.maketemplater(ui, tmpl, resources=tres)
3975 if ui.verbose:
3975 if ui.verbose:
3976 kwds, funcs = t.symbolsuseddefault()
3976 kwds, funcs = t.symbolsuseddefault()
3977 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3977 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3978 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3978 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3979 ui.write(t.renderdefault(props))
3979 ui.write(t.renderdefault(props))
3980 else:
3980 else:
3981 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3981 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3982 if ui.verbose:
3982 if ui.verbose:
3983 kwds, funcs = displayer.t.symbolsuseddefault()
3983 kwds, funcs = displayer.t.symbolsuseddefault()
3984 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3984 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3985 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3985 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3986 for r in revs:
3986 for r in revs:
3987 displayer.show(repo[r], **pycompat.strkwargs(props))
3987 displayer.show(repo[r], **pycompat.strkwargs(props))
3988 displayer.close()
3988 displayer.close()
3989
3989
3990
3990
3991 @command(
3991 @command(
3992 b'debuguigetpass',
3992 b'debuguigetpass',
3993 [
3993 [
3994 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3994 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3995 ],
3995 ],
3996 _(b'[-p TEXT]'),
3996 _(b'[-p TEXT]'),
3997 norepo=True,
3997 norepo=True,
3998 )
3998 )
3999 def debuguigetpass(ui, prompt=b''):
3999 def debuguigetpass(ui, prompt=b''):
4000 """show prompt to type password"""
4000 """show prompt to type password"""
4001 r = ui.getpass(prompt)
4001 r = ui.getpass(prompt)
4002 if r is None:
4002 if r is None:
4003 r = b"<default response>"
4003 r = b"<default response>"
4004 ui.writenoi18n(b'response: %s\n' % r)
4004 ui.writenoi18n(b'response: %s\n' % r)
4005
4005
4006
4006
4007 @command(
4007 @command(
4008 b'debuguiprompt',
4008 b'debuguiprompt',
4009 [
4009 [
4010 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4010 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4011 ],
4011 ],
4012 _(b'[-p TEXT]'),
4012 _(b'[-p TEXT]'),
4013 norepo=True,
4013 norepo=True,
4014 )
4014 )
4015 def debuguiprompt(ui, prompt=b''):
4015 def debuguiprompt(ui, prompt=b''):
4016 """show plain prompt"""
4016 """show plain prompt"""
4017 r = ui.prompt(prompt)
4017 r = ui.prompt(prompt)
4018 ui.writenoi18n(b'response: %s\n' % r)
4018 ui.writenoi18n(b'response: %s\n' % r)
4019
4019
4020
4020
4021 @command(b'debugupdatecaches', [])
4021 @command(b'debugupdatecaches', [])
4022 def debugupdatecaches(ui, repo, *pats, **opts):
4022 def debugupdatecaches(ui, repo, *pats, **opts):
4023 """warm all known caches in the repository"""
4023 """warm all known caches in the repository"""
4024 with repo.wlock(), repo.lock():
4024 with repo.wlock(), repo.lock():
4025 repo.updatecaches(caches=repository.CACHES_ALL)
4025 repo.updatecaches(caches=repository.CACHES_ALL)
4026
4026
4027
4027
4028 @command(
4028 @command(
4029 b'debugupgraderepo',
4029 b'debugupgraderepo',
4030 [
4030 [
4031 (
4031 (
4032 b'o',
4032 b'o',
4033 b'optimize',
4033 b'optimize',
4034 [],
4034 [],
4035 _(b'extra optimization to perform'),
4035 _(b'extra optimization to perform'),
4036 _(b'NAME'),
4036 _(b'NAME'),
4037 ),
4037 ),
4038 (b'', b'run', False, _(b'performs an upgrade')),
4038 (b'', b'run', False, _(b'performs an upgrade')),
4039 (b'', b'backup', True, _(b'keep the old repository content around')),
4039 (b'', b'backup', True, _(b'keep the old repository content around')),
4040 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4040 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4041 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4041 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4042 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4042 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4043 ],
4043 ],
4044 )
4044 )
4045 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4045 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4046 """upgrade a repository to use different features
4046 """upgrade a repository to use different features
4047
4047
4048 If no arguments are specified, the repository is evaluated for upgrade
4048 If no arguments are specified, the repository is evaluated for upgrade
4049 and a list of problems and potential optimizations is printed.
4049 and a list of problems and potential optimizations is printed.
4050
4050
4051 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4051 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4052 can be influenced via additional arguments. More details will be provided
4052 can be influenced via additional arguments. More details will be provided
4053 by the command output when run without ``--run``.
4053 by the command output when run without ``--run``.
4054
4054
4055 During the upgrade, the repository will be locked and no writes will be
4055 During the upgrade, the repository will be locked and no writes will be
4056 allowed.
4056 allowed.
4057
4057
4058 At the end of the upgrade, the repository may not be readable while new
4058 At the end of the upgrade, the repository may not be readable while new
4059 repository data is swapped in. This window will be as long as it takes to
4059 repository data is swapped in. This window will be as long as it takes to
4060 rename some directories inside the ``.hg`` directory. On most machines, this
4060 rename some directories inside the ``.hg`` directory. On most machines, this
4061 should complete almost instantaneously and the chances of a consumer being
4061 should complete almost instantaneously and the chances of a consumer being
4062 unable to access the repository should be low.
4062 unable to access the repository should be low.
4063
4063
4064 By default, all revlogs will be upgraded. You can restrict this using flags
4064 By default, all revlogs will be upgraded. You can restrict this using flags
4065 such as `--manifest`:
4065 such as `--manifest`:
4066
4066
4067 * `--manifest`: only optimize the manifest
4067 * `--manifest`: only optimize the manifest
4068 * `--no-manifest`: optimize all revlog but the manifest
4068 * `--no-manifest`: optimize all revlog but the manifest
4069 * `--changelog`: optimize the changelog only
4069 * `--changelog`: optimize the changelog only
4070 * `--no-changelog --no-manifest`: optimize filelogs only
4070 * `--no-changelog --no-manifest`: optimize filelogs only
4071 * `--filelogs`: optimize the filelogs only
4071 * `--filelogs`: optimize the filelogs only
4072 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4072 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4073 """
4073 """
4074 return upgrade.upgraderepo(
4074 return upgrade.upgraderepo(
4075 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4075 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4076 )
4076 )
4077
4077
4078
4078
4079 @command(
4079 @command(
4080 b'debug::unbundle',
4081 [
4082 (
4083 b'u',
4084 b'update',
4085 None,
4086 _(b'update to new branch head if changesets were unbundled'),
4087 )
4088 ],
4089 _(b'[-u] FILE...'),
4090 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4091 )
4092 def debugunbundle(ui, repo, *args, **kwargs):
4093 """same as `hg unbundle`, but pretent to come from a push
4094
4095 This is useful to debug behavior and performance change in this case.
4096 """
4097 from . import commands # avoid cycle
4098
4099 unbundle = cmdutil.findcmd(b'unbundle', commands.table)[1][0]
4100 return unbundle(ui, repo, *args, _unbundle_source=b'push', **kwargs)
4101
4102
4103 @command(
4080 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4104 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4081 )
4105 )
4082 def debugwalk(ui, repo, *pats, **opts):
4106 def debugwalk(ui, repo, *pats, **opts):
4083 """show how files match on given patterns"""
4107 """show how files match on given patterns"""
4084 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
4108 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
4085 if ui.verbose:
4109 if ui.verbose:
4086 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4110 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4087 items = list(repo[None].walk(m))
4111 items = list(repo[None].walk(m))
4088 if not items:
4112 if not items:
4089 return
4113 return
4090 f = lambda fn: fn
4114 f = lambda fn: fn
4091 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4115 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4092 f = lambda fn: util.normpath(fn)
4116 f = lambda fn: util.normpath(fn)
4093 fmt = b'f %%-%ds %%-%ds %%s' % (
4117 fmt = b'f %%-%ds %%-%ds %%s' % (
4094 max([len(abs) for abs in items]),
4118 max([len(abs) for abs in items]),
4095 max([len(repo.pathto(abs)) for abs in items]),
4119 max([len(repo.pathto(abs)) for abs in items]),
4096 )
4120 )
4097 for abs in items:
4121 for abs in items:
4098 line = fmt % (
4122 line = fmt % (
4099 abs,
4123 abs,
4100 f(repo.pathto(abs)),
4124 f(repo.pathto(abs)),
4101 m.exact(abs) and b'exact' or b'',
4125 m.exact(abs) and b'exact' or b'',
4102 )
4126 )
4103 ui.write(b"%s\n" % line.rstrip())
4127 ui.write(b"%s\n" % line.rstrip())
4104
4128
4105
4129
4106 @command(b'debugwhyunstable', [], _(b'REV'))
4130 @command(b'debugwhyunstable', [], _(b'REV'))
4107 def debugwhyunstable(ui, repo, rev):
4131 def debugwhyunstable(ui, repo, rev):
4108 """explain instabilities of a changeset"""
4132 """explain instabilities of a changeset"""
4109 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4133 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4110 dnodes = b''
4134 dnodes = b''
4111 if entry.get(b'divergentnodes'):
4135 if entry.get(b'divergentnodes'):
4112 dnodes = (
4136 dnodes = (
4113 b' '.join(
4137 b' '.join(
4114 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4138 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4115 for ctx in entry[b'divergentnodes']
4139 for ctx in entry[b'divergentnodes']
4116 )
4140 )
4117 + b' '
4141 + b' '
4118 )
4142 )
4119 ui.write(
4143 ui.write(
4120 b'%s: %s%s %s\n'
4144 b'%s: %s%s %s\n'
4121 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4145 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4122 )
4146 )
4123
4147
4124
4148
4125 @command(
4149 @command(
4126 b'debugwireargs',
4150 b'debugwireargs',
4127 [
4151 [
4128 (b'', b'three', b'', b'three'),
4152 (b'', b'three', b'', b'three'),
4129 (b'', b'four', b'', b'four'),
4153 (b'', b'four', b'', b'four'),
4130 (b'', b'five', b'', b'five'),
4154 (b'', b'five', b'', b'five'),
4131 ]
4155 ]
4132 + cmdutil.remoteopts,
4156 + cmdutil.remoteopts,
4133 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4157 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4134 norepo=True,
4158 norepo=True,
4135 )
4159 )
4136 def debugwireargs(ui, repopath, *vals, **opts):
4160 def debugwireargs(ui, repopath, *vals, **opts):
4137 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
4161 repo = hg.peer(ui, pycompat.byteskwargs(opts), repopath)
4138 try:
4162 try:
4139 for opt in cmdutil.remoteopts:
4163 for opt in cmdutil.remoteopts:
4140 del opts[pycompat.sysstr(opt[1])]
4164 del opts[pycompat.sysstr(opt[1])]
4141 args = {}
4165 args = {}
4142 for k, v in opts.items():
4166 for k, v in opts.items():
4143 if v:
4167 if v:
4144 args[k] = v
4168 args[k] = v
4145
4169
4146 # run twice to check that we don't mess up the stream for the next command
4170 # run twice to check that we don't mess up the stream for the next command
4147 res1 = repo.debugwireargs(*vals, **args)
4171 res1 = repo.debugwireargs(*vals, **args)
4148 res2 = repo.debugwireargs(*vals, **args)
4172 res2 = repo.debugwireargs(*vals, **args)
4149 ui.write(b"%s\n" % res1)
4173 ui.write(b"%s\n" % res1)
4150 if res1 != res2:
4174 if res1 != res2:
4151 ui.warn(b"%s\n" % res2)
4175 ui.warn(b"%s\n" % res2)
4152 finally:
4176 finally:
4153 repo.close()
4177 repo.close()
4154
4178
4155
4179
4156 def _parsewirelangblocks(fh):
4180 def _parsewirelangblocks(fh):
4157 activeaction = None
4181 activeaction = None
4158 blocklines = []
4182 blocklines = []
4159 lastindent = 0
4183 lastindent = 0
4160
4184
4161 for line in fh:
4185 for line in fh:
4162 line = line.rstrip()
4186 line = line.rstrip()
4163 if not line:
4187 if not line:
4164 continue
4188 continue
4165
4189
4166 if line.startswith(b'#'):
4190 if line.startswith(b'#'):
4167 continue
4191 continue
4168
4192
4169 if not line.startswith(b' '):
4193 if not line.startswith(b' '):
4170 # New block. Flush previous one.
4194 # New block. Flush previous one.
4171 if activeaction:
4195 if activeaction:
4172 yield activeaction, blocklines
4196 yield activeaction, blocklines
4173
4197
4174 activeaction = line
4198 activeaction = line
4175 blocklines = []
4199 blocklines = []
4176 lastindent = 0
4200 lastindent = 0
4177 continue
4201 continue
4178
4202
4179 # Else we start with an indent.
4203 # Else we start with an indent.
4180
4204
4181 if not activeaction:
4205 if not activeaction:
4182 raise error.Abort(_(b'indented line outside of block'))
4206 raise error.Abort(_(b'indented line outside of block'))
4183
4207
4184 indent = len(line) - len(line.lstrip())
4208 indent = len(line) - len(line.lstrip())
4185
4209
4186 # If this line is indented more than the last line, concatenate it.
4210 # If this line is indented more than the last line, concatenate it.
4187 if indent > lastindent and blocklines:
4211 if indent > lastindent and blocklines:
4188 blocklines[-1] += line.lstrip()
4212 blocklines[-1] += line.lstrip()
4189 else:
4213 else:
4190 blocklines.append(line)
4214 blocklines.append(line)
4191 lastindent = indent
4215 lastindent = indent
4192
4216
4193 # Flush last block.
4217 # Flush last block.
4194 if activeaction:
4218 if activeaction:
4195 yield activeaction, blocklines
4219 yield activeaction, blocklines
4196
4220
4197
4221
4198 @command(
4222 @command(
4199 b'debugwireproto',
4223 b'debugwireproto',
4200 [
4224 [
4201 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4225 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4202 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4226 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4203 (
4227 (
4204 b'',
4228 b'',
4205 b'noreadstderr',
4229 b'noreadstderr',
4206 False,
4230 False,
4207 _(b'do not read from stderr of the remote'),
4231 _(b'do not read from stderr of the remote'),
4208 ),
4232 ),
4209 (
4233 (
4210 b'',
4234 b'',
4211 b'nologhandshake',
4235 b'nologhandshake',
4212 False,
4236 False,
4213 _(b'do not log I/O related to the peer handshake'),
4237 _(b'do not log I/O related to the peer handshake'),
4214 ),
4238 ),
4215 ]
4239 ]
4216 + cmdutil.remoteopts,
4240 + cmdutil.remoteopts,
4217 _(b'[PATH]'),
4241 _(b'[PATH]'),
4218 optionalrepo=True,
4242 optionalrepo=True,
4219 )
4243 )
4220 def debugwireproto(ui, repo, path=None, **opts):
4244 def debugwireproto(ui, repo, path=None, **opts):
4221 """send wire protocol commands to a server
4245 """send wire protocol commands to a server
4222
4246
4223 This command can be used to issue wire protocol commands to remote
4247 This command can be used to issue wire protocol commands to remote
4224 peers and to debug the raw data being exchanged.
4248 peers and to debug the raw data being exchanged.
4225
4249
4226 ``--localssh`` will start an SSH server against the current repository
4250 ``--localssh`` will start an SSH server against the current repository
4227 and connect to that. By default, the connection will perform a handshake
4251 and connect to that. By default, the connection will perform a handshake
4228 and establish an appropriate peer instance.
4252 and establish an appropriate peer instance.
4229
4253
4230 ``--peer`` can be used to bypass the handshake protocol and construct a
4254 ``--peer`` can be used to bypass the handshake protocol and construct a
4231 peer instance using the specified class type. Valid values are ``raw``,
4255 peer instance using the specified class type. Valid values are ``raw``,
4232 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4256 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4233 don't support higher-level command actions.
4257 don't support higher-level command actions.
4234
4258
4235 ``--noreadstderr`` can be used to disable automatic reading from stderr
4259 ``--noreadstderr`` can be used to disable automatic reading from stderr
4236 of the peer (for SSH connections only). Disabling automatic reading of
4260 of the peer (for SSH connections only). Disabling automatic reading of
4237 stderr is useful for making output more deterministic.
4261 stderr is useful for making output more deterministic.
4238
4262
4239 Commands are issued via a mini language which is specified via stdin.
4263 Commands are issued via a mini language which is specified via stdin.
4240 The language consists of individual actions to perform. An action is
4264 The language consists of individual actions to perform. An action is
4241 defined by a block. A block is defined as a line with no leading
4265 defined by a block. A block is defined as a line with no leading
4242 space followed by 0 or more lines with leading space. Blocks are
4266 space followed by 0 or more lines with leading space. Blocks are
4243 effectively a high-level command with additional metadata.
4267 effectively a high-level command with additional metadata.
4244
4268
4245 Lines beginning with ``#`` are ignored.
4269 Lines beginning with ``#`` are ignored.
4246
4270
4247 The following sections denote available actions.
4271 The following sections denote available actions.
4248
4272
4249 raw
4273 raw
4250 ---
4274 ---
4251
4275
4252 Send raw data to the server.
4276 Send raw data to the server.
4253
4277
4254 The block payload contains the raw data to send as one atomic send
4278 The block payload contains the raw data to send as one atomic send
4255 operation. The data may not actually be delivered in a single system
4279 operation. The data may not actually be delivered in a single system
4256 call: it depends on the abilities of the transport being used.
4280 call: it depends on the abilities of the transport being used.
4257
4281
4258 Each line in the block is de-indented and concatenated. Then, that
4282 Each line in the block is de-indented and concatenated. Then, that
4259 value is evaluated as a Python b'' literal. This allows the use of
4283 value is evaluated as a Python b'' literal. This allows the use of
4260 backslash escaping, etc.
4284 backslash escaping, etc.
4261
4285
4262 raw+
4286 raw+
4263 ----
4287 ----
4264
4288
4265 Behaves like ``raw`` except flushes output afterwards.
4289 Behaves like ``raw`` except flushes output afterwards.
4266
4290
4267 command <X>
4291 command <X>
4268 -----------
4292 -----------
4269
4293
4270 Send a request to run a named command, whose name follows the ``command``
4294 Send a request to run a named command, whose name follows the ``command``
4271 string.
4295 string.
4272
4296
4273 Arguments to the command are defined as lines in this block. The format of
4297 Arguments to the command are defined as lines in this block. The format of
4274 each line is ``<key> <value>``. e.g.::
4298 each line is ``<key> <value>``. e.g.::
4275
4299
4276 command listkeys
4300 command listkeys
4277 namespace bookmarks
4301 namespace bookmarks
4278
4302
4279 If the value begins with ``eval:``, it will be interpreted as a Python
4303 If the value begins with ``eval:``, it will be interpreted as a Python
4280 literal expression. Otherwise values are interpreted as Python b'' literals.
4304 literal expression. Otherwise values are interpreted as Python b'' literals.
4281 This allows sending complex types and encoding special byte sequences via
4305 This allows sending complex types and encoding special byte sequences via
4282 backslash escaping.
4306 backslash escaping.
4283
4307
4284 The following arguments have special meaning:
4308 The following arguments have special meaning:
4285
4309
4286 ``PUSHFILE``
4310 ``PUSHFILE``
4287 When defined, the *push* mechanism of the peer will be used instead
4311 When defined, the *push* mechanism of the peer will be used instead
4288 of the static request-response mechanism and the content of the
4312 of the static request-response mechanism and the content of the
4289 file specified in the value of this argument will be sent as the
4313 file specified in the value of this argument will be sent as the
4290 command payload.
4314 command payload.
4291
4315
4292 This can be used to submit a local bundle file to the remote.
4316 This can be used to submit a local bundle file to the remote.
4293
4317
4294 batchbegin
4318 batchbegin
4295 ----------
4319 ----------
4296
4320
4297 Instruct the peer to begin a batched send.
4321 Instruct the peer to begin a batched send.
4298
4322
4299 All ``command`` blocks are queued for execution until the next
4323 All ``command`` blocks are queued for execution until the next
4300 ``batchsubmit`` block.
4324 ``batchsubmit`` block.
4301
4325
4302 batchsubmit
4326 batchsubmit
4303 -----------
4327 -----------
4304
4328
4305 Submit previously queued ``command`` blocks as a batch request.
4329 Submit previously queued ``command`` blocks as a batch request.
4306
4330
4307 This action MUST be paired with a ``batchbegin`` action.
4331 This action MUST be paired with a ``batchbegin`` action.
4308
4332
4309 httprequest <method> <path>
4333 httprequest <method> <path>
4310 ---------------------------
4334 ---------------------------
4311
4335
4312 (HTTP peer only)
4336 (HTTP peer only)
4313
4337
4314 Send an HTTP request to the peer.
4338 Send an HTTP request to the peer.
4315
4339
4316 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4340 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4317
4341
4318 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4342 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4319 headers to add to the request. e.g. ``Accept: foo``.
4343 headers to add to the request. e.g. ``Accept: foo``.
4320
4344
4321 The following arguments are special:
4345 The following arguments are special:
4322
4346
4323 ``BODYFILE``
4347 ``BODYFILE``
4324 The content of the file defined as the value to this argument will be
4348 The content of the file defined as the value to this argument will be
4325 transferred verbatim as the HTTP request body.
4349 transferred verbatim as the HTTP request body.
4326
4350
4327 ``frame <type> <flags> <payload>``
4351 ``frame <type> <flags> <payload>``
4328 Send a unified protocol frame as part of the request body.
4352 Send a unified protocol frame as part of the request body.
4329
4353
4330 All frames will be collected and sent as the body to the HTTP
4354 All frames will be collected and sent as the body to the HTTP
4331 request.
4355 request.
4332
4356
4333 close
4357 close
4334 -----
4358 -----
4335
4359
4336 Close the connection to the server.
4360 Close the connection to the server.
4337
4361
4338 flush
4362 flush
4339 -----
4363 -----
4340
4364
4341 Flush data written to the server.
4365 Flush data written to the server.
4342
4366
4343 readavailable
4367 readavailable
4344 -------------
4368 -------------
4345
4369
4346 Close the write end of the connection and read all available data from
4370 Close the write end of the connection and read all available data from
4347 the server.
4371 the server.
4348
4372
4349 If the connection to the server encompasses multiple pipes, we poll both
4373 If the connection to the server encompasses multiple pipes, we poll both
4350 pipes and read available data.
4374 pipes and read available data.
4351
4375
4352 readline
4376 readline
4353 --------
4377 --------
4354
4378
4355 Read a line of output from the server. If there are multiple output
4379 Read a line of output from the server. If there are multiple output
4356 pipes, reads only the main pipe.
4380 pipes, reads only the main pipe.
4357
4381
4358 ereadline
4382 ereadline
4359 ---------
4383 ---------
4360
4384
4361 Like ``readline``, but read from the stderr pipe, if available.
4385 Like ``readline``, but read from the stderr pipe, if available.
4362
4386
4363 read <X>
4387 read <X>
4364 --------
4388 --------
4365
4389
4366 ``read()`` N bytes from the server's main output pipe.
4390 ``read()`` N bytes from the server's main output pipe.
4367
4391
4368 eread <X>
4392 eread <X>
4369 ---------
4393 ---------
4370
4394
4371 ``read()`` N bytes from the server's stderr pipe, if available.
4395 ``read()`` N bytes from the server's stderr pipe, if available.
4372
4396
4373 Specifying Unified Frame-Based Protocol Frames
4397 Specifying Unified Frame-Based Protocol Frames
4374 ----------------------------------------------
4398 ----------------------------------------------
4375
4399
4376 It is possible to emit a *Unified Frame-Based Protocol* by using special
4400 It is possible to emit a *Unified Frame-Based Protocol* by using special
4377 syntax.
4401 syntax.
4378
4402
4379 A frame is composed as a type, flags, and payload. These can be parsed
4403 A frame is composed as a type, flags, and payload. These can be parsed
4380 from a string of the form:
4404 from a string of the form:
4381
4405
4382 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4406 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4383
4407
4384 ``request-id`` and ``stream-id`` are integers defining the request and
4408 ``request-id`` and ``stream-id`` are integers defining the request and
4385 stream identifiers.
4409 stream identifiers.
4386
4410
4387 ``type`` can be an integer value for the frame type or the string name
4411 ``type`` can be an integer value for the frame type or the string name
4388 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4412 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4389 ``command-name``.
4413 ``command-name``.
4390
4414
4391 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4415 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4392 components. Each component (and there can be just one) can be an integer
4416 components. Each component (and there can be just one) can be an integer
4393 or a flag name for stream flags or frame flags, respectively. Values are
4417 or a flag name for stream flags or frame flags, respectively. Values are
4394 resolved to integers and then bitwise OR'd together.
4418 resolved to integers and then bitwise OR'd together.
4395
4419
4396 ``payload`` represents the raw frame payload. If it begins with
4420 ``payload`` represents the raw frame payload. If it begins with
4397 ``cbor:``, the following string is evaluated as Python code and the
4421 ``cbor:``, the following string is evaluated as Python code and the
4398 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4422 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4399 as a Python byte string literal.
4423 as a Python byte string literal.
4400 """
4424 """
4401 if opts['localssh'] and not repo:
4425 if opts['localssh'] and not repo:
4402 raise error.Abort(_(b'--localssh requires a repository'))
4426 raise error.Abort(_(b'--localssh requires a repository'))
4403
4427
4404 if opts['peer'] and opts['peer'] not in (
4428 if opts['peer'] and opts['peer'] not in (
4405 b'raw',
4429 b'raw',
4406 b'ssh1',
4430 b'ssh1',
4407 ):
4431 ):
4408 raise error.Abort(
4432 raise error.Abort(
4409 _(b'invalid value for --peer'),
4433 _(b'invalid value for --peer'),
4410 hint=_(b'valid values are "raw" and "ssh1"'),
4434 hint=_(b'valid values are "raw" and "ssh1"'),
4411 )
4435 )
4412
4436
4413 if path and opts['localssh']:
4437 if path and opts['localssh']:
4414 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4438 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4415
4439
4416 if ui.interactive():
4440 if ui.interactive():
4417 ui.write(_(b'(waiting for commands on stdin)\n'))
4441 ui.write(_(b'(waiting for commands on stdin)\n'))
4418
4442
4419 blocks = list(_parsewirelangblocks(ui.fin))
4443 blocks = list(_parsewirelangblocks(ui.fin))
4420
4444
4421 proc = None
4445 proc = None
4422 stdin = None
4446 stdin = None
4423 stdout = None
4447 stdout = None
4424 stderr = None
4448 stderr = None
4425 opener = None
4449 opener = None
4426
4450
4427 if opts['localssh']:
4451 if opts['localssh']:
4428 # We start the SSH server in its own process so there is process
4452 # We start the SSH server in its own process so there is process
4429 # separation. This prevents a whole class of potential bugs around
4453 # separation. This prevents a whole class of potential bugs around
4430 # shared state from interfering with server operation.
4454 # shared state from interfering with server operation.
4431 args = procutil.hgcmd() + [
4455 args = procutil.hgcmd() + [
4432 b'-R',
4456 b'-R',
4433 repo.root,
4457 repo.root,
4434 b'debugserve',
4458 b'debugserve',
4435 b'--sshstdio',
4459 b'--sshstdio',
4436 ]
4460 ]
4437 proc = subprocess.Popen(
4461 proc = subprocess.Popen(
4438 pycompat.rapply(procutil.tonativestr, args),
4462 pycompat.rapply(procutil.tonativestr, args),
4439 stdin=subprocess.PIPE,
4463 stdin=subprocess.PIPE,
4440 stdout=subprocess.PIPE,
4464 stdout=subprocess.PIPE,
4441 stderr=subprocess.PIPE,
4465 stderr=subprocess.PIPE,
4442 bufsize=0,
4466 bufsize=0,
4443 )
4467 )
4444
4468
4445 stdin = proc.stdin
4469 stdin = proc.stdin
4446 stdout = proc.stdout
4470 stdout = proc.stdout
4447 stderr = proc.stderr
4471 stderr = proc.stderr
4448
4472
4449 # We turn the pipes into observers so we can log I/O.
4473 # We turn the pipes into observers so we can log I/O.
4450 if ui.verbose or opts['peer'] == b'raw':
4474 if ui.verbose or opts['peer'] == b'raw':
4451 stdin = util.makeloggingfileobject(
4475 stdin = util.makeloggingfileobject(
4452 ui, proc.stdin, b'i', logdata=True
4476 ui, proc.stdin, b'i', logdata=True
4453 )
4477 )
4454 stdout = util.makeloggingfileobject(
4478 stdout = util.makeloggingfileobject(
4455 ui, proc.stdout, b'o', logdata=True
4479 ui, proc.stdout, b'o', logdata=True
4456 )
4480 )
4457 stderr = util.makeloggingfileobject(
4481 stderr = util.makeloggingfileobject(
4458 ui, proc.stderr, b'e', logdata=True
4482 ui, proc.stderr, b'e', logdata=True
4459 )
4483 )
4460
4484
4461 # --localssh also implies the peer connection settings.
4485 # --localssh also implies the peer connection settings.
4462
4486
4463 url = b'ssh://localserver'
4487 url = b'ssh://localserver'
4464 autoreadstderr = not opts['noreadstderr']
4488 autoreadstderr = not opts['noreadstderr']
4465
4489
4466 if opts['peer'] == b'ssh1':
4490 if opts['peer'] == b'ssh1':
4467 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4491 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4468 peer = sshpeer.sshv1peer(
4492 peer = sshpeer.sshv1peer(
4469 ui,
4493 ui,
4470 url,
4494 url,
4471 proc,
4495 proc,
4472 stdin,
4496 stdin,
4473 stdout,
4497 stdout,
4474 stderr,
4498 stderr,
4475 None,
4499 None,
4476 autoreadstderr=autoreadstderr,
4500 autoreadstderr=autoreadstderr,
4477 )
4501 )
4478 elif opts['peer'] == b'raw':
4502 elif opts['peer'] == b'raw':
4479 ui.write(_(b'using raw connection to peer\n'))
4503 ui.write(_(b'using raw connection to peer\n'))
4480 peer = None
4504 peer = None
4481 else:
4505 else:
4482 ui.write(_(b'creating ssh peer from handshake results\n'))
4506 ui.write(_(b'creating ssh peer from handshake results\n'))
4483 peer = sshpeer._make_peer(
4507 peer = sshpeer._make_peer(
4484 ui,
4508 ui,
4485 url,
4509 url,
4486 proc,
4510 proc,
4487 stdin,
4511 stdin,
4488 stdout,
4512 stdout,
4489 stderr,
4513 stderr,
4490 autoreadstderr=autoreadstderr,
4514 autoreadstderr=autoreadstderr,
4491 )
4515 )
4492
4516
4493 elif path:
4517 elif path:
4494 # We bypass hg.peer() so we can proxy the sockets.
4518 # We bypass hg.peer() so we can proxy the sockets.
4495 # TODO consider not doing this because we skip
4519 # TODO consider not doing this because we skip
4496 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4520 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4497 u = urlutil.url(path)
4521 u = urlutil.url(path)
4498 if u.scheme != b'http':
4522 if u.scheme != b'http':
4499 raise error.Abort(_(b'only http:// paths are currently supported'))
4523 raise error.Abort(_(b'only http:// paths are currently supported'))
4500
4524
4501 url, authinfo = u.authinfo()
4525 url, authinfo = u.authinfo()
4502 openerargs = {
4526 openerargs = {
4503 'useragent': b'Mercurial debugwireproto',
4527 'useragent': b'Mercurial debugwireproto',
4504 }
4528 }
4505
4529
4506 # Turn pipes/sockets into observers so we can log I/O.
4530 # Turn pipes/sockets into observers so we can log I/O.
4507 if ui.verbose:
4531 if ui.verbose:
4508 openerargs.update(
4532 openerargs.update(
4509 {
4533 {
4510 'loggingfh': ui,
4534 'loggingfh': ui,
4511 'loggingname': b's',
4535 'loggingname': b's',
4512 'loggingopts': {
4536 'loggingopts': {
4513 'logdata': True,
4537 'logdata': True,
4514 'logdataapis': False,
4538 'logdataapis': False,
4515 },
4539 },
4516 }
4540 }
4517 )
4541 )
4518
4542
4519 if ui.debugflag:
4543 if ui.debugflag:
4520 openerargs['loggingopts']['logdataapis'] = True
4544 openerargs['loggingopts']['logdataapis'] = True
4521
4545
4522 # Don't send default headers when in raw mode. This allows us to
4546 # Don't send default headers when in raw mode. This allows us to
4523 # bypass most of the behavior of our URL handling code so we can
4547 # bypass most of the behavior of our URL handling code so we can
4524 # have near complete control over what's sent on the wire.
4548 # have near complete control over what's sent on the wire.
4525 if opts['peer'] == b'raw':
4549 if opts['peer'] == b'raw':
4526 openerargs['sendaccept'] = False
4550 openerargs['sendaccept'] = False
4527
4551
4528 opener = urlmod.opener(ui, authinfo, **openerargs)
4552 opener = urlmod.opener(ui, authinfo, **openerargs)
4529
4553
4530 if opts['peer'] == b'raw':
4554 if opts['peer'] == b'raw':
4531 ui.write(_(b'using raw connection to peer\n'))
4555 ui.write(_(b'using raw connection to peer\n'))
4532 peer = None
4556 peer = None
4533 elif opts['peer']:
4557 elif opts['peer']:
4534 raise error.Abort(
4558 raise error.Abort(
4535 _(b'--peer %s not supported with HTTP peers') % opts['peer']
4559 _(b'--peer %s not supported with HTTP peers') % opts['peer']
4536 )
4560 )
4537 else:
4561 else:
4538 peer_path = urlutil.try_path(ui, path)
4562 peer_path = urlutil.try_path(ui, path)
4539 peer = httppeer._make_peer(ui, peer_path, opener=opener)
4563 peer = httppeer._make_peer(ui, peer_path, opener=opener)
4540
4564
4541 # We /could/ populate stdin/stdout with sock.makefile()...
4565 # We /could/ populate stdin/stdout with sock.makefile()...
4542 else:
4566 else:
4543 raise error.Abort(_(b'unsupported connection configuration'))
4567 raise error.Abort(_(b'unsupported connection configuration'))
4544
4568
4545 batchedcommands = None
4569 batchedcommands = None
4546
4570
4547 # Now perform actions based on the parsed wire language instructions.
4571 # Now perform actions based on the parsed wire language instructions.
4548 for action, lines in blocks:
4572 for action, lines in blocks:
4549 if action in (b'raw', b'raw+'):
4573 if action in (b'raw', b'raw+'):
4550 if not stdin:
4574 if not stdin:
4551 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4575 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4552
4576
4553 # Concatenate the data together.
4577 # Concatenate the data together.
4554 data = b''.join(l.lstrip() for l in lines)
4578 data = b''.join(l.lstrip() for l in lines)
4555 data = stringutil.unescapestr(data)
4579 data = stringutil.unescapestr(data)
4556 stdin.write(data)
4580 stdin.write(data)
4557
4581
4558 if action == b'raw+':
4582 if action == b'raw+':
4559 stdin.flush()
4583 stdin.flush()
4560 elif action == b'flush':
4584 elif action == b'flush':
4561 if not stdin:
4585 if not stdin:
4562 raise error.Abort(_(b'cannot call flush on this peer'))
4586 raise error.Abort(_(b'cannot call flush on this peer'))
4563 stdin.flush()
4587 stdin.flush()
4564 elif action.startswith(b'command'):
4588 elif action.startswith(b'command'):
4565 if not peer:
4589 if not peer:
4566 raise error.Abort(
4590 raise error.Abort(
4567 _(
4591 _(
4568 b'cannot send commands unless peer instance '
4592 b'cannot send commands unless peer instance '
4569 b'is available'
4593 b'is available'
4570 )
4594 )
4571 )
4595 )
4572
4596
4573 command = action.split(b' ', 1)[1]
4597 command = action.split(b' ', 1)[1]
4574
4598
4575 args = {}
4599 args = {}
4576 for line in lines:
4600 for line in lines:
4577 # We need to allow empty values.
4601 # We need to allow empty values.
4578 fields = line.lstrip().split(b' ', 1)
4602 fields = line.lstrip().split(b' ', 1)
4579 if len(fields) == 1:
4603 if len(fields) == 1:
4580 key = fields[0]
4604 key = fields[0]
4581 value = b''
4605 value = b''
4582 else:
4606 else:
4583 key, value = fields
4607 key, value = fields
4584
4608
4585 if value.startswith(b'eval:'):
4609 if value.startswith(b'eval:'):
4586 value = stringutil.evalpythonliteral(value[5:])
4610 value = stringutil.evalpythonliteral(value[5:])
4587 else:
4611 else:
4588 value = stringutil.unescapestr(value)
4612 value = stringutil.unescapestr(value)
4589
4613
4590 args[key] = value
4614 args[key] = value
4591
4615
4592 if batchedcommands is not None:
4616 if batchedcommands is not None:
4593 batchedcommands.append((command, args))
4617 batchedcommands.append((command, args))
4594 continue
4618 continue
4595
4619
4596 ui.status(_(b'sending %s command\n') % command)
4620 ui.status(_(b'sending %s command\n') % command)
4597
4621
4598 if b'PUSHFILE' in args:
4622 if b'PUSHFILE' in args:
4599 with open(args[b'PUSHFILE'], 'rb') as fh:
4623 with open(args[b'PUSHFILE'], 'rb') as fh:
4600 del args[b'PUSHFILE']
4624 del args[b'PUSHFILE']
4601 res, output = peer._callpush(
4625 res, output = peer._callpush(
4602 command, fh, **pycompat.strkwargs(args)
4626 command, fh, **pycompat.strkwargs(args)
4603 )
4627 )
4604 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4628 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4605 ui.status(
4629 ui.status(
4606 _(b'remote output: %s\n') % stringutil.escapestr(output)
4630 _(b'remote output: %s\n') % stringutil.escapestr(output)
4607 )
4631 )
4608 else:
4632 else:
4609 with peer.commandexecutor() as e:
4633 with peer.commandexecutor() as e:
4610 res = e.callcommand(command, args).result()
4634 res = e.callcommand(command, args).result()
4611
4635
4612 ui.status(
4636 ui.status(
4613 _(b'response: %s\n')
4637 _(b'response: %s\n')
4614 % stringutil.pprint(res, bprefix=True, indent=2)
4638 % stringutil.pprint(res, bprefix=True, indent=2)
4615 )
4639 )
4616
4640
4617 elif action == b'batchbegin':
4641 elif action == b'batchbegin':
4618 if batchedcommands is not None:
4642 if batchedcommands is not None:
4619 raise error.Abort(_(b'nested batchbegin not allowed'))
4643 raise error.Abort(_(b'nested batchbegin not allowed'))
4620
4644
4621 batchedcommands = []
4645 batchedcommands = []
4622 elif action == b'batchsubmit':
4646 elif action == b'batchsubmit':
4623 # There is a batching API we could go through. But it would be
4647 # There is a batching API we could go through. But it would be
4624 # difficult to normalize requests into function calls. It is easier
4648 # difficult to normalize requests into function calls. It is easier
4625 # to bypass this layer and normalize to commands + args.
4649 # to bypass this layer and normalize to commands + args.
4626 ui.status(
4650 ui.status(
4627 _(b'sending batch with %d sub-commands\n')
4651 _(b'sending batch with %d sub-commands\n')
4628 % len(batchedcommands)
4652 % len(batchedcommands)
4629 )
4653 )
4630 assert peer is not None
4654 assert peer is not None
4631 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4655 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4632 ui.status(
4656 ui.status(
4633 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4657 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4634 )
4658 )
4635
4659
4636 batchedcommands = None
4660 batchedcommands = None
4637
4661
4638 elif action.startswith(b'httprequest '):
4662 elif action.startswith(b'httprequest '):
4639 if not opener:
4663 if not opener:
4640 raise error.Abort(
4664 raise error.Abort(
4641 _(b'cannot use httprequest without an HTTP peer')
4665 _(b'cannot use httprequest without an HTTP peer')
4642 )
4666 )
4643
4667
4644 request = action.split(b' ', 2)
4668 request = action.split(b' ', 2)
4645 if len(request) != 3:
4669 if len(request) != 3:
4646 raise error.Abort(
4670 raise error.Abort(
4647 _(
4671 _(
4648 b'invalid httprequest: expected format is '
4672 b'invalid httprequest: expected format is '
4649 b'"httprequest <method> <path>'
4673 b'"httprequest <method> <path>'
4650 )
4674 )
4651 )
4675 )
4652
4676
4653 method, httppath = request[1:]
4677 method, httppath = request[1:]
4654 headers = {}
4678 headers = {}
4655 body = None
4679 body = None
4656 frames = []
4680 frames = []
4657 for line in lines:
4681 for line in lines:
4658 line = line.lstrip()
4682 line = line.lstrip()
4659 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4683 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4660 if m:
4684 if m:
4661 # Headers need to use native strings.
4685 # Headers need to use native strings.
4662 key = pycompat.strurl(m.group(1))
4686 key = pycompat.strurl(m.group(1))
4663 value = pycompat.strurl(m.group(2))
4687 value = pycompat.strurl(m.group(2))
4664 headers[key] = value
4688 headers[key] = value
4665 continue
4689 continue
4666
4690
4667 if line.startswith(b'BODYFILE '):
4691 if line.startswith(b'BODYFILE '):
4668 with open(line.split(b' ', 1), b'rb') as fh:
4692 with open(line.split(b' ', 1), b'rb') as fh:
4669 body = fh.read()
4693 body = fh.read()
4670 elif line.startswith(b'frame '):
4694 elif line.startswith(b'frame '):
4671 frame = wireprotoframing.makeframefromhumanstring(
4695 frame = wireprotoframing.makeframefromhumanstring(
4672 line[len(b'frame ') :]
4696 line[len(b'frame ') :]
4673 )
4697 )
4674
4698
4675 frames.append(frame)
4699 frames.append(frame)
4676 else:
4700 else:
4677 raise error.Abort(
4701 raise error.Abort(
4678 _(b'unknown argument to httprequest: %s') % line
4702 _(b'unknown argument to httprequest: %s') % line
4679 )
4703 )
4680
4704
4681 url = path + httppath
4705 url = path + httppath
4682
4706
4683 if frames:
4707 if frames:
4684 body = b''.join(bytes(f) for f in frames)
4708 body = b''.join(bytes(f) for f in frames)
4685
4709
4686 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4710 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4687
4711
4688 # urllib.Request insists on using has_data() as a proxy for
4712 # urllib.Request insists on using has_data() as a proxy for
4689 # determining the request method. Override that to use our
4713 # determining the request method. Override that to use our
4690 # explicitly requested method.
4714 # explicitly requested method.
4691 req.get_method = lambda: pycompat.sysstr(method)
4715 req.get_method = lambda: pycompat.sysstr(method)
4692
4716
4693 try:
4717 try:
4694 res = opener.open(req)
4718 res = opener.open(req)
4695 body = res.read()
4719 body = res.read()
4696 except util.urlerr.urlerror as e:
4720 except util.urlerr.urlerror as e:
4697 # read() method must be called, but only exists in Python 2
4721 # read() method must be called, but only exists in Python 2
4698 getattr(e, 'read', lambda: None)()
4722 getattr(e, 'read', lambda: None)()
4699 continue
4723 continue
4700
4724
4701 ct = res.headers.get('Content-Type')
4725 ct = res.headers.get('Content-Type')
4702 if ct == 'application/mercurial-cbor':
4726 if ct == 'application/mercurial-cbor':
4703 ui.write(
4727 ui.write(
4704 _(b'cbor> %s\n')
4728 _(b'cbor> %s\n')
4705 % stringutil.pprint(
4729 % stringutil.pprint(
4706 cborutil.decodeall(body), bprefix=True, indent=2
4730 cborutil.decodeall(body), bprefix=True, indent=2
4707 )
4731 )
4708 )
4732 )
4709
4733
4710 elif action == b'close':
4734 elif action == b'close':
4711 assert peer is not None
4735 assert peer is not None
4712 peer.close()
4736 peer.close()
4713 elif action == b'readavailable':
4737 elif action == b'readavailable':
4714 if not stdout or not stderr:
4738 if not stdout or not stderr:
4715 raise error.Abort(
4739 raise error.Abort(
4716 _(b'readavailable not available on this peer')
4740 _(b'readavailable not available on this peer')
4717 )
4741 )
4718
4742
4719 stdin.close()
4743 stdin.close()
4720 stdout.read()
4744 stdout.read()
4721 stderr.read()
4745 stderr.read()
4722
4746
4723 elif action == b'readline':
4747 elif action == b'readline':
4724 if not stdout:
4748 if not stdout:
4725 raise error.Abort(_(b'readline not available on this peer'))
4749 raise error.Abort(_(b'readline not available on this peer'))
4726 stdout.readline()
4750 stdout.readline()
4727 elif action == b'ereadline':
4751 elif action == b'ereadline':
4728 if not stderr:
4752 if not stderr:
4729 raise error.Abort(_(b'ereadline not available on this peer'))
4753 raise error.Abort(_(b'ereadline not available on this peer'))
4730 stderr.readline()
4754 stderr.readline()
4731 elif action.startswith(b'read '):
4755 elif action.startswith(b'read '):
4732 count = int(action.split(b' ', 1)[1])
4756 count = int(action.split(b' ', 1)[1])
4733 if not stdout:
4757 if not stdout:
4734 raise error.Abort(_(b'read not available on this peer'))
4758 raise error.Abort(_(b'read not available on this peer'))
4735 stdout.read(count)
4759 stdout.read(count)
4736 elif action.startswith(b'eread '):
4760 elif action.startswith(b'eread '):
4737 count = int(action.split(b' ', 1)[1])
4761 count = int(action.split(b' ', 1)[1])
4738 if not stderr:
4762 if not stderr:
4739 raise error.Abort(_(b'eread not available on this peer'))
4763 raise error.Abort(_(b'eread not available on this peer'))
4740 stderr.read(count)
4764 stderr.read(count)
4741 else:
4765 else:
4742 raise error.Abort(_(b'unknown action: %s') % action)
4766 raise error.Abort(_(b'unknown action: %s') % action)
4743
4767
4744 if batchedcommands is not None:
4768 if batchedcommands is not None:
4745 raise error.Abort(_(b'unclosed "batchbegin" request'))
4769 raise error.Abort(_(b'unclosed "batchbegin" request'))
4746
4770
4747 if peer:
4771 if peer:
4748 peer.close()
4772 peer.close()
4749
4773
4750 if proc:
4774 if proc:
4751 proc.kill()
4775 proc.kill()
@@ -1,458 +1,460 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 abort
3 abort
4 add
4 add
5 addremove
5 addremove
6 admin::verify
6 admin::verify
7 annotate
7 annotate
8 archive
8 archive
9 backout
9 backout
10 bisect
10 bisect
11 bookmarks
11 bookmarks
12 branch
12 branch
13 branches
13 branches
14 bundle
14 bundle
15 cat
15 cat
16 clone
16 clone
17 commit
17 commit
18 config
18 config
19 continue
19 continue
20 copy
20 copy
21 diff
21 diff
22 export
22 export
23 files
23 files
24 forget
24 forget
25 graft
25 graft
26 grep
26 grep
27 heads
27 heads
28 help
28 help
29 identify
29 identify
30 import
30 import
31 incoming
31 incoming
32 init
32 init
33 locate
33 locate
34 log
34 log
35 manifest
35 manifest
36 merge
36 merge
37 outgoing
37 outgoing
38 parents
38 parents
39 paths
39 paths
40 phase
40 phase
41 pull
41 pull
42 purge
42 purge
43 push
43 push
44 recover
44 recover
45 remove
45 remove
46 rename
46 rename
47 resolve
47 resolve
48 revert
48 revert
49 rollback
49 rollback
50 root
50 root
51 serve
51 serve
52 shelve
52 shelve
53 status
53 status
54 summary
54 summary
55 tag
55 tag
56 tags
56 tags
57 tip
57 tip
58 unbundle
58 unbundle
59 unshelve
59 unshelve
60 update
60 update
61 verify
61 verify
62 version
62 version
63
63
64 Show all commands that start with "a"
64 Show all commands that start with "a"
65 $ hg debugcomplete a
65 $ hg debugcomplete a
66 abort
66 abort
67 add
67 add
68 addremove
68 addremove
69 admin::verify
69 admin::verify
70 annotate
70 annotate
71 archive
71 archive
72
72
73 Do not show debug commands if there are other candidates
73 Do not show debug commands if there are other candidates
74 $ hg debugcomplete d
74 $ hg debugcomplete d
75 diff
75 diff
76
76
77 Show debug commands if there are no other candidates
77 Show debug commands if there are no other candidates
78 $ hg debugcomplete debug
78 $ hg debugcomplete debug
79 debug-delta-find
79 debug-delta-find
80 debug-repair-issue6528
80 debug-repair-issue6528
81 debug-revlog-index
81 debug-revlog-index
82 debug-revlog-stats
82 debug-revlog-stats
83 debug::stable-tail-sort
83 debug::stable-tail-sort
84 debug::stable-tail-sort-leaps
84 debug::stable-tail-sort-leaps
85 debug::unbundle
85 debugancestor
86 debugancestor
86 debugantivirusrunning
87 debugantivirusrunning
87 debugapplystreamclonebundle
88 debugapplystreamclonebundle
88 debugbackupbundle
89 debugbackupbundle
89 debugbuilddag
90 debugbuilddag
90 debugbundle
91 debugbundle
91 debugcapabilities
92 debugcapabilities
92 debugchangedfiles
93 debugchangedfiles
93 debugcheckstate
94 debugcheckstate
94 debugcolor
95 debugcolor
95 debugcommands
96 debugcommands
96 debugcomplete
97 debugcomplete
97 debugconfig
98 debugconfig
98 debugcreatestreamclonebundle
99 debugcreatestreamclonebundle
99 debugdag
100 debugdag
100 debugdata
101 debugdata
101 debugdate
102 debugdate
102 debugdeltachain
103 debugdeltachain
103 debugdirstate
104 debugdirstate
104 debugdirstateignorepatternshash
105 debugdirstateignorepatternshash
105 debugdiscovery
106 debugdiscovery
106 debugdownload
107 debugdownload
107 debugextensions
108 debugextensions
108 debugfileset
109 debugfileset
109 debugformat
110 debugformat
110 debugfsinfo
111 debugfsinfo
111 debuggetbundle
112 debuggetbundle
112 debugignore
113 debugignore
113 debugindexdot
114 debugindexdot
114 debugindexstats
115 debugindexstats
115 debuginstall
116 debuginstall
116 debugknown
117 debugknown
117 debuglabelcomplete
118 debuglabelcomplete
118 debuglocks
119 debuglocks
119 debugmanifestfulltextcache
120 debugmanifestfulltextcache
120 debugmergestate
121 debugmergestate
121 debugnamecomplete
122 debugnamecomplete
122 debugnodemap
123 debugnodemap
123 debugobsolete
124 debugobsolete
124 debugp1copies
125 debugp1copies
125 debugp2copies
126 debugp2copies
126 debugpathcomplete
127 debugpathcomplete
127 debugpathcopies
128 debugpathcopies
128 debugpeer
129 debugpeer
129 debugpickmergetool
130 debugpickmergetool
130 debugpushkey
131 debugpushkey
131 debugpvec
132 debugpvec
132 debugrebuilddirstate
133 debugrebuilddirstate
133 debugrebuildfncache
134 debugrebuildfncache
134 debugrename
135 debugrename
135 debugrequires
136 debugrequires
136 debugrevlog
137 debugrevlog
137 debugrevlogindex
138 debugrevlogindex
138 debugrevspec
139 debugrevspec
139 debugserve
140 debugserve
140 debugsetparents
141 debugsetparents
141 debugshell
142 debugshell
142 debugsidedata
143 debugsidedata
143 debugssl
144 debugssl
144 debugstrip
145 debugstrip
145 debugsub
146 debugsub
146 debugsuccessorssets
147 debugsuccessorssets
147 debugtagscache
148 debugtagscache
148 debugtemplate
149 debugtemplate
149 debuguigetpass
150 debuguigetpass
150 debuguiprompt
151 debuguiprompt
151 debugupdatecaches
152 debugupdatecaches
152 debugupgraderepo
153 debugupgraderepo
153 debugwalk
154 debugwalk
154 debugwhyunstable
155 debugwhyunstable
155 debugwireargs
156 debugwireargs
156 debugwireproto
157 debugwireproto
157
158
158 Do not show the alias of a debug command if there are other candidates
159 Do not show the alias of a debug command if there are other candidates
159 (this should hide rawcommit)
160 (this should hide rawcommit)
160 $ hg debugcomplete r
161 $ hg debugcomplete r
161 recover
162 recover
162 remove
163 remove
163 rename
164 rename
164 resolve
165 resolve
165 revert
166 revert
166 rollback
167 rollback
167 root
168 root
168 Show the alias of a debug command if there are no other candidates
169 Show the alias of a debug command if there are no other candidates
169 $ hg debugcomplete rawc
170 $ hg debugcomplete rawc
170
171
171
172
172 Show the global options
173 Show the global options
173 $ hg debugcomplete --options | sort
174 $ hg debugcomplete --options | sort
174 --color
175 --color
175 --config
176 --config
176 --cwd
177 --cwd
177 --debug
178 --debug
178 --debugger
179 --debugger
179 --encoding
180 --encoding
180 --encodingmode
181 --encodingmode
181 --help
182 --help
182 --hidden
183 --hidden
183 --noninteractive
184 --noninteractive
184 --pager
185 --pager
185 --profile
186 --profile
186 --quiet
187 --quiet
187 --repository
188 --repository
188 --time
189 --time
189 --traceback
190 --traceback
190 --verbose
191 --verbose
191 --version
192 --version
192 -R
193 -R
193 -h
194 -h
194 -q
195 -q
195 -v
196 -v
196 -y
197 -y
197
198
198 Show the options for the "serve" command
199 Show the options for the "serve" command
199 $ hg debugcomplete --options serve | sort
200 $ hg debugcomplete --options serve | sort
200 --accesslog
201 --accesslog
201 --address
202 --address
202 --certificate
203 --certificate
203 --cmdserver
204 --cmdserver
204 --color
205 --color
205 --config
206 --config
206 --cwd
207 --cwd
207 --daemon
208 --daemon
208 --daemon-postexec
209 --daemon-postexec
209 --debug
210 --debug
210 --debugger
211 --debugger
211 --encoding
212 --encoding
212 --encodingmode
213 --encodingmode
213 --errorlog
214 --errorlog
214 --help
215 --help
215 --hidden
216 --hidden
216 --ipv6
217 --ipv6
217 --name
218 --name
218 --noninteractive
219 --noninteractive
219 --pager
220 --pager
220 --pid-file
221 --pid-file
221 --port
222 --port
222 --prefix
223 --prefix
223 --print-url
224 --print-url
224 --profile
225 --profile
225 --quiet
226 --quiet
226 --repository
227 --repository
227 --stdio
228 --stdio
228 --style
229 --style
229 --subrepos
230 --subrepos
230 --templates
231 --templates
231 --time
232 --time
232 --traceback
233 --traceback
233 --verbose
234 --verbose
234 --version
235 --version
235 --web-conf
236 --web-conf
236 -6
237 -6
237 -A
238 -A
238 -E
239 -E
239 -R
240 -R
240 -S
241 -S
241 -a
242 -a
242 -d
243 -d
243 -h
244 -h
244 -n
245 -n
245 -p
246 -p
246 -q
247 -q
247 -t
248 -t
248 -v
249 -v
249 -y
250 -y
250
251
251 Show an error if we use --options with an ambiguous abbreviation
252 Show an error if we use --options with an ambiguous abbreviation
252 $ hg debugcomplete --options s
253 $ hg debugcomplete --options s
253 hg: command 's' is ambiguous:
254 hg: command 's' is ambiguous:
254 serve shelve showconfig status summary
255 serve shelve showconfig status summary
255 [10]
256 [10]
256
257
257 Show all commands + options
258 Show all commands + options
258 $ hg debugcommands
259 $ hg debugcommands
259 abort: dry-run
260 abort: dry-run
260 add: include, exclude, subrepos, dry-run
261 add: include, exclude, subrepos, dry-run
261 addremove: similarity, subrepos, include, exclude, dry-run
262 addremove: similarity, subrepos, include, exclude, dry-run
262 admin::verify: check, option
263 admin::verify: check, option
263 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, line-range, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
264 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, line-range, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
264 archive: no-decode, prefix, rev, type, subrepos, include, exclude
265 archive: no-decode, prefix, rev, type, subrepos, include, exclude
265 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
266 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
266 bisect: reset, good, bad, skip, extend, command, noupdate
267 bisect: reset, good, bad, skip, extend, command, noupdate
267 bookmarks: force, rev, delete, rename, inactive, list, template
268 bookmarks: force, rev, delete, rename, inactive, list, template
268 branch: force, clean, rev
269 branch: force, clean, rev
269 branches: active, closed, rev, template
270 branches: active, closed, rev, template
270 bundle: exact, force, rev, branch, base, all, type, ssh, remotecmd, insecure
271 bundle: exact, force, rev, branch, base, all, type, ssh, remotecmd, insecure
271 cat: output, rev, decode, include, exclude, template
272 cat: output, rev, decode, include, exclude, template
272 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
273 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
273 commit: addremove, close-branch, amend, secret, draft, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
274 commit: addremove, close-branch, amend, secret, draft, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
274 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
275 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
275 continue: dry-run
276 continue: dry-run
276 copy: forget, after, at-rev, force, include, exclude, dry-run
277 copy: forget, after, at-rev, force, include, exclude, dry-run
277 debug-delta-find: changelog, manifest, dir, template, source
278 debug-delta-find: changelog, manifest, dir, template, source
278 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
279 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
279 debug-revlog-index: changelog, manifest, dir, template
280 debug-revlog-index: changelog, manifest, dir, template
280 debug-revlog-stats: changelog, manifest, filelogs, template
281 debug-revlog-stats: changelog, manifest, filelogs, template
281 debug::stable-tail-sort: template
282 debug::stable-tail-sort: template
282 debug::stable-tail-sort-leaps: template, specific
283 debug::stable-tail-sort-leaps: template, specific
284 debug::unbundle: update
283 debugancestor:
285 debugancestor:
284 debugantivirusrunning:
286 debugantivirusrunning:
285 debugapplystreamclonebundle:
287 debugapplystreamclonebundle:
286 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
288 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
287 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
289 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
288 debugbundle: all, part-type, spec
290 debugbundle: all, part-type, spec
289 debugcapabilities:
291 debugcapabilities:
290 debugchangedfiles: compute
292 debugchangedfiles: compute
291 debugcheckstate:
293 debugcheckstate:
292 debugcolor: style
294 debugcolor: style
293 debugcommands:
295 debugcommands:
294 debugcomplete: options
296 debugcomplete: options
295 debugcreatestreamclonebundle:
297 debugcreatestreamclonebundle:
296 debugdag: tags, branches, dots, spaces
298 debugdag: tags, branches, dots, spaces
297 debugdata: changelog, manifest, dir
299 debugdata: changelog, manifest, dir
298 debugdate: extended
300 debugdate: extended
299 debugdeltachain: rev, all-info, size-info, dist-info, sparse-info, changelog, manifest, dir, template
301 debugdeltachain: rev, all-info, size-info, dist-info, sparse-info, changelog, manifest, dir, template
300 debugdirstateignorepatternshash:
302 debugdirstateignorepatternshash:
301 debugdirstate: nodates, dates, datesort, docket, all
303 debugdirstate: nodates, dates, datesort, docket, all
302 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
304 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
303 debugdownload: output
305 debugdownload: output
304 debugextensions: template
306 debugextensions: template
305 debugfileset: rev, all-files, show-matcher, show-stage
307 debugfileset: rev, all-files, show-matcher, show-stage
306 debugformat: template
308 debugformat: template
307 debugfsinfo:
309 debugfsinfo:
308 debuggetbundle: head, common, type
310 debuggetbundle: head, common, type
309 debugignore:
311 debugignore:
310 debugindexdot: changelog, manifest, dir
312 debugindexdot: changelog, manifest, dir
311 debugindexstats:
313 debugindexstats:
312 debuginstall: template
314 debuginstall: template
313 debugknown:
315 debugknown:
314 debuglabelcomplete:
316 debuglabelcomplete:
315 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
317 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
316 debugmanifestfulltextcache: clear, add
318 debugmanifestfulltextcache: clear, add
317 debugmergestate: style, template
319 debugmergestate: style, template
318 debugnamecomplete:
320 debugnamecomplete:
319 debugnodemap: changelog, manifest, dir, dump-new, dump-disk, check, metadata
321 debugnodemap: changelog, manifest, dir, dump-new, dump-disk, check, metadata
320 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
322 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
321 debugp1copies: rev
323 debugp1copies: rev
322 debugp2copies: rev
324 debugp2copies: rev
323 debugpathcomplete: full, normal, added, removed
325 debugpathcomplete: full, normal, added, removed
324 debugpathcopies: include, exclude
326 debugpathcopies: include, exclude
325 debugpeer:
327 debugpeer:
326 debugpickmergetool: rev, changedelete, include, exclude, tool
328 debugpickmergetool: rev, changedelete, include, exclude, tool
327 debugpushkey:
329 debugpushkey:
328 debugpvec:
330 debugpvec:
329 debugrebuilddirstate: rev, minimal
331 debugrebuilddirstate: rev, minimal
330 debugrebuildfncache: only-data
332 debugrebuildfncache: only-data
331 debugrename: rev
333 debugrename: rev
332 debugrequires:
334 debugrequires:
333 debugrevlog: changelog, manifest, dir, dump
335 debugrevlog: changelog, manifest, dir, dump
334 debugrevlogindex: changelog, manifest, dir, format
336 debugrevlogindex: changelog, manifest, dir, format
335 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
337 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
336 debugserve: sshstdio, logiofd, logiofile
338 debugserve: sshstdio, logiofd, logiofile
337 debugsetparents:
339 debugsetparents:
338 debugshell: command
340 debugshell: command
339 debugsidedata: changelog, manifest, dir
341 debugsidedata: changelog, manifest, dir
340 debugssl:
342 debugssl:
341 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
343 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
342 debugsub: rev
344 debugsub: rev
343 debugsuccessorssets: closest
345 debugsuccessorssets: closest
344 debugtagscache:
346 debugtagscache:
345 debugtemplate: rev, define
347 debugtemplate: rev, define
346 debuguigetpass: prompt
348 debuguigetpass: prompt
347 debuguiprompt: prompt
349 debuguiprompt: prompt
348 debugupdatecaches:
350 debugupdatecaches:
349 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
351 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
350 debugwalk: include, exclude
352 debugwalk: include, exclude
351 debugwhyunstable:
353 debugwhyunstable:
352 debugwireargs: three, four, five, ssh, remotecmd, insecure
354 debugwireargs: three, four, five, ssh, remotecmd, insecure
353 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
355 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
354 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
356 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
355 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
357 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
356 files: rev, print0, include, exclude, template, subrepos
358 files: rev, print0, include, exclude, template, subrepos
357 forget: interactive, include, exclude, dry-run
359 forget: interactive, include, exclude, dry-run
358 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
360 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
359 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
361 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
360 heads: rev, topo, active, closed, style, template
362 heads: rev, topo, active, closed, style, template
361 help: extension, command, keyword, system
363 help: extension, command, keyword, system
362 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
364 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
363 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
365 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
364 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
366 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
365 init: ssh, remotecmd, insecure
367 init: ssh, remotecmd, insecure
366 locate: rev, print0, fullpath, include, exclude
368 locate: rev, print0, fullpath, include, exclude
367 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
369 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
368 manifest: rev, all, template
370 manifest: rev, all, template
369 merge: force, rev, preview, abort, tool
371 merge: force, rev, preview, abort, tool
370 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
372 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
371 parents: rev, style, template
373 parents: rev, style, template
372 paths: template
374 paths: template
373 phase: public, draft, secret, force, rev
375 phase: public, draft, secret, force, rev
374 pull: update, force, confirm, rev, bookmark, branch, remote-hidden, ssh, remotecmd, insecure
376 pull: update, force, confirm, rev, bookmark, branch, remote-hidden, ssh, remotecmd, insecure
375 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
377 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
376 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
378 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
377 recover: verify
379 recover: verify
378 remove: after, force, subrepos, include, exclude, dry-run
380 remove: after, force, subrepos, include, exclude, dry-run
379 rename: forget, after, at-rev, force, include, exclude, dry-run
381 rename: forget, after, at-rev, force, include, exclude, dry-run
380 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
382 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
381 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
383 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
382 rollback: dry-run, force
384 rollback: dry-run, force
383 root: template
385 root: template
384 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
386 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
385 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
387 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
386 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
388 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
387 summary: remote
389 summary: remote
388 tag: force, local, rev, remove, edit, message, date, user
390 tag: force, local, rev, remove, edit, message, date, user
389 tags: template
391 tags: template
390 tip: patch, git, style, template
392 tip: patch, git, style, template
391 unbundle: update
393 unbundle: update
392 unshelve: abort, continue, interactive, keep, name, tool, date
394 unshelve: abort, continue, interactive, keep, name, tool, date
393 update: clean, check, merge, date, rev, tool
395 update: clean, check, merge, date, rev, tool
394 verify: full
396 verify: full
395 version: template
397 version: template
396
398
397 $ hg init a
399 $ hg init a
398 $ cd a
400 $ cd a
399 $ echo fee > fee
401 $ echo fee > fee
400 $ hg ci -q -Amfee
402 $ hg ci -q -Amfee
401 $ hg tag fee
403 $ hg tag fee
402 $ mkdir fie
404 $ mkdir fie
403 $ echo dead > fie/dead
405 $ echo dead > fie/dead
404 $ echo live > fie/live
406 $ echo live > fie/live
405 $ hg bookmark fo
407 $ hg bookmark fo
406 $ hg branch -q fie
408 $ hg branch -q fie
407 $ hg ci -q -Amfie
409 $ hg ci -q -Amfie
408 $ echo fo > fo
410 $ echo fo > fo
409 $ hg branch -qf default
411 $ hg branch -qf default
410 $ hg ci -q -Amfo
412 $ hg ci -q -Amfo
411 $ echo Fum > Fum
413 $ echo Fum > Fum
412 $ hg ci -q -AmFum
414 $ hg ci -q -AmFum
413 $ hg bookmark Fum
415 $ hg bookmark Fum
414
416
415 Test debugpathcomplete
417 Test debugpathcomplete
416
418
417 $ hg debugpathcomplete f
419 $ hg debugpathcomplete f
418 fee
420 fee
419 fie
421 fie
420 fo
422 fo
421 $ hg debugpathcomplete -f f
423 $ hg debugpathcomplete -f f
422 fee
424 fee
423 fie/dead
425 fie/dead
424 fie/live
426 fie/live
425 fo
427 fo
426
428
427 $ hg rm Fum
429 $ hg rm Fum
428 $ hg debugpathcomplete -r F
430 $ hg debugpathcomplete -r F
429 Fum
431 Fum
430
432
431 Test debugnamecomplete
433 Test debugnamecomplete
432
434
433 $ hg debugnamecomplete
435 $ hg debugnamecomplete
434 Fum
436 Fum
435 default
437 default
436 fee
438 fee
437 fie
439 fie
438 fo
440 fo
439 tip
441 tip
440 $ hg debugnamecomplete f
442 $ hg debugnamecomplete f
441 fee
443 fee
442 fie
444 fie
443 fo
445 fo
444
446
445 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
447 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
446 used for completions in some shells.
448 used for completions in some shells.
447
449
448 $ hg debuglabelcomplete
450 $ hg debuglabelcomplete
449 Fum
451 Fum
450 default
452 default
451 fee
453 fee
452 fie
454 fie
453 fo
455 fo
454 tip
456 tip
455 $ hg debuglabelcomplete f
457 $ hg debuglabelcomplete f
456 fee
458 fee
457 fie
459 fie
458 fo
460 fo
@@ -1,818 +1,831 b''
1 $ cat << EOF >> $HGRCPATH
1 $ cat << EOF >> $HGRCPATH
2 > [ui]
2 > [ui]
3 > interactive=yes
3 > interactive=yes
4 > EOF
4 > EOF
5
5
6 $ hg init debugrevlog
6 $ hg init debugrevlog
7 $ cd debugrevlog
7 $ cd debugrevlog
8 $ echo a > a
8 $ echo a > a
9 $ hg ci -Am adda
9 $ hg ci -Am adda
10 adding a
10 adding a
11 $ hg rm .
11 $ hg rm .
12 removing a
12 removing a
13 $ hg ci -Am make-it-empty
13 $ hg ci -Am make-it-empty
14 $ hg revert --all -r 0
14 $ hg revert --all -r 0
15 adding a
15 adding a
16 $ hg ci -Am make-it-full
16 $ hg ci -Am make-it-full
17 #if reporevlogstore
17 #if reporevlogstore
18 $ hg debugrevlog -c
18 $ hg debugrevlog -c
19 format : 1
19 format : 1
20 flags : (none)
20 flags : (none)
21
21
22 revisions : 3
22 revisions : 3
23 merges : 0 ( 0.00%)
23 merges : 0 ( 0.00%)
24 normal : 3 (100.00%)
24 normal : 3 (100.00%)
25 revisions : 3
25 revisions : 3
26 empty : 0 ( 0.00%)
26 empty : 0 ( 0.00%)
27 text : 0 (100.00%)
27 text : 0 (100.00%)
28 delta : 0 (100.00%)
28 delta : 0 (100.00%)
29 snapshot : 3 (100.00%)
29 snapshot : 3 (100.00%)
30 lvl-0 : 3 (100.00%)
30 lvl-0 : 3 (100.00%)
31 deltas : 0 ( 0.00%)
31 deltas : 0 ( 0.00%)
32 revision size : 191
32 revision size : 191
33 snapshot : 191 (100.00%)
33 snapshot : 191 (100.00%)
34 lvl-0 : 191 (100.00%)
34 lvl-0 : 191 (100.00%)
35 deltas : 0 ( 0.00%)
35 deltas : 0 ( 0.00%)
36
36
37 chunks : 3
37 chunks : 3
38 0x75 (u) : 3 (100.00%)
38 0x75 (u) : 3 (100.00%)
39 chunks size : 191
39 chunks size : 191
40 0x75 (u) : 191 (100.00%)
40 0x75 (u) : 191 (100.00%)
41
41
42
42
43 total-stored-content: 188 bytes
43 total-stored-content: 188 bytes
44
44
45 avg chain length : 0
45 avg chain length : 0
46 max chain length : 0
46 max chain length : 0
47 max chain reach : 67
47 max chain reach : 67
48 compression ratio : 0
48 compression ratio : 0
49
49
50 uncompressed data size (min/max/avg) : 57 / 66 / 62
50 uncompressed data size (min/max/avg) : 57 / 66 / 62
51 full revision size (min/max/avg) : 58 / 67 / 63
51 full revision size (min/max/avg) : 58 / 67 / 63
52 inter-snapshot size (min/max/avg) : 0 / 0 / 0
52 inter-snapshot size (min/max/avg) : 0 / 0 / 0
53 delta size (min/max/avg) : 0 / 0 / 0
53 delta size (min/max/avg) : 0 / 0 / 0
54 $ hg debugrevlog -m
54 $ hg debugrevlog -m
55 format : 1
55 format : 1
56 flags : inline, generaldelta
56 flags : inline, generaldelta
57
57
58 revisions : 3
58 revisions : 3
59 merges : 0 ( 0.00%)
59 merges : 0 ( 0.00%)
60 normal : 3 (100.00%)
60 normal : 3 (100.00%)
61 revisions : 3
61 revisions : 3
62 empty : 1 (33.33%)
62 empty : 1 (33.33%)
63 text : 1 (100.00%)
63 text : 1 (100.00%)
64 delta : 0 ( 0.00%)
64 delta : 0 ( 0.00%)
65 snapshot : 2 (66.67%)
65 snapshot : 2 (66.67%)
66 lvl-0 : 2 (66.67%)
66 lvl-0 : 2 (66.67%)
67 deltas : 0 ( 0.00%)
67 deltas : 0 ( 0.00%)
68 revision size : 88
68 revision size : 88
69 snapshot : 88 (100.00%)
69 snapshot : 88 (100.00%)
70 lvl-0 : 88 (100.00%)
70 lvl-0 : 88 (100.00%)
71 deltas : 0 ( 0.00%)
71 deltas : 0 ( 0.00%)
72
72
73 chunks : 3
73 chunks : 3
74 empty : 1 (33.33%)
74 empty : 1 (33.33%)
75 0x75 (u) : 2 (66.67%)
75 0x75 (u) : 2 (66.67%)
76 chunks size : 88
76 chunks size : 88
77 empty : 0 ( 0.00%)
77 empty : 0 ( 0.00%)
78 0x75 (u) : 88 (100.00%)
78 0x75 (u) : 88 (100.00%)
79
79
80
80
81 total-stored-content: 86 bytes
81 total-stored-content: 86 bytes
82
82
83 avg chain length : 0
83 avg chain length : 0
84 max chain length : 0
84 max chain length : 0
85 max chain reach : 44
85 max chain reach : 44
86 compression ratio : 0
86 compression ratio : 0
87
87
88 uncompressed data size (min/max/avg) : 0 / 43 / 28
88 uncompressed data size (min/max/avg) : 0 / 43 / 28
89 full revision size (min/max/avg) : 44 / 44 / 44
89 full revision size (min/max/avg) : 44 / 44 / 44
90 inter-snapshot size (min/max/avg) : 0 / 0 / 0
90 inter-snapshot size (min/max/avg) : 0 / 0 / 0
91 delta size (min/max/avg) : 0 / 0 / 0
91 delta size (min/max/avg) : 0 / 0 / 0
92 $ hg debugrevlog a
92 $ hg debugrevlog a
93 format : 1
93 format : 1
94 flags : inline, generaldelta
94 flags : inline, generaldelta
95
95
96 revisions : 1
96 revisions : 1
97 merges : 0 ( 0.00%)
97 merges : 0 ( 0.00%)
98 normal : 1 (100.00%)
98 normal : 1 (100.00%)
99 revisions : 1
99 revisions : 1
100 empty : 0 ( 0.00%)
100 empty : 0 ( 0.00%)
101 text : 0 (100.00%)
101 text : 0 (100.00%)
102 delta : 0 (100.00%)
102 delta : 0 (100.00%)
103 snapshot : 1 (100.00%)
103 snapshot : 1 (100.00%)
104 lvl-0 : 1 (100.00%)
104 lvl-0 : 1 (100.00%)
105 deltas : 0 ( 0.00%)
105 deltas : 0 ( 0.00%)
106 revision size : 3
106 revision size : 3
107 snapshot : 3 (100.00%)
107 snapshot : 3 (100.00%)
108 lvl-0 : 3 (100.00%)
108 lvl-0 : 3 (100.00%)
109 deltas : 0 ( 0.00%)
109 deltas : 0 ( 0.00%)
110
110
111 chunks : 1
111 chunks : 1
112 0x75 (u) : 1 (100.00%)
112 0x75 (u) : 1 (100.00%)
113 chunks size : 3
113 chunks size : 3
114 0x75 (u) : 3 (100.00%)
114 0x75 (u) : 3 (100.00%)
115
115
116
116
117 total-stored-content: 2 bytes
117 total-stored-content: 2 bytes
118
118
119 avg chain length : 0
119 avg chain length : 0
120 max chain length : 0
120 max chain length : 0
121 max chain reach : 3
121 max chain reach : 3
122 compression ratio : 0
122 compression ratio : 0
123
123
124 uncompressed data size (min/max/avg) : 2 / 2 / 2
124 uncompressed data size (min/max/avg) : 2 / 2 / 2
125 full revision size (min/max/avg) : 3 / 3 / 3
125 full revision size (min/max/avg) : 3 / 3 / 3
126 inter-snapshot size (min/max/avg) : 0 / 0 / 0
126 inter-snapshot size (min/max/avg) : 0 / 0 / 0
127 delta size (min/max/avg) : 0 / 0 / 0
127 delta size (min/max/avg) : 0 / 0 / 0
128 #endif
128 #endif
129
129
130 Test debugindex, with and without the --verbose/--debug flag
130 Test debugindex, with and without the --verbose/--debug flag
131 $ hg debugrevlogindex a
131 $ hg debugrevlogindex a
132 rev linkrev nodeid p1 p2
132 rev linkrev nodeid p1 p2
133 0 0 b789fdd96dc2 000000000000 000000000000
133 0 0 b789fdd96dc2 000000000000 000000000000
134
134
135 #if no-reposimplestore
135 #if no-reposimplestore
136 $ hg --verbose debugrevlogindex a
136 $ hg --verbose debugrevlogindex a
137 rev offset length linkrev nodeid p1 p2
137 rev offset length linkrev nodeid p1 p2
138 0 0 3 0 b789fdd96dc2 000000000000 000000000000
138 0 0 3 0 b789fdd96dc2 000000000000 000000000000
139
139
140 $ hg --debug debugrevlogindex a
140 $ hg --debug debugrevlogindex a
141 rev offset length linkrev nodeid p1 p2
141 rev offset length linkrev nodeid p1 p2
142 0 0 3 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
142 0 0 3 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
143 #endif
143 #endif
144
144
145 $ hg debugrevlogindex -f 1 a
145 $ hg debugrevlogindex -f 1 a
146 rev flag size link p1 p2 nodeid
146 rev flag size link p1 p2 nodeid
147 0 0000 2 0 -1 -1 b789fdd96dc2
147 0 0000 2 0 -1 -1 b789fdd96dc2
148
148
149 #if no-reposimplestore
149 #if no-reposimplestore
150 $ hg --verbose debugrevlogindex -f 1 a
150 $ hg --verbose debugrevlogindex -f 1 a
151 rev flag offset length size link p1 p2 nodeid
151 rev flag offset length size link p1 p2 nodeid
152 0 0000 0 3 2 0 -1 -1 b789fdd96dc2
152 0 0000 0 3 2 0 -1 -1 b789fdd96dc2
153
153
154 $ hg --debug debugrevlogindex -f 1 a
154 $ hg --debug debugrevlogindex -f 1 a
155 rev flag offset length size link p1 p2 nodeid
155 rev flag offset length size link p1 p2 nodeid
156 0 0000 0 3 2 0 -1 -1 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
156 0 0000 0 3 2 0 -1 -1 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
157 #endif
157 #endif
158
158
159 $ hg debugindex -c
159 $ hg debugindex -c
160 rev linkrev nodeid p1-nodeid p2-nodeid
160 rev linkrev nodeid p1-nodeid p2-nodeid
161 0 0 07f494440405 000000000000 000000000000
161 0 0 07f494440405 000000000000 000000000000
162 1 1 8cccb4b5fec2 07f494440405 000000000000
162 1 1 8cccb4b5fec2 07f494440405 000000000000
163 2 2 b1e228c512c5 8cccb4b5fec2 000000000000
163 2 2 b1e228c512c5 8cccb4b5fec2 000000000000
164 $ hg debugindex -c --debug
164 $ hg debugindex -c --debug
165 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
165 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
166 0 -1 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 57 0 0 2 0 58 inline 0 0
166 0 -1 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 57 0 0 2 0 58 inline 0 0
167 1 -1 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 66 1 0 2 58 67 inline 0 0
167 1 -1 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a 0 07f4944404050f47db2e5c5071e0e84e7a27bba9 -1 0000000000000000000000000000000000000000 66 1 0 2 58 67 inline 0 0
168 2 -1 2 b1e228c512c5d7066d70562ed839c3323a62d6d2 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a -1 0000000000000000000000000000000000000000 65 2 0 2 125 66 inline 0 0
168 2 -1 2 b1e228c512c5d7066d70562ed839c3323a62d6d2 1 8cccb4b5fec20cafeb99dd01c26d4dee8ea4388a -1 0000000000000000000000000000000000000000 65 2 0 2 125 66 inline 0 0
169 $ hg debugindex -m
169 $ hg debugindex -m
170 rev linkrev nodeid p1-nodeid p2-nodeid
170 rev linkrev nodeid p1-nodeid p2-nodeid
171 0 0 a0c8bcbbb45c 000000000000 000000000000
171 0 0 a0c8bcbbb45c 000000000000 000000000000
172 1 1 57faf8a737ae a0c8bcbbb45c 000000000000
172 1 1 57faf8a737ae a0c8bcbbb45c 000000000000
173 2 2 a35b10320954 57faf8a737ae 000000000000
173 2 2 a35b10320954 57faf8a737ae 000000000000
174 $ hg debugindex -m --debug
174 $ hg debugindex -m --debug
175 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
175 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
176 0 -1 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 43 0 0 2 0 44 inline 0 0
176 0 -1 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 43 0 0 2 0 44 inline 0 0
177 1 -1 1 57faf8a737ae7faf490582941a82319ba6529dca 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 0 1 0 2 44 0 inline 0 0
177 1 -1 1 57faf8a737ae7faf490582941a82319ba6529dca 0 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 -1 0000000000000000000000000000000000000000 0 1 0 2 44 0 inline 0 0
178 2 -1 2 a35b103209548032201c16c7688cb2657f037a38 1 57faf8a737ae7faf490582941a82319ba6529dca -1 0000000000000000000000000000000000000000 43 2 0 2 44 44 inline 0 0
178 2 -1 2 a35b103209548032201c16c7688cb2657f037a38 1 57faf8a737ae7faf490582941a82319ba6529dca -1 0000000000000000000000000000000000000000 43 2 0 2 44 44 inline 0 0
179 $ hg debugindex a
179 $ hg debugindex a
180 rev linkrev nodeid p1-nodeid p2-nodeid
180 rev linkrev nodeid p1-nodeid p2-nodeid
181 0 0 b789fdd96dc2 000000000000 000000000000
181 0 0 b789fdd96dc2 000000000000 000000000000
182 $ hg debugindex --debug a
182 $ hg debugindex --debug a
183 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
183 rev rank linkrev nodeid p1-rev p1-nodeid p2-rev p2-nodeid full-size delta-base flags comp-mode data-offset chunk-size sd-comp-mode sidedata-offset sd-chunk-size
184 0 -1 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 2 0 0 2 0 3 inline 0 0
184 0 -1 0 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000 2 0 0 2 0 3 inline 0 0
185
185
186 debugdelta chain basic output
186 debugdelta chain basic output
187
187
188 #if reporevlogstore pure rust
188 #if reporevlogstore pure rust
189 $ hg debugindexstats
189 $ hg debugindexstats
190 abort: debugindexstats only works with native C code
190 abort: debugindexstats only works with native C code
191 [255]
191 [255]
192 #endif
192 #endif
193 #if reporevlogstore no-pure no-rust
193 #if reporevlogstore no-pure no-rust
194 $ hg debugindexstats
194 $ hg debugindexstats
195 node trie capacity: 4
195 node trie capacity: 4
196 node trie count: 2
196 node trie count: 2
197 node trie depth: 1
197 node trie depth: 1
198 node trie last rev scanned: -1 (no-rust !)
198 node trie last rev scanned: -1 (no-rust !)
199 node trie last rev scanned: 3 (rust !)
199 node trie last rev scanned: 3 (rust !)
200 node trie lookups: 4 (no-rust !)
200 node trie lookups: 4 (no-rust !)
201 node trie lookups: 2 (rust !)
201 node trie lookups: 2 (rust !)
202 node trie misses: 1
202 node trie misses: 1
203 node trie splits: 1
203 node trie splits: 1
204 revs in memory: 3
204 revs in memory: 3
205 #endif
205 #endif
206
206
207 #if reporevlogstore no-pure
207 #if reporevlogstore no-pure
208 $ hg debugdeltachain -m --all-info
208 $ hg debugdeltachain -m --all-info
209 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
209 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
210 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
210 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
211 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
211 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
212 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
212 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
213
213
214 $ hg debugdeltachain -m -T '{rev} {chainid} {chainlen}\n'
214 $ hg debugdeltachain -m -T '{rev} {chainid} {chainlen}\n'
215 0 1 1
215 0 1 1
216 1 2 1
216 1 2 1
217 2 3 1
217 2 3 1
218
218
219 $ hg debugdeltachain -m -Tjson --size-info
219 $ hg debugdeltachain -m -Tjson --size-info
220 [
220 [
221 {
221 {
222 "chainid": 1,
222 "chainid": 1,
223 "chainlen": 1,
223 "chainlen": 1,
224 "chainratio": 1.0232558139534884,
224 "chainratio": 1.0232558139534884,
225 "chainsize": 44,
225 "chainsize": 44,
226 "compsize": 44,
226 "compsize": 44,
227 "deltatype": "base",
227 "deltatype": "base",
228 "p1": -1,
228 "p1": -1,
229 "p2": -1,
229 "p2": -1,
230 "prevrev": -1,
230 "prevrev": -1,
231 "rev": 0,
231 "rev": 0,
232 "uncompsize": 43
232 "uncompsize": 43
233 },
233 },
234 {
234 {
235 "chainid": 2,
235 "chainid": 2,
236 "chainlen": 1,
236 "chainlen": 1,
237 "chainratio": 0,
237 "chainratio": 0,
238 "chainsize": 0,
238 "chainsize": 0,
239 "compsize": 0,
239 "compsize": 0,
240 "deltatype": "base",
240 "deltatype": "base",
241 "p1": 0,
241 "p1": 0,
242 "p2": -1,
242 "p2": -1,
243 "prevrev": -1,
243 "prevrev": -1,
244 "rev": 1,
244 "rev": 1,
245 "uncompsize": 0
245 "uncompsize": 0
246 },
246 },
247 {
247 {
248 "chainid": 3,
248 "chainid": 3,
249 "chainlen": 1,
249 "chainlen": 1,
250 "chainratio": 1.0232558139534884,
250 "chainratio": 1.0232558139534884,
251 "chainsize": 44,
251 "chainsize": 44,
252 "compsize": 44,
252 "compsize": 44,
253 "deltatype": "base",
253 "deltatype": "base",
254 "p1": 1,
254 "p1": 1,
255 "p2": -1,
255 "p2": -1,
256 "prevrev": -1,
256 "prevrev": -1,
257 "rev": 2,
257 "rev": 2,
258 "uncompsize": 43
258 "uncompsize": 43
259 }
259 }
260 ]
260 ]
261
261
262 $ hg debugdeltachain -m -Tjson --all-info
262 $ hg debugdeltachain -m -Tjson --all-info
263 [
263 [
264 {
264 {
265 "chainid": 1,
265 "chainid": 1,
266 "chainlen": 1,
266 "chainlen": 1,
267 "chainratio": 1.0232558139534884,
267 "chainratio": 1.0232558139534884,
268 "chainsize": 44,
268 "chainsize": 44,
269 "compsize": 44,
269 "compsize": 44,
270 "deltatype": "base",
270 "deltatype": "base",
271 "extradist": 0,
271 "extradist": 0,
272 "extraratio": 0.0,
272 "extraratio": 0.0,
273 "largestblock": 44,
273 "largestblock": 44,
274 "lindist": 44,
274 "lindist": 44,
275 "p1": -1,
275 "p1": -1,
276 "p2": -1,
276 "p2": -1,
277 "prevrev": -1,
277 "prevrev": -1,
278 "readdensity": 1.0,
278 "readdensity": 1.0,
279 "readsize": 44,
279 "readsize": 44,
280 "rev": 0,
280 "rev": 0,
281 "srchunks": 1,
281 "srchunks": 1,
282 "uncompsize": 43
282 "uncompsize": 43
283 },
283 },
284 {
284 {
285 "chainid": 2,
285 "chainid": 2,
286 "chainlen": 1,
286 "chainlen": 1,
287 "chainratio": 0,
287 "chainratio": 0,
288 "chainsize": 0,
288 "chainsize": 0,
289 "compsize": 0,
289 "compsize": 0,
290 "deltatype": "base",
290 "deltatype": "base",
291 "extradist": 0,
291 "extradist": 0,
292 "extraratio": 0,
292 "extraratio": 0,
293 "largestblock": 0,
293 "largestblock": 0,
294 "lindist": 0,
294 "lindist": 0,
295 "p1": 0,
295 "p1": 0,
296 "p2": -1,
296 "p2": -1,
297 "prevrev": -1,
297 "prevrev": -1,
298 "readdensity": 1,
298 "readdensity": 1,
299 "readsize": 0,
299 "readsize": 0,
300 "rev": 1,
300 "rev": 1,
301 "srchunks": 1,
301 "srchunks": 1,
302 "uncompsize": 0
302 "uncompsize": 0
303 },
303 },
304 {
304 {
305 "chainid": 3,
305 "chainid": 3,
306 "chainlen": 1,
306 "chainlen": 1,
307 "chainratio": 1.0232558139534884,
307 "chainratio": 1.0232558139534884,
308 "chainsize": 44,
308 "chainsize": 44,
309 "compsize": 44,
309 "compsize": 44,
310 "deltatype": "base",
310 "deltatype": "base",
311 "extradist": 0,
311 "extradist": 0,
312 "extraratio": 0.0,
312 "extraratio": 0.0,
313 "largestblock": 44,
313 "largestblock": 44,
314 "lindist": 44,
314 "lindist": 44,
315 "p1": 1,
315 "p1": 1,
316 "p2": -1,
316 "p2": -1,
317 "prevrev": -1,
317 "prevrev": -1,
318 "readdensity": 1.0,
318 "readdensity": 1.0,
319 "readsize": 44,
319 "readsize": 44,
320 "rev": 2,
320 "rev": 2,
321 "srchunks": 1,
321 "srchunks": 1,
322 "uncompsize": 43
322 "uncompsize": 43
323 }
323 }
324 ]
324 ]
325
325
326 debugdelta chain with sparse read enabled
326 debugdelta chain with sparse read enabled
327
327
328 $ cat >> $HGRCPATH <<EOF
328 $ cat >> $HGRCPATH <<EOF
329 > [experimental]
329 > [experimental]
330 > sparse-read = True
330 > sparse-read = True
331 > EOF
331 > EOF
332 $ hg debugdeltachain -m --all-info
332 $ hg debugdeltachain -m --all-info
333 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
333 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
334 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
334 0 -1 -1 1 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
335 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
335 1 0 -1 2 1 -1 base 0 0 0 0.00000 0 0 0.00000 0 0 1.00000 1
336 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
336 2 1 -1 3 1 -1 base 44 43 44 1.02326 44 0 0.00000 44 44 1.00000 1
337
337
338 $ hg debugdeltachain -m --sparse-info -T '{rev} {chainid} {chainlen} {readsize} {largestblock} {readdensity}\n'
338 $ hg debugdeltachain -m --sparse-info -T '{rev} {chainid} {chainlen} {readsize} {largestblock} {readdensity}\n'
339 0 1 1 44 44 1.0
339 0 1 1 44 44 1.0
340 1 2 1 0 0 1
340 1 2 1 0 0 1
341 2 3 1 44 44 1.0
341 2 3 1 44 44 1.0
342
342
343 $ hg debugdeltachain -m -Tjson --sparse-info
343 $ hg debugdeltachain -m -Tjson --sparse-info
344 [
344 [
345 {
345 {
346 "chainid": 1,
346 "chainid": 1,
347 "chainlen": 1,
347 "chainlen": 1,
348 "deltatype": "base",
348 "deltatype": "base",
349 "largestblock": 44,
349 "largestblock": 44,
350 "p1": -1,
350 "p1": -1,
351 "p2": -1,
351 "p2": -1,
352 "prevrev": -1,
352 "prevrev": -1,
353 "readdensity": 1.0,
353 "readdensity": 1.0,
354 "readsize": 44,
354 "readsize": 44,
355 "rev": 0,
355 "rev": 0,
356 "srchunks": 1
356 "srchunks": 1
357 },
357 },
358 {
358 {
359 "chainid": 2,
359 "chainid": 2,
360 "chainlen": 1,
360 "chainlen": 1,
361 "deltatype": "base",
361 "deltatype": "base",
362 "largestblock": 0,
362 "largestblock": 0,
363 "p1": 0,
363 "p1": 0,
364 "p2": -1,
364 "p2": -1,
365 "prevrev": -1,
365 "prevrev": -1,
366 "readdensity": 1,
366 "readdensity": 1,
367 "readsize": 0,
367 "readsize": 0,
368 "rev": 1,
368 "rev": 1,
369 "srchunks": 1
369 "srchunks": 1
370 },
370 },
371 {
371 {
372 "chainid": 3,
372 "chainid": 3,
373 "chainlen": 1,
373 "chainlen": 1,
374 "deltatype": "base",
374 "deltatype": "base",
375 "largestblock": 44,
375 "largestblock": 44,
376 "p1": 1,
376 "p1": 1,
377 "p2": -1,
377 "p2": -1,
378 "prevrev": -1,
378 "prevrev": -1,
379 "readdensity": 1.0,
379 "readdensity": 1.0,
380 "readsize": 44,
380 "readsize": 44,
381 "rev": 2,
381 "rev": 2,
382 "srchunks": 1
382 "srchunks": 1
383 }
383 }
384 ]
384 ]
385
385
386 $ hg debugdeltachain -m -Tjson --all-info
386 $ hg debugdeltachain -m -Tjson --all-info
387 [
387 [
388 {
388 {
389 "chainid": 1,
389 "chainid": 1,
390 "chainlen": 1,
390 "chainlen": 1,
391 "chainratio": 1.0232558139534884,
391 "chainratio": 1.0232558139534884,
392 "chainsize": 44,
392 "chainsize": 44,
393 "compsize": 44,
393 "compsize": 44,
394 "deltatype": "base",
394 "deltatype": "base",
395 "extradist": 0,
395 "extradist": 0,
396 "extraratio": 0.0,
396 "extraratio": 0.0,
397 "largestblock": 44,
397 "largestblock": 44,
398 "lindist": 44,
398 "lindist": 44,
399 "p1": -1,
399 "p1": -1,
400 "p2": -1,
400 "p2": -1,
401 "prevrev": -1,
401 "prevrev": -1,
402 "readdensity": 1.0,
402 "readdensity": 1.0,
403 "readsize": 44,
403 "readsize": 44,
404 "rev": 0,
404 "rev": 0,
405 "srchunks": 1,
405 "srchunks": 1,
406 "uncompsize": 43
406 "uncompsize": 43
407 },
407 },
408 {
408 {
409 "chainid": 2,
409 "chainid": 2,
410 "chainlen": 1,
410 "chainlen": 1,
411 "chainratio": 0,
411 "chainratio": 0,
412 "chainsize": 0,
412 "chainsize": 0,
413 "compsize": 0,
413 "compsize": 0,
414 "deltatype": "base",
414 "deltatype": "base",
415 "extradist": 0,
415 "extradist": 0,
416 "extraratio": 0,
416 "extraratio": 0,
417 "largestblock": 0,
417 "largestblock": 0,
418 "lindist": 0,
418 "lindist": 0,
419 "p1": 0,
419 "p1": 0,
420 "p2": -1,
420 "p2": -1,
421 "prevrev": -1,
421 "prevrev": -1,
422 "readdensity": 1,
422 "readdensity": 1,
423 "readsize": 0,
423 "readsize": 0,
424 "rev": 1,
424 "rev": 1,
425 "srchunks": 1,
425 "srchunks": 1,
426 "uncompsize": 0
426 "uncompsize": 0
427 },
427 },
428 {
428 {
429 "chainid": 3,
429 "chainid": 3,
430 "chainlen": 1,
430 "chainlen": 1,
431 "chainratio": 1.0232558139534884,
431 "chainratio": 1.0232558139534884,
432 "chainsize": 44,
432 "chainsize": 44,
433 "compsize": 44,
433 "compsize": 44,
434 "deltatype": "base",
434 "deltatype": "base",
435 "extradist": 0,
435 "extradist": 0,
436 "extraratio": 0.0,
436 "extraratio": 0.0,
437 "largestblock": 44,
437 "largestblock": 44,
438 "lindist": 44,
438 "lindist": 44,
439 "p1": 1,
439 "p1": 1,
440 "p2": -1,
440 "p2": -1,
441 "prevrev": -1,
441 "prevrev": -1,
442 "readdensity": 1.0,
442 "readdensity": 1.0,
443 "readsize": 44,
443 "readsize": 44,
444 "rev": 2,
444 "rev": 2,
445 "srchunks": 1,
445 "srchunks": 1,
446 "uncompsize": 43
446 "uncompsize": 43
447 }
447 }
448 ]
448 ]
449
449
450 $ printf "This test checks things.\n" >> a
450 $ printf "This test checks things.\n" >> a
451 $ hg ci -m a
451 $ hg ci -m a
452 $ hg branch other
452 $ hg branch other
453 marked working directory as branch other
453 marked working directory as branch other
454 (branches are permanent and global, did you want a bookmark?)
454 (branches are permanent and global, did you want a bookmark?)
455 $ for i in `$TESTDIR/seq.py 5`; do
455 $ for i in `$TESTDIR/seq.py 5`; do
456 > printf "shorter ${i}" >> a
456 > printf "shorter ${i}" >> a
457 > hg ci -m "a other:$i"
457 > hg ci -m "a other:$i"
458 > hg up -q default
458 > hg up -q default
459 > printf "for the branch default we want longer chains: ${i}" >> a
459 > printf "for the branch default we want longer chains: ${i}" >> a
460 > hg ci -m "a default:$i"
460 > hg ci -m "a default:$i"
461 > hg up -q other
461 > hg up -q other
462 > done
462 > done
463 $ hg debugdeltachain a -T '{rev} {srchunks}\n' --all-info\
463 $ hg debugdeltachain a -T '{rev} {srchunks}\n' --all-info\
464 > --config experimental.sparse-read.density-threshold=0.50 \
464 > --config experimental.sparse-read.density-threshold=0.50 \
465 > --config experimental.sparse-read.min-gap-size=0
465 > --config experimental.sparse-read.min-gap-size=0
466 0 1
466 0 1
467 1 1
467 1 1
468 2 1
468 2 1
469 3 1
469 3 1
470 4 1
470 4 1
471 5 1
471 5 1
472 6 1
472 6 1
473 7 1
473 7 1
474 8 1
474 8 1
475 9 1
475 9 1
476 10 2 (no-zstd !)
476 10 2 (no-zstd !)
477 10 1 (zstd !)
477 10 1 (zstd !)
478 11 1
478 11 1
479 $ hg --config extensions.strip= strip --no-backup -r 1
479 $ hg --config extensions.strip= strip --no-backup -r 1
480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
480 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
481
481
482 Test max chain len
482 Test max chain len
483 $ cat >> $HGRCPATH << EOF
483 $ cat >> $HGRCPATH << EOF
484 > [format]
484 > [format]
485 > maxchainlen=4
485 > maxchainlen=4
486 > EOF
486 > EOF
487
487
488 $ printf "This test checks if maxchainlen config value is respected also it can serve as basic test for debugrevlog -d <file>.\n" >> a
488 $ printf "This test checks if maxchainlen config value is respected also it can serve as basic test for debugrevlog -d <file>.\n" >> a
489 $ hg ci -m a
489 $ hg ci -m a
490 $ printf "b\n" >> a
490 $ printf "b\n" >> a
491 $ hg ci -m a
491 $ hg ci -m a
492 $ printf "c\n" >> a
492 $ printf "c\n" >> a
493 $ hg ci -m a
493 $ hg ci -m a
494 $ printf "d\n" >> a
494 $ printf "d\n" >> a
495 $ hg ci -m a
495 $ hg ci -m a
496 $ printf "e\n" >> a
496 $ printf "e\n" >> a
497 $ hg ci -m a
497 $ hg ci -m a
498 $ printf "f\n" >> a
498 $ printf "f\n" >> a
499 $ hg ci -m a
499 $ hg ci -m a
500 $ printf 'g\n' >> a
500 $ printf 'g\n' >> a
501 $ hg ci -m a
501 $ hg ci -m a
502 $ printf 'h\n' >> a
502 $ printf 'h\n' >> a
503 $ hg ci -m a
503 $ hg ci -m a
504
504
505 $ hg debugrevlog -d a
505 $ hg debugrevlog -d a
506 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
506 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
507 0 -1 -1 0 ??? 0 0 0 0 ??? ???? ? 1 0 (glob)
507 0 -1 -1 0 ??? 0 0 0 0 ??? ???? ? 1 0 (glob)
508 1 0 -1 ??? ??? 0 0 0 0 ??? ???? ? 1 1 (glob)
508 1 0 -1 ??? ??? 0 0 0 0 ??? ???? ? 1 1 (glob)
509 2 1 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
509 2 1 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
510 3 2 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
510 3 2 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
511 4 3 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 4 (glob)
511 4 3 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 4 (glob)
512 5 4 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 0 (glob)
512 5 4 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 0 (glob)
513 6 5 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 1 (glob)
513 6 5 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 1 (glob)
514 7 6 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
514 7 6 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 2 (glob)
515 8 7 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
515 8 7 -1 ??? ??? ??? ??? ??? 0 ??? ???? ? 1 3 (glob)
516 #endif
516 #endif
517
517
518 Test debuglocks command:
518 Test debuglocks command:
519
519
520 $ hg debuglocks
520 $ hg debuglocks
521 lock: free
521 lock: free
522 wlock: free
522 wlock: free
523
523
524 * Test setting the lock
524 * Test setting the lock
525
525
526 waitlock <file> will wait for file to be created. If it isn't in a reasonable
526 waitlock <file> will wait for file to be created. If it isn't in a reasonable
527 amount of time, displays error message and returns 1
527 amount of time, displays error message and returns 1
528 $ waitlock() {
528 $ waitlock() {
529 > start=`date +%s`
529 > start=`date +%s`
530 > timeout=5
530 > timeout=5
531 > while [ \( ! -f $1 \) -a \( ! -L $1 \) ]; do
531 > while [ \( ! -f $1 \) -a \( ! -L $1 \) ]; do
532 > now=`date +%s`
532 > now=`date +%s`
533 > if [ "`expr $now - $start`" -gt $timeout ]; then
533 > if [ "`expr $now - $start`" -gt $timeout ]; then
534 > echo "timeout: $1 was not created in $timeout seconds"
534 > echo "timeout: $1 was not created in $timeout seconds"
535 > return 1
535 > return 1
536 > fi
536 > fi
537 > sleep 0.1
537 > sleep 0.1
538 > done
538 > done
539 > }
539 > }
540 $ dolock() {
540 $ dolock() {
541 > {
541 > {
542 > waitlock .hg/unlock
542 > waitlock .hg/unlock
543 > rm -f .hg/unlock
543 > rm -f .hg/unlock
544 > echo y
544 > echo y
545 > } | hg debuglocks "$@" > /dev/null
545 > } | hg debuglocks "$@" > /dev/null
546 > }
546 > }
547 $ dolock -s &
547 $ dolock -s &
548 $ waitlock .hg/store/lock
548 $ waitlock .hg/store/lock
549
549
550 $ hg debuglocks
550 $ hg debuglocks
551 lock: user *, process * (*s) (glob)
551 lock: user *, process * (*s) (glob)
552 wlock: free
552 wlock: free
553 [1]
553 [1]
554 $ touch .hg/unlock
554 $ touch .hg/unlock
555 $ wait
555 $ wait
556 $ [ -f .hg/store/lock ] || echo "There is no lock"
556 $ [ -f .hg/store/lock ] || echo "There is no lock"
557 There is no lock
557 There is no lock
558
558
559 * Test setting the wlock
559 * Test setting the wlock
560
560
561 $ dolock -S &
561 $ dolock -S &
562 $ waitlock .hg/wlock
562 $ waitlock .hg/wlock
563
563
564 $ hg debuglocks
564 $ hg debuglocks
565 lock: free
565 lock: free
566 wlock: user *, process * (*s) (glob)
566 wlock: user *, process * (*s) (glob)
567 [1]
567 [1]
568 $ touch .hg/unlock
568 $ touch .hg/unlock
569 $ wait
569 $ wait
570 $ [ -f .hg/wlock ] || echo "There is no wlock"
570 $ [ -f .hg/wlock ] || echo "There is no wlock"
571 There is no wlock
571 There is no wlock
572
572
573 * Test setting both locks
573 * Test setting both locks
574
574
575 $ dolock -Ss &
575 $ dolock -Ss &
576 $ waitlock .hg/wlock && waitlock .hg/store/lock
576 $ waitlock .hg/wlock && waitlock .hg/store/lock
577
577
578 $ hg debuglocks
578 $ hg debuglocks
579 lock: user *, process * (*s) (glob)
579 lock: user *, process * (*s) (glob)
580 wlock: user *, process * (*s) (glob)
580 wlock: user *, process * (*s) (glob)
581 [2]
581 [2]
582
582
583 * Test failing to set a lock
583 * Test failing to set a lock
584
584
585 $ hg debuglocks -s
585 $ hg debuglocks -s
586 abort: lock is already held
586 abort: lock is already held
587 [255]
587 [255]
588
588
589 $ hg debuglocks -S
589 $ hg debuglocks -S
590 abort: wlock is already held
590 abort: wlock is already held
591 [255]
591 [255]
592
592
593 $ touch .hg/unlock
593 $ touch .hg/unlock
594 $ wait
594 $ wait
595
595
596 $ hg debuglocks
596 $ hg debuglocks
597 lock: free
597 lock: free
598 wlock: free
598 wlock: free
599
599
600 * Test forcing the lock
600 * Test forcing the lock
601
601
602 $ dolock -s &
602 $ dolock -s &
603 $ waitlock .hg/store/lock
603 $ waitlock .hg/store/lock
604
604
605 $ hg debuglocks
605 $ hg debuglocks
606 lock: user *, process * (*s) (glob)
606 lock: user *, process * (*s) (glob)
607 wlock: free
607 wlock: free
608 [1]
608 [1]
609
609
610 $ hg debuglocks -L
610 $ hg debuglocks -L
611
611
612 $ hg debuglocks
612 $ hg debuglocks
613 lock: free
613 lock: free
614 wlock: free
614 wlock: free
615
615
616 $ touch .hg/unlock
616 $ touch .hg/unlock
617 $ wait
617 $ wait
618
618
619 * Test forcing the wlock
619 * Test forcing the wlock
620
620
621 $ dolock -S &
621 $ dolock -S &
622 $ waitlock .hg/wlock
622 $ waitlock .hg/wlock
623
623
624 $ hg debuglocks
624 $ hg debuglocks
625 lock: free
625 lock: free
626 wlock: user *, process * (*s) (glob)
626 wlock: user *, process * (*s) (glob)
627 [1]
627 [1]
628
628
629 $ hg debuglocks -W
629 $ hg debuglocks -W
630
630
631 $ hg debuglocks
631 $ hg debuglocks
632 lock: free
632 lock: free
633 wlock: free
633 wlock: free
634
634
635 $ touch .hg/unlock
635 $ touch .hg/unlock
636 $ wait
636 $ wait
637
637
638 Test WdirUnsupported exception
638 Test WdirUnsupported exception
639
639
640 $ hg debugdata -c ffffffffffffffffffffffffffffffffffffffff
640 $ hg debugdata -c ffffffffffffffffffffffffffffffffffffffff
641 abort: working directory revision cannot be specified
641 abort: working directory revision cannot be specified
642 [255]
642 [255]
643
643
644 Test cache warming command
644 Test cache warming command
645
645
646 $ rm -rf .hg/cache/
646 $ rm -rf .hg/cache/
647 $ hg debugupdatecaches --debug
647 $ hg debugupdatecaches --debug
648 updating the branch cache
648 updating the branch cache
649 $ ls -r .hg/cache/*
649 $ ls -r .hg/cache/*
650 .hg/cache/tags2-served
650 .hg/cache/tags2-served
651 .hg/cache/tags2
651 .hg/cache/tags2
652 .hg/cache/rbc-revs-v1
652 .hg/cache/rbc-revs-v1
653 .hg/cache/rbc-names-v1
653 .hg/cache/rbc-names-v1
654 .hg/cache/hgtagsfnodes1
654 .hg/cache/hgtagsfnodes1
655 .hg/cache/branch2-visible-hidden
655 .hg/cache/branch2-visible-hidden
656 .hg/cache/branch2-visible
656 .hg/cache/branch2-visible
657 .hg/cache/branch2-served.hidden
657 .hg/cache/branch2-served.hidden
658 .hg/cache/branch2-served
658 .hg/cache/branch2-served
659 .hg/cache/branch2-immutable
659 .hg/cache/branch2-immutable
660 .hg/cache/branch2-base
660 .hg/cache/branch2-base
661
661
662 Test debug::unbundle
663
664 $ hg bundle --exact --rev tip foo.hg
665 1 changesets found
666 $ hg debug::unbundle foo.hg
667 adding changesets
668 adding manifests
669 adding file changes
670 added 0 changesets with 0 changes to 1 files (no-pure !)
671 9 local changesets published (no-pure !)
672 3 local changesets published (pure !)
673 (run 'hg update' to get a working copy)
674
662 Test debugcolor
675 Test debugcolor
663
676
664 #if no-windows
677 #if no-windows
665 $ hg debugcolor --style --color always | grep -E 'mode|style|log\.'
678 $ hg debugcolor --style --color always | grep -E 'mode|style|log\.'
666 color mode: 'ansi'
679 color mode: 'ansi'
667 available style:
680 available style:
668 \x1b[0;33mlog.changeset\x1b[0m: \x1b[0;33myellow\x1b[0m (esc)
681 \x1b[0;33mlog.changeset\x1b[0m: \x1b[0;33myellow\x1b[0m (esc)
669 #endif
682 #endif
670
683
671 $ hg debugcolor --style --color never
684 $ hg debugcolor --style --color never
672 color mode: None
685 color mode: None
673 available style:
686 available style:
674
687
675 $ cd ..
688 $ cd ..
676
689
677 Test internal debugstacktrace command
690 Test internal debugstacktrace command
678
691
679 $ cat > debugstacktrace.py << EOF
692 $ cat > debugstacktrace.py << EOF
680 > from mercurial import (
693 > from mercurial import (
681 > util,
694 > util,
682 > )
695 > )
683 > from mercurial.utils import (
696 > from mercurial.utils import (
684 > procutil,
697 > procutil,
685 > )
698 > )
686 > def f():
699 > def f():
687 > util.debugstacktrace(f=procutil.stdout)
700 > util.debugstacktrace(f=procutil.stdout)
688 > g()
701 > g()
689 > def g():
702 > def g():
690 > util.dst(b'hello from g\\n', skip=1)
703 > util.dst(b'hello from g\\n', skip=1)
691 > h()
704 > h()
692 > def h():
705 > def h():
693 > util.dst(b'hi ...\\nfrom h hidden in g', 1, depth=2)
706 > util.dst(b'hi ...\\nfrom h hidden in g', 1, depth=2)
694 > f()
707 > f()
695 > EOF
708 > EOF
696 $ "$PYTHON" debugstacktrace.py
709 $ "$PYTHON" debugstacktrace.py
697 stacktrace at:
710 stacktrace at:
698 *debugstacktrace.py:15 in * (glob)
711 *debugstacktrace.py:15 in * (glob)
699 *debugstacktrace.py:8 in f (glob)
712 *debugstacktrace.py:8 in f (glob)
700 hello from g at:
713 hello from g at:
701 *debugstacktrace.py:15 in * (glob)
714 *debugstacktrace.py:15 in * (glob)
702 *debugstacktrace.py:9 in f (glob)
715 *debugstacktrace.py:9 in f (glob)
703 hi ...
716 hi ...
704 from h hidden in g at:
717 from h hidden in g at:
705 *debugstacktrace.py:9 in f (glob)
718 *debugstacktrace.py:9 in f (glob)
706 *debugstacktrace.py:12 in g (glob)
719 *debugstacktrace.py:12 in g (glob)
707
720
708 Test debugcapabilities command:
721 Test debugcapabilities command:
709
722
710 $ hg debugcapabilities ./debugrevlog/
723 $ hg debugcapabilities ./debugrevlog/
711 Main capabilities:
724 Main capabilities:
712 branchmap
725 branchmap
713 $USUAL_BUNDLE2_CAPS$
726 $USUAL_BUNDLE2_CAPS$
714 getbundle
727 getbundle
715 known
728 known
716 lookup
729 lookup
717 pushkey
730 pushkey
718 unbundle
731 unbundle
719 Bundle2 capabilities:
732 Bundle2 capabilities:
720 HG20
733 HG20
721 bookmarks
734 bookmarks
722 changegroup
735 changegroup
723 01
736 01
724 02
737 02
725 03
738 03
726 checkheads
739 checkheads
727 related
740 related
728 digests
741 digests
729 md5
742 md5
730 sha1
743 sha1
731 sha512
744 sha512
732 error
745 error
733 abort
746 abort
734 unsupportedcontent
747 unsupportedcontent
735 pushraced
748 pushraced
736 pushkey
749 pushkey
737 hgtagsfnodes
750 hgtagsfnodes
738 listkeys
751 listkeys
739 phases
752 phases
740 heads
753 heads
741 pushkey
754 pushkey
742 remote-changegroup
755 remote-changegroup
743 http
756 http
744 https
757 https
745 stream
758 stream
746 v2
759 v2
747
760
748 Test debugpeer
761 Test debugpeer
749
762
750 $ hg debugpeer ssh://user@dummy/debugrevlog
763 $ hg debugpeer ssh://user@dummy/debugrevlog
751 url: ssh://user@dummy/debugrevlog
764 url: ssh://user@dummy/debugrevlog
752 local: no
765 local: no
753 pushable: yes
766 pushable: yes
754
767
755 #if rust
768 #if rust
756
769
757 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
770 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
758 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
771 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
759 devel-peer-request: hello+between
772 devel-peer-request: hello+between
760 devel-peer-request: pairs: 81 bytes
773 devel-peer-request: pairs: 81 bytes
761 sending hello command
774 sending hello command
762 sending between command
775 sending between command
763 remote: 473
776 remote: 473
764 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
777 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
765 remote: 1
778 remote: 1
766 devel-peer-request: protocaps
779 devel-peer-request: protocaps
767 devel-peer-request: caps: * bytes (glob)
780 devel-peer-request: caps: * bytes (glob)
768 sending protocaps command
781 sending protocaps command
769 url: ssh://user@dummy/debugrevlog
782 url: ssh://user@dummy/debugrevlog
770 local: no
783 local: no
771 pushable: yes
784 pushable: yes
772
785
773 #endif
786 #endif
774
787
775 #if no-rust zstd
788 #if no-rust zstd
776
789
777 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
790 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
778 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
791 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
779 devel-peer-request: hello+between
792 devel-peer-request: hello+between
780 devel-peer-request: pairs: 81 bytes
793 devel-peer-request: pairs: 81 bytes
781 sending hello command
794 sending hello command
782 sending between command
795 sending between command
783 remote: 473
796 remote: 473
784 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
797 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlog-compression-zstd,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
785 remote: 1
798 remote: 1
786 devel-peer-request: protocaps
799 devel-peer-request: protocaps
787 devel-peer-request: caps: * bytes (glob)
800 devel-peer-request: caps: * bytes (glob)
788 sending protocaps command
801 sending protocaps command
789 url: ssh://user@dummy/debugrevlog
802 url: ssh://user@dummy/debugrevlog
790 local: no
803 local: no
791 pushable: yes
804 pushable: yes
792
805
793 #endif
806 #endif
794
807
795 #if no-rust no-zstd
808 #if no-rust no-zstd
796
809
797 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
810 $ hg --debug debugpeer ssh://user@dummy/debugrevlog
798 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
811 running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R debugrevlog serve --stdio['"] (re)
799 devel-peer-request: hello+between
812 devel-peer-request: hello+between
800 devel-peer-request: pairs: 81 bytes
813 devel-peer-request: pairs: 81 bytes
801 sending hello command
814 sending hello command
802 sending between command
815 sending between command
803 remote: 449
816 remote: 449
804 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
817 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
805 remote: 1
818 remote: 1
806 devel-peer-request: protocaps
819 devel-peer-request: protocaps
807 devel-peer-request: caps: * bytes (glob)
820 devel-peer-request: caps: * bytes (glob)
808 sending protocaps command
821 sending protocaps command
809 url: ssh://user@dummy/debugrevlog
822 url: ssh://user@dummy/debugrevlog
810 local: no
823 local: no
811 pushable: yes
824 pushable: yes
812
825
813 #endif
826 #endif
814
827
815 Test debugshell
828 Test debugshell
816
829
817 $ hg debugshell -c 'ui.write(b"%s\n" % ui.username())'
830 $ hg debugshell -c 'ui.write(b"%s\n" % ui.username())'
818 test
831 test
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now