##// END OF EJS Templates
graft: minor copyediting of the help text for the `--to` argument...
Matt Harbison -
r53414:700086cf default
parent child Browse files
Show More
@@ -1,7686 +1,7686
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 from __future__ import annotations
8 from __future__ import annotations
9
9
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullid,
17 nullid,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 wdirrev,
20 wdirrev,
21 )
21 )
22 from . import (
22 from . import (
23 admin_commands as admin_commands_mod,
23 admin_commands as admin_commands_mod,
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 bundlecaches,
27 bundlecaches,
28 changegroup,
28 changegroup,
29 cmdutil,
29 cmdutil,
30 copies,
30 copies,
31 debugcommands as debugcommandsmod,
31 debugcommands as debugcommandsmod,
32 destutil,
32 destutil,
33 diffutil,
33 diffutil,
34 discovery,
34 discovery,
35 encoding,
35 encoding,
36 error,
36 error,
37 exchange,
37 exchange,
38 extensions,
38 extensions,
39 filemerge,
39 filemerge,
40 formatter,
40 formatter,
41 graphmod,
41 graphmod,
42 grep as grepmod,
42 grep as grepmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 mergestate as mergestatemod,
48 mergestate as mergestatemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 registrar,
55 registrar,
56 revsetlang,
56 revsetlang,
57 rewriteutil,
57 rewriteutil,
58 scmutil,
58 scmutil,
59 server,
59 server,
60 shelve as shelvemod,
60 shelve as shelvemod,
61 state as statemod,
61 state as statemod,
62 tags as tagsmod,
62 tags as tagsmod,
63 util,
63 util,
64 verify as verifymod,
64 verify as verifymod,
65 wireprotoserver,
65 wireprotoserver,
66 )
66 )
67
67
68 from .cmd_impls import graft as graft_impl
68 from .cmd_impls import graft as graft_impl
69 from .configuration import (
69 from .configuration import (
70 command as config_command,
70 command as config_command,
71 )
71 )
72 from .utils import (
72 from .utils import (
73 dateutil,
73 dateutil,
74 procutil,
74 procutil,
75 stringutil,
75 stringutil,
76 urlutil,
76 urlutil,
77 )
77 )
78
78
79 table = {}
79 table = {}
80 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
81 table.update(admin_commands_mod.command._table)
81 table.update(admin_commands_mod.command._table)
82
82
83 command = registrar.command(table)
83 command = registrar.command(table)
84 INTENT_READONLY = registrar.INTENT_READONLY
84 INTENT_READONLY = registrar.INTENT_READONLY
85
85
86 # common command options
86 # common command options
87
87
88 globalopts = [
88 globalopts = [
89 (
89 (
90 b'R',
90 b'R',
91 b'repository',
91 b'repository',
92 b'',
92 b'',
93 _(b'repository root directory or name of overlay bundle file'),
93 _(b'repository root directory or name of overlay bundle file'),
94 _(b'REPO'),
94 _(b'REPO'),
95 ),
95 ),
96 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
97 (
97 (
98 b'y',
98 b'y',
99 b'noninteractive',
99 b'noninteractive',
100 None,
100 None,
101 _(
101 _(
102 b'do not prompt, automatically pick the first choice for all prompts'
102 b'do not prompt, automatically pick the first choice for all prompts'
103 ),
103 ),
104 ),
104 ),
105 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'q', b'quiet', None, _(b'suppress output')),
106 (b'v', b'verbose', None, _(b'enable additional output')),
106 (b'v', b'verbose', None, _(b'enable additional output')),
107 (
107 (
108 b'',
108 b'',
109 b'color',
109 b'color',
110 b'',
110 b'',
111 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
112 # and should not be translated
112 # and should not be translated
113 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b"when to colorize (boolean, always, auto, never, or debug)"),
114 _(b'TYPE'),
114 _(b'TYPE'),
115 ),
115 ),
116 (
116 (
117 b'',
117 b'',
118 b'config',
118 b'config',
119 [],
119 [],
120 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'set/override config option (use \'section.name=value\')'),
121 _(b'CONFIG'),
121 _(b'CONFIG'),
122 ),
122 ),
123 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debug', None, _(b'enable debugging output')),
124 (b'', b'debugger', None, _(b'start debugger')),
124 (b'', b'debugger', None, _(b'start debugger')),
125 (
125 (
126 b'',
126 b'',
127 b'encoding',
127 b'encoding',
128 encoding.encoding,
128 encoding.encoding,
129 _(b'set the charset encoding'),
129 _(b'set the charset encoding'),
130 _(b'ENCODE'),
130 _(b'ENCODE'),
131 ),
131 ),
132 (
132 (
133 b'',
133 b'',
134 b'encodingmode',
134 b'encodingmode',
135 encoding.encodingmode,
135 encoding.encodingmode,
136 _(b'set the charset encoding mode'),
136 _(b'set the charset encoding mode'),
137 _(b'MODE'),
137 _(b'MODE'),
138 ),
138 ),
139 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'traceback', None, _(b'always print a traceback on exception')),
140 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'time', None, _(b'time how long the command takes')),
141 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'profile', None, _(b'print command execution profile')),
142 (b'', b'version', None, _(b'output version information and exit')),
142 (b'', b'version', None, _(b'output version information and exit')),
143 (b'h', b'help', None, _(b'display help and exit')),
143 (b'h', b'help', None, _(b'display help and exit')),
144 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (b'', b'hidden', False, _(b'consider hidden changesets')),
145 (
145 (
146 b'',
146 b'',
147 b'pager',
147 b'pager',
148 b'auto',
148 b'auto',
149 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b"when to paginate (boolean, always, auto, or never)"),
150 _(b'TYPE'),
150 _(b'TYPE'),
151 ),
151 ),
152 ]
152 ]
153
153
154 dryrunopts = cmdutil.dryrunopts
154 dryrunopts = cmdutil.dryrunopts
155 remoteopts = cmdutil.remoteopts
155 remoteopts = cmdutil.remoteopts
156 walkopts = cmdutil.walkopts
156 walkopts = cmdutil.walkopts
157 commitopts = cmdutil.commitopts
157 commitopts = cmdutil.commitopts
158 commitopts2 = cmdutil.commitopts2
158 commitopts2 = cmdutil.commitopts2
159 commitopts3 = cmdutil.commitopts3
159 commitopts3 = cmdutil.commitopts3
160 formatteropts = cmdutil.formatteropts
160 formatteropts = cmdutil.formatteropts
161 templateopts = cmdutil.templateopts
161 templateopts = cmdutil.templateopts
162 logopts = cmdutil.logopts
162 logopts = cmdutil.logopts
163 diffopts = cmdutil.diffopts
163 diffopts = cmdutil.diffopts
164 diffwsopts = cmdutil.diffwsopts
164 diffwsopts = cmdutil.diffwsopts
165 diffopts2 = cmdutil.diffopts2
165 diffopts2 = cmdutil.diffopts2
166 mergetoolopts = cmdutil.mergetoolopts
166 mergetoolopts = cmdutil.mergetoolopts
167 similarityopts = cmdutil.similarityopts
167 similarityopts = cmdutil.similarityopts
168 subrepoopts = cmdutil.subrepoopts
168 subrepoopts = cmdutil.subrepoopts
169 debugrevlogopts = cmdutil.debugrevlogopts
169 debugrevlogopts = cmdutil.debugrevlogopts
170
170
171 # Commands start here, listed alphabetically
171 # Commands start here, listed alphabetically
172
172
173
173
174 @command(
174 @command(
175 b'abort',
175 b'abort',
176 dryrunopts,
176 dryrunopts,
177 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
178 helpbasic=True,
178 helpbasic=True,
179 )
179 )
180 def abort(ui, repo, **opts):
180 def abort(ui, repo, **opts):
181 """abort an unfinished operation (EXPERIMENTAL)
181 """abort an unfinished operation (EXPERIMENTAL)
182
182
183 Aborts a multistep operation like graft, histedit, rebase, merge,
183 Aborts a multistep operation like graft, histedit, rebase, merge,
184 and unshelve if they are in an unfinished state.
184 and unshelve if they are in an unfinished state.
185
185
186 use --dry-run/-n to dry run the command.
186 use --dry-run/-n to dry run the command.
187 """
187 """
188 dryrun = opts.get('dry_run')
188 dryrun = opts.get('dry_run')
189 abortstate = cmdutil.getunfinishedstate(repo)
189 abortstate = cmdutil.getunfinishedstate(repo)
190 if not abortstate:
190 if not abortstate:
191 raise error.StateError(_(b'no operation in progress'))
191 raise error.StateError(_(b'no operation in progress'))
192 if not abortstate.abortfunc:
192 if not abortstate.abortfunc:
193 raise error.InputError(
193 raise error.InputError(
194 (
194 (
195 _(b"%s in progress but does not support 'hg abort'")
195 _(b"%s in progress but does not support 'hg abort'")
196 % (abortstate._opname)
196 % (abortstate._opname)
197 ),
197 ),
198 hint=abortstate.hint(),
198 hint=abortstate.hint(),
199 )
199 )
200 if dryrun:
200 if dryrun:
201 ui.status(
201 ui.status(
202 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
203 )
203 )
204 return
204 return
205 return abortstate.abortfunc(ui, repo)
205 return abortstate.abortfunc(ui, repo)
206
206
207
207
208 @command(
208 @command(
209 b'add',
209 b'add',
210 walkopts + subrepoopts + dryrunopts,
210 walkopts + subrepoopts + dryrunopts,
211 _(b'[OPTION]... [FILE]...'),
211 _(b'[OPTION]... [FILE]...'),
212 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
213 helpbasic=True,
213 helpbasic=True,
214 inferrepo=True,
214 inferrepo=True,
215 )
215 )
216 def add(ui, repo, *pats, **opts):
216 def add(ui, repo, *pats, **opts):
217 """add the specified files on the next commit
217 """add the specified files on the next commit
218
218
219 Schedule files to be version controlled and added to the
219 Schedule files to be version controlled and added to the
220 repository.
220 repository.
221
221
222 The files will be added to the repository at the next commit. To
222 The files will be added to the repository at the next commit. To
223 undo an add before that, see :hg:`forget`.
223 undo an add before that, see :hg:`forget`.
224
224
225 If no names are given, add all files to the repository (except
225 If no names are given, add all files to the repository (except
226 files matching ``.hgignore``).
226 files matching ``.hgignore``).
227
227
228 .. container:: verbose
228 .. container:: verbose
229
229
230 Examples:
230 Examples:
231
231
232 - New (unknown) files are added
232 - New (unknown) files are added
233 automatically by :hg:`add`::
233 automatically by :hg:`add`::
234
234
235 $ ls
235 $ ls
236 foo.c
236 foo.c
237 $ hg status
237 $ hg status
238 ? foo.c
238 ? foo.c
239 $ hg add
239 $ hg add
240 adding foo.c
240 adding foo.c
241 $ hg status
241 $ hg status
242 A foo.c
242 A foo.c
243
243
244 - Specific files to be added can be specified::
244 - Specific files to be added can be specified::
245
245
246 $ ls
246 $ ls
247 bar.c foo.c
247 bar.c foo.c
248 $ hg status
248 $ hg status
249 ? bar.c
249 ? bar.c
250 ? foo.c
250 ? foo.c
251 $ hg add bar.c
251 $ hg add bar.c
252 $ hg status
252 $ hg status
253 A bar.c
253 A bar.c
254 ? foo.c
254 ? foo.c
255
255
256 Returns 0 if all files are successfully added.
256 Returns 0 if all files are successfully added.
257 """
257 """
258
258
259 with repo.wlock(), repo.dirstate.changing_files(repo):
259 with repo.wlock(), repo.dirstate.changing_files(repo):
260 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
260 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
261 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
261 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
262 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
262 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
263 return rejected and 1 or 0
263 return rejected and 1 or 0
264
264
265
265
266 @command(
266 @command(
267 b'addremove',
267 b'addremove',
268 similarityopts + subrepoopts + walkopts + dryrunopts,
268 similarityopts + subrepoopts + walkopts + dryrunopts,
269 _(b'[OPTION]... [FILE]...'),
269 _(b'[OPTION]... [FILE]...'),
270 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
270 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
271 inferrepo=True,
271 inferrepo=True,
272 )
272 )
273 def addremove(ui, repo, *pats, **opts):
273 def addremove(ui, repo, *pats, **opts):
274 """add all new files, delete all missing files
274 """add all new files, delete all missing files
275
275
276 Add all new files and remove all missing files from the
276 Add all new files and remove all missing files from the
277 repository.
277 repository.
278
278
279 Unless names are given, new files are ignored if they match any of
279 Unless names are given, new files are ignored if they match any of
280 the patterns in ``.hgignore``. As with add, these changes take
280 the patterns in ``.hgignore``. As with add, these changes take
281 effect at the next commit.
281 effect at the next commit.
282
282
283 Use the -s/--similarity option to detect renamed files. This
283 Use the -s/--similarity option to detect renamed files. This
284 option takes a percentage between 0 (disabled) and 100 (files must
284 option takes a percentage between 0 (disabled) and 100 (files must
285 be identical) as its parameter. With a parameter greater than 0,
285 be identical) as its parameter. With a parameter greater than 0,
286 this compares every removed file with every added file and records
286 this compares every removed file with every added file and records
287 those similar enough as renames. Detecting renamed files this way
287 those similar enough as renames. Detecting renamed files this way
288 can be expensive. After using this option, :hg:`status -C` can be
288 can be expensive. After using this option, :hg:`status -C` can be
289 used to check which files were identified as moved or renamed. If
289 used to check which files were identified as moved or renamed. If
290 not specified, -s/--similarity defaults to 100 and only renames of
290 not specified, -s/--similarity defaults to 100 and only renames of
291 identical files are detected.
291 identical files are detected.
292
292
293 .. container:: verbose
293 .. container:: verbose
294
294
295 Examples:
295 Examples:
296
296
297 - A number of files (bar.c and foo.c) are new,
297 - A number of files (bar.c and foo.c) are new,
298 while foobar.c has been removed (without using :hg:`remove`)
298 while foobar.c has been removed (without using :hg:`remove`)
299 from the repository::
299 from the repository::
300
300
301 $ ls
301 $ ls
302 bar.c foo.c
302 bar.c foo.c
303 $ hg status
303 $ hg status
304 ! foobar.c
304 ! foobar.c
305 ? bar.c
305 ? bar.c
306 ? foo.c
306 ? foo.c
307 $ hg addremove
307 $ hg addremove
308 adding bar.c
308 adding bar.c
309 adding foo.c
309 adding foo.c
310 removing foobar.c
310 removing foobar.c
311 $ hg status
311 $ hg status
312 A bar.c
312 A bar.c
313 A foo.c
313 A foo.c
314 R foobar.c
314 R foobar.c
315
315
316 - A file foobar.c was moved to foo.c without using :hg:`rename`.
316 - A file foobar.c was moved to foo.c without using :hg:`rename`.
317 Afterwards, it was edited slightly::
317 Afterwards, it was edited slightly::
318
318
319 $ ls
319 $ ls
320 foo.c
320 foo.c
321 $ hg status
321 $ hg status
322 ! foobar.c
322 ! foobar.c
323 ? foo.c
323 ? foo.c
324 $ hg addremove --similarity 90
324 $ hg addremove --similarity 90
325 removing foobar.c
325 removing foobar.c
326 adding foo.c
326 adding foo.c
327 recording removal of foobar.c as rename to foo.c (94% similar)
327 recording removal of foobar.c as rename to foo.c (94% similar)
328 $ hg status -C
328 $ hg status -C
329 A foo.c
329 A foo.c
330 foobar.c
330 foobar.c
331 R foobar.c
331 R foobar.c
332
332
333 Returns 0 if all files are successfully added.
333 Returns 0 if all files are successfully added.
334 """
334 """
335 opts = pycompat.byteskwargs(opts)
335 opts = pycompat.byteskwargs(opts)
336 if not opts.get(b'similarity'):
336 if not opts.get(b'similarity'):
337 opts[b'similarity'] = b'100'
337 opts[b'similarity'] = b'100'
338 with repo.wlock(), repo.dirstate.changing_files(repo):
338 with repo.wlock(), repo.dirstate.changing_files(repo):
339 matcher = scmutil.match(repo[None], pats, opts)
339 matcher = scmutil.match(repo[None], pats, opts)
340 relative = scmutil.anypats(pats, opts)
340 relative = scmutil.anypats(pats, opts)
341 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
341 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
342 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
342 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
343
343
344
344
345 @command(
345 @command(
346 b'annotate|blame',
346 b'annotate|blame',
347 [
347 [
348 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
348 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
349 (
349 (
350 b'',
350 b'',
351 b'follow',
351 b'follow',
352 None,
352 None,
353 _(b'follow copies/renames and list the filename (DEPRECATED)'),
353 _(b'follow copies/renames and list the filename (DEPRECATED)'),
354 ),
354 ),
355 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
355 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
356 (b'a', b'text', None, _(b'treat all files as text')),
356 (b'a', b'text', None, _(b'treat all files as text')),
357 (b'u', b'user', None, _(b'list the author (long with -v)')),
357 (b'u', b'user', None, _(b'list the author (long with -v)')),
358 (b'f', b'file', None, _(b'list the filename')),
358 (b'f', b'file', None, _(b'list the filename')),
359 (b'd', b'date', None, _(b'list the date (short with -q)')),
359 (b'd', b'date', None, _(b'list the date (short with -q)')),
360 (b'n', b'number', None, _(b'list the revision number (default)')),
360 (b'n', b'number', None, _(b'list the revision number (default)')),
361 (b'c', b'changeset', None, _(b'list the changeset')),
361 (b'c', b'changeset', None, _(b'list the changeset')),
362 (
362 (
363 b'l',
363 b'l',
364 b'line-number',
364 b'line-number',
365 None,
365 None,
366 _(b'show line number at the first appearance'),
366 _(b'show line number at the first appearance'),
367 ),
367 ),
368 (
368 (
369 b'',
369 b'',
370 b'skip',
370 b'skip',
371 [],
371 [],
372 _(b'revset to not display (EXPERIMENTAL)'),
372 _(b'revset to not display (EXPERIMENTAL)'),
373 _(b'REV'),
373 _(b'REV'),
374 ),
374 ),
375 (
375 (
376 b'L',
376 b'L',
377 b'line-range',
377 b'line-range',
378 [],
378 [],
379 _(b'follow line range of specified file (EXPERIMENTAL)'),
379 _(b'follow line range of specified file (EXPERIMENTAL)'),
380 _(b'FILE,RANGE'),
380 _(b'FILE,RANGE'),
381 ),
381 ),
382 ]
382 ]
383 + diffwsopts
383 + diffwsopts
384 + walkopts
384 + walkopts
385 + formatteropts,
385 + formatteropts,
386 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
386 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
387 helpcategory=command.CATEGORY_FILE_CONTENTS,
387 helpcategory=command.CATEGORY_FILE_CONTENTS,
388 helpbasic=True,
388 helpbasic=True,
389 inferrepo=True,
389 inferrepo=True,
390 )
390 )
391 def annotate(ui, repo, *pats, **opts):
391 def annotate(ui, repo, *pats, **opts):
392 """show changeset information by line for each file
392 """show changeset information by line for each file
393
393
394 List changes in files, showing the revision id responsible for
394 List changes in files, showing the revision id responsible for
395 each line.
395 each line.
396
396
397 This command is useful for discovering when a change was made and
397 This command is useful for discovering when a change was made and
398 by whom.
398 by whom.
399
399
400 If you include --file, --user, or --date, the revision number is
400 If you include --file, --user, or --date, the revision number is
401 suppressed unless you also include --number.
401 suppressed unless you also include --number.
402
402
403 Without the -a/--text option, annotate will avoid processing files
403 Without the -a/--text option, annotate will avoid processing files
404 it detects as binary. With -a, annotate will annotate the file
404 it detects as binary. With -a, annotate will annotate the file
405 anyway, although the results will probably be neither useful
405 anyway, although the results will probably be neither useful
406 nor desirable.
406 nor desirable.
407
407
408 .. container:: verbose
408 .. container:: verbose
409
409
410 Use -L/--line-range FILE,M:N options to filter the output to the lines
410 Use -L/--line-range FILE,M:N options to filter the output to the lines
411 from M to N in FILE. This option is incompatible with --no-follow and
411 from M to N in FILE. This option is incompatible with --no-follow and
412 cannot be combined with file pattern arguments. When combined with --rev
412 cannot be combined with file pattern arguments. When combined with --rev
413 the line ranges refer to the state of the file at the requested revision.
413 the line ranges refer to the state of the file at the requested revision.
414
414
415 .. container:: verbose
415 .. container:: verbose
416
416
417 Template:
417 Template:
418
418
419 The following keywords are supported in addition to the common template
419 The following keywords are supported in addition to the common template
420 keywords and functions. See also :hg:`help templates`.
420 keywords and functions. See also :hg:`help templates`.
421
421
422 :lines: List of lines with annotation data.
422 :lines: List of lines with annotation data.
423 :path: String. Repository-absolute path of the specified file.
423 :path: String. Repository-absolute path of the specified file.
424
424
425 And each entry of ``{lines}`` provides the following sub-keywords in
425 And each entry of ``{lines}`` provides the following sub-keywords in
426 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
426 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
427
427
428 :line: String. Line content.
428 :line: String. Line content.
429 :lineno: Integer. Line number at that revision.
429 :lineno: Integer. Line number at that revision.
430 :path: String. Repository-absolute path of the file at that revision.
430 :path: String. Repository-absolute path of the file at that revision.
431
431
432 See :hg:`help templates.operators` for the list expansion syntax.
432 See :hg:`help templates.operators` for the list expansion syntax.
433
433
434 Returns 0 on success.
434 Returns 0 on success.
435 """
435 """
436 opts = pycompat.byteskwargs(opts)
436 opts = pycompat.byteskwargs(opts)
437
437
438 linerange = opts.get(b'line_range')
438 linerange = opts.get(b'line_range')
439
439
440 if linerange and opts.get(b'no_follow'):
440 if linerange and opts.get(b'no_follow'):
441 raise error.InputError(
441 raise error.InputError(
442 _(b'--line-range is incompatible with --no-follow')
442 _(b'--line-range is incompatible with --no-follow')
443 )
443 )
444
444
445 if pats and linerange:
445 if pats and linerange:
446 raise error.InputError(
446 raise error.InputError(
447 _(b'cannot combine filename or pattern and --line-range')
447 _(b'cannot combine filename or pattern and --line-range')
448 )
448 )
449
449
450 if not pats and not linerange:
450 if not pats and not linerange:
451 raise error.InputError(
451 raise error.InputError(
452 _(b'at least one filename or pattern is required')
452 _(b'at least one filename or pattern is required')
453 )
453 )
454
454
455 if opts.get(b'follow'):
455 if opts.get(b'follow'):
456 # --follow is deprecated and now just an alias for -f/--file
456 # --follow is deprecated and now just an alias for -f/--file
457 # to mimic the behavior of Mercurial before version 1.5
457 # to mimic the behavior of Mercurial before version 1.5
458 opts[b'file'] = True
458 opts[b'file'] = True
459
459
460 if (
460 if (
461 not opts.get(b'user')
461 not opts.get(b'user')
462 and not opts.get(b'changeset')
462 and not opts.get(b'changeset')
463 and not opts.get(b'date')
463 and not opts.get(b'date')
464 and not opts.get(b'file')
464 and not opts.get(b'file')
465 ):
465 ):
466 opts[b'number'] = True
466 opts[b'number'] = True
467
467
468 linenumber = opts.get(b'line_number') is not None
468 linenumber = opts.get(b'line_number') is not None
469 if (
469 if (
470 linenumber
470 linenumber
471 and (not opts.get(b'changeset'))
471 and (not opts.get(b'changeset'))
472 and (not opts.get(b'number'))
472 and (not opts.get(b'number'))
473 ):
473 ):
474 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
474 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
475
475
476 rev = opts.get(b'rev')
476 rev = opts.get(b'rev')
477 if rev:
477 if rev:
478 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
478 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
479 ctx = logcmdutil.revsingle(repo, rev)
479 ctx = logcmdutil.revsingle(repo, rev)
480
480
481 if not pats:
481 if not pats:
482 pats = [
482 pats = [
483 fname
483 fname
484 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
484 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
485 ]
485 ]
486
486
487 ui.pager(b'annotate')
487 ui.pager(b'annotate')
488 rootfm = ui.formatter(b'annotate', opts)
488 rootfm = ui.formatter(b'annotate', opts)
489 if ui.debugflag:
489 if ui.debugflag:
490 shorthex = pycompat.identity
490 shorthex = pycompat.identity
491 else:
491 else:
492
492
493 def shorthex(h):
493 def shorthex(h):
494 return h[:12]
494 return h[:12]
495
495
496 if ui.quiet:
496 if ui.quiet:
497 datefunc = dateutil.shortdate
497 datefunc = dateutil.shortdate
498 else:
498 else:
499 datefunc = dateutil.datestr
499 datefunc = dateutil.datestr
500 if ctx.rev() is None:
500 if ctx.rev() is None:
501 if opts.get(b'changeset'):
501 if opts.get(b'changeset'):
502 # omit "+" suffix which is appended to node hex
502 # omit "+" suffix which is appended to node hex
503 def formatrev(rev):
503 def formatrev(rev):
504 if rev == wdirrev:
504 if rev == wdirrev:
505 return b'%d' % ctx.p1().rev()
505 return b'%d' % ctx.p1().rev()
506 else:
506 else:
507 return b'%d' % rev
507 return b'%d' % rev
508
508
509 else:
509 else:
510
510
511 def formatrev(rev):
511 def formatrev(rev):
512 if rev == wdirrev:
512 if rev == wdirrev:
513 return b'%d+' % ctx.p1().rev()
513 return b'%d+' % ctx.p1().rev()
514 else:
514 else:
515 return b'%d ' % rev
515 return b'%d ' % rev
516
516
517 def formathex(h):
517 def formathex(h):
518 if h == repo.nodeconstants.wdirhex:
518 if h == repo.nodeconstants.wdirhex:
519 return b'%s+' % shorthex(hex(ctx.p1().node()))
519 return b'%s+' % shorthex(hex(ctx.p1().node()))
520 else:
520 else:
521 return b'%s ' % shorthex(h)
521 return b'%s ' % shorthex(h)
522
522
523 else:
523 else:
524 formatrev = b'%d'.__mod__
524 formatrev = b'%d'.__mod__
525 formathex = shorthex
525 formathex = shorthex
526
526
527 opmap = [
527 opmap = [
528 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
528 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
529 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
529 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
530 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
530 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
531 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
531 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
532 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
532 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
533 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
533 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
534 ]
534 ]
535 opnamemap = {
535 opnamemap = {
536 b'rev': b'number',
536 b'rev': b'number',
537 b'node': b'changeset',
537 b'node': b'changeset',
538 b'path': b'file',
538 b'path': b'file',
539 b'lineno': b'line_number',
539 b'lineno': b'line_number',
540 }
540 }
541
541
542 if rootfm.isplain():
542 if rootfm.isplain():
543
543
544 def makefunc(get, fmt):
544 def makefunc(get, fmt):
545 return lambda x: fmt(get(x))
545 return lambda x: fmt(get(x))
546
546
547 else:
547 else:
548
548
549 def makefunc(get, fmt):
549 def makefunc(get, fmt):
550 return get
550 return get
551
551
552 datahint = rootfm.datahint()
552 datahint = rootfm.datahint()
553 funcmap = [
553 funcmap = [
554 (makefunc(get, fmt), sep)
554 (makefunc(get, fmt), sep)
555 for fn, sep, get, fmt in opmap
555 for fn, sep, get, fmt in opmap
556 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
556 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
557 ]
557 ]
558 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
558 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
559 fields = b' '.join(
559 fields = b' '.join(
560 fn
560 fn
561 for fn, sep, get, fmt in opmap
561 for fn, sep, get, fmt in opmap
562 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
562 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
563 )
563 )
564
564
565 def bad(x, y):
565 def bad(x, y):
566 raise error.InputError(b"%s: %s" % (x, y))
566 raise error.InputError(b"%s: %s" % (x, y))
567
567
568 m = scmutil.match(ctx, pats, opts, badfn=bad)
568 m = scmutil.match(ctx, pats, opts, badfn=bad)
569
569
570 follow = not opts.get(b'no_follow')
570 follow = not opts.get(b'no_follow')
571 diffopts = patch.difffeatureopts(
571 diffopts = patch.difffeatureopts(
572 ui, opts, section=b'annotate', whitespace=True
572 ui, opts, section=b'annotate', whitespace=True
573 )
573 )
574 skiprevs = opts.get(b'skip')
574 skiprevs = opts.get(b'skip')
575 if skiprevs:
575 if skiprevs:
576 skiprevs = logcmdutil.revrange(repo, skiprevs)
576 skiprevs = logcmdutil.revrange(repo, skiprevs)
577
577
578 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
578 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
579 for abs in ctx.walk(m):
579 for abs in ctx.walk(m):
580 fctx = ctx[abs]
580 fctx = ctx[abs]
581 rootfm.startitem()
581 rootfm.startitem()
582 rootfm.data(path=abs)
582 rootfm.data(path=abs)
583 if not opts.get(b'text') and fctx.isbinary():
583 if not opts.get(b'text') and fctx.isbinary():
584 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
584 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
585 continue
585 continue
586
586
587 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
587 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
588 lines = fctx.annotate(
588 lines = fctx.annotate(
589 follow=follow, skiprevs=skiprevs, diffopts=diffopts
589 follow=follow, skiprevs=skiprevs, diffopts=diffopts
590 )
590 )
591 if linerange:
591 if linerange:
592 _fname, (line_start, line_end) = list(
592 _fname, (line_start, line_end) = list(
593 logcmdutil._parselinerangeopt(repo, opts)
593 logcmdutil._parselinerangeopt(repo, opts)
594 )[0]
594 )[0]
595 lines = [
595 lines = [
596 line
596 line
597 for no, line in enumerate(lines)
597 for no, line in enumerate(lines)
598 if line_start <= no < line_end
598 if line_start <= no < line_end
599 ]
599 ]
600
600
601 if not lines:
601 if not lines:
602 fm.end()
602 fm.end()
603 continue
603 continue
604 formats = []
604 formats = []
605 pieces = []
605 pieces = []
606
606
607 for f, sep in funcmap:
607 for f, sep in funcmap:
608 l = [f(n) for n in lines]
608 l = [f(n) for n in lines]
609 if fm.isplain():
609 if fm.isplain():
610 sizes = [encoding.colwidth(x) for x in l]
610 sizes = [encoding.colwidth(x) for x in l]
611 ml = max(sizes)
611 ml = max(sizes)
612 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
612 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
613 else:
613 else:
614 formats.append([b'%s'] * len(l))
614 formats.append([b'%s'] * len(l))
615 pieces.append(l)
615 pieces.append(l)
616
616
617 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
617 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
618 fm.startitem()
618 fm.startitem()
619 fm.context(fctx=n.fctx)
619 fm.context(fctx=n.fctx)
620 fm.write(fields, b"".join(f), *p)
620 fm.write(fields, b"".join(f), *p)
621 if n.skip:
621 if n.skip:
622 fmt = b"* %s"
622 fmt = b"* %s"
623 else:
623 else:
624 fmt = b": %s"
624 fmt = b": %s"
625 fm.write(b'line', fmt, n.text)
625 fm.write(b'line', fmt, n.text)
626
626
627 if not lines[-1].text.endswith(b'\n'):
627 if not lines[-1].text.endswith(b'\n'):
628 fm.plain(b'\n')
628 fm.plain(b'\n')
629 fm.end()
629 fm.end()
630
630
631 rootfm.end()
631 rootfm.end()
632
632
633
633
634 @command(
634 @command(
635 b'archive',
635 b'archive',
636 [
636 [
637 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
637 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
638 (
638 (
639 b'p',
639 b'p',
640 b'prefix',
640 b'prefix',
641 b'',
641 b'',
642 _(b'directory prefix for files in archive'),
642 _(b'directory prefix for files in archive'),
643 _(b'PREFIX'),
643 _(b'PREFIX'),
644 ),
644 ),
645 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
645 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
646 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
646 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
647 ]
647 ]
648 + subrepoopts
648 + subrepoopts
649 + walkopts,
649 + walkopts,
650 _(b'[OPTION]... DEST'),
650 _(b'[OPTION]... DEST'),
651 helpcategory=command.CATEGORY_IMPORT_EXPORT,
651 helpcategory=command.CATEGORY_IMPORT_EXPORT,
652 )
652 )
653 def archive(ui, repo, dest, **opts):
653 def archive(ui, repo, dest, **opts):
654 """create an unversioned archive of a repository revision
654 """create an unversioned archive of a repository revision
655
655
656 By default, the revision used is the parent of the working
656 By default, the revision used is the parent of the working
657 directory; use -r/--rev to specify a different revision.
657 directory; use -r/--rev to specify a different revision.
658
658
659 The archive type is automatically detected based on file
659 The archive type is automatically detected based on file
660 extension (to override, use -t/--type).
660 extension (to override, use -t/--type).
661
661
662 .. container:: verbose
662 .. container:: verbose
663
663
664 Examples:
664 Examples:
665
665
666 - create a zip file containing the 1.0 release::
666 - create a zip file containing the 1.0 release::
667
667
668 hg archive -r 1.0 project-1.0.zip
668 hg archive -r 1.0 project-1.0.zip
669
669
670 - create a tarball excluding .hg files::
670 - create a tarball excluding .hg files::
671
671
672 hg archive project.tar.gz -X ".hg*"
672 hg archive project.tar.gz -X ".hg*"
673
673
674 Valid types are:
674 Valid types are:
675
675
676 :``files``: a directory full of files (default)
676 :``files``: a directory full of files (default)
677 :``tar``: tar archive, uncompressed
677 :``tar``: tar archive, uncompressed
678 :``tbz2``: tar archive, compressed using bzip2
678 :``tbz2``: tar archive, compressed using bzip2
679 :``tgz``: tar archive, compressed using gzip
679 :``tgz``: tar archive, compressed using gzip
680 :``txz``: tar archive, compressed using lzma (only in Python 3)
680 :``txz``: tar archive, compressed using lzma (only in Python 3)
681 :``uzip``: zip archive, uncompressed
681 :``uzip``: zip archive, uncompressed
682 :``zip``: zip archive, compressed using deflate
682 :``zip``: zip archive, compressed using deflate
683
683
684 The exact name of the destination archive or directory is given
684 The exact name of the destination archive or directory is given
685 using a format string; see :hg:`help export` for details.
685 using a format string; see :hg:`help export` for details.
686
686
687 Each member added to an archive file has a directory prefix
687 Each member added to an archive file has a directory prefix
688 prepended. Use -p/--prefix to specify a format string for the
688 prepended. Use -p/--prefix to specify a format string for the
689 prefix. The default is the basename of the archive, with suffixes
689 prefix. The default is the basename of the archive, with suffixes
690 removed.
690 removed.
691
691
692 Returns 0 on success.
692 Returns 0 on success.
693 """
693 """
694
694
695 rev = opts.get('rev')
695 rev = opts.get('rev')
696 if rev:
696 if rev:
697 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
697 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
698 ctx = logcmdutil.revsingle(repo, rev)
698 ctx = logcmdutil.revsingle(repo, rev)
699 if not ctx:
699 if not ctx:
700 raise error.InputError(
700 raise error.InputError(
701 _(b'no working directory: please specify a revision')
701 _(b'no working directory: please specify a revision')
702 )
702 )
703 node = ctx.node()
703 node = ctx.node()
704 dest = cmdutil.makefilename(ctx, dest)
704 dest = cmdutil.makefilename(ctx, dest)
705 if os.path.realpath(dest) == repo.root:
705 if os.path.realpath(dest) == repo.root:
706 raise error.InputError(_(b'repository root cannot be destination'))
706 raise error.InputError(_(b'repository root cannot be destination'))
707
707
708 kind = opts.get('type') or archival.guesskind(dest) or b'files'
708 kind = opts.get('type') or archival.guesskind(dest) or b'files'
709 prefix = opts.get('prefix')
709 prefix = opts.get('prefix')
710
710
711 if dest == b'-':
711 if dest == b'-':
712 if kind == b'files':
712 if kind == b'files':
713 raise error.InputError(_(b'cannot archive plain files to stdout'))
713 raise error.InputError(_(b'cannot archive plain files to stdout'))
714 realdest = dest
714 realdest = dest
715 dest = lambda: cmdutil.makefileobj(ctx, realdest)
715 dest = lambda: cmdutil.makefileobj(ctx, realdest)
716 if not prefix:
716 if not prefix:
717 prefix = os.path.basename(repo.root) + b'-%h'
717 prefix = os.path.basename(repo.root) + b'-%h'
718
718
719 prefix = cmdutil.makefilename(ctx, prefix)
719 prefix = cmdutil.makefilename(ctx, prefix)
720 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
720 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
721 archival.archive(
721 archival.archive(
722 repo,
722 repo,
723 dest,
723 dest,
724 node,
724 node,
725 kind,
725 kind,
726 not opts.get('no_decode'),
726 not opts.get('no_decode'),
727 match,
727 match,
728 prefix,
728 prefix,
729 subrepos=opts.get('subrepos'),
729 subrepos=opts.get('subrepos'),
730 )
730 )
731
731
732
732
733 @command(
733 @command(
734 b'backout',
734 b'backout',
735 [
735 [
736 (
736 (
737 b'',
737 b'',
738 b'merge',
738 b'merge',
739 None,
739 None,
740 _(b'merge with old dirstate parent after backout'),
740 _(b'merge with old dirstate parent after backout'),
741 ),
741 ),
742 (
742 (
743 b'',
743 b'',
744 b'commit',
744 b'commit',
745 None,
745 None,
746 _(b'commit if no conflicts were encountered (DEPRECATED)'),
746 _(b'commit if no conflicts were encountered (DEPRECATED)'),
747 ),
747 ),
748 (b'', b'no-commit', None, _(b'do not commit')),
748 (b'', b'no-commit', None, _(b'do not commit')),
749 (
749 (
750 b'',
750 b'',
751 b'parent',
751 b'parent',
752 b'',
752 b'',
753 _(b'parent to choose when backing out merge (DEPRECATED)'),
753 _(b'parent to choose when backing out merge (DEPRECATED)'),
754 _(b'REV'),
754 _(b'REV'),
755 ),
755 ),
756 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
756 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
757 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
757 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
758 ]
758 ]
759 + mergetoolopts
759 + mergetoolopts
760 + walkopts
760 + walkopts
761 + commitopts
761 + commitopts
762 + commitopts2,
762 + commitopts2,
763 _(b'[OPTION]... [-r] REV'),
763 _(b'[OPTION]... [-r] REV'),
764 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
764 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
765 )
765 )
766 def backout(ui, repo, node=None, rev=None, **opts):
766 def backout(ui, repo, node=None, rev=None, **opts):
767 """reverse effect of earlier changeset
767 """reverse effect of earlier changeset
768
768
769 Prepare a new changeset with the effect of REV undone in the
769 Prepare a new changeset with the effect of REV undone in the
770 current working directory. If no conflicts were encountered,
770 current working directory. If no conflicts were encountered,
771 it will be committed immediately.
771 it will be committed immediately.
772
772
773 If REV is the parent of the working directory, then this new changeset
773 If REV is the parent of the working directory, then this new changeset
774 is committed automatically (unless --no-commit is specified).
774 is committed automatically (unless --no-commit is specified).
775
775
776 .. note::
776 .. note::
777
777
778 :hg:`backout` cannot be used to fix either an unwanted or
778 :hg:`backout` cannot be used to fix either an unwanted or
779 incorrect merge.
779 incorrect merge.
780
780
781 .. container:: verbose
781 .. container:: verbose
782
782
783 Examples:
783 Examples:
784
784
785 - Reverse the effect of the parent of the working directory.
785 - Reverse the effect of the parent of the working directory.
786 This backout will be committed immediately::
786 This backout will be committed immediately::
787
787
788 hg backout -r .
788 hg backout -r .
789
789
790 - Reverse the effect of previous bad revision 23::
790 - Reverse the effect of previous bad revision 23::
791
791
792 hg backout -r 23
792 hg backout -r 23
793
793
794 - Reverse the effect of previous bad revision 23 and
794 - Reverse the effect of previous bad revision 23 and
795 leave changes uncommitted::
795 leave changes uncommitted::
796
796
797 hg backout -r 23 --no-commit
797 hg backout -r 23 --no-commit
798 hg commit -m "Backout revision 23"
798 hg commit -m "Backout revision 23"
799
799
800 By default, the pending changeset will have one parent,
800 By default, the pending changeset will have one parent,
801 maintaining a linear history. With --merge, the pending
801 maintaining a linear history. With --merge, the pending
802 changeset will instead have two parents: the old parent of the
802 changeset will instead have two parents: the old parent of the
803 working directory and a new child of REV that simply undoes REV.
803 working directory and a new child of REV that simply undoes REV.
804
804
805 Before version 1.7, the behavior without --merge was equivalent
805 Before version 1.7, the behavior without --merge was equivalent
806 to specifying --merge followed by :hg:`update --clean .` to
806 to specifying --merge followed by :hg:`update --clean .` to
807 cancel the merge and leave the child of REV as a head to be
807 cancel the merge and leave the child of REV as a head to be
808 merged separately.
808 merged separately.
809
809
810 See :hg:`help dates` for a list of formats valid for -d/--date.
810 See :hg:`help dates` for a list of formats valid for -d/--date.
811
811
812 See :hg:`help revert` for a way to restore files to the state
812 See :hg:`help revert` for a way to restore files to the state
813 of another revision.
813 of another revision.
814
814
815 Returns 0 on success, 1 if nothing to backout or there are unresolved
815 Returns 0 on success, 1 if nothing to backout or there are unresolved
816 files.
816 files.
817 """
817 """
818 with repo.wlock(), repo.lock():
818 with repo.wlock(), repo.lock():
819 return _dobackout(ui, repo, node, rev, **opts)
819 return _dobackout(ui, repo, node, rev, **opts)
820
820
821
821
822 def _dobackout(ui, repo, node=None, rev=None, **opts):
822 def _dobackout(ui, repo, node=None, rev=None, **opts):
823 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
823 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
824
824
825 if rev and node:
825 if rev and node:
826 raise error.InputError(_(b"please specify just one revision"))
826 raise error.InputError(_(b"please specify just one revision"))
827
827
828 if not rev:
828 if not rev:
829 rev = node
829 rev = node
830
830
831 if not rev:
831 if not rev:
832 raise error.InputError(_(b"please specify a revision to backout"))
832 raise error.InputError(_(b"please specify a revision to backout"))
833
833
834 date = opts.get('date')
834 date = opts.get('date')
835 if date:
835 if date:
836 opts['date'] = dateutil.parsedate(date)
836 opts['date'] = dateutil.parsedate(date)
837
837
838 cmdutil.checkunfinished(repo)
838 cmdutil.checkunfinished(repo)
839 cmdutil.bailifchanged(repo)
839 cmdutil.bailifchanged(repo)
840 ctx = logcmdutil.revsingle(repo, rev)
840 ctx = logcmdutil.revsingle(repo, rev)
841 node = ctx.node()
841 node = ctx.node()
842
842
843 op1, op2 = repo.dirstate.parents()
843 op1, op2 = repo.dirstate.parents()
844 if not repo.changelog.isancestor(node, op1):
844 if not repo.changelog.isancestor(node, op1):
845 raise error.InputError(
845 raise error.InputError(
846 _(b'cannot backout change that is not an ancestor')
846 _(b'cannot backout change that is not an ancestor')
847 )
847 )
848
848
849 p1, p2 = repo.changelog.parents(node)
849 p1, p2 = repo.changelog.parents(node)
850 if p1 == repo.nullid:
850 if p1 == repo.nullid:
851 raise error.InputError(_(b'cannot backout a change with no parents'))
851 raise error.InputError(_(b'cannot backout a change with no parents'))
852 if p2 != repo.nullid:
852 if p2 != repo.nullid:
853 if not opts.get('parent'):
853 if not opts.get('parent'):
854 raise error.InputError(_(b'cannot backout a merge changeset'))
854 raise error.InputError(_(b'cannot backout a merge changeset'))
855 p = repo.lookup(opts['parent'])
855 p = repo.lookup(opts['parent'])
856 if p not in (p1, p2):
856 if p not in (p1, p2):
857 raise error.InputError(
857 raise error.InputError(
858 _(b'%s is not a parent of %s') % (short(p), short(node))
858 _(b'%s is not a parent of %s') % (short(p), short(node))
859 )
859 )
860 parent = p
860 parent = p
861 else:
861 else:
862 if opts.get('parent'):
862 if opts.get('parent'):
863 raise error.InputError(
863 raise error.InputError(
864 _(b'cannot use --parent on non-merge changeset')
864 _(b'cannot use --parent on non-merge changeset')
865 )
865 )
866 parent = p1
866 parent = p1
867
867
868 # the backout should appear on the same branch
868 # the backout should appear on the same branch
869 branch = repo.dirstate.branch()
869 branch = repo.dirstate.branch()
870 bheads = repo.branchheads(branch)
870 bheads = repo.branchheads(branch)
871 rctx = scmutil.revsingle(repo, hex(parent))
871 rctx = scmutil.revsingle(repo, hex(parent))
872 if not opts.get('merge') and op1 != node:
872 if not opts.get('merge') and op1 != node:
873 with repo.transaction(b"backout"):
873 with repo.transaction(b"backout"):
874 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
874 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
875 with ui.configoverride(overrides, b'backout'):
875 with ui.configoverride(overrides, b'backout'):
876 stats = mergemod.back_out(ctx, parent=repo[parent])
876 stats = mergemod.back_out(ctx, parent=repo[parent])
877 repo.setparents(op1, op2)
877 repo.setparents(op1, op2)
878 hg._showstats(repo, stats)
878 hg._showstats(repo, stats)
879 if stats.unresolvedcount:
879 if stats.unresolvedcount:
880 repo.ui.status(
880 repo.ui.status(
881 _(b"use 'hg resolve' to retry unresolved file merges\n")
881 _(b"use 'hg resolve' to retry unresolved file merges\n")
882 )
882 )
883 return 1
883 return 1
884 else:
884 else:
885 hg.clean(repo, node, show_stats=False)
885 hg.clean(repo, node, show_stats=False)
886 repo.dirstate.setbranch(branch, repo.currenttransaction())
886 repo.dirstate.setbranch(branch, repo.currenttransaction())
887 cmdutil.revert(ui, repo, rctx)
887 cmdutil.revert(ui, repo, rctx)
888
888
889 if opts.get('no_commit'):
889 if opts.get('no_commit'):
890 msg = _(b"changeset %s backed out, don't forget to commit.\n")
890 msg = _(b"changeset %s backed out, don't forget to commit.\n")
891 ui.status(msg % short(node))
891 ui.status(msg % short(node))
892 return 0
892 return 0
893
893
894 def commitfunc(ui, repo, message, match, opts):
894 def commitfunc(ui, repo, message, match, opts):
895 editform = b'backout'
895 editform = b'backout'
896 e = cmdutil.getcommiteditor(
896 e = cmdutil.getcommiteditor(
897 editform=editform, **pycompat.strkwargs(opts)
897 editform=editform, **pycompat.strkwargs(opts)
898 )
898 )
899 if not message:
899 if not message:
900 # we don't translate commit messages
900 # we don't translate commit messages
901 message = b"Backed out changeset %s" % short(node)
901 message = b"Backed out changeset %s" % short(node)
902 e = cmdutil.getcommiteditor(edit=True, editform=editform)
902 e = cmdutil.getcommiteditor(edit=True, editform=editform)
903 return repo.commit(
903 return repo.commit(
904 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
904 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
905 )
905 )
906
906
907 # save to detect changes
907 # save to detect changes
908 tip = repo.changelog.tip()
908 tip = repo.changelog.tip()
909
909
910 newnode = cmdutil.commit(
910 newnode = cmdutil.commit(
911 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
911 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
912 )
912 )
913 if not newnode:
913 if not newnode:
914 ui.status(_(b"nothing changed\n"))
914 ui.status(_(b"nothing changed\n"))
915 return 1
915 return 1
916 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
916 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
917
917
918 def nice(node):
918 def nice(node):
919 return b'%d:%s' % (repo.changelog.rev(node), short(node))
919 return b'%d:%s' % (repo.changelog.rev(node), short(node))
920
920
921 ui.status(
921 ui.status(
922 _(b'changeset %s backs out changeset %s\n')
922 _(b'changeset %s backs out changeset %s\n')
923 % (nice(newnode), nice(node))
923 % (nice(newnode), nice(node))
924 )
924 )
925 if opts.get('merge') and op1 != node:
925 if opts.get('merge') and op1 != node:
926 hg.clean(repo, op1, show_stats=False)
926 hg.clean(repo, op1, show_stats=False)
927 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
927 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
928 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
928 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
929 with ui.configoverride(overrides, b'backout'):
929 with ui.configoverride(overrides, b'backout'):
930 return hg.merge(repo[b'tip'])
930 return hg.merge(repo[b'tip'])
931 return 0
931 return 0
932
932
933
933
934 @command(
934 @command(
935 b'bisect',
935 b'bisect',
936 [
936 [
937 (b'r', b'reset', False, _(b'reset bisect state')),
937 (b'r', b'reset', False, _(b'reset bisect state')),
938 (b'g', b'good', False, _(b'mark changeset good')),
938 (b'g', b'good', False, _(b'mark changeset good')),
939 (b'b', b'bad', False, _(b'mark changeset bad')),
939 (b'b', b'bad', False, _(b'mark changeset bad')),
940 (b's', b'skip', False, _(b'skip testing changeset')),
940 (b's', b'skip', False, _(b'skip testing changeset')),
941 (b'e', b'extend', False, _(b'extend the bisect range')),
941 (b'e', b'extend', False, _(b'extend the bisect range')),
942 (
942 (
943 b'c',
943 b'c',
944 b'command',
944 b'command',
945 b'',
945 b'',
946 _(b'use command to check changeset state'),
946 _(b'use command to check changeset state'),
947 _(b'CMD'),
947 _(b'CMD'),
948 ),
948 ),
949 (b'U', b'noupdate', False, _(b'do not update to target')),
949 (b'U', b'noupdate', False, _(b'do not update to target')),
950 ],
950 ],
951 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
951 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
952 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
952 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
953 )
953 )
954 def bisect(
954 def bisect(
955 ui,
955 ui,
956 repo,
956 repo,
957 positional_1=None,
957 positional_1=None,
958 positional_2=None,
958 positional_2=None,
959 command=None,
959 command=None,
960 reset=None,
960 reset=None,
961 good=None,
961 good=None,
962 bad=None,
962 bad=None,
963 skip=None,
963 skip=None,
964 extend=None,
964 extend=None,
965 noupdate=None,
965 noupdate=None,
966 ):
966 ):
967 """subdivision search of changesets
967 """subdivision search of changesets
968
968
969 This command helps to find changesets which introduce problems. To
969 This command helps to find changesets which introduce problems. To
970 use, mark the earliest changeset you know exhibits the problem as
970 use, mark the earliest changeset you know exhibits the problem as
971 bad, then mark the latest changeset which is free from the problem
971 bad, then mark the latest changeset which is free from the problem
972 as good. Bisect will update your working directory to a revision
972 as good. Bisect will update your working directory to a revision
973 for testing (unless the -U/--noupdate option is specified). Once
973 for testing (unless the -U/--noupdate option is specified). Once
974 you have performed tests, mark the working directory as good or
974 you have performed tests, mark the working directory as good or
975 bad, and bisect will either update to another candidate changeset
975 bad, and bisect will either update to another candidate changeset
976 or announce that it has found the bad revision.
976 or announce that it has found the bad revision.
977
977
978 As a shortcut, you can also use the revision argument to mark a
978 As a shortcut, you can also use the revision argument to mark a
979 revision as good or bad without checking it out first.
979 revision as good or bad without checking it out first.
980
980
981 If you supply a command, it will be used for automatic bisection.
981 If you supply a command, it will be used for automatic bisection.
982 The environment variable HG_NODE will contain the ID of the
982 The environment variable HG_NODE will contain the ID of the
983 changeset being tested. The exit status of the command will be
983 changeset being tested. The exit status of the command will be
984 used to mark revisions as good or bad: status 0 means good, 125
984 used to mark revisions as good or bad: status 0 means good, 125
985 means to skip the revision, 127 (command not found) will abort the
985 means to skip the revision, 127 (command not found) will abort the
986 bisection, and any other non-zero exit status means the revision
986 bisection, and any other non-zero exit status means the revision
987 is bad.
987 is bad.
988
988
989 .. container:: verbose
989 .. container:: verbose
990
990
991 Some examples:
991 Some examples:
992
992
993 - start a bisection with known bad revision 34, and good revision 12::
993 - start a bisection with known bad revision 34, and good revision 12::
994
994
995 hg bisect --bad 34
995 hg bisect --bad 34
996 hg bisect --good 12
996 hg bisect --good 12
997
997
998 - advance the current bisection by marking current revision as good or
998 - advance the current bisection by marking current revision as good or
999 bad::
999 bad::
1000
1000
1001 hg bisect --good
1001 hg bisect --good
1002 hg bisect --bad
1002 hg bisect --bad
1003
1003
1004 - mark the current revision, or a known revision, to be skipped (e.g. if
1004 - mark the current revision, or a known revision, to be skipped (e.g. if
1005 that revision is not usable because of another issue)::
1005 that revision is not usable because of another issue)::
1006
1006
1007 hg bisect --skip
1007 hg bisect --skip
1008 hg bisect --skip 23
1008 hg bisect --skip 23
1009
1009
1010 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1010 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1011
1011
1012 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1012 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1013
1013
1014 - forget the current bisection::
1014 - forget the current bisection::
1015
1015
1016 hg bisect --reset
1016 hg bisect --reset
1017
1017
1018 - use 'make && make tests' to automatically find the first broken
1018 - use 'make && make tests' to automatically find the first broken
1019 revision::
1019 revision::
1020
1020
1021 hg bisect --reset
1021 hg bisect --reset
1022 hg bisect --bad 34
1022 hg bisect --bad 34
1023 hg bisect --good 12
1023 hg bisect --good 12
1024 hg bisect --command "make && make tests"
1024 hg bisect --command "make && make tests"
1025
1025
1026 - see all changesets whose states are already known in the current
1026 - see all changesets whose states are already known in the current
1027 bisection::
1027 bisection::
1028
1028
1029 hg log -r "bisect(pruned)"
1029 hg log -r "bisect(pruned)"
1030
1030
1031 - see the changeset currently being bisected (especially useful
1031 - see the changeset currently being bisected (especially useful
1032 if running with -U/--noupdate)::
1032 if running with -U/--noupdate)::
1033
1033
1034 hg log -r "bisect(current)"
1034 hg log -r "bisect(current)"
1035
1035
1036 - see all changesets that took part in the current bisection::
1036 - see all changesets that took part in the current bisection::
1037
1037
1038 hg log -r "bisect(range)"
1038 hg log -r "bisect(range)"
1039
1039
1040 - you can even get a nice graph::
1040 - you can even get a nice graph::
1041
1041
1042 hg log --graph -r "bisect(range)"
1042 hg log --graph -r "bisect(range)"
1043
1043
1044 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1044 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1045
1045
1046 Returns 0 on success.
1046 Returns 0 on success.
1047 """
1047 """
1048 rev = []
1048 rev = []
1049 # backward compatibility
1049 # backward compatibility
1050 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1050 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1051 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1051 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1052 cmd = positional_1
1052 cmd = positional_1
1053 rev.append(positional_2)
1053 rev.append(positional_2)
1054 if cmd == b"good":
1054 if cmd == b"good":
1055 good = True
1055 good = True
1056 elif cmd == b"bad":
1056 elif cmd == b"bad":
1057 bad = True
1057 bad = True
1058 else:
1058 else:
1059 reset = True
1059 reset = True
1060 elif positional_2:
1060 elif positional_2:
1061 raise error.InputError(_(b'incompatible arguments'))
1061 raise error.InputError(_(b'incompatible arguments'))
1062 elif positional_1 is not None:
1062 elif positional_1 is not None:
1063 rev.append(positional_1)
1063 rev.append(positional_1)
1064
1064
1065 incompatibles = {
1065 incompatibles = {
1066 b'--bad': bad,
1066 b'--bad': bad,
1067 b'--command': bool(command),
1067 b'--command': bool(command),
1068 b'--extend': extend,
1068 b'--extend': extend,
1069 b'--good': good,
1069 b'--good': good,
1070 b'--reset': reset,
1070 b'--reset': reset,
1071 b'--skip': skip,
1071 b'--skip': skip,
1072 }
1072 }
1073
1073
1074 enabled = [x for x in incompatibles if incompatibles[x]]
1074 enabled = [x for x in incompatibles if incompatibles[x]]
1075
1075
1076 if len(enabled) > 1:
1076 if len(enabled) > 1:
1077 raise error.InputError(
1077 raise error.InputError(
1078 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1078 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1079 )
1079 )
1080
1080
1081 if reset:
1081 if reset:
1082 hbisect.resetstate(repo)
1082 hbisect.resetstate(repo)
1083 return
1083 return
1084
1084
1085 state = hbisect.load_state(repo)
1085 state = hbisect.load_state(repo)
1086
1086
1087 if rev:
1087 if rev:
1088 revs = logcmdutil.revrange(repo, rev)
1088 revs = logcmdutil.revrange(repo, rev)
1089 goodnodes = state[b'good']
1089 goodnodes = state[b'good']
1090 badnodes = state[b'bad']
1090 badnodes = state[b'bad']
1091 if goodnodes and badnodes:
1091 if goodnodes and badnodes:
1092 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1092 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1093 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1093 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1094 revs = candidates & revs
1094 revs = candidates & revs
1095 nodes = [repo.changelog.node(i) for i in revs]
1095 nodes = [repo.changelog.node(i) for i in revs]
1096 else:
1096 else:
1097 nodes = [repo.lookup(b'.')]
1097 nodes = [repo.lookup(b'.')]
1098
1098
1099 # update state
1099 # update state
1100 if good or bad or skip:
1100 if good or bad or skip:
1101 if good:
1101 if good:
1102 state[b'good'] += nodes
1102 state[b'good'] += nodes
1103 elif bad:
1103 elif bad:
1104 state[b'bad'] += nodes
1104 state[b'bad'] += nodes
1105 elif skip:
1105 elif skip:
1106 state[b'skip'] += nodes
1106 state[b'skip'] += nodes
1107 hbisect.save_state(repo, state)
1107 hbisect.save_state(repo, state)
1108 if not (state[b'good'] and state[b'bad']):
1108 if not (state[b'good'] and state[b'bad']):
1109 return
1109 return
1110
1110
1111 def mayupdate(repo, node, show_stats=True):
1111 def mayupdate(repo, node, show_stats=True):
1112 """common used update sequence"""
1112 """common used update sequence"""
1113 if noupdate:
1113 if noupdate:
1114 return
1114 return
1115 cmdutil.checkunfinished(repo)
1115 cmdutil.checkunfinished(repo)
1116 cmdutil.bailifchanged(repo)
1116 cmdutil.bailifchanged(repo)
1117 return hg.clean(repo, node, show_stats=show_stats)
1117 return hg.clean(repo, node, show_stats=show_stats)
1118
1118
1119 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1119 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1120
1120
1121 if command:
1121 if command:
1122 changesets = 1
1122 changesets = 1
1123 if noupdate:
1123 if noupdate:
1124 try:
1124 try:
1125 node = state[b'current'][0]
1125 node = state[b'current'][0]
1126 except LookupError:
1126 except LookupError:
1127 raise error.StateError(
1127 raise error.StateError(
1128 _(
1128 _(
1129 b'current bisect revision is unknown - '
1129 b'current bisect revision is unknown - '
1130 b'start a new bisect to fix'
1130 b'start a new bisect to fix'
1131 )
1131 )
1132 )
1132 )
1133 else:
1133 else:
1134 node, p2 = repo.dirstate.parents()
1134 node, p2 = repo.dirstate.parents()
1135 if p2 != repo.nullid:
1135 if p2 != repo.nullid:
1136 raise error.StateError(_(b'current bisect revision is a merge'))
1136 raise error.StateError(_(b'current bisect revision is a merge'))
1137 if rev:
1137 if rev:
1138 if not nodes:
1138 if not nodes:
1139 raise error.InputError(_(b'empty revision set'))
1139 raise error.InputError(_(b'empty revision set'))
1140 node = repo[nodes[-1]].node()
1140 node = repo[nodes[-1]].node()
1141 with hbisect.restore_state(repo, state, node):
1141 with hbisect.restore_state(repo, state, node):
1142 while changesets:
1142 while changesets:
1143 # update state
1143 # update state
1144 state[b'current'] = [node]
1144 state[b'current'] = [node]
1145 hbisect.save_state(repo, state)
1145 hbisect.save_state(repo, state)
1146 status = ui.system(
1146 status = ui.system(
1147 command,
1147 command,
1148 environ={b'HG_NODE': hex(node)},
1148 environ={b'HG_NODE': hex(node)},
1149 blockedtag=b'bisect_check',
1149 blockedtag=b'bisect_check',
1150 )
1150 )
1151 if status == 125:
1151 if status == 125:
1152 transition = b"skip"
1152 transition = b"skip"
1153 elif status == 0:
1153 elif status == 0:
1154 transition = b"good"
1154 transition = b"good"
1155 # status < 0 means process was killed
1155 # status < 0 means process was killed
1156 elif status == 127:
1156 elif status == 127:
1157 raise error.Abort(_(b"failed to execute %s") % command)
1157 raise error.Abort(_(b"failed to execute %s") % command)
1158 elif status < 0:
1158 elif status < 0:
1159 raise error.Abort(_(b"%s killed") % command)
1159 raise error.Abort(_(b"%s killed") % command)
1160 else:
1160 else:
1161 transition = b"bad"
1161 transition = b"bad"
1162 state[transition].append(node)
1162 state[transition].append(node)
1163 ctx = repo[node]
1163 ctx = repo[node]
1164 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1164 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1165 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1165 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1166 hbisect.checkstate(state)
1166 hbisect.checkstate(state)
1167 # bisect
1167 # bisect
1168 nodes, changesets, bgood = hbisect.bisect(repo, state)
1168 nodes, changesets, bgood = hbisect.bisect(repo, state)
1169 # update to next check
1169 # update to next check
1170 node = nodes[0]
1170 node = nodes[0]
1171 mayupdate(repo, node, show_stats=False)
1171 mayupdate(repo, node, show_stats=False)
1172 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1172 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1173 return
1173 return
1174
1174
1175 hbisect.checkstate(state)
1175 hbisect.checkstate(state)
1176
1176
1177 # actually bisect
1177 # actually bisect
1178 nodes, changesets, good = hbisect.bisect(repo, state)
1178 nodes, changesets, good = hbisect.bisect(repo, state)
1179 if extend:
1179 if extend:
1180 if not changesets:
1180 if not changesets:
1181 extendctx = hbisect.extendrange(repo, state, nodes, good)
1181 extendctx = hbisect.extendrange(repo, state, nodes, good)
1182 if extendctx is not None:
1182 if extendctx is not None:
1183 ui.write(
1183 ui.write(
1184 _(b"Extending search to changeset %s\n")
1184 _(b"Extending search to changeset %s\n")
1185 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1185 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1186 )
1186 )
1187 state[b'current'] = [extendctx.node()]
1187 state[b'current'] = [extendctx.node()]
1188 hbisect.save_state(repo, state)
1188 hbisect.save_state(repo, state)
1189 return mayupdate(repo, extendctx.node())
1189 return mayupdate(repo, extendctx.node())
1190 raise error.StateError(_(b"nothing to extend"))
1190 raise error.StateError(_(b"nothing to extend"))
1191
1191
1192 if changesets == 0:
1192 if changesets == 0:
1193 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1193 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1194 else:
1194 else:
1195 assert len(nodes) == 1 # only a single node can be tested next
1195 assert len(nodes) == 1 # only a single node can be tested next
1196 node = nodes[0]
1196 node = nodes[0]
1197 # compute the approximate number of remaining tests
1197 # compute the approximate number of remaining tests
1198 tests, size = 0, 2
1198 tests, size = 0, 2
1199 while size <= changesets:
1199 while size <= changesets:
1200 tests, size = tests + 1, size * 2
1200 tests, size = tests + 1, size * 2
1201 rev = repo.changelog.rev(node)
1201 rev = repo.changelog.rev(node)
1202 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1202 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1203 ui.write(
1203 ui.write(
1204 _(
1204 _(
1205 b"Testing changeset %s "
1205 b"Testing changeset %s "
1206 b"(%d changesets remaining, ~%d tests)\n"
1206 b"(%d changesets remaining, ~%d tests)\n"
1207 )
1207 )
1208 % (summary, changesets, tests)
1208 % (summary, changesets, tests)
1209 )
1209 )
1210 state[b'current'] = [node]
1210 state[b'current'] = [node]
1211 hbisect.save_state(repo, state)
1211 hbisect.save_state(repo, state)
1212 return mayupdate(repo, node)
1212 return mayupdate(repo, node)
1213
1213
1214
1214
1215 @command(
1215 @command(
1216 b'bookmarks|bookmark',
1216 b'bookmarks|bookmark',
1217 [
1217 [
1218 (b'f', b'force', False, _(b'force')),
1218 (b'f', b'force', False, _(b'force')),
1219 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1219 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1220 (b'd', b'delete', False, _(b'delete a given bookmark')),
1220 (b'd', b'delete', False, _(b'delete a given bookmark')),
1221 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1221 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1222 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1222 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1223 (b'l', b'list', False, _(b'list existing bookmarks')),
1223 (b'l', b'list', False, _(b'list existing bookmarks')),
1224 ]
1224 ]
1225 + formatteropts,
1225 + formatteropts,
1226 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1226 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1227 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1227 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1228 )
1228 )
1229 def bookmark(ui, repo, *names, **opts):
1229 def bookmark(ui, repo, *names, **opts):
1230 """create a new bookmark or list existing bookmarks
1230 """create a new bookmark or list existing bookmarks
1231
1231
1232 Bookmarks are labels on changesets to help track lines of development.
1232 Bookmarks are labels on changesets to help track lines of development.
1233 Bookmarks are unversioned and can be moved, renamed and deleted.
1233 Bookmarks are unversioned and can be moved, renamed and deleted.
1234 Deleting or moving a bookmark has no effect on the associated changesets.
1234 Deleting or moving a bookmark has no effect on the associated changesets.
1235
1235
1236 Creating or updating to a bookmark causes it to be marked as 'active'.
1236 Creating or updating to a bookmark causes it to be marked as 'active'.
1237 The active bookmark is indicated with a '*'.
1237 The active bookmark is indicated with a '*'.
1238 When a commit is made, the active bookmark will advance to the new commit.
1238 When a commit is made, the active bookmark will advance to the new commit.
1239 A plain :hg:`update` will also advance an active bookmark, if possible.
1239 A plain :hg:`update` will also advance an active bookmark, if possible.
1240 Updating away from a bookmark will cause it to be deactivated.
1240 Updating away from a bookmark will cause it to be deactivated.
1241
1241
1242 Bookmarks can be pushed and pulled between repositories (see
1242 Bookmarks can be pushed and pulled between repositories (see
1243 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1243 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1244 diverged, a new 'divergent bookmark' of the form 'name@path' will
1244 diverged, a new 'divergent bookmark' of the form 'name@path' will
1245 be created. Using :hg:`merge` will resolve the divergence.
1245 be created. Using :hg:`merge` will resolve the divergence.
1246
1246
1247 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1247 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1248 the active bookmark's name.
1248 the active bookmark's name.
1249
1249
1250 A bookmark named '@' has the special property that :hg:`clone` will
1250 A bookmark named '@' has the special property that :hg:`clone` will
1251 check it out by default if it exists.
1251 check it out by default if it exists.
1252
1252
1253 .. container:: verbose
1253 .. container:: verbose
1254
1254
1255 Template:
1255 Template:
1256
1256
1257 The following keywords are supported in addition to the common template
1257 The following keywords are supported in addition to the common template
1258 keywords and functions such as ``{bookmark}``. See also
1258 keywords and functions such as ``{bookmark}``. See also
1259 :hg:`help templates`.
1259 :hg:`help templates`.
1260
1260
1261 :active: Boolean. True if the bookmark is active.
1261 :active: Boolean. True if the bookmark is active.
1262
1262
1263 Examples:
1263 Examples:
1264
1264
1265 - create an active bookmark for a new line of development::
1265 - create an active bookmark for a new line of development::
1266
1266
1267 hg book new-feature
1267 hg book new-feature
1268
1268
1269 - create an inactive bookmark as a place marker::
1269 - create an inactive bookmark as a place marker::
1270
1270
1271 hg book -i reviewed
1271 hg book -i reviewed
1272
1272
1273 - create an inactive bookmark on another changeset::
1273 - create an inactive bookmark on another changeset::
1274
1274
1275 hg book -r .^ tested
1275 hg book -r .^ tested
1276
1276
1277 - rename bookmark turkey to dinner::
1277 - rename bookmark turkey to dinner::
1278
1278
1279 hg book -m turkey dinner
1279 hg book -m turkey dinner
1280
1280
1281 - move the '@' bookmark from another branch::
1281 - move the '@' bookmark from another branch::
1282
1282
1283 hg book -f @
1283 hg book -f @
1284
1284
1285 - print only the active bookmark name::
1285 - print only the active bookmark name::
1286
1286
1287 hg book -ql .
1287 hg book -ql .
1288 """
1288 """
1289 force = opts.get('force')
1289 force = opts.get('force')
1290 rev = opts.get('rev')
1290 rev = opts.get('rev')
1291 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1291 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1292
1292
1293 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1293 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1294 if action:
1294 if action:
1295 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1295 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1296 elif names or rev:
1296 elif names or rev:
1297 action = 'add'
1297 action = 'add'
1298 elif inactive:
1298 elif inactive:
1299 action = 'inactive' # meaning deactivate
1299 action = 'inactive' # meaning deactivate
1300 else:
1300 else:
1301 action = 'list'
1301 action = 'list'
1302
1302
1303 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1303 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1304 if not names and action in {'add', 'delete'}:
1304 if not names and action in {'add', 'delete'}:
1305 raise error.InputError(_(b"bookmark name required"))
1305 raise error.InputError(_(b"bookmark name required"))
1306
1306
1307 if action in {'add', 'delete', 'rename', 'inactive'}:
1307 if action in {'add', 'delete', 'rename', 'inactive'}:
1308 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1308 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1309 if action == 'delete':
1309 if action == 'delete':
1310 names = pycompat.maplist(repo._bookmarks.expandname, names)
1310 names = pycompat.maplist(repo._bookmarks.expandname, names)
1311 bookmarks.delete(repo, tr, names)
1311 bookmarks.delete(repo, tr, names)
1312 elif action == 'rename':
1312 elif action == 'rename':
1313 if not names:
1313 if not names:
1314 raise error.InputError(_(b"new bookmark name required"))
1314 raise error.InputError(_(b"new bookmark name required"))
1315 elif len(names) > 1:
1315 elif len(names) > 1:
1316 raise error.InputError(
1316 raise error.InputError(
1317 _(b"only one new bookmark name allowed")
1317 _(b"only one new bookmark name allowed")
1318 )
1318 )
1319 oldname = repo._bookmarks.expandname(opts['rename'])
1319 oldname = repo._bookmarks.expandname(opts['rename'])
1320 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1320 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1321 elif action == 'add':
1321 elif action == 'add':
1322 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1322 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1323 elif action == 'inactive':
1323 elif action == 'inactive':
1324 if len(repo._bookmarks) == 0:
1324 if len(repo._bookmarks) == 0:
1325 ui.status(_(b"no bookmarks set\n"))
1325 ui.status(_(b"no bookmarks set\n"))
1326 elif not repo._activebookmark:
1326 elif not repo._activebookmark:
1327 ui.status(_(b"no active bookmark\n"))
1327 ui.status(_(b"no active bookmark\n"))
1328 else:
1328 else:
1329 bookmarks.deactivate(repo)
1329 bookmarks.deactivate(repo)
1330 elif action == 'list':
1330 elif action == 'list':
1331 names = pycompat.maplist(repo._bookmarks.expandname, names)
1331 names = pycompat.maplist(repo._bookmarks.expandname, names)
1332 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1332 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1333 bookmarks.printbookmarks(ui, repo, fm, names)
1333 bookmarks.printbookmarks(ui, repo, fm, names)
1334 else:
1334 else:
1335 raise error.ProgrammingError(
1335 raise error.ProgrammingError(
1336 b'invalid action: %s' % pycompat.sysbytes(action)
1336 b'invalid action: %s' % pycompat.sysbytes(action)
1337 )
1337 )
1338
1338
1339
1339
1340 @command(
1340 @command(
1341 b'branch',
1341 b'branch',
1342 [
1342 [
1343 (
1343 (
1344 b'f',
1344 b'f',
1345 b'force',
1345 b'force',
1346 None,
1346 None,
1347 _(b'set branch name even if it shadows an existing branch'),
1347 _(b'set branch name even if it shadows an existing branch'),
1348 ),
1348 ),
1349 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1349 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1350 (
1350 (
1351 b'r',
1351 b'r',
1352 b'rev',
1352 b'rev',
1353 [],
1353 [],
1354 _(b'change branches of the given revs (EXPERIMENTAL)'),
1354 _(b'change branches of the given revs (EXPERIMENTAL)'),
1355 ),
1355 ),
1356 ],
1356 ],
1357 _(b'[-fC] [NAME]'),
1357 _(b'[-fC] [NAME]'),
1358 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1358 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1359 )
1359 )
1360 def branch(ui, repo, label=None, **opts):
1360 def branch(ui, repo, label=None, **opts):
1361 """set or show the current branch name
1361 """set or show the current branch name
1362
1362
1363 .. note::
1363 .. note::
1364
1364
1365 Branch names are permanent and global. Use :hg:`bookmark` to create a
1365 Branch names are permanent and global. Use :hg:`bookmark` to create a
1366 light-weight bookmark instead. See :hg:`help glossary` for more
1366 light-weight bookmark instead. See :hg:`help glossary` for more
1367 information about named branches and bookmarks.
1367 information about named branches and bookmarks.
1368
1368
1369 With no argument, show the current branch name. With one argument,
1369 With no argument, show the current branch name. With one argument,
1370 set the working directory branch name (the branch will not exist
1370 set the working directory branch name (the branch will not exist
1371 in the repository until the next commit). Standard practice
1371 in the repository until the next commit). Standard practice
1372 recommends that primary development take place on the 'default'
1372 recommends that primary development take place on the 'default'
1373 branch.
1373 branch.
1374
1374
1375 Unless -f/--force is specified, branch will not let you set a
1375 Unless -f/--force is specified, branch will not let you set a
1376 branch name that already exists.
1376 branch name that already exists.
1377
1377
1378 Use -C/--clean to reset the working directory branch to that of
1378 Use -C/--clean to reset the working directory branch to that of
1379 the parent of the working directory, negating a previous branch
1379 the parent of the working directory, negating a previous branch
1380 change.
1380 change.
1381
1381
1382 Use the command :hg:`update` to switch to an existing branch. Use
1382 Use the command :hg:`update` to switch to an existing branch. Use
1383 :hg:`commit --close-branch` to mark this branch head as closed.
1383 :hg:`commit --close-branch` to mark this branch head as closed.
1384 When all heads of a branch are closed, the branch will be
1384 When all heads of a branch are closed, the branch will be
1385 considered closed.
1385 considered closed.
1386
1386
1387 Returns 0 on success.
1387 Returns 0 on success.
1388 """
1388 """
1389 revs = opts.get('rev')
1389 revs = opts.get('rev')
1390 if label:
1390 if label:
1391 label = label.strip()
1391 label = label.strip()
1392
1392
1393 if not opts.get('clean') and not label:
1393 if not opts.get('clean') and not label:
1394 if revs:
1394 if revs:
1395 raise error.InputError(
1395 raise error.InputError(
1396 _(b"no branch name specified for the revisions")
1396 _(b"no branch name specified for the revisions")
1397 )
1397 )
1398 ui.write(b"%s\n" % repo.dirstate.branch())
1398 ui.write(b"%s\n" % repo.dirstate.branch())
1399 return
1399 return
1400
1400
1401 with repo.wlock():
1401 with repo.wlock():
1402 if opts.get('clean'):
1402 if opts.get('clean'):
1403 label = repo[b'.'].branch()
1403 label = repo[b'.'].branch()
1404 repo.dirstate.setbranch(label, repo.currenttransaction())
1404 repo.dirstate.setbranch(label, repo.currenttransaction())
1405 ui.status(_(b'reset working directory to branch %s\n') % label)
1405 ui.status(_(b'reset working directory to branch %s\n') % label)
1406 elif label:
1406 elif label:
1407 scmutil.checknewlabel(repo, label, b'branch')
1407 scmutil.checknewlabel(repo, label, b'branch')
1408 if revs:
1408 if revs:
1409 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1409 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1410
1410
1411 if not opts.get('force') and label in repo.branchmap():
1411 if not opts.get('force') and label in repo.branchmap():
1412 if label not in [p.branch() for p in repo[None].parents()]:
1412 if label not in [p.branch() for p in repo[None].parents()]:
1413 raise error.InputError(
1413 raise error.InputError(
1414 _(b'a branch of the same name already exists'),
1414 _(b'a branch of the same name already exists'),
1415 # i18n: "it" refers to an existing branch
1415 # i18n: "it" refers to an existing branch
1416 hint=_(b"use 'hg update' to switch to it"),
1416 hint=_(b"use 'hg update' to switch to it"),
1417 )
1417 )
1418
1418
1419 repo.dirstate.setbranch(label, repo.currenttransaction())
1419 repo.dirstate.setbranch(label, repo.currenttransaction())
1420 ui.status(_(b'marked working directory as branch %s\n') % label)
1420 ui.status(_(b'marked working directory as branch %s\n') % label)
1421
1421
1422 # find any open named branches aside from default
1422 # find any open named branches aside from default
1423 for n, h, t, c in repo.branchmap().iterbranches():
1423 for n, h, t, c in repo.branchmap().iterbranches():
1424 if n != b"default" and not c:
1424 if n != b"default" and not c:
1425 return 0
1425 return 0
1426 ui.status(
1426 ui.status(
1427 _(
1427 _(
1428 b'(branches are permanent and global, '
1428 b'(branches are permanent and global, '
1429 b'did you want a bookmark?)\n'
1429 b'did you want a bookmark?)\n'
1430 )
1430 )
1431 )
1431 )
1432
1432
1433
1433
1434 @command(
1434 @command(
1435 b'branches',
1435 b'branches',
1436 [
1436 [
1437 (
1437 (
1438 b'a',
1438 b'a',
1439 b'active',
1439 b'active',
1440 False,
1440 False,
1441 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1441 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1442 ),
1442 ),
1443 (b'c', b'closed', False, _(b'show normal and closed branches')),
1443 (b'c', b'closed', False, _(b'show normal and closed branches')),
1444 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1444 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1445 ]
1445 ]
1446 + formatteropts,
1446 + formatteropts,
1447 _(b'[-c]'),
1447 _(b'[-c]'),
1448 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1448 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1449 intents={INTENT_READONLY},
1449 intents={INTENT_READONLY},
1450 )
1450 )
1451 def branches(ui, repo, active=False, closed=False, **opts):
1451 def branches(ui, repo, active=False, closed=False, **opts):
1452 """list repository named branches
1452 """list repository named branches
1453
1453
1454 List the repository's named branches, indicating which ones are
1454 List the repository's named branches, indicating which ones are
1455 inactive. If -c/--closed is specified, also list branches which have
1455 inactive. If -c/--closed is specified, also list branches which have
1456 been marked closed (see :hg:`commit --close-branch`).
1456 been marked closed (see :hg:`commit --close-branch`).
1457
1457
1458 Use the command :hg:`update` to switch to an existing branch.
1458 Use the command :hg:`update` to switch to an existing branch.
1459
1459
1460 .. container:: verbose
1460 .. container:: verbose
1461
1461
1462 Template:
1462 Template:
1463
1463
1464 The following keywords are supported in addition to the common template
1464 The following keywords are supported in addition to the common template
1465 keywords and functions such as ``{branch}``. See also
1465 keywords and functions such as ``{branch}``. See also
1466 :hg:`help templates`.
1466 :hg:`help templates`.
1467
1467
1468 :active: Boolean. True if the branch is active.
1468 :active: Boolean. True if the branch is active.
1469 :closed: Boolean. True if the branch is closed.
1469 :closed: Boolean. True if the branch is closed.
1470 :current: Boolean. True if it is the current branch.
1470 :current: Boolean. True if it is the current branch.
1471
1471
1472 Returns 0.
1472 Returns 0.
1473 """
1473 """
1474
1474
1475 revs = opts.get('rev')
1475 revs = opts.get('rev')
1476 selectedbranches = None
1476 selectedbranches = None
1477 if revs:
1477 if revs:
1478 revs = logcmdutil.revrange(repo, revs)
1478 revs = logcmdutil.revrange(repo, revs)
1479 getbi = repo.revbranchcache().branchinfo
1479 getbi = repo.revbranchcache().branchinfo
1480 selectedbranches = {getbi(r)[0] for r in revs}
1480 selectedbranches = {getbi(r)[0] for r in revs}
1481
1481
1482 ui.pager(b'branches')
1482 ui.pager(b'branches')
1483 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1483 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1484 hexfunc = fm.hexfunc
1484 hexfunc = fm.hexfunc
1485
1485
1486 allheads = set(repo.heads())
1486 allheads = set(repo.heads())
1487 branches = []
1487 branches = []
1488 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1488 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1489 if selectedbranches is not None and tag not in selectedbranches:
1489 if selectedbranches is not None and tag not in selectedbranches:
1490 continue
1490 continue
1491 isactive = False
1491 isactive = False
1492 if not isclosed:
1492 if not isclosed:
1493 openheads = set(repo.branchmap().iteropen(heads))
1493 openheads = set(repo.branchmap().iteropen(heads))
1494 isactive = bool(openheads & allheads)
1494 isactive = bool(openheads & allheads)
1495 branches.append((tag, repo[tip], isactive, not isclosed))
1495 branches.append((tag, repo[tip], isactive, not isclosed))
1496 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1496 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1497
1497
1498 for tag, ctx, isactive, isopen in branches:
1498 for tag, ctx, isactive, isopen in branches:
1499 if active and not isactive:
1499 if active and not isactive:
1500 continue
1500 continue
1501 if isactive:
1501 if isactive:
1502 label = b'branches.active'
1502 label = b'branches.active'
1503 notice = b''
1503 notice = b''
1504 elif not isopen:
1504 elif not isopen:
1505 if not closed:
1505 if not closed:
1506 continue
1506 continue
1507 label = b'branches.closed'
1507 label = b'branches.closed'
1508 notice = _(b' (closed)')
1508 notice = _(b' (closed)')
1509 else:
1509 else:
1510 label = b'branches.inactive'
1510 label = b'branches.inactive'
1511 notice = _(b' (inactive)')
1511 notice = _(b' (inactive)')
1512 current = tag == repo.dirstate.branch()
1512 current = tag == repo.dirstate.branch()
1513 if current:
1513 if current:
1514 label = b'branches.current'
1514 label = b'branches.current'
1515
1515
1516 fm.startitem()
1516 fm.startitem()
1517 fm.write(b'branch', b'%s', tag, label=label)
1517 fm.write(b'branch', b'%s', tag, label=label)
1518 rev = ctx.rev()
1518 rev = ctx.rev()
1519 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1519 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1520 fmt = b' ' * padsize + b' %d:%s'
1520 fmt = b' ' * padsize + b' %d:%s'
1521 fm.condwrite(
1521 fm.condwrite(
1522 not ui.quiet,
1522 not ui.quiet,
1523 b'rev node',
1523 b'rev node',
1524 fmt,
1524 fmt,
1525 rev,
1525 rev,
1526 hexfunc(ctx.node()),
1526 hexfunc(ctx.node()),
1527 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1527 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1528 )
1528 )
1529 fm.context(ctx=ctx)
1529 fm.context(ctx=ctx)
1530 fm.data(active=isactive, closed=not isopen, current=current)
1530 fm.data(active=isactive, closed=not isopen, current=current)
1531 if not ui.quiet:
1531 if not ui.quiet:
1532 fm.plain(notice)
1532 fm.plain(notice)
1533 fm.plain(b'\n')
1533 fm.plain(b'\n')
1534 fm.end()
1534 fm.end()
1535
1535
1536
1536
1537 @command(
1537 @command(
1538 b'bundle',
1538 b'bundle',
1539 [
1539 [
1540 (
1540 (
1541 b'',
1541 b'',
1542 b'exact',
1542 b'exact',
1543 None,
1543 None,
1544 _(b'compute the base from the revision specified'),
1544 _(b'compute the base from the revision specified'),
1545 ),
1545 ),
1546 (
1546 (
1547 b'f',
1547 b'f',
1548 b'force',
1548 b'force',
1549 None,
1549 None,
1550 _(b'run even when the destination is unrelated'),
1550 _(b'run even when the destination is unrelated'),
1551 ),
1551 ),
1552 (
1552 (
1553 b'r',
1553 b'r',
1554 b'rev',
1554 b'rev',
1555 [],
1555 [],
1556 _(b'a changeset intended to be added to the destination'),
1556 _(b'a changeset intended to be added to the destination'),
1557 _(b'REV'),
1557 _(b'REV'),
1558 ),
1558 ),
1559 (
1559 (
1560 b'b',
1560 b'b',
1561 b'branch',
1561 b'branch',
1562 [],
1562 [],
1563 _(b'a specific branch you would like to bundle'),
1563 _(b'a specific branch you would like to bundle'),
1564 _(b'BRANCH'),
1564 _(b'BRANCH'),
1565 ),
1565 ),
1566 (
1566 (
1567 b'',
1567 b'',
1568 b'base',
1568 b'base',
1569 [],
1569 [],
1570 _(b'a base changeset assumed to be available at the destination'),
1570 _(b'a base changeset assumed to be available at the destination'),
1571 _(b'REV'),
1571 _(b'REV'),
1572 ),
1572 ),
1573 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1573 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1574 (
1574 (
1575 b't',
1575 b't',
1576 b'type',
1576 b'type',
1577 b'bzip2',
1577 b'bzip2',
1578 _(b'bundle compression type to use'),
1578 _(b'bundle compression type to use'),
1579 _(b'TYPE'),
1579 _(b'TYPE'),
1580 ),
1580 ),
1581 ]
1581 ]
1582 + remoteopts,
1582 + remoteopts,
1583 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1583 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1584 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1584 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1585 )
1585 )
1586 def bundle(ui, repo, fname, *dests, **opts):
1586 def bundle(ui, repo, fname, *dests, **opts):
1587 """create a bundle file
1587 """create a bundle file
1588
1588
1589 Generate a bundle file containing data to be transferred to another
1589 Generate a bundle file containing data to be transferred to another
1590 repository.
1590 repository.
1591
1591
1592 To create a bundle containing all changesets, use -a/--all
1592 To create a bundle containing all changesets, use -a/--all
1593 (or --base null). Otherwise, hg assumes the destination will have
1593 (or --base null). Otherwise, hg assumes the destination will have
1594 all the nodes you specify with --base parameters. Otherwise, hg
1594 all the nodes you specify with --base parameters. Otherwise, hg
1595 will assume the repository has all the nodes in destination, or
1595 will assume the repository has all the nodes in destination, or
1596 default-push/default if no destination is specified, where destination
1596 default-push/default if no destination is specified, where destination
1597 is the repositories you provide through DEST option.
1597 is the repositories you provide through DEST option.
1598
1598
1599 You can change bundle format with the -t/--type option. See
1599 You can change bundle format with the -t/--type option. See
1600 :hg:`help bundlespec` for documentation on this format. By default,
1600 :hg:`help bundlespec` for documentation on this format. By default,
1601 the most appropriate format is used and compression defaults to
1601 the most appropriate format is used and compression defaults to
1602 bzip2.
1602 bzip2.
1603
1603
1604 The bundle file can then be transferred using conventional means
1604 The bundle file can then be transferred using conventional means
1605 and applied to another repository with the unbundle or pull
1605 and applied to another repository with the unbundle or pull
1606 command. This is useful when direct push and pull are not
1606 command. This is useful when direct push and pull are not
1607 available or when exporting an entire repository is undesirable.
1607 available or when exporting an entire repository is undesirable.
1608
1608
1609 Applying bundles preserves all changeset contents including
1609 Applying bundles preserves all changeset contents including
1610 permissions, copy/rename information, and revision history.
1610 permissions, copy/rename information, and revision history.
1611
1611
1612 Returns 0 on success, 1 if no changes found.
1612 Returns 0 on success, 1 if no changes found.
1613 """
1613 """
1614
1614
1615 revs = None
1615 revs = None
1616 if 'rev' in opts:
1616 if 'rev' in opts:
1617 revstrings = opts['rev']
1617 revstrings = opts['rev']
1618 revs = logcmdutil.revrange(repo, revstrings)
1618 revs = logcmdutil.revrange(repo, revstrings)
1619 if revstrings and not revs:
1619 if revstrings and not revs:
1620 raise error.InputError(_(b'no commits to bundle'))
1620 raise error.InputError(_(b'no commits to bundle'))
1621
1621
1622 bundletype = opts.get('type', b'bzip2').lower()
1622 bundletype = opts.get('type', b'bzip2').lower()
1623 try:
1623 try:
1624 bundlespec = bundlecaches.parsebundlespec(
1624 bundlespec = bundlecaches.parsebundlespec(
1625 repo, bundletype, strict=False
1625 repo, bundletype, strict=False
1626 )
1626 )
1627 except error.UnsupportedBundleSpecification as e:
1627 except error.UnsupportedBundleSpecification as e:
1628 raise error.InputError(
1628 raise error.InputError(
1629 pycompat.bytestr(e),
1629 pycompat.bytestr(e),
1630 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1630 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1631 )
1631 )
1632
1632
1633 has_changegroup = bundlespec.params.get(b"changegroup", False)
1633 has_changegroup = bundlespec.params.get(b"changegroup", False)
1634 cgversion = bundlespec.params[b"cg.version"]
1634 cgversion = bundlespec.params[b"cg.version"]
1635
1635
1636 # Packed bundles are a pseudo bundle format for now.
1636 # Packed bundles are a pseudo bundle format for now.
1637 if cgversion == b's1':
1637 if cgversion == b's1':
1638 raise error.InputError(
1638 raise error.InputError(
1639 _(b'packed bundles cannot be produced by "hg bundle"'),
1639 _(b'packed bundles cannot be produced by "hg bundle"'),
1640 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1640 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1641 )
1641 )
1642 base_opt = opts.get('base')
1642 base_opt = opts.get('base')
1643 if opts.get('all'):
1643 if opts.get('all'):
1644 if dests:
1644 if dests:
1645 raise error.InputError(
1645 raise error.InputError(
1646 _(b"--all is incompatible with specifying destinations")
1646 _(b"--all is incompatible with specifying destinations")
1647 )
1647 )
1648 if base_opt:
1648 if base_opt:
1649 ui.warn(_(b"ignoring --base because --all was specified\n"))
1649 ui.warn(_(b"ignoring --base because --all was specified\n"))
1650 if opts.get('exact'):
1650 if opts.get('exact'):
1651 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1651 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1652 base = [nullrev]
1652 base = [nullrev]
1653 elif opts.get('exact'):
1653 elif opts.get('exact'):
1654 if dests:
1654 if dests:
1655 raise error.InputError(
1655 raise error.InputError(
1656 _(b"--exact is incompatible with specifying destinations")
1656 _(b"--exact is incompatible with specifying destinations")
1657 )
1657 )
1658 if base_opt:
1658 if base_opt:
1659 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1659 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1660 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1660 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1661 if not base:
1661 if not base:
1662 base = [nullrev]
1662 base = [nullrev]
1663 elif base_opt:
1663 elif base_opt:
1664 base = logcmdutil.revrange(repo, base_opt)
1664 base = logcmdutil.revrange(repo, base_opt)
1665 if not base:
1665 if not base:
1666 # base specified, but nothing was selected
1666 # base specified, but nothing was selected
1667 base = [nullrev]
1667 base = [nullrev]
1668 else:
1668 else:
1669 base = None
1669 base = None
1670 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1670 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1671 if has_changegroup and cgversion not in supported_cg_versions:
1671 if has_changegroup and cgversion not in supported_cg_versions:
1672 raise error.Abort(
1672 raise error.Abort(
1673 _(b"repository does not support bundle version %s") % cgversion
1673 _(b"repository does not support bundle version %s") % cgversion
1674 )
1674 )
1675
1675
1676 if base is not None:
1676 if base is not None:
1677 if dests:
1677 if dests:
1678 raise error.InputError(
1678 raise error.InputError(
1679 _(b"--base is incompatible with specifying destinations")
1679 _(b"--base is incompatible with specifying destinations")
1680 )
1680 )
1681 cl = repo.changelog
1681 cl = repo.changelog
1682 common = [cl.node(rev) for rev in base]
1682 common = [cl.node(rev) for rev in base]
1683 heads = [cl.node(r) for r in revs] if revs else None
1683 heads = [cl.node(r) for r in revs] if revs else None
1684 outgoing = discovery.outgoing(repo, common, heads)
1684 outgoing = discovery.outgoing(repo, common, heads)
1685 missing = outgoing.missing
1685 missing = outgoing.missing
1686 excluded = outgoing.excluded
1686 excluded = outgoing.excluded
1687 else:
1687 else:
1688 missing = set()
1688 missing = set()
1689 excluded = set()
1689 excluded = set()
1690 for path in urlutil.get_push_paths(repo, ui, dests):
1690 for path in urlutil.get_push_paths(repo, ui, dests):
1691 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1691 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1692 if revs is not None:
1692 if revs is not None:
1693 hex_revs = [repo[r].hex() for r in revs]
1693 hex_revs = [repo[r].hex() for r in revs]
1694 else:
1694 else:
1695 hex_revs = None
1695 hex_revs = None
1696 branches = (path.branch, [])
1696 branches = (path.branch, [])
1697 head_revs, checkout = hg.addbranchrevs(
1697 head_revs, checkout = hg.addbranchrevs(
1698 repo, repo, branches, hex_revs
1698 repo, repo, branches, hex_revs
1699 )
1699 )
1700 heads = (
1700 heads = (
1701 head_revs
1701 head_revs
1702 and pycompat.maplist(repo.lookup, head_revs)
1702 and pycompat.maplist(repo.lookup, head_revs)
1703 or head_revs
1703 or head_revs
1704 )
1704 )
1705 outgoing = discovery.findcommonoutgoing(
1705 outgoing = discovery.findcommonoutgoing(
1706 repo,
1706 repo,
1707 other,
1707 other,
1708 onlyheads=heads,
1708 onlyheads=heads,
1709 force=opts.get('force'),
1709 force=opts.get('force'),
1710 portable=True,
1710 portable=True,
1711 )
1711 )
1712 missing.update(outgoing.missing)
1712 missing.update(outgoing.missing)
1713 excluded.update(outgoing.excluded)
1713 excluded.update(outgoing.excluded)
1714
1714
1715 if not missing:
1715 if not missing:
1716 scmutil.nochangesfound(ui, repo, not base and excluded)
1716 scmutil.nochangesfound(ui, repo, not base and excluded)
1717 return 1
1717 return 1
1718
1718
1719 # internal changeset are internal implementation details that should not
1719 # internal changeset are internal implementation details that should not
1720 # leave the repository. Bundling with `hg bundle` create such risk.
1720 # leave the repository. Bundling with `hg bundle` create such risk.
1721 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1721 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1722 if bundled_internal:
1722 if bundled_internal:
1723 msg = _(b"cannot bundle internal changesets")
1723 msg = _(b"cannot bundle internal changesets")
1724 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1724 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1725 raise error.Abort(msg, hint=hint)
1725 raise error.Abort(msg, hint=hint)
1726
1726
1727 if heads:
1727 if heads:
1728 outgoing = discovery.outgoing(
1728 outgoing = discovery.outgoing(
1729 repo, missingroots=missing, ancestorsof=heads
1729 repo, missingroots=missing, ancestorsof=heads
1730 )
1730 )
1731 else:
1731 else:
1732 outgoing = discovery.outgoing(repo, missingroots=missing)
1732 outgoing = discovery.outgoing(repo, missingroots=missing)
1733 outgoing.excluded = sorted(excluded)
1733 outgoing.excluded = sorted(excluded)
1734
1734
1735 if cgversion == b'01': # bundle1
1735 if cgversion == b'01': # bundle1
1736 bversion = b'HG10' + bundlespec.wirecompression
1736 bversion = b'HG10' + bundlespec.wirecompression
1737 bcompression = None
1737 bcompression = None
1738 elif cgversion in (b'02', b'03'):
1738 elif cgversion in (b'02', b'03'):
1739 bversion = b'HG20'
1739 bversion = b'HG20'
1740 bcompression = bundlespec.wirecompression
1740 bcompression = bundlespec.wirecompression
1741 else:
1741 else:
1742 raise error.ProgrammingError(
1742 raise error.ProgrammingError(
1743 b'bundle: unexpected changegroup version %s' % cgversion
1743 b'bundle: unexpected changegroup version %s' % cgversion
1744 )
1744 )
1745
1745
1746 # TODO compression options should be derived from bundlespec parsing.
1746 # TODO compression options should be derived from bundlespec parsing.
1747 # This is a temporary hack to allow adjusting bundle compression
1747 # This is a temporary hack to allow adjusting bundle compression
1748 # level without a) formalizing the bundlespec changes to declare it
1748 # level without a) formalizing the bundlespec changes to declare it
1749 # b) introducing a command flag.
1749 # b) introducing a command flag.
1750 compopts = {}
1750 compopts = {}
1751 complevel = ui.configint(
1751 complevel = ui.configint(
1752 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1752 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1753 )
1753 )
1754 if complevel is None:
1754 if complevel is None:
1755 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1755 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1756 if complevel is not None:
1756 if complevel is not None:
1757 compopts[b'level'] = complevel
1757 compopts[b'level'] = complevel
1758
1758
1759 compthreads = ui.configint(
1759 compthreads = ui.configint(
1760 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1760 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1761 )
1761 )
1762 if compthreads is None:
1762 if compthreads is None:
1763 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1763 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1764 if compthreads is not None:
1764 if compthreads is not None:
1765 compopts[b'threads'] = compthreads
1765 compopts[b'threads'] = compthreads
1766
1766
1767 # Bundling of obsmarker and phases is optional as not all clients
1767 # Bundling of obsmarker and phases is optional as not all clients
1768 # support the necessary features.
1768 # support the necessary features.
1769 cfg = ui.configbool
1769 cfg = ui.configbool
1770 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1770 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1771 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1771 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1772 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1772 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1773 bundlespec.set_param(
1773 bundlespec.set_param(
1774 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1774 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1775 )
1775 )
1776 if not bundlespec.params.get(b'phases', False):
1776 if not bundlespec.params.get(b'phases', False):
1777 phases_cfg = cfg(b'experimental', b'bundle-phases')
1777 phases_cfg = cfg(b'experimental', b'bundle-phases')
1778 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1778 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1779
1779
1780 bundle2.writenewbundle(
1780 bundle2.writenewbundle(
1781 ui,
1781 ui,
1782 repo,
1782 repo,
1783 b'bundle',
1783 b'bundle',
1784 fname,
1784 fname,
1785 bversion,
1785 bversion,
1786 outgoing,
1786 outgoing,
1787 bundlespec.params,
1787 bundlespec.params,
1788 compression=bcompression,
1788 compression=bcompression,
1789 compopts=compopts,
1789 compopts=compopts,
1790 )
1790 )
1791
1791
1792
1792
1793 @command(
1793 @command(
1794 b'cat',
1794 b'cat',
1795 [
1795 [
1796 (
1796 (
1797 b'o',
1797 b'o',
1798 b'output',
1798 b'output',
1799 b'',
1799 b'',
1800 _(b'print output to file with formatted name'),
1800 _(b'print output to file with formatted name'),
1801 _(b'FORMAT'),
1801 _(b'FORMAT'),
1802 ),
1802 ),
1803 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1803 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1804 (b'', b'decode', None, _(b'apply any matching decode filter')),
1804 (b'', b'decode', None, _(b'apply any matching decode filter')),
1805 ]
1805 ]
1806 + walkopts
1806 + walkopts
1807 + formatteropts,
1807 + formatteropts,
1808 _(b'[OPTION]... FILE...'),
1808 _(b'[OPTION]... FILE...'),
1809 helpcategory=command.CATEGORY_FILE_CONTENTS,
1809 helpcategory=command.CATEGORY_FILE_CONTENTS,
1810 inferrepo=True,
1810 inferrepo=True,
1811 intents={INTENT_READONLY},
1811 intents={INTENT_READONLY},
1812 )
1812 )
1813 def cat(ui, repo, file1, *pats, **opts):
1813 def cat(ui, repo, file1, *pats, **opts):
1814 """output the current or given revision of files
1814 """output the current or given revision of files
1815
1815
1816 Print the specified files as they were at the given revision. If
1816 Print the specified files as they were at the given revision. If
1817 no revision is given, the parent of the working directory is used.
1817 no revision is given, the parent of the working directory is used.
1818
1818
1819 Output may be to a file, in which case the name of the file is
1819 Output may be to a file, in which case the name of the file is
1820 given using a template string. See :hg:`help templates`. In addition
1820 given using a template string. See :hg:`help templates`. In addition
1821 to the common template keywords, the following formatting rules are
1821 to the common template keywords, the following formatting rules are
1822 supported:
1822 supported:
1823
1823
1824 :``%%``: literal "%" character
1824 :``%%``: literal "%" character
1825 :``%s``: basename of file being printed
1825 :``%s``: basename of file being printed
1826 :``%d``: dirname of file being printed, or '.' if in repository root
1826 :``%d``: dirname of file being printed, or '.' if in repository root
1827 :``%p``: root-relative path name of file being printed
1827 :``%p``: root-relative path name of file being printed
1828 :``%H``: changeset hash (40 hexadecimal digits)
1828 :``%H``: changeset hash (40 hexadecimal digits)
1829 :``%R``: changeset revision number
1829 :``%R``: changeset revision number
1830 :``%h``: short-form changeset hash (12 hexadecimal digits)
1830 :``%h``: short-form changeset hash (12 hexadecimal digits)
1831 :``%r``: zero-padded changeset revision number
1831 :``%r``: zero-padded changeset revision number
1832 :``%b``: basename of the exporting repository
1832 :``%b``: basename of the exporting repository
1833 :``\\``: literal "\\" character
1833 :``\\``: literal "\\" character
1834
1834
1835 .. container:: verbose
1835 .. container:: verbose
1836
1836
1837 Template:
1837 Template:
1838
1838
1839 The following keywords are supported in addition to the common template
1839 The following keywords are supported in addition to the common template
1840 keywords and functions. See also :hg:`help templates`.
1840 keywords and functions. See also :hg:`help templates`.
1841
1841
1842 :data: String. File content.
1842 :data: String. File content.
1843 :path: String. Repository-absolute path of the file.
1843 :path: String. Repository-absolute path of the file.
1844
1844
1845 Returns 0 on success.
1845 Returns 0 on success.
1846 """
1846 """
1847 rev = opts.get('rev')
1847 rev = opts.get('rev')
1848 if rev:
1848 if rev:
1849 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1849 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1850 ctx = logcmdutil.revsingle(repo, rev)
1850 ctx = logcmdutil.revsingle(repo, rev)
1851 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1851 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1852 fntemplate = opts.pop('output', b'')
1852 fntemplate = opts.pop('output', b'')
1853 if cmdutil.isstdiofilename(fntemplate):
1853 if cmdutil.isstdiofilename(fntemplate):
1854 fntemplate = b''
1854 fntemplate = b''
1855
1855
1856 if fntemplate:
1856 if fntemplate:
1857 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1857 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1858 else:
1858 else:
1859 ui.pager(b'cat')
1859 ui.pager(b'cat')
1860 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1860 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1861 with fm:
1861 with fm:
1862 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1862 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1863
1863
1864
1864
1865 @command(
1865 @command(
1866 b'clone',
1866 b'clone',
1867 [
1867 [
1868 (
1868 (
1869 b'U',
1869 b'U',
1870 b'noupdate',
1870 b'noupdate',
1871 None,
1871 None,
1872 _(
1872 _(
1873 b'the clone will include an empty working '
1873 b'the clone will include an empty working '
1874 b'directory (only a repository)'
1874 b'directory (only a repository)'
1875 ),
1875 ),
1876 ),
1876 ),
1877 (
1877 (
1878 b'u',
1878 b'u',
1879 b'updaterev',
1879 b'updaterev',
1880 b'',
1880 b'',
1881 _(b'revision, tag, or branch to check out'),
1881 _(b'revision, tag, or branch to check out'),
1882 _(b'REV'),
1882 _(b'REV'),
1883 ),
1883 ),
1884 (
1884 (
1885 b'r',
1885 b'r',
1886 b'rev',
1886 b'rev',
1887 [],
1887 [],
1888 _(
1888 _(
1889 b'do not clone everything, but include this changeset'
1889 b'do not clone everything, but include this changeset'
1890 b' and its ancestors'
1890 b' and its ancestors'
1891 ),
1891 ),
1892 _(b'REV'),
1892 _(b'REV'),
1893 ),
1893 ),
1894 (
1894 (
1895 b'b',
1895 b'b',
1896 b'branch',
1896 b'branch',
1897 [],
1897 [],
1898 _(
1898 _(
1899 b'do not clone everything, but include this branch\'s'
1899 b'do not clone everything, but include this branch\'s'
1900 b' changesets and their ancestors'
1900 b' changesets and their ancestors'
1901 ),
1901 ),
1902 _(b'BRANCH'),
1902 _(b'BRANCH'),
1903 ),
1903 ),
1904 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1904 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1905 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1905 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1906 (b'', b'stream', None, _(b'clone with minimal data processing')),
1906 (b'', b'stream', None, _(b'clone with minimal data processing')),
1907 ]
1907 ]
1908 + remoteopts,
1908 + remoteopts,
1909 _(b'[OPTION]... SOURCE [DEST]'),
1909 _(b'[OPTION]... SOURCE [DEST]'),
1910 helpcategory=command.CATEGORY_REPO_CREATION,
1910 helpcategory=command.CATEGORY_REPO_CREATION,
1911 helpbasic=True,
1911 helpbasic=True,
1912 norepo=True,
1912 norepo=True,
1913 )
1913 )
1914 def clone(ui, source, dest=None, **opts):
1914 def clone(ui, source, dest=None, **opts):
1915 """make a copy of an existing repository
1915 """make a copy of an existing repository
1916
1916
1917 Create a copy of an existing repository in a new directory.
1917 Create a copy of an existing repository in a new directory.
1918
1918
1919 If no destination directory name is specified, it defaults to the
1919 If no destination directory name is specified, it defaults to the
1920 basename of the source.
1920 basename of the source.
1921
1921
1922 The location of the source is added to the new repository's
1922 The location of the source is added to the new repository's
1923 ``.hg/hgrc`` file, as the default to be used for future pulls.
1923 ``.hg/hgrc`` file, as the default to be used for future pulls.
1924
1924
1925 Only local paths and ``ssh://`` URLs are supported as
1925 Only local paths and ``ssh://`` URLs are supported as
1926 destinations. For ``ssh://`` destinations, no working directory or
1926 destinations. For ``ssh://`` destinations, no working directory or
1927 ``.hg/hgrc`` will be created on the remote side.
1927 ``.hg/hgrc`` will be created on the remote side.
1928
1928
1929 If the source repository has a bookmark called '@' set, that
1929 If the source repository has a bookmark called '@' set, that
1930 revision will be checked out in the new repository by default.
1930 revision will be checked out in the new repository by default.
1931
1931
1932 To check out a particular version, use -u/--update, or
1932 To check out a particular version, use -u/--update, or
1933 -U/--noupdate to create a clone with no working directory.
1933 -U/--noupdate to create a clone with no working directory.
1934
1934
1935 To pull only a subset of changesets, specify one or more revisions
1935 To pull only a subset of changesets, specify one or more revisions
1936 identifiers with -r/--rev or branches with -b/--branch. The
1936 identifiers with -r/--rev or branches with -b/--branch. The
1937 resulting clone will contain only the specified changesets and
1937 resulting clone will contain only the specified changesets and
1938 their ancestors. These options (or 'clone src#rev dest') imply
1938 their ancestors. These options (or 'clone src#rev dest') imply
1939 --pull, even for local source repositories.
1939 --pull, even for local source repositories.
1940
1940
1941 In normal clone mode, the remote normalizes repository data into a common
1941 In normal clone mode, the remote normalizes repository data into a common
1942 exchange format and the receiving end translates this data into its local
1942 exchange format and the receiving end translates this data into its local
1943 storage format. --stream activates a different clone mode that essentially
1943 storage format. --stream activates a different clone mode that essentially
1944 copies repository files from the remote with minimal data processing. This
1944 copies repository files from the remote with minimal data processing. This
1945 significantly reduces the CPU cost of a clone both remotely and locally.
1945 significantly reduces the CPU cost of a clone both remotely and locally.
1946 However, it often increases the transferred data size by 30-40%. This can
1946 However, it often increases the transferred data size by 30-40%. This can
1947 result in substantially faster clones where I/O throughput is plentiful,
1947 result in substantially faster clones where I/O throughput is plentiful,
1948 especially for larger repositories. A side-effect of --stream clones is
1948 especially for larger repositories. A side-effect of --stream clones is
1949 that storage settings and requirements on the remote are applied locally:
1949 that storage settings and requirements on the remote are applied locally:
1950 a modern client may inherit legacy or inefficient storage used by the
1950 a modern client may inherit legacy or inefficient storage used by the
1951 remote or a legacy Mercurial client may not be able to clone from a
1951 remote or a legacy Mercurial client may not be able to clone from a
1952 modern Mercurial remote.
1952 modern Mercurial remote.
1953
1953
1954 .. note::
1954 .. note::
1955
1955
1956 Specifying a tag will include the tagged changeset but not the
1956 Specifying a tag will include the tagged changeset but not the
1957 changeset containing the tag.
1957 changeset containing the tag.
1958
1958
1959 .. container:: verbose
1959 .. container:: verbose
1960
1960
1961 For efficiency, hardlinks are used for cloning whenever the
1961 For efficiency, hardlinks are used for cloning whenever the
1962 source and destination are on the same filesystem (note this
1962 source and destination are on the same filesystem (note this
1963 applies only to the repository data, not to the working
1963 applies only to the repository data, not to the working
1964 directory). Some filesystems, such as AFS, implement hardlinking
1964 directory). Some filesystems, such as AFS, implement hardlinking
1965 incorrectly, but do not report errors. In these cases, use the
1965 incorrectly, but do not report errors. In these cases, use the
1966 --pull option to avoid hardlinking.
1966 --pull option to avoid hardlinking.
1967
1967
1968 Mercurial will update the working directory to the first applicable
1968 Mercurial will update the working directory to the first applicable
1969 revision from this list:
1969 revision from this list:
1970
1970
1971 a) null if -U or the source repository has no changesets
1971 a) null if -U or the source repository has no changesets
1972 b) if -u . and the source repository is local, the first parent of
1972 b) if -u . and the source repository is local, the first parent of
1973 the source repository's working directory
1973 the source repository's working directory
1974 c) the changeset specified with -u (if a branch name, this means the
1974 c) the changeset specified with -u (if a branch name, this means the
1975 latest head of that branch)
1975 latest head of that branch)
1976 d) the changeset specified with -r
1976 d) the changeset specified with -r
1977 e) the tipmost head specified with -b
1977 e) the tipmost head specified with -b
1978 f) the tipmost head specified with the url#branch source syntax
1978 f) the tipmost head specified with the url#branch source syntax
1979 g) the revision marked with the '@' bookmark, if present
1979 g) the revision marked with the '@' bookmark, if present
1980 h) the tipmost head of the default branch
1980 h) the tipmost head of the default branch
1981 i) tip
1981 i) tip
1982
1982
1983 When cloning from servers that support it, Mercurial may fetch
1983 When cloning from servers that support it, Mercurial may fetch
1984 pre-generated data from a server-advertised URL or inline from the
1984 pre-generated data from a server-advertised URL or inline from the
1985 same stream. When this is done, hooks operating on incoming changesets
1985 same stream. When this is done, hooks operating on incoming changesets
1986 and changegroups may fire more than once, once for each pre-generated
1986 and changegroups may fire more than once, once for each pre-generated
1987 bundle and as well as for any additional remaining data. In addition,
1987 bundle and as well as for any additional remaining data. In addition,
1988 if an error occurs, the repository may be rolled back to a partial
1988 if an error occurs, the repository may be rolled back to a partial
1989 clone. This behavior may change in future releases.
1989 clone. This behavior may change in future releases.
1990 See :hg:`help -e clonebundles` for more.
1990 See :hg:`help -e clonebundles` for more.
1991
1991
1992 Examples:
1992 Examples:
1993
1993
1994 - clone a remote repository to a new directory named hg/::
1994 - clone a remote repository to a new directory named hg/::
1995
1995
1996 hg clone https://www.mercurial-scm.org/repo/hg/
1996 hg clone https://www.mercurial-scm.org/repo/hg/
1997
1997
1998 - create a lightweight local clone::
1998 - create a lightweight local clone::
1999
1999
2000 hg clone project/ project-feature/
2000 hg clone project/ project-feature/
2001
2001
2002 - clone from an absolute path on an ssh server (note double-slash)::
2002 - clone from an absolute path on an ssh server (note double-slash)::
2003
2003
2004 hg clone ssh://user@server//home/projects/alpha/
2004 hg clone ssh://user@server//home/projects/alpha/
2005
2005
2006 - do a streaming clone while checking out a specified version::
2006 - do a streaming clone while checking out a specified version::
2007
2007
2008 hg clone --stream http://server/repo -u 1.5
2008 hg clone --stream http://server/repo -u 1.5
2009
2009
2010 - create a repository without changesets after a particular revision::
2010 - create a repository without changesets after a particular revision::
2011
2011
2012 hg clone -r 04e544 experimental/ good/
2012 hg clone -r 04e544 experimental/ good/
2013
2013
2014 - clone (and track) a particular named branch::
2014 - clone (and track) a particular named branch::
2015
2015
2016 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2016 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2017
2017
2018 See :hg:`help urls` for details on specifying URLs.
2018 See :hg:`help urls` for details on specifying URLs.
2019
2019
2020 Returns 0 on success.
2020 Returns 0 on success.
2021 """
2021 """
2022 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2022 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2023
2023
2024 # --include/--exclude can come from narrow or sparse.
2024 # --include/--exclude can come from narrow or sparse.
2025 includepats, excludepats = None, None
2025 includepats, excludepats = None, None
2026
2026
2027 # hg.clone() differentiates between None and an empty set. So make sure
2027 # hg.clone() differentiates between None and an empty set. So make sure
2028 # patterns are sets if narrow is requested without patterns.
2028 # patterns are sets if narrow is requested without patterns.
2029 if opts.get('narrow'):
2029 if opts.get('narrow'):
2030 includepats = set()
2030 includepats = set()
2031 excludepats = set()
2031 excludepats = set()
2032
2032
2033 if opts.get('include'):
2033 if opts.get('include'):
2034 includepats = narrowspec.parsepatterns(opts.get('include'))
2034 includepats = narrowspec.parsepatterns(opts.get('include'))
2035 if opts.get('exclude'):
2035 if opts.get('exclude'):
2036 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2036 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2037
2037
2038 r = hg.clone(
2038 r = hg.clone(
2039 ui,
2039 ui,
2040 pycompat.byteskwargs(opts),
2040 pycompat.byteskwargs(opts),
2041 source,
2041 source,
2042 dest,
2042 dest,
2043 pull=opts.get('pull'),
2043 pull=opts.get('pull'),
2044 stream=opts.get('stream') or opts.get('uncompressed'),
2044 stream=opts.get('stream') or opts.get('uncompressed'),
2045 revs=opts.get('rev'),
2045 revs=opts.get('rev'),
2046 update=opts.get('updaterev') or not opts.get('noupdate'),
2046 update=opts.get('updaterev') or not opts.get('noupdate'),
2047 branch=opts.get('branch'),
2047 branch=opts.get('branch'),
2048 shareopts=opts.get('shareopts'),
2048 shareopts=opts.get('shareopts'),
2049 storeincludepats=includepats,
2049 storeincludepats=includepats,
2050 storeexcludepats=excludepats,
2050 storeexcludepats=excludepats,
2051 depth=opts.get('depth') or None,
2051 depth=opts.get('depth') or None,
2052 )
2052 )
2053
2053
2054 return r is None
2054 return r is None
2055
2055
2056
2056
2057 @command(
2057 @command(
2058 b'commit|ci',
2058 b'commit|ci',
2059 [
2059 [
2060 (
2060 (
2061 b'A',
2061 b'A',
2062 b'addremove',
2062 b'addremove',
2063 None,
2063 None,
2064 _(b'mark new/missing files as added/removed before committing'),
2064 _(b'mark new/missing files as added/removed before committing'),
2065 ),
2065 ),
2066 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2066 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2067 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2067 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2068 (b's', b'secret', None, _(b'use the secret phase for committing')),
2068 (b's', b'secret', None, _(b'use the secret phase for committing')),
2069 (b'', b'draft', None, _(b'use the draft phase for committing')),
2069 (b'', b'draft', None, _(b'use the draft phase for committing')),
2070 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2070 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2071 (
2071 (
2072 b'',
2072 b'',
2073 b'force-close-branch',
2073 b'force-close-branch',
2074 None,
2074 None,
2075 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2075 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2076 ),
2076 ),
2077 (b'i', b'interactive', None, _(b'use interactive mode')),
2077 (b'i', b'interactive', None, _(b'use interactive mode')),
2078 ]
2078 ]
2079 + walkopts
2079 + walkopts
2080 + commitopts
2080 + commitopts
2081 + commitopts2
2081 + commitopts2
2082 + subrepoopts,
2082 + subrepoopts,
2083 _(b'[OPTION]... [FILE]...'),
2083 _(b'[OPTION]... [FILE]...'),
2084 helpcategory=command.CATEGORY_COMMITTING,
2084 helpcategory=command.CATEGORY_COMMITTING,
2085 helpbasic=True,
2085 helpbasic=True,
2086 inferrepo=True,
2086 inferrepo=True,
2087 )
2087 )
2088 def commit(ui, repo, *pats, **opts):
2088 def commit(ui, repo, *pats, **opts):
2089 """commit the specified files or all outstanding changes
2089 """commit the specified files or all outstanding changes
2090
2090
2091 Commit changes to the given files into the repository. Unlike a
2091 Commit changes to the given files into the repository. Unlike a
2092 centralized SCM, this operation is a local operation. See
2092 centralized SCM, this operation is a local operation. See
2093 :hg:`push` for a way to actively distribute your changes.
2093 :hg:`push` for a way to actively distribute your changes.
2094
2094
2095 If a list of files is omitted, all changes reported by :hg:`status`
2095 If a list of files is omitted, all changes reported by :hg:`status`
2096 will be committed.
2096 will be committed.
2097
2097
2098 If you are committing the result of a merge, do not provide any
2098 If you are committing the result of a merge, do not provide any
2099 filenames or -I/-X filters.
2099 filenames or -I/-X filters.
2100
2100
2101 If no commit message is specified, Mercurial starts your
2101 If no commit message is specified, Mercurial starts your
2102 configured editor where you can enter a message. In case your
2102 configured editor where you can enter a message. In case your
2103 commit fails, you will find a backup of your message in
2103 commit fails, you will find a backup of your message in
2104 ``.hg/last-message.txt``.
2104 ``.hg/last-message.txt``.
2105
2105
2106 The --close-branch flag can be used to mark the current branch
2106 The --close-branch flag can be used to mark the current branch
2107 head closed. When all heads of a branch are closed, the branch
2107 head closed. When all heads of a branch are closed, the branch
2108 will be considered closed and no longer listed.
2108 will be considered closed and no longer listed.
2109
2109
2110 The --amend flag can be used to amend the parent of the
2110 The --amend flag can be used to amend the parent of the
2111 working directory with a new commit that contains the changes
2111 working directory with a new commit that contains the changes
2112 in the parent in addition to those currently reported by :hg:`status`,
2112 in the parent in addition to those currently reported by :hg:`status`,
2113 if there are any. The old commit is stored in a backup bundle in
2113 if there are any. The old commit is stored in a backup bundle in
2114 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2114 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2115 on how to restore it).
2115 on how to restore it).
2116
2116
2117 Message, user and date are taken from the amended commit unless
2117 Message, user and date are taken from the amended commit unless
2118 specified. When a message isn't specified on the command line,
2118 specified. When a message isn't specified on the command line,
2119 the editor will open with the message of the amended commit.
2119 the editor will open with the message of the amended commit.
2120
2120
2121 It is not possible to amend public changesets (see :hg:`help phases`)
2121 It is not possible to amend public changesets (see :hg:`help phases`)
2122 or changesets that have children.
2122 or changesets that have children.
2123
2123
2124 See :hg:`help dates` for a list of formats valid for -d/--date.
2124 See :hg:`help dates` for a list of formats valid for -d/--date.
2125
2125
2126 Returns 0 on success, 1 if nothing changed.
2126 Returns 0 on success, 1 if nothing changed.
2127
2127
2128 .. container:: verbose
2128 .. container:: verbose
2129
2129
2130 Examples:
2130 Examples:
2131
2131
2132 - commit all files ending in .py::
2132 - commit all files ending in .py::
2133
2133
2134 hg commit --include "set:**.py"
2134 hg commit --include "set:**.py"
2135
2135
2136 - commit all non-binary files::
2136 - commit all non-binary files::
2137
2137
2138 hg commit --exclude "set:binary()"
2138 hg commit --exclude "set:binary()"
2139
2139
2140 - amend the current commit and set the date to now::
2140 - amend the current commit and set the date to now::
2141
2141
2142 hg commit --amend --date now
2142 hg commit --amend --date now
2143 """
2143 """
2144 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2144 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2145 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2145 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2146 with repo.wlock(), repo.lock():
2146 with repo.wlock(), repo.lock():
2147 return _docommit(ui, repo, *pats, **opts)
2147 return _docommit(ui, repo, *pats, **opts)
2148
2148
2149
2149
2150 def _docommit(ui, repo, *pats, **opts):
2150 def _docommit(ui, repo, *pats, **opts):
2151 if opts.get('interactive'):
2151 if opts.get('interactive'):
2152 opts.pop('interactive')
2152 opts.pop('interactive')
2153 ret = cmdutil.dorecord(
2153 ret = cmdutil.dorecord(
2154 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2154 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2155 )
2155 )
2156 # ret can be 0 (no changes to record) or the value returned by
2156 # ret can be 0 (no changes to record) or the value returned by
2157 # commit(), 1 if nothing changed or None on success.
2157 # commit(), 1 if nothing changed or None on success.
2158 return 1 if ret == 0 else ret
2158 return 1 if ret == 0 else ret
2159
2159
2160 if opts.get('subrepos'):
2160 if opts.get('subrepos'):
2161 # Let --subrepos on the command line override config setting.
2161 # Let --subrepos on the command line override config setting.
2162 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2162 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2163
2163
2164 cmdutil.checkunfinished(repo, commit=True)
2164 cmdutil.checkunfinished(repo, commit=True)
2165
2165
2166 branch = repo[None].branch()
2166 branch = repo[None].branch()
2167 bheads = repo.branchheads(branch)
2167 bheads = repo.branchheads(branch)
2168 tip = repo.changelog.tip()
2168 tip = repo.changelog.tip()
2169
2169
2170 extra = {}
2170 extra = {}
2171 if opts.get('close_branch') or opts.get('force_close_branch'):
2171 if opts.get('close_branch') or opts.get('force_close_branch'):
2172 extra[b'close'] = b'1'
2172 extra[b'close'] = b'1'
2173
2173
2174 if repo[b'.'].closesbranch():
2174 if repo[b'.'].closesbranch():
2175 # Not ideal, but let us do an extra status early to prevent early
2175 # Not ideal, but let us do an extra status early to prevent early
2176 # bail out.
2176 # bail out.
2177 matcher = scmutil.match(
2177 matcher = scmutil.match(
2178 repo[None], pats, pycompat.byteskwargs(opts)
2178 repo[None], pats, pycompat.byteskwargs(opts)
2179 )
2179 )
2180 s = repo.status(match=matcher)
2180 s = repo.status(match=matcher)
2181 if s.modified or s.added or s.removed:
2181 if s.modified or s.added or s.removed:
2182 bheads = repo.branchheads(branch, closed=True)
2182 bheads = repo.branchheads(branch, closed=True)
2183 else:
2183 else:
2184 msg = _(b'current revision is already a branch closing head')
2184 msg = _(b'current revision is already a branch closing head')
2185 raise error.InputError(msg)
2185 raise error.InputError(msg)
2186
2186
2187 if not bheads:
2187 if not bheads:
2188 raise error.InputError(
2188 raise error.InputError(
2189 _(b'branch "%s" has no heads to close') % branch
2189 _(b'branch "%s" has no heads to close') % branch
2190 )
2190 )
2191 elif (
2191 elif (
2192 branch == repo[b'.'].branch()
2192 branch == repo[b'.'].branch()
2193 and repo[b'.'].node() not in bheads
2193 and repo[b'.'].node() not in bheads
2194 and not opts.get('force_close_branch')
2194 and not opts.get('force_close_branch')
2195 ):
2195 ):
2196 hint = _(
2196 hint = _(
2197 b'use --force-close-branch to close branch from a non-head'
2197 b'use --force-close-branch to close branch from a non-head'
2198 b' changeset'
2198 b' changeset'
2199 )
2199 )
2200 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2200 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2201 elif opts.get('amend'):
2201 elif opts.get('amend'):
2202 if (
2202 if (
2203 repo[b'.'].p1().branch() != branch
2203 repo[b'.'].p1().branch() != branch
2204 and repo[b'.'].p2().branch() != branch
2204 and repo[b'.'].p2().branch() != branch
2205 ):
2205 ):
2206 raise error.InputError(_(b'can only close branch heads'))
2206 raise error.InputError(_(b'can only close branch heads'))
2207
2207
2208 if opts.get('amend'):
2208 if opts.get('amend'):
2209 if ui.configbool(b'ui', b'commitsubrepos'):
2209 if ui.configbool(b'ui', b'commitsubrepos'):
2210 raise error.InputError(
2210 raise error.InputError(
2211 _(b'cannot amend with ui.commitsubrepos enabled')
2211 _(b'cannot amend with ui.commitsubrepos enabled')
2212 )
2212 )
2213
2213
2214 old = repo[b'.']
2214 old = repo[b'.']
2215 rewriteutil.precheck(repo, [old.rev()], b'amend')
2215 rewriteutil.precheck(repo, [old.rev()], b'amend')
2216
2216
2217 # Currently histedit gets confused if an amend happens while histedit
2217 # Currently histedit gets confused if an amend happens while histedit
2218 # is in progress. Since we have a checkunfinished command, we are
2218 # is in progress. Since we have a checkunfinished command, we are
2219 # temporarily honoring it.
2219 # temporarily honoring it.
2220 #
2220 #
2221 # Note: eventually this guard will be removed. Please do not expect
2221 # Note: eventually this guard will be removed. Please do not expect
2222 # this behavior to remain.
2222 # this behavior to remain.
2223 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2223 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2224 cmdutil.checkunfinished(repo)
2224 cmdutil.checkunfinished(repo)
2225
2225
2226 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2226 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2227 if node == old.node():
2227 if node == old.node():
2228 ui.status(_(b"nothing changed\n"))
2228 ui.status(_(b"nothing changed\n"))
2229 return 1
2229 return 1
2230 else:
2230 else:
2231
2231
2232 def commitfunc(ui, repo, message, match, opts):
2232 def commitfunc(ui, repo, message, match, opts):
2233 overrides = {}
2233 overrides = {}
2234 if opts.get(b'secret'):
2234 if opts.get(b'secret'):
2235 overrides[(b'phases', b'new-commit')] = b'secret'
2235 overrides[(b'phases', b'new-commit')] = b'secret'
2236 elif opts.get(b'draft'):
2236 elif opts.get(b'draft'):
2237 overrides[(b'phases', b'new-commit')] = b'draft'
2237 overrides[(b'phases', b'new-commit')] = b'draft'
2238
2238
2239 baseui = repo.baseui
2239 baseui = repo.baseui
2240 with baseui.configoverride(overrides, b'commit'):
2240 with baseui.configoverride(overrides, b'commit'):
2241 with ui.configoverride(overrides, b'commit'):
2241 with ui.configoverride(overrides, b'commit'):
2242 editform = cmdutil.mergeeditform(
2242 editform = cmdutil.mergeeditform(
2243 repo[None], b'commit.normal'
2243 repo[None], b'commit.normal'
2244 )
2244 )
2245 editor = cmdutil.getcommiteditor(
2245 editor = cmdutil.getcommiteditor(
2246 editform=editform, **pycompat.strkwargs(opts)
2246 editform=editform, **pycompat.strkwargs(opts)
2247 )
2247 )
2248 return repo.commit(
2248 return repo.commit(
2249 message,
2249 message,
2250 opts.get(b'user'),
2250 opts.get(b'user'),
2251 opts.get(b'date'),
2251 opts.get(b'date'),
2252 match,
2252 match,
2253 editor=editor,
2253 editor=editor,
2254 extra=extra,
2254 extra=extra,
2255 )
2255 )
2256
2256
2257 node = cmdutil.commit(
2257 node = cmdutil.commit(
2258 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2258 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2259 )
2259 )
2260
2260
2261 if not node:
2261 if not node:
2262 stat = cmdutil.postcommitstatus(
2262 stat = cmdutil.postcommitstatus(
2263 repo, pats, pycompat.byteskwargs(opts)
2263 repo, pats, pycompat.byteskwargs(opts)
2264 )
2264 )
2265 if stat.deleted:
2265 if stat.deleted:
2266 ui.status(
2266 ui.status(
2267 _(
2267 _(
2268 b"nothing changed (%d missing files, see "
2268 b"nothing changed (%d missing files, see "
2269 b"'hg status')\n"
2269 b"'hg status')\n"
2270 )
2270 )
2271 % len(stat.deleted)
2271 % len(stat.deleted)
2272 )
2272 )
2273 else:
2273 else:
2274 ui.status(_(b"nothing changed\n"))
2274 ui.status(_(b"nothing changed\n"))
2275 return 1
2275 return 1
2276
2276
2277 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2277 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2278
2278
2279 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2279 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2280 status(
2280 status(
2281 ui,
2281 ui,
2282 repo,
2282 repo,
2283 modified=True,
2283 modified=True,
2284 added=True,
2284 added=True,
2285 removed=True,
2285 removed=True,
2286 deleted=True,
2286 deleted=True,
2287 unknown=True,
2287 unknown=True,
2288 subrepos=opts.get('subrepos'),
2288 subrepos=opts.get('subrepos'),
2289 )
2289 )
2290
2290
2291
2291
2292 @command(
2292 @command(
2293 b'config|showconfig|debugconfig',
2293 b'config|showconfig|debugconfig',
2294 [
2294 [
2295 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2295 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2296 # This is experimental because we need
2296 # This is experimental because we need
2297 # * reasonable behavior around aliases,
2297 # * reasonable behavior around aliases,
2298 # * decide if we display [debug] [experimental] and [devel] section par
2298 # * decide if we display [debug] [experimental] and [devel] section par
2299 # default
2299 # default
2300 # * some way to display "generic" config entry (the one matching
2300 # * some way to display "generic" config entry (the one matching
2301 # regexp,
2301 # regexp,
2302 # * proper display of the different value type
2302 # * proper display of the different value type
2303 # * a better way to handle <DYNAMIC> values (and variable types),
2303 # * a better way to handle <DYNAMIC> values (and variable types),
2304 # * maybe some type information ?
2304 # * maybe some type information ?
2305 (
2305 (
2306 b'',
2306 b'',
2307 b'exp-all-known',
2307 b'exp-all-known',
2308 None,
2308 None,
2309 _(b'show all known config option (EXPERIMENTAL)'),
2309 _(b'show all known config option (EXPERIMENTAL)'),
2310 ),
2310 ),
2311 (b'e', b'edit', None, _(b'edit user config')),
2311 (b'e', b'edit', None, _(b'edit user config')),
2312 (b'l', b'local', None, _(b'edit repository config')),
2312 (b'l', b'local', None, _(b'edit repository config')),
2313 (b'', b'source', None, _(b'show source of configuration value')),
2313 (b'', b'source', None, _(b'show source of configuration value')),
2314 (
2314 (
2315 b'',
2315 b'',
2316 b'shared',
2316 b'shared',
2317 None,
2317 None,
2318 _(b'edit shared source repository config (EXPERIMENTAL)'),
2318 _(b'edit shared source repository config (EXPERIMENTAL)'),
2319 ),
2319 ),
2320 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2320 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2321 (b'g', b'global', None, _(b'edit global config')),
2321 (b'g', b'global', None, _(b'edit global config')),
2322 ]
2322 ]
2323 + formatteropts,
2323 + formatteropts,
2324 _(b'[-u] [NAME]...'),
2324 _(b'[-u] [NAME]...'),
2325 helpcategory=command.CATEGORY_HELP,
2325 helpcategory=command.CATEGORY_HELP,
2326 optionalrepo=True,
2326 optionalrepo=True,
2327 intents={INTENT_READONLY},
2327 intents={INTENT_READONLY},
2328 )
2328 )
2329 def config(ui, repo, *values, **opts):
2329 def config(ui, repo, *values, **opts):
2330 """show combined config settings from all hgrc files
2330 """show combined config settings from all hgrc files
2331
2331
2332 With no arguments, print names and values of all config items.
2332 With no arguments, print names and values of all config items.
2333
2333
2334 With one argument of the form section.name, print just the value
2334 With one argument of the form section.name, print just the value
2335 of that config item.
2335 of that config item.
2336
2336
2337 With multiple arguments, print names and values of all config
2337 With multiple arguments, print names and values of all config
2338 items with matching section names or section.names.
2338 items with matching section names or section.names.
2339
2339
2340 With --edit, start an editor on the user-level config file. With
2340 With --edit, start an editor on the user-level config file. With
2341 --global, edit the system-wide config file. With --local, edit the
2341 --global, edit the system-wide config file. With --local, edit the
2342 repository-level config file.
2342 repository-level config file.
2343
2343
2344 With --source, the source (filename and line number) is printed
2344 With --source, the source (filename and line number) is printed
2345 for each config item.
2345 for each config item.
2346
2346
2347 See :hg:`help config` for more information about config files.
2347 See :hg:`help config` for more information about config files.
2348
2348
2349 .. container:: verbose
2349 .. container:: verbose
2350
2350
2351 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2351 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2352 This file is not shared across shares when in share-safe mode.
2352 This file is not shared across shares when in share-safe mode.
2353
2353
2354 Template:
2354 Template:
2355
2355
2356 The following keywords are supported. See also :hg:`help templates`.
2356 The following keywords are supported. See also :hg:`help templates`.
2357
2357
2358 :name: String. Config name.
2358 :name: String. Config name.
2359 :source: String. Filename and line number where the item is defined.
2359 :source: String. Filename and line number where the item is defined.
2360 :value: String. Config value.
2360 :value: String. Config value.
2361
2361
2362 The --shared flag can be used to edit the config file of shared source
2362 The --shared flag can be used to edit the config file of shared source
2363 repository. It only works when you have shared using the experimental
2363 repository. It only works when you have shared using the experimental
2364 share safe feature.
2364 share safe feature.
2365
2365
2366 Returns 0 on success, 1 if NAME does not exist.
2366 Returns 0 on success, 1 if NAME does not exist.
2367
2367
2368 """
2368 """
2369 edit_level = config_command.find_edit_level(ui, repo, opts)
2369 edit_level = config_command.find_edit_level(ui, repo, opts)
2370 if edit_level is not None:
2370 if edit_level is not None:
2371 return config_command.edit_config(ui, repo, edit_level)
2371 return config_command.edit_config(ui, repo, edit_level)
2372
2372
2373 ui.pager(b'config')
2373 ui.pager(b'config')
2374 config_command.show_component(ui, repo)
2374 config_command.show_component(ui, repo)
2375
2375
2376 matched = config_command.show_config(
2376 matched = config_command.show_config(
2377 ui,
2377 ui,
2378 repo,
2378 repo,
2379 value_filters=values,
2379 value_filters=values,
2380 formatter_options=pycompat.byteskwargs(opts),
2380 formatter_options=pycompat.byteskwargs(opts),
2381 untrusted=bool(opts.get('untrusted')),
2381 untrusted=bool(opts.get('untrusted')),
2382 all_known=bool(opts.get('exp_all_known')),
2382 all_known=bool(opts.get('exp_all_known')),
2383 show_source=bool(ui.debugflag or opts.get('source')),
2383 show_source=bool(ui.debugflag or opts.get('source')),
2384 )
2384 )
2385 if matched:
2385 if matched:
2386 return 0
2386 return 0
2387 return 1
2387 return 1
2388
2388
2389
2389
2390 @command(
2390 @command(
2391 b'continue',
2391 b'continue',
2392 dryrunopts,
2392 dryrunopts,
2393 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2393 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2394 helpbasic=True,
2394 helpbasic=True,
2395 )
2395 )
2396 def continuecmd(ui, repo, **opts):
2396 def continuecmd(ui, repo, **opts):
2397 """resumes an interrupted operation (EXPERIMENTAL)
2397 """resumes an interrupted operation (EXPERIMENTAL)
2398
2398
2399 Finishes a multistep operation like graft, histedit, rebase, merge,
2399 Finishes a multistep operation like graft, histedit, rebase, merge,
2400 and unshelve if they are in an interrupted state.
2400 and unshelve if they are in an interrupted state.
2401
2401
2402 use --dry-run/-n to dry run the command.
2402 use --dry-run/-n to dry run the command.
2403 """
2403 """
2404 dryrun = opts.get('dry_run')
2404 dryrun = opts.get('dry_run')
2405 contstate = cmdutil.getunfinishedstate(repo)
2405 contstate = cmdutil.getunfinishedstate(repo)
2406 if not contstate:
2406 if not contstate:
2407 raise error.StateError(_(b'no operation in progress'))
2407 raise error.StateError(_(b'no operation in progress'))
2408 if not contstate.continuefunc:
2408 if not contstate.continuefunc:
2409 raise error.StateError(
2409 raise error.StateError(
2410 (
2410 (
2411 _(b"%s in progress but does not support 'hg continue'")
2411 _(b"%s in progress but does not support 'hg continue'")
2412 % (contstate._opname)
2412 % (contstate._opname)
2413 ),
2413 ),
2414 hint=contstate.continuemsg(),
2414 hint=contstate.continuemsg(),
2415 )
2415 )
2416 if dryrun:
2416 if dryrun:
2417 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2417 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2418 return
2418 return
2419 return contstate.continuefunc(ui, repo)
2419 return contstate.continuefunc(ui, repo)
2420
2420
2421
2421
2422 @command(
2422 @command(
2423 b'copy|cp',
2423 b'copy|cp',
2424 [
2424 [
2425 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2425 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2426 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2426 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2427 (
2427 (
2428 b'',
2428 b'',
2429 b'at-rev',
2429 b'at-rev',
2430 b'',
2430 b'',
2431 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2431 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2432 _(b'REV'),
2432 _(b'REV'),
2433 ),
2433 ),
2434 (
2434 (
2435 b'f',
2435 b'f',
2436 b'force',
2436 b'force',
2437 None,
2437 None,
2438 _(b'forcibly copy over an existing managed file'),
2438 _(b'forcibly copy over an existing managed file'),
2439 ),
2439 ),
2440 ]
2440 ]
2441 + walkopts
2441 + walkopts
2442 + dryrunopts,
2442 + dryrunopts,
2443 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2443 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2444 helpcategory=command.CATEGORY_FILE_CONTENTS,
2444 helpcategory=command.CATEGORY_FILE_CONTENTS,
2445 )
2445 )
2446 def copy(ui, repo, *pats, **opts):
2446 def copy(ui, repo, *pats, **opts):
2447 """mark files as copied for the next commit
2447 """mark files as copied for the next commit
2448
2448
2449 Mark dest as having copies of source files. If dest is a
2449 Mark dest as having copies of source files. If dest is a
2450 directory, copies are put in that directory. If dest is a file,
2450 directory, copies are put in that directory. If dest is a file,
2451 the source must be a single file.
2451 the source must be a single file.
2452
2452
2453 By default, this command copies the contents of files as they
2453 By default, this command copies the contents of files as they
2454 exist in the working directory. If invoked with -A/--after, the
2454 exist in the working directory. If invoked with -A/--after, the
2455 operation is recorded, but no copying is performed.
2455 operation is recorded, but no copying is performed.
2456
2456
2457 To undo marking a destination file as copied, use --forget. With that
2457 To undo marking a destination file as copied, use --forget. With that
2458 option, all given (positional) arguments are unmarked as copies. The
2458 option, all given (positional) arguments are unmarked as copies. The
2459 destination file(s) will be left in place (still tracked). Note that
2459 destination file(s) will be left in place (still tracked). Note that
2460 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2460 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2461
2461
2462 This command takes effect with the next commit by default.
2462 This command takes effect with the next commit by default.
2463
2463
2464 Returns 0 on success, 1 if errors are encountered.
2464 Returns 0 on success, 1 if errors are encountered.
2465 """
2465 """
2466
2466
2467 context = lambda repo: repo.dirstate.changing_files(repo)
2467 context = lambda repo: repo.dirstate.changing_files(repo)
2468 rev = opts.get('at_rev')
2468 rev = opts.get('at_rev')
2469
2469
2470 if rev:
2470 if rev:
2471 ctx = logcmdutil.revsingle(repo, rev)
2471 ctx = logcmdutil.revsingle(repo, rev)
2472 if ctx.rev() is not None:
2472 if ctx.rev() is not None:
2473
2473
2474 def context(repo):
2474 def context(repo):
2475 return util.nullcontextmanager()
2475 return util.nullcontextmanager()
2476
2476
2477 opts['at_rev'] = ctx.rev()
2477 opts['at_rev'] = ctx.rev()
2478 with repo.wlock(), context(repo):
2478 with repo.wlock(), context(repo):
2479 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2479 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2480
2480
2481
2481
2482 @command(
2482 @command(
2483 b'debugcommands',
2483 b'debugcommands',
2484 [],
2484 [],
2485 _(b'[COMMAND]'),
2485 _(b'[COMMAND]'),
2486 helpcategory=command.CATEGORY_HELP,
2486 helpcategory=command.CATEGORY_HELP,
2487 norepo=True,
2487 norepo=True,
2488 )
2488 )
2489 def debugcommands(ui, cmd=b'', *args):
2489 def debugcommands(ui, cmd=b'', *args):
2490 """list all available commands and options"""
2490 """list all available commands and options"""
2491 for cmd, vals in sorted(table.items()):
2491 for cmd, vals in sorted(table.items()):
2492 cmd = cmd.split(b'|')[0]
2492 cmd = cmd.split(b'|')[0]
2493 opts = b', '.join([i[1] for i in vals[1]])
2493 opts = b', '.join([i[1] for i in vals[1]])
2494 ui.write(b'%s: %s\n' % (cmd, opts))
2494 ui.write(b'%s: %s\n' % (cmd, opts))
2495
2495
2496
2496
2497 @command(
2497 @command(
2498 b'debugcomplete',
2498 b'debugcomplete',
2499 [(b'o', b'options', None, _(b'show the command options'))],
2499 [(b'o', b'options', None, _(b'show the command options'))],
2500 _(b'[-o] CMD'),
2500 _(b'[-o] CMD'),
2501 helpcategory=command.CATEGORY_HELP,
2501 helpcategory=command.CATEGORY_HELP,
2502 norepo=True,
2502 norepo=True,
2503 )
2503 )
2504 def debugcomplete(ui, cmd=b'', **opts):
2504 def debugcomplete(ui, cmd=b'', **opts):
2505 """returns the completion list associated with the given command"""
2505 """returns the completion list associated with the given command"""
2506
2506
2507 if opts.get('options'):
2507 if opts.get('options'):
2508 options = []
2508 options = []
2509 otables = [globalopts]
2509 otables = [globalopts]
2510 if cmd:
2510 if cmd:
2511 aliases, entry = cmdutil.findcmd(cmd, table, False)
2511 aliases, entry = cmdutil.findcmd(cmd, table, False)
2512 otables.append(entry[1])
2512 otables.append(entry[1])
2513 for t in otables:
2513 for t in otables:
2514 for o in t:
2514 for o in t:
2515 if b"(DEPRECATED)" in o[3]:
2515 if b"(DEPRECATED)" in o[3]:
2516 continue
2516 continue
2517 if o[0]:
2517 if o[0]:
2518 options.append(b'-%s' % o[0])
2518 options.append(b'-%s' % o[0])
2519 options.append(b'--%s' % o[1])
2519 options.append(b'--%s' % o[1])
2520 ui.write(b"%s\n" % b"\n".join(options))
2520 ui.write(b"%s\n" % b"\n".join(options))
2521 return
2521 return
2522
2522
2523 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2523 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2524 if ui.verbose:
2524 if ui.verbose:
2525 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2525 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2526 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2526 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2527
2527
2528
2528
2529 @command(
2529 @command(
2530 b'diff',
2530 b'diff',
2531 [
2531 [
2532 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2532 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2533 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2533 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2534 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2534 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2535 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2535 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2536 ]
2536 ]
2537 + diffopts
2537 + diffopts
2538 + diffopts2
2538 + diffopts2
2539 + walkopts
2539 + walkopts
2540 + subrepoopts,
2540 + subrepoopts,
2541 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2541 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2542 helpcategory=command.CATEGORY_FILE_CONTENTS,
2542 helpcategory=command.CATEGORY_FILE_CONTENTS,
2543 helpbasic=True,
2543 helpbasic=True,
2544 inferrepo=True,
2544 inferrepo=True,
2545 intents={INTENT_READONLY},
2545 intents={INTENT_READONLY},
2546 )
2546 )
2547 def diff(ui, repo, *pats, **opts):
2547 def diff(ui, repo, *pats, **opts):
2548 """diff repository (or selected files)
2548 """diff repository (or selected files)
2549
2549
2550 Show differences between revisions for the specified files.
2550 Show differences between revisions for the specified files.
2551
2551
2552 Differences between files are shown using the unified diff format.
2552 Differences between files are shown using the unified diff format.
2553
2553
2554 .. note::
2554 .. note::
2555
2555
2556 :hg:`diff` may generate unexpected results for merges, as it will
2556 :hg:`diff` may generate unexpected results for merges, as it will
2557 default to comparing against the working directory's first
2557 default to comparing against the working directory's first
2558 parent changeset if no revisions are specified. To diff against the
2558 parent changeset if no revisions are specified. To diff against the
2559 conflict regions, you can use `--config diff.merge=yes`.
2559 conflict regions, you can use `--config diff.merge=yes`.
2560
2560
2561 By default, the working directory files are compared to its first parent. To
2561 By default, the working directory files are compared to its first parent. To
2562 see the differences from another revision, use --from. To see the difference
2562 see the differences from another revision, use --from. To see the difference
2563 to another revision, use --to. For example, :hg:`diff --from .^` will show
2563 to another revision, use --to. For example, :hg:`diff --from .^` will show
2564 the differences from the working copy's grandparent to the working copy,
2564 the differences from the working copy's grandparent to the working copy,
2565 :hg:`diff --to .` will show the diff from the working copy to its parent
2565 :hg:`diff --to .` will show the diff from the working copy to its parent
2566 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2566 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2567 show the diff between those two revisions.
2567 show the diff between those two revisions.
2568
2568
2569 Alternatively you can specify -c/--change with a revision to see the changes
2569 Alternatively you can specify -c/--change with a revision to see the changes
2570 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2570 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2571 equivalent to :hg:`diff --from 42^ --to 42`)
2571 equivalent to :hg:`diff --from 42^ --to 42`)
2572
2572
2573 Without the -a/--text option, diff will avoid generating diffs of
2573 Without the -a/--text option, diff will avoid generating diffs of
2574 files it detects as binary. With -a, diff will generate a diff
2574 files it detects as binary. With -a, diff will generate a diff
2575 anyway, probably with undesirable results.
2575 anyway, probably with undesirable results.
2576
2576
2577 Use the -g/--git option to generate diffs in the git extended diff
2577 Use the -g/--git option to generate diffs in the git extended diff
2578 format. For more information, read :hg:`help diffs`.
2578 format. For more information, read :hg:`help diffs`.
2579
2579
2580 .. container:: verbose
2580 .. container:: verbose
2581
2581
2582 Examples:
2582 Examples:
2583
2583
2584 - compare a file in the current working directory to its parent::
2584 - compare a file in the current working directory to its parent::
2585
2585
2586 hg diff foo.c
2586 hg diff foo.c
2587
2587
2588 - compare two historical versions of a directory, with rename info::
2588 - compare two historical versions of a directory, with rename info::
2589
2589
2590 hg diff --git --from 1.0 --to 1.2 lib/
2590 hg diff --git --from 1.0 --to 1.2 lib/
2591
2591
2592 - get change stats relative to the last change on some date::
2592 - get change stats relative to the last change on some date::
2593
2593
2594 hg diff --stat --from "date('may 2')"
2594 hg diff --stat --from "date('may 2')"
2595
2595
2596 - diff all newly-added files that contain a keyword::
2596 - diff all newly-added files that contain a keyword::
2597
2597
2598 hg diff "set:added() and grep(GNU)"
2598 hg diff "set:added() and grep(GNU)"
2599
2599
2600 - compare a revision and its parents::
2600 - compare a revision and its parents::
2601
2601
2602 hg diff -c 9353 # compare against first parent
2602 hg diff -c 9353 # compare against first parent
2603 hg diff --from 9353^ --to 9353 # same using revset syntax
2603 hg diff --from 9353^ --to 9353 # same using revset syntax
2604 hg diff --from 9353^2 --to 9353 # compare against the second parent
2604 hg diff --from 9353^2 --to 9353 # compare against the second parent
2605
2605
2606 Returns 0 on success.
2606 Returns 0 on success.
2607 """
2607 """
2608
2608
2609 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2609 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2610 opts = pycompat.byteskwargs(opts)
2610 opts = pycompat.byteskwargs(opts)
2611 revs = opts.get(b'rev')
2611 revs = opts.get(b'rev')
2612 change = opts.get(b'change')
2612 change = opts.get(b'change')
2613 from_rev = opts.get(b'from')
2613 from_rev = opts.get(b'from')
2614 to_rev = opts.get(b'to')
2614 to_rev = opts.get(b'to')
2615 stat = opts.get(b'stat')
2615 stat = opts.get(b'stat')
2616 reverse = opts.get(b'reverse')
2616 reverse = opts.get(b'reverse')
2617
2617
2618 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2618 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2619 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2619 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2620 if change:
2620 if change:
2621 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2621 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2622 ctx2 = logcmdutil.revsingle(repo, change, None)
2622 ctx2 = logcmdutil.revsingle(repo, change, None)
2623 ctx1 = diffutil.diff_parent(ctx2)
2623 ctx1 = diffutil.diff_parent(ctx2)
2624 elif from_rev or to_rev:
2624 elif from_rev or to_rev:
2625 repo = scmutil.unhidehashlikerevs(
2625 repo = scmutil.unhidehashlikerevs(
2626 repo, [from_rev] + [to_rev], b'nowarn'
2626 repo, [from_rev] + [to_rev], b'nowarn'
2627 )
2627 )
2628 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2628 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2629 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2629 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2630 else:
2630 else:
2631 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2631 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2632 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2632 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2633
2633
2634 if reverse:
2634 if reverse:
2635 ctxleft = ctx2
2635 ctxleft = ctx2
2636 ctxright = ctx1
2636 ctxright = ctx1
2637 else:
2637 else:
2638 ctxleft = ctx1
2638 ctxleft = ctx1
2639 ctxright = ctx2
2639 ctxright = ctx2
2640
2640
2641 diffopts = patch.diffallopts(ui, opts)
2641 diffopts = patch.diffallopts(ui, opts)
2642 m = scmutil.match(ctx2, pats, opts)
2642 m = scmutil.match(ctx2, pats, opts)
2643 m = repo.narrowmatch(m)
2643 m = repo.narrowmatch(m)
2644 ui.pager(b'diff')
2644 ui.pager(b'diff')
2645 logcmdutil.diffordiffstat(
2645 logcmdutil.diffordiffstat(
2646 ui,
2646 ui,
2647 repo,
2647 repo,
2648 diffopts,
2648 diffopts,
2649 ctxleft,
2649 ctxleft,
2650 ctxright,
2650 ctxright,
2651 m,
2651 m,
2652 stat=stat,
2652 stat=stat,
2653 listsubrepos=opts.get(b'subrepos'),
2653 listsubrepos=opts.get(b'subrepos'),
2654 root=opts.get(b'root'),
2654 root=opts.get(b'root'),
2655 )
2655 )
2656
2656
2657
2657
2658 @command(
2658 @command(
2659 b'export',
2659 b'export',
2660 [
2660 [
2661 (
2661 (
2662 b'B',
2662 b'B',
2663 b'bookmark',
2663 b'bookmark',
2664 b'',
2664 b'',
2665 _(b'export changes only reachable by given bookmark'),
2665 _(b'export changes only reachable by given bookmark'),
2666 _(b'BOOKMARK'),
2666 _(b'BOOKMARK'),
2667 ),
2667 ),
2668 (
2668 (
2669 b'o',
2669 b'o',
2670 b'output',
2670 b'output',
2671 b'',
2671 b'',
2672 _(b'print output to file with formatted name'),
2672 _(b'print output to file with formatted name'),
2673 _(b'FORMAT'),
2673 _(b'FORMAT'),
2674 ),
2674 ),
2675 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2675 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2676 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2676 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2677 ]
2677 ]
2678 + diffopts
2678 + diffopts
2679 + formatteropts,
2679 + formatteropts,
2680 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2680 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2681 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2681 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2682 helpbasic=True,
2682 helpbasic=True,
2683 intents={INTENT_READONLY},
2683 intents={INTENT_READONLY},
2684 )
2684 )
2685 def export(ui, repo, *changesets, **opts):
2685 def export(ui, repo, *changesets, **opts):
2686 """dump the header and diffs for one or more changesets
2686 """dump the header and diffs for one or more changesets
2687
2687
2688 Print the changeset header and diffs for one or more revisions.
2688 Print the changeset header and diffs for one or more revisions.
2689 If no revision is given, the parent of the working directory is used.
2689 If no revision is given, the parent of the working directory is used.
2690
2690
2691 The information shown in the changeset header is: author, date,
2691 The information shown in the changeset header is: author, date,
2692 branch name (if non-default), changeset hash, parent(s) and commit
2692 branch name (if non-default), changeset hash, parent(s) and commit
2693 comment.
2693 comment.
2694
2694
2695 .. note::
2695 .. note::
2696
2696
2697 :hg:`export` may generate unexpected diff output for merge
2697 :hg:`export` may generate unexpected diff output for merge
2698 changesets, as it will compare the merge changeset against its
2698 changesets, as it will compare the merge changeset against its
2699 first parent only.
2699 first parent only.
2700
2700
2701 Output may be to a file, in which case the name of the file is
2701 Output may be to a file, in which case the name of the file is
2702 given using a template string. See :hg:`help templates`. In addition
2702 given using a template string. See :hg:`help templates`. In addition
2703 to the common template keywords, the following formatting rules are
2703 to the common template keywords, the following formatting rules are
2704 supported:
2704 supported:
2705
2705
2706 :``%%``: literal "%" character
2706 :``%%``: literal "%" character
2707 :``%H``: changeset hash (40 hexadecimal digits)
2707 :``%H``: changeset hash (40 hexadecimal digits)
2708 :``%N``: number of patches being generated
2708 :``%N``: number of patches being generated
2709 :``%R``: changeset revision number
2709 :``%R``: changeset revision number
2710 :``%b``: basename of the exporting repository
2710 :``%b``: basename of the exporting repository
2711 :``%h``: short-form changeset hash (12 hexadecimal digits)
2711 :``%h``: short-form changeset hash (12 hexadecimal digits)
2712 :``%m``: first line of the commit message (only alphanumeric characters)
2712 :``%m``: first line of the commit message (only alphanumeric characters)
2713 :``%n``: zero-padded sequence number, starting at 1
2713 :``%n``: zero-padded sequence number, starting at 1
2714 :``%r``: zero-padded changeset revision number
2714 :``%r``: zero-padded changeset revision number
2715 :``\\``: literal "\\" character
2715 :``\\``: literal "\\" character
2716
2716
2717 Without the -a/--text option, export will avoid generating diffs
2717 Without the -a/--text option, export will avoid generating diffs
2718 of files it detects as binary. With -a, export will generate a
2718 of files it detects as binary. With -a, export will generate a
2719 diff anyway, probably with undesirable results.
2719 diff anyway, probably with undesirable results.
2720
2720
2721 With -B/--bookmark changesets reachable by the given bookmark are
2721 With -B/--bookmark changesets reachable by the given bookmark are
2722 selected.
2722 selected.
2723
2723
2724 Use the -g/--git option to generate diffs in the git extended diff
2724 Use the -g/--git option to generate diffs in the git extended diff
2725 format. See :hg:`help diffs` for more information.
2725 format. See :hg:`help diffs` for more information.
2726
2726
2727 With the --switch-parent option, the diff will be against the
2727 With the --switch-parent option, the diff will be against the
2728 second parent. It can be useful to review a merge.
2728 second parent. It can be useful to review a merge.
2729
2729
2730 .. container:: verbose
2730 .. container:: verbose
2731
2731
2732 Template:
2732 Template:
2733
2733
2734 The following keywords are supported in addition to the common template
2734 The following keywords are supported in addition to the common template
2735 keywords and functions. See also :hg:`help templates`.
2735 keywords and functions. See also :hg:`help templates`.
2736
2736
2737 :diff: String. Diff content.
2737 :diff: String. Diff content.
2738 :parents: List of strings. Parent nodes of the changeset.
2738 :parents: List of strings. Parent nodes of the changeset.
2739
2739
2740 Examples:
2740 Examples:
2741
2741
2742 - use export and import to transplant a bugfix to the current
2742 - use export and import to transplant a bugfix to the current
2743 branch::
2743 branch::
2744
2744
2745 hg export -r 9353 | hg import -
2745 hg export -r 9353 | hg import -
2746
2746
2747 - export all the changesets between two revisions to a file with
2747 - export all the changesets between two revisions to a file with
2748 rename information::
2748 rename information::
2749
2749
2750 hg export --git -r 123:150 > changes.txt
2750 hg export --git -r 123:150 > changes.txt
2751
2751
2752 - split outgoing changes into a series of patches with
2752 - split outgoing changes into a series of patches with
2753 descriptive names::
2753 descriptive names::
2754
2754
2755 hg export -r "outgoing()" -o "%n-%m.patch"
2755 hg export -r "outgoing()" -o "%n-%m.patch"
2756
2756
2757 Returns 0 on success.
2757 Returns 0 on success.
2758 """
2758 """
2759 opts = pycompat.byteskwargs(opts)
2759 opts = pycompat.byteskwargs(opts)
2760 bookmark = opts.get(b'bookmark')
2760 bookmark = opts.get(b'bookmark')
2761 changesets += tuple(opts.get(b'rev', []))
2761 changesets += tuple(opts.get(b'rev', []))
2762
2762
2763 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2763 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2764
2764
2765 if bookmark:
2765 if bookmark:
2766 if bookmark not in repo._bookmarks:
2766 if bookmark not in repo._bookmarks:
2767 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2767 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2768
2768
2769 revs = scmutil.bookmarkrevs(repo, bookmark)
2769 revs = scmutil.bookmarkrevs(repo, bookmark)
2770 else:
2770 else:
2771 if not changesets:
2771 if not changesets:
2772 changesets = [b'.']
2772 changesets = [b'.']
2773
2773
2774 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2774 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2775 revs = logcmdutil.revrange(repo, changesets)
2775 revs = logcmdutil.revrange(repo, changesets)
2776
2776
2777 if not revs:
2777 if not revs:
2778 raise error.InputError(_(b"export requires at least one changeset"))
2778 raise error.InputError(_(b"export requires at least one changeset"))
2779 if len(revs) > 1:
2779 if len(revs) > 1:
2780 ui.note(_(b'exporting patches:\n'))
2780 ui.note(_(b'exporting patches:\n'))
2781 else:
2781 else:
2782 ui.note(_(b'exporting patch:\n'))
2782 ui.note(_(b'exporting patch:\n'))
2783
2783
2784 fntemplate = opts.get(b'output')
2784 fntemplate = opts.get(b'output')
2785 if cmdutil.isstdiofilename(fntemplate):
2785 if cmdutil.isstdiofilename(fntemplate):
2786 fntemplate = b''
2786 fntemplate = b''
2787
2787
2788 if fntemplate:
2788 if fntemplate:
2789 fm = formatter.nullformatter(ui, b'export', opts)
2789 fm = formatter.nullformatter(ui, b'export', opts)
2790 else:
2790 else:
2791 ui.pager(b'export')
2791 ui.pager(b'export')
2792 fm = ui.formatter(b'export', opts)
2792 fm = ui.formatter(b'export', opts)
2793 with fm:
2793 with fm:
2794 cmdutil.export(
2794 cmdutil.export(
2795 repo,
2795 repo,
2796 revs,
2796 revs,
2797 fm,
2797 fm,
2798 fntemplate=fntemplate,
2798 fntemplate=fntemplate,
2799 switch_parent=opts.get(b'switch_parent'),
2799 switch_parent=opts.get(b'switch_parent'),
2800 opts=patch.diffallopts(ui, opts),
2800 opts=patch.diffallopts(ui, opts),
2801 )
2801 )
2802
2802
2803
2803
2804 @command(
2804 @command(
2805 b'files',
2805 b'files',
2806 [
2806 [
2807 (
2807 (
2808 b'r',
2808 b'r',
2809 b'rev',
2809 b'rev',
2810 b'',
2810 b'',
2811 _(b'search the repository as it is in REV'),
2811 _(b'search the repository as it is in REV'),
2812 _(b'REV'),
2812 _(b'REV'),
2813 ),
2813 ),
2814 (
2814 (
2815 b'0',
2815 b'0',
2816 b'print0',
2816 b'print0',
2817 None,
2817 None,
2818 _(b'end filenames with NUL, for use with xargs'),
2818 _(b'end filenames with NUL, for use with xargs'),
2819 ),
2819 ),
2820 ]
2820 ]
2821 + walkopts
2821 + walkopts
2822 + formatteropts
2822 + formatteropts
2823 + subrepoopts,
2823 + subrepoopts,
2824 _(b'[OPTION]... [FILE]...'),
2824 _(b'[OPTION]... [FILE]...'),
2825 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2825 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2826 intents={INTENT_READONLY},
2826 intents={INTENT_READONLY},
2827 )
2827 )
2828 def files(ui, repo, *pats, **opts):
2828 def files(ui, repo, *pats, **opts):
2829 """list tracked files
2829 """list tracked files
2830
2830
2831 Print files under Mercurial control in the working directory or
2831 Print files under Mercurial control in the working directory or
2832 specified revision for given files (excluding removed files).
2832 specified revision for given files (excluding removed files).
2833 Files can be specified as filenames or filesets.
2833 Files can be specified as filenames or filesets.
2834
2834
2835 If no files are given to match, this command prints the names
2835 If no files are given to match, this command prints the names
2836 of all files under Mercurial control.
2836 of all files under Mercurial control.
2837
2837
2838 .. container:: verbose
2838 .. container:: verbose
2839
2839
2840 Template:
2840 Template:
2841
2841
2842 The following keywords are supported in addition to the common template
2842 The following keywords are supported in addition to the common template
2843 keywords and functions. See also :hg:`help templates`.
2843 keywords and functions. See also :hg:`help templates`.
2844
2844
2845 :flags: String. Character denoting file's symlink and executable bits.
2845 :flags: String. Character denoting file's symlink and executable bits.
2846 :path: String. Repository-absolute path of the file.
2846 :path: String. Repository-absolute path of the file.
2847 :size: Integer. Size of the file in bytes.
2847 :size: Integer. Size of the file in bytes.
2848
2848
2849 Examples:
2849 Examples:
2850
2850
2851 - list all files under the current directory::
2851 - list all files under the current directory::
2852
2852
2853 hg files .
2853 hg files .
2854
2854
2855 - shows sizes and flags for current revision::
2855 - shows sizes and flags for current revision::
2856
2856
2857 hg files -vr .
2857 hg files -vr .
2858
2858
2859 - list all files named README::
2859 - list all files named README::
2860
2860
2861 hg files -I "**/README"
2861 hg files -I "**/README"
2862
2862
2863 - list all binary files::
2863 - list all binary files::
2864
2864
2865 hg files "set:binary()"
2865 hg files "set:binary()"
2866
2866
2867 - find files containing a regular expression::
2867 - find files containing a regular expression::
2868
2868
2869 hg files "set:grep('bob')"
2869 hg files "set:grep('bob')"
2870
2870
2871 - search tracked file contents with xargs and grep::
2871 - search tracked file contents with xargs and grep::
2872
2872
2873 hg files -0 | xargs -0 grep foo
2873 hg files -0 | xargs -0 grep foo
2874
2874
2875 See :hg:`help patterns` and :hg:`help filesets` for more information
2875 See :hg:`help patterns` and :hg:`help filesets` for more information
2876 on specifying file patterns.
2876 on specifying file patterns.
2877
2877
2878 Returns 0 if a match is found, 1 otherwise.
2878 Returns 0 if a match is found, 1 otherwise.
2879
2879
2880 """
2880 """
2881
2881
2882 opts = pycompat.byteskwargs(opts)
2882 opts = pycompat.byteskwargs(opts)
2883 rev = opts.get(b'rev')
2883 rev = opts.get(b'rev')
2884 if rev:
2884 if rev:
2885 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2885 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2886 ctx = logcmdutil.revsingle(repo, rev, None)
2886 ctx = logcmdutil.revsingle(repo, rev, None)
2887
2887
2888 end = b'\n'
2888 end = b'\n'
2889 if opts.get(b'print0'):
2889 if opts.get(b'print0'):
2890 end = b'\0'
2890 end = b'\0'
2891 fmt = b'%s' + end
2891 fmt = b'%s' + end
2892
2892
2893 m = scmutil.match(ctx, pats, opts)
2893 m = scmutil.match(ctx, pats, opts)
2894 ui.pager(b'files')
2894 ui.pager(b'files')
2895 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2895 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2896 with ui.formatter(b'files', opts) as fm:
2896 with ui.formatter(b'files', opts) as fm:
2897 return cmdutil.files(
2897 return cmdutil.files(
2898 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2898 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2899 )
2899 )
2900
2900
2901
2901
2902 @command(
2902 @command(
2903 b'forget',
2903 b'forget',
2904 [
2904 [
2905 (b'i', b'interactive', None, _(b'use interactive mode')),
2905 (b'i', b'interactive', None, _(b'use interactive mode')),
2906 ]
2906 ]
2907 + walkopts
2907 + walkopts
2908 + dryrunopts,
2908 + dryrunopts,
2909 _(b'[OPTION]... FILE...'),
2909 _(b'[OPTION]... FILE...'),
2910 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2910 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2911 helpbasic=True,
2911 helpbasic=True,
2912 inferrepo=True,
2912 inferrepo=True,
2913 )
2913 )
2914 def forget(ui, repo, *pats, **opts):
2914 def forget(ui, repo, *pats, **opts):
2915 """forget the specified files on the next commit
2915 """forget the specified files on the next commit
2916
2916
2917 Mark the specified files so they will no longer be tracked
2917 Mark the specified files so they will no longer be tracked
2918 after the next commit.
2918 after the next commit.
2919
2919
2920 This only removes files from the current branch, not from the
2920 This only removes files from the current branch, not from the
2921 entire project history, and it does not delete them from the
2921 entire project history, and it does not delete them from the
2922 working directory.
2922 working directory.
2923
2923
2924 To delete the file from the working directory, see :hg:`remove`.
2924 To delete the file from the working directory, see :hg:`remove`.
2925
2925
2926 To undo a forget before the next commit, see :hg:`add`.
2926 To undo a forget before the next commit, see :hg:`add`.
2927
2927
2928 .. container:: verbose
2928 .. container:: verbose
2929
2929
2930 Examples:
2930 Examples:
2931
2931
2932 - forget newly-added binary files::
2932 - forget newly-added binary files::
2933
2933
2934 hg forget "set:added() and binary()"
2934 hg forget "set:added() and binary()"
2935
2935
2936 - forget files that would be excluded by .hgignore::
2936 - forget files that would be excluded by .hgignore::
2937
2937
2938 hg forget "set:hgignore()"
2938 hg forget "set:hgignore()"
2939
2939
2940 Returns 0 on success.
2940 Returns 0 on success.
2941 """
2941 """
2942
2942
2943 if not pats:
2943 if not pats:
2944 raise error.InputError(_(b'no files specified'))
2944 raise error.InputError(_(b'no files specified'))
2945
2945
2946 with repo.wlock(), repo.dirstate.changing_files(repo):
2946 with repo.wlock(), repo.dirstate.changing_files(repo):
2947 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2947 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2948 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2948 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2949 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2949 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2950 rejected = cmdutil.forget(
2950 rejected = cmdutil.forget(
2951 ui,
2951 ui,
2952 repo,
2952 repo,
2953 m,
2953 m,
2954 prefix=b"",
2954 prefix=b"",
2955 uipathfn=uipathfn,
2955 uipathfn=uipathfn,
2956 explicitonly=False,
2956 explicitonly=False,
2957 dryrun=dryrun,
2957 dryrun=dryrun,
2958 interactive=interactive,
2958 interactive=interactive,
2959 )[0]
2959 )[0]
2960 return rejected and 1 or 0
2960 return rejected and 1 or 0
2961
2961
2962
2962
2963 @command(
2963 @command(
2964 b'graft',
2964 b'graft',
2965 [
2965 [
2966 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2966 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2967 (
2967 (
2968 b'',
2968 b'',
2969 b'base',
2969 b'base',
2970 b'',
2970 b'',
2971 _(b'base revision when doing the graft merge (ADVANCED)'),
2971 _(b'base revision when doing the graft merge (ADVANCED)'),
2972 _(b'REV'),
2972 _(b'REV'),
2973 ),
2973 ),
2974 (
2974 (
2975 b'',
2975 b'',
2976 b'to',
2976 b'to',
2977 b'',
2977 b'',
2978 _(b'graft to this destination, in memory (EXPERIMENTAL)'),
2978 _(b'graft to this destination, in-memory (EXPERIMENTAL)'),
2979 ),
2979 ),
2980 (b'c', b'continue', False, _(b'resume interrupted graft')),
2980 (b'c', b'continue', False, _(b'resume interrupted graft')),
2981 (b'', b'stop', False, _(b'stop interrupted graft')),
2981 (b'', b'stop', False, _(b'stop interrupted graft')),
2982 (b'', b'abort', False, _(b'abort interrupted graft')),
2982 (b'', b'abort', False, _(b'abort interrupted graft')),
2983 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2983 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2984 (b'', b'log', None, _(b'append graft info to log message')),
2984 (b'', b'log', None, _(b'append graft info to log message')),
2985 (
2985 (
2986 b'',
2986 b'',
2987 b'no-commit',
2987 b'no-commit',
2988 None,
2988 None,
2989 _(b"don't commit, just apply the changes in working directory"),
2989 _(b"don't commit, just apply the changes in working directory"),
2990 ),
2990 ),
2991 (b'f', b'force', False, _(b'force graft')),
2991 (b'f', b'force', False, _(b'force graft')),
2992 (
2992 (
2993 b'D',
2993 b'D',
2994 b'currentdate',
2994 b'currentdate',
2995 False,
2995 False,
2996 _(b'record the current date as commit date'),
2996 _(b'record the current date as commit date'),
2997 ),
2997 ),
2998 (
2998 (
2999 b'U',
2999 b'U',
3000 b'currentuser',
3000 b'currentuser',
3001 False,
3001 False,
3002 _(b'record the current user as committer'),
3002 _(b'record the current user as committer'),
3003 ),
3003 ),
3004 ]
3004 ]
3005 + commitopts2
3005 + commitopts2
3006 + mergetoolopts
3006 + mergetoolopts
3007 + dryrunopts,
3007 + dryrunopts,
3008 _(b'[OPTION]... [-r REV]... REV...'),
3008 _(b'[OPTION]... [-r REV]... REV...'),
3009 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3009 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3010 )
3010 )
3011 def graft(ui, repo, *revs, **opts):
3011 def graft(ui, repo, *revs, **opts):
3012 """copy changes from other branches onto the current branch
3012 """copy changes from other branches onto the current branch
3013
3013
3014 This command uses Mercurial's merge logic to copy individual
3014 This command uses Mercurial's merge logic to copy individual
3015 changes from other branches without merging branches in the
3015 changes from other branches without merging branches in the
3016 history graph. This is sometimes known as 'backporting' or
3016 history graph. This is sometimes known as 'backporting' or
3017 'cherry-picking'. By default, graft will copy user, date, and
3017 'cherry-picking'. By default, graft will copy user, date, and
3018 description from the source changesets.
3018 description from the source changesets.
3019
3019
3020 Changesets that are ancestors of the current revision, that have
3020 Changesets that are ancestors of the current revision, that have
3021 already been grafted, or that are merges will be skipped.
3021 already been grafted, or that are merges will be skipped.
3022
3022
3023 If --log is specified, log messages will have a comment appended
3023 If --log is specified, log messages will have a comment appended
3024 of the form::
3024 of the form::
3025
3025
3026 (grafted from CHANGESETHASH)
3026 (grafted from CHANGESETHASH)
3027
3027
3028 If --force is specified, revisions will be grafted even if they
3028 If --force is specified, revisions will be grafted even if they
3029 are already ancestors of, or have been grafted to, the destination.
3029 are already ancestors of, or have been grafted to, the destination.
3030 This is useful when the revisions have since been backed out.
3030 This is useful when the revisions have since been backed out.
3031
3031
3032 If a graft merge results in conflicts, the graft process is
3032 If a graft merge results in conflicts, the graft process is
3033 interrupted so that the current merge can be manually resolved.
3033 interrupted so that the current merge can be manually resolved.
3034 Once all conflicts are addressed, the graft process can be
3034 Once all conflicts are addressed, the graft process can be
3035 continued with the -c/--continue option.
3035 continued with the -c/--continue option.
3036
3036
3037 The -c/--continue option reapplies all the earlier options.
3037 The -c/--continue option reapplies all the earlier options.
3038
3038
3039 .. container:: verbose
3039 .. container:: verbose
3040
3040
3041 The --base option exposes more of how graft internally uses merge with a
3041 The --base option exposes more of how graft internally uses merge with a
3042 custom base revision. --base can be used to specify another ancestor than
3042 custom base revision. --base can be used to specify another ancestor than
3043 the first and only parent.
3043 the first and only parent.
3044
3044
3045 The command::
3045 The command::
3046
3046
3047 hg graft -r 345 --base 234
3047 hg graft -r 345 --base 234
3048
3048
3049 is thus pretty much the same as::
3049 is thus pretty much the same as::
3050
3050
3051 hg diff --from 234 --to 345 | hg import
3051 hg diff --from 234 --to 345 | hg import
3052
3052
3053 but using merge to resolve conflicts and track moved files.
3053 but using merge to resolve conflicts and track moved files.
3054
3054
3055 The result of a merge can thus be backported as a single commit by
3055 The result of a merge can thus be backported as a single commit by
3056 specifying one of the merge parents as base, and thus effectively
3056 specifying one of the merge parents as base, and thus effectively
3057 grafting the changes from the other side.
3057 grafting the changes from the other side.
3058
3058
3059 It is also possible to collapse multiple changesets and clean up history
3059 It is also possible to collapse multiple changesets and clean up history
3060 by specifying another ancestor as base, much like rebase --collapse
3060 by specifying another ancestor as base, much like rebase --collapse
3061 --keep.
3061 --keep.
3062
3062
3063 The commit message can be tweaked after the fact using commit --amend .
3063 The commit message can be tweaked after the fact using commit --amend .
3064
3064
3065 For using non-ancestors as the base to backout changes, see the backout
3065 For using non-ancestors as the base to backout changes, see the backout
3066 command and the hidden --parent option.
3066 command and the hidden --parent option.
3067
3067
3068 .. container:: verbose
3068 .. container:: verbose
3069
3069
3070 The experimental --to option allow to graft a revision in memory,
3070 The experimental --to option allows grafting a revision in-memory,
3071 independently from the working copy. Merge conflict are not currenly
3071 independent of the working copy. Merge conflicts are not currently
3072 supported and the operation will be aborted if the configured tool
3072 supported, and the operation will be aborted if the configured tool
3073 cannot handle the conflict that might be encountered.
3073 cannot handle the conflicts that might be encountered.
3074
3074
3075 As the operation is performence in memory, the on disk file will not be
3075 As the operation is performed in-memory, the on-disk files will not be
3076 modified and some hooks might not be run.
3076 modified, and some hooks might not be run.
3077
3077
3078 .. container:: verbose
3078 .. container:: verbose
3079
3079
3080 Examples:
3080 Examples:
3081
3081
3082 - copy a single change to the stable branch and edit its description::
3082 - copy a single change to the stable branch and edit its description::
3083
3083
3084 hg update stable
3084 hg update stable
3085 hg graft --edit 9393
3085 hg graft --edit 9393
3086
3086
3087 - graft a range of changesets with one exception, updating dates::
3087 - graft a range of changesets with one exception, updating dates::
3088
3088
3089 hg graft -D "2085::2093 and not 2091"
3089 hg graft -D "2085::2093 and not 2091"
3090
3090
3091 - continue a graft after resolving conflicts::
3091 - continue a graft after resolving conflicts::
3092
3092
3093 hg graft -c
3093 hg graft -c
3094
3094
3095 - show the source of a grafted changeset::
3095 - show the source of a grafted changeset::
3096
3096
3097 hg log --debug -r .
3097 hg log --debug -r .
3098
3098
3099 - show revisions sorted by date::
3099 - show revisions sorted by date::
3100
3100
3101 hg log -r "sort(all(), date)"
3101 hg log -r "sort(all(), date)"
3102
3102
3103 - backport the result of a merge as a single commit::
3103 - backport the result of a merge as a single commit::
3104
3104
3105 hg graft -r 123 --base 123^
3105 hg graft -r 123 --base 123^
3106
3106
3107 - land a feature branch as one changeset::
3107 - land a feature branch as one changeset::
3108
3108
3109 hg up -cr default
3109 hg up -cr default
3110 hg graft -r featureX --base "ancestor('featureX', 'default')"
3110 hg graft -r featureX --base "ancestor('featureX', 'default')"
3111
3111
3112 See :hg:`help revisions` for more about specifying revisions.
3112 See :hg:`help revisions` for more about specifying revisions.
3113
3113
3114 Returns 0 on successful completion, 1 if there are unresolved files.
3114 Returns 0 on successful completion, 1 if there are unresolved files.
3115 """
3115 """
3116 with repo.wlock():
3116 with repo.wlock():
3117 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3117 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3118
3118
3119
3119
3120 statemod.addunfinished(
3120 statemod.addunfinished(
3121 b'graft',
3121 b'graft',
3122 fname=b'graftstate',
3122 fname=b'graftstate',
3123 clearable=True,
3123 clearable=True,
3124 stopflag=True,
3124 stopflag=True,
3125 continueflag=True,
3125 continueflag=True,
3126 abortfunc=cmdutil.hgabortgraft,
3126 abortfunc=cmdutil.hgabortgraft,
3127 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3127 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3128 )
3128 )
3129
3129
3130
3130
3131 @command(
3131 @command(
3132 b'grep',
3132 b'grep',
3133 [
3133 [
3134 (b'0', b'print0', None, _(b'end fields with NUL')),
3134 (b'0', b'print0', None, _(b'end fields with NUL')),
3135 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3135 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3136 (
3136 (
3137 b'',
3137 b'',
3138 b'diff',
3138 b'diff',
3139 None,
3139 None,
3140 _(
3140 _(
3141 b'search revision differences for when the pattern was added '
3141 b'search revision differences for when the pattern was added '
3142 b'or removed'
3142 b'or removed'
3143 ),
3143 ),
3144 ),
3144 ),
3145 (b'a', b'text', None, _(b'treat all files as text')),
3145 (b'a', b'text', None, _(b'treat all files as text')),
3146 (
3146 (
3147 b'f',
3147 b'f',
3148 b'follow',
3148 b'follow',
3149 None,
3149 None,
3150 _(
3150 _(
3151 b'follow changeset history,'
3151 b'follow changeset history,'
3152 b' or file history across copies and renames'
3152 b' or file history across copies and renames'
3153 ),
3153 ),
3154 ),
3154 ),
3155 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3155 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3156 (
3156 (
3157 b'l',
3157 b'l',
3158 b'files-with-matches',
3158 b'files-with-matches',
3159 None,
3159 None,
3160 _(b'print only filenames and revisions that match'),
3160 _(b'print only filenames and revisions that match'),
3161 ),
3161 ),
3162 (b'n', b'line-number', None, _(b'print matching line numbers')),
3162 (b'n', b'line-number', None, _(b'print matching line numbers')),
3163 (
3163 (
3164 b'r',
3164 b'r',
3165 b'rev',
3165 b'rev',
3166 [],
3166 [],
3167 _(b'search files changed within revision range'),
3167 _(b'search files changed within revision range'),
3168 _(b'REV'),
3168 _(b'REV'),
3169 ),
3169 ),
3170 (
3170 (
3171 b'',
3171 b'',
3172 b'all-files',
3172 b'all-files',
3173 None,
3173 None,
3174 _(
3174 _(
3175 b'include all files in the changeset while grepping (DEPRECATED)'
3175 b'include all files in the changeset while grepping (DEPRECATED)'
3176 ),
3176 ),
3177 ),
3177 ),
3178 (b'u', b'user', None, _(b'list the author (long with -v)')),
3178 (b'u', b'user', None, _(b'list the author (long with -v)')),
3179 (b'd', b'date', None, _(b'list the date (short with -q)')),
3179 (b'd', b'date', None, _(b'list the date (short with -q)')),
3180 ]
3180 ]
3181 + formatteropts
3181 + formatteropts
3182 + walkopts,
3182 + walkopts,
3183 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3183 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3184 helpcategory=command.CATEGORY_FILE_CONTENTS,
3184 helpcategory=command.CATEGORY_FILE_CONTENTS,
3185 inferrepo=True,
3185 inferrepo=True,
3186 intents={INTENT_READONLY},
3186 intents={INTENT_READONLY},
3187 )
3187 )
3188 def grep(ui, repo, pattern, *pats, **opts):
3188 def grep(ui, repo, pattern, *pats, **opts):
3189 """search for a pattern in specified files
3189 """search for a pattern in specified files
3190
3190
3191 Search the working directory or revision history for a regular
3191 Search the working directory or revision history for a regular
3192 expression in the specified files for the entire repository.
3192 expression in the specified files for the entire repository.
3193
3193
3194 By default, grep searches the repository files in the working
3194 By default, grep searches the repository files in the working
3195 directory and prints the files where it finds a match. To specify
3195 directory and prints the files where it finds a match. To specify
3196 historical revisions instead of the working directory, use the
3196 historical revisions instead of the working directory, use the
3197 --rev flag.
3197 --rev flag.
3198
3198
3199 To search instead historical revision differences that contains a
3199 To search instead historical revision differences that contains a
3200 change in match status ("-" for a match that becomes a non-match,
3200 change in match status ("-" for a match that becomes a non-match,
3201 or "+" for a non-match that becomes a match), use the --diff flag.
3201 or "+" for a non-match that becomes a match), use the --diff flag.
3202
3202
3203 PATTERN can be any Python (roughly Perl-compatible) regular
3203 PATTERN can be any Python (roughly Perl-compatible) regular
3204 expression.
3204 expression.
3205
3205
3206 If no FILEs are specified and the --rev flag isn't supplied, all
3206 If no FILEs are specified and the --rev flag isn't supplied, all
3207 files in the working directory are searched. When using the --rev
3207 files in the working directory are searched. When using the --rev
3208 flag and specifying FILEs, use the --follow argument to also
3208 flag and specifying FILEs, use the --follow argument to also
3209 follow the specified FILEs across renames and copies.
3209 follow the specified FILEs across renames and copies.
3210
3210
3211 .. container:: verbose
3211 .. container:: verbose
3212
3212
3213 Template:
3213 Template:
3214
3214
3215 The following keywords are supported in addition to the common template
3215 The following keywords are supported in addition to the common template
3216 keywords and functions. See also :hg:`help templates`.
3216 keywords and functions. See also :hg:`help templates`.
3217
3217
3218 :change: String. Character denoting insertion ``+`` or removal ``-``.
3218 :change: String. Character denoting insertion ``+`` or removal ``-``.
3219 Available if ``--diff`` is specified.
3219 Available if ``--diff`` is specified.
3220 :lineno: Integer. Line number of the match.
3220 :lineno: Integer. Line number of the match.
3221 :path: String. Repository-absolute path of the file.
3221 :path: String. Repository-absolute path of the file.
3222 :texts: List of text chunks.
3222 :texts: List of text chunks.
3223
3223
3224 And each entry of ``{texts}`` provides the following sub-keywords.
3224 And each entry of ``{texts}`` provides the following sub-keywords.
3225
3225
3226 :matched: Boolean. True if the chunk matches the specified pattern.
3226 :matched: Boolean. True if the chunk matches the specified pattern.
3227 :text: String. Chunk content.
3227 :text: String. Chunk content.
3228
3228
3229 See :hg:`help templates.operators` for the list expansion syntax.
3229 See :hg:`help templates.operators` for the list expansion syntax.
3230
3230
3231 Returns 0 if a match is found, 1 otherwise.
3231 Returns 0 if a match is found, 1 otherwise.
3232
3232
3233 """
3233 """
3234 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3234 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3235
3235
3236 diff = opts.get('all') or opts.get('diff')
3236 diff = opts.get('all') or opts.get('diff')
3237 follow = opts.get('follow')
3237 follow = opts.get('follow')
3238 if opts.get('all_files') is None and not diff:
3238 if opts.get('all_files') is None and not diff:
3239 opts['all_files'] = True
3239 opts['all_files'] = True
3240 plaingrep = (
3240 plaingrep = (
3241 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3241 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3242 )
3242 )
3243 all_files = opts.get('all_files')
3243 all_files = opts.get('all_files')
3244 if plaingrep:
3244 if plaingrep:
3245 opts['rev'] = [b'wdir()']
3245 opts['rev'] = [b'wdir()']
3246
3246
3247 reflags = re.M
3247 reflags = re.M
3248 if opts.get('ignore_case'):
3248 if opts.get('ignore_case'):
3249 reflags |= re.I
3249 reflags |= re.I
3250 try:
3250 try:
3251 regexp = util.re.compile(pattern, reflags)
3251 regexp = util.re.compile(pattern, reflags)
3252 except re.error as inst:
3252 except re.error as inst:
3253 ui.warn(
3253 ui.warn(
3254 _(b"grep: invalid match pattern: %s\n")
3254 _(b"grep: invalid match pattern: %s\n")
3255 % stringutil.forcebytestr(inst)
3255 % stringutil.forcebytestr(inst)
3256 )
3256 )
3257 return 1
3257 return 1
3258 sep, eol = b':', b'\n'
3258 sep, eol = b':', b'\n'
3259 if opts.get('print0'):
3259 if opts.get('print0'):
3260 sep = eol = b'\0'
3260 sep = eol = b'\0'
3261
3261
3262 searcher = grepmod.grepsearcher(
3262 searcher = grepmod.grepsearcher(
3263 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3263 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3264 )
3264 )
3265
3265
3266 getfile = searcher._getfile
3266 getfile = searcher._getfile
3267
3267
3268 uipathfn = scmutil.getuipathfn(repo)
3268 uipathfn = scmutil.getuipathfn(repo)
3269
3269
3270 def display(fm, fn, ctx, pstates, states):
3270 def display(fm, fn, ctx, pstates, states):
3271 rev = scmutil.intrev(ctx)
3271 rev = scmutil.intrev(ctx)
3272 if fm.isplain():
3272 if fm.isplain():
3273 formatuser = ui.shortuser
3273 formatuser = ui.shortuser
3274 else:
3274 else:
3275 formatuser = pycompat.bytestr
3275 formatuser = pycompat.bytestr
3276 if ui.quiet:
3276 if ui.quiet:
3277 datefmt = b'%Y-%m-%d'
3277 datefmt = b'%Y-%m-%d'
3278 else:
3278 else:
3279 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3279 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3280 found = False
3280 found = False
3281
3281
3282 @util.cachefunc
3282 @util.cachefunc
3283 def binary():
3283 def binary():
3284 flog = getfile(fn)
3284 flog = getfile(fn)
3285 try:
3285 try:
3286 return stringutil.binary(flog.read(ctx.filenode(fn)))
3286 return stringutil.binary(flog.read(ctx.filenode(fn)))
3287 except error.WdirUnsupported:
3287 except error.WdirUnsupported:
3288 return ctx[fn].isbinary()
3288 return ctx[fn].isbinary()
3289
3289
3290 fieldnamemap = {b'linenumber': b'lineno'}
3290 fieldnamemap = {b'linenumber': b'lineno'}
3291 if diff:
3291 if diff:
3292 iter = grepmod.difflinestates(pstates, states)
3292 iter = grepmod.difflinestates(pstates, states)
3293 else:
3293 else:
3294 iter = [(b'', l) for l in states]
3294 iter = [(b'', l) for l in states]
3295 for change, l in iter:
3295 for change, l in iter:
3296 fm.startitem()
3296 fm.startitem()
3297 fm.context(ctx=ctx)
3297 fm.context(ctx=ctx)
3298 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3298 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3299 fm.plain(uipathfn(fn), label=b'grep.filename')
3299 fm.plain(uipathfn(fn), label=b'grep.filename')
3300
3300
3301 cols = [
3301 cols = [
3302 (b'rev', b'%d', rev, not plaingrep, b''),
3302 (b'rev', b'%d', rev, not plaingrep, b''),
3303 (
3303 (
3304 b'linenumber',
3304 b'linenumber',
3305 b'%d',
3305 b'%d',
3306 l.linenum,
3306 l.linenum,
3307 opts.get('line_number'),
3307 opts.get('line_number'),
3308 b'',
3308 b'',
3309 ),
3309 ),
3310 ]
3310 ]
3311 if diff:
3311 if diff:
3312 cols.append(
3312 cols.append(
3313 (
3313 (
3314 b'change',
3314 b'change',
3315 b'%s',
3315 b'%s',
3316 change,
3316 change,
3317 True,
3317 True,
3318 b'grep.inserted '
3318 b'grep.inserted '
3319 if change == b'+'
3319 if change == b'+'
3320 else b'grep.deleted ',
3320 else b'grep.deleted ',
3321 )
3321 )
3322 )
3322 )
3323 cols.extend(
3323 cols.extend(
3324 [
3324 [
3325 (
3325 (
3326 b'user',
3326 b'user',
3327 b'%s',
3327 b'%s',
3328 formatuser(ctx.user()),
3328 formatuser(ctx.user()),
3329 opts.get('user'),
3329 opts.get('user'),
3330 b'',
3330 b'',
3331 ),
3331 ),
3332 (
3332 (
3333 b'date',
3333 b'date',
3334 b'%s',
3334 b'%s',
3335 fm.formatdate(ctx.date(), datefmt),
3335 fm.formatdate(ctx.date(), datefmt),
3336 opts.get('date'),
3336 opts.get('date'),
3337 b'',
3337 b'',
3338 ),
3338 ),
3339 ]
3339 ]
3340 )
3340 )
3341 for name, fmt, data, cond, extra_label in cols:
3341 for name, fmt, data, cond, extra_label in cols:
3342 if cond:
3342 if cond:
3343 fm.plain(sep, label=b'grep.sep')
3343 fm.plain(sep, label=b'grep.sep')
3344 field = fieldnamemap.get(name, name)
3344 field = fieldnamemap.get(name, name)
3345 label = extra_label + (b'grep.%s' % name)
3345 label = extra_label + (b'grep.%s' % name)
3346 fm.condwrite(cond, field, fmt, data, label=label)
3346 fm.condwrite(cond, field, fmt, data, label=label)
3347 if not opts.get('files_with_matches'):
3347 if not opts.get('files_with_matches'):
3348 fm.plain(sep, label=b'grep.sep')
3348 fm.plain(sep, label=b'grep.sep')
3349 if not opts.get('text') and binary():
3349 if not opts.get('text') and binary():
3350 fm.plain(_(b" Binary file matches"))
3350 fm.plain(_(b" Binary file matches"))
3351 else:
3351 else:
3352 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3352 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3353 fm.plain(eol)
3353 fm.plain(eol)
3354 found = True
3354 found = True
3355 if opts.get('files_with_matches'):
3355 if opts.get('files_with_matches'):
3356 break
3356 break
3357 return found
3357 return found
3358
3358
3359 def displaymatches(fm, l):
3359 def displaymatches(fm, l):
3360 p = 0
3360 p = 0
3361 for s, e in l.findpos(regexp):
3361 for s, e in l.findpos(regexp):
3362 if p < s:
3362 if p < s:
3363 fm.startitem()
3363 fm.startitem()
3364 fm.write(b'text', b'%s', l.line[p:s])
3364 fm.write(b'text', b'%s', l.line[p:s])
3365 fm.data(matched=False)
3365 fm.data(matched=False)
3366 fm.startitem()
3366 fm.startitem()
3367 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3367 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3368 fm.data(matched=True)
3368 fm.data(matched=True)
3369 p = e
3369 p = e
3370 if p < len(l.line):
3370 if p < len(l.line):
3371 fm.startitem()
3371 fm.startitem()
3372 fm.write(b'text', b'%s', l.line[p:])
3372 fm.write(b'text', b'%s', l.line[p:])
3373 fm.data(matched=False)
3373 fm.data(matched=False)
3374 fm.end()
3374 fm.end()
3375
3375
3376 found = False
3376 found = False
3377
3377
3378 wopts = logcmdutil.walkopts(
3378 wopts = logcmdutil.walkopts(
3379 pats=pats,
3379 pats=pats,
3380 opts=pycompat.byteskwargs(opts),
3380 opts=pycompat.byteskwargs(opts),
3381 revspec=opts['rev'],
3381 revspec=opts['rev'],
3382 include_pats=opts['include'],
3382 include_pats=opts['include'],
3383 exclude_pats=opts['exclude'],
3383 exclude_pats=opts['exclude'],
3384 follow=follow,
3384 follow=follow,
3385 force_changelog_traversal=all_files,
3385 force_changelog_traversal=all_files,
3386 filter_revisions_by_pats=not all_files,
3386 filter_revisions_by_pats=not all_files,
3387 )
3387 )
3388 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3388 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3389
3389
3390 ui.pager(b'grep')
3390 ui.pager(b'grep')
3391 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3391 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3392 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3392 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3393 r = display(fm, fn, ctx, pstates, states)
3393 r = display(fm, fn, ctx, pstates, states)
3394 found = found or r
3394 found = found or r
3395 if r and not diff and not all_files:
3395 if r and not diff and not all_files:
3396 searcher.skipfile(fn, ctx.rev())
3396 searcher.skipfile(fn, ctx.rev())
3397 fm.end()
3397 fm.end()
3398
3398
3399 return not found
3399 return not found
3400
3400
3401
3401
3402 @command(
3402 @command(
3403 b'heads',
3403 b'heads',
3404 [
3404 [
3405 (
3405 (
3406 b'r',
3406 b'r',
3407 b'rev',
3407 b'rev',
3408 b'',
3408 b'',
3409 _(b'show only heads which are descendants of STARTREV'),
3409 _(b'show only heads which are descendants of STARTREV'),
3410 _(b'STARTREV'),
3410 _(b'STARTREV'),
3411 ),
3411 ),
3412 (b't', b'topo', False, _(b'show topological heads only')),
3412 (b't', b'topo', False, _(b'show topological heads only')),
3413 (
3413 (
3414 b'a',
3414 b'a',
3415 b'active',
3415 b'active',
3416 False,
3416 False,
3417 _(b'show active branchheads only (DEPRECATED)'),
3417 _(b'show active branchheads only (DEPRECATED)'),
3418 ),
3418 ),
3419 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3419 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3420 ]
3420 ]
3421 + templateopts,
3421 + templateopts,
3422 _(b'[-ct] [-r STARTREV] [REV]...'),
3422 _(b'[-ct] [-r STARTREV] [REV]...'),
3423 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3423 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3424 intents={INTENT_READONLY},
3424 intents={INTENT_READONLY},
3425 )
3425 )
3426 def heads(ui, repo, *branchrevs, **opts):
3426 def heads(ui, repo, *branchrevs, **opts):
3427 """show branch heads
3427 """show branch heads
3428
3428
3429 With no arguments, show all open branch heads in the repository.
3429 With no arguments, show all open branch heads in the repository.
3430 Branch heads are changesets that have no descendants on the
3430 Branch heads are changesets that have no descendants on the
3431 same branch. They are where development generally takes place and
3431 same branch. They are where development generally takes place and
3432 are the usual targets for update and merge operations.
3432 are the usual targets for update and merge operations.
3433
3433
3434 If one or more REVs are given, only open branch heads on the
3434 If one or more REVs are given, only open branch heads on the
3435 branches associated with the specified changesets are shown. This
3435 branches associated with the specified changesets are shown. This
3436 means that you can use :hg:`heads .` to see the heads on the
3436 means that you can use :hg:`heads .` to see the heads on the
3437 currently checked-out branch.
3437 currently checked-out branch.
3438
3438
3439 If -c/--closed is specified, also show branch heads marked closed
3439 If -c/--closed is specified, also show branch heads marked closed
3440 (see :hg:`commit --close-branch`).
3440 (see :hg:`commit --close-branch`).
3441
3441
3442 If STARTREV is specified, only those heads that are descendants of
3442 If STARTREV is specified, only those heads that are descendants of
3443 STARTREV will be displayed.
3443 STARTREV will be displayed.
3444
3444
3445 If -t/--topo is specified, named branch mechanics will be ignored and only
3445 If -t/--topo is specified, named branch mechanics will be ignored and only
3446 topological heads (changesets with no children) will be shown.
3446 topological heads (changesets with no children) will be shown.
3447
3447
3448 Returns 0 if matching heads are found, 1 if not.
3448 Returns 0 if matching heads are found, 1 if not.
3449 """
3449 """
3450
3450
3451 start = None
3451 start = None
3452 rev = opts.get('rev')
3452 rev = opts.get('rev')
3453 if rev:
3453 if rev:
3454 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3454 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3455 start = logcmdutil.revsingle(repo, rev, None).node()
3455 start = logcmdutil.revsingle(repo, rev, None).node()
3456
3456
3457 if opts.get('topo'):
3457 if opts.get('topo'):
3458 heads = [repo[h] for h in repo.heads(start)]
3458 heads = [repo[h] for h in repo.heads(start)]
3459 else:
3459 else:
3460 heads = []
3460 heads = []
3461 for branch in repo.branchmap():
3461 for branch in repo.branchmap():
3462 heads += repo.branchheads(branch, start, opts.get('closed'))
3462 heads += repo.branchheads(branch, start, opts.get('closed'))
3463 heads = [repo[h] for h in heads]
3463 heads = [repo[h] for h in heads]
3464
3464
3465 if branchrevs:
3465 if branchrevs:
3466 branches = {
3466 branches = {
3467 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3467 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3468 }
3468 }
3469 heads = [h for h in heads if h.branch() in branches]
3469 heads = [h for h in heads if h.branch() in branches]
3470
3470
3471 if opts.get('active') and branchrevs:
3471 if opts.get('active') and branchrevs:
3472 dagheads = repo.heads(start)
3472 dagheads = repo.heads(start)
3473 heads = [h for h in heads if h.node() in dagheads]
3473 heads = [h for h in heads if h.node() in dagheads]
3474
3474
3475 if branchrevs:
3475 if branchrevs:
3476 haveheads = {h.branch() for h in heads}
3476 haveheads = {h.branch() for h in heads}
3477 if branches - haveheads:
3477 if branches - haveheads:
3478 headless = b', '.join(b for b in branches - haveheads)
3478 headless = b', '.join(b for b in branches - haveheads)
3479 msg = _(b'no open branch heads found on branches %s')
3479 msg = _(b'no open branch heads found on branches %s')
3480 if opts.get('rev'):
3480 if opts.get('rev'):
3481 msg += _(b' (started at %s)') % opts['rev']
3481 msg += _(b' (started at %s)') % opts['rev']
3482 ui.warn((msg + b'\n') % headless)
3482 ui.warn((msg + b'\n') % headless)
3483
3483
3484 if not heads:
3484 if not heads:
3485 return 1
3485 return 1
3486
3486
3487 ui.pager(b'heads')
3487 ui.pager(b'heads')
3488 heads = sorted(heads, key=lambda x: -(x.rev()))
3488 heads = sorted(heads, key=lambda x: -(x.rev()))
3489 displayer = logcmdutil.changesetdisplayer(
3489 displayer = logcmdutil.changesetdisplayer(
3490 ui, repo, pycompat.byteskwargs(opts)
3490 ui, repo, pycompat.byteskwargs(opts)
3491 )
3491 )
3492 for ctx in heads:
3492 for ctx in heads:
3493 displayer.show(ctx)
3493 displayer.show(ctx)
3494 displayer.close()
3494 displayer.close()
3495
3495
3496
3496
3497 @command(
3497 @command(
3498 b'help',
3498 b'help',
3499 [
3499 [
3500 (b'e', b'extension', None, _(b'show only help for extensions')),
3500 (b'e', b'extension', None, _(b'show only help for extensions')),
3501 (b'c', b'command', None, _(b'show only help for commands')),
3501 (b'c', b'command', None, _(b'show only help for commands')),
3502 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3502 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3503 (
3503 (
3504 b's',
3504 b's',
3505 b'system',
3505 b'system',
3506 [],
3506 [],
3507 _(b'show help for specific platform(s)'),
3507 _(b'show help for specific platform(s)'),
3508 _(b'PLATFORM'),
3508 _(b'PLATFORM'),
3509 ),
3509 ),
3510 ],
3510 ],
3511 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3511 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3512 helpcategory=command.CATEGORY_HELP,
3512 helpcategory=command.CATEGORY_HELP,
3513 norepo=True,
3513 norepo=True,
3514 intents={INTENT_READONLY},
3514 intents={INTENT_READONLY},
3515 )
3515 )
3516 def help_(ui, name=None, **opts):
3516 def help_(ui, name=None, **opts):
3517 """show help for a given topic or a help overview
3517 """show help for a given topic or a help overview
3518
3518
3519 With no arguments, print a list of commands with short help messages.
3519 With no arguments, print a list of commands with short help messages.
3520
3520
3521 Given a topic, extension, or command name, print help for that
3521 Given a topic, extension, or command name, print help for that
3522 topic.
3522 topic.
3523
3523
3524 Returns 0 if successful.
3524 Returns 0 if successful.
3525 """
3525 """
3526
3526
3527 keep = opts.get('system') or []
3527 keep = opts.get('system') or []
3528 if len(keep) == 0:
3528 if len(keep) == 0:
3529 if pycompat.sysplatform.startswith(b'win'):
3529 if pycompat.sysplatform.startswith(b'win'):
3530 keep.append(b'windows')
3530 keep.append(b'windows')
3531 elif pycompat.sysplatform == b'OpenVMS':
3531 elif pycompat.sysplatform == b'OpenVMS':
3532 keep.append(b'vms')
3532 keep.append(b'vms')
3533 elif pycompat.sysplatform == b'plan9':
3533 elif pycompat.sysplatform == b'plan9':
3534 keep.append(b'plan9')
3534 keep.append(b'plan9')
3535 else:
3535 else:
3536 keep.append(b'unix')
3536 keep.append(b'unix')
3537 keep.append(pycompat.sysplatform.lower())
3537 keep.append(pycompat.sysplatform.lower())
3538 if ui.verbose:
3538 if ui.verbose:
3539 keep.append(b'verbose')
3539 keep.append(b'verbose')
3540
3540
3541 commands = sys.modules[__name__]
3541 commands = sys.modules[__name__]
3542 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3542 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3543 ui.pager(b'help')
3543 ui.pager(b'help')
3544 ui.write(formatted)
3544 ui.write(formatted)
3545
3545
3546
3546
3547 @command(
3547 @command(
3548 b'identify|id',
3548 b'identify|id',
3549 [
3549 [
3550 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3550 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3551 (b'n', b'num', None, _(b'show local revision number')),
3551 (b'n', b'num', None, _(b'show local revision number')),
3552 (b'i', b'id', None, _(b'show global revision id')),
3552 (b'i', b'id', None, _(b'show global revision id')),
3553 (b'b', b'branch', None, _(b'show branch')),
3553 (b'b', b'branch', None, _(b'show branch')),
3554 (b't', b'tags', None, _(b'show tags')),
3554 (b't', b'tags', None, _(b'show tags')),
3555 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3555 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3556 ]
3556 ]
3557 + remoteopts
3557 + remoteopts
3558 + formatteropts,
3558 + formatteropts,
3559 _(b'[-nibtB] [-r REV] [SOURCE]'),
3559 _(b'[-nibtB] [-r REV] [SOURCE]'),
3560 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3560 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3561 optionalrepo=True,
3561 optionalrepo=True,
3562 intents={INTENT_READONLY},
3562 intents={INTENT_READONLY},
3563 )
3563 )
3564 def identify(
3564 def identify(
3565 ui,
3565 ui,
3566 repo,
3566 repo,
3567 source=None,
3567 source=None,
3568 rev=None,
3568 rev=None,
3569 num=None,
3569 num=None,
3570 id=None,
3570 id=None,
3571 branch=None,
3571 branch=None,
3572 tags=None,
3572 tags=None,
3573 bookmarks=None,
3573 bookmarks=None,
3574 **opts,
3574 **opts,
3575 ):
3575 ):
3576 """identify the working directory or specified revision
3576 """identify the working directory or specified revision
3577
3577
3578 Print a summary identifying the repository state at REV using one or
3578 Print a summary identifying the repository state at REV using one or
3579 two parent hash identifiers, followed by a "+" if the working
3579 two parent hash identifiers, followed by a "+" if the working
3580 directory has uncommitted changes, the branch name (if not default),
3580 directory has uncommitted changes, the branch name (if not default),
3581 a list of tags, and a list of bookmarks.
3581 a list of tags, and a list of bookmarks.
3582
3582
3583 When REV is not given, print a summary of the current state of the
3583 When REV is not given, print a summary of the current state of the
3584 repository including the working directory. Specify -r. to get information
3584 repository including the working directory. Specify -r. to get information
3585 of the working directory parent without scanning uncommitted changes.
3585 of the working directory parent without scanning uncommitted changes.
3586
3586
3587 Specifying a path to a repository root or Mercurial bundle will
3587 Specifying a path to a repository root or Mercurial bundle will
3588 cause lookup to operate on that repository/bundle.
3588 cause lookup to operate on that repository/bundle.
3589
3589
3590 .. container:: verbose
3590 .. container:: verbose
3591
3591
3592 Template:
3592 Template:
3593
3593
3594 The following keywords are supported in addition to the common template
3594 The following keywords are supported in addition to the common template
3595 keywords and functions. See also :hg:`help templates`.
3595 keywords and functions. See also :hg:`help templates`.
3596
3596
3597 :dirty: String. Character ``+`` denoting if the working directory has
3597 :dirty: String. Character ``+`` denoting if the working directory has
3598 uncommitted changes.
3598 uncommitted changes.
3599 :id: String. One or two nodes, optionally followed by ``+``.
3599 :id: String. One or two nodes, optionally followed by ``+``.
3600 :parents: List of strings. Parent nodes of the changeset.
3600 :parents: List of strings. Parent nodes of the changeset.
3601
3601
3602 Examples:
3602 Examples:
3603
3603
3604 - generate a build identifier for the working directory::
3604 - generate a build identifier for the working directory::
3605
3605
3606 hg id --id > build-id.dat
3606 hg id --id > build-id.dat
3607
3607
3608 - find the revision corresponding to a tag::
3608 - find the revision corresponding to a tag::
3609
3609
3610 hg id -n -r 1.3
3610 hg id -n -r 1.3
3611
3611
3612 - check the most recent revision of a remote repository::
3612 - check the most recent revision of a remote repository::
3613
3613
3614 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3614 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3615
3615
3616 See :hg:`log` for generating more information about specific revisions,
3616 See :hg:`log` for generating more information about specific revisions,
3617 including full hash identifiers.
3617 including full hash identifiers.
3618
3618
3619 Returns 0 if successful.
3619 Returns 0 if successful.
3620 """
3620 """
3621
3621
3622 opts = pycompat.byteskwargs(opts)
3622 opts = pycompat.byteskwargs(opts)
3623 if not repo and not source:
3623 if not repo and not source:
3624 raise error.InputError(
3624 raise error.InputError(
3625 _(b"there is no Mercurial repository here (.hg not found)")
3625 _(b"there is no Mercurial repository here (.hg not found)")
3626 )
3626 )
3627
3627
3628 default = not (num or id or branch or tags or bookmarks)
3628 default = not (num or id or branch or tags or bookmarks)
3629 output = []
3629 output = []
3630 revs = []
3630 revs = []
3631
3631
3632 peer = None
3632 peer = None
3633 try:
3633 try:
3634 if source:
3634 if source:
3635 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3635 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3636 # only pass ui when no repo
3636 # only pass ui when no repo
3637 peer = hg.peer(repo or ui, opts, path)
3637 peer = hg.peer(repo or ui, opts, path)
3638 repo = peer.local()
3638 repo = peer.local()
3639 branches = (path.branch, [])
3639 branches = (path.branch, [])
3640 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3640 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3641
3641
3642 fm = ui.formatter(b'identify', opts)
3642 fm = ui.formatter(b'identify', opts)
3643 fm.startitem()
3643 fm.startitem()
3644
3644
3645 if not repo:
3645 if not repo:
3646 if num or branch or tags:
3646 if num or branch or tags:
3647 raise error.InputError(
3647 raise error.InputError(
3648 _(b"can't query remote revision number, branch, or tags")
3648 _(b"can't query remote revision number, branch, or tags")
3649 )
3649 )
3650 if not rev and revs:
3650 if not rev and revs:
3651 rev = revs[0]
3651 rev = revs[0]
3652 if not rev:
3652 if not rev:
3653 rev = b"tip"
3653 rev = b"tip"
3654
3654
3655 remoterev = peer.lookup(rev)
3655 remoterev = peer.lookup(rev)
3656 hexrev = fm.hexfunc(remoterev)
3656 hexrev = fm.hexfunc(remoterev)
3657 if default or id:
3657 if default or id:
3658 output = [hexrev]
3658 output = [hexrev]
3659 fm.data(id=hexrev)
3659 fm.data(id=hexrev)
3660
3660
3661 @util.cachefunc
3661 @util.cachefunc
3662 def getbms():
3662 def getbms():
3663 bms = []
3663 bms = []
3664
3664
3665 if b'bookmarks' in peer.listkeys(b'namespaces'):
3665 if b'bookmarks' in peer.listkeys(b'namespaces'):
3666 hexremoterev = hex(remoterev)
3666 hexremoterev = hex(remoterev)
3667 bms = [
3667 bms = [
3668 bm
3668 bm
3669 for bm, bmr in peer.listkeys(b'bookmarks').items()
3669 for bm, bmr in peer.listkeys(b'bookmarks').items()
3670 if bmr == hexremoterev
3670 if bmr == hexremoterev
3671 ]
3671 ]
3672
3672
3673 return sorted(bms)
3673 return sorted(bms)
3674
3674
3675 if fm.isplain():
3675 if fm.isplain():
3676 if bookmarks:
3676 if bookmarks:
3677 output.extend(getbms())
3677 output.extend(getbms())
3678 elif default and not ui.quiet:
3678 elif default and not ui.quiet:
3679 # multiple bookmarks for a single parent separated by '/'
3679 # multiple bookmarks for a single parent separated by '/'
3680 bm = b'/'.join(getbms())
3680 bm = b'/'.join(getbms())
3681 if bm:
3681 if bm:
3682 output.append(bm)
3682 output.append(bm)
3683 else:
3683 else:
3684 fm.data(node=hex(remoterev))
3684 fm.data(node=hex(remoterev))
3685 if bookmarks or b'bookmarks' in fm.datahint():
3685 if bookmarks or b'bookmarks' in fm.datahint():
3686 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3686 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3687 else:
3687 else:
3688 if rev:
3688 if rev:
3689 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3689 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3690 ctx = logcmdutil.revsingle(repo, rev, None)
3690 ctx = logcmdutil.revsingle(repo, rev, None)
3691
3691
3692 if ctx.rev() is None:
3692 if ctx.rev() is None:
3693 ctx = repo[None]
3693 ctx = repo[None]
3694 parents = ctx.parents()
3694 parents = ctx.parents()
3695 taglist = []
3695 taglist = []
3696 for p in parents:
3696 for p in parents:
3697 taglist.extend(p.tags())
3697 taglist.extend(p.tags())
3698
3698
3699 dirty = b""
3699 dirty = b""
3700 if ctx.dirty(missing=True, merge=False, branch=False):
3700 if ctx.dirty(missing=True, merge=False, branch=False):
3701 dirty = b'+'
3701 dirty = b'+'
3702 fm.data(dirty=dirty)
3702 fm.data(dirty=dirty)
3703
3703
3704 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3704 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3705 if default or id:
3705 if default or id:
3706 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3706 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3707 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3707 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3708
3708
3709 if num:
3709 if num:
3710 numoutput = [b"%d" % p.rev() for p in parents]
3710 numoutput = [b"%d" % p.rev() for p in parents]
3711 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3711 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3712
3712
3713 fm.data(
3713 fm.data(
3714 parents=fm.formatlist(
3714 parents=fm.formatlist(
3715 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3715 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3716 )
3716 )
3717 )
3717 )
3718 else:
3718 else:
3719 hexoutput = fm.hexfunc(ctx.node())
3719 hexoutput = fm.hexfunc(ctx.node())
3720 if default or id:
3720 if default or id:
3721 output = [hexoutput]
3721 output = [hexoutput]
3722 fm.data(id=hexoutput)
3722 fm.data(id=hexoutput)
3723
3723
3724 if num:
3724 if num:
3725 output.append(pycompat.bytestr(ctx.rev()))
3725 output.append(pycompat.bytestr(ctx.rev()))
3726 taglist = ctx.tags()
3726 taglist = ctx.tags()
3727
3727
3728 if default and not ui.quiet:
3728 if default and not ui.quiet:
3729 b = ctx.branch()
3729 b = ctx.branch()
3730 if b != b'default':
3730 if b != b'default':
3731 output.append(b"(%s)" % b)
3731 output.append(b"(%s)" % b)
3732
3732
3733 # multiple tags for a single parent separated by '/'
3733 # multiple tags for a single parent separated by '/'
3734 t = b'/'.join(taglist)
3734 t = b'/'.join(taglist)
3735 if t:
3735 if t:
3736 output.append(t)
3736 output.append(t)
3737
3737
3738 # multiple bookmarks for a single parent separated by '/'
3738 # multiple bookmarks for a single parent separated by '/'
3739 bm = b'/'.join(ctx.bookmarks())
3739 bm = b'/'.join(ctx.bookmarks())
3740 if bm:
3740 if bm:
3741 output.append(bm)
3741 output.append(bm)
3742 else:
3742 else:
3743 if branch:
3743 if branch:
3744 output.append(ctx.branch())
3744 output.append(ctx.branch())
3745
3745
3746 if tags:
3746 if tags:
3747 output.extend(taglist)
3747 output.extend(taglist)
3748
3748
3749 if bookmarks:
3749 if bookmarks:
3750 output.extend(ctx.bookmarks())
3750 output.extend(ctx.bookmarks())
3751
3751
3752 fm.data(node=ctx.hex())
3752 fm.data(node=ctx.hex())
3753 fm.data(branch=ctx.branch())
3753 fm.data(branch=ctx.branch())
3754 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3754 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3755 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3755 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3756 fm.context(ctx=ctx)
3756 fm.context(ctx=ctx)
3757
3757
3758 fm.plain(b"%s\n" % b' '.join(output))
3758 fm.plain(b"%s\n" % b' '.join(output))
3759 fm.end()
3759 fm.end()
3760 finally:
3760 finally:
3761 if peer:
3761 if peer:
3762 peer.close()
3762 peer.close()
3763
3763
3764
3764
3765 @command(
3765 @command(
3766 b'import|patch',
3766 b'import|patch',
3767 [
3767 [
3768 (
3768 (
3769 b'p',
3769 b'p',
3770 b'strip',
3770 b'strip',
3771 1,
3771 1,
3772 _(
3772 _(
3773 b'directory strip option for patch. This has the same '
3773 b'directory strip option for patch. This has the same '
3774 b'meaning as the corresponding patch option'
3774 b'meaning as the corresponding patch option'
3775 ),
3775 ),
3776 _(b'NUM'),
3776 _(b'NUM'),
3777 ),
3777 ),
3778 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3778 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3779 (b'', b'secret', None, _(b'use the secret phase for committing')),
3779 (b'', b'secret', None, _(b'use the secret phase for committing')),
3780 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3780 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3781 (
3781 (
3782 b'f',
3782 b'f',
3783 b'force',
3783 b'force',
3784 None,
3784 None,
3785 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3785 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3786 ),
3786 ),
3787 (
3787 (
3788 b'',
3788 b'',
3789 b'no-commit',
3789 b'no-commit',
3790 None,
3790 None,
3791 _(b"don't commit, just update the working directory"),
3791 _(b"don't commit, just update the working directory"),
3792 ),
3792 ),
3793 (
3793 (
3794 b'',
3794 b'',
3795 b'bypass',
3795 b'bypass',
3796 None,
3796 None,
3797 _(b"apply patch without touching the working directory"),
3797 _(b"apply patch without touching the working directory"),
3798 ),
3798 ),
3799 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3799 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3800 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3800 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3801 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3801 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3802 (
3802 (
3803 b'',
3803 b'',
3804 b'import-branch',
3804 b'import-branch',
3805 None,
3805 None,
3806 _(b'use any branch information in patch (implied by --exact)'),
3806 _(b'use any branch information in patch (implied by --exact)'),
3807 ),
3807 ),
3808 ]
3808 ]
3809 + commitopts
3809 + commitopts
3810 + commitopts2
3810 + commitopts2
3811 + similarityopts,
3811 + similarityopts,
3812 _(b'[OPTION]... PATCH...'),
3812 _(b'[OPTION]... PATCH...'),
3813 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3813 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3814 )
3814 )
3815 def import_(ui, repo, patch1=None, *patches, **opts):
3815 def import_(ui, repo, patch1=None, *patches, **opts):
3816 """import an ordered set of patches
3816 """import an ordered set of patches
3817
3817
3818 Import a list of patches and commit them individually (unless
3818 Import a list of patches and commit them individually (unless
3819 --no-commit is specified).
3819 --no-commit is specified).
3820
3820
3821 To read a patch from standard input (stdin), use "-" as the patch
3821 To read a patch from standard input (stdin), use "-" as the patch
3822 name. If a URL is specified, the patch will be downloaded from
3822 name. If a URL is specified, the patch will be downloaded from
3823 there.
3823 there.
3824
3824
3825 Import first applies changes to the working directory (unless
3825 Import first applies changes to the working directory (unless
3826 --bypass is specified), import will abort if there are outstanding
3826 --bypass is specified), import will abort if there are outstanding
3827 changes.
3827 changes.
3828
3828
3829 Use --bypass to apply and commit patches directly to the
3829 Use --bypass to apply and commit patches directly to the
3830 repository, without affecting the working directory. Without
3830 repository, without affecting the working directory. Without
3831 --exact, patches will be applied on top of the working directory
3831 --exact, patches will be applied on top of the working directory
3832 parent revision.
3832 parent revision.
3833
3833
3834 You can import a patch straight from a mail message. Even patches
3834 You can import a patch straight from a mail message. Even patches
3835 as attachments work (to use the body part, it must have type
3835 as attachments work (to use the body part, it must have type
3836 text/plain or text/x-patch). From and Subject headers of email
3836 text/plain or text/x-patch). From and Subject headers of email
3837 message are used as default committer and commit message. All
3837 message are used as default committer and commit message. All
3838 text/plain body parts before first diff are added to the commit
3838 text/plain body parts before first diff are added to the commit
3839 message.
3839 message.
3840
3840
3841 If the imported patch was generated by :hg:`export`, user and
3841 If the imported patch was generated by :hg:`export`, user and
3842 description from patch override values from message headers and
3842 description from patch override values from message headers and
3843 body. Values given on command line with -m/--message and -u/--user
3843 body. Values given on command line with -m/--message and -u/--user
3844 override these.
3844 override these.
3845
3845
3846 If --exact is specified, import will set the working directory to
3846 If --exact is specified, import will set the working directory to
3847 the parent of each patch before applying it, and will abort if the
3847 the parent of each patch before applying it, and will abort if the
3848 resulting changeset has a different ID than the one recorded in
3848 resulting changeset has a different ID than the one recorded in
3849 the patch. This will guard against various ways that portable
3849 the patch. This will guard against various ways that portable
3850 patch formats and mail systems might fail to transfer Mercurial
3850 patch formats and mail systems might fail to transfer Mercurial
3851 data or metadata. See :hg:`bundle` for lossless transmission.
3851 data or metadata. See :hg:`bundle` for lossless transmission.
3852
3852
3853 Use --partial to ensure a changeset will be created from the patch
3853 Use --partial to ensure a changeset will be created from the patch
3854 even if some hunks fail to apply. Hunks that fail to apply will be
3854 even if some hunks fail to apply. Hunks that fail to apply will be
3855 written to a <target-file>.rej file. Conflicts can then be resolved
3855 written to a <target-file>.rej file. Conflicts can then be resolved
3856 by hand before :hg:`commit --amend` is run to update the created
3856 by hand before :hg:`commit --amend` is run to update the created
3857 changeset. This flag exists to let people import patches that
3857 changeset. This flag exists to let people import patches that
3858 partially apply without losing the associated metadata (author,
3858 partially apply without losing the associated metadata (author,
3859 date, description, ...).
3859 date, description, ...).
3860
3860
3861 .. note::
3861 .. note::
3862
3862
3863 When no hunks apply cleanly, :hg:`import --partial` will create
3863 When no hunks apply cleanly, :hg:`import --partial` will create
3864 an empty changeset, importing only the patch metadata.
3864 an empty changeset, importing only the patch metadata.
3865
3865
3866 With -s/--similarity, hg will attempt to discover renames and
3866 With -s/--similarity, hg will attempt to discover renames and
3867 copies in the patch in the same way as :hg:`addremove`.
3867 copies in the patch in the same way as :hg:`addremove`.
3868
3868
3869 It is possible to use external patch programs to perform the patch
3869 It is possible to use external patch programs to perform the patch
3870 by setting the ``ui.patch`` configuration option. For the default
3870 by setting the ``ui.patch`` configuration option. For the default
3871 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3871 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3872 See :hg:`help config` for more information about configuration
3872 See :hg:`help config` for more information about configuration
3873 files and how to use these options.
3873 files and how to use these options.
3874
3874
3875 See :hg:`help dates` for a list of formats valid for -d/--date.
3875 See :hg:`help dates` for a list of formats valid for -d/--date.
3876
3876
3877 .. container:: verbose
3877 .. container:: verbose
3878
3878
3879 Examples:
3879 Examples:
3880
3880
3881 - import a traditional patch from a website and detect renames::
3881 - import a traditional patch from a website and detect renames::
3882
3882
3883 hg import -s 80 http://example.com/bugfix.patch
3883 hg import -s 80 http://example.com/bugfix.patch
3884
3884
3885 - import a changeset from an hgweb server::
3885 - import a changeset from an hgweb server::
3886
3886
3887 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3887 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3888
3888
3889 - import all the patches in an Unix-style mbox::
3889 - import all the patches in an Unix-style mbox::
3890
3890
3891 hg import incoming-patches.mbox
3891 hg import incoming-patches.mbox
3892
3892
3893 - import patches from stdin::
3893 - import patches from stdin::
3894
3894
3895 hg import -
3895 hg import -
3896
3896
3897 - attempt to exactly restore an exported changeset (not always
3897 - attempt to exactly restore an exported changeset (not always
3898 possible)::
3898 possible)::
3899
3899
3900 hg import --exact proposed-fix.patch
3900 hg import --exact proposed-fix.patch
3901
3901
3902 - use an external tool to apply a patch which is too fuzzy for
3902 - use an external tool to apply a patch which is too fuzzy for
3903 the default internal tool.
3903 the default internal tool.
3904
3904
3905 hg import --config ui.patch="patch --merge" fuzzy.patch
3905 hg import --config ui.patch="patch --merge" fuzzy.patch
3906
3906
3907 - change the default fuzzing from 2 to a less strict 7
3907 - change the default fuzzing from 2 to a less strict 7
3908
3908
3909 hg import --config ui.fuzz=7 fuzz.patch
3909 hg import --config ui.fuzz=7 fuzz.patch
3910
3910
3911 Returns 0 on success, 1 on partial success (see --partial).
3911 Returns 0 on success, 1 on partial success (see --partial).
3912 """
3912 """
3913
3913
3914 cmdutil.check_incompatible_arguments(
3914 cmdutil.check_incompatible_arguments(
3915 opts, 'no_commit', ['bypass', 'secret']
3915 opts, 'no_commit', ['bypass', 'secret']
3916 )
3916 )
3917 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3917 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3918
3918
3919 if not patch1:
3919 if not patch1:
3920 raise error.InputError(_(b'need at least one patch to import'))
3920 raise error.InputError(_(b'need at least one patch to import'))
3921
3921
3922 patches = (patch1,) + patches
3922 patches = (patch1,) + patches
3923
3923
3924 date = opts.get('date')
3924 date = opts.get('date')
3925 if date:
3925 if date:
3926 opts['date'] = dateutil.parsedate(date)
3926 opts['date'] = dateutil.parsedate(date)
3927
3927
3928 exact = opts.get('exact')
3928 exact = opts.get('exact')
3929 update = not opts.get('bypass')
3929 update = not opts.get('bypass')
3930 try:
3930 try:
3931 sim = float(opts.get('similarity') or 0)
3931 sim = float(opts.get('similarity') or 0)
3932 except ValueError:
3932 except ValueError:
3933 raise error.InputError(_(b'similarity must be a number'))
3933 raise error.InputError(_(b'similarity must be a number'))
3934 if sim < 0 or sim > 100:
3934 if sim < 0 or sim > 100:
3935 raise error.InputError(_(b'similarity must be between 0 and 100'))
3935 raise error.InputError(_(b'similarity must be between 0 and 100'))
3936 if sim and not update:
3936 if sim and not update:
3937 raise error.InputError(_(b'cannot use --similarity with --bypass'))
3937 raise error.InputError(_(b'cannot use --similarity with --bypass'))
3938
3938
3939 base = opts["base"]
3939 base = opts["base"]
3940 msgs = []
3940 msgs = []
3941 ret = 0
3941 ret = 0
3942
3942
3943 with repo.wlock():
3943 with repo.wlock():
3944 if update:
3944 if update:
3945 cmdutil.checkunfinished(repo)
3945 cmdutil.checkunfinished(repo)
3946 if exact or not opts.get('force'):
3946 if exact or not opts.get('force'):
3947 cmdutil.bailifchanged(repo)
3947 cmdutil.bailifchanged(repo)
3948
3948
3949 if not opts.get('no_commit'):
3949 if not opts.get('no_commit'):
3950 lock = repo.lock
3950 lock = repo.lock
3951 tr = lambda: repo.transaction(b'import')
3951 tr = lambda: repo.transaction(b'import')
3952 else:
3952 else:
3953 lock = util.nullcontextmanager
3953 lock = util.nullcontextmanager
3954 tr = util.nullcontextmanager
3954 tr = util.nullcontextmanager
3955 with lock(), tr():
3955 with lock(), tr():
3956 parents = repo[None].parents()
3956 parents = repo[None].parents()
3957 for patchurl in patches:
3957 for patchurl in patches:
3958 if patchurl == b'-':
3958 if patchurl == b'-':
3959 ui.status(_(b'applying patch from stdin\n'))
3959 ui.status(_(b'applying patch from stdin\n'))
3960 patchfile = ui.fin
3960 patchfile = ui.fin
3961 patchurl = b'stdin' # for error message
3961 patchurl = b'stdin' # for error message
3962 else:
3962 else:
3963 patchurl = os.path.join(base, patchurl)
3963 patchurl = os.path.join(base, patchurl)
3964 ui.status(_(b'applying %s\n') % patchurl)
3964 ui.status(_(b'applying %s\n') % patchurl)
3965 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3965 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3966
3966
3967 haspatch = False
3967 haspatch = False
3968 for hunk in patch.split(patchfile):
3968 for hunk in patch.split(patchfile):
3969 with patch.extract(ui, hunk) as patchdata:
3969 with patch.extract(ui, hunk) as patchdata:
3970 msg, node, rej = cmdutil.tryimportone(
3970 msg, node, rej = cmdutil.tryimportone(
3971 ui,
3971 ui,
3972 repo,
3972 repo,
3973 patchdata,
3973 patchdata,
3974 parents,
3974 parents,
3975 pycompat.byteskwargs(opts),
3975 pycompat.byteskwargs(opts),
3976 msgs,
3976 msgs,
3977 hg.clean,
3977 hg.clean,
3978 )
3978 )
3979 if msg:
3979 if msg:
3980 haspatch = True
3980 haspatch = True
3981 ui.note(msg + b'\n')
3981 ui.note(msg + b'\n')
3982 if update or exact:
3982 if update or exact:
3983 parents = repo[None].parents()
3983 parents = repo[None].parents()
3984 else:
3984 else:
3985 parents = [repo[node]]
3985 parents = [repo[node]]
3986 if rej:
3986 if rej:
3987 ui.write_err(_(b"patch applied partially\n"))
3987 ui.write_err(_(b"patch applied partially\n"))
3988 ui.write_err(
3988 ui.write_err(
3989 _(
3989 _(
3990 b"(fix the .rej files and run "
3990 b"(fix the .rej files and run "
3991 b"`hg commit --amend`)\n"
3991 b"`hg commit --amend`)\n"
3992 )
3992 )
3993 )
3993 )
3994 ret = 1
3994 ret = 1
3995 break
3995 break
3996
3996
3997 if not haspatch:
3997 if not haspatch:
3998 raise error.InputError(_(b'%s: no diffs found') % patchurl)
3998 raise error.InputError(_(b'%s: no diffs found') % patchurl)
3999
3999
4000 if msgs:
4000 if msgs:
4001 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4001 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4002 return ret
4002 return ret
4003
4003
4004
4004
4005 @command(
4005 @command(
4006 b'incoming|in',
4006 b'incoming|in',
4007 [
4007 [
4008 (
4008 (
4009 b'f',
4009 b'f',
4010 b'force',
4010 b'force',
4011 None,
4011 None,
4012 _(b'run even if remote repository is unrelated'),
4012 _(b'run even if remote repository is unrelated'),
4013 ),
4013 ),
4014 (b'n', b'newest-first', None, _(b'show newest record first')),
4014 (b'n', b'newest-first', None, _(b'show newest record first')),
4015 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4015 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4016 (
4016 (
4017 b'r',
4017 b'r',
4018 b'rev',
4018 b'rev',
4019 [],
4019 [],
4020 _(b'a remote changeset intended to be added'),
4020 _(b'a remote changeset intended to be added'),
4021 _(b'REV'),
4021 _(b'REV'),
4022 ),
4022 ),
4023 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4023 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4024 (
4024 (
4025 b'b',
4025 b'b',
4026 b'branch',
4026 b'branch',
4027 [],
4027 [],
4028 _(b'a specific branch you would like to pull'),
4028 _(b'a specific branch you would like to pull'),
4029 _(b'BRANCH'),
4029 _(b'BRANCH'),
4030 ),
4030 ),
4031 ]
4031 ]
4032 + logopts
4032 + logopts
4033 + remoteopts
4033 + remoteopts
4034 + subrepoopts,
4034 + subrepoopts,
4035 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4035 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4036 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4036 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4037 )
4037 )
4038 def incoming(ui, repo, source=b"default", **opts):
4038 def incoming(ui, repo, source=b"default", **opts):
4039 """show new changesets found in source
4039 """show new changesets found in source
4040
4040
4041 Show new changesets found in the specified path/URL or the default
4041 Show new changesets found in the specified path/URL or the default
4042 pull location. These are the changesets that would have been pulled
4042 pull location. These are the changesets that would have been pulled
4043 by :hg:`pull` at the time you issued this command.
4043 by :hg:`pull` at the time you issued this command.
4044
4044
4045 See pull for valid source format details.
4045 See pull for valid source format details.
4046
4046
4047 .. container:: verbose
4047 .. container:: verbose
4048
4048
4049 With -B/--bookmarks, the result of bookmark comparison between
4049 With -B/--bookmarks, the result of bookmark comparison between
4050 local and remote repositories is displayed. With -v/--verbose,
4050 local and remote repositories is displayed. With -v/--verbose,
4051 status is also displayed for each bookmark like below::
4051 status is also displayed for each bookmark like below::
4052
4052
4053 BM1 01234567890a added
4053 BM1 01234567890a added
4054 BM2 1234567890ab advanced
4054 BM2 1234567890ab advanced
4055 BM3 234567890abc diverged
4055 BM3 234567890abc diverged
4056 BM4 34567890abcd changed
4056 BM4 34567890abcd changed
4057
4057
4058 The action taken locally when pulling depends on the
4058 The action taken locally when pulling depends on the
4059 status of each bookmark:
4059 status of each bookmark:
4060
4060
4061 :``added``: pull will create it
4061 :``added``: pull will create it
4062 :``advanced``: pull will update it
4062 :``advanced``: pull will update it
4063 :``diverged``: pull will create a divergent bookmark
4063 :``diverged``: pull will create a divergent bookmark
4064 :``changed``: result depends on remote changesets
4064 :``changed``: result depends on remote changesets
4065
4065
4066 From the point of view of pulling behavior, bookmark
4066 From the point of view of pulling behavior, bookmark
4067 existing only in the remote repository are treated as ``added``,
4067 existing only in the remote repository are treated as ``added``,
4068 even if it is in fact locally deleted.
4068 even if it is in fact locally deleted.
4069
4069
4070 .. container:: verbose
4070 .. container:: verbose
4071
4071
4072 For remote repository, using --bundle avoids downloading the
4072 For remote repository, using --bundle avoids downloading the
4073 changesets twice if the incoming is followed by a pull.
4073 changesets twice if the incoming is followed by a pull.
4074
4074
4075 Examples:
4075 Examples:
4076
4076
4077 - show incoming changes with patches and full description::
4077 - show incoming changes with patches and full description::
4078
4078
4079 hg incoming -vp
4079 hg incoming -vp
4080
4080
4081 - show incoming changes excluding merges, store a bundle::
4081 - show incoming changes excluding merges, store a bundle::
4082
4082
4083 hg in -vpM --bundle incoming.hg
4083 hg in -vpM --bundle incoming.hg
4084 hg pull incoming.hg
4084 hg pull incoming.hg
4085
4085
4086 - briefly list changes inside a bundle::
4086 - briefly list changes inside a bundle::
4087
4087
4088 hg in changes.hg -T "{desc|firstline}\\n"
4088 hg in changes.hg -T "{desc|firstline}\\n"
4089
4089
4090 Returns 0 if there are incoming changes, 1 otherwise.
4090 Returns 0 if there are incoming changes, 1 otherwise.
4091 """
4091 """
4092 opts = pycompat.byteskwargs(opts)
4092 opts = pycompat.byteskwargs(opts)
4093 if opts.get(b'graph'):
4093 if opts.get(b'graph'):
4094 logcmdutil.checkunsupportedgraphflags([], opts)
4094 logcmdutil.checkunsupportedgraphflags([], opts)
4095
4095
4096 def display(other, chlist, displayer):
4096 def display(other, chlist, displayer):
4097 revdag = logcmdutil.graphrevs(other, chlist, opts)
4097 revdag = logcmdutil.graphrevs(other, chlist, opts)
4098 logcmdutil.displaygraph(
4098 logcmdutil.displaygraph(
4099 ui, repo, revdag, displayer, graphmod.asciiedges
4099 ui, repo, revdag, displayer, graphmod.asciiedges
4100 )
4100 )
4101
4101
4102 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4102 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4103 return 0
4103 return 0
4104
4104
4105 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4105 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4106
4106
4107 if opts.get(b'bookmarks'):
4107 if opts.get(b'bookmarks'):
4108 srcs = urlutil.get_pull_paths(repo, ui, [source])
4108 srcs = urlutil.get_pull_paths(repo, ui, [source])
4109 for path in srcs:
4109 for path in srcs:
4110 # XXX the "branches" options are not used. Should it be used?
4110 # XXX the "branches" options are not used. Should it be used?
4111 other = hg.peer(repo, opts, path)
4111 other = hg.peer(repo, opts, path)
4112 try:
4112 try:
4113 if b'bookmarks' not in other.listkeys(b'namespaces'):
4113 if b'bookmarks' not in other.listkeys(b'namespaces'):
4114 ui.warn(_(b"remote doesn't support bookmarks\n"))
4114 ui.warn(_(b"remote doesn't support bookmarks\n"))
4115 return 0
4115 return 0
4116 ui.pager(b'incoming')
4116 ui.pager(b'incoming')
4117 ui.status(
4117 ui.status(
4118 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4118 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4119 )
4119 )
4120 return bookmarks.incoming(
4120 return bookmarks.incoming(
4121 ui, repo, other, mode=path.bookmarks_mode
4121 ui, repo, other, mode=path.bookmarks_mode
4122 )
4122 )
4123 finally:
4123 finally:
4124 other.close()
4124 other.close()
4125
4125
4126 return hg.incoming(ui, repo, source, opts)
4126 return hg.incoming(ui, repo, source, opts)
4127
4127
4128
4128
4129 @command(
4129 @command(
4130 b'init',
4130 b'init',
4131 remoteopts,
4131 remoteopts,
4132 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4132 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4133 helpcategory=command.CATEGORY_REPO_CREATION,
4133 helpcategory=command.CATEGORY_REPO_CREATION,
4134 helpbasic=True,
4134 helpbasic=True,
4135 norepo=True,
4135 norepo=True,
4136 )
4136 )
4137 def init(ui, dest=b".", **opts):
4137 def init(ui, dest=b".", **opts):
4138 """create a new repository in the given directory
4138 """create a new repository in the given directory
4139
4139
4140 Initialize a new repository in the given directory. If the given
4140 Initialize a new repository in the given directory. If the given
4141 directory does not exist, it will be created.
4141 directory does not exist, it will be created.
4142
4142
4143 If no directory is given, the current directory is used.
4143 If no directory is given, the current directory is used.
4144
4144
4145 It is possible to specify an ``ssh://`` URL as the destination.
4145 It is possible to specify an ``ssh://`` URL as the destination.
4146 See :hg:`help urls` for more information.
4146 See :hg:`help urls` for more information.
4147
4147
4148 Returns 0 on success.
4148 Returns 0 on success.
4149 """
4149 """
4150 opts = pycompat.byteskwargs(opts)
4150 opts = pycompat.byteskwargs(opts)
4151 path = urlutil.get_clone_path_obj(ui, dest)
4151 path = urlutil.get_clone_path_obj(ui, dest)
4152 peer = hg.peer(ui, opts, path, create=True)
4152 peer = hg.peer(ui, opts, path, create=True)
4153 peer.close()
4153 peer.close()
4154
4154
4155
4155
4156 @command(
4156 @command(
4157 b'locate',
4157 b'locate',
4158 [
4158 [
4159 (
4159 (
4160 b'r',
4160 b'r',
4161 b'rev',
4161 b'rev',
4162 b'',
4162 b'',
4163 _(b'search the repository as it is in REV'),
4163 _(b'search the repository as it is in REV'),
4164 _(b'REV'),
4164 _(b'REV'),
4165 ),
4165 ),
4166 (
4166 (
4167 b'0',
4167 b'0',
4168 b'print0',
4168 b'print0',
4169 None,
4169 None,
4170 _(b'end filenames with NUL, for use with xargs'),
4170 _(b'end filenames with NUL, for use with xargs'),
4171 ),
4171 ),
4172 (
4172 (
4173 b'f',
4173 b'f',
4174 b'fullpath',
4174 b'fullpath',
4175 None,
4175 None,
4176 _(b'print complete paths from the filesystem root'),
4176 _(b'print complete paths from the filesystem root'),
4177 ),
4177 ),
4178 ]
4178 ]
4179 + walkopts,
4179 + walkopts,
4180 _(b'[OPTION]... [PATTERN]...'),
4180 _(b'[OPTION]... [PATTERN]...'),
4181 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4181 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4182 )
4182 )
4183 def locate(ui, repo, *pats, **opts):
4183 def locate(ui, repo, *pats, **opts):
4184 """locate files matching specific patterns (DEPRECATED)
4184 """locate files matching specific patterns (DEPRECATED)
4185
4185
4186 Print files under Mercurial control in the working directory whose
4186 Print files under Mercurial control in the working directory whose
4187 names match the given patterns.
4187 names match the given patterns.
4188
4188
4189 By default, this command searches all directories in the working
4189 By default, this command searches all directories in the working
4190 directory. To search just the current directory and its
4190 directory. To search just the current directory and its
4191 subdirectories, use "--include .".
4191 subdirectories, use "--include .".
4192
4192
4193 If no patterns are given to match, this command prints the names
4193 If no patterns are given to match, this command prints the names
4194 of all files under Mercurial control in the working directory.
4194 of all files under Mercurial control in the working directory.
4195
4195
4196 If you want to feed the output of this command into the "xargs"
4196 If you want to feed the output of this command into the "xargs"
4197 command, use the -0 option to both this command and "xargs". This
4197 command, use the -0 option to both this command and "xargs". This
4198 will avoid the problem of "xargs" treating single filenames that
4198 will avoid the problem of "xargs" treating single filenames that
4199 contain whitespace as multiple filenames.
4199 contain whitespace as multiple filenames.
4200
4200
4201 See :hg:`help files` for a more versatile command.
4201 See :hg:`help files` for a more versatile command.
4202
4202
4203 Returns 0 if a match is found, 1 otherwise.
4203 Returns 0 if a match is found, 1 otherwise.
4204 """
4204 """
4205 if opts.get('print0'):
4205 if opts.get('print0'):
4206 end = b'\0'
4206 end = b'\0'
4207 else:
4207 else:
4208 end = b'\n'
4208 end = b'\n'
4209 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4209 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4210
4210
4211 ret = 1
4211 ret = 1
4212 m = scmutil.match(
4212 m = scmutil.match(
4213 ctx,
4213 ctx,
4214 pats,
4214 pats,
4215 pycompat.byteskwargs(opts),
4215 pycompat.byteskwargs(opts),
4216 default=b'relglob',
4216 default=b'relglob',
4217 badfn=lambda x, y: False,
4217 badfn=lambda x, y: False,
4218 )
4218 )
4219
4219
4220 ui.pager(b'locate')
4220 ui.pager(b'locate')
4221 if ctx.rev() is None:
4221 if ctx.rev() is None:
4222 # When run on the working copy, "locate" includes removed files, so
4222 # When run on the working copy, "locate" includes removed files, so
4223 # we get the list of files from the dirstate.
4223 # we get the list of files from the dirstate.
4224 filesgen = sorted(repo.dirstate.matches(m))
4224 filesgen = sorted(repo.dirstate.matches(m))
4225 else:
4225 else:
4226 filesgen = ctx.matches(m)
4226 filesgen = ctx.matches(m)
4227 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4227 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4228 for abs in filesgen:
4228 for abs in filesgen:
4229 if opts.get('fullpath'):
4229 if opts.get('fullpath'):
4230 ui.write(repo.wjoin(abs), end)
4230 ui.write(repo.wjoin(abs), end)
4231 else:
4231 else:
4232 ui.write(uipathfn(abs), end)
4232 ui.write(uipathfn(abs), end)
4233 ret = 0
4233 ret = 0
4234
4234
4235 return ret
4235 return ret
4236
4236
4237
4237
4238 @command(
4238 @command(
4239 b'log|history',
4239 b'log|history',
4240 [
4240 [
4241 (
4241 (
4242 b'f',
4242 b'f',
4243 b'follow',
4243 b'follow',
4244 None,
4244 None,
4245 _(
4245 _(
4246 b'follow changeset history, or file history across copies and renames'
4246 b'follow changeset history, or file history across copies and renames'
4247 ),
4247 ),
4248 ),
4248 ),
4249 (
4249 (
4250 b'',
4250 b'',
4251 b'follow-first',
4251 b'follow-first',
4252 None,
4252 None,
4253 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4253 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4254 ),
4254 ),
4255 (
4255 (
4256 b'd',
4256 b'd',
4257 b'date',
4257 b'date',
4258 b'',
4258 b'',
4259 _(b'show revisions matching date spec'),
4259 _(b'show revisions matching date spec'),
4260 _(b'DATE'),
4260 _(b'DATE'),
4261 ),
4261 ),
4262 (b'C', b'copies', None, _(b'show copied files')),
4262 (b'C', b'copies', None, _(b'show copied files')),
4263 (
4263 (
4264 b'k',
4264 b'k',
4265 b'keyword',
4265 b'keyword',
4266 [],
4266 [],
4267 _(b'do case-insensitive search for a given text'),
4267 _(b'do case-insensitive search for a given text'),
4268 _(b'TEXT'),
4268 _(b'TEXT'),
4269 ),
4269 ),
4270 (
4270 (
4271 b'r',
4271 b'r',
4272 b'rev',
4272 b'rev',
4273 [],
4273 [],
4274 _(b'revisions to select or follow from'),
4274 _(b'revisions to select or follow from'),
4275 _(b'REV'),
4275 _(b'REV'),
4276 ),
4276 ),
4277 (
4277 (
4278 b'L',
4278 b'L',
4279 b'line-range',
4279 b'line-range',
4280 [],
4280 [],
4281 _(b'follow line range of specified file (EXPERIMENTAL)'),
4281 _(b'follow line range of specified file (EXPERIMENTAL)'),
4282 _(b'FILE,RANGE'),
4282 _(b'FILE,RANGE'),
4283 ),
4283 ),
4284 (
4284 (
4285 b'',
4285 b'',
4286 b'removed',
4286 b'removed',
4287 None,
4287 None,
4288 _(b'include revisions where files were removed'),
4288 _(b'include revisions where files were removed'),
4289 ),
4289 ),
4290 (
4290 (
4291 b'm',
4291 b'm',
4292 b'only-merges',
4292 b'only-merges',
4293 None,
4293 None,
4294 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4294 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4295 ),
4295 ),
4296 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4296 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4297 (
4297 (
4298 b'',
4298 b'',
4299 b'only-branch',
4299 b'only-branch',
4300 [],
4300 [],
4301 _(
4301 _(
4302 b'show only changesets within the given named branch (DEPRECATED)'
4302 b'show only changesets within the given named branch (DEPRECATED)'
4303 ),
4303 ),
4304 _(b'BRANCH'),
4304 _(b'BRANCH'),
4305 ),
4305 ),
4306 (
4306 (
4307 b'b',
4307 b'b',
4308 b'branch',
4308 b'branch',
4309 [],
4309 [],
4310 _(b'show changesets within the given named branch'),
4310 _(b'show changesets within the given named branch'),
4311 _(b'BRANCH'),
4311 _(b'BRANCH'),
4312 ),
4312 ),
4313 (
4313 (
4314 b'B',
4314 b'B',
4315 b'bookmark',
4315 b'bookmark',
4316 [],
4316 [],
4317 _(b"show changesets within the given bookmark"),
4317 _(b"show changesets within the given bookmark"),
4318 _(b'BOOKMARK'),
4318 _(b'BOOKMARK'),
4319 ),
4319 ),
4320 (
4320 (
4321 b'P',
4321 b'P',
4322 b'prune',
4322 b'prune',
4323 [],
4323 [],
4324 _(b'do not display revision or any of its ancestors'),
4324 _(b'do not display revision or any of its ancestors'),
4325 _(b'REV'),
4325 _(b'REV'),
4326 ),
4326 ),
4327 ]
4327 ]
4328 + logopts
4328 + logopts
4329 + walkopts,
4329 + walkopts,
4330 _(b'[OPTION]... [FILE]'),
4330 _(b'[OPTION]... [FILE]'),
4331 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4331 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4332 helpbasic=True,
4332 helpbasic=True,
4333 inferrepo=True,
4333 inferrepo=True,
4334 intents={INTENT_READONLY},
4334 intents={INTENT_READONLY},
4335 )
4335 )
4336 def log(ui, repo, *pats, **opts):
4336 def log(ui, repo, *pats, **opts):
4337 """show revision history of entire repository or files
4337 """show revision history of entire repository or files
4338
4338
4339 Print the revision history of the specified files or the entire
4339 Print the revision history of the specified files or the entire
4340 project.
4340 project.
4341
4341
4342 If no revision range is specified, the default is ``tip:0`` unless
4342 If no revision range is specified, the default is ``tip:0`` unless
4343 --follow is set.
4343 --follow is set.
4344
4344
4345 File history is shown without following rename or copy history of
4345 File history is shown without following rename or copy history of
4346 files. Use -f/--follow with a filename to follow history across
4346 files. Use -f/--follow with a filename to follow history across
4347 renames and copies. --follow without a filename will only show
4347 renames and copies. --follow without a filename will only show
4348 ancestors of the starting revisions. The starting revisions can be
4348 ancestors of the starting revisions. The starting revisions can be
4349 specified by -r/--rev, which default to the working directory parent.
4349 specified by -r/--rev, which default to the working directory parent.
4350
4350
4351 By default this command prints revision number and changeset id,
4351 By default this command prints revision number and changeset id,
4352 tags, non-trivial parents, user, date and time, and a summary for
4352 tags, non-trivial parents, user, date and time, and a summary for
4353 each commit. When the -v/--verbose switch is used, the list of
4353 each commit. When the -v/--verbose switch is used, the list of
4354 changed files and full commit message are shown.
4354 changed files and full commit message are shown.
4355
4355
4356 With --graph the revisions are shown as an ASCII art DAG with the most
4356 With --graph the revisions are shown as an ASCII art DAG with the most
4357 recent changeset at the top.
4357 recent changeset at the top.
4358 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4358 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4359 involved in an unresolved merge conflict, '_' closes a branch,
4359 involved in an unresolved merge conflict, '_' closes a branch,
4360 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4360 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4361 changeset from the lines below is a parent of the 'o' merge on the same
4361 changeset from the lines below is a parent of the 'o' merge on the same
4362 line.
4362 line.
4363 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4363 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4364 of a '|' indicates one or more revisions in a path are omitted.
4364 of a '|' indicates one or more revisions in a path are omitted.
4365
4365
4366 .. container:: verbose
4366 .. container:: verbose
4367
4367
4368 Use -L/--line-range FILE,M:N options to follow the history of lines
4368 Use -L/--line-range FILE,M:N options to follow the history of lines
4369 from M to N in FILE. With -p/--patch only diff hunks affecting
4369 from M to N in FILE. With -p/--patch only diff hunks affecting
4370 specified line range will be shown. This option requires --follow;
4370 specified line range will be shown. This option requires --follow;
4371 it can be specified multiple times. Currently, this option is not
4371 it can be specified multiple times. Currently, this option is not
4372 compatible with --graph. This option is experimental.
4372 compatible with --graph. This option is experimental.
4373
4373
4374 .. note::
4374 .. note::
4375
4375
4376 :hg:`log --patch` may generate unexpected diff output for merge
4376 :hg:`log --patch` may generate unexpected diff output for merge
4377 changesets, as it will only compare the merge changeset against
4377 changesets, as it will only compare the merge changeset against
4378 its first parent. Also, only files different from BOTH parents
4378 its first parent. Also, only files different from BOTH parents
4379 will appear in files:.
4379 will appear in files:.
4380
4380
4381 .. note::
4381 .. note::
4382
4382
4383 For performance reasons, :hg:`log FILE` may omit duplicate changes
4383 For performance reasons, :hg:`log FILE` may omit duplicate changes
4384 made on branches and will not show removals or mode changes. To
4384 made on branches and will not show removals or mode changes. To
4385 see all such changes, use the --removed switch.
4385 see all such changes, use the --removed switch.
4386
4386
4387 .. container:: verbose
4387 .. container:: verbose
4388
4388
4389 .. note::
4389 .. note::
4390
4390
4391 The history resulting from -L/--line-range options depends on diff
4391 The history resulting from -L/--line-range options depends on diff
4392 options; for instance if white-spaces are ignored, respective changes
4392 options; for instance if white-spaces are ignored, respective changes
4393 with only white-spaces in specified line range will not be listed.
4393 with only white-spaces in specified line range will not be listed.
4394
4394
4395 .. container:: verbose
4395 .. container:: verbose
4396
4396
4397 Some examples:
4397 Some examples:
4398
4398
4399 - changesets with full descriptions and file lists::
4399 - changesets with full descriptions and file lists::
4400
4400
4401 hg log -v
4401 hg log -v
4402
4402
4403 - changesets ancestral to the working directory::
4403 - changesets ancestral to the working directory::
4404
4404
4405 hg log -f
4405 hg log -f
4406
4406
4407 - last 10 commits on the current branch::
4407 - last 10 commits on the current branch::
4408
4408
4409 hg log -l 10 -b .
4409 hg log -l 10 -b .
4410
4410
4411 - changesets showing all modifications of a file, including removals::
4411 - changesets showing all modifications of a file, including removals::
4412
4412
4413 hg log --removed file.c
4413 hg log --removed file.c
4414
4414
4415 - all changesets that touch a directory, with diffs, excluding merges::
4415 - all changesets that touch a directory, with diffs, excluding merges::
4416
4416
4417 hg log -Mp lib/
4417 hg log -Mp lib/
4418
4418
4419 - all revision numbers that match a keyword::
4419 - all revision numbers that match a keyword::
4420
4420
4421 hg log -k bug --template "{rev}\\n"
4421 hg log -k bug --template "{rev}\\n"
4422
4422
4423 - the full hash identifier of the working directory parent::
4423 - the full hash identifier of the working directory parent::
4424
4424
4425 hg log -r . --template "{node}\\n"
4425 hg log -r . --template "{node}\\n"
4426
4426
4427 - list available log templates::
4427 - list available log templates::
4428
4428
4429 hg log -T list
4429 hg log -T list
4430
4430
4431 - check if a given changeset is included in a tagged release::
4431 - check if a given changeset is included in a tagged release::
4432
4432
4433 hg log -r "a21ccf and ancestor(1.9)"
4433 hg log -r "a21ccf and ancestor(1.9)"
4434
4434
4435 - find all changesets by some user in a date range::
4435 - find all changesets by some user in a date range::
4436
4436
4437 hg log -k alice -d "may 2008 to jul 2008"
4437 hg log -k alice -d "may 2008 to jul 2008"
4438
4438
4439 - summary of all changesets after the last tag::
4439 - summary of all changesets after the last tag::
4440
4440
4441 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4441 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4442
4442
4443 - changesets touching lines 13 to 23 for file.c::
4443 - changesets touching lines 13 to 23 for file.c::
4444
4444
4445 hg log -L file.c,13:23
4445 hg log -L file.c,13:23
4446
4446
4447 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4447 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4448 main.c with patch::
4448 main.c with patch::
4449
4449
4450 hg log -L file.c,13:23 -L main.c,2:6 -p
4450 hg log -L file.c,13:23 -L main.c,2:6 -p
4451
4451
4452 See :hg:`help dates` for a list of formats valid for -d/--date.
4452 See :hg:`help dates` for a list of formats valid for -d/--date.
4453
4453
4454 See :hg:`help revisions` for more about specifying and ordering
4454 See :hg:`help revisions` for more about specifying and ordering
4455 revisions.
4455 revisions.
4456
4456
4457 See :hg:`help templates` for more about pre-packaged styles and
4457 See :hg:`help templates` for more about pre-packaged styles and
4458 specifying custom templates. The default template used by the log
4458 specifying custom templates. The default template used by the log
4459 command can be customized via the ``command-templates.log`` configuration
4459 command can be customized via the ``command-templates.log`` configuration
4460 setting.
4460 setting.
4461
4461
4462 Returns 0 on success.
4462 Returns 0 on success.
4463
4463
4464 """
4464 """
4465 opts = pycompat.byteskwargs(opts)
4465 opts = pycompat.byteskwargs(opts)
4466 linerange = opts.get(b'line_range')
4466 linerange = opts.get(b'line_range')
4467
4467
4468 if linerange and not opts.get(b'follow'):
4468 if linerange and not opts.get(b'follow'):
4469 raise error.InputError(_(b'--line-range requires --follow'))
4469 raise error.InputError(_(b'--line-range requires --follow'))
4470
4470
4471 if linerange and pats:
4471 if linerange and pats:
4472 # TODO: take pats as patterns with no line-range filter
4472 # TODO: take pats as patterns with no line-range filter
4473 raise error.InputError(
4473 raise error.InputError(
4474 _(b'FILE arguments are not compatible with --line-range option')
4474 _(b'FILE arguments are not compatible with --line-range option')
4475 )
4475 )
4476
4476
4477 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4477 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4478 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4478 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4479 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4479 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4480 if linerange:
4480 if linerange:
4481 # TODO: should follow file history from logcmdutil._initialrevs(),
4481 # TODO: should follow file history from logcmdutil._initialrevs(),
4482 # then filter the result by logcmdutil._makerevset() and --limit
4482 # then filter the result by logcmdutil._makerevset() and --limit
4483 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4483 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4484
4484
4485 getcopies = None
4485 getcopies = None
4486 if opts.get(b'copies'):
4486 if opts.get(b'copies'):
4487 endrev = None
4487 endrev = None
4488 if revs:
4488 if revs:
4489 endrev = revs.max() + 1
4489 endrev = revs.max() + 1
4490 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4490 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4491
4491
4492 ui.pager(b'log')
4492 ui.pager(b'log')
4493 displayer = logcmdutil.changesetdisplayer(
4493 displayer = logcmdutil.changesetdisplayer(
4494 ui, repo, opts, differ, buffered=True
4494 ui, repo, opts, differ, buffered=True
4495 )
4495 )
4496 if opts.get(b'graph'):
4496 if opts.get(b'graph'):
4497 displayfn = logcmdutil.displaygraphrevs
4497 displayfn = logcmdutil.displaygraphrevs
4498 else:
4498 else:
4499 displayfn = logcmdutil.displayrevs
4499 displayfn = logcmdutil.displayrevs
4500 displayfn(ui, repo, revs, displayer, getcopies)
4500 displayfn(ui, repo, revs, displayer, getcopies)
4501
4501
4502
4502
4503 @command(
4503 @command(
4504 b'manifest',
4504 b'manifest',
4505 [
4505 [
4506 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4506 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4507 (b'', b'all', False, _(b"list files from all revisions")),
4507 (b'', b'all', False, _(b"list files from all revisions")),
4508 ]
4508 ]
4509 + formatteropts,
4509 + formatteropts,
4510 _(b'[-r REV]'),
4510 _(b'[-r REV]'),
4511 helpcategory=command.CATEGORY_MAINTENANCE,
4511 helpcategory=command.CATEGORY_MAINTENANCE,
4512 intents={INTENT_READONLY},
4512 intents={INTENT_READONLY},
4513 )
4513 )
4514 def manifest(ui, repo, node=None, rev=None, **opts):
4514 def manifest(ui, repo, node=None, rev=None, **opts):
4515 """output the current or given revision of the project manifest
4515 """output the current or given revision of the project manifest
4516
4516
4517 Print a list of version controlled files for the given revision.
4517 Print a list of version controlled files for the given revision.
4518 If no revision is given, the first parent of the working directory
4518 If no revision is given, the first parent of the working directory
4519 is used, or the null revision if no revision is checked out.
4519 is used, or the null revision if no revision is checked out.
4520
4520
4521 With -v, print file permissions, symlink and executable bits.
4521 With -v, print file permissions, symlink and executable bits.
4522 With --debug, print file revision hashes.
4522 With --debug, print file revision hashes.
4523
4523
4524 If option --all is specified, the list of all files from all revisions
4524 If option --all is specified, the list of all files from all revisions
4525 is printed. This includes deleted and renamed files.
4525 is printed. This includes deleted and renamed files.
4526
4526
4527 Returns 0 on success.
4527 Returns 0 on success.
4528 """
4528 """
4529 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4529 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4530
4530
4531 if opts.get('all'):
4531 if opts.get('all'):
4532 if rev or node:
4532 if rev or node:
4533 raise error.InputError(_(b"can't specify a revision with --all"))
4533 raise error.InputError(_(b"can't specify a revision with --all"))
4534
4534
4535 res = set()
4535 res = set()
4536 for rev in repo:
4536 for rev in repo:
4537 ctx = repo[rev]
4537 ctx = repo[rev]
4538 res |= set(ctx.files())
4538 res |= set(ctx.files())
4539
4539
4540 ui.pager(b'manifest')
4540 ui.pager(b'manifest')
4541 for f in sorted(res):
4541 for f in sorted(res):
4542 fm.startitem()
4542 fm.startitem()
4543 fm.write(b"path", b'%s\n', f)
4543 fm.write(b"path", b'%s\n', f)
4544 fm.end()
4544 fm.end()
4545 return
4545 return
4546
4546
4547 if rev and node:
4547 if rev and node:
4548 raise error.InputError(_(b"please specify just one revision"))
4548 raise error.InputError(_(b"please specify just one revision"))
4549
4549
4550 if not node:
4550 if not node:
4551 node = rev
4551 node = rev
4552
4552
4553 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4553 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4554 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4554 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4555 if node:
4555 if node:
4556 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4556 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4557 ctx = logcmdutil.revsingle(repo, node)
4557 ctx = logcmdutil.revsingle(repo, node)
4558 mf = ctx.manifest()
4558 mf = ctx.manifest()
4559 ui.pager(b'manifest')
4559 ui.pager(b'manifest')
4560 for f in ctx:
4560 for f in ctx:
4561 fm.startitem()
4561 fm.startitem()
4562 fm.context(ctx=ctx)
4562 fm.context(ctx=ctx)
4563 fl = ctx[f].flags()
4563 fl = ctx[f].flags()
4564 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4564 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4565 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4565 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4566 fm.write(b'path', b'%s\n', f)
4566 fm.write(b'path', b'%s\n', f)
4567 fm.end()
4567 fm.end()
4568
4568
4569
4569
4570 @command(
4570 @command(
4571 b'merge',
4571 b'merge',
4572 [
4572 [
4573 (
4573 (
4574 b'f',
4574 b'f',
4575 b'force',
4575 b'force',
4576 None,
4576 None,
4577 _(b'force a merge including outstanding changes (DEPRECATED)'),
4577 _(b'force a merge including outstanding changes (DEPRECATED)'),
4578 ),
4578 ),
4579 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4579 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4580 (
4580 (
4581 b'P',
4581 b'P',
4582 b'preview',
4582 b'preview',
4583 None,
4583 None,
4584 _(b'review revisions to merge (no merge is performed)'),
4584 _(b'review revisions to merge (no merge is performed)'),
4585 ),
4585 ),
4586 (b'', b'abort', None, _(b'abort the ongoing merge')),
4586 (b'', b'abort', None, _(b'abort the ongoing merge')),
4587 ]
4587 ]
4588 + mergetoolopts,
4588 + mergetoolopts,
4589 _(b'[-P] [[-r] REV]'),
4589 _(b'[-P] [[-r] REV]'),
4590 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4590 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4591 helpbasic=True,
4591 helpbasic=True,
4592 )
4592 )
4593 def merge(ui, repo, node=None, **opts):
4593 def merge(ui, repo, node=None, **opts):
4594 """merge another revision into working directory
4594 """merge another revision into working directory
4595
4595
4596 The current working directory is updated with all changes made in
4596 The current working directory is updated with all changes made in
4597 the requested revision since the last common predecessor revision.
4597 the requested revision since the last common predecessor revision.
4598
4598
4599 Files that changed between either parent are marked as changed for
4599 Files that changed between either parent are marked as changed for
4600 the next commit and a commit must be performed before any further
4600 the next commit and a commit must be performed before any further
4601 updates to the repository are allowed. The next commit will have
4601 updates to the repository are allowed. The next commit will have
4602 two parents.
4602 two parents.
4603
4603
4604 ``--tool`` can be used to specify the merge tool used for file
4604 ``--tool`` can be used to specify the merge tool used for file
4605 merges. It overrides the HGMERGE environment variable and your
4605 merges. It overrides the HGMERGE environment variable and your
4606 configuration files. See :hg:`help merge-tools` for options.
4606 configuration files. See :hg:`help merge-tools` for options.
4607
4607
4608 If no revision is specified, the working directory's parent is a
4608 If no revision is specified, the working directory's parent is a
4609 head revision, and the current branch contains exactly one other
4609 head revision, and the current branch contains exactly one other
4610 head, the other head is merged with by default. Otherwise, an
4610 head, the other head is merged with by default. Otherwise, an
4611 explicit revision with which to merge must be provided.
4611 explicit revision with which to merge must be provided.
4612
4612
4613 See :hg:`help resolve` for information on handling file conflicts.
4613 See :hg:`help resolve` for information on handling file conflicts.
4614
4614
4615 To undo an uncommitted merge, use :hg:`merge --abort` which
4615 To undo an uncommitted merge, use :hg:`merge --abort` which
4616 will check out a clean copy of the original merge parent, losing
4616 will check out a clean copy of the original merge parent, losing
4617 all changes.
4617 all changes.
4618
4618
4619 Returns 0 on success, 1 if there are unresolved files.
4619 Returns 0 on success, 1 if there are unresolved files.
4620 """
4620 """
4621
4621
4622 abort = opts.get('abort')
4622 abort = opts.get('abort')
4623 if abort and repo.dirstate.p2() == repo.nullid:
4623 if abort and repo.dirstate.p2() == repo.nullid:
4624 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4624 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4625 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4625 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4626 if abort:
4626 if abort:
4627 state = cmdutil.getunfinishedstate(repo)
4627 state = cmdutil.getunfinishedstate(repo)
4628 if state and state._opname != b'merge':
4628 if state and state._opname != b'merge':
4629 raise error.StateError(
4629 raise error.StateError(
4630 _(b'cannot abort merge with %s in progress') % (state._opname),
4630 _(b'cannot abort merge with %s in progress') % (state._opname),
4631 hint=state.hint(),
4631 hint=state.hint(),
4632 )
4632 )
4633 if node:
4633 if node:
4634 raise error.InputError(_(b"cannot specify a node with --abort"))
4634 raise error.InputError(_(b"cannot specify a node with --abort"))
4635 return hg.abortmerge(repo.ui, repo)
4635 return hg.abortmerge(repo.ui, repo)
4636
4636
4637 if opts.get('rev') and node:
4637 if opts.get('rev') and node:
4638 raise error.InputError(_(b"please specify just one revision"))
4638 raise error.InputError(_(b"please specify just one revision"))
4639 if not node:
4639 if not node:
4640 node = opts.get('rev')
4640 node = opts.get('rev')
4641
4641
4642 if node:
4642 if node:
4643 ctx = logcmdutil.revsingle(repo, node)
4643 ctx = logcmdutil.revsingle(repo, node)
4644 else:
4644 else:
4645 if ui.configbool(b'commands', b'merge.require-rev'):
4645 if ui.configbool(b'commands', b'merge.require-rev'):
4646 raise error.InputError(
4646 raise error.InputError(
4647 _(
4647 _(
4648 b'configuration requires specifying revision to merge '
4648 b'configuration requires specifying revision to merge '
4649 b'with'
4649 b'with'
4650 )
4650 )
4651 )
4651 )
4652 ctx = repo[destutil.destmerge(repo)]
4652 ctx = repo[destutil.destmerge(repo)]
4653
4653
4654 if ctx.node() is None:
4654 if ctx.node() is None:
4655 raise error.InputError(
4655 raise error.InputError(
4656 _(b'merging with the working copy has no effect')
4656 _(b'merging with the working copy has no effect')
4657 )
4657 )
4658
4658
4659 if opts.get('preview'):
4659 if opts.get('preview'):
4660 # find nodes that are ancestors of p2 but not of p1
4660 # find nodes that are ancestors of p2 but not of p1
4661 p1 = repo[b'.'].node()
4661 p1 = repo[b'.'].node()
4662 p2 = ctx.node()
4662 p2 = ctx.node()
4663 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4663 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4664
4664
4665 displayer = logcmdutil.changesetdisplayer(
4665 displayer = logcmdutil.changesetdisplayer(
4666 ui, repo, pycompat.byteskwargs(opts)
4666 ui, repo, pycompat.byteskwargs(opts)
4667 )
4667 )
4668 for node in nodes:
4668 for node in nodes:
4669 displayer.show(repo[node])
4669 displayer.show(repo[node])
4670 displayer.close()
4670 displayer.close()
4671 return 0
4671 return 0
4672
4672
4673 # ui.forcemerge is an internal variable, do not document
4673 # ui.forcemerge is an internal variable, do not document
4674 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4674 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4675 with ui.configoverride(overrides, b'merge'):
4675 with ui.configoverride(overrides, b'merge'):
4676 force = opts.get('force')
4676 force = opts.get('force')
4677 labels = [b'working copy', b'merge rev', b'common ancestor']
4677 labels = [b'working copy', b'merge rev', b'common ancestor']
4678 return hg.merge(ctx, force=force, labels=labels)
4678 return hg.merge(ctx, force=force, labels=labels)
4679
4679
4680
4680
4681 statemod.addunfinished(
4681 statemod.addunfinished(
4682 b'merge',
4682 b'merge',
4683 fname=None,
4683 fname=None,
4684 clearable=True,
4684 clearable=True,
4685 allowcommit=True,
4685 allowcommit=True,
4686 cmdmsg=_(b'outstanding uncommitted merge'),
4686 cmdmsg=_(b'outstanding uncommitted merge'),
4687 abortfunc=hg.abortmerge,
4687 abortfunc=hg.abortmerge,
4688 statushint=_(
4688 statushint=_(
4689 b'To continue: hg commit\nTo abort: hg merge --abort'
4689 b'To continue: hg commit\nTo abort: hg merge --abort'
4690 ),
4690 ),
4691 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4691 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4692 )
4692 )
4693
4693
4694
4694
4695 @command(
4695 @command(
4696 b'outgoing|out',
4696 b'outgoing|out',
4697 [
4697 [
4698 (
4698 (
4699 b'f',
4699 b'f',
4700 b'force',
4700 b'force',
4701 None,
4701 None,
4702 _(b'run even when the destination is unrelated'),
4702 _(b'run even when the destination is unrelated'),
4703 ),
4703 ),
4704 (
4704 (
4705 b'r',
4705 b'r',
4706 b'rev',
4706 b'rev',
4707 [],
4707 [],
4708 _(b'a changeset intended to be included in the destination'),
4708 _(b'a changeset intended to be included in the destination'),
4709 _(b'REV'),
4709 _(b'REV'),
4710 ),
4710 ),
4711 (b'n', b'newest-first', None, _(b'show newest record first')),
4711 (b'n', b'newest-first', None, _(b'show newest record first')),
4712 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4712 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4713 (
4713 (
4714 b'b',
4714 b'b',
4715 b'branch',
4715 b'branch',
4716 [],
4716 [],
4717 _(b'a specific branch you would like to push'),
4717 _(b'a specific branch you would like to push'),
4718 _(b'BRANCH'),
4718 _(b'BRANCH'),
4719 ),
4719 ),
4720 ]
4720 ]
4721 + logopts
4721 + logopts
4722 + remoteopts
4722 + remoteopts
4723 + subrepoopts,
4723 + subrepoopts,
4724 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4724 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4725 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4725 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4726 )
4726 )
4727 def outgoing(ui, repo, *dests, **opts):
4727 def outgoing(ui, repo, *dests, **opts):
4728 """show changesets not found in the destination
4728 """show changesets not found in the destination
4729
4729
4730 Show changesets not found in the specified destination repository
4730 Show changesets not found in the specified destination repository
4731 or the default push location. These are the changesets that would
4731 or the default push location. These are the changesets that would
4732 be pushed if a push was requested.
4732 be pushed if a push was requested.
4733
4733
4734 See pull for details of valid destination formats.
4734 See pull for details of valid destination formats.
4735
4735
4736 .. container:: verbose
4736 .. container:: verbose
4737
4737
4738 With -B/--bookmarks, the result of bookmark comparison between
4738 With -B/--bookmarks, the result of bookmark comparison between
4739 local and remote repositories is displayed. With -v/--verbose,
4739 local and remote repositories is displayed. With -v/--verbose,
4740 status is also displayed for each bookmark like below::
4740 status is also displayed for each bookmark like below::
4741
4741
4742 BM1 01234567890a added
4742 BM1 01234567890a added
4743 BM2 deleted
4743 BM2 deleted
4744 BM3 234567890abc advanced
4744 BM3 234567890abc advanced
4745 BM4 34567890abcd diverged
4745 BM4 34567890abcd diverged
4746 BM5 4567890abcde changed
4746 BM5 4567890abcde changed
4747
4747
4748 The action taken when pushing depends on the
4748 The action taken when pushing depends on the
4749 status of each bookmark:
4749 status of each bookmark:
4750
4750
4751 :``added``: push with ``-B`` will create it
4751 :``added``: push with ``-B`` will create it
4752 :``deleted``: push with ``-B`` will delete it
4752 :``deleted``: push with ``-B`` will delete it
4753 :``advanced``: push will update it
4753 :``advanced``: push will update it
4754 :``diverged``: push with ``-B`` will update it
4754 :``diverged``: push with ``-B`` will update it
4755 :``changed``: push with ``-B`` will update it
4755 :``changed``: push with ``-B`` will update it
4756
4756
4757 From the point of view of pushing behavior, bookmarks
4757 From the point of view of pushing behavior, bookmarks
4758 existing only in the remote repository are treated as
4758 existing only in the remote repository are treated as
4759 ``deleted``, even if it is in fact added remotely.
4759 ``deleted``, even if it is in fact added remotely.
4760
4760
4761 Returns 0 if there are outgoing changes, 1 otherwise.
4761 Returns 0 if there are outgoing changes, 1 otherwise.
4762 """
4762 """
4763 opts = pycompat.byteskwargs(opts)
4763 opts = pycompat.byteskwargs(opts)
4764 if opts.get(b'bookmarks'):
4764 if opts.get(b'bookmarks'):
4765 for path in urlutil.get_push_paths(repo, ui, dests):
4765 for path in urlutil.get_push_paths(repo, ui, dests):
4766 other = hg.peer(repo, opts, path)
4766 other = hg.peer(repo, opts, path)
4767 try:
4767 try:
4768 if b'bookmarks' not in other.listkeys(b'namespaces'):
4768 if b'bookmarks' not in other.listkeys(b'namespaces'):
4769 ui.warn(_(b"remote doesn't support bookmarks\n"))
4769 ui.warn(_(b"remote doesn't support bookmarks\n"))
4770 return 0
4770 return 0
4771 ui.status(
4771 ui.status(
4772 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4772 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4773 )
4773 )
4774 ui.pager(b'outgoing')
4774 ui.pager(b'outgoing')
4775 return bookmarks.outgoing(ui, repo, other)
4775 return bookmarks.outgoing(ui, repo, other)
4776 finally:
4776 finally:
4777 other.close()
4777 other.close()
4778
4778
4779 return hg.outgoing(ui, repo, dests, opts)
4779 return hg.outgoing(ui, repo, dests, opts)
4780
4780
4781
4781
4782 @command(
4782 @command(
4783 b'parents',
4783 b'parents',
4784 [
4784 [
4785 (
4785 (
4786 b'r',
4786 b'r',
4787 b'rev',
4787 b'rev',
4788 b'',
4788 b'',
4789 _(b'show parents of the specified revision'),
4789 _(b'show parents of the specified revision'),
4790 _(b'REV'),
4790 _(b'REV'),
4791 ),
4791 ),
4792 ]
4792 ]
4793 + templateopts,
4793 + templateopts,
4794 _(b'[-r REV] [FILE]'),
4794 _(b'[-r REV] [FILE]'),
4795 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4795 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4796 inferrepo=True,
4796 inferrepo=True,
4797 )
4797 )
4798 def parents(ui, repo, file_=None, **opts):
4798 def parents(ui, repo, file_=None, **opts):
4799 """show the parents of the working directory or revision (DEPRECATED)
4799 """show the parents of the working directory or revision (DEPRECATED)
4800
4800
4801 Print the working directory's parent revisions. If a revision is
4801 Print the working directory's parent revisions. If a revision is
4802 given via -r/--rev, the parent of that revision will be printed.
4802 given via -r/--rev, the parent of that revision will be printed.
4803 If a file argument is given, the revision in which the file was
4803 If a file argument is given, the revision in which the file was
4804 last changed (before the working directory revision or the
4804 last changed (before the working directory revision or the
4805 argument to --rev if given) is printed.
4805 argument to --rev if given) is printed.
4806
4806
4807 This command is equivalent to::
4807 This command is equivalent to::
4808
4808
4809 hg log -r "p1()+p2()" or
4809 hg log -r "p1()+p2()" or
4810 hg log -r "p1(REV)+p2(REV)" or
4810 hg log -r "p1(REV)+p2(REV)" or
4811 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4811 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4812 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4812 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4813
4813
4814 See :hg:`summary` and :hg:`help revsets` for related information.
4814 See :hg:`summary` and :hg:`help revsets` for related information.
4815
4815
4816 Returns 0 on success.
4816 Returns 0 on success.
4817 """
4817 """
4818
4818
4819 opts = pycompat.byteskwargs(opts)
4819 opts = pycompat.byteskwargs(opts)
4820 rev = opts.get(b'rev')
4820 rev = opts.get(b'rev')
4821 if rev:
4821 if rev:
4822 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4822 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4823 ctx = logcmdutil.revsingle(repo, rev, None)
4823 ctx = logcmdutil.revsingle(repo, rev, None)
4824
4824
4825 if file_:
4825 if file_:
4826 m = scmutil.match(ctx, (file_,), opts)
4826 m = scmutil.match(ctx, (file_,), opts)
4827 if m.anypats() or len(m.files()) != 1:
4827 if m.anypats() or len(m.files()) != 1:
4828 raise error.InputError(_(b'can only specify an explicit filename'))
4828 raise error.InputError(_(b'can only specify an explicit filename'))
4829 file_ = m.files()[0]
4829 file_ = m.files()[0]
4830 filenodes = []
4830 filenodes = []
4831 for cp in ctx.parents():
4831 for cp in ctx.parents():
4832 if not cp:
4832 if not cp:
4833 continue
4833 continue
4834 try:
4834 try:
4835 filenodes.append(cp.filenode(file_))
4835 filenodes.append(cp.filenode(file_))
4836 except error.LookupError:
4836 except error.LookupError:
4837 pass
4837 pass
4838 if not filenodes:
4838 if not filenodes:
4839 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4839 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4840 p = []
4840 p = []
4841 for fn in filenodes:
4841 for fn in filenodes:
4842 fctx = repo.filectx(file_, fileid=fn)
4842 fctx = repo.filectx(file_, fileid=fn)
4843 p.append(fctx.node())
4843 p.append(fctx.node())
4844 else:
4844 else:
4845 p = [cp.node() for cp in ctx.parents()]
4845 p = [cp.node() for cp in ctx.parents()]
4846
4846
4847 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4847 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4848 for n in p:
4848 for n in p:
4849 if n != repo.nullid:
4849 if n != repo.nullid:
4850 displayer.show(repo[n])
4850 displayer.show(repo[n])
4851 displayer.close()
4851 displayer.close()
4852
4852
4853
4853
4854 @command(
4854 @command(
4855 b'paths',
4855 b'paths',
4856 formatteropts,
4856 formatteropts,
4857 _(b'[NAME]'),
4857 _(b'[NAME]'),
4858 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4858 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4859 optionalrepo=True,
4859 optionalrepo=True,
4860 intents={INTENT_READONLY},
4860 intents={INTENT_READONLY},
4861 )
4861 )
4862 def paths(ui, repo, search=None, **opts):
4862 def paths(ui, repo, search=None, **opts):
4863 """show aliases for remote repositories
4863 """show aliases for remote repositories
4864
4864
4865 Show definition of symbolic path name NAME. If no name is given,
4865 Show definition of symbolic path name NAME. If no name is given,
4866 show definition of all available names.
4866 show definition of all available names.
4867
4867
4868 Option -q/--quiet suppresses all output when searching for NAME
4868 Option -q/--quiet suppresses all output when searching for NAME
4869 and shows only the path names when listing all definitions.
4869 and shows only the path names when listing all definitions.
4870
4870
4871 Path names are defined in the [paths] section of your
4871 Path names are defined in the [paths] section of your
4872 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4872 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4873 repository, ``.hg/hgrc`` is used, too.
4873 repository, ``.hg/hgrc`` is used, too.
4874
4874
4875 The path names ``default`` and ``default-push`` have a special
4875 The path names ``default`` and ``default-push`` have a special
4876 meaning. When performing a push or pull operation, they are used
4876 meaning. When performing a push or pull operation, they are used
4877 as fallbacks if no location is specified on the command-line.
4877 as fallbacks if no location is specified on the command-line.
4878 When ``default-push`` is set, it will be used for push and
4878 When ``default-push`` is set, it will be used for push and
4879 ``default`` will be used for pull; otherwise ``default`` is used
4879 ``default`` will be used for pull; otherwise ``default`` is used
4880 as the fallback for both. When cloning a repository, the clone
4880 as the fallback for both. When cloning a repository, the clone
4881 source is written as ``default`` in ``.hg/hgrc``.
4881 source is written as ``default`` in ``.hg/hgrc``.
4882
4882
4883 .. note::
4883 .. note::
4884
4884
4885 ``default`` and ``default-push`` apply to all inbound (e.g.
4885 ``default`` and ``default-push`` apply to all inbound (e.g.
4886 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4886 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4887 and :hg:`bundle`) operations.
4887 and :hg:`bundle`) operations.
4888
4888
4889 See :hg:`help urls` for more information.
4889 See :hg:`help urls` for more information.
4890
4890
4891 .. container:: verbose
4891 .. container:: verbose
4892
4892
4893 Template:
4893 Template:
4894
4894
4895 The following keywords are supported. See also :hg:`help templates`.
4895 The following keywords are supported. See also :hg:`help templates`.
4896
4896
4897 :name: String. Symbolic name of the path alias.
4897 :name: String. Symbolic name of the path alias.
4898 :pushurl: String. URL for push operations.
4898 :pushurl: String. URL for push operations.
4899 :url: String. URL or directory path for the other operations.
4899 :url: String. URL or directory path for the other operations.
4900
4900
4901 Returns 0 on success.
4901 Returns 0 on success.
4902 """
4902 """
4903
4903
4904 pathitems = urlutil.list_paths(ui, search)
4904 pathitems = urlutil.list_paths(ui, search)
4905 ui.pager(b'paths')
4905 ui.pager(b'paths')
4906
4906
4907 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4907 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4908 if fm.isplain():
4908 if fm.isplain():
4909 hidepassword = urlutil.hidepassword
4909 hidepassword = urlutil.hidepassword
4910 else:
4910 else:
4911 hidepassword = bytes
4911 hidepassword = bytes
4912 if ui.quiet:
4912 if ui.quiet:
4913 namefmt = b'%s\n'
4913 namefmt = b'%s\n'
4914 else:
4914 else:
4915 namefmt = b'%s = '
4915 namefmt = b'%s = '
4916 showsubopts = not search and not ui.quiet
4916 showsubopts = not search and not ui.quiet
4917
4917
4918 for name, path in pathitems:
4918 for name, path in pathitems:
4919 fm.startitem()
4919 fm.startitem()
4920 fm.condwrite(not search, b'name', namefmt, name)
4920 fm.condwrite(not search, b'name', namefmt, name)
4921 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4921 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4922 for subopt, value in sorted(path.suboptions.items()):
4922 for subopt, value in sorted(path.suboptions.items()):
4923 assert subopt not in (b'name', b'url')
4923 assert subopt not in (b'name', b'url')
4924 if showsubopts:
4924 if showsubopts:
4925 fm.plain(b'%s:%s = ' % (name, subopt))
4925 fm.plain(b'%s:%s = ' % (name, subopt))
4926 display = urlutil.path_suboptions_display[subopt]
4926 display = urlutil.path_suboptions_display[subopt]
4927 value = display(value)
4927 value = display(value)
4928 fm.condwrite(showsubopts, subopt, b'%s\n', value)
4928 fm.condwrite(showsubopts, subopt, b'%s\n', value)
4929
4929
4930 fm.end()
4930 fm.end()
4931
4931
4932 if search and not pathitems:
4932 if search and not pathitems:
4933 if not ui.quiet:
4933 if not ui.quiet:
4934 ui.warn(_(b"not found!\n"))
4934 ui.warn(_(b"not found!\n"))
4935 return 1
4935 return 1
4936 else:
4936 else:
4937 return 0
4937 return 0
4938
4938
4939
4939
4940 @command(
4940 @command(
4941 b'phase',
4941 b'phase',
4942 [
4942 [
4943 (b'p', b'public', False, _(b'set changeset phase to public')),
4943 (b'p', b'public', False, _(b'set changeset phase to public')),
4944 (b'd', b'draft', False, _(b'set changeset phase to draft')),
4944 (b'd', b'draft', False, _(b'set changeset phase to draft')),
4945 (b's', b'secret', False, _(b'set changeset phase to secret')),
4945 (b's', b'secret', False, _(b'set changeset phase to secret')),
4946 (b'f', b'force', False, _(b'allow to move boundary backward')),
4946 (b'f', b'force', False, _(b'allow to move boundary backward')),
4947 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
4947 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
4948 ],
4948 ],
4949 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
4949 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
4950 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
4950 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
4951 )
4951 )
4952 def phase(ui, repo, *revs, **opts):
4952 def phase(ui, repo, *revs, **opts):
4953 """set or show the current phase name
4953 """set or show the current phase name
4954
4954
4955 With no argument, show the phase name of the current revision(s).
4955 With no argument, show the phase name of the current revision(s).
4956
4956
4957 With one of -p/--public, -d/--draft or -s/--secret, change the
4957 With one of -p/--public, -d/--draft or -s/--secret, change the
4958 phase value of the specified revisions.
4958 phase value of the specified revisions.
4959
4959
4960 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4960 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4961 lower phase to a higher phase. Phases are ordered as follows::
4961 lower phase to a higher phase. Phases are ordered as follows::
4962
4962
4963 public < draft < secret
4963 public < draft < secret
4964
4964
4965 Returns 0 on success, 1 if some phases could not be changed.
4965 Returns 0 on success, 1 if some phases could not be changed.
4966
4966
4967 (For more information about the phases concept, see :hg:`help phases`.)
4967 (For more information about the phases concept, see :hg:`help phases`.)
4968 """
4968 """
4969 opts = pycompat.byteskwargs(opts)
4969 opts = pycompat.byteskwargs(opts)
4970 # search for a unique phase argument
4970 # search for a unique phase argument
4971 targetphase = None
4971 targetphase = None
4972 for idx, name in enumerate(phases.cmdphasenames):
4972 for idx, name in enumerate(phases.cmdphasenames):
4973 if opts[name]:
4973 if opts[name]:
4974 if targetphase is not None:
4974 if targetphase is not None:
4975 raise error.InputError(_(b'only one phase can be specified'))
4975 raise error.InputError(_(b'only one phase can be specified'))
4976 targetphase = idx
4976 targetphase = idx
4977
4977
4978 # look for specified revision
4978 # look for specified revision
4979 revs = list(revs)
4979 revs = list(revs)
4980 revs.extend(opts[b'rev'])
4980 revs.extend(opts[b'rev'])
4981 if revs:
4981 if revs:
4982 revs = logcmdutil.revrange(repo, revs)
4982 revs = logcmdutil.revrange(repo, revs)
4983 else:
4983 else:
4984 # display both parents as the second parent phase can influence
4984 # display both parents as the second parent phase can influence
4985 # the phase of a merge commit
4985 # the phase of a merge commit
4986 revs = [c.rev() for c in repo[None].parents()]
4986 revs = [c.rev() for c in repo[None].parents()]
4987
4987
4988 ret = 0
4988 ret = 0
4989 if targetphase is None:
4989 if targetphase is None:
4990 # display
4990 # display
4991 for r in revs:
4991 for r in revs:
4992 ctx = repo[r]
4992 ctx = repo[r]
4993 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4993 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4994 else:
4994 else:
4995 with repo.lock(), repo.transaction(b"phase") as tr:
4995 with repo.lock(), repo.transaction(b"phase") as tr:
4996 # set phase
4996 # set phase
4997 if not revs:
4997 if not revs:
4998 raise error.InputError(_(b'empty revision set'))
4998 raise error.InputError(_(b'empty revision set'))
4999 nodes = [repo[r].node() for r in revs]
4999 nodes = [repo[r].node() for r in revs]
5000 # moving revision from public to draft may hide them
5000 # moving revision from public to draft may hide them
5001 # We have to check result on an unfiltered repository
5001 # We have to check result on an unfiltered repository
5002 unfi = repo.unfiltered()
5002 unfi = repo.unfiltered()
5003 getphase = unfi._phasecache.phase
5003 getphase = unfi._phasecache.phase
5004 olddata = [getphase(unfi, r) for r in unfi]
5004 olddata = [getphase(unfi, r) for r in unfi]
5005 phases.advanceboundary(repo, tr, targetphase, nodes)
5005 phases.advanceboundary(repo, tr, targetphase, nodes)
5006 if opts[b'force']:
5006 if opts[b'force']:
5007 phases.retractboundary(repo, tr, targetphase, nodes)
5007 phases.retractboundary(repo, tr, targetphase, nodes)
5008 getphase = unfi._phasecache.phase
5008 getphase = unfi._phasecache.phase
5009 newdata = [getphase(unfi, r) for r in unfi]
5009 newdata = [getphase(unfi, r) for r in unfi]
5010 changes = sum(newdata[r] != olddata[r] for r in unfi)
5010 changes = sum(newdata[r] != olddata[r] for r in unfi)
5011 cl = unfi.changelog
5011 cl = unfi.changelog
5012 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5012 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5013 if rejected:
5013 if rejected:
5014 ui.warn(
5014 ui.warn(
5015 _(
5015 _(
5016 b'cannot move %i changesets to a higher '
5016 b'cannot move %i changesets to a higher '
5017 b'phase, use --force\n'
5017 b'phase, use --force\n'
5018 )
5018 )
5019 % len(rejected)
5019 % len(rejected)
5020 )
5020 )
5021 ret = 1
5021 ret = 1
5022 if changes:
5022 if changes:
5023 msg = _(b'phase changed for %i changesets\n') % changes
5023 msg = _(b'phase changed for %i changesets\n') % changes
5024 if ret:
5024 if ret:
5025 ui.status(msg)
5025 ui.status(msg)
5026 else:
5026 else:
5027 ui.note(msg)
5027 ui.note(msg)
5028 else:
5028 else:
5029 ui.warn(_(b'no phases changed\n'))
5029 ui.warn(_(b'no phases changed\n'))
5030 return ret
5030 return ret
5031
5031
5032
5032
5033 @command(
5033 @command(
5034 b'pull',
5034 b'pull',
5035 [
5035 [
5036 (
5036 (
5037 b'u',
5037 b'u',
5038 b'update',
5038 b'update',
5039 None,
5039 None,
5040 _(b'update to new branch head if new descendants were pulled'),
5040 _(b'update to new branch head if new descendants were pulled'),
5041 ),
5041 ),
5042 (
5042 (
5043 b'f',
5043 b'f',
5044 b'force',
5044 b'force',
5045 None,
5045 None,
5046 _(b'run even when remote repository is unrelated'),
5046 _(b'run even when remote repository is unrelated'),
5047 ),
5047 ),
5048 (
5048 (
5049 b'',
5049 b'',
5050 b'confirm',
5050 b'confirm',
5051 None,
5051 None,
5052 _(b'confirm pull before applying changes'),
5052 _(b'confirm pull before applying changes'),
5053 ),
5053 ),
5054 (
5054 (
5055 b'r',
5055 b'r',
5056 b'rev',
5056 b'rev',
5057 [],
5057 [],
5058 _(b'a remote changeset intended to be added'),
5058 _(b'a remote changeset intended to be added'),
5059 _(b'REV'),
5059 _(b'REV'),
5060 ),
5060 ),
5061 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5061 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5062 (
5062 (
5063 b'b',
5063 b'b',
5064 b'branch',
5064 b'branch',
5065 [],
5065 [],
5066 _(b'a specific branch you would like to pull'),
5066 _(b'a specific branch you would like to pull'),
5067 _(b'BRANCH'),
5067 _(b'BRANCH'),
5068 ),
5068 ),
5069 (
5069 (
5070 b'',
5070 b'',
5071 b'remote-hidden',
5071 b'remote-hidden',
5072 False,
5072 False,
5073 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5073 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5074 ),
5074 ),
5075 ]
5075 ]
5076 + remoteopts,
5076 + remoteopts,
5077 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5077 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5078 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5078 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5079 helpbasic=True,
5079 helpbasic=True,
5080 )
5080 )
5081 def pull(ui, repo, *sources, **opts):
5081 def pull(ui, repo, *sources, **opts):
5082 """pull changes from the specified source
5082 """pull changes from the specified source
5083
5083
5084 Pull changes from a remote repository to a local one.
5084 Pull changes from a remote repository to a local one.
5085
5085
5086 This finds all changes from the repository at the specified path
5086 This finds all changes from the repository at the specified path
5087 or URL and adds them to a local repository (the current one unless
5087 or URL and adds them to a local repository (the current one unless
5088 -R is specified). By default, this does not update the copy of the
5088 -R is specified). By default, this does not update the copy of the
5089 project in the working directory.
5089 project in the working directory.
5090
5090
5091 When cloning from servers that support it, Mercurial may fetch
5091 When cloning from servers that support it, Mercurial may fetch
5092 pre-generated data. When this is done, hooks operating on incoming
5092 pre-generated data. When this is done, hooks operating on incoming
5093 changesets and changegroups may fire more than once, once for each
5093 changesets and changegroups may fire more than once, once for each
5094 pre-generated bundle and as well as for any additional remaining
5094 pre-generated bundle and as well as for any additional remaining
5095 data. See :hg:`help -e clonebundles` for more.
5095 data. See :hg:`help -e clonebundles` for more.
5096
5096
5097 Use :hg:`incoming` if you want to see what would have been added
5097 Use :hg:`incoming` if you want to see what would have been added
5098 by a pull at the time you issued this command. If you then decide
5098 by a pull at the time you issued this command. If you then decide
5099 to add those changes to the repository, you should use :hg:`pull
5099 to add those changes to the repository, you should use :hg:`pull
5100 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5100 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5101
5101
5102 If SOURCE is omitted, the 'default' path will be used.
5102 If SOURCE is omitted, the 'default' path will be used.
5103 See :hg:`help urls` for more information.
5103 See :hg:`help urls` for more information.
5104
5104
5105 If multiple sources are specified, they will be pulled sequentially as if
5105 If multiple sources are specified, they will be pulled sequentially as if
5106 the command was run multiple time. If --update is specify and the command
5106 the command was run multiple time. If --update is specify and the command
5107 will stop at the first failed --update.
5107 will stop at the first failed --update.
5108
5108
5109 Specifying bookmark as ``.`` is equivalent to specifying the active
5109 Specifying bookmark as ``.`` is equivalent to specifying the active
5110 bookmark's name.
5110 bookmark's name.
5111
5111
5112 .. container:: verbose
5112 .. container:: verbose
5113
5113
5114 One can use the `--remote-hidden` flag to pull changesets
5114 One can use the `--remote-hidden` flag to pull changesets
5115 hidden on the remote. This flag is "best effort", and will only
5115 hidden on the remote. This flag is "best effort", and will only
5116 work if the server supports the feature and is configured to
5116 work if the server supports the feature and is configured to
5117 allow the user to access hidden changesets. This option is
5117 allow the user to access hidden changesets. This option is
5118 experimental and backwards compatibility is not garanteed.
5118 experimental and backwards compatibility is not garanteed.
5119
5119
5120 Returns 0 on success, 1 if an update had unresolved files.
5120 Returns 0 on success, 1 if an update had unresolved files.
5121 """
5121 """
5122
5122
5123 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5123 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5124 msg = _(b'update destination required by configuration')
5124 msg = _(b'update destination required by configuration')
5125 hint = _(b'use hg pull followed by hg update DEST')
5125 hint = _(b'use hg pull followed by hg update DEST')
5126 raise error.InputError(msg, hint=hint)
5126 raise error.InputError(msg, hint=hint)
5127
5127
5128 update_conflict = None
5128 update_conflict = None
5129
5129
5130 for path in urlutil.get_pull_paths(repo, ui, sources):
5130 for path in urlutil.get_pull_paths(repo, ui, sources):
5131 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5131 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5132 ui.flush()
5132 ui.flush()
5133 other = hg.peer(
5133 other = hg.peer(
5134 repo,
5134 repo,
5135 pycompat.byteskwargs(opts),
5135 pycompat.byteskwargs(opts),
5136 path,
5136 path,
5137 remotehidden=opts['remote_hidden'],
5137 remotehidden=opts['remote_hidden'],
5138 )
5138 )
5139 update_conflict = None
5139 update_conflict = None
5140 try:
5140 try:
5141 branches = (path.branch, opts.get('branch', []))
5141 branches = (path.branch, opts.get('branch', []))
5142 revs, checkout = hg.addbranchrevs(
5142 revs, checkout = hg.addbranchrevs(
5143 repo,
5143 repo,
5144 other,
5144 other,
5145 branches,
5145 branches,
5146 opts.get('rev'),
5146 opts.get('rev'),
5147 remotehidden=opts['remote_hidden'],
5147 remotehidden=opts['remote_hidden'],
5148 )
5148 )
5149
5149
5150 pullopargs = {}
5150 pullopargs = {}
5151
5151
5152 nodes = None
5152 nodes = None
5153 if opts.get('bookmark') or revs:
5153 if opts.get('bookmark') or revs:
5154 # The list of bookmark used here is the same used to actually update
5154 # The list of bookmark used here is the same used to actually update
5155 # the bookmark names, to avoid the race from issue 4689 and we do
5155 # the bookmark names, to avoid the race from issue 4689 and we do
5156 # all lookup and bookmark queries in one go so they see the same
5156 # all lookup and bookmark queries in one go so they see the same
5157 # version of the server state (issue 4700).
5157 # version of the server state (issue 4700).
5158 nodes = []
5158 nodes = []
5159 fnodes = []
5159 fnodes = []
5160 revs = revs or []
5160 revs = revs or []
5161 if revs and not other.capable(b'lookup'):
5161 if revs and not other.capable(b'lookup'):
5162 err = _(
5162 err = _(
5163 b"other repository doesn't support revision lookup, "
5163 b"other repository doesn't support revision lookup, "
5164 b"so a rev cannot be specified."
5164 b"so a rev cannot be specified."
5165 )
5165 )
5166 raise error.Abort(err)
5166 raise error.Abort(err)
5167 with other.commandexecutor() as e:
5167 with other.commandexecutor() as e:
5168 fremotebookmarks = e.callcommand(
5168 fremotebookmarks = e.callcommand(
5169 b'listkeys', {b'namespace': b'bookmarks'}
5169 b'listkeys', {b'namespace': b'bookmarks'}
5170 )
5170 )
5171 for r in revs:
5171 for r in revs:
5172 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5172 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5173 remotebookmarks = fremotebookmarks.result()
5173 remotebookmarks = fremotebookmarks.result()
5174 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5174 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5175 pullopargs[b'remotebookmarks'] = remotebookmarks
5175 pullopargs[b'remotebookmarks'] = remotebookmarks
5176 for b in opts.get('bookmark', []):
5176 for b in opts.get('bookmark', []):
5177 b = repo._bookmarks.expandname(b)
5177 b = repo._bookmarks.expandname(b)
5178 if b not in remotebookmarks:
5178 if b not in remotebookmarks:
5179 raise error.InputError(
5179 raise error.InputError(
5180 _(b'remote bookmark %s not found!') % b
5180 _(b'remote bookmark %s not found!') % b
5181 )
5181 )
5182 nodes.append(remotebookmarks[b])
5182 nodes.append(remotebookmarks[b])
5183 for i, rev in enumerate(revs):
5183 for i, rev in enumerate(revs):
5184 node = fnodes[i].result()
5184 node = fnodes[i].result()
5185 nodes.append(node)
5185 nodes.append(node)
5186 if rev == checkout:
5186 if rev == checkout:
5187 checkout = node
5187 checkout = node
5188
5188
5189 wlock = util.nullcontextmanager()
5189 wlock = util.nullcontextmanager()
5190 if opts.get('update'):
5190 if opts.get('update'):
5191 wlock = repo.wlock()
5191 wlock = repo.wlock()
5192 with wlock:
5192 with wlock:
5193 pullopargs.update(opts.get('opargs', {}))
5193 pullopargs.update(opts.get('opargs', {}))
5194 modheads = exchange.pull(
5194 modheads = exchange.pull(
5195 repo,
5195 repo,
5196 other,
5196 other,
5197 path=path,
5197 path=path,
5198 heads=nodes,
5198 heads=nodes,
5199 force=opts.get('force'),
5199 force=opts.get('force'),
5200 bookmarks=opts.get('bookmark', ()),
5200 bookmarks=opts.get('bookmark', ()),
5201 opargs=pullopargs,
5201 opargs=pullopargs,
5202 confirm=opts.get('confirm'),
5202 confirm=opts.get('confirm'),
5203 ).cgresult
5203 ).cgresult
5204
5204
5205 # brev is a name, which might be a bookmark to be activated at
5205 # brev is a name, which might be a bookmark to be activated at
5206 # the end of the update. In other words, it is an explicit
5206 # the end of the update. In other words, it is an explicit
5207 # destination of the update
5207 # destination of the update
5208 brev = None
5208 brev = None
5209
5209
5210 if checkout:
5210 if checkout:
5211 checkout = repo.unfiltered().changelog.rev(checkout)
5211 checkout = repo.unfiltered().changelog.rev(checkout)
5212
5212
5213 # order below depends on implementation of
5213 # order below depends on implementation of
5214 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5214 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5215 # because 'checkout' is determined without it.
5215 # because 'checkout' is determined without it.
5216 if opts.get('rev'):
5216 if opts.get('rev'):
5217 brev = opts['rev'][0]
5217 brev = opts['rev'][0]
5218 elif opts.get('branch'):
5218 elif opts.get('branch'):
5219 brev = opts['branch'][0]
5219 brev = opts['branch'][0]
5220 else:
5220 else:
5221 brev = path.branch
5221 brev = path.branch
5222
5222
5223 # XXX path: we are losing the `path` object here. Keeping it
5223 # XXX path: we are losing the `path` object here. Keeping it
5224 # would be valuable. For example as a "variant" as we do
5224 # would be valuable. For example as a "variant" as we do
5225 # for pushes.
5225 # for pushes.
5226 repo._subtoppath = path.loc
5226 repo._subtoppath = path.loc
5227 try:
5227 try:
5228 update_conflict = cmdutil.postincoming(
5228 update_conflict = cmdutil.postincoming(
5229 ui, repo, modheads, opts.get('update'), checkout, brev
5229 ui, repo, modheads, opts.get('update'), checkout, brev
5230 )
5230 )
5231 except error.FilteredRepoLookupError as exc:
5231 except error.FilteredRepoLookupError as exc:
5232 msg = _(b'cannot update to target: %s') % exc.args[0]
5232 msg = _(b'cannot update to target: %s') % exc.args[0]
5233 exc.args = (msg,) + exc.args[1:]
5233 exc.args = (msg,) + exc.args[1:]
5234 raise
5234 raise
5235 finally:
5235 finally:
5236 del repo._subtoppath
5236 del repo._subtoppath
5237
5237
5238 finally:
5238 finally:
5239 other.close()
5239 other.close()
5240 # skip the remaining pull source if they are some conflict.
5240 # skip the remaining pull source if they are some conflict.
5241 if update_conflict:
5241 if update_conflict:
5242 break
5242 break
5243 if update_conflict:
5243 if update_conflict:
5244 return 1
5244 return 1
5245 else:
5245 else:
5246 return 0
5246 return 0
5247
5247
5248
5248
5249 @command(
5249 @command(
5250 b'purge|clean',
5250 b'purge|clean',
5251 [
5251 [
5252 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5252 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5253 (b'', b'all', None, _(b'purge ignored files too')),
5253 (b'', b'all', None, _(b'purge ignored files too')),
5254 (b'i', b'ignored', None, _(b'purge only ignored files')),
5254 (b'i', b'ignored', None, _(b'purge only ignored files')),
5255 (b'', b'dirs', None, _(b'purge empty directories')),
5255 (b'', b'dirs', None, _(b'purge empty directories')),
5256 (b'', b'files', None, _(b'purge files')),
5256 (b'', b'files', None, _(b'purge files')),
5257 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5257 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5258 (
5258 (
5259 b'0',
5259 b'0',
5260 b'print0',
5260 b'print0',
5261 None,
5261 None,
5262 _(
5262 _(
5263 b'end filenames with NUL, for use with xargs'
5263 b'end filenames with NUL, for use with xargs'
5264 b' (implies -p/--print)'
5264 b' (implies -p/--print)'
5265 ),
5265 ),
5266 ),
5266 ),
5267 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5267 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5268 ]
5268 ]
5269 + cmdutil.walkopts,
5269 + cmdutil.walkopts,
5270 _(b'hg purge [OPTION]... [DIR]...'),
5270 _(b'hg purge [OPTION]... [DIR]...'),
5271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5272 )
5272 )
5273 def purge(ui, repo, *dirs, **opts):
5273 def purge(ui, repo, *dirs, **opts):
5274 """removes files not tracked by Mercurial
5274 """removes files not tracked by Mercurial
5275
5275
5276 Delete files not known to Mercurial. This is useful to test local
5276 Delete files not known to Mercurial. This is useful to test local
5277 and uncommitted changes in an otherwise-clean source tree.
5277 and uncommitted changes in an otherwise-clean source tree.
5278
5278
5279 This means that purge will delete the following by default:
5279 This means that purge will delete the following by default:
5280
5280
5281 - Unknown files: files marked with "?" by :hg:`status`
5281 - Unknown files: files marked with "?" by :hg:`status`
5282 - Empty directories: in fact Mercurial ignores directories unless
5282 - Empty directories: in fact Mercurial ignores directories unless
5283 they contain files under source control management
5283 they contain files under source control management
5284
5284
5285 But it will leave untouched:
5285 But it will leave untouched:
5286
5286
5287 - Modified and unmodified tracked files
5287 - Modified and unmodified tracked files
5288 - Ignored files (unless -i or --all is specified)
5288 - Ignored files (unless -i or --all is specified)
5289 - New files added to the repository (with :hg:`add`)
5289 - New files added to the repository (with :hg:`add`)
5290
5290
5291 The --files and --dirs options can be used to direct purge to delete
5291 The --files and --dirs options can be used to direct purge to delete
5292 only files, only directories, or both. If neither option is given,
5292 only files, only directories, or both. If neither option is given,
5293 both will be deleted.
5293 both will be deleted.
5294
5294
5295 If directories are given on the command line, only files in these
5295 If directories are given on the command line, only files in these
5296 directories are considered.
5296 directories are considered.
5297
5297
5298 Be careful with purge, as you could irreversibly delete some files
5298 Be careful with purge, as you could irreversibly delete some files
5299 you forgot to add to the repository. If you only want to print the
5299 you forgot to add to the repository. If you only want to print the
5300 list of files that this program would delete, use the --print
5300 list of files that this program would delete, use the --print
5301 option.
5301 option.
5302 """
5302 """
5303 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5303 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5304
5304
5305 act = not opts.get('print')
5305 act = not opts.get('print')
5306 eol = b'\n'
5306 eol = b'\n'
5307 if opts.get('print0'):
5307 if opts.get('print0'):
5308 eol = b'\0'
5308 eol = b'\0'
5309 act = False # --print0 implies --print
5309 act = False # --print0 implies --print
5310 if opts.get('all', False):
5310 if opts.get('all', False):
5311 ignored = True
5311 ignored = True
5312 unknown = True
5312 unknown = True
5313 else:
5313 else:
5314 ignored = opts.get('ignored', False)
5314 ignored = opts.get('ignored', False)
5315 unknown = not ignored
5315 unknown = not ignored
5316
5316
5317 removefiles = opts.get('files')
5317 removefiles = opts.get('files')
5318 removedirs = opts.get('dirs')
5318 removedirs = opts.get('dirs')
5319 confirm = opts.get('confirm')
5319 confirm = opts.get('confirm')
5320 if confirm is None:
5320 if confirm is None:
5321 try:
5321 try:
5322 extensions.find(b'purge')
5322 extensions.find(b'purge')
5323 confirm = False
5323 confirm = False
5324 except KeyError:
5324 except KeyError:
5325 confirm = True
5325 confirm = True
5326
5326
5327 if not removefiles and not removedirs:
5327 if not removefiles and not removedirs:
5328 removefiles = True
5328 removefiles = True
5329 removedirs = True
5329 removedirs = True
5330
5330
5331 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5331 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5332
5332
5333 paths = mergemod.purge(
5333 paths = mergemod.purge(
5334 repo,
5334 repo,
5335 match,
5335 match,
5336 unknown=unknown,
5336 unknown=unknown,
5337 ignored=ignored,
5337 ignored=ignored,
5338 removeemptydirs=removedirs,
5338 removeemptydirs=removedirs,
5339 removefiles=removefiles,
5339 removefiles=removefiles,
5340 abortonerror=opts.get('abort_on_err'),
5340 abortonerror=opts.get('abort_on_err'),
5341 noop=not act,
5341 noop=not act,
5342 confirm=confirm,
5342 confirm=confirm,
5343 )
5343 )
5344
5344
5345 for path in paths:
5345 for path in paths:
5346 if not act:
5346 if not act:
5347 ui.write(b'%s%s' % (path, eol))
5347 ui.write(b'%s%s' % (path, eol))
5348
5348
5349
5349
5350 @command(
5350 @command(
5351 b'push',
5351 b'push',
5352 [
5352 [
5353 (b'f', b'force', None, _(b'force push')),
5353 (b'f', b'force', None, _(b'force push')),
5354 (
5354 (
5355 b'r',
5355 b'r',
5356 b'rev',
5356 b'rev',
5357 [],
5357 [],
5358 _(b'a changeset intended to be included in the destination'),
5358 _(b'a changeset intended to be included in the destination'),
5359 _(b'REV'),
5359 _(b'REV'),
5360 ),
5360 ),
5361 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5361 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5362 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5362 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5363 (
5363 (
5364 b'b',
5364 b'b',
5365 b'branch',
5365 b'branch',
5366 [],
5366 [],
5367 _(b'a specific branch you would like to push'),
5367 _(b'a specific branch you would like to push'),
5368 _(b'BRANCH'),
5368 _(b'BRANCH'),
5369 ),
5369 ),
5370 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5370 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5371 (
5371 (
5372 b'',
5372 b'',
5373 b'pushvars',
5373 b'pushvars',
5374 [],
5374 [],
5375 _(b'variables that can be sent to server (ADVANCED)'),
5375 _(b'variables that can be sent to server (ADVANCED)'),
5376 ),
5376 ),
5377 (
5377 (
5378 b'',
5378 b'',
5379 b'publish',
5379 b'publish',
5380 False,
5380 False,
5381 _(b'push the changeset as public (EXPERIMENTAL)'),
5381 _(b'push the changeset as public (EXPERIMENTAL)'),
5382 ),
5382 ),
5383 ]
5383 ]
5384 + remoteopts,
5384 + remoteopts,
5385 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5385 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5386 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5386 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5387 helpbasic=True,
5387 helpbasic=True,
5388 )
5388 )
5389 def push(ui, repo, *dests, **opts):
5389 def push(ui, repo, *dests, **opts):
5390 """push changes to the specified destination
5390 """push changes to the specified destination
5391
5391
5392 Push changesets from the local repository to the specified
5392 Push changesets from the local repository to the specified
5393 destination.
5393 destination.
5394
5394
5395 This operation is symmetrical to pull: it is identical to a pull
5395 This operation is symmetrical to pull: it is identical to a pull
5396 in the destination repository from the current one.
5396 in the destination repository from the current one.
5397
5397
5398 By default, push will not allow creation of new heads at the
5398 By default, push will not allow creation of new heads at the
5399 destination, since multiple heads would make it unclear which head
5399 destination, since multiple heads would make it unclear which head
5400 to use. In this situation, it is recommended to pull and merge
5400 to use. In this situation, it is recommended to pull and merge
5401 before pushing.
5401 before pushing.
5402
5402
5403 Use --new-branch if you want to allow push to create a new named
5403 Use --new-branch if you want to allow push to create a new named
5404 branch that is not present at the destination. This allows you to
5404 branch that is not present at the destination. This allows you to
5405 only create a new branch without forcing other changes.
5405 only create a new branch without forcing other changes.
5406
5406
5407 .. note::
5407 .. note::
5408
5408
5409 Extra care should be taken with the -f/--force option,
5409 Extra care should be taken with the -f/--force option,
5410 which will push all new heads on all branches, an action which will
5410 which will push all new heads on all branches, an action which will
5411 almost always cause confusion for collaborators.
5411 almost always cause confusion for collaborators.
5412
5412
5413 If -r/--rev is used, the specified revision and all its ancestors
5413 If -r/--rev is used, the specified revision and all its ancestors
5414 will be pushed to the remote repository.
5414 will be pushed to the remote repository.
5415
5415
5416 If -B/--bookmark is used, the specified bookmarked revision, its
5416 If -B/--bookmark is used, the specified bookmarked revision, its
5417 ancestors, and the bookmark will be pushed to the remote
5417 ancestors, and the bookmark will be pushed to the remote
5418 repository. Specifying ``.`` is equivalent to specifying the active
5418 repository. Specifying ``.`` is equivalent to specifying the active
5419 bookmark's name. Use the --all-bookmarks option for pushing all
5419 bookmark's name. Use the --all-bookmarks option for pushing all
5420 current bookmarks.
5420 current bookmarks.
5421
5421
5422 Please see :hg:`help urls` for important details about ``ssh://``
5422 Please see :hg:`help urls` for important details about ``ssh://``
5423 URLs. If DESTINATION is omitted, a default path will be used.
5423 URLs. If DESTINATION is omitted, a default path will be used.
5424
5424
5425 When passed multiple destinations, push will process them one after the
5425 When passed multiple destinations, push will process them one after the
5426 other, but stop should an error occur.
5426 other, but stop should an error occur.
5427
5427
5428 .. container:: verbose
5428 .. container:: verbose
5429
5429
5430 The --pushvars option sends strings to the server that become
5430 The --pushvars option sends strings to the server that become
5431 environment variables prepended with ``HG_USERVAR_``. For example,
5431 environment variables prepended with ``HG_USERVAR_``. For example,
5432 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5432 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5433 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5433 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5434
5434
5435 pushvars can provide for user-overridable hooks as well as set debug
5435 pushvars can provide for user-overridable hooks as well as set debug
5436 levels. One example is having a hook that blocks commits containing
5436 levels. One example is having a hook that blocks commits containing
5437 conflict markers, but enables the user to override the hook if the file
5437 conflict markers, but enables the user to override the hook if the file
5438 is using conflict markers for testing purposes or the file format has
5438 is using conflict markers for testing purposes or the file format has
5439 strings that look like conflict markers.
5439 strings that look like conflict markers.
5440
5440
5441 By default, servers will ignore `--pushvars`. To enable it add the
5441 By default, servers will ignore `--pushvars`. To enable it add the
5442 following to your configuration file::
5442 following to your configuration file::
5443
5443
5444 [push]
5444 [push]
5445 pushvars.server = true
5445 pushvars.server = true
5446
5446
5447 Returns 0 if push was successful, 1 if nothing to push.
5447 Returns 0 if push was successful, 1 if nothing to push.
5448 """
5448 """
5449
5449
5450 opts = pycompat.byteskwargs(opts)
5450 opts = pycompat.byteskwargs(opts)
5451
5451
5452 if opts.get(b'all_bookmarks'):
5452 if opts.get(b'all_bookmarks'):
5453 cmdutil.check_incompatible_arguments(
5453 cmdutil.check_incompatible_arguments(
5454 opts,
5454 opts,
5455 b'all_bookmarks',
5455 b'all_bookmarks',
5456 [b'bookmark', b'rev'],
5456 [b'bookmark', b'rev'],
5457 )
5457 )
5458 opts[b'bookmark'] = list(repo._bookmarks)
5458 opts[b'bookmark'] = list(repo._bookmarks)
5459
5459
5460 if opts.get(b'bookmark'):
5460 if opts.get(b'bookmark'):
5461 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5461 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5462 for b in opts[b'bookmark']:
5462 for b in opts[b'bookmark']:
5463 # translate -B options to -r so changesets get pushed
5463 # translate -B options to -r so changesets get pushed
5464 b = repo._bookmarks.expandname(b)
5464 b = repo._bookmarks.expandname(b)
5465 if b in repo._bookmarks:
5465 if b in repo._bookmarks:
5466 opts.setdefault(b'rev', []).append(b)
5466 opts.setdefault(b'rev', []).append(b)
5467 else:
5467 else:
5468 # if we try to push a deleted bookmark, translate it to null
5468 # if we try to push a deleted bookmark, translate it to null
5469 # this lets simultaneous -r, -b options continue working
5469 # this lets simultaneous -r, -b options continue working
5470 opts.setdefault(b'rev', []).append(b"null")
5470 opts.setdefault(b'rev', []).append(b"null")
5471
5471
5472 some_pushed = False
5472 some_pushed = False
5473 result = 0
5473 result = 0
5474 for path in urlutil.get_push_paths(repo, ui, dests):
5474 for path in urlutil.get_push_paths(repo, ui, dests):
5475 dest = path.loc
5475 dest = path.loc
5476 branches = (path.branch, opts.get(b'branch') or [])
5476 branches = (path.branch, opts.get(b'branch') or [])
5477 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5477 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5478 revs, checkout = hg.addbranchrevs(
5478 revs, checkout = hg.addbranchrevs(
5479 repo, repo, branches, opts.get(b'rev')
5479 repo, repo, branches, opts.get(b'rev')
5480 )
5480 )
5481 other = hg.peer(repo, opts, dest)
5481 other = hg.peer(repo, opts, dest)
5482
5482
5483 try:
5483 try:
5484 if revs:
5484 if revs:
5485 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5485 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5486 if not revs:
5486 if not revs:
5487 raise error.InputError(
5487 raise error.InputError(
5488 _(b"specified revisions evaluate to an empty set"),
5488 _(b"specified revisions evaluate to an empty set"),
5489 hint=_(b"use different revision arguments"),
5489 hint=_(b"use different revision arguments"),
5490 )
5490 )
5491 elif path.pushrev:
5491 elif path.pushrev:
5492 # It doesn't make any sense to specify ancestor revisions. So limit
5492 # It doesn't make any sense to specify ancestor revisions. So limit
5493 # to DAG heads to make discovery simpler.
5493 # to DAG heads to make discovery simpler.
5494 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5494 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5495 revs = scmutil.revrange(repo, [expr])
5495 revs = scmutil.revrange(repo, [expr])
5496 revs = [repo[rev].node() for rev in revs]
5496 revs = [repo[rev].node() for rev in revs]
5497 if not revs:
5497 if not revs:
5498 raise error.InputError(
5498 raise error.InputError(
5499 _(
5499 _(
5500 b'default push revset for path evaluates to an empty set'
5500 b'default push revset for path evaluates to an empty set'
5501 )
5501 )
5502 )
5502 )
5503 elif ui.configbool(b'commands', b'push.require-revs'):
5503 elif ui.configbool(b'commands', b'push.require-revs'):
5504 raise error.InputError(
5504 raise error.InputError(
5505 _(b'no revisions specified to push'),
5505 _(b'no revisions specified to push'),
5506 hint=_(b'did you mean "hg push -r ."?'),
5506 hint=_(b'did you mean "hg push -r ."?'),
5507 )
5507 )
5508
5508
5509 repo._subtoppath = dest
5509 repo._subtoppath = dest
5510 try:
5510 try:
5511 # push subrepos depth-first for coherent ordering
5511 # push subrepos depth-first for coherent ordering
5512 c = repo[b'.']
5512 c = repo[b'.']
5513 subs = c.substate # only repos that are committed
5513 subs = c.substate # only repos that are committed
5514 for s in sorted(subs):
5514 for s in sorted(subs):
5515 sub_result = c.sub(s).push(opts)
5515 sub_result = c.sub(s).push(opts)
5516 if sub_result == 0:
5516 if sub_result == 0:
5517 return 1
5517 return 1
5518 finally:
5518 finally:
5519 del repo._subtoppath
5519 del repo._subtoppath
5520
5520
5521 opargs = dict(
5521 opargs = dict(
5522 opts.get(b'opargs', {})
5522 opts.get(b'opargs', {})
5523 ) # copy opargs since we may mutate it
5523 ) # copy opargs since we may mutate it
5524 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5524 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5525
5525
5526 pushop = exchange.push(
5526 pushop = exchange.push(
5527 repo,
5527 repo,
5528 other,
5528 other,
5529 opts.get(b'force'),
5529 opts.get(b'force'),
5530 revs=revs,
5530 revs=revs,
5531 newbranch=opts.get(b'new_branch'),
5531 newbranch=opts.get(b'new_branch'),
5532 bookmarks=opts.get(b'bookmark', ()),
5532 bookmarks=opts.get(b'bookmark', ()),
5533 publish=opts.get(b'publish'),
5533 publish=opts.get(b'publish'),
5534 opargs=opargs,
5534 opargs=opargs,
5535 )
5535 )
5536
5536
5537 if pushop.cgresult == 0:
5537 if pushop.cgresult == 0:
5538 result = 1
5538 result = 1
5539 elif pushop.cgresult is not None:
5539 elif pushop.cgresult is not None:
5540 some_pushed = True
5540 some_pushed = True
5541
5541
5542 if pushop.bkresult is not None:
5542 if pushop.bkresult is not None:
5543 if pushop.bkresult == 2:
5543 if pushop.bkresult == 2:
5544 result = 2
5544 result = 2
5545 elif not result and pushop.bkresult:
5545 elif not result and pushop.bkresult:
5546 result = 2
5546 result = 2
5547
5547
5548 if result:
5548 if result:
5549 break
5549 break
5550
5550
5551 finally:
5551 finally:
5552 other.close()
5552 other.close()
5553 if result == 0 and not some_pushed:
5553 if result == 0 and not some_pushed:
5554 result = 1
5554 result = 1
5555 return result
5555 return result
5556
5556
5557
5557
5558 @command(
5558 @command(
5559 b'recover',
5559 b'recover',
5560 [
5560 [
5561 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5561 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5562 ],
5562 ],
5563 helpcategory=command.CATEGORY_MAINTENANCE,
5563 helpcategory=command.CATEGORY_MAINTENANCE,
5564 )
5564 )
5565 def recover(ui, repo, **opts):
5565 def recover(ui, repo, **opts):
5566 """roll back an interrupted transaction
5566 """roll back an interrupted transaction
5567
5567
5568 Recover from an interrupted commit or pull.
5568 Recover from an interrupted commit or pull.
5569
5569
5570 This command tries to fix the repository status after an
5570 This command tries to fix the repository status after an
5571 interrupted operation. It should only be necessary when Mercurial
5571 interrupted operation. It should only be necessary when Mercurial
5572 suggests it.
5572 suggests it.
5573
5573
5574 Returns 0 if successful, 1 if nothing to recover or verify fails.
5574 Returns 0 if successful, 1 if nothing to recover or verify fails.
5575 """
5575 """
5576 ret = repo.recover()
5576 ret = repo.recover()
5577 if ret:
5577 if ret:
5578 if opts['verify']:
5578 if opts['verify']:
5579 return hg.verify(repo)
5579 return hg.verify(repo)
5580 else:
5580 else:
5581 msg = _(
5581 msg = _(
5582 b"(verify step skipped, run `hg verify` to check your "
5582 b"(verify step skipped, run `hg verify` to check your "
5583 b"repository content)\n"
5583 b"repository content)\n"
5584 )
5584 )
5585 ui.warn(msg)
5585 ui.warn(msg)
5586 return 0
5586 return 0
5587 return 1
5587 return 1
5588
5588
5589
5589
5590 @command(
5590 @command(
5591 b'remove|rm',
5591 b'remove|rm',
5592 [
5592 [
5593 (b'A', b'after', None, _(b'record delete for missing files')),
5593 (b'A', b'after', None, _(b'record delete for missing files')),
5594 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5594 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5595 ]
5595 ]
5596 + subrepoopts
5596 + subrepoopts
5597 + walkopts
5597 + walkopts
5598 + dryrunopts,
5598 + dryrunopts,
5599 _(b'[OPTION]... FILE...'),
5599 _(b'[OPTION]... FILE...'),
5600 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5600 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5601 helpbasic=True,
5601 helpbasic=True,
5602 inferrepo=True,
5602 inferrepo=True,
5603 )
5603 )
5604 def remove(ui, repo, *pats, **opts):
5604 def remove(ui, repo, *pats, **opts):
5605 """remove the specified files on the next commit
5605 """remove the specified files on the next commit
5606
5606
5607 Schedule the indicated files for removal from the current branch.
5607 Schedule the indicated files for removal from the current branch.
5608
5608
5609 This command schedules the files to be removed at the next commit.
5609 This command schedules the files to be removed at the next commit.
5610 To undo a remove before that, see :hg:`revert`. To undo added
5610 To undo a remove before that, see :hg:`revert`. To undo added
5611 files, see :hg:`forget`.
5611 files, see :hg:`forget`.
5612
5612
5613 .. container:: verbose
5613 .. container:: verbose
5614
5614
5615 -A/--after can be used to remove only files that have already
5615 -A/--after can be used to remove only files that have already
5616 been deleted, -f/--force can be used to force deletion, and -Af
5616 been deleted, -f/--force can be used to force deletion, and -Af
5617 can be used to remove files from the next revision without
5617 can be used to remove files from the next revision without
5618 deleting them from the working directory.
5618 deleting them from the working directory.
5619
5619
5620 The following table details the behavior of remove for different
5620 The following table details the behavior of remove for different
5621 file states (columns) and option combinations (rows). The file
5621 file states (columns) and option combinations (rows). The file
5622 states are Added [A], Clean [C], Modified [M] and Missing [!]
5622 states are Added [A], Clean [C], Modified [M] and Missing [!]
5623 (as reported by :hg:`status`). The actions are Warn, Remove
5623 (as reported by :hg:`status`). The actions are Warn, Remove
5624 (from branch) and Delete (from disk):
5624 (from branch) and Delete (from disk):
5625
5625
5626 ========= == == == ==
5626 ========= == == == ==
5627 opt/state A C M !
5627 opt/state A C M !
5628 ========= == == == ==
5628 ========= == == == ==
5629 none W RD W R
5629 none W RD W R
5630 -f R RD RD R
5630 -f R RD RD R
5631 -A W W W R
5631 -A W W W R
5632 -Af R R R R
5632 -Af R R R R
5633 ========= == == == ==
5633 ========= == == == ==
5634
5634
5635 .. note::
5635 .. note::
5636
5636
5637 :hg:`remove` never deletes files in Added [A] state from the
5637 :hg:`remove` never deletes files in Added [A] state from the
5638 working directory, not even if ``--force`` is specified.
5638 working directory, not even if ``--force`` is specified.
5639
5639
5640 Returns 0 on success, 1 if any warnings encountered.
5640 Returns 0 on success, 1 if any warnings encountered.
5641 """
5641 """
5642
5642
5643 after, force = opts.get('after'), opts.get('force')
5643 after, force = opts.get('after'), opts.get('force')
5644 dryrun = opts.get('dry_run')
5644 dryrun = opts.get('dry_run')
5645 if not pats and not after:
5645 if not pats and not after:
5646 raise error.InputError(_(b'no files specified'))
5646 raise error.InputError(_(b'no files specified'))
5647
5647
5648 with repo.wlock(), repo.dirstate.changing_files(repo):
5648 with repo.wlock(), repo.dirstate.changing_files(repo):
5649 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5649 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5650 subrepos = opts.get('subrepos')
5650 subrepos = opts.get('subrepos')
5651 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5651 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5652 return cmdutil.remove(
5652 return cmdutil.remove(
5653 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5653 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5654 )
5654 )
5655
5655
5656
5656
5657 @command(
5657 @command(
5658 b'rename|move|mv',
5658 b'rename|move|mv',
5659 [
5659 [
5660 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5660 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5661 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5661 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5662 (
5662 (
5663 b'',
5663 b'',
5664 b'at-rev',
5664 b'at-rev',
5665 b'',
5665 b'',
5666 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5666 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5667 _(b'REV'),
5667 _(b'REV'),
5668 ),
5668 ),
5669 (
5669 (
5670 b'f',
5670 b'f',
5671 b'force',
5671 b'force',
5672 None,
5672 None,
5673 _(b'forcibly move over an existing managed file'),
5673 _(b'forcibly move over an existing managed file'),
5674 ),
5674 ),
5675 ]
5675 ]
5676 + walkopts
5676 + walkopts
5677 + dryrunopts,
5677 + dryrunopts,
5678 _(b'[OPTION]... SOURCE... DEST'),
5678 _(b'[OPTION]... SOURCE... DEST'),
5679 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5679 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5680 )
5680 )
5681 def rename(ui, repo, *pats, **opts):
5681 def rename(ui, repo, *pats, **opts):
5682 """rename files; equivalent of copy + remove
5682 """rename files; equivalent of copy + remove
5683
5683
5684 Mark dest as copies of sources; mark sources for deletion. If dest
5684 Mark dest as copies of sources; mark sources for deletion. If dest
5685 is a directory, copies are put in that directory. If dest is a
5685 is a directory, copies are put in that directory. If dest is a
5686 file, there can only be one source.
5686 file, there can only be one source.
5687
5687
5688 By default, this command copies the contents of files as they
5688 By default, this command copies the contents of files as they
5689 exist in the working directory. If invoked with -A/--after, the
5689 exist in the working directory. If invoked with -A/--after, the
5690 operation is recorded, but no copying is performed.
5690 operation is recorded, but no copying is performed.
5691
5691
5692 To undo marking a destination file as renamed, use --forget. With that
5692 To undo marking a destination file as renamed, use --forget. With that
5693 option, all given (positional) arguments are unmarked as renames. The
5693 option, all given (positional) arguments are unmarked as renames. The
5694 destination file(s) will be left in place (still tracked). The source
5694 destination file(s) will be left in place (still tracked). The source
5695 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5695 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5696 the same way as :hg:`copy --forget`.
5696 the same way as :hg:`copy --forget`.
5697
5697
5698 This command takes effect with the next commit by default.
5698 This command takes effect with the next commit by default.
5699
5699
5700 Returns 0 on success, 1 if errors are encountered.
5700 Returns 0 on success, 1 if errors are encountered.
5701 """
5701 """
5702 context = lambda repo: repo.dirstate.changing_files(repo)
5702 context = lambda repo: repo.dirstate.changing_files(repo)
5703 rev = opts.get('at_rev')
5703 rev = opts.get('at_rev')
5704
5704
5705 if rev:
5705 if rev:
5706 ctx = logcmdutil.revsingle(repo, rev)
5706 ctx = logcmdutil.revsingle(repo, rev)
5707 if ctx.rev() is not None:
5707 if ctx.rev() is not None:
5708
5708
5709 def context(repo):
5709 def context(repo):
5710 return util.nullcontextmanager()
5710 return util.nullcontextmanager()
5711
5711
5712 opts['at_rev'] = ctx.rev()
5712 opts['at_rev'] = ctx.rev()
5713 with repo.wlock(), context(repo):
5713 with repo.wlock(), context(repo):
5714 return cmdutil.copy(
5714 return cmdutil.copy(
5715 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5715 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5716 )
5716 )
5717
5717
5718
5718
5719 @command(
5719 @command(
5720 b'resolve',
5720 b'resolve',
5721 [
5721 [
5722 (b'a', b'all', None, _(b'select all unresolved files')),
5722 (b'a', b'all', None, _(b'select all unresolved files')),
5723 (b'l', b'list', None, _(b'list state of files needing merge')),
5723 (b'l', b'list', None, _(b'list state of files needing merge')),
5724 (b'm', b'mark', None, _(b'mark files as resolved')),
5724 (b'm', b'mark', None, _(b'mark files as resolved')),
5725 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5725 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5726 (b'n', b'no-status', None, _(b'hide status prefix')),
5726 (b'n', b'no-status', None, _(b'hide status prefix')),
5727 (b'', b're-merge', None, _(b're-merge files')),
5727 (b'', b're-merge', None, _(b're-merge files')),
5728 ]
5728 ]
5729 + mergetoolopts
5729 + mergetoolopts
5730 + walkopts
5730 + walkopts
5731 + formatteropts,
5731 + formatteropts,
5732 _(b'[OPTION]... [FILE]...'),
5732 _(b'[OPTION]... [FILE]...'),
5733 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5733 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5734 inferrepo=True,
5734 inferrepo=True,
5735 )
5735 )
5736 def resolve(ui, repo, *pats, **opts):
5736 def resolve(ui, repo, *pats, **opts):
5737 """redo merges or set/view the merge status of files
5737 """redo merges or set/view the merge status of files
5738
5738
5739 Merges with unresolved conflicts are often the result of
5739 Merges with unresolved conflicts are often the result of
5740 non-interactive merging using the ``internal:merge`` configuration
5740 non-interactive merging using the ``internal:merge`` configuration
5741 setting, or a command-line merge tool like ``diff3``. The resolve
5741 setting, or a command-line merge tool like ``diff3``. The resolve
5742 command is used to manage the files involved in a merge, after
5742 command is used to manage the files involved in a merge, after
5743 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5743 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5744 working directory must have two parents). See :hg:`help
5744 working directory must have two parents). See :hg:`help
5745 merge-tools` for information on configuring merge tools.
5745 merge-tools` for information on configuring merge tools.
5746
5746
5747 The resolve command can be used in the following ways:
5747 The resolve command can be used in the following ways:
5748
5748
5749 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5749 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5750 the specified files, discarding any previous merge attempts. Re-merging
5750 the specified files, discarding any previous merge attempts. Re-merging
5751 is not performed for files already marked as resolved. Use ``--all/-a``
5751 is not performed for files already marked as resolved. Use ``--all/-a``
5752 to select all unresolved files. ``--tool`` can be used to specify
5752 to select all unresolved files. ``--tool`` can be used to specify
5753 the merge tool used for the given files. It overrides the HGMERGE
5753 the merge tool used for the given files. It overrides the HGMERGE
5754 environment variable and your configuration files. Previous file
5754 environment variable and your configuration files. Previous file
5755 contents are saved with a ``.orig`` suffix.
5755 contents are saved with a ``.orig`` suffix.
5756
5756
5757 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5757 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5758 (e.g. after having manually fixed-up the files). The default is
5758 (e.g. after having manually fixed-up the files). The default is
5759 to mark all unresolved files.
5759 to mark all unresolved files.
5760
5760
5761 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5761 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5762 default is to mark all resolved files.
5762 default is to mark all resolved files.
5763
5763
5764 - :hg:`resolve -l`: list files which had or still have conflicts.
5764 - :hg:`resolve -l`: list files which had or still have conflicts.
5765 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5765 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5766 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5766 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5767 the list. See :hg:`help filesets` for details.
5767 the list. See :hg:`help filesets` for details.
5768
5768
5769 .. note::
5769 .. note::
5770
5770
5771 Mercurial will not let you commit files with unresolved merge
5771 Mercurial will not let you commit files with unresolved merge
5772 conflicts. You must use :hg:`resolve -m ...` before you can
5772 conflicts. You must use :hg:`resolve -m ...` before you can
5773 commit after a conflicting merge.
5773 commit after a conflicting merge.
5774
5774
5775 .. container:: verbose
5775 .. container:: verbose
5776
5776
5777 Template:
5777 Template:
5778
5778
5779 The following keywords are supported in addition to the common template
5779 The following keywords are supported in addition to the common template
5780 keywords and functions. See also :hg:`help templates`.
5780 keywords and functions. See also :hg:`help templates`.
5781
5781
5782 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5782 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5783 :path: String. Repository-absolute path of the file.
5783 :path: String. Repository-absolute path of the file.
5784
5784
5785 Returns 0 on success, 1 if any files fail a resolve attempt.
5785 Returns 0 on success, 1 if any files fail a resolve attempt.
5786 """
5786 """
5787
5787
5788 opts = pycompat.byteskwargs(opts)
5788 opts = pycompat.byteskwargs(opts)
5789 confirm = ui.configbool(b'commands', b'resolve.confirm')
5789 confirm = ui.configbool(b'commands', b'resolve.confirm')
5790 flaglist = b'all mark unmark list no_status re_merge'.split()
5790 flaglist = b'all mark unmark list no_status re_merge'.split()
5791 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5791 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5792
5792
5793 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5793 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5794 if actioncount > 1:
5794 if actioncount > 1:
5795 raise error.InputError(_(b"too many actions specified"))
5795 raise error.InputError(_(b"too many actions specified"))
5796 elif actioncount == 0 and ui.configbool(
5796 elif actioncount == 0 and ui.configbool(
5797 b'commands', b'resolve.explicit-re-merge'
5797 b'commands', b'resolve.explicit-re-merge'
5798 ):
5798 ):
5799 hint = _(b'use --mark, --unmark, --list or --re-merge')
5799 hint = _(b'use --mark, --unmark, --list or --re-merge')
5800 raise error.InputError(_(b'no action specified'), hint=hint)
5800 raise error.InputError(_(b'no action specified'), hint=hint)
5801 if pats and all:
5801 if pats and all:
5802 raise error.InputError(_(b"can't specify --all and patterns"))
5802 raise error.InputError(_(b"can't specify --all and patterns"))
5803 if not (all or pats or show or mark or unmark):
5803 if not (all or pats or show or mark or unmark):
5804 raise error.InputError(
5804 raise error.InputError(
5805 _(b'no files or directories specified'),
5805 _(b'no files or directories specified'),
5806 hint=b'use --all to re-merge all unresolved files',
5806 hint=b'use --all to re-merge all unresolved files',
5807 )
5807 )
5808
5808
5809 if confirm:
5809 if confirm:
5810 if all:
5810 if all:
5811 if ui.promptchoice(
5811 if ui.promptchoice(
5812 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5812 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5813 ):
5813 ):
5814 raise error.CanceledError(_(b'user quit'))
5814 raise error.CanceledError(_(b'user quit'))
5815 if mark and not pats:
5815 if mark and not pats:
5816 if ui.promptchoice(
5816 if ui.promptchoice(
5817 _(
5817 _(
5818 b'mark all unresolved files as resolved (yn)?'
5818 b'mark all unresolved files as resolved (yn)?'
5819 b'$$ &Yes $$ &No'
5819 b'$$ &Yes $$ &No'
5820 )
5820 )
5821 ):
5821 ):
5822 raise error.CanceledError(_(b'user quit'))
5822 raise error.CanceledError(_(b'user quit'))
5823 if unmark and not pats:
5823 if unmark and not pats:
5824 if ui.promptchoice(
5824 if ui.promptchoice(
5825 _(
5825 _(
5826 b'mark all resolved files as unresolved (yn)?'
5826 b'mark all resolved files as unresolved (yn)?'
5827 b'$$ &Yes $$ &No'
5827 b'$$ &Yes $$ &No'
5828 )
5828 )
5829 ):
5829 ):
5830 raise error.CanceledError(_(b'user quit'))
5830 raise error.CanceledError(_(b'user quit'))
5831
5831
5832 uipathfn = scmutil.getuipathfn(repo)
5832 uipathfn = scmutil.getuipathfn(repo)
5833
5833
5834 if show:
5834 if show:
5835 ui.pager(b'resolve')
5835 ui.pager(b'resolve')
5836 fm = ui.formatter(b'resolve', opts)
5836 fm = ui.formatter(b'resolve', opts)
5837 ms = mergestatemod.mergestate.read(repo)
5837 ms = mergestatemod.mergestate.read(repo)
5838 wctx = repo[None]
5838 wctx = repo[None]
5839 m = scmutil.match(wctx, pats, opts)
5839 m = scmutil.match(wctx, pats, opts)
5840
5840
5841 # Labels and keys based on merge state. Unresolved path conflicts show
5841 # Labels and keys based on merge state. Unresolved path conflicts show
5842 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5842 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5843 # resolved conflicts.
5843 # resolved conflicts.
5844 mergestateinfo = {
5844 mergestateinfo = {
5845 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5845 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5846 b'resolve.unresolved',
5846 b'resolve.unresolved',
5847 b'U',
5847 b'U',
5848 ),
5848 ),
5849 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5849 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5850 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5850 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5851 b'resolve.unresolved',
5851 b'resolve.unresolved',
5852 b'P',
5852 b'P',
5853 ),
5853 ),
5854 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5854 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5855 b'resolve.resolved',
5855 b'resolve.resolved',
5856 b'R',
5856 b'R',
5857 ),
5857 ),
5858 }
5858 }
5859
5859
5860 for f in ms:
5860 for f in ms:
5861 if not m(f):
5861 if not m(f):
5862 continue
5862 continue
5863
5863
5864 label, key = mergestateinfo[ms[f]]
5864 label, key = mergestateinfo[ms[f]]
5865 fm.startitem()
5865 fm.startitem()
5866 fm.context(ctx=wctx)
5866 fm.context(ctx=wctx)
5867 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5867 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5868 fm.data(path=f)
5868 fm.data(path=f)
5869 fm.plain(b'%s\n' % uipathfn(f), label=label)
5869 fm.plain(b'%s\n' % uipathfn(f), label=label)
5870 fm.end()
5870 fm.end()
5871 return 0
5871 return 0
5872
5872
5873 with repo.wlock():
5873 with repo.wlock():
5874 ms = mergestatemod.mergestate.read(repo)
5874 ms = mergestatemod.mergestate.read(repo)
5875
5875
5876 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5876 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5877 raise error.StateError(
5877 raise error.StateError(
5878 _(b'resolve command not applicable when not merging')
5878 _(b'resolve command not applicable when not merging')
5879 )
5879 )
5880
5880
5881 wctx = repo[None]
5881 wctx = repo[None]
5882 m = scmutil.match(wctx, pats, opts)
5882 m = scmutil.match(wctx, pats, opts)
5883 ret = 0
5883 ret = 0
5884 didwork = False
5884 didwork = False
5885
5885
5886 hasconflictmarkers = []
5886 hasconflictmarkers = []
5887 if mark:
5887 if mark:
5888 markcheck = ui.config(b'commands', b'resolve.mark-check')
5888 markcheck = ui.config(b'commands', b'resolve.mark-check')
5889 if markcheck not in [b'warn', b'abort']:
5889 if markcheck not in [b'warn', b'abort']:
5890 # Treat all invalid / unrecognized values as 'none'.
5890 # Treat all invalid / unrecognized values as 'none'.
5891 markcheck = False
5891 markcheck = False
5892 for f in ms:
5892 for f in ms:
5893 if not m(f):
5893 if not m(f):
5894 continue
5894 continue
5895
5895
5896 didwork = True
5896 didwork = True
5897
5897
5898 # path conflicts must be resolved manually
5898 # path conflicts must be resolved manually
5899 if ms[f] in (
5899 if ms[f] in (
5900 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5900 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5901 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5901 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5902 ):
5902 ):
5903 if mark:
5903 if mark:
5904 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5904 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5905 elif unmark:
5905 elif unmark:
5906 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5906 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5907 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5907 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5908 ui.warn(
5908 ui.warn(
5909 _(b'%s: path conflict must be resolved manually\n')
5909 _(b'%s: path conflict must be resolved manually\n')
5910 % uipathfn(f)
5910 % uipathfn(f)
5911 )
5911 )
5912 continue
5912 continue
5913
5913
5914 if mark:
5914 if mark:
5915 if markcheck:
5915 if markcheck:
5916 fdata = repo.wvfs.tryread(f)
5916 fdata = repo.wvfs.tryread(f)
5917 if (
5917 if (
5918 filemerge.hasconflictmarkers(fdata)
5918 filemerge.hasconflictmarkers(fdata)
5919 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5919 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5920 ):
5920 ):
5921 hasconflictmarkers.append(f)
5921 hasconflictmarkers.append(f)
5922 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5922 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5923 elif unmark:
5923 elif unmark:
5924 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5924 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5925 else:
5925 else:
5926 # backup pre-resolve (merge uses .orig for its own purposes)
5926 # backup pre-resolve (merge uses .orig for its own purposes)
5927 a = repo.wjoin(f)
5927 a = repo.wjoin(f)
5928 try:
5928 try:
5929 util.copyfile(a, a + b".resolve")
5929 util.copyfile(a, a + b".resolve")
5930 except FileNotFoundError:
5930 except FileNotFoundError:
5931 pass
5931 pass
5932
5932
5933 try:
5933 try:
5934 # preresolve file
5934 # preresolve file
5935 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5935 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5936 with ui.configoverride(overrides, b'resolve'):
5936 with ui.configoverride(overrides, b'resolve'):
5937 r = ms.resolve(f, wctx)
5937 r = ms.resolve(f, wctx)
5938 if r:
5938 if r:
5939 ret = 1
5939 ret = 1
5940 finally:
5940 finally:
5941 ms.commit()
5941 ms.commit()
5942
5942
5943 # replace filemerge's .orig file with our resolve file
5943 # replace filemerge's .orig file with our resolve file
5944 try:
5944 try:
5945 util.rename(
5945 util.rename(
5946 a + b".resolve", scmutil.backuppath(ui, repo, f)
5946 a + b".resolve", scmutil.backuppath(ui, repo, f)
5947 )
5947 )
5948 except FileNotFoundError:
5948 except FileNotFoundError:
5949 pass
5949 pass
5950
5950
5951 if hasconflictmarkers:
5951 if hasconflictmarkers:
5952 ui.warn(
5952 ui.warn(
5953 _(
5953 _(
5954 b'warning: the following files still have conflict '
5954 b'warning: the following files still have conflict '
5955 b'markers:\n'
5955 b'markers:\n'
5956 )
5956 )
5957 + b''.join(
5957 + b''.join(
5958 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5958 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5959 )
5959 )
5960 )
5960 )
5961 if markcheck == b'abort' and not all and not pats:
5961 if markcheck == b'abort' and not all and not pats:
5962 raise error.StateError(
5962 raise error.StateError(
5963 _(b'conflict markers detected'),
5963 _(b'conflict markers detected'),
5964 hint=_(b'use --all to mark anyway'),
5964 hint=_(b'use --all to mark anyway'),
5965 )
5965 )
5966
5966
5967 ms.commit()
5967 ms.commit()
5968 branchmerge = repo.dirstate.p2() != repo.nullid
5968 branchmerge = repo.dirstate.p2() != repo.nullid
5969 # resolve is not doing a parent change here, however, `record updates`
5969 # resolve is not doing a parent change here, however, `record updates`
5970 # will call some dirstate API that at intended for parent changes call.
5970 # will call some dirstate API that at intended for parent changes call.
5971 # Ideally we would not need this and could implement a lighter version
5971 # Ideally we would not need this and could implement a lighter version
5972 # of the recordupdateslogic that will not have to deal with the part
5972 # of the recordupdateslogic that will not have to deal with the part
5973 # related to parent changes. However this would requires that:
5973 # related to parent changes. However this would requires that:
5974 # - we are sure we passed around enough information at update/merge
5974 # - we are sure we passed around enough information at update/merge
5975 # time to no longer needs it at `hg resolve time`
5975 # time to no longer needs it at `hg resolve time`
5976 # - we are sure we store that information well enough to be able to reuse it
5976 # - we are sure we store that information well enough to be able to reuse it
5977 # - we are the necessary logic to reuse it right.
5977 # - we are the necessary logic to reuse it right.
5978 #
5978 #
5979 # All this should eventually happens, but in the mean time, we use this
5979 # All this should eventually happens, but in the mean time, we use this
5980 # context manager slightly out of the context it should be.
5980 # context manager slightly out of the context it should be.
5981 with repo.dirstate.changing_parents(repo):
5981 with repo.dirstate.changing_parents(repo):
5982 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5982 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5983
5983
5984 if not didwork and pats:
5984 if not didwork and pats:
5985 hint = None
5985 hint = None
5986 if not any([p for p in pats if p.find(b':') >= 0]):
5986 if not any([p for p in pats if p.find(b':') >= 0]):
5987 pats = [b'path:%s' % p for p in pats]
5987 pats = [b'path:%s' % p for p in pats]
5988 m = scmutil.match(wctx, pats, opts)
5988 m = scmutil.match(wctx, pats, opts)
5989 for f in ms:
5989 for f in ms:
5990 if not m(f):
5990 if not m(f):
5991 continue
5991 continue
5992
5992
5993 def flag(o):
5993 def flag(o):
5994 if o == b're_merge':
5994 if o == b're_merge':
5995 return b'--re-merge '
5995 return b'--re-merge '
5996 return b'-%s ' % o[0:1]
5996 return b'-%s ' % o[0:1]
5997
5997
5998 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5998 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5999 hint = _(b"(try: hg resolve %s%s)\n") % (
5999 hint = _(b"(try: hg resolve %s%s)\n") % (
6000 flags,
6000 flags,
6001 b' '.join(pats),
6001 b' '.join(pats),
6002 )
6002 )
6003 break
6003 break
6004 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6004 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6005 if hint:
6005 if hint:
6006 ui.warn(hint)
6006 ui.warn(hint)
6007
6007
6008 unresolvedf = ms.unresolvedcount()
6008 unresolvedf = ms.unresolvedcount()
6009 if not unresolvedf:
6009 if not unresolvedf:
6010 ui.status(_(b'(no more unresolved files)\n'))
6010 ui.status(_(b'(no more unresolved files)\n'))
6011 cmdutil.checkafterresolved(repo)
6011 cmdutil.checkafterresolved(repo)
6012
6012
6013 return ret
6013 return ret
6014
6014
6015
6015
6016 @command(
6016 @command(
6017 b'revert',
6017 b'revert',
6018 [
6018 [
6019 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6019 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6020 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6020 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6021 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6021 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6022 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6022 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6023 (b'i', b'interactive', None, _(b'interactively select the changes')),
6023 (b'i', b'interactive', None, _(b'interactively select the changes')),
6024 ]
6024 ]
6025 + walkopts
6025 + walkopts
6026 + dryrunopts,
6026 + dryrunopts,
6027 _(b'[OPTION]... [-r REV] [NAME]...'),
6027 _(b'[OPTION]... [-r REV] [NAME]...'),
6028 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6028 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6029 )
6029 )
6030 def revert(ui, repo, *pats, **opts):
6030 def revert(ui, repo, *pats, **opts):
6031 """restore files to their checkout state
6031 """restore files to their checkout state
6032
6032
6033 .. note::
6033 .. note::
6034
6034
6035 To check out earlier revisions, you should use :hg:`update REV`.
6035 To check out earlier revisions, you should use :hg:`update REV`.
6036 To cancel an uncommitted merge (and lose your changes),
6036 To cancel an uncommitted merge (and lose your changes),
6037 use :hg:`merge --abort`.
6037 use :hg:`merge --abort`.
6038
6038
6039 With no revision specified, revert the specified files or directories
6039 With no revision specified, revert the specified files or directories
6040 to the contents they had in the parent of the working directory.
6040 to the contents they had in the parent of the working directory.
6041 This restores the contents of files to an unmodified
6041 This restores the contents of files to an unmodified
6042 state and unschedules adds, removes, copies, and renames. If the
6042 state and unschedules adds, removes, copies, and renames. If the
6043 working directory has two parents, you must explicitly specify a
6043 working directory has two parents, you must explicitly specify a
6044 revision.
6044 revision.
6045
6045
6046 Using the -r/--rev or -d/--date options, revert the given files or
6046 Using the -r/--rev or -d/--date options, revert the given files or
6047 directories to their states as of a specific revision. Because
6047 directories to their states as of a specific revision. Because
6048 revert does not change the working directory parents, this will
6048 revert does not change the working directory parents, this will
6049 cause these files to appear modified. This can be helpful to "back
6049 cause these files to appear modified. This can be helpful to "back
6050 out" some or all of an earlier change. See :hg:`backout` for a
6050 out" some or all of an earlier change. See :hg:`backout` for a
6051 related method.
6051 related method.
6052
6052
6053 Modified files are saved with a .orig suffix before reverting.
6053 Modified files are saved with a .orig suffix before reverting.
6054 To disable these backups, use --no-backup. It is possible to store
6054 To disable these backups, use --no-backup. It is possible to store
6055 the backup files in a custom directory relative to the root of the
6055 the backup files in a custom directory relative to the root of the
6056 repository by setting the ``ui.origbackuppath`` configuration
6056 repository by setting the ``ui.origbackuppath`` configuration
6057 option.
6057 option.
6058
6058
6059 See :hg:`help dates` for a list of formats valid for -d/--date.
6059 See :hg:`help dates` for a list of formats valid for -d/--date.
6060
6060
6061 See :hg:`help backout` for a way to reverse the effect of an
6061 See :hg:`help backout` for a way to reverse the effect of an
6062 earlier changeset.
6062 earlier changeset.
6063
6063
6064 Returns 0 on success.
6064 Returns 0 on success.
6065 """
6065 """
6066
6066
6067 if opts.get("date"):
6067 if opts.get("date"):
6068 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6068 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6069 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6069 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6070
6070
6071 parent, p2 = repo.dirstate.parents()
6071 parent, p2 = repo.dirstate.parents()
6072 if not opts.get('rev') and p2 != repo.nullid:
6072 if not opts.get('rev') and p2 != repo.nullid:
6073 # revert after merge is a trap for new users (issue2915)
6073 # revert after merge is a trap for new users (issue2915)
6074 raise error.InputError(
6074 raise error.InputError(
6075 _(b'uncommitted merge with no revision specified'),
6075 _(b'uncommitted merge with no revision specified'),
6076 hint=_(b"use 'hg update' or see 'hg help revert'"),
6076 hint=_(b"use 'hg update' or see 'hg help revert'"),
6077 )
6077 )
6078
6078
6079 rev = opts.get('rev')
6079 rev = opts.get('rev')
6080 if rev:
6080 if rev:
6081 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6081 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6082 ctx = logcmdutil.revsingle(repo, rev)
6082 ctx = logcmdutil.revsingle(repo, rev)
6083
6083
6084 if not (
6084 if not (
6085 pats
6085 pats
6086 or opts.get('include')
6086 or opts.get('include')
6087 or opts.get('exclude')
6087 or opts.get('exclude')
6088 or opts.get('all')
6088 or opts.get('all')
6089 or opts.get('interactive')
6089 or opts.get('interactive')
6090 ):
6090 ):
6091 msg = _(b"no files or directories specified")
6091 msg = _(b"no files or directories specified")
6092 if p2 != repo.nullid:
6092 if p2 != repo.nullid:
6093 hint = _(
6093 hint = _(
6094 b"uncommitted merge, use --all to discard all changes,"
6094 b"uncommitted merge, use --all to discard all changes,"
6095 b" or 'hg update -C .' to abort the merge"
6095 b" or 'hg update -C .' to abort the merge"
6096 )
6096 )
6097 raise error.InputError(msg, hint=hint)
6097 raise error.InputError(msg, hint=hint)
6098 dirty = any(repo.status())
6098 dirty = any(repo.status())
6099 node = ctx.node()
6099 node = ctx.node()
6100 if node != parent:
6100 if node != parent:
6101 if dirty:
6101 if dirty:
6102 hint = (
6102 hint = (
6103 _(
6103 _(
6104 b"uncommitted changes, use --all to discard all"
6104 b"uncommitted changes, use --all to discard all"
6105 b" changes, or 'hg update %d' to update"
6105 b" changes, or 'hg update %d' to update"
6106 )
6106 )
6107 % ctx.rev()
6107 % ctx.rev()
6108 )
6108 )
6109 else:
6109 else:
6110 hint = (
6110 hint = (
6111 _(
6111 _(
6112 b"use --all to revert all files,"
6112 b"use --all to revert all files,"
6113 b" or 'hg update %d' to update"
6113 b" or 'hg update %d' to update"
6114 )
6114 )
6115 % ctx.rev()
6115 % ctx.rev()
6116 )
6116 )
6117 elif dirty:
6117 elif dirty:
6118 hint = _(b"uncommitted changes, use --all to discard all changes")
6118 hint = _(b"uncommitted changes, use --all to discard all changes")
6119 else:
6119 else:
6120 hint = _(b"use --all to revert all files")
6120 hint = _(b"use --all to revert all files")
6121 raise error.InputError(msg, hint=hint)
6121 raise error.InputError(msg, hint=hint)
6122
6122
6123 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6123 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6124
6124
6125
6125
6126 @command(
6126 @command(
6127 b'rollback',
6127 b'rollback',
6128 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6128 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6129 helpcategory=command.CATEGORY_MAINTENANCE,
6129 helpcategory=command.CATEGORY_MAINTENANCE,
6130 )
6130 )
6131 def rollback(ui, repo, **opts):
6131 def rollback(ui, repo, **opts):
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6133
6133
6134 Please use :hg:`commit --amend` instead of rollback to correct
6134 Please use :hg:`commit --amend` instead of rollback to correct
6135 mistakes in the last commit.
6135 mistakes in the last commit.
6136
6136
6137 This command should be used with care. There is only one level of
6137 This command should be used with care. There is only one level of
6138 rollback, and there is no way to undo a rollback. It will also
6138 rollback, and there is no way to undo a rollback. It will also
6139 restore the dirstate at the time of the last transaction, losing
6139 restore the dirstate at the time of the last transaction, losing
6140 any dirstate changes since that time. This command does not alter
6140 any dirstate changes since that time. This command does not alter
6141 the working directory.
6141 the working directory.
6142
6142
6143 Transactions are used to encapsulate the effects of all commands
6143 Transactions are used to encapsulate the effects of all commands
6144 that create new changesets or propagate existing changesets into a
6144 that create new changesets or propagate existing changesets into a
6145 repository.
6145 repository.
6146
6146
6147 .. container:: verbose
6147 .. container:: verbose
6148
6148
6149 For example, the following commands are transactional, and their
6149 For example, the following commands are transactional, and their
6150 effects can be rolled back:
6150 effects can be rolled back:
6151
6151
6152 - commit
6152 - commit
6153 - import
6153 - import
6154 - pull
6154 - pull
6155 - push (with this repository as the destination)
6155 - push (with this repository as the destination)
6156 - unbundle
6156 - unbundle
6157
6157
6158 To avoid permanent data loss, rollback will refuse to rollback a
6158 To avoid permanent data loss, rollback will refuse to rollback a
6159 commit transaction if it isn't checked out. Use --force to
6159 commit transaction if it isn't checked out. Use --force to
6160 override this protection.
6160 override this protection.
6161
6161
6162 The rollback command can be entirely disabled by setting the
6162 The rollback command can be entirely disabled by setting the
6163 ``ui.rollback`` configuration setting to false. If you're here
6163 ``ui.rollback`` configuration setting to false. If you're here
6164 because you want to use rollback and it's disabled, you can
6164 because you want to use rollback and it's disabled, you can
6165 re-enable the command by setting ``ui.rollback`` to true.
6165 re-enable the command by setting ``ui.rollback`` to true.
6166
6166
6167 This command is not intended for use on public repositories. Once
6167 This command is not intended for use on public repositories. Once
6168 changes are visible for pull by other users, rolling a transaction
6168 changes are visible for pull by other users, rolling a transaction
6169 back locally is ineffective (someone else may already have pulled
6169 back locally is ineffective (someone else may already have pulled
6170 the changes). Furthermore, a race is possible with readers of the
6170 the changes). Furthermore, a race is possible with readers of the
6171 repository; for example an in-progress pull from the repository
6171 repository; for example an in-progress pull from the repository
6172 may fail if a rollback is performed.
6172 may fail if a rollback is performed.
6173
6173
6174 Returns 0 on success, 1 if no rollback data is available.
6174 Returns 0 on success, 1 if no rollback data is available.
6175 """
6175 """
6176 if not ui.configbool(b'ui', b'rollback'):
6176 if not ui.configbool(b'ui', b'rollback'):
6177 raise error.Abort(
6177 raise error.Abort(
6178 _(b'rollback is disabled because it is unsafe'),
6178 _(b'rollback is disabled because it is unsafe'),
6179 hint=b'see `hg help -v rollback` for information',
6179 hint=b'see `hg help -v rollback` for information',
6180 )
6180 )
6181 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6181 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6182
6182
6183
6183
6184 @command(
6184 @command(
6185 b'root',
6185 b'root',
6186 [] + formatteropts,
6186 [] + formatteropts,
6187 intents={INTENT_READONLY},
6187 intents={INTENT_READONLY},
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6189 )
6189 )
6190 def root(ui, repo, **opts):
6190 def root(ui, repo, **opts):
6191 """print the root (top) of the current working directory
6191 """print the root (top) of the current working directory
6192
6192
6193 Print the root directory of the current repository.
6193 Print the root directory of the current repository.
6194
6194
6195 .. container:: verbose
6195 .. container:: verbose
6196
6196
6197 Template:
6197 Template:
6198
6198
6199 The following keywords are supported in addition to the common template
6199 The following keywords are supported in addition to the common template
6200 keywords and functions. See also :hg:`help templates`.
6200 keywords and functions. See also :hg:`help templates`.
6201
6201
6202 :hgpath: String. Path to the .hg directory.
6202 :hgpath: String. Path to the .hg directory.
6203 :storepath: String. Path to the directory holding versioned data.
6203 :storepath: String. Path to the directory holding versioned data.
6204
6204
6205 Returns 0 on success.
6205 Returns 0 on success.
6206 """
6206 """
6207 opts = pycompat.byteskwargs(opts)
6207 opts = pycompat.byteskwargs(opts)
6208 with ui.formatter(b'root', opts) as fm:
6208 with ui.formatter(b'root', opts) as fm:
6209 fm.startitem()
6209 fm.startitem()
6210 fm.write(b'reporoot', b'%s\n', repo.root)
6210 fm.write(b'reporoot', b'%s\n', repo.root)
6211 fm.data(hgpath=repo.path, storepath=repo.spath)
6211 fm.data(hgpath=repo.path, storepath=repo.spath)
6212
6212
6213
6213
6214 @command(
6214 @command(
6215 b'serve',
6215 b'serve',
6216 [
6216 [
6217 (
6217 (
6218 b'A',
6218 b'A',
6219 b'accesslog',
6219 b'accesslog',
6220 b'',
6220 b'',
6221 _(b'name of access log file to write to'),
6221 _(b'name of access log file to write to'),
6222 _(b'FILE'),
6222 _(b'FILE'),
6223 ),
6223 ),
6224 (b'd', b'daemon', None, _(b'run server in background')),
6224 (b'd', b'daemon', None, _(b'run server in background')),
6225 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6225 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6226 (
6226 (
6227 b'E',
6227 b'E',
6228 b'errorlog',
6228 b'errorlog',
6229 b'',
6229 b'',
6230 _(b'name of error log file to write to'),
6230 _(b'name of error log file to write to'),
6231 _(b'FILE'),
6231 _(b'FILE'),
6232 ),
6232 ),
6233 # use string type, then we can check if something was passed
6233 # use string type, then we can check if something was passed
6234 (
6234 (
6235 b'p',
6235 b'p',
6236 b'port',
6236 b'port',
6237 b'',
6237 b'',
6238 _(b'port to listen on (default: 8000)'),
6238 _(b'port to listen on (default: 8000)'),
6239 _(b'PORT'),
6239 _(b'PORT'),
6240 ),
6240 ),
6241 (
6241 (
6242 b'a',
6242 b'a',
6243 b'address',
6243 b'address',
6244 b'',
6244 b'',
6245 _(b'address to listen on (default: all interfaces)'),
6245 _(b'address to listen on (default: all interfaces)'),
6246 _(b'ADDR'),
6246 _(b'ADDR'),
6247 ),
6247 ),
6248 (
6248 (
6249 b'',
6249 b'',
6250 b'prefix',
6250 b'prefix',
6251 b'',
6251 b'',
6252 _(b'prefix path to serve from (default: server root)'),
6252 _(b'prefix path to serve from (default: server root)'),
6253 _(b'PREFIX'),
6253 _(b'PREFIX'),
6254 ),
6254 ),
6255 (
6255 (
6256 b'n',
6256 b'n',
6257 b'name',
6257 b'name',
6258 b'',
6258 b'',
6259 _(b'name to show in web pages (default: working directory)'),
6259 _(b'name to show in web pages (default: working directory)'),
6260 _(b'NAME'),
6260 _(b'NAME'),
6261 ),
6261 ),
6262 (
6262 (
6263 b'',
6263 b'',
6264 b'web-conf',
6264 b'web-conf',
6265 b'',
6265 b'',
6266 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6266 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6267 _(b'FILE'),
6267 _(b'FILE'),
6268 ),
6268 ),
6269 (
6269 (
6270 b'',
6270 b'',
6271 b'webdir-conf',
6271 b'webdir-conf',
6272 b'',
6272 b'',
6273 _(b'name of the hgweb config file (DEPRECATED)'),
6273 _(b'name of the hgweb config file (DEPRECATED)'),
6274 _(b'FILE'),
6274 _(b'FILE'),
6275 ),
6275 ),
6276 (
6276 (
6277 b'',
6277 b'',
6278 b'pid-file',
6278 b'pid-file',
6279 b'',
6279 b'',
6280 _(b'name of file to write process ID to'),
6280 _(b'name of file to write process ID to'),
6281 _(b'FILE'),
6281 _(b'FILE'),
6282 ),
6282 ),
6283 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6283 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6284 (
6284 (
6285 b'',
6285 b'',
6286 b'cmdserver',
6286 b'cmdserver',
6287 b'',
6287 b'',
6288 _(b'for remote clients (ADVANCED)'),
6288 _(b'for remote clients (ADVANCED)'),
6289 _(b'MODE'),
6289 _(b'MODE'),
6290 ),
6290 ),
6291 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6291 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6292 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6292 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6293 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6293 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6294 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6294 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6295 (b'', b'print-url', None, _(b'start and print only the URL')),
6295 (b'', b'print-url', None, _(b'start and print only the URL')),
6296 ]
6296 ]
6297 + subrepoopts,
6297 + subrepoopts,
6298 _(b'[OPTION]...'),
6298 _(b'[OPTION]...'),
6299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6300 helpbasic=True,
6300 helpbasic=True,
6301 optionalrepo=True,
6301 optionalrepo=True,
6302 )
6302 )
6303 def serve(ui, repo, **opts):
6303 def serve(ui, repo, **opts):
6304 """start stand-alone webserver
6304 """start stand-alone webserver
6305
6305
6306 Start a local HTTP repository browser and pull server. You can use
6306 Start a local HTTP repository browser and pull server. You can use
6307 this for ad-hoc sharing and browsing of repositories. It is
6307 this for ad-hoc sharing and browsing of repositories. It is
6308 recommended to use a real web server to serve a repository for
6308 recommended to use a real web server to serve a repository for
6309 longer periods of time.
6309 longer periods of time.
6310
6310
6311 Please note that the server does not implement access control.
6311 Please note that the server does not implement access control.
6312 This means that, by default, anybody can read from the server and
6312 This means that, by default, anybody can read from the server and
6313 nobody can write to it by default. Set the ``web.allow-push``
6313 nobody can write to it by default. Set the ``web.allow-push``
6314 option to ``*`` to allow everybody to push to the server. You
6314 option to ``*`` to allow everybody to push to the server. You
6315 should use a real web server if you need to authenticate users.
6315 should use a real web server if you need to authenticate users.
6316
6316
6317 By default, the server logs accesses to stdout and errors to
6317 By default, the server logs accesses to stdout and errors to
6318 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6318 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6319 files.
6319 files.
6320
6320
6321 To have the server choose a free port number to listen on, specify
6321 To have the server choose a free port number to listen on, specify
6322 a port number of 0; in this case, the server will print the port
6322 a port number of 0; in this case, the server will print the port
6323 number it uses.
6323 number it uses.
6324
6324
6325 Returns 0 on success.
6325 Returns 0 on success.
6326 """
6326 """
6327
6327
6328 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6328 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6329 opts = pycompat.byteskwargs(opts)
6329 opts = pycompat.byteskwargs(opts)
6330 if opts[b"print_url"] and ui.verbose:
6330 if opts[b"print_url"] and ui.verbose:
6331 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6331 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6332
6332
6333 if opts[b"stdio"]:
6333 if opts[b"stdio"]:
6334 if repo is None:
6334 if repo is None:
6335 raise error.RepoError(
6335 raise error.RepoError(
6336 _(b"there is no Mercurial repository here (.hg not found)")
6336 _(b"there is no Mercurial repository here (.hg not found)")
6337 )
6337 )
6338 accesshidden = False
6338 accesshidden = False
6339 if repo.filtername is None:
6339 if repo.filtername is None:
6340 allow = ui.configlist(
6340 allow = ui.configlist(
6341 b'experimental', b'server.allow-hidden-access'
6341 b'experimental', b'server.allow-hidden-access'
6342 )
6342 )
6343 user = procutil.getuser()
6343 user = procutil.getuser()
6344 if allow and scmutil.ismember(ui, user, allow):
6344 if allow and scmutil.ismember(ui, user, allow):
6345 accesshidden = True
6345 accesshidden = True
6346 else:
6346 else:
6347 msg = (
6347 msg = (
6348 _(
6348 _(
6349 b'ignoring request to access hidden changeset by '
6349 b'ignoring request to access hidden changeset by '
6350 b'unauthorized user: %s\n'
6350 b'unauthorized user: %s\n'
6351 )
6351 )
6352 % user
6352 % user
6353 )
6353 )
6354 ui.warn(msg)
6354 ui.warn(msg)
6355
6355
6356 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6356 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6357 s.serve_forever()
6357 s.serve_forever()
6358 return
6358 return
6359
6359
6360 service = server.createservice(ui, repo, opts)
6360 service = server.createservice(ui, repo, opts)
6361 return server.runservice(opts, initfn=service.init, runfn=service.run)
6361 return server.runservice(opts, initfn=service.init, runfn=service.run)
6362
6362
6363
6363
6364 @command(
6364 @command(
6365 b'shelve',
6365 b'shelve',
6366 [
6366 [
6367 (
6367 (
6368 b'A',
6368 b'A',
6369 b'addremove',
6369 b'addremove',
6370 None,
6370 None,
6371 _(b'mark new/missing files as added/removed before shelving'),
6371 _(b'mark new/missing files as added/removed before shelving'),
6372 ),
6372 ),
6373 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6373 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6374 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6374 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6375 (
6375 (
6376 b'',
6376 b'',
6377 b'date',
6377 b'date',
6378 b'',
6378 b'',
6379 _(b'shelve with the specified commit date'),
6379 _(b'shelve with the specified commit date'),
6380 _(b'DATE'),
6380 _(b'DATE'),
6381 ),
6381 ),
6382 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6382 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6383 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6383 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6384 (
6384 (
6385 b'k',
6385 b'k',
6386 b'keep',
6386 b'keep',
6387 False,
6387 False,
6388 _(b'shelve, but keep changes in the working directory'),
6388 _(b'shelve, but keep changes in the working directory'),
6389 ),
6389 ),
6390 (b'l', b'list', None, _(b'list current shelves')),
6390 (b'l', b'list', None, _(b'list current shelves')),
6391 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6391 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6392 (
6392 (
6393 b'n',
6393 b'n',
6394 b'name',
6394 b'name',
6395 b'',
6395 b'',
6396 _(b'use the given name for the shelved commit'),
6396 _(b'use the given name for the shelved commit'),
6397 _(b'NAME'),
6397 _(b'NAME'),
6398 ),
6398 ),
6399 (
6399 (
6400 b'p',
6400 b'p',
6401 b'patch',
6401 b'patch',
6402 None,
6402 None,
6403 _(
6403 _(
6404 b'output patches for changes (provide the names of the shelved '
6404 b'output patches for changes (provide the names of the shelved '
6405 b'changes as positional arguments)'
6405 b'changes as positional arguments)'
6406 ),
6406 ),
6407 ),
6407 ),
6408 (b'i', b'interactive', None, _(b'interactive mode')),
6408 (b'i', b'interactive', None, _(b'interactive mode')),
6409 (
6409 (
6410 b'',
6410 b'',
6411 b'stat',
6411 b'stat',
6412 None,
6412 None,
6413 _(
6413 _(
6414 b'output diffstat-style summary of changes (provide the names of '
6414 b'output diffstat-style summary of changes (provide the names of '
6415 b'the shelved changes as positional arguments)'
6415 b'the shelved changes as positional arguments)'
6416 ),
6416 ),
6417 ),
6417 ),
6418 ]
6418 ]
6419 + cmdutil.walkopts,
6419 + cmdutil.walkopts,
6420 _(b'hg shelve [OPTION]... [FILE]...'),
6420 _(b'hg shelve [OPTION]... [FILE]...'),
6421 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6421 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6422 )
6422 )
6423 def shelve(ui, repo, *pats, **opts):
6423 def shelve(ui, repo, *pats, **opts):
6424 """save and set aside changes from the working directory
6424 """save and set aside changes from the working directory
6425
6425
6426 Shelving takes files that "hg status" reports as not clean, saves
6426 Shelving takes files that "hg status" reports as not clean, saves
6427 the modifications to a bundle (a shelved change), and reverts the
6427 the modifications to a bundle (a shelved change), and reverts the
6428 files so that their state in the working directory becomes clean.
6428 files so that their state in the working directory becomes clean.
6429
6429
6430 To restore these changes to the working directory, using "hg
6430 To restore these changes to the working directory, using "hg
6431 unshelve"; this will work even if you switch to a different
6431 unshelve"; this will work even if you switch to a different
6432 commit.
6432 commit.
6433
6433
6434 When no files are specified, "hg shelve" saves all not-clean
6434 When no files are specified, "hg shelve" saves all not-clean
6435 files. If specific files or directories are named, only changes to
6435 files. If specific files or directories are named, only changes to
6436 those files are shelved.
6436 those files are shelved.
6437
6437
6438 In bare shelve (when no files are specified, without interactive,
6438 In bare shelve (when no files are specified, without interactive,
6439 include and exclude option), shelving remembers information if the
6439 include and exclude option), shelving remembers information if the
6440 working directory was on newly created branch, in other words working
6440 working directory was on newly created branch, in other words working
6441 directory was on different branch than its first parent. In this
6441 directory was on different branch than its first parent. In this
6442 situation unshelving restores branch information to the working directory.
6442 situation unshelving restores branch information to the working directory.
6443
6443
6444 Each shelved change has a name that makes it easier to find later.
6444 Each shelved change has a name that makes it easier to find later.
6445 The name of a shelved change defaults to being based on the active
6445 The name of a shelved change defaults to being based on the active
6446 bookmark, or if there is no active bookmark, the current named
6446 bookmark, or if there is no active bookmark, the current named
6447 branch. To specify a different name, use ``--name``.
6447 branch. To specify a different name, use ``--name``.
6448
6448
6449 To see a list of existing shelved changes, use the ``--list``
6449 To see a list of existing shelved changes, use the ``--list``
6450 option. For each shelved change, this will print its name, age,
6450 option. For each shelved change, this will print its name, age,
6451 and description; use ``--patch`` or ``--stat`` for more details.
6451 and description; use ``--patch`` or ``--stat`` for more details.
6452
6452
6453 To delete specific shelved changes, use ``--delete``. To delete
6453 To delete specific shelved changes, use ``--delete``. To delete
6454 all shelved changes, use ``--cleanup``.
6454 all shelved changes, use ``--cleanup``.
6455 """
6455 """
6456 opts = pycompat.byteskwargs(opts)
6456 opts = pycompat.byteskwargs(opts)
6457 allowables = [
6457 allowables = [
6458 (b'addremove', {b'create'}), # 'create' is pseudo action
6458 (b'addremove', {b'create'}), # 'create' is pseudo action
6459 (b'unknown', {b'create'}),
6459 (b'unknown', {b'create'}),
6460 (b'cleanup', {b'cleanup'}),
6460 (b'cleanup', {b'cleanup'}),
6461 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6461 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6462 (b'delete', {b'delete'}),
6462 (b'delete', {b'delete'}),
6463 (b'edit', {b'create'}),
6463 (b'edit', {b'create'}),
6464 (b'keep', {b'create'}),
6464 (b'keep', {b'create'}),
6465 (b'list', {b'list'}),
6465 (b'list', {b'list'}),
6466 (b'message', {b'create'}),
6466 (b'message', {b'create'}),
6467 (b'name', {b'create'}),
6467 (b'name', {b'create'}),
6468 (b'patch', {b'patch', b'list'}),
6468 (b'patch', {b'patch', b'list'}),
6469 (b'stat', {b'stat', b'list'}),
6469 (b'stat', {b'stat', b'list'}),
6470 ]
6470 ]
6471
6471
6472 def checkopt(opt):
6472 def checkopt(opt):
6473 if opts.get(opt):
6473 if opts.get(opt):
6474 for i, allowable in allowables:
6474 for i, allowable in allowables:
6475 if opts[i] and opt not in allowable:
6475 if opts[i] and opt not in allowable:
6476 raise error.InputError(
6476 raise error.InputError(
6477 _(
6477 _(
6478 b"options '--%s' and '--%s' may not be "
6478 b"options '--%s' and '--%s' may not be "
6479 b"used together"
6479 b"used together"
6480 )
6480 )
6481 % (opt, i)
6481 % (opt, i)
6482 )
6482 )
6483 return True
6483 return True
6484
6484
6485 if checkopt(b'cleanup'):
6485 if checkopt(b'cleanup'):
6486 if pats:
6486 if pats:
6487 raise error.InputError(
6487 raise error.InputError(
6488 _(b"cannot specify names when using '--cleanup'")
6488 _(b"cannot specify names when using '--cleanup'")
6489 )
6489 )
6490 return shelvemod.cleanupcmd(ui, repo)
6490 return shelvemod.cleanupcmd(ui, repo)
6491 elif checkopt(b'delete'):
6491 elif checkopt(b'delete'):
6492 return shelvemod.deletecmd(ui, repo, pats)
6492 return shelvemod.deletecmd(ui, repo, pats)
6493 elif checkopt(b'list'):
6493 elif checkopt(b'list'):
6494 return shelvemod.listcmd(ui, repo, pats, opts)
6494 return shelvemod.listcmd(ui, repo, pats, opts)
6495 elif checkopt(b'patch') or checkopt(b'stat'):
6495 elif checkopt(b'patch') or checkopt(b'stat'):
6496 return shelvemod.patchcmds(ui, repo, pats, opts)
6496 return shelvemod.patchcmds(ui, repo, pats, opts)
6497 else:
6497 else:
6498 return shelvemod.createcmd(ui, repo, pats, opts)
6498 return shelvemod.createcmd(ui, repo, pats, opts)
6499
6499
6500
6500
6501 _NOTTERSE = b'nothing'
6501 _NOTTERSE = b'nothing'
6502
6502
6503
6503
6504 @command(
6504 @command(
6505 b'status|st',
6505 b'status|st',
6506 [
6506 [
6507 (b'A', b'all', None, _(b'show status of all files')),
6507 (b'A', b'all', None, _(b'show status of all files')),
6508 (b'm', b'modified', None, _(b'show only modified files')),
6508 (b'm', b'modified', None, _(b'show only modified files')),
6509 (b'a', b'added', None, _(b'show only added files')),
6509 (b'a', b'added', None, _(b'show only added files')),
6510 (b'r', b'removed', None, _(b'show only removed files')),
6510 (b'r', b'removed', None, _(b'show only removed files')),
6511 (b'd', b'deleted', None, _(b'show only missing files')),
6511 (b'd', b'deleted', None, _(b'show only missing files')),
6512 (b'c', b'clean', None, _(b'show only files without changes')),
6512 (b'c', b'clean', None, _(b'show only files without changes')),
6513 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6513 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6514 (b'i', b'ignored', None, _(b'show only ignored files')),
6514 (b'i', b'ignored', None, _(b'show only ignored files')),
6515 (b'n', b'no-status', None, _(b'hide status prefix')),
6515 (b'n', b'no-status', None, _(b'hide status prefix')),
6516 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6516 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6517 (
6517 (
6518 b'C',
6518 b'C',
6519 b'copies',
6519 b'copies',
6520 None,
6520 None,
6521 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6521 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6522 ),
6522 ),
6523 (
6523 (
6524 b'0',
6524 b'0',
6525 b'print0',
6525 b'print0',
6526 None,
6526 None,
6527 _(b'end filenames with NUL, for use with xargs'),
6527 _(b'end filenames with NUL, for use with xargs'),
6528 ),
6528 ),
6529 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6529 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6530 (
6530 (
6531 b'',
6531 b'',
6532 b'change',
6532 b'change',
6533 b'',
6533 b'',
6534 _(b'list the changed files of a revision'),
6534 _(b'list the changed files of a revision'),
6535 _(b'REV'),
6535 _(b'REV'),
6536 ),
6536 ),
6537 ]
6537 ]
6538 + walkopts
6538 + walkopts
6539 + subrepoopts
6539 + subrepoopts
6540 + formatteropts,
6540 + formatteropts,
6541 _(b'[OPTION]... [FILE]...'),
6541 _(b'[OPTION]... [FILE]...'),
6542 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6542 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6543 helpbasic=True,
6543 helpbasic=True,
6544 inferrepo=True,
6544 inferrepo=True,
6545 intents={INTENT_READONLY},
6545 intents={INTENT_READONLY},
6546 )
6546 )
6547 def status(ui, repo, *pats, **opts):
6547 def status(ui, repo, *pats, **opts):
6548 """show changed files in the working directory
6548 """show changed files in the working directory
6549
6549
6550 Show status of files in the repository. If names are given, only
6550 Show status of files in the repository. If names are given, only
6551 files that match are shown. Files that are clean or ignored or
6551 files that match are shown. Files that are clean or ignored or
6552 the source of a copy/move operation, are not listed unless
6552 the source of a copy/move operation, are not listed unless
6553 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6553 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6554 Unless options described with "show only ..." are given, the
6554 Unless options described with "show only ..." are given, the
6555 options -mardu are used.
6555 options -mardu are used.
6556
6556
6557 Option -q/--quiet hides untracked (unknown and ignored) files
6557 Option -q/--quiet hides untracked (unknown and ignored) files
6558 unless explicitly requested with -u/--unknown or -i/--ignored.
6558 unless explicitly requested with -u/--unknown or -i/--ignored.
6559
6559
6560 .. note::
6560 .. note::
6561
6561
6562 :hg:`status` may appear to disagree with diff if permissions have
6562 :hg:`status` may appear to disagree with diff if permissions have
6563 changed or a merge has occurred. The standard diff format does
6563 changed or a merge has occurred. The standard diff format does
6564 not report permission changes and diff only reports changes
6564 not report permission changes and diff only reports changes
6565 relative to one merge parent.
6565 relative to one merge parent.
6566
6566
6567 If one revision is given, it is used as the base revision.
6567 If one revision is given, it is used as the base revision.
6568 If two revisions are given, the differences between them are
6568 If two revisions are given, the differences between them are
6569 shown. The --change option can also be used as a shortcut to list
6569 shown. The --change option can also be used as a shortcut to list
6570 the changed files of a revision from its first parent.
6570 the changed files of a revision from its first parent.
6571
6571
6572 The codes used to show the status of files are::
6572 The codes used to show the status of files are::
6573
6573
6574 M = modified
6574 M = modified
6575 A = added
6575 A = added
6576 R = removed
6576 R = removed
6577 C = clean
6577 C = clean
6578 ! = missing (deleted by non-hg command, but still tracked)
6578 ! = missing (deleted by non-hg command, but still tracked)
6579 ? = not tracked
6579 ? = not tracked
6580 I = ignored
6580 I = ignored
6581 = origin of the previous file (with --copies)
6581 = origin of the previous file (with --copies)
6582
6582
6583 .. container:: verbose
6583 .. container:: verbose
6584
6584
6585 The -t/--terse option abbreviates the output by showing only the directory
6585 The -t/--terse option abbreviates the output by showing only the directory
6586 name if all the files in it share the same status. The option takes an
6586 name if all the files in it share the same status. The option takes an
6587 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6587 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6588 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6588 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6589 for 'ignored' and 'c' for clean.
6589 for 'ignored' and 'c' for clean.
6590
6590
6591 It abbreviates only those statuses which are passed. Note that clean and
6591 It abbreviates only those statuses which are passed. Note that clean and
6592 ignored files are not displayed with '--terse ic' unless the -c/--clean
6592 ignored files are not displayed with '--terse ic' unless the -c/--clean
6593 and -i/--ignored options are also used.
6593 and -i/--ignored options are also used.
6594
6594
6595 The -v/--verbose option shows information when the repository is in an
6595 The -v/--verbose option shows information when the repository is in an
6596 unfinished merge, shelve, rebase state etc. You can have this behavior
6596 unfinished merge, shelve, rebase state etc. You can have this behavior
6597 turned on by default by enabling the ``commands.status.verbose`` option.
6597 turned on by default by enabling the ``commands.status.verbose`` option.
6598
6598
6599 You can skip displaying some of these states by setting
6599 You can skip displaying some of these states by setting
6600 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6600 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6601 'histedit', 'merge', 'rebase', or 'unshelve'.
6601 'histedit', 'merge', 'rebase', or 'unshelve'.
6602
6602
6603 Template:
6603 Template:
6604
6604
6605 The following keywords are supported in addition to the common template
6605 The following keywords are supported in addition to the common template
6606 keywords and functions. See also :hg:`help templates`.
6606 keywords and functions. See also :hg:`help templates`.
6607
6607
6608 :path: String. Repository-absolute path of the file.
6608 :path: String. Repository-absolute path of the file.
6609 :source: String. Repository-absolute path of the file originated from.
6609 :source: String. Repository-absolute path of the file originated from.
6610 Available if ``--copies`` is specified.
6610 Available if ``--copies`` is specified.
6611 :status: String. Character denoting file's status.
6611 :status: String. Character denoting file's status.
6612
6612
6613 Examples:
6613 Examples:
6614
6614
6615 - show changes in the working directory relative to a
6615 - show changes in the working directory relative to a
6616 changeset::
6616 changeset::
6617
6617
6618 hg status --rev 9353
6618 hg status --rev 9353
6619
6619
6620 - show changes in the working directory relative to the
6620 - show changes in the working directory relative to the
6621 current directory (see :hg:`help patterns` for more information)::
6621 current directory (see :hg:`help patterns` for more information)::
6622
6622
6623 hg status re:
6623 hg status re:
6624
6624
6625 - show all changes including copies in an existing changeset::
6625 - show all changes including copies in an existing changeset::
6626
6626
6627 hg status --copies --change 9353
6627 hg status --copies --change 9353
6628
6628
6629 - get a NUL separated list of added files, suitable for xargs::
6629 - get a NUL separated list of added files, suitable for xargs::
6630
6630
6631 hg status -an0
6631 hg status -an0
6632
6632
6633 - show more information about the repository status, abbreviating
6633 - show more information about the repository status, abbreviating
6634 added, removed, modified, deleted, and untracked paths::
6634 added, removed, modified, deleted, and untracked paths::
6635
6635
6636 hg status -v -t mardu
6636 hg status -v -t mardu
6637
6637
6638 Returns 0 on success.
6638 Returns 0 on success.
6639
6639
6640 """
6640 """
6641
6641
6642 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6642 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6643 opts = pycompat.byteskwargs(opts)
6643 opts = pycompat.byteskwargs(opts)
6644 revs = opts.get(b'rev', [])
6644 revs = opts.get(b'rev', [])
6645 change = opts.get(b'change', b'')
6645 change = opts.get(b'change', b'')
6646 terse = opts.get(b'terse', _NOTTERSE)
6646 terse = opts.get(b'terse', _NOTTERSE)
6647 if terse is _NOTTERSE:
6647 if terse is _NOTTERSE:
6648 if revs:
6648 if revs:
6649 terse = b''
6649 terse = b''
6650 else:
6650 else:
6651 terse = ui.config(b'commands', b'status.terse')
6651 terse = ui.config(b'commands', b'status.terse')
6652
6652
6653 if revs and terse:
6653 if revs and terse:
6654 msg = _(b'cannot use --terse with --rev')
6654 msg = _(b'cannot use --terse with --rev')
6655 raise error.InputError(msg)
6655 raise error.InputError(msg)
6656 elif change:
6656 elif change:
6657 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6657 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6658 ctx2 = logcmdutil.revsingle(repo, change, None)
6658 ctx2 = logcmdutil.revsingle(repo, change, None)
6659 ctx1 = ctx2.p1()
6659 ctx1 = ctx2.p1()
6660 else:
6660 else:
6661 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6661 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6662 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6662 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6663
6663
6664 forcerelativevalue = None
6664 forcerelativevalue = None
6665 if ui.hasconfig(b'commands', b'status.relative'):
6665 if ui.hasconfig(b'commands', b'status.relative'):
6666 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6666 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6667 uipathfn = scmutil.getuipathfn(
6667 uipathfn = scmutil.getuipathfn(
6668 repo,
6668 repo,
6669 legacyrelativevalue=bool(pats),
6669 legacyrelativevalue=bool(pats),
6670 forcerelativevalue=forcerelativevalue,
6670 forcerelativevalue=forcerelativevalue,
6671 )
6671 )
6672
6672
6673 if opts.get(b'print0'):
6673 if opts.get(b'print0'):
6674 end = b'\0'
6674 end = b'\0'
6675 else:
6675 else:
6676 end = b'\n'
6676 end = b'\n'
6677 states = b'modified added removed deleted unknown ignored clean'.split()
6677 states = b'modified added removed deleted unknown ignored clean'.split()
6678 show = [k for k in states if opts.get(k)]
6678 show = [k for k in states if opts.get(k)]
6679 if opts.get(b'all'):
6679 if opts.get(b'all'):
6680 show += ui.quiet and (states[:4] + [b'clean']) or states
6680 show += ui.quiet and (states[:4] + [b'clean']) or states
6681
6681
6682 if not show:
6682 if not show:
6683 if ui.quiet:
6683 if ui.quiet:
6684 show = states[:4]
6684 show = states[:4]
6685 else:
6685 else:
6686 show = states[:5]
6686 show = states[:5]
6687
6687
6688 m = scmutil.match(ctx2, pats, opts)
6688 m = scmutil.match(ctx2, pats, opts)
6689 if terse:
6689 if terse:
6690 # we need to compute clean and unknown to terse
6690 # we need to compute clean and unknown to terse
6691 stat = repo.status(
6691 stat = repo.status(
6692 ctx1.node(),
6692 ctx1.node(),
6693 ctx2.node(),
6693 ctx2.node(),
6694 m,
6694 m,
6695 b'ignored' in show or b'i' in terse,
6695 b'ignored' in show or b'i' in terse,
6696 clean=True,
6696 clean=True,
6697 unknown=True,
6697 unknown=True,
6698 listsubrepos=opts.get(b'subrepos'),
6698 listsubrepos=opts.get(b'subrepos'),
6699 )
6699 )
6700
6700
6701 stat = cmdutil.tersedir(stat, terse)
6701 stat = cmdutil.tersedir(stat, terse)
6702 else:
6702 else:
6703 stat = repo.status(
6703 stat = repo.status(
6704 ctx1.node(),
6704 ctx1.node(),
6705 ctx2.node(),
6705 ctx2.node(),
6706 m,
6706 m,
6707 b'ignored' in show,
6707 b'ignored' in show,
6708 b'clean' in show,
6708 b'clean' in show,
6709 b'unknown' in show,
6709 b'unknown' in show,
6710 opts.get(b'subrepos'),
6710 opts.get(b'subrepos'),
6711 )
6711 )
6712
6712
6713 changestates = zip(
6713 changestates = zip(
6714 states,
6714 states,
6715 pycompat.iterbytestr(b'MAR!?IC'),
6715 pycompat.iterbytestr(b'MAR!?IC'),
6716 [getattr(stat, s.decode('utf8')) for s in states],
6716 [getattr(stat, s.decode('utf8')) for s in states],
6717 )
6717 )
6718
6718
6719 copy = {}
6719 copy = {}
6720 show_copies = ui.configbool(b'ui', b'statuscopies')
6720 show_copies = ui.configbool(b'ui', b'statuscopies')
6721 if opts.get(b'copies') is not None:
6721 if opts.get(b'copies') is not None:
6722 show_copies = opts.get(b'copies')
6722 show_copies = opts.get(b'copies')
6723 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6723 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6724 b'no_status'
6724 b'no_status'
6725 )
6725 )
6726 if show_copies:
6726 if show_copies:
6727 copy = copies.pathcopies(ctx1, ctx2, m)
6727 copy = copies.pathcopies(ctx1, ctx2, m)
6728
6728
6729 morestatus = None
6729 morestatus = None
6730 if (
6730 if (
6731 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6731 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6732 and not ui.plain()
6732 and not ui.plain()
6733 and not opts.get(b'print0')
6733 and not opts.get(b'print0')
6734 ):
6734 ):
6735 morestatus = cmdutil.readmorestatus(repo)
6735 morestatus = cmdutil.readmorestatus(repo)
6736
6736
6737 ui.pager(b'status')
6737 ui.pager(b'status')
6738 fm = ui.formatter(b'status', opts)
6738 fm = ui.formatter(b'status', opts)
6739 fmt = b'%s' + end
6739 fmt = b'%s' + end
6740 showchar = not opts.get(b'no_status')
6740 showchar = not opts.get(b'no_status')
6741
6741
6742 for state, char, files in changestates:
6742 for state, char, files in changestates:
6743 if state in show:
6743 if state in show:
6744 label = b'status.' + state
6744 label = b'status.' + state
6745 for f in files:
6745 for f in files:
6746 fm.startitem()
6746 fm.startitem()
6747 fm.context(ctx=ctx2)
6747 fm.context(ctx=ctx2)
6748 fm.data(itemtype=b'file', path=f)
6748 fm.data(itemtype=b'file', path=f)
6749 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6749 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6750 fm.plain(fmt % uipathfn(f), label=label)
6750 fm.plain(fmt % uipathfn(f), label=label)
6751 if f in copy:
6751 if f in copy:
6752 fm.data(source=copy[f])
6752 fm.data(source=copy[f])
6753 fm.plain(
6753 fm.plain(
6754 (b' %s' + end) % uipathfn(copy[f]),
6754 (b' %s' + end) % uipathfn(copy[f]),
6755 label=b'status.copied',
6755 label=b'status.copied',
6756 )
6756 )
6757 if morestatus:
6757 if morestatus:
6758 morestatus.formatfile(f, fm)
6758 morestatus.formatfile(f, fm)
6759
6759
6760 if morestatus:
6760 if morestatus:
6761 morestatus.formatfooter(fm)
6761 morestatus.formatfooter(fm)
6762 fm.end()
6762 fm.end()
6763
6763
6764
6764
6765 @command(
6765 @command(
6766 b'summary|sum',
6766 b'summary|sum',
6767 [(b'', b'remote', None, _(b'check for push and pull'))],
6767 [(b'', b'remote', None, _(b'check for push and pull'))],
6768 b'[--remote]',
6768 b'[--remote]',
6769 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6769 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6770 helpbasic=True,
6770 helpbasic=True,
6771 intents={INTENT_READONLY},
6771 intents={INTENT_READONLY},
6772 )
6772 )
6773 def summary(ui, repo, **opts):
6773 def summary(ui, repo, **opts):
6774 """summarize working directory state
6774 """summarize working directory state
6775
6775
6776 This generates a brief summary of the working directory state,
6776 This generates a brief summary of the working directory state,
6777 including parents, branch, commit status, phase and available updates.
6777 including parents, branch, commit status, phase and available updates.
6778
6778
6779 With the --remote option, this will check the default paths for
6779 With the --remote option, this will check the default paths for
6780 incoming and outgoing changes. This can be time-consuming.
6780 incoming and outgoing changes. This can be time-consuming.
6781
6781
6782 Returns 0 on success.
6782 Returns 0 on success.
6783 """
6783 """
6784
6784
6785 ui.pager(b'summary')
6785 ui.pager(b'summary')
6786 ctx = repo[None]
6786 ctx = repo[None]
6787 parents = ctx.parents()
6787 parents = ctx.parents()
6788 pnode = parents[0].node()
6788 pnode = parents[0].node()
6789 marks = []
6789 marks = []
6790
6790
6791 try:
6791 try:
6792 ms = mergestatemod.mergestate.read(repo)
6792 ms = mergestatemod.mergestate.read(repo)
6793 except error.UnsupportedMergeRecords as e:
6793 except error.UnsupportedMergeRecords as e:
6794 s = b' '.join(e.recordtypes)
6794 s = b' '.join(e.recordtypes)
6795 ui.warn(
6795 ui.warn(
6796 _(b'warning: merge state has unsupported record types: %s\n') % s
6796 _(b'warning: merge state has unsupported record types: %s\n') % s
6797 )
6797 )
6798 unresolved = []
6798 unresolved = []
6799 else:
6799 else:
6800 unresolved = list(ms.unresolved())
6800 unresolved = list(ms.unresolved())
6801
6801
6802 for p in parents:
6802 for p in parents:
6803 # label with log.changeset (instead of log.parent) since this
6803 # label with log.changeset (instead of log.parent) since this
6804 # shows a working directory parent *changeset*:
6804 # shows a working directory parent *changeset*:
6805 # i18n: column positioning for "hg summary"
6805 # i18n: column positioning for "hg summary"
6806 ui.write(
6806 ui.write(
6807 _(b'parent: %d:%s ') % (p.rev(), p),
6807 _(b'parent: %d:%s ') % (p.rev(), p),
6808 label=logcmdutil.changesetlabels(p),
6808 label=logcmdutil.changesetlabels(p),
6809 )
6809 )
6810 ui.write(b' '.join(p.tags()), label=b'log.tag')
6810 ui.write(b' '.join(p.tags()), label=b'log.tag')
6811 if p.bookmarks():
6811 if p.bookmarks():
6812 marks.extend(p.bookmarks())
6812 marks.extend(p.bookmarks())
6813 if p.rev() == -1:
6813 if p.rev() == -1:
6814 if not len(repo):
6814 if not len(repo):
6815 ui.write(_(b' (empty repository)'))
6815 ui.write(_(b' (empty repository)'))
6816 else:
6816 else:
6817 ui.write(_(b' (no revision checked out)'))
6817 ui.write(_(b' (no revision checked out)'))
6818 if p.obsolete():
6818 if p.obsolete():
6819 ui.write(_(b' (obsolete)'))
6819 ui.write(_(b' (obsolete)'))
6820 if p.isunstable():
6820 if p.isunstable():
6821 instabilities = (
6821 instabilities = (
6822 ui.label(instability, b'trouble.%s' % instability)
6822 ui.label(instability, b'trouble.%s' % instability)
6823 for instability in p.instabilities()
6823 for instability in p.instabilities()
6824 )
6824 )
6825 ui.write(b' (' + b', '.join(instabilities) + b')')
6825 ui.write(b' (' + b', '.join(instabilities) + b')')
6826 ui.write(b'\n')
6826 ui.write(b'\n')
6827 if p.description():
6827 if p.description():
6828 ui.status(
6828 ui.status(
6829 b' ' + p.description().splitlines()[0].strip() + b'\n',
6829 b' ' + p.description().splitlines()[0].strip() + b'\n',
6830 label=b'log.summary',
6830 label=b'log.summary',
6831 )
6831 )
6832
6832
6833 branch = ctx.branch()
6833 branch = ctx.branch()
6834 bheads = repo.branchheads(branch)
6834 bheads = repo.branchheads(branch)
6835 # i18n: column positioning for "hg summary"
6835 # i18n: column positioning for "hg summary"
6836 m = _(b'branch: %s\n') % branch
6836 m = _(b'branch: %s\n') % branch
6837 if branch != b'default':
6837 if branch != b'default':
6838 ui.write(m, label=b'log.branch')
6838 ui.write(m, label=b'log.branch')
6839 else:
6839 else:
6840 ui.status(m, label=b'log.branch')
6840 ui.status(m, label=b'log.branch')
6841
6841
6842 if marks:
6842 if marks:
6843 active = repo._activebookmark
6843 active = repo._activebookmark
6844 # i18n: column positioning for "hg summary"
6844 # i18n: column positioning for "hg summary"
6845 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6845 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6846 if active is not None:
6846 if active is not None:
6847 if active in marks:
6847 if active in marks:
6848 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6848 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6849 marks.remove(active)
6849 marks.remove(active)
6850 else:
6850 else:
6851 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6851 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6852 for m in marks:
6852 for m in marks:
6853 ui.write(b' ' + m, label=b'log.bookmark')
6853 ui.write(b' ' + m, label=b'log.bookmark')
6854 ui.write(b'\n', label=b'log.bookmark')
6854 ui.write(b'\n', label=b'log.bookmark')
6855
6855
6856 status = repo.status(unknown=True)
6856 status = repo.status(unknown=True)
6857
6857
6858 c = repo.dirstate.copies()
6858 c = repo.dirstate.copies()
6859 copied, renamed = [], []
6859 copied, renamed = [], []
6860 for d, s in c.items():
6860 for d, s in c.items():
6861 if s in status.removed:
6861 if s in status.removed:
6862 status.removed.remove(s)
6862 status.removed.remove(s)
6863 renamed.append(d)
6863 renamed.append(d)
6864 else:
6864 else:
6865 copied.append(d)
6865 copied.append(d)
6866 if d in status.added:
6866 if d in status.added:
6867 status.added.remove(d)
6867 status.added.remove(d)
6868
6868
6869 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6869 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6870
6870
6871 labels = [
6871 labels = [
6872 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6872 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6873 (ui.label(_(b'%d added'), b'status.added'), status.added),
6873 (ui.label(_(b'%d added'), b'status.added'), status.added),
6874 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6874 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6875 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6875 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6876 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6876 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6877 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6877 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6878 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6878 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6879 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6879 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6880 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6880 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6881 ]
6881 ]
6882 t = []
6882 t = []
6883 for l, s in labels:
6883 for l, s in labels:
6884 if s:
6884 if s:
6885 t.append(l % len(s))
6885 t.append(l % len(s))
6886
6886
6887 t = b', '.join(t)
6887 t = b', '.join(t)
6888 cleanworkdir = False
6888 cleanworkdir = False
6889
6889
6890 if repo.vfs.exists(b'graftstate'):
6890 if repo.vfs.exists(b'graftstate'):
6891 t += _(b' (graft in progress)')
6891 t += _(b' (graft in progress)')
6892 if repo.vfs.exists(b'updatestate'):
6892 if repo.vfs.exists(b'updatestate'):
6893 t += _(b' (interrupted update)')
6893 t += _(b' (interrupted update)')
6894 elif len(parents) > 1:
6894 elif len(parents) > 1:
6895 t += _(b' (merge)')
6895 t += _(b' (merge)')
6896 elif branch != parents[0].branch():
6896 elif branch != parents[0].branch():
6897 t += _(b' (new branch)')
6897 t += _(b' (new branch)')
6898 elif parents[0].closesbranch() and pnode in repo.branchheads(
6898 elif parents[0].closesbranch() and pnode in repo.branchheads(
6899 branch, closed=True
6899 branch, closed=True
6900 ):
6900 ):
6901 t += _(b' (head closed)')
6901 t += _(b' (head closed)')
6902 elif not (
6902 elif not (
6903 status.modified
6903 status.modified
6904 or status.added
6904 or status.added
6905 or status.removed
6905 or status.removed
6906 or renamed
6906 or renamed
6907 or copied
6907 or copied
6908 or subs
6908 or subs
6909 ):
6909 ):
6910 t += _(b' (clean)')
6910 t += _(b' (clean)')
6911 cleanworkdir = True
6911 cleanworkdir = True
6912 elif pnode not in bheads:
6912 elif pnode not in bheads:
6913 t += _(b' (new branch head)')
6913 t += _(b' (new branch head)')
6914
6914
6915 if parents:
6915 if parents:
6916 pendingphase = max(p.phase() for p in parents)
6916 pendingphase = max(p.phase() for p in parents)
6917 else:
6917 else:
6918 pendingphase = phases.public
6918 pendingphase = phases.public
6919
6919
6920 if pendingphase > phases.newcommitphase(ui):
6920 if pendingphase > phases.newcommitphase(ui):
6921 t += b' (%s)' % phases.phasenames[pendingphase]
6921 t += b' (%s)' % phases.phasenames[pendingphase]
6922
6922
6923 if cleanworkdir:
6923 if cleanworkdir:
6924 # i18n: column positioning for "hg summary"
6924 # i18n: column positioning for "hg summary"
6925 ui.status(_(b'commit: %s\n') % t.strip())
6925 ui.status(_(b'commit: %s\n') % t.strip())
6926 else:
6926 else:
6927 # i18n: column positioning for "hg summary"
6927 # i18n: column positioning for "hg summary"
6928 ui.write(_(b'commit: %s\n') % t.strip())
6928 ui.write(_(b'commit: %s\n') % t.strip())
6929
6929
6930 # all ancestors of branch heads - all ancestors of parent = new csets
6930 # all ancestors of branch heads - all ancestors of parent = new csets
6931 new = len(
6931 new = len(
6932 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6932 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6933 )
6933 )
6934
6934
6935 if new == 0:
6935 if new == 0:
6936 # i18n: column positioning for "hg summary"
6936 # i18n: column positioning for "hg summary"
6937 ui.status(_(b'update: (current)\n'))
6937 ui.status(_(b'update: (current)\n'))
6938 elif pnode not in bheads:
6938 elif pnode not in bheads:
6939 # i18n: column positioning for "hg summary"
6939 # i18n: column positioning for "hg summary"
6940 ui.write(_(b'update: %d new changesets (update)\n') % new)
6940 ui.write(_(b'update: %d new changesets (update)\n') % new)
6941 else:
6941 else:
6942 # i18n: column positioning for "hg summary"
6942 # i18n: column positioning for "hg summary"
6943 ui.write(
6943 ui.write(
6944 _(b'update: %d new changesets, %d branch heads (merge)\n')
6944 _(b'update: %d new changesets, %d branch heads (merge)\n')
6945 % (new, len(bheads))
6945 % (new, len(bheads))
6946 )
6946 )
6947
6947
6948 t = []
6948 t = []
6949 draft = len(repo.revs(b'draft()'))
6949 draft = len(repo.revs(b'draft()'))
6950 if draft:
6950 if draft:
6951 t.append(_(b'%d draft') % draft)
6951 t.append(_(b'%d draft') % draft)
6952 secret = len(repo.revs(b'secret()'))
6952 secret = len(repo.revs(b'secret()'))
6953 if secret:
6953 if secret:
6954 t.append(_(b'%d secret') % secret)
6954 t.append(_(b'%d secret') % secret)
6955
6955
6956 if draft or secret:
6956 if draft or secret:
6957 ui.status(_(b'phases: %s\n') % b', '.join(t))
6957 ui.status(_(b'phases: %s\n') % b', '.join(t))
6958
6958
6959 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6959 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6960 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6960 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6961 numtrouble = len(repo.revs(trouble + b"()"))
6961 numtrouble = len(repo.revs(trouble + b"()"))
6962 # We write all the possibilities to ease translation
6962 # We write all the possibilities to ease translation
6963 troublemsg = {
6963 troublemsg = {
6964 b"orphan": _(b"orphan: %d changesets"),
6964 b"orphan": _(b"orphan: %d changesets"),
6965 b"contentdivergent": _(b"content-divergent: %d changesets"),
6965 b"contentdivergent": _(b"content-divergent: %d changesets"),
6966 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6966 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6967 }
6967 }
6968 if numtrouble > 0:
6968 if numtrouble > 0:
6969 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6969 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6970
6970
6971 cmdutil.summaryhooks(ui, repo)
6971 cmdutil.summaryhooks(ui, repo)
6972
6972
6973 if opts.get('remote'):
6973 if opts.get('remote'):
6974 needsincoming, needsoutgoing = True, True
6974 needsincoming, needsoutgoing = True, True
6975 else:
6975 else:
6976 needsincoming, needsoutgoing = False, False
6976 needsincoming, needsoutgoing = False, False
6977 for i, o in cmdutil.summaryremotehooks(
6977 for i, o in cmdutil.summaryremotehooks(
6978 ui, repo, pycompat.byteskwargs(opts), None
6978 ui, repo, pycompat.byteskwargs(opts), None
6979 ):
6979 ):
6980 if i:
6980 if i:
6981 needsincoming = True
6981 needsincoming = True
6982 if o:
6982 if o:
6983 needsoutgoing = True
6983 needsoutgoing = True
6984 if not needsincoming and not needsoutgoing:
6984 if not needsincoming and not needsoutgoing:
6985 return
6985 return
6986
6986
6987 def getincoming():
6987 def getincoming():
6988 # XXX We should actually skip this if no default is specified, instead
6988 # XXX We should actually skip this if no default is specified, instead
6989 # of passing "default" which will resolve as "./default/" if no default
6989 # of passing "default" which will resolve as "./default/" if no default
6990 # path is defined.
6990 # path is defined.
6991 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
6991 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
6992 sbranch = path.branch
6992 sbranch = path.branch
6993 try:
6993 try:
6994 other = hg.peer(repo, {}, path)
6994 other = hg.peer(repo, {}, path)
6995 except error.RepoError:
6995 except error.RepoError:
6996 if opts.get('remote'):
6996 if opts.get('remote'):
6997 raise
6997 raise
6998 return path.loc, sbranch, None, None, None
6998 return path.loc, sbranch, None, None, None
6999 branches = (path.branch, [])
6999 branches = (path.branch, [])
7000 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7000 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7001 if revs:
7001 if revs:
7002 revs = [other.lookup(rev) for rev in revs]
7002 revs = [other.lookup(rev) for rev in revs]
7003 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7003 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7004 with repo.ui.silent():
7004 with repo.ui.silent():
7005 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7005 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7006 return path.loc, sbranch, other, commoninc, commoninc[1]
7006 return path.loc, sbranch, other, commoninc, commoninc[1]
7007
7007
7008 if needsincoming:
7008 if needsincoming:
7009 source, sbranch, sother, commoninc, incoming = getincoming()
7009 source, sbranch, sother, commoninc, incoming = getincoming()
7010 else:
7010 else:
7011 source = sbranch = sother = commoninc = incoming = None
7011 source = sbranch = sother = commoninc = incoming = None
7012
7012
7013 def getoutgoing():
7013 def getoutgoing():
7014 # XXX We should actually skip this if no default is specified, instead
7014 # XXX We should actually skip this if no default is specified, instead
7015 # of passing "default" which will resolve as "./default/" if no default
7015 # of passing "default" which will resolve as "./default/" if no default
7016 # path is defined.
7016 # path is defined.
7017 d = None
7017 d = None
7018 if b'default-push' in ui.paths:
7018 if b'default-push' in ui.paths:
7019 d = b'default-push'
7019 d = b'default-push'
7020 elif b'default' in ui.paths:
7020 elif b'default' in ui.paths:
7021 d = b'default'
7021 d = b'default'
7022 path = None
7022 path = None
7023 if d is not None:
7023 if d is not None:
7024 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7024 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7025 dest = path.loc
7025 dest = path.loc
7026 dbranch = path.branch
7026 dbranch = path.branch
7027 else:
7027 else:
7028 dest = b'default'
7028 dest = b'default'
7029 dbranch = None
7029 dbranch = None
7030 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7030 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7031 if source != dest:
7031 if source != dest:
7032 try:
7032 try:
7033 dother = hg.peer(repo, {}, path if path is not None else dest)
7033 dother = hg.peer(repo, {}, path if path is not None else dest)
7034 except error.RepoError:
7034 except error.RepoError:
7035 if opts.get('remote'):
7035 if opts.get('remote'):
7036 raise
7036 raise
7037 return dest, dbranch, None, None
7037 return dest, dbranch, None, None
7038 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7038 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7039 elif sother is None:
7039 elif sother is None:
7040 # there is no explicit destination peer, but source one is invalid
7040 # there is no explicit destination peer, but source one is invalid
7041 return dest, dbranch, None, None
7041 return dest, dbranch, None, None
7042 else:
7042 else:
7043 dother = sother
7043 dother = sother
7044 if source != dest or (sbranch is not None and sbranch != dbranch):
7044 if source != dest or (sbranch is not None and sbranch != dbranch):
7045 common = None
7045 common = None
7046 else:
7046 else:
7047 common = commoninc
7047 common = commoninc
7048 if revs:
7048 if revs:
7049 revs = [repo.lookup(rev) for rev in revs]
7049 revs = [repo.lookup(rev) for rev in revs]
7050 with repo.ui.silent():
7050 with repo.ui.silent():
7051 outgoing = discovery.findcommonoutgoing(
7051 outgoing = discovery.findcommonoutgoing(
7052 repo, dother, onlyheads=revs, commoninc=common
7052 repo, dother, onlyheads=revs, commoninc=common
7053 )
7053 )
7054 return dest, dbranch, dother, outgoing
7054 return dest, dbranch, dother, outgoing
7055
7055
7056 if needsoutgoing:
7056 if needsoutgoing:
7057 dest, dbranch, dother, outgoing = getoutgoing()
7057 dest, dbranch, dother, outgoing = getoutgoing()
7058 else:
7058 else:
7059 dest = dbranch = dother = outgoing = None
7059 dest = dbranch = dother = outgoing = None
7060
7060
7061 if opts.get('remote'):
7061 if opts.get('remote'):
7062 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7062 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7063 # The former always sets `sother` (or raises an exception if it can't);
7063 # The former always sets `sother` (or raises an exception if it can't);
7064 # the latter always sets `outgoing`.
7064 # the latter always sets `outgoing`.
7065 assert sother is not None
7065 assert sother is not None
7066 assert outgoing is not None
7066 assert outgoing is not None
7067
7067
7068 t = []
7068 t = []
7069 if incoming:
7069 if incoming:
7070 t.append(_(b'1 or more incoming'))
7070 t.append(_(b'1 or more incoming'))
7071 o = outgoing.missing
7071 o = outgoing.missing
7072 if o:
7072 if o:
7073 t.append(_(b'%d outgoing') % len(o))
7073 t.append(_(b'%d outgoing') % len(o))
7074 other = dother or sother
7074 other = dother or sother
7075 if b'bookmarks' in other.listkeys(b'namespaces'):
7075 if b'bookmarks' in other.listkeys(b'namespaces'):
7076 counts = bookmarks.summary(repo, other)
7076 counts = bookmarks.summary(repo, other)
7077 if counts[0] > 0:
7077 if counts[0] > 0:
7078 t.append(_(b'%d incoming bookmarks') % counts[0])
7078 t.append(_(b'%d incoming bookmarks') % counts[0])
7079 if counts[1] > 0:
7079 if counts[1] > 0:
7080 t.append(_(b'%d outgoing bookmarks') % counts[1])
7080 t.append(_(b'%d outgoing bookmarks') % counts[1])
7081
7081
7082 if t:
7082 if t:
7083 # i18n: column positioning for "hg summary"
7083 # i18n: column positioning for "hg summary"
7084 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7084 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7085 else:
7085 else:
7086 # i18n: column positioning for "hg summary"
7086 # i18n: column positioning for "hg summary"
7087 ui.status(_(b'remote: (synced)\n'))
7087 ui.status(_(b'remote: (synced)\n'))
7088
7088
7089 cmdutil.summaryremotehooks(
7089 cmdutil.summaryremotehooks(
7090 ui,
7090 ui,
7091 repo,
7091 repo,
7092 pycompat.byteskwargs(opts),
7092 pycompat.byteskwargs(opts),
7093 (
7093 (
7094 (source, sbranch, sother, commoninc),
7094 (source, sbranch, sother, commoninc),
7095 (dest, dbranch, dother, outgoing),
7095 (dest, dbranch, dother, outgoing),
7096 ),
7096 ),
7097 )
7097 )
7098
7098
7099
7099
7100 @command(
7100 @command(
7101 b'tag',
7101 b'tag',
7102 [
7102 [
7103 (b'f', b'force', None, _(b'force tag')),
7103 (b'f', b'force', None, _(b'force tag')),
7104 (b'l', b'local', None, _(b'make the tag local')),
7104 (b'l', b'local', None, _(b'make the tag local')),
7105 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7105 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7106 (b'', b'remove', None, _(b'remove a tag')),
7106 (b'', b'remove', None, _(b'remove a tag')),
7107 # -l/--local is already there, commitopts cannot be used
7107 # -l/--local is already there, commitopts cannot be used
7108 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7108 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7109 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7109 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7110 ]
7110 ]
7111 + commitopts2,
7111 + commitopts2,
7112 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7112 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7113 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7113 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7114 )
7114 )
7115 def tag(ui, repo, name1, *names, **opts):
7115 def tag(ui, repo, name1, *names, **opts):
7116 """add one or more tags for the current or given revision
7116 """add one or more tags for the current or given revision
7117
7117
7118 Name a particular revision using <name>.
7118 Name a particular revision using <name>.
7119
7119
7120 Tags are used to name particular revisions of the repository and are
7120 Tags are used to name particular revisions of the repository and are
7121 very useful to compare different revisions, to go back to significant
7121 very useful to compare different revisions, to go back to significant
7122 earlier versions or to mark branch points as releases, etc. Changing
7122 earlier versions or to mark branch points as releases, etc. Changing
7123 an existing tag is normally disallowed; use -f/--force to override.
7123 an existing tag is normally disallowed; use -f/--force to override.
7124
7124
7125 If no revision is given, the parent of the working directory is
7125 If no revision is given, the parent of the working directory is
7126 used.
7126 used.
7127
7127
7128 To facilitate version control, distribution, and merging of tags,
7128 To facilitate version control, distribution, and merging of tags,
7129 they are stored as a file named ".hgtags" which is managed similarly
7129 they are stored as a file named ".hgtags" which is managed similarly
7130 to other project files and can be hand-edited if necessary. This
7130 to other project files and can be hand-edited if necessary. This
7131 also means that tagging creates a new commit. The file
7131 also means that tagging creates a new commit. The file
7132 ".hg/localtags" is used for local tags (not shared among
7132 ".hg/localtags" is used for local tags (not shared among
7133 repositories).
7133 repositories).
7134
7134
7135 Tag commits are usually made at the head of a branch. If the parent
7135 Tag commits are usually made at the head of a branch. If the parent
7136 of the working directory is not a branch head, :hg:`tag` aborts; use
7136 of the working directory is not a branch head, :hg:`tag` aborts; use
7137 -f/--force to force the tag commit to be based on a non-head
7137 -f/--force to force the tag commit to be based on a non-head
7138 changeset.
7138 changeset.
7139
7139
7140 See :hg:`help dates` for a list of formats valid for -d/--date.
7140 See :hg:`help dates` for a list of formats valid for -d/--date.
7141
7141
7142 Since tag names have priority over branch names during revision
7142 Since tag names have priority over branch names during revision
7143 lookup, using an existing branch name as a tag name is discouraged.
7143 lookup, using an existing branch name as a tag name is discouraged.
7144
7144
7145 Returns 0 on success.
7145 Returns 0 on success.
7146 """
7146 """
7147 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7147 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7148
7148
7149 with repo.wlock(), repo.lock():
7149 with repo.wlock(), repo.lock():
7150 rev_ = b"."
7150 rev_ = b"."
7151 names = [t.strip() for t in (name1,) + names]
7151 names = [t.strip() for t in (name1,) + names]
7152 if len(names) != len(set(names)):
7152 if len(names) != len(set(names)):
7153 raise error.InputError(_(b'tag names must be unique'))
7153 raise error.InputError(_(b'tag names must be unique'))
7154 for n in names:
7154 for n in names:
7155 scmutil.checknewlabel(repo, n, b'tag')
7155 scmutil.checknewlabel(repo, n, b'tag')
7156 if not n:
7156 if not n:
7157 raise error.InputError(
7157 raise error.InputError(
7158 _(b'tag names cannot consist entirely of whitespace')
7158 _(b'tag names cannot consist entirely of whitespace')
7159 )
7159 )
7160 if opts.get('rev'):
7160 if opts.get('rev'):
7161 rev_ = opts['rev']
7161 rev_ = opts['rev']
7162 message = opts.get('message')
7162 message = opts.get('message')
7163 if opts.get('remove'):
7163 if opts.get('remove'):
7164 if opts.get('local'):
7164 if opts.get('local'):
7165 expectedtype = b'local'
7165 expectedtype = b'local'
7166 else:
7166 else:
7167 expectedtype = b'global'
7167 expectedtype = b'global'
7168
7168
7169 for n in names:
7169 for n in names:
7170 if repo.tagtype(n) == b'global':
7170 if repo.tagtype(n) == b'global':
7171 alltags = tagsmod.findglobaltags(ui, repo)
7171 alltags = tagsmod.findglobaltags(ui, repo)
7172 if alltags[n][0] == repo.nullid:
7172 if alltags[n][0] == repo.nullid:
7173 raise error.InputError(
7173 raise error.InputError(
7174 _(b"tag '%s' is already removed") % n
7174 _(b"tag '%s' is already removed") % n
7175 )
7175 )
7176 if not repo.tagtype(n):
7176 if not repo.tagtype(n):
7177 raise error.InputError(_(b"tag '%s' does not exist") % n)
7177 raise error.InputError(_(b"tag '%s' does not exist") % n)
7178 if repo.tagtype(n) != expectedtype:
7178 if repo.tagtype(n) != expectedtype:
7179 if expectedtype == b'global':
7179 if expectedtype == b'global':
7180 raise error.InputError(
7180 raise error.InputError(
7181 _(b"tag '%s' is not a global tag") % n
7181 _(b"tag '%s' is not a global tag") % n
7182 )
7182 )
7183 else:
7183 else:
7184 raise error.InputError(
7184 raise error.InputError(
7185 _(b"tag '%s' is not a local tag") % n
7185 _(b"tag '%s' is not a local tag") % n
7186 )
7186 )
7187 rev_ = b'null'
7187 rev_ = b'null'
7188 if not message:
7188 if not message:
7189 # we don't translate commit messages
7189 # we don't translate commit messages
7190 message = b'Removed tag %s' % b', '.join(names)
7190 message = b'Removed tag %s' % b', '.join(names)
7191 elif not opts.get('force'):
7191 elif not opts.get('force'):
7192 for n in names:
7192 for n in names:
7193 if n in repo.tags():
7193 if n in repo.tags():
7194 raise error.InputError(
7194 raise error.InputError(
7195 _(b"tag '%s' already exists (use -f to force)") % n
7195 _(b"tag '%s' already exists (use -f to force)") % n
7196 )
7196 )
7197 if not opts.get('local'):
7197 if not opts.get('local'):
7198 p1, p2 = repo.dirstate.parents()
7198 p1, p2 = repo.dirstate.parents()
7199 if p2 != repo.nullid:
7199 if p2 != repo.nullid:
7200 raise error.StateError(_(b'uncommitted merge'))
7200 raise error.StateError(_(b'uncommitted merge'))
7201 bheads = repo.branchheads()
7201 bheads = repo.branchheads()
7202 if not opts.get('force') and bheads and p1 not in bheads:
7202 if not opts.get('force') and bheads and p1 not in bheads:
7203 raise error.InputError(
7203 raise error.InputError(
7204 _(
7204 _(
7205 b'working directory is not at a branch head '
7205 b'working directory is not at a branch head '
7206 b'(use -f to force)'
7206 b'(use -f to force)'
7207 )
7207 )
7208 )
7208 )
7209 node = logcmdutil.revsingle(repo, rev_).node()
7209 node = logcmdutil.revsingle(repo, rev_).node()
7210
7210
7211 # don't allow tagging the null rev or the working directory
7211 # don't allow tagging the null rev or the working directory
7212 if node is None:
7212 if node is None:
7213 raise error.InputError(_(b"cannot tag working directory"))
7213 raise error.InputError(_(b"cannot tag working directory"))
7214 elif not opts.get('remove') and node == nullid:
7214 elif not opts.get('remove') and node == nullid:
7215 raise error.InputError(_(b"cannot tag null revision"))
7215 raise error.InputError(_(b"cannot tag null revision"))
7216
7216
7217 if not message:
7217 if not message:
7218 # we don't translate commit messages
7218 # we don't translate commit messages
7219 message = b'Added tag %s for changeset %s' % (
7219 message = b'Added tag %s for changeset %s' % (
7220 b', '.join(names),
7220 b', '.join(names),
7221 short(node),
7221 short(node),
7222 )
7222 )
7223
7223
7224 date = opts.get('date')
7224 date = opts.get('date')
7225 if date:
7225 if date:
7226 date = dateutil.parsedate(date)
7226 date = dateutil.parsedate(date)
7227
7227
7228 if opts.get('remove'):
7228 if opts.get('remove'):
7229 editform = b'tag.remove'
7229 editform = b'tag.remove'
7230 else:
7230 else:
7231 editform = b'tag.add'
7231 editform = b'tag.add'
7232 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7232 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7233
7233
7234 tagsmod.tag(
7234 tagsmod.tag(
7235 repo,
7235 repo,
7236 names,
7236 names,
7237 node,
7237 node,
7238 message,
7238 message,
7239 opts.get('local'),
7239 opts.get('local'),
7240 opts.get('user'),
7240 opts.get('user'),
7241 date,
7241 date,
7242 editor=editor,
7242 editor=editor,
7243 )
7243 )
7244
7244
7245
7245
7246 @command(
7246 @command(
7247 b'tags',
7247 b'tags',
7248 formatteropts,
7248 formatteropts,
7249 b'',
7249 b'',
7250 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7250 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7251 intents={INTENT_READONLY},
7251 intents={INTENT_READONLY},
7252 )
7252 )
7253 def tags(ui, repo, **opts):
7253 def tags(ui, repo, **opts):
7254 """list repository tags
7254 """list repository tags
7255
7255
7256 This lists both regular and local tags. When the -v/--verbose
7256 This lists both regular and local tags. When the -v/--verbose
7257 switch is used, a third column "local" is printed for local tags.
7257 switch is used, a third column "local" is printed for local tags.
7258 When the -q/--quiet switch is used, only the tag name is printed.
7258 When the -q/--quiet switch is used, only the tag name is printed.
7259
7259
7260 .. container:: verbose
7260 .. container:: verbose
7261
7261
7262 Template:
7262 Template:
7263
7263
7264 The following keywords are supported in addition to the common template
7264 The following keywords are supported in addition to the common template
7265 keywords and functions such as ``{tag}``. See also
7265 keywords and functions such as ``{tag}``. See also
7266 :hg:`help templates`.
7266 :hg:`help templates`.
7267
7267
7268 :type: String. ``local`` for local tags.
7268 :type: String. ``local`` for local tags.
7269
7269
7270 Returns 0 on success.
7270 Returns 0 on success.
7271 """
7271 """
7272
7272
7273 ui.pager(b'tags')
7273 ui.pager(b'tags')
7274 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7274 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7275 hexfunc = fm.hexfunc
7275 hexfunc = fm.hexfunc
7276
7276
7277 for t, n in reversed(repo.tagslist()):
7277 for t, n in reversed(repo.tagslist()):
7278 hn = hexfunc(n)
7278 hn = hexfunc(n)
7279 label = b'tags.normal'
7279 label = b'tags.normal'
7280 tagtype = repo.tagtype(t)
7280 tagtype = repo.tagtype(t)
7281 if not tagtype or tagtype == b'global':
7281 if not tagtype or tagtype == b'global':
7282 tagtype = b''
7282 tagtype = b''
7283 else:
7283 else:
7284 label = b'tags.' + tagtype
7284 label = b'tags.' + tagtype
7285
7285
7286 fm.startitem()
7286 fm.startitem()
7287 fm.context(repo=repo)
7287 fm.context(repo=repo)
7288 fm.write(b'tag', b'%s', t, label=label)
7288 fm.write(b'tag', b'%s', t, label=label)
7289 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7289 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7290 fm.condwrite(
7290 fm.condwrite(
7291 not ui.quiet,
7291 not ui.quiet,
7292 b'rev node',
7292 b'rev node',
7293 fmt,
7293 fmt,
7294 repo.changelog.rev(n),
7294 repo.changelog.rev(n),
7295 hn,
7295 hn,
7296 label=label,
7296 label=label,
7297 )
7297 )
7298 fm.condwrite(
7298 fm.condwrite(
7299 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7299 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7300 )
7300 )
7301 fm.plain(b'\n')
7301 fm.plain(b'\n')
7302 fm.end()
7302 fm.end()
7303
7303
7304
7304
7305 @command(
7305 @command(
7306 b'tip',
7306 b'tip',
7307 [
7307 [
7308 (b'p', b'patch', None, _(b'show patch')),
7308 (b'p', b'patch', None, _(b'show patch')),
7309 (b'g', b'git', None, _(b'use git extended diff format')),
7309 (b'g', b'git', None, _(b'use git extended diff format')),
7310 ]
7310 ]
7311 + templateopts,
7311 + templateopts,
7312 _(b'[-p] [-g]'),
7312 _(b'[-p] [-g]'),
7313 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7313 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7314 )
7314 )
7315 def tip(ui, repo, **opts):
7315 def tip(ui, repo, **opts):
7316 """show the tip revision (DEPRECATED)
7316 """show the tip revision (DEPRECATED)
7317
7317
7318 The tip revision (usually just called the tip) is the changeset
7318 The tip revision (usually just called the tip) is the changeset
7319 most recently added to the repository (and therefore the most
7319 most recently added to the repository (and therefore the most
7320 recently changed head).
7320 recently changed head).
7321
7321
7322 If you have just made a commit, that commit will be the tip. If
7322 If you have just made a commit, that commit will be the tip. If
7323 you have just pulled changes from another repository, the tip of
7323 you have just pulled changes from another repository, the tip of
7324 that repository becomes the current tip. The "tip" tag is special
7324 that repository becomes the current tip. The "tip" tag is special
7325 and cannot be renamed or assigned to a different changeset.
7325 and cannot be renamed or assigned to a different changeset.
7326
7326
7327 This command is deprecated, please use :hg:`heads` instead.
7327 This command is deprecated, please use :hg:`heads` instead.
7328
7328
7329 Returns 0 on success.
7329 Returns 0 on success.
7330 """
7330 """
7331 opts = pycompat.byteskwargs(opts)
7331 opts = pycompat.byteskwargs(opts)
7332 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7332 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7333 displayer.show(repo[b'tip'])
7333 displayer.show(repo[b'tip'])
7334 displayer.close()
7334 displayer.close()
7335
7335
7336
7336
7337 @command(
7337 @command(
7338 b'unbundle',
7338 b'unbundle',
7339 [
7339 [
7340 (
7340 (
7341 b'u',
7341 b'u',
7342 b'update',
7342 b'update',
7343 None,
7343 None,
7344 _(b'update to new branch head if changesets were unbundled'),
7344 _(b'update to new branch head if changesets were unbundled'),
7345 )
7345 )
7346 ],
7346 ],
7347 _(b'[-u] FILE...'),
7347 _(b'[-u] FILE...'),
7348 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7348 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7349 )
7349 )
7350 def unbundle(ui, repo, fname1, *fnames, **opts):
7350 def unbundle(ui, repo, fname1, *fnames, **opts):
7351 """apply one or more bundle files
7351 """apply one or more bundle files
7352
7352
7353 Apply one or more bundle files generated by :hg:`bundle`.
7353 Apply one or more bundle files generated by :hg:`bundle`.
7354
7354
7355 Returns 0 on success, 1 if an update has unresolved files.
7355 Returns 0 on success, 1 if an update has unresolved files.
7356 """
7356 """
7357 fnames = (fname1,) + fnames
7357 fnames = (fname1,) + fnames
7358 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7358 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7359
7359
7360 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7360 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7361 return 1
7361 return 1
7362 else:
7362 else:
7363 return 0
7363 return 0
7364
7364
7365
7365
7366 @command(
7366 @command(
7367 b'unshelve',
7367 b'unshelve',
7368 [
7368 [
7369 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7369 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7370 (
7370 (
7371 b'c',
7371 b'c',
7372 b'continue',
7372 b'continue',
7373 None,
7373 None,
7374 _(b'continue an incomplete unshelve operation'),
7374 _(b'continue an incomplete unshelve operation'),
7375 ),
7375 ),
7376 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7376 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7377 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7377 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7378 (
7378 (
7379 b'n',
7379 b'n',
7380 b'name',
7380 b'name',
7381 b'',
7381 b'',
7382 _(b'restore shelved change with given name'),
7382 _(b'restore shelved change with given name'),
7383 _(b'NAME'),
7383 _(b'NAME'),
7384 ),
7384 ),
7385 (b't', b'tool', b'', _(b'specify merge tool')),
7385 (b't', b'tool', b'', _(b'specify merge tool')),
7386 (
7386 (
7387 b'',
7387 b'',
7388 b'date',
7388 b'date',
7389 b'',
7389 b'',
7390 _(b'set date for temporary commits (DEPRECATED)'),
7390 _(b'set date for temporary commits (DEPRECATED)'),
7391 _(b'DATE'),
7391 _(b'DATE'),
7392 ),
7392 ),
7393 ],
7393 ],
7394 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7394 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7395 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7395 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7396 )
7396 )
7397 def unshelve(ui, repo, *shelved, **opts):
7397 def unshelve(ui, repo, *shelved, **opts):
7398 """restore a shelved change to the working directory
7398 """restore a shelved change to the working directory
7399
7399
7400 This command accepts an optional name of a shelved change to
7400 This command accepts an optional name of a shelved change to
7401 restore. If none is given, the most recent shelved change is used.
7401 restore. If none is given, the most recent shelved change is used.
7402
7402
7403 If a shelved change is applied successfully, the bundle that
7403 If a shelved change is applied successfully, the bundle that
7404 contains the shelved changes is moved to a backup location
7404 contains the shelved changes is moved to a backup location
7405 (.hg/shelve-backup).
7405 (.hg/shelve-backup).
7406
7406
7407 Since you can restore a shelved change on top of an arbitrary
7407 Since you can restore a shelved change on top of an arbitrary
7408 commit, it is possible that unshelving will result in a conflict
7408 commit, it is possible that unshelving will result in a conflict
7409 between your changes and the commits you are unshelving onto. If
7409 between your changes and the commits you are unshelving onto. If
7410 this occurs, you must resolve the conflict, then use
7410 this occurs, you must resolve the conflict, then use
7411 ``--continue`` to complete the unshelve operation. (The bundle
7411 ``--continue`` to complete the unshelve operation. (The bundle
7412 will not be moved until you successfully complete the unshelve.)
7412 will not be moved until you successfully complete the unshelve.)
7413
7413
7414 (Alternatively, you can use ``--abort`` to abandon an unshelve
7414 (Alternatively, you can use ``--abort`` to abandon an unshelve
7415 that causes a conflict. This reverts the unshelved changes, and
7415 that causes a conflict. This reverts the unshelved changes, and
7416 leaves the bundle in place.)
7416 leaves the bundle in place.)
7417
7417
7418 If bare shelved change (without interactive, include and exclude
7418 If bare shelved change (without interactive, include and exclude
7419 option) was done on newly created branch it would restore branch
7419 option) was done on newly created branch it would restore branch
7420 information to the working directory.
7420 information to the working directory.
7421
7421
7422 After a successful unshelve, the shelved changes are stored in a
7422 After a successful unshelve, the shelved changes are stored in a
7423 backup directory. Only the N most recent backups are kept. N
7423 backup directory. Only the N most recent backups are kept. N
7424 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7424 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7425 configuration option.
7425 configuration option.
7426
7426
7427 .. container:: verbose
7427 .. container:: verbose
7428
7428
7429 Timestamp in seconds is used to decide order of backups. More
7429 Timestamp in seconds is used to decide order of backups. More
7430 than ``maxbackups`` backups are kept, if same timestamp
7430 than ``maxbackups`` backups are kept, if same timestamp
7431 prevents from deciding exact order of them, for safety.
7431 prevents from deciding exact order of them, for safety.
7432
7432
7433 Selected changes can be unshelved with ``--interactive`` flag.
7433 Selected changes can be unshelved with ``--interactive`` flag.
7434 The working directory is updated with the selected changes, and
7434 The working directory is updated with the selected changes, and
7435 only the unselected changes remain shelved.
7435 only the unselected changes remain shelved.
7436 Note: The whole shelve is applied to working directory first before
7436 Note: The whole shelve is applied to working directory first before
7437 running interactively. So, this will bring up all the conflicts between
7437 running interactively. So, this will bring up all the conflicts between
7438 working directory and the shelve, irrespective of which changes will be
7438 working directory and the shelve, irrespective of which changes will be
7439 unshelved.
7439 unshelved.
7440 """
7440 """
7441 with repo.wlock():
7441 with repo.wlock():
7442 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7442 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7443
7443
7444
7444
7445 statemod.addunfinished(
7445 statemod.addunfinished(
7446 b'unshelve',
7446 b'unshelve',
7447 fname=b'shelvedstate',
7447 fname=b'shelvedstate',
7448 continueflag=True,
7448 continueflag=True,
7449 abortfunc=shelvemod.hgabortunshelve,
7449 abortfunc=shelvemod.hgabortunshelve,
7450 continuefunc=shelvemod.hgcontinueunshelve,
7450 continuefunc=shelvemod.hgcontinueunshelve,
7451 cmdmsg=_(b'unshelve already in progress'),
7451 cmdmsg=_(b'unshelve already in progress'),
7452 )
7452 )
7453
7453
7454
7454
7455 @command(
7455 @command(
7456 b'update|up|checkout|co',
7456 b'update|up|checkout|co',
7457 [
7457 [
7458 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7458 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7459 (b'c', b'check', None, _(b'require clean working directory')),
7459 (b'c', b'check', None, _(b'require clean working directory')),
7460 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7460 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7461 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7461 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7462 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7462 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7463 ]
7463 ]
7464 + mergetoolopts,
7464 + mergetoolopts,
7465 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7465 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7466 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7466 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7467 helpbasic=True,
7467 helpbasic=True,
7468 )
7468 )
7469 def update(ui, repo, node=None, **opts):
7469 def update(ui, repo, node=None, **opts):
7470 """update working directory (or switch revisions)
7470 """update working directory (or switch revisions)
7471
7471
7472 Update the repository's working directory to the specified
7472 Update the repository's working directory to the specified
7473 changeset. If no changeset is specified, update to the tip of the
7473 changeset. If no changeset is specified, update to the tip of the
7474 current named branch and move the active bookmark (see :hg:`help
7474 current named branch and move the active bookmark (see :hg:`help
7475 bookmarks`).
7475 bookmarks`).
7476
7476
7477 Update sets the working directory's parent revision to the specified
7477 Update sets the working directory's parent revision to the specified
7478 changeset (see :hg:`help parents`).
7478 changeset (see :hg:`help parents`).
7479
7479
7480 If the changeset is not a descendant or ancestor of the working
7480 If the changeset is not a descendant or ancestor of the working
7481 directory's parent and there are uncommitted changes, the update is
7481 directory's parent and there are uncommitted changes, the update is
7482 aborted. With the -c/--check option, the working directory is checked
7482 aborted. With the -c/--check option, the working directory is checked
7483 for uncommitted changes; if none are found, the working directory is
7483 for uncommitted changes; if none are found, the working directory is
7484 updated to the specified changeset.
7484 updated to the specified changeset.
7485
7485
7486 .. container:: verbose
7486 .. container:: verbose
7487
7487
7488 The -C/--clean, -c/--check, and -m/--merge options control what
7488 The -C/--clean, -c/--check, and -m/--merge options control what
7489 happens if the working directory contains uncommitted changes.
7489 happens if the working directory contains uncommitted changes.
7490 At most of one of them can be specified.
7490 At most of one of them can be specified.
7491
7491
7492 1. If no option is specified, and if
7492 1. If no option is specified, and if
7493 the requested changeset is an ancestor or descendant of
7493 the requested changeset is an ancestor or descendant of
7494 the working directory's parent, the uncommitted changes
7494 the working directory's parent, the uncommitted changes
7495 are merged into the requested changeset and the merged
7495 are merged into the requested changeset and the merged
7496 result is left uncommitted. If the requested changeset is
7496 result is left uncommitted. If the requested changeset is
7497 not an ancestor or descendant (that is, it is on another
7497 not an ancestor or descendant (that is, it is on another
7498 branch), the update is aborted and the uncommitted changes
7498 branch), the update is aborted and the uncommitted changes
7499 are preserved.
7499 are preserved.
7500
7500
7501 2. With the -m/--merge option, the update is allowed even if the
7501 2. With the -m/--merge option, the update is allowed even if the
7502 requested changeset is not an ancestor or descendant of
7502 requested changeset is not an ancestor or descendant of
7503 the working directory's parent.
7503 the working directory's parent.
7504
7504
7505 3. With the -c/--check option, the update is aborted and the
7505 3. With the -c/--check option, the update is aborted and the
7506 uncommitted changes are preserved.
7506 uncommitted changes are preserved.
7507
7507
7508 4. With the -C/--clean option, uncommitted changes are discarded and
7508 4. With the -C/--clean option, uncommitted changes are discarded and
7509 the working directory is updated to the requested changeset.
7509 the working directory is updated to the requested changeset.
7510
7510
7511 To cancel an uncommitted merge (and lose your changes), use
7511 To cancel an uncommitted merge (and lose your changes), use
7512 :hg:`merge --abort`.
7512 :hg:`merge --abort`.
7513
7513
7514 Use null as the changeset to remove the working directory (like
7514 Use null as the changeset to remove the working directory (like
7515 :hg:`clone -U`).
7515 :hg:`clone -U`).
7516
7516
7517 If you want to revert just one file to an older revision, use
7517 If you want to revert just one file to an older revision, use
7518 :hg:`revert [-r REV] NAME`.
7518 :hg:`revert [-r REV] NAME`.
7519
7519
7520 See :hg:`help dates` for a list of formats valid for -d/--date.
7520 See :hg:`help dates` for a list of formats valid for -d/--date.
7521
7521
7522 Returns 0 on success, 1 if there are unresolved files.
7522 Returns 0 on success, 1 if there are unresolved files.
7523 """
7523 """
7524 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7524 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7525 rev = opts.get('rev')
7525 rev = opts.get('rev')
7526 date = opts.get('date')
7526 date = opts.get('date')
7527 clean = opts.get('clean')
7527 clean = opts.get('clean')
7528 check = opts.get('check')
7528 check = opts.get('check')
7529 merge = opts.get('merge')
7529 merge = opts.get('merge')
7530 if rev and node:
7530 if rev and node:
7531 raise error.InputError(_(b"please specify just one revision"))
7531 raise error.InputError(_(b"please specify just one revision"))
7532
7532
7533 if ui.configbool(b'commands', b'update.requiredest'):
7533 if ui.configbool(b'commands', b'update.requiredest'):
7534 if not node and not rev and not date:
7534 if not node and not rev and not date:
7535 raise error.InputError(
7535 raise error.InputError(
7536 _(b'you must specify a destination'),
7536 _(b'you must specify a destination'),
7537 hint=_(b'for example: hg update ".::"'),
7537 hint=_(b'for example: hg update ".::"'),
7538 )
7538 )
7539
7539
7540 if rev is None or rev == b'':
7540 if rev is None or rev == b'':
7541 rev = node
7541 rev = node
7542
7542
7543 if date and rev is not None:
7543 if date and rev is not None:
7544 raise error.InputError(_(b"you can't specify a revision and a date"))
7544 raise error.InputError(_(b"you can't specify a revision and a date"))
7545
7545
7546 updatecheck = None
7546 updatecheck = None
7547 if check or merge is not None and not merge:
7547 if check or merge is not None and not merge:
7548 updatecheck = b'abort'
7548 updatecheck = b'abort'
7549 elif merge or check is not None and not check:
7549 elif merge or check is not None and not check:
7550 updatecheck = b'none'
7550 updatecheck = b'none'
7551
7551
7552 with repo.wlock():
7552 with repo.wlock():
7553 cmdutil.clearunfinished(repo)
7553 cmdutil.clearunfinished(repo)
7554 if date:
7554 if date:
7555 rev = cmdutil.finddate(ui, repo, date)
7555 rev = cmdutil.finddate(ui, repo, date)
7556
7556
7557 # if we defined a bookmark, we have to remember the original name
7557 # if we defined a bookmark, we have to remember the original name
7558 brev = rev
7558 brev = rev
7559 if rev:
7559 if rev:
7560 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7560 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7561 ctx = logcmdutil.revsingle(repo, rev, default=None)
7561 ctx = logcmdutil.revsingle(repo, rev, default=None)
7562 rev = ctx.rev()
7562 rev = ctx.rev()
7563 hidden = ctx.hidden()
7563 hidden = ctx.hidden()
7564 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7564 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7565 with ui.configoverride(overrides, b'update'):
7565 with ui.configoverride(overrides, b'update'):
7566 ret = hg.updatetotally(
7566 ret = hg.updatetotally(
7567 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7567 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7568 )
7568 )
7569 if hidden:
7569 if hidden:
7570 ctxstr = ctx.hex()[:12]
7570 ctxstr = ctx.hex()[:12]
7571 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7571 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7572
7572
7573 if ctx.obsolete():
7573 if ctx.obsolete():
7574 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7574 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7575 ui.warn(b"(%s)\n" % obsfatemsg)
7575 ui.warn(b"(%s)\n" % obsfatemsg)
7576 return ret
7576 return ret
7577
7577
7578
7578
7579 @command(
7579 @command(
7580 b'verify',
7580 b'verify',
7581 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7581 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7582 helpcategory=command.CATEGORY_MAINTENANCE,
7582 helpcategory=command.CATEGORY_MAINTENANCE,
7583 )
7583 )
7584 def verify(ui, repo, **opts):
7584 def verify(ui, repo, **opts):
7585 """verify the integrity of the repository
7585 """verify the integrity of the repository
7586
7586
7587 Verify the integrity of the current repository.
7587 Verify the integrity of the current repository.
7588
7588
7589 This will perform an extensive check of the repository's
7589 This will perform an extensive check of the repository's
7590 integrity, validating the hashes and checksums of each entry in
7590 integrity, validating the hashes and checksums of each entry in
7591 the changelog, manifest, and tracked files, as well as the
7591 the changelog, manifest, and tracked files, as well as the
7592 integrity of their crosslinks and indices.
7592 integrity of their crosslinks and indices.
7593
7593
7594 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7594 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7595 for more information about recovery from corruption of the
7595 for more information about recovery from corruption of the
7596 repository.
7596 repository.
7597
7597
7598 For an alternative UI with a lot more control over the verification
7598 For an alternative UI with a lot more control over the verification
7599 process and better error reporting, try `hg help admin::verify`.
7599 process and better error reporting, try `hg help admin::verify`.
7600
7600
7601 Returns 0 on success, 1 if errors are encountered.
7601 Returns 0 on success, 1 if errors are encountered.
7602 """
7602 """
7603 level = None
7603 level = None
7604 if opts['full']:
7604 if opts['full']:
7605 level = verifymod.VERIFY_FULL
7605 level = verifymod.VERIFY_FULL
7606 return hg.verify(repo, level)
7606 return hg.verify(repo, level)
7607
7607
7608
7608
7609 @command(
7609 @command(
7610 b'version',
7610 b'version',
7611 [] + formatteropts,
7611 [] + formatteropts,
7612 helpcategory=command.CATEGORY_HELP,
7612 helpcategory=command.CATEGORY_HELP,
7613 norepo=True,
7613 norepo=True,
7614 intents={INTENT_READONLY},
7614 intents={INTENT_READONLY},
7615 )
7615 )
7616 def version_(ui, **opts):
7616 def version_(ui, **opts):
7617 """output version and copyright information
7617 """output version and copyright information
7618
7618
7619 .. container:: verbose
7619 .. container:: verbose
7620
7620
7621 Template:
7621 Template:
7622
7622
7623 The following keywords are supported. See also :hg:`help templates`.
7623 The following keywords are supported. See also :hg:`help templates`.
7624
7624
7625 :extensions: List of extensions.
7625 :extensions: List of extensions.
7626 :ver: String. Version number.
7626 :ver: String. Version number.
7627
7627
7628 And each entry of ``{extensions}`` provides the following sub-keywords
7628 And each entry of ``{extensions}`` provides the following sub-keywords
7629 in addition to ``{ver}``.
7629 in addition to ``{ver}``.
7630
7630
7631 :bundled: Boolean. True if included in the release.
7631 :bundled: Boolean. True if included in the release.
7632 :name: String. Extension name.
7632 :name: String. Extension name.
7633 """
7633 """
7634 if ui.verbose:
7634 if ui.verbose:
7635 ui.pager(b'version')
7635 ui.pager(b'version')
7636 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7636 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7637 fm.startitem()
7637 fm.startitem()
7638 fm.write(
7638 fm.write(
7639 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7639 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7640 )
7640 )
7641 license = _(
7641 license = _(
7642 b"(see https://mercurial-scm.org for more information)\n"
7642 b"(see https://mercurial-scm.org for more information)\n"
7643 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7643 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7644 b"This is free software; see the source for copying conditions. "
7644 b"This is free software; see the source for copying conditions. "
7645 b"There is NO\nwarranty; "
7645 b"There is NO\nwarranty; "
7646 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7646 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7647 )
7647 )
7648 if not ui.quiet:
7648 if not ui.quiet:
7649 fm.plain(license)
7649 fm.plain(license)
7650
7650
7651 if ui.verbose:
7651 if ui.verbose:
7652 fm.plain(_(b"\nEnabled extensions:\n\n"))
7652 fm.plain(_(b"\nEnabled extensions:\n\n"))
7653 # format names and versions into columns
7653 # format names and versions into columns
7654 names = []
7654 names = []
7655 vers = []
7655 vers = []
7656 isinternals = []
7656 isinternals = []
7657 for name, module in sorted(extensions.extensions()):
7657 for name, module in sorted(extensions.extensions()):
7658 names.append(name)
7658 names.append(name)
7659 vers.append(extensions.moduleversion(module) or None)
7659 vers.append(extensions.moduleversion(module) or None)
7660 isinternals.append(extensions.ismoduleinternal(module))
7660 isinternals.append(extensions.ismoduleinternal(module))
7661 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7661 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7662 if names:
7662 if names:
7663 namefmt = b" %%-%ds " % max(len(n) for n in names)
7663 namefmt = b" %%-%ds " % max(len(n) for n in names)
7664 places = [_(b"external"), _(b"internal")]
7664 places = [_(b"external"), _(b"internal")]
7665 for n, v, p in zip(names, vers, isinternals):
7665 for n, v, p in zip(names, vers, isinternals):
7666 fn.startitem()
7666 fn.startitem()
7667 fn.condwrite(ui.verbose, b"name", namefmt, n)
7667 fn.condwrite(ui.verbose, b"name", namefmt, n)
7668 if ui.verbose:
7668 if ui.verbose:
7669 fn.plain(b"%s " % places[p])
7669 fn.plain(b"%s " % places[p])
7670 fn.data(bundled=p)
7670 fn.data(bundled=p)
7671 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7671 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7672 if ui.verbose:
7672 if ui.verbose:
7673 fn.plain(b"\n")
7673 fn.plain(b"\n")
7674 fn.end()
7674 fn.end()
7675 fm.end()
7675 fm.end()
7676
7676
7677
7677
7678 def loadcmdtable(ui, name, cmdtable):
7678 def loadcmdtable(ui, name, cmdtable):
7679 """Load command functions from specified cmdtable"""
7679 """Load command functions from specified cmdtable"""
7680 overrides = [cmd for cmd in cmdtable if cmd in table]
7680 overrides = [cmd for cmd in cmdtable if cmd in table]
7681 if overrides:
7681 if overrides:
7682 ui.warn(
7682 ui.warn(
7683 _(b"extension '%s' overrides commands: %s\n")
7683 _(b"extension '%s' overrides commands: %s\n")
7684 % (name, b" ".join(overrides))
7684 % (name, b" ".join(overrides))
7685 )
7685 )
7686 table.update(cmdtable)
7686 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now