##// END OF EJS Templates
paths: use `list_paths` in `hg paths`...
marmoute -
r47795:9bfe3818 default draft
parent child Browse files
Show More
@@ -1,7946 +1,7940 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 wdirrev,
20 wdirrev,
21 )
21 )
22 from .pycompat import open
22 from .pycompat import open
23 from . import (
23 from . import (
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 dirstateguard,
33 dirstateguard,
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 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 requirements,
57 requirements,
58 revsetlang,
58 revsetlang,
59 rewriteutil,
59 rewriteutil,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 shelve as shelvemod,
62 shelve as shelvemod,
63 state as statemod,
63 state as statemod,
64 streamclone,
64 streamclone,
65 tags as tagsmod,
65 tags as tagsmod,
66 ui as uimod,
66 ui as uimod,
67 util,
67 util,
68 verify as verifymod,
68 verify as verifymod,
69 vfs as vfsmod,
69 vfs as vfsmod,
70 wireprotoserver,
70 wireprotoserver,
71 )
71 )
72 from .utils import (
72 from .utils import (
73 dateutil,
73 dateutil,
74 stringutil,
74 stringutil,
75 urlutil,
75 urlutil,
76 )
76 )
77
77
78 if pycompat.TYPE_CHECKING:
78 if pycompat.TYPE_CHECKING:
79 from typing import (
79 from typing import (
80 List,
80 List,
81 )
81 )
82
82
83
83
84 table = {}
84 table = {}
85 table.update(debugcommandsmod.command._table)
85 table.update(debugcommandsmod.command._table)
86
86
87 command = registrar.command(table)
87 command = registrar.command(table)
88 INTENT_READONLY = registrar.INTENT_READONLY
88 INTENT_READONLY = registrar.INTENT_READONLY
89
89
90 # common command options
90 # common command options
91
91
92 globalopts = [
92 globalopts = [
93 (
93 (
94 b'R',
94 b'R',
95 b'repository',
95 b'repository',
96 b'',
96 b'',
97 _(b'repository root directory or name of overlay bundle file'),
97 _(b'repository root directory or name of overlay bundle file'),
98 _(b'REPO'),
98 _(b'REPO'),
99 ),
99 ),
100 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
100 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
101 (
101 (
102 b'y',
102 b'y',
103 b'noninteractive',
103 b'noninteractive',
104 None,
104 None,
105 _(
105 _(
106 b'do not prompt, automatically pick the first choice for all prompts'
106 b'do not prompt, automatically pick the first choice for all prompts'
107 ),
107 ),
108 ),
108 ),
109 (b'q', b'quiet', None, _(b'suppress output')),
109 (b'q', b'quiet', None, _(b'suppress output')),
110 (b'v', b'verbose', None, _(b'enable additional output')),
110 (b'v', b'verbose', None, _(b'enable additional output')),
111 (
111 (
112 b'',
112 b'',
113 b'color',
113 b'color',
114 b'',
114 b'',
115 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
115 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
116 # and should not be translated
116 # and should not be translated
117 _(b"when to colorize (boolean, always, auto, never, or debug)"),
117 _(b"when to colorize (boolean, always, auto, never, or debug)"),
118 _(b'TYPE'),
118 _(b'TYPE'),
119 ),
119 ),
120 (
120 (
121 b'',
121 b'',
122 b'config',
122 b'config',
123 [],
123 [],
124 _(b'set/override config option (use \'section.name=value\')'),
124 _(b'set/override config option (use \'section.name=value\')'),
125 _(b'CONFIG'),
125 _(b'CONFIG'),
126 ),
126 ),
127 (b'', b'debug', None, _(b'enable debugging output')),
127 (b'', b'debug', None, _(b'enable debugging output')),
128 (b'', b'debugger', None, _(b'start debugger')),
128 (b'', b'debugger', None, _(b'start debugger')),
129 (
129 (
130 b'',
130 b'',
131 b'encoding',
131 b'encoding',
132 encoding.encoding,
132 encoding.encoding,
133 _(b'set the charset encoding'),
133 _(b'set the charset encoding'),
134 _(b'ENCODE'),
134 _(b'ENCODE'),
135 ),
135 ),
136 (
136 (
137 b'',
137 b'',
138 b'encodingmode',
138 b'encodingmode',
139 encoding.encodingmode,
139 encoding.encodingmode,
140 _(b'set the charset encoding mode'),
140 _(b'set the charset encoding mode'),
141 _(b'MODE'),
141 _(b'MODE'),
142 ),
142 ),
143 (b'', b'traceback', None, _(b'always print a traceback on exception')),
143 (b'', b'traceback', None, _(b'always print a traceback on exception')),
144 (b'', b'time', None, _(b'time how long the command takes')),
144 (b'', b'time', None, _(b'time how long the command takes')),
145 (b'', b'profile', None, _(b'print command execution profile')),
145 (b'', b'profile', None, _(b'print command execution profile')),
146 (b'', b'version', None, _(b'output version information and exit')),
146 (b'', b'version', None, _(b'output version information and exit')),
147 (b'h', b'help', None, _(b'display help and exit')),
147 (b'h', b'help', None, _(b'display help and exit')),
148 (b'', b'hidden', False, _(b'consider hidden changesets')),
148 (b'', b'hidden', False, _(b'consider hidden changesets')),
149 (
149 (
150 b'',
150 b'',
151 b'pager',
151 b'pager',
152 b'auto',
152 b'auto',
153 _(b"when to paginate (boolean, always, auto, or never)"),
153 _(b"when to paginate (boolean, always, auto, or never)"),
154 _(b'TYPE'),
154 _(b'TYPE'),
155 ),
155 ),
156 ]
156 ]
157
157
158 dryrunopts = cmdutil.dryrunopts
158 dryrunopts = cmdutil.dryrunopts
159 remoteopts = cmdutil.remoteopts
159 remoteopts = cmdutil.remoteopts
160 walkopts = cmdutil.walkopts
160 walkopts = cmdutil.walkopts
161 commitopts = cmdutil.commitopts
161 commitopts = cmdutil.commitopts
162 commitopts2 = cmdutil.commitopts2
162 commitopts2 = cmdutil.commitopts2
163 commitopts3 = cmdutil.commitopts3
163 commitopts3 = cmdutil.commitopts3
164 formatteropts = cmdutil.formatteropts
164 formatteropts = cmdutil.formatteropts
165 templateopts = cmdutil.templateopts
165 templateopts = cmdutil.templateopts
166 logopts = cmdutil.logopts
166 logopts = cmdutil.logopts
167 diffopts = cmdutil.diffopts
167 diffopts = cmdutil.diffopts
168 diffwsopts = cmdutil.diffwsopts
168 diffwsopts = cmdutil.diffwsopts
169 diffopts2 = cmdutil.diffopts2
169 diffopts2 = cmdutil.diffopts2
170 mergetoolopts = cmdutil.mergetoolopts
170 mergetoolopts = cmdutil.mergetoolopts
171 similarityopts = cmdutil.similarityopts
171 similarityopts = cmdutil.similarityopts
172 subrepoopts = cmdutil.subrepoopts
172 subrepoopts = cmdutil.subrepoopts
173 debugrevlogopts = cmdutil.debugrevlogopts
173 debugrevlogopts = cmdutil.debugrevlogopts
174
174
175 # Commands start here, listed alphabetically
175 # Commands start here, listed alphabetically
176
176
177
177
178 @command(
178 @command(
179 b'abort',
179 b'abort',
180 dryrunopts,
180 dryrunopts,
181 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
181 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
182 helpbasic=True,
182 helpbasic=True,
183 )
183 )
184 def abort(ui, repo, **opts):
184 def abort(ui, repo, **opts):
185 """abort an unfinished operation (EXPERIMENTAL)
185 """abort an unfinished operation (EXPERIMENTAL)
186
186
187 Aborts a multistep operation like graft, histedit, rebase, merge,
187 Aborts a multistep operation like graft, histedit, rebase, merge,
188 and unshelve if they are in an unfinished state.
188 and unshelve if they are in an unfinished state.
189
189
190 use --dry-run/-n to dry run the command.
190 use --dry-run/-n to dry run the command.
191 """
191 """
192 dryrun = opts.get('dry_run')
192 dryrun = opts.get('dry_run')
193 abortstate = cmdutil.getunfinishedstate(repo)
193 abortstate = cmdutil.getunfinishedstate(repo)
194 if not abortstate:
194 if not abortstate:
195 raise error.StateError(_(b'no operation in progress'))
195 raise error.StateError(_(b'no operation in progress'))
196 if not abortstate.abortfunc:
196 if not abortstate.abortfunc:
197 raise error.InputError(
197 raise error.InputError(
198 (
198 (
199 _(b"%s in progress but does not support 'hg abort'")
199 _(b"%s in progress but does not support 'hg abort'")
200 % (abortstate._opname)
200 % (abortstate._opname)
201 ),
201 ),
202 hint=abortstate.hint(),
202 hint=abortstate.hint(),
203 )
203 )
204 if dryrun:
204 if dryrun:
205 ui.status(
205 ui.status(
206 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
206 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
207 )
207 )
208 return
208 return
209 return abortstate.abortfunc(ui, repo)
209 return abortstate.abortfunc(ui, repo)
210
210
211
211
212 @command(
212 @command(
213 b'add',
213 b'add',
214 walkopts + subrepoopts + dryrunopts,
214 walkopts + subrepoopts + dryrunopts,
215 _(b'[OPTION]... [FILE]...'),
215 _(b'[OPTION]... [FILE]...'),
216 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
216 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
217 helpbasic=True,
217 helpbasic=True,
218 inferrepo=True,
218 inferrepo=True,
219 )
219 )
220 def add(ui, repo, *pats, **opts):
220 def add(ui, repo, *pats, **opts):
221 """add the specified files on the next commit
221 """add the specified files on the next commit
222
222
223 Schedule files to be version controlled and added to the
223 Schedule files to be version controlled and added to the
224 repository.
224 repository.
225
225
226 The files will be added to the repository at the next commit. To
226 The files will be added to the repository at the next commit. To
227 undo an add before that, see :hg:`forget`.
227 undo an add before that, see :hg:`forget`.
228
228
229 If no names are given, add all files to the repository (except
229 If no names are given, add all files to the repository (except
230 files matching ``.hgignore``).
230 files matching ``.hgignore``).
231
231
232 .. container:: verbose
232 .. container:: verbose
233
233
234 Examples:
234 Examples:
235
235
236 - New (unknown) files are added
236 - New (unknown) files are added
237 automatically by :hg:`add`::
237 automatically by :hg:`add`::
238
238
239 $ ls
239 $ ls
240 foo.c
240 foo.c
241 $ hg status
241 $ hg status
242 ? foo.c
242 ? foo.c
243 $ hg add
243 $ hg add
244 adding foo.c
244 adding foo.c
245 $ hg status
245 $ hg status
246 A foo.c
246 A foo.c
247
247
248 - Specific files to be added can be specified::
248 - Specific files to be added can be specified::
249
249
250 $ ls
250 $ ls
251 bar.c foo.c
251 bar.c foo.c
252 $ hg status
252 $ hg status
253 ? bar.c
253 ? bar.c
254 ? foo.c
254 ? foo.c
255 $ hg add bar.c
255 $ hg add bar.c
256 $ hg status
256 $ hg status
257 A bar.c
257 A bar.c
258 ? foo.c
258 ? foo.c
259
259
260 Returns 0 if all files are successfully added.
260 Returns 0 if all files are successfully added.
261 """
261 """
262
262
263 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
263 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
264 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
264 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
265 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
265 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
266 return rejected and 1 or 0
266 return rejected and 1 or 0
267
267
268
268
269 @command(
269 @command(
270 b'addremove',
270 b'addremove',
271 similarityopts + subrepoopts + walkopts + dryrunopts,
271 similarityopts + subrepoopts + walkopts + dryrunopts,
272 _(b'[OPTION]... [FILE]...'),
272 _(b'[OPTION]... [FILE]...'),
273 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
273 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
274 inferrepo=True,
274 inferrepo=True,
275 )
275 )
276 def addremove(ui, repo, *pats, **opts):
276 def addremove(ui, repo, *pats, **opts):
277 """add all new files, delete all missing files
277 """add all new files, delete all missing files
278
278
279 Add all new files and remove all missing files from the
279 Add all new files and remove all missing files from the
280 repository.
280 repository.
281
281
282 Unless names are given, new files are ignored if they match any of
282 Unless names are given, new files are ignored if they match any of
283 the patterns in ``.hgignore``. As with add, these changes take
283 the patterns in ``.hgignore``. As with add, these changes take
284 effect at the next commit.
284 effect at the next commit.
285
285
286 Use the -s/--similarity option to detect renamed files. This
286 Use the -s/--similarity option to detect renamed files. This
287 option takes a percentage between 0 (disabled) and 100 (files must
287 option takes a percentage between 0 (disabled) and 100 (files must
288 be identical) as its parameter. With a parameter greater than 0,
288 be identical) as its parameter. With a parameter greater than 0,
289 this compares every removed file with every added file and records
289 this compares every removed file with every added file and records
290 those similar enough as renames. Detecting renamed files this way
290 those similar enough as renames. Detecting renamed files this way
291 can be expensive. After using this option, :hg:`status -C` can be
291 can be expensive. After using this option, :hg:`status -C` can be
292 used to check which files were identified as moved or renamed. If
292 used to check which files were identified as moved or renamed. If
293 not specified, -s/--similarity defaults to 100 and only renames of
293 not specified, -s/--similarity defaults to 100 and only renames of
294 identical files are detected.
294 identical files are detected.
295
295
296 .. container:: verbose
296 .. container:: verbose
297
297
298 Examples:
298 Examples:
299
299
300 - A number of files (bar.c and foo.c) are new,
300 - A number of files (bar.c and foo.c) are new,
301 while foobar.c has been removed (without using :hg:`remove`)
301 while foobar.c has been removed (without using :hg:`remove`)
302 from the repository::
302 from the repository::
303
303
304 $ ls
304 $ ls
305 bar.c foo.c
305 bar.c foo.c
306 $ hg status
306 $ hg status
307 ! foobar.c
307 ! foobar.c
308 ? bar.c
308 ? bar.c
309 ? foo.c
309 ? foo.c
310 $ hg addremove
310 $ hg addremove
311 adding bar.c
311 adding bar.c
312 adding foo.c
312 adding foo.c
313 removing foobar.c
313 removing foobar.c
314 $ hg status
314 $ hg status
315 A bar.c
315 A bar.c
316 A foo.c
316 A foo.c
317 R foobar.c
317 R foobar.c
318
318
319 - A file foobar.c was moved to foo.c without using :hg:`rename`.
319 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 Afterwards, it was edited slightly::
320 Afterwards, it was edited slightly::
321
321
322 $ ls
322 $ ls
323 foo.c
323 foo.c
324 $ hg status
324 $ hg status
325 ! foobar.c
325 ! foobar.c
326 ? foo.c
326 ? foo.c
327 $ hg addremove --similarity 90
327 $ hg addremove --similarity 90
328 removing foobar.c
328 removing foobar.c
329 adding foo.c
329 adding foo.c
330 recording removal of foobar.c as rename to foo.c (94% similar)
330 recording removal of foobar.c as rename to foo.c (94% similar)
331 $ hg status -C
331 $ hg status -C
332 A foo.c
332 A foo.c
333 foobar.c
333 foobar.c
334 R foobar.c
334 R foobar.c
335
335
336 Returns 0 if all files are successfully added.
336 Returns 0 if all files are successfully added.
337 """
337 """
338 opts = pycompat.byteskwargs(opts)
338 opts = pycompat.byteskwargs(opts)
339 if not opts.get(b'similarity'):
339 if not opts.get(b'similarity'):
340 opts[b'similarity'] = b'100'
340 opts[b'similarity'] = b'100'
341 matcher = scmutil.match(repo[None], pats, opts)
341 matcher = scmutil.match(repo[None], pats, opts)
342 relative = scmutil.anypats(pats, opts)
342 relative = scmutil.anypats(pats, opts)
343 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
343 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
344 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
344 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
345
345
346
346
347 @command(
347 @command(
348 b'annotate|blame',
348 b'annotate|blame',
349 [
349 [
350 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
350 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
351 (
351 (
352 b'',
352 b'',
353 b'follow',
353 b'follow',
354 None,
354 None,
355 _(b'follow copies/renames and list the filename (DEPRECATED)'),
355 _(b'follow copies/renames and list the filename (DEPRECATED)'),
356 ),
356 ),
357 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
357 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
358 (b'a', b'text', None, _(b'treat all files as text')),
358 (b'a', b'text', None, _(b'treat all files as text')),
359 (b'u', b'user', None, _(b'list the author (long with -v)')),
359 (b'u', b'user', None, _(b'list the author (long with -v)')),
360 (b'f', b'file', None, _(b'list the filename')),
360 (b'f', b'file', None, _(b'list the filename')),
361 (b'd', b'date', None, _(b'list the date (short with -q)')),
361 (b'd', b'date', None, _(b'list the date (short with -q)')),
362 (b'n', b'number', None, _(b'list the revision number (default)')),
362 (b'n', b'number', None, _(b'list the revision number (default)')),
363 (b'c', b'changeset', None, _(b'list the changeset')),
363 (b'c', b'changeset', None, _(b'list the changeset')),
364 (
364 (
365 b'l',
365 b'l',
366 b'line-number',
366 b'line-number',
367 None,
367 None,
368 _(b'show line number at the first appearance'),
368 _(b'show line number at the first appearance'),
369 ),
369 ),
370 (
370 (
371 b'',
371 b'',
372 b'skip',
372 b'skip',
373 [],
373 [],
374 _(b'revset to not display (EXPERIMENTAL)'),
374 _(b'revset to not display (EXPERIMENTAL)'),
375 _(b'REV'),
375 _(b'REV'),
376 ),
376 ),
377 ]
377 ]
378 + diffwsopts
378 + diffwsopts
379 + walkopts
379 + walkopts
380 + formatteropts,
380 + formatteropts,
381 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
381 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
382 helpcategory=command.CATEGORY_FILE_CONTENTS,
382 helpcategory=command.CATEGORY_FILE_CONTENTS,
383 helpbasic=True,
383 helpbasic=True,
384 inferrepo=True,
384 inferrepo=True,
385 )
385 )
386 def annotate(ui, repo, *pats, **opts):
386 def annotate(ui, repo, *pats, **opts):
387 """show changeset information by line for each file
387 """show changeset information by line for each file
388
388
389 List changes in files, showing the revision id responsible for
389 List changes in files, showing the revision id responsible for
390 each line.
390 each line.
391
391
392 This command is useful for discovering when a change was made and
392 This command is useful for discovering when a change was made and
393 by whom.
393 by whom.
394
394
395 If you include --file, --user, or --date, the revision number is
395 If you include --file, --user, or --date, the revision number is
396 suppressed unless you also include --number.
396 suppressed unless you also include --number.
397
397
398 Without the -a/--text option, annotate will avoid processing files
398 Without the -a/--text option, annotate will avoid processing files
399 it detects as binary. With -a, annotate will annotate the file
399 it detects as binary. With -a, annotate will annotate the file
400 anyway, although the results will probably be neither useful
400 anyway, although the results will probably be neither useful
401 nor desirable.
401 nor desirable.
402
402
403 .. container:: verbose
403 .. container:: verbose
404
404
405 Template:
405 Template:
406
406
407 The following keywords are supported in addition to the common template
407 The following keywords are supported in addition to the common template
408 keywords and functions. See also :hg:`help templates`.
408 keywords and functions. See also :hg:`help templates`.
409
409
410 :lines: List of lines with annotation data.
410 :lines: List of lines with annotation data.
411 :path: String. Repository-absolute path of the specified file.
411 :path: String. Repository-absolute path of the specified file.
412
412
413 And each entry of ``{lines}`` provides the following sub-keywords in
413 And each entry of ``{lines}`` provides the following sub-keywords in
414 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
414 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
415
415
416 :line: String. Line content.
416 :line: String. Line content.
417 :lineno: Integer. Line number at that revision.
417 :lineno: Integer. Line number at that revision.
418 :path: String. Repository-absolute path of the file at that revision.
418 :path: String. Repository-absolute path of the file at that revision.
419
419
420 See :hg:`help templates.operators` for the list expansion syntax.
420 See :hg:`help templates.operators` for the list expansion syntax.
421
421
422 Returns 0 on success.
422 Returns 0 on success.
423 """
423 """
424 opts = pycompat.byteskwargs(opts)
424 opts = pycompat.byteskwargs(opts)
425 if not pats:
425 if not pats:
426 raise error.InputError(
426 raise error.InputError(
427 _(b'at least one filename or pattern is required')
427 _(b'at least one filename or pattern is required')
428 )
428 )
429
429
430 if opts.get(b'follow'):
430 if opts.get(b'follow'):
431 # --follow is deprecated and now just an alias for -f/--file
431 # --follow is deprecated and now just an alias for -f/--file
432 # to mimic the behavior of Mercurial before version 1.5
432 # to mimic the behavior of Mercurial before version 1.5
433 opts[b'file'] = True
433 opts[b'file'] = True
434
434
435 if (
435 if (
436 not opts.get(b'user')
436 not opts.get(b'user')
437 and not opts.get(b'changeset')
437 and not opts.get(b'changeset')
438 and not opts.get(b'date')
438 and not opts.get(b'date')
439 and not opts.get(b'file')
439 and not opts.get(b'file')
440 ):
440 ):
441 opts[b'number'] = True
441 opts[b'number'] = True
442
442
443 linenumber = opts.get(b'line_number') is not None
443 linenumber = opts.get(b'line_number') is not None
444 if (
444 if (
445 linenumber
445 linenumber
446 and (not opts.get(b'changeset'))
446 and (not opts.get(b'changeset'))
447 and (not opts.get(b'number'))
447 and (not opts.get(b'number'))
448 ):
448 ):
449 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
449 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
450
450
451 rev = opts.get(b'rev')
451 rev = opts.get(b'rev')
452 if rev:
452 if rev:
453 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
453 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
454 ctx = scmutil.revsingle(repo, rev)
454 ctx = scmutil.revsingle(repo, rev)
455
455
456 ui.pager(b'annotate')
456 ui.pager(b'annotate')
457 rootfm = ui.formatter(b'annotate', opts)
457 rootfm = ui.formatter(b'annotate', opts)
458 if ui.debugflag:
458 if ui.debugflag:
459 shorthex = pycompat.identity
459 shorthex = pycompat.identity
460 else:
460 else:
461
461
462 def shorthex(h):
462 def shorthex(h):
463 return h[:12]
463 return h[:12]
464
464
465 if ui.quiet:
465 if ui.quiet:
466 datefunc = dateutil.shortdate
466 datefunc = dateutil.shortdate
467 else:
467 else:
468 datefunc = dateutil.datestr
468 datefunc = dateutil.datestr
469 if ctx.rev() is None:
469 if ctx.rev() is None:
470 if opts.get(b'changeset'):
470 if opts.get(b'changeset'):
471 # omit "+" suffix which is appended to node hex
471 # omit "+" suffix which is appended to node hex
472 def formatrev(rev):
472 def formatrev(rev):
473 if rev == wdirrev:
473 if rev == wdirrev:
474 return b'%d' % ctx.p1().rev()
474 return b'%d' % ctx.p1().rev()
475 else:
475 else:
476 return b'%d' % rev
476 return b'%d' % rev
477
477
478 else:
478 else:
479
479
480 def formatrev(rev):
480 def formatrev(rev):
481 if rev == wdirrev:
481 if rev == wdirrev:
482 return b'%d+' % ctx.p1().rev()
482 return b'%d+' % ctx.p1().rev()
483 else:
483 else:
484 return b'%d ' % rev
484 return b'%d ' % rev
485
485
486 def formathex(h):
486 def formathex(h):
487 if h == repo.nodeconstants.wdirhex:
487 if h == repo.nodeconstants.wdirhex:
488 return b'%s+' % shorthex(hex(ctx.p1().node()))
488 return b'%s+' % shorthex(hex(ctx.p1().node()))
489 else:
489 else:
490 return b'%s ' % shorthex(h)
490 return b'%s ' % shorthex(h)
491
491
492 else:
492 else:
493 formatrev = b'%d'.__mod__
493 formatrev = b'%d'.__mod__
494 formathex = shorthex
494 formathex = shorthex
495
495
496 opmap = [
496 opmap = [
497 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
497 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
498 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
498 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
499 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
499 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
500 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
500 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
501 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
501 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
502 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
502 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
503 ]
503 ]
504 opnamemap = {
504 opnamemap = {
505 b'rev': b'number',
505 b'rev': b'number',
506 b'node': b'changeset',
506 b'node': b'changeset',
507 b'path': b'file',
507 b'path': b'file',
508 b'lineno': b'line_number',
508 b'lineno': b'line_number',
509 }
509 }
510
510
511 if rootfm.isplain():
511 if rootfm.isplain():
512
512
513 def makefunc(get, fmt):
513 def makefunc(get, fmt):
514 return lambda x: fmt(get(x))
514 return lambda x: fmt(get(x))
515
515
516 else:
516 else:
517
517
518 def makefunc(get, fmt):
518 def makefunc(get, fmt):
519 return get
519 return get
520
520
521 datahint = rootfm.datahint()
521 datahint = rootfm.datahint()
522 funcmap = [
522 funcmap = [
523 (makefunc(get, fmt), sep)
523 (makefunc(get, fmt), sep)
524 for fn, sep, get, fmt in opmap
524 for fn, sep, get, fmt in opmap
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 ]
526 ]
527 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
527 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
528 fields = b' '.join(
528 fields = b' '.join(
529 fn
529 fn
530 for fn, sep, get, fmt in opmap
530 for fn, sep, get, fmt in opmap
531 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
531 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
532 )
532 )
533
533
534 def bad(x, y):
534 def bad(x, y):
535 raise error.Abort(b"%s: %s" % (x, y))
535 raise error.Abort(b"%s: %s" % (x, y))
536
536
537 m = scmutil.match(ctx, pats, opts, badfn=bad)
537 m = scmutil.match(ctx, pats, opts, badfn=bad)
538
538
539 follow = not opts.get(b'no_follow')
539 follow = not opts.get(b'no_follow')
540 diffopts = patch.difffeatureopts(
540 diffopts = patch.difffeatureopts(
541 ui, opts, section=b'annotate', whitespace=True
541 ui, opts, section=b'annotate', whitespace=True
542 )
542 )
543 skiprevs = opts.get(b'skip')
543 skiprevs = opts.get(b'skip')
544 if skiprevs:
544 if skiprevs:
545 skiprevs = scmutil.revrange(repo, skiprevs)
545 skiprevs = scmutil.revrange(repo, skiprevs)
546
546
547 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
547 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
548 for abs in ctx.walk(m):
548 for abs in ctx.walk(m):
549 fctx = ctx[abs]
549 fctx = ctx[abs]
550 rootfm.startitem()
550 rootfm.startitem()
551 rootfm.data(path=abs)
551 rootfm.data(path=abs)
552 if not opts.get(b'text') and fctx.isbinary():
552 if not opts.get(b'text') and fctx.isbinary():
553 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
553 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
554 continue
554 continue
555
555
556 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
556 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
557 lines = fctx.annotate(
557 lines = fctx.annotate(
558 follow=follow, skiprevs=skiprevs, diffopts=diffopts
558 follow=follow, skiprevs=skiprevs, diffopts=diffopts
559 )
559 )
560 if not lines:
560 if not lines:
561 fm.end()
561 fm.end()
562 continue
562 continue
563 formats = []
563 formats = []
564 pieces = []
564 pieces = []
565
565
566 for f, sep in funcmap:
566 for f, sep in funcmap:
567 l = [f(n) for n in lines]
567 l = [f(n) for n in lines]
568 if fm.isplain():
568 if fm.isplain():
569 sizes = [encoding.colwidth(x) for x in l]
569 sizes = [encoding.colwidth(x) for x in l]
570 ml = max(sizes)
570 ml = max(sizes)
571 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
571 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
572 else:
572 else:
573 formats.append([b'%s'] * len(l))
573 formats.append([b'%s'] * len(l))
574 pieces.append(l)
574 pieces.append(l)
575
575
576 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
576 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
577 fm.startitem()
577 fm.startitem()
578 fm.context(fctx=n.fctx)
578 fm.context(fctx=n.fctx)
579 fm.write(fields, b"".join(f), *p)
579 fm.write(fields, b"".join(f), *p)
580 if n.skip:
580 if n.skip:
581 fmt = b"* %s"
581 fmt = b"* %s"
582 else:
582 else:
583 fmt = b": %s"
583 fmt = b": %s"
584 fm.write(b'line', fmt, n.text)
584 fm.write(b'line', fmt, n.text)
585
585
586 if not lines[-1].text.endswith(b'\n'):
586 if not lines[-1].text.endswith(b'\n'):
587 fm.plain(b'\n')
587 fm.plain(b'\n')
588 fm.end()
588 fm.end()
589
589
590 rootfm.end()
590 rootfm.end()
591
591
592
592
593 @command(
593 @command(
594 b'archive',
594 b'archive',
595 [
595 [
596 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
596 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
597 (
597 (
598 b'p',
598 b'p',
599 b'prefix',
599 b'prefix',
600 b'',
600 b'',
601 _(b'directory prefix for files in archive'),
601 _(b'directory prefix for files in archive'),
602 _(b'PREFIX'),
602 _(b'PREFIX'),
603 ),
603 ),
604 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
604 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
605 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
605 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
606 ]
606 ]
607 + subrepoopts
607 + subrepoopts
608 + walkopts,
608 + walkopts,
609 _(b'[OPTION]... DEST'),
609 _(b'[OPTION]... DEST'),
610 helpcategory=command.CATEGORY_IMPORT_EXPORT,
610 helpcategory=command.CATEGORY_IMPORT_EXPORT,
611 )
611 )
612 def archive(ui, repo, dest, **opts):
612 def archive(ui, repo, dest, **opts):
613 """create an unversioned archive of a repository revision
613 """create an unversioned archive of a repository revision
614
614
615 By default, the revision used is the parent of the working
615 By default, the revision used is the parent of the working
616 directory; use -r/--rev to specify a different revision.
616 directory; use -r/--rev to specify a different revision.
617
617
618 The archive type is automatically detected based on file
618 The archive type is automatically detected based on file
619 extension (to override, use -t/--type).
619 extension (to override, use -t/--type).
620
620
621 .. container:: verbose
621 .. container:: verbose
622
622
623 Examples:
623 Examples:
624
624
625 - create a zip file containing the 1.0 release::
625 - create a zip file containing the 1.0 release::
626
626
627 hg archive -r 1.0 project-1.0.zip
627 hg archive -r 1.0 project-1.0.zip
628
628
629 - create a tarball excluding .hg files::
629 - create a tarball excluding .hg files::
630
630
631 hg archive project.tar.gz -X ".hg*"
631 hg archive project.tar.gz -X ".hg*"
632
632
633 Valid types are:
633 Valid types are:
634
634
635 :``files``: a directory full of files (default)
635 :``files``: a directory full of files (default)
636 :``tar``: tar archive, uncompressed
636 :``tar``: tar archive, uncompressed
637 :``tbz2``: tar archive, compressed using bzip2
637 :``tbz2``: tar archive, compressed using bzip2
638 :``tgz``: tar archive, compressed using gzip
638 :``tgz``: tar archive, compressed using gzip
639 :``txz``: tar archive, compressed using lzma (only in Python 3)
639 :``txz``: tar archive, compressed using lzma (only in Python 3)
640 :``uzip``: zip archive, uncompressed
640 :``uzip``: zip archive, uncompressed
641 :``zip``: zip archive, compressed using deflate
641 :``zip``: zip archive, compressed using deflate
642
642
643 The exact name of the destination archive or directory is given
643 The exact name of the destination archive or directory is given
644 using a format string; see :hg:`help export` for details.
644 using a format string; see :hg:`help export` for details.
645
645
646 Each member added to an archive file has a directory prefix
646 Each member added to an archive file has a directory prefix
647 prepended. Use -p/--prefix to specify a format string for the
647 prepended. Use -p/--prefix to specify a format string for the
648 prefix. The default is the basename of the archive, with suffixes
648 prefix. The default is the basename of the archive, with suffixes
649 removed.
649 removed.
650
650
651 Returns 0 on success.
651 Returns 0 on success.
652 """
652 """
653
653
654 opts = pycompat.byteskwargs(opts)
654 opts = pycompat.byteskwargs(opts)
655 rev = opts.get(b'rev')
655 rev = opts.get(b'rev')
656 if rev:
656 if rev:
657 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
657 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
658 ctx = scmutil.revsingle(repo, rev)
658 ctx = scmutil.revsingle(repo, rev)
659 if not ctx:
659 if not ctx:
660 raise error.InputError(
660 raise error.InputError(
661 _(b'no working directory: please specify a revision')
661 _(b'no working directory: please specify a revision')
662 )
662 )
663 node = ctx.node()
663 node = ctx.node()
664 dest = cmdutil.makefilename(ctx, dest)
664 dest = cmdutil.makefilename(ctx, dest)
665 if os.path.realpath(dest) == repo.root:
665 if os.path.realpath(dest) == repo.root:
666 raise error.InputError(_(b'repository root cannot be destination'))
666 raise error.InputError(_(b'repository root cannot be destination'))
667
667
668 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
668 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
669 prefix = opts.get(b'prefix')
669 prefix = opts.get(b'prefix')
670
670
671 if dest == b'-':
671 if dest == b'-':
672 if kind == b'files':
672 if kind == b'files':
673 raise error.InputError(_(b'cannot archive plain files to stdout'))
673 raise error.InputError(_(b'cannot archive plain files to stdout'))
674 dest = cmdutil.makefileobj(ctx, dest)
674 dest = cmdutil.makefileobj(ctx, dest)
675 if not prefix:
675 if not prefix:
676 prefix = os.path.basename(repo.root) + b'-%h'
676 prefix = os.path.basename(repo.root) + b'-%h'
677
677
678 prefix = cmdutil.makefilename(ctx, prefix)
678 prefix = cmdutil.makefilename(ctx, prefix)
679 match = scmutil.match(ctx, [], opts)
679 match = scmutil.match(ctx, [], opts)
680 archival.archive(
680 archival.archive(
681 repo,
681 repo,
682 dest,
682 dest,
683 node,
683 node,
684 kind,
684 kind,
685 not opts.get(b'no_decode'),
685 not opts.get(b'no_decode'),
686 match,
686 match,
687 prefix,
687 prefix,
688 subrepos=opts.get(b'subrepos'),
688 subrepos=opts.get(b'subrepos'),
689 )
689 )
690
690
691
691
692 @command(
692 @command(
693 b'backout',
693 b'backout',
694 [
694 [
695 (
695 (
696 b'',
696 b'',
697 b'merge',
697 b'merge',
698 None,
698 None,
699 _(b'merge with old dirstate parent after backout'),
699 _(b'merge with old dirstate parent after backout'),
700 ),
700 ),
701 (
701 (
702 b'',
702 b'',
703 b'commit',
703 b'commit',
704 None,
704 None,
705 _(b'commit if no conflicts were encountered (DEPRECATED)'),
705 _(b'commit if no conflicts were encountered (DEPRECATED)'),
706 ),
706 ),
707 (b'', b'no-commit', None, _(b'do not commit')),
707 (b'', b'no-commit', None, _(b'do not commit')),
708 (
708 (
709 b'',
709 b'',
710 b'parent',
710 b'parent',
711 b'',
711 b'',
712 _(b'parent to choose when backing out merge (DEPRECATED)'),
712 _(b'parent to choose when backing out merge (DEPRECATED)'),
713 _(b'REV'),
713 _(b'REV'),
714 ),
714 ),
715 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
715 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
716 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
716 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
717 ]
717 ]
718 + mergetoolopts
718 + mergetoolopts
719 + walkopts
719 + walkopts
720 + commitopts
720 + commitopts
721 + commitopts2,
721 + commitopts2,
722 _(b'[OPTION]... [-r] REV'),
722 _(b'[OPTION]... [-r] REV'),
723 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
723 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
724 )
724 )
725 def backout(ui, repo, node=None, rev=None, **opts):
725 def backout(ui, repo, node=None, rev=None, **opts):
726 """reverse effect of earlier changeset
726 """reverse effect of earlier changeset
727
727
728 Prepare a new changeset with the effect of REV undone in the
728 Prepare a new changeset with the effect of REV undone in the
729 current working directory. If no conflicts were encountered,
729 current working directory. If no conflicts were encountered,
730 it will be committed immediately.
730 it will be committed immediately.
731
731
732 If REV is the parent of the working directory, then this new changeset
732 If REV is the parent of the working directory, then this new changeset
733 is committed automatically (unless --no-commit is specified).
733 is committed automatically (unless --no-commit is specified).
734
734
735 .. note::
735 .. note::
736
736
737 :hg:`backout` cannot be used to fix either an unwanted or
737 :hg:`backout` cannot be used to fix either an unwanted or
738 incorrect merge.
738 incorrect merge.
739
739
740 .. container:: verbose
740 .. container:: verbose
741
741
742 Examples:
742 Examples:
743
743
744 - Reverse the effect of the parent of the working directory.
744 - Reverse the effect of the parent of the working directory.
745 This backout will be committed immediately::
745 This backout will be committed immediately::
746
746
747 hg backout -r .
747 hg backout -r .
748
748
749 - Reverse the effect of previous bad revision 23::
749 - Reverse the effect of previous bad revision 23::
750
750
751 hg backout -r 23
751 hg backout -r 23
752
752
753 - Reverse the effect of previous bad revision 23 and
753 - Reverse the effect of previous bad revision 23 and
754 leave changes uncommitted::
754 leave changes uncommitted::
755
755
756 hg backout -r 23 --no-commit
756 hg backout -r 23 --no-commit
757 hg commit -m "Backout revision 23"
757 hg commit -m "Backout revision 23"
758
758
759 By default, the pending changeset will have one parent,
759 By default, the pending changeset will have one parent,
760 maintaining a linear history. With --merge, the pending
760 maintaining a linear history. With --merge, the pending
761 changeset will instead have two parents: the old parent of the
761 changeset will instead have two parents: the old parent of the
762 working directory and a new child of REV that simply undoes REV.
762 working directory and a new child of REV that simply undoes REV.
763
763
764 Before version 1.7, the behavior without --merge was equivalent
764 Before version 1.7, the behavior without --merge was equivalent
765 to specifying --merge followed by :hg:`update --clean .` to
765 to specifying --merge followed by :hg:`update --clean .` to
766 cancel the merge and leave the child of REV as a head to be
766 cancel the merge and leave the child of REV as a head to be
767 merged separately.
767 merged separately.
768
768
769 See :hg:`help dates` for a list of formats valid for -d/--date.
769 See :hg:`help dates` for a list of formats valid for -d/--date.
770
770
771 See :hg:`help revert` for a way to restore files to the state
771 See :hg:`help revert` for a way to restore files to the state
772 of another revision.
772 of another revision.
773
773
774 Returns 0 on success, 1 if nothing to backout or there are unresolved
774 Returns 0 on success, 1 if nothing to backout or there are unresolved
775 files.
775 files.
776 """
776 """
777 with repo.wlock(), repo.lock():
777 with repo.wlock(), repo.lock():
778 return _dobackout(ui, repo, node, rev, **opts)
778 return _dobackout(ui, repo, node, rev, **opts)
779
779
780
780
781 def _dobackout(ui, repo, node=None, rev=None, **opts):
781 def _dobackout(ui, repo, node=None, rev=None, **opts):
782 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
782 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
783 opts = pycompat.byteskwargs(opts)
783 opts = pycompat.byteskwargs(opts)
784
784
785 if rev and node:
785 if rev and node:
786 raise error.InputError(_(b"please specify just one revision"))
786 raise error.InputError(_(b"please specify just one revision"))
787
787
788 if not rev:
788 if not rev:
789 rev = node
789 rev = node
790
790
791 if not rev:
791 if not rev:
792 raise error.InputError(_(b"please specify a revision to backout"))
792 raise error.InputError(_(b"please specify a revision to backout"))
793
793
794 date = opts.get(b'date')
794 date = opts.get(b'date')
795 if date:
795 if date:
796 opts[b'date'] = dateutil.parsedate(date)
796 opts[b'date'] = dateutil.parsedate(date)
797
797
798 cmdutil.checkunfinished(repo)
798 cmdutil.checkunfinished(repo)
799 cmdutil.bailifchanged(repo)
799 cmdutil.bailifchanged(repo)
800 ctx = scmutil.revsingle(repo, rev)
800 ctx = scmutil.revsingle(repo, rev)
801 node = ctx.node()
801 node = ctx.node()
802
802
803 op1, op2 = repo.dirstate.parents()
803 op1, op2 = repo.dirstate.parents()
804 if not repo.changelog.isancestor(node, op1):
804 if not repo.changelog.isancestor(node, op1):
805 raise error.InputError(
805 raise error.InputError(
806 _(b'cannot backout change that is not an ancestor')
806 _(b'cannot backout change that is not an ancestor')
807 )
807 )
808
808
809 p1, p2 = repo.changelog.parents(node)
809 p1, p2 = repo.changelog.parents(node)
810 if p1 == repo.nullid:
810 if p1 == repo.nullid:
811 raise error.InputError(_(b'cannot backout a change with no parents'))
811 raise error.InputError(_(b'cannot backout a change with no parents'))
812 if p2 != repo.nullid:
812 if p2 != repo.nullid:
813 if not opts.get(b'parent'):
813 if not opts.get(b'parent'):
814 raise error.InputError(_(b'cannot backout a merge changeset'))
814 raise error.InputError(_(b'cannot backout a merge changeset'))
815 p = repo.lookup(opts[b'parent'])
815 p = repo.lookup(opts[b'parent'])
816 if p not in (p1, p2):
816 if p not in (p1, p2):
817 raise error.InputError(
817 raise error.InputError(
818 _(b'%s is not a parent of %s') % (short(p), short(node))
818 _(b'%s is not a parent of %s') % (short(p), short(node))
819 )
819 )
820 parent = p
820 parent = p
821 else:
821 else:
822 if opts.get(b'parent'):
822 if opts.get(b'parent'):
823 raise error.InputError(
823 raise error.InputError(
824 _(b'cannot use --parent on non-merge changeset')
824 _(b'cannot use --parent on non-merge changeset')
825 )
825 )
826 parent = p1
826 parent = p1
827
827
828 # the backout should appear on the same branch
828 # the backout should appear on the same branch
829 branch = repo.dirstate.branch()
829 branch = repo.dirstate.branch()
830 bheads = repo.branchheads(branch)
830 bheads = repo.branchheads(branch)
831 rctx = scmutil.revsingle(repo, hex(parent))
831 rctx = scmutil.revsingle(repo, hex(parent))
832 if not opts.get(b'merge') and op1 != node:
832 if not opts.get(b'merge') and op1 != node:
833 with dirstateguard.dirstateguard(repo, b'backout'):
833 with dirstateguard.dirstateguard(repo, b'backout'):
834 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
834 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
835 with ui.configoverride(overrides, b'backout'):
835 with ui.configoverride(overrides, b'backout'):
836 stats = mergemod.back_out(ctx, parent=repo[parent])
836 stats = mergemod.back_out(ctx, parent=repo[parent])
837 repo.setparents(op1, op2)
837 repo.setparents(op1, op2)
838 hg._showstats(repo, stats)
838 hg._showstats(repo, stats)
839 if stats.unresolvedcount:
839 if stats.unresolvedcount:
840 repo.ui.status(
840 repo.ui.status(
841 _(b"use 'hg resolve' to retry unresolved file merges\n")
841 _(b"use 'hg resolve' to retry unresolved file merges\n")
842 )
842 )
843 return 1
843 return 1
844 else:
844 else:
845 hg.clean(repo, node, show_stats=False)
845 hg.clean(repo, node, show_stats=False)
846 repo.dirstate.setbranch(branch)
846 repo.dirstate.setbranch(branch)
847 cmdutil.revert(ui, repo, rctx)
847 cmdutil.revert(ui, repo, rctx)
848
848
849 if opts.get(b'no_commit'):
849 if opts.get(b'no_commit'):
850 msg = _(b"changeset %s backed out, don't forget to commit.\n")
850 msg = _(b"changeset %s backed out, don't forget to commit.\n")
851 ui.status(msg % short(node))
851 ui.status(msg % short(node))
852 return 0
852 return 0
853
853
854 def commitfunc(ui, repo, message, match, opts):
854 def commitfunc(ui, repo, message, match, opts):
855 editform = b'backout'
855 editform = b'backout'
856 e = cmdutil.getcommiteditor(
856 e = cmdutil.getcommiteditor(
857 editform=editform, **pycompat.strkwargs(opts)
857 editform=editform, **pycompat.strkwargs(opts)
858 )
858 )
859 if not message:
859 if not message:
860 # we don't translate commit messages
860 # we don't translate commit messages
861 message = b"Backed out changeset %s" % short(node)
861 message = b"Backed out changeset %s" % short(node)
862 e = cmdutil.getcommiteditor(edit=True, editform=editform)
862 e = cmdutil.getcommiteditor(edit=True, editform=editform)
863 return repo.commit(
863 return repo.commit(
864 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
864 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
865 )
865 )
866
866
867 # save to detect changes
867 # save to detect changes
868 tip = repo.changelog.tip()
868 tip = repo.changelog.tip()
869
869
870 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
870 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
871 if not newnode:
871 if not newnode:
872 ui.status(_(b"nothing changed\n"))
872 ui.status(_(b"nothing changed\n"))
873 return 1
873 return 1
874 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
874 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
875
875
876 def nice(node):
876 def nice(node):
877 return b'%d:%s' % (repo.changelog.rev(node), short(node))
877 return b'%d:%s' % (repo.changelog.rev(node), short(node))
878
878
879 ui.status(
879 ui.status(
880 _(b'changeset %s backs out changeset %s\n')
880 _(b'changeset %s backs out changeset %s\n')
881 % (nice(newnode), nice(node))
881 % (nice(newnode), nice(node))
882 )
882 )
883 if opts.get(b'merge') and op1 != node:
883 if opts.get(b'merge') and op1 != node:
884 hg.clean(repo, op1, show_stats=False)
884 hg.clean(repo, op1, show_stats=False)
885 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
885 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
886 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
886 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
887 with ui.configoverride(overrides, b'backout'):
887 with ui.configoverride(overrides, b'backout'):
888 return hg.merge(repo[b'tip'])
888 return hg.merge(repo[b'tip'])
889 return 0
889 return 0
890
890
891
891
892 @command(
892 @command(
893 b'bisect',
893 b'bisect',
894 [
894 [
895 (b'r', b'reset', False, _(b'reset bisect state')),
895 (b'r', b'reset', False, _(b'reset bisect state')),
896 (b'g', b'good', False, _(b'mark changeset good')),
896 (b'g', b'good', False, _(b'mark changeset good')),
897 (b'b', b'bad', False, _(b'mark changeset bad')),
897 (b'b', b'bad', False, _(b'mark changeset bad')),
898 (b's', b'skip', False, _(b'skip testing changeset')),
898 (b's', b'skip', False, _(b'skip testing changeset')),
899 (b'e', b'extend', False, _(b'extend the bisect range')),
899 (b'e', b'extend', False, _(b'extend the bisect range')),
900 (
900 (
901 b'c',
901 b'c',
902 b'command',
902 b'command',
903 b'',
903 b'',
904 _(b'use command to check changeset state'),
904 _(b'use command to check changeset state'),
905 _(b'CMD'),
905 _(b'CMD'),
906 ),
906 ),
907 (b'U', b'noupdate', False, _(b'do not update to target')),
907 (b'U', b'noupdate', False, _(b'do not update to target')),
908 ],
908 ],
909 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
909 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
910 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
910 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
911 )
911 )
912 def bisect(
912 def bisect(
913 ui,
913 ui,
914 repo,
914 repo,
915 positional_1=None,
915 positional_1=None,
916 positional_2=None,
916 positional_2=None,
917 command=None,
917 command=None,
918 reset=None,
918 reset=None,
919 good=None,
919 good=None,
920 bad=None,
920 bad=None,
921 skip=None,
921 skip=None,
922 extend=None,
922 extend=None,
923 noupdate=None,
923 noupdate=None,
924 ):
924 ):
925 """subdivision search of changesets
925 """subdivision search of changesets
926
926
927 This command helps to find changesets which introduce problems. To
927 This command helps to find changesets which introduce problems. To
928 use, mark the earliest changeset you know exhibits the problem as
928 use, mark the earliest changeset you know exhibits the problem as
929 bad, then mark the latest changeset which is free from the problem
929 bad, then mark the latest changeset which is free from the problem
930 as good. Bisect will update your working directory to a revision
930 as good. Bisect will update your working directory to a revision
931 for testing (unless the -U/--noupdate option is specified). Once
931 for testing (unless the -U/--noupdate option is specified). Once
932 you have performed tests, mark the working directory as good or
932 you have performed tests, mark the working directory as good or
933 bad, and bisect will either update to another candidate changeset
933 bad, and bisect will either update to another candidate changeset
934 or announce that it has found the bad revision.
934 or announce that it has found the bad revision.
935
935
936 As a shortcut, you can also use the revision argument to mark a
936 As a shortcut, you can also use the revision argument to mark a
937 revision as good or bad without checking it out first.
937 revision as good or bad without checking it out first.
938
938
939 If you supply a command, it will be used for automatic bisection.
939 If you supply a command, it will be used for automatic bisection.
940 The environment variable HG_NODE will contain the ID of the
940 The environment variable HG_NODE will contain the ID of the
941 changeset being tested. The exit status of the command will be
941 changeset being tested. The exit status of the command will be
942 used to mark revisions as good or bad: status 0 means good, 125
942 used to mark revisions as good or bad: status 0 means good, 125
943 means to skip the revision, 127 (command not found) will abort the
943 means to skip the revision, 127 (command not found) will abort the
944 bisection, and any other non-zero exit status means the revision
944 bisection, and any other non-zero exit status means the revision
945 is bad.
945 is bad.
946
946
947 .. container:: verbose
947 .. container:: verbose
948
948
949 Some examples:
949 Some examples:
950
950
951 - start a bisection with known bad revision 34, and good revision 12::
951 - start a bisection with known bad revision 34, and good revision 12::
952
952
953 hg bisect --bad 34
953 hg bisect --bad 34
954 hg bisect --good 12
954 hg bisect --good 12
955
955
956 - advance the current bisection by marking current revision as good or
956 - advance the current bisection by marking current revision as good or
957 bad::
957 bad::
958
958
959 hg bisect --good
959 hg bisect --good
960 hg bisect --bad
960 hg bisect --bad
961
961
962 - mark the current revision, or a known revision, to be skipped (e.g. if
962 - mark the current revision, or a known revision, to be skipped (e.g. if
963 that revision is not usable because of another issue)::
963 that revision is not usable because of another issue)::
964
964
965 hg bisect --skip
965 hg bisect --skip
966 hg bisect --skip 23
966 hg bisect --skip 23
967
967
968 - skip all revisions that do not touch directories ``foo`` or ``bar``::
968 - skip all revisions that do not touch directories ``foo`` or ``bar``::
969
969
970 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
970 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
971
971
972 - forget the current bisection::
972 - forget the current bisection::
973
973
974 hg bisect --reset
974 hg bisect --reset
975
975
976 - use 'make && make tests' to automatically find the first broken
976 - use 'make && make tests' to automatically find the first broken
977 revision::
977 revision::
978
978
979 hg bisect --reset
979 hg bisect --reset
980 hg bisect --bad 34
980 hg bisect --bad 34
981 hg bisect --good 12
981 hg bisect --good 12
982 hg bisect --command "make && make tests"
982 hg bisect --command "make && make tests"
983
983
984 - see all changesets whose states are already known in the current
984 - see all changesets whose states are already known in the current
985 bisection::
985 bisection::
986
986
987 hg log -r "bisect(pruned)"
987 hg log -r "bisect(pruned)"
988
988
989 - see the changeset currently being bisected (especially useful
989 - see the changeset currently being bisected (especially useful
990 if running with -U/--noupdate)::
990 if running with -U/--noupdate)::
991
991
992 hg log -r "bisect(current)"
992 hg log -r "bisect(current)"
993
993
994 - see all changesets that took part in the current bisection::
994 - see all changesets that took part in the current bisection::
995
995
996 hg log -r "bisect(range)"
996 hg log -r "bisect(range)"
997
997
998 - you can even get a nice graph::
998 - you can even get a nice graph::
999
999
1000 hg log --graph -r "bisect(range)"
1000 hg log --graph -r "bisect(range)"
1001
1001
1002 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1002 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1003
1003
1004 Returns 0 on success.
1004 Returns 0 on success.
1005 """
1005 """
1006 rev = []
1006 rev = []
1007 # backward compatibility
1007 # backward compatibility
1008 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1008 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1009 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1009 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1010 cmd = positional_1
1010 cmd = positional_1
1011 rev.append(positional_2)
1011 rev.append(positional_2)
1012 if cmd == b"good":
1012 if cmd == b"good":
1013 good = True
1013 good = True
1014 elif cmd == b"bad":
1014 elif cmd == b"bad":
1015 bad = True
1015 bad = True
1016 else:
1016 else:
1017 reset = True
1017 reset = True
1018 elif positional_2:
1018 elif positional_2:
1019 raise error.InputError(_(b'incompatible arguments'))
1019 raise error.InputError(_(b'incompatible arguments'))
1020 elif positional_1 is not None:
1020 elif positional_1 is not None:
1021 rev.append(positional_1)
1021 rev.append(positional_1)
1022
1022
1023 incompatibles = {
1023 incompatibles = {
1024 b'--bad': bad,
1024 b'--bad': bad,
1025 b'--command': bool(command),
1025 b'--command': bool(command),
1026 b'--extend': extend,
1026 b'--extend': extend,
1027 b'--good': good,
1027 b'--good': good,
1028 b'--reset': reset,
1028 b'--reset': reset,
1029 b'--skip': skip,
1029 b'--skip': skip,
1030 }
1030 }
1031
1031
1032 enabled = [x for x in incompatibles if incompatibles[x]]
1032 enabled = [x for x in incompatibles if incompatibles[x]]
1033
1033
1034 if len(enabled) > 1:
1034 if len(enabled) > 1:
1035 raise error.InputError(
1035 raise error.InputError(
1036 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1036 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1037 )
1037 )
1038
1038
1039 if reset:
1039 if reset:
1040 hbisect.resetstate(repo)
1040 hbisect.resetstate(repo)
1041 return
1041 return
1042
1042
1043 state = hbisect.load_state(repo)
1043 state = hbisect.load_state(repo)
1044
1044
1045 if rev:
1045 if rev:
1046 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1046 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1047 else:
1047 else:
1048 nodes = [repo.lookup(b'.')]
1048 nodes = [repo.lookup(b'.')]
1049
1049
1050 # update state
1050 # update state
1051 if good or bad or skip:
1051 if good or bad or skip:
1052 if good:
1052 if good:
1053 state[b'good'] += nodes
1053 state[b'good'] += nodes
1054 elif bad:
1054 elif bad:
1055 state[b'bad'] += nodes
1055 state[b'bad'] += nodes
1056 elif skip:
1056 elif skip:
1057 state[b'skip'] += nodes
1057 state[b'skip'] += nodes
1058 hbisect.save_state(repo, state)
1058 hbisect.save_state(repo, state)
1059 if not (state[b'good'] and state[b'bad']):
1059 if not (state[b'good'] and state[b'bad']):
1060 return
1060 return
1061
1061
1062 def mayupdate(repo, node, show_stats=True):
1062 def mayupdate(repo, node, show_stats=True):
1063 """common used update sequence"""
1063 """common used update sequence"""
1064 if noupdate:
1064 if noupdate:
1065 return
1065 return
1066 cmdutil.checkunfinished(repo)
1066 cmdutil.checkunfinished(repo)
1067 cmdutil.bailifchanged(repo)
1067 cmdutil.bailifchanged(repo)
1068 return hg.clean(repo, node, show_stats=show_stats)
1068 return hg.clean(repo, node, show_stats=show_stats)
1069
1069
1070 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1070 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1071
1071
1072 if command:
1072 if command:
1073 changesets = 1
1073 changesets = 1
1074 if noupdate:
1074 if noupdate:
1075 try:
1075 try:
1076 node = state[b'current'][0]
1076 node = state[b'current'][0]
1077 except LookupError:
1077 except LookupError:
1078 raise error.StateError(
1078 raise error.StateError(
1079 _(
1079 _(
1080 b'current bisect revision is unknown - '
1080 b'current bisect revision is unknown - '
1081 b'start a new bisect to fix'
1081 b'start a new bisect to fix'
1082 )
1082 )
1083 )
1083 )
1084 else:
1084 else:
1085 node, p2 = repo.dirstate.parents()
1085 node, p2 = repo.dirstate.parents()
1086 if p2 != repo.nullid:
1086 if p2 != repo.nullid:
1087 raise error.StateError(_(b'current bisect revision is a merge'))
1087 raise error.StateError(_(b'current bisect revision is a merge'))
1088 if rev:
1088 if rev:
1089 if not nodes:
1089 if not nodes:
1090 raise error.Abort(_(b'empty revision set'))
1090 raise error.Abort(_(b'empty revision set'))
1091 node = repo[nodes[-1]].node()
1091 node = repo[nodes[-1]].node()
1092 with hbisect.restore_state(repo, state, node):
1092 with hbisect.restore_state(repo, state, node):
1093 while changesets:
1093 while changesets:
1094 # update state
1094 # update state
1095 state[b'current'] = [node]
1095 state[b'current'] = [node]
1096 hbisect.save_state(repo, state)
1096 hbisect.save_state(repo, state)
1097 status = ui.system(
1097 status = ui.system(
1098 command,
1098 command,
1099 environ={b'HG_NODE': hex(node)},
1099 environ={b'HG_NODE': hex(node)},
1100 blockedtag=b'bisect_check',
1100 blockedtag=b'bisect_check',
1101 )
1101 )
1102 if status == 125:
1102 if status == 125:
1103 transition = b"skip"
1103 transition = b"skip"
1104 elif status == 0:
1104 elif status == 0:
1105 transition = b"good"
1105 transition = b"good"
1106 # status < 0 means process was killed
1106 # status < 0 means process was killed
1107 elif status == 127:
1107 elif status == 127:
1108 raise error.Abort(_(b"failed to execute %s") % command)
1108 raise error.Abort(_(b"failed to execute %s") % command)
1109 elif status < 0:
1109 elif status < 0:
1110 raise error.Abort(_(b"%s killed") % command)
1110 raise error.Abort(_(b"%s killed") % command)
1111 else:
1111 else:
1112 transition = b"bad"
1112 transition = b"bad"
1113 state[transition].append(node)
1113 state[transition].append(node)
1114 ctx = repo[node]
1114 ctx = repo[node]
1115 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1115 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1116 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1116 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1117 hbisect.checkstate(state)
1117 hbisect.checkstate(state)
1118 # bisect
1118 # bisect
1119 nodes, changesets, bgood = hbisect.bisect(repo, state)
1119 nodes, changesets, bgood = hbisect.bisect(repo, state)
1120 # update to next check
1120 # update to next check
1121 node = nodes[0]
1121 node = nodes[0]
1122 mayupdate(repo, node, show_stats=False)
1122 mayupdate(repo, node, show_stats=False)
1123 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1123 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1124 return
1124 return
1125
1125
1126 hbisect.checkstate(state)
1126 hbisect.checkstate(state)
1127
1127
1128 # actually bisect
1128 # actually bisect
1129 nodes, changesets, good = hbisect.bisect(repo, state)
1129 nodes, changesets, good = hbisect.bisect(repo, state)
1130 if extend:
1130 if extend:
1131 if not changesets:
1131 if not changesets:
1132 extendctx = hbisect.extendrange(repo, state, nodes, good)
1132 extendctx = hbisect.extendrange(repo, state, nodes, good)
1133 if extendctx is not None:
1133 if extendctx is not None:
1134 ui.write(
1134 ui.write(
1135 _(b"Extending search to changeset %s\n")
1135 _(b"Extending search to changeset %s\n")
1136 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1136 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1137 )
1137 )
1138 state[b'current'] = [extendctx.node()]
1138 state[b'current'] = [extendctx.node()]
1139 hbisect.save_state(repo, state)
1139 hbisect.save_state(repo, state)
1140 return mayupdate(repo, extendctx.node())
1140 return mayupdate(repo, extendctx.node())
1141 raise error.StateError(_(b"nothing to extend"))
1141 raise error.StateError(_(b"nothing to extend"))
1142
1142
1143 if changesets == 0:
1143 if changesets == 0:
1144 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1144 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1145 else:
1145 else:
1146 assert len(nodes) == 1 # only a single node can be tested next
1146 assert len(nodes) == 1 # only a single node can be tested next
1147 node = nodes[0]
1147 node = nodes[0]
1148 # compute the approximate number of remaining tests
1148 # compute the approximate number of remaining tests
1149 tests, size = 0, 2
1149 tests, size = 0, 2
1150 while size <= changesets:
1150 while size <= changesets:
1151 tests, size = tests + 1, size * 2
1151 tests, size = tests + 1, size * 2
1152 rev = repo.changelog.rev(node)
1152 rev = repo.changelog.rev(node)
1153 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1153 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1154 ui.write(
1154 ui.write(
1155 _(
1155 _(
1156 b"Testing changeset %s "
1156 b"Testing changeset %s "
1157 b"(%d changesets remaining, ~%d tests)\n"
1157 b"(%d changesets remaining, ~%d tests)\n"
1158 )
1158 )
1159 % (summary, changesets, tests)
1159 % (summary, changesets, tests)
1160 )
1160 )
1161 state[b'current'] = [node]
1161 state[b'current'] = [node]
1162 hbisect.save_state(repo, state)
1162 hbisect.save_state(repo, state)
1163 return mayupdate(repo, node)
1163 return mayupdate(repo, node)
1164
1164
1165
1165
1166 @command(
1166 @command(
1167 b'bookmarks|bookmark',
1167 b'bookmarks|bookmark',
1168 [
1168 [
1169 (b'f', b'force', False, _(b'force')),
1169 (b'f', b'force', False, _(b'force')),
1170 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1170 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1171 (b'd', b'delete', False, _(b'delete a given bookmark')),
1171 (b'd', b'delete', False, _(b'delete a given bookmark')),
1172 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1172 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1173 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1173 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1174 (b'l', b'list', False, _(b'list existing bookmarks')),
1174 (b'l', b'list', False, _(b'list existing bookmarks')),
1175 ]
1175 ]
1176 + formatteropts,
1176 + formatteropts,
1177 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1177 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1178 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1178 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1179 )
1179 )
1180 def bookmark(ui, repo, *names, **opts):
1180 def bookmark(ui, repo, *names, **opts):
1181 """create a new bookmark or list existing bookmarks
1181 """create a new bookmark or list existing bookmarks
1182
1182
1183 Bookmarks are labels on changesets to help track lines of development.
1183 Bookmarks are labels on changesets to help track lines of development.
1184 Bookmarks are unversioned and can be moved, renamed and deleted.
1184 Bookmarks are unversioned and can be moved, renamed and deleted.
1185 Deleting or moving a bookmark has no effect on the associated changesets.
1185 Deleting or moving a bookmark has no effect on the associated changesets.
1186
1186
1187 Creating or updating to a bookmark causes it to be marked as 'active'.
1187 Creating or updating to a bookmark causes it to be marked as 'active'.
1188 The active bookmark is indicated with a '*'.
1188 The active bookmark is indicated with a '*'.
1189 When a commit is made, the active bookmark will advance to the new commit.
1189 When a commit is made, the active bookmark will advance to the new commit.
1190 A plain :hg:`update` will also advance an active bookmark, if possible.
1190 A plain :hg:`update` will also advance an active bookmark, if possible.
1191 Updating away from a bookmark will cause it to be deactivated.
1191 Updating away from a bookmark will cause it to be deactivated.
1192
1192
1193 Bookmarks can be pushed and pulled between repositories (see
1193 Bookmarks can be pushed and pulled between repositories (see
1194 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1194 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1195 diverged, a new 'divergent bookmark' of the form 'name@path' will
1195 diverged, a new 'divergent bookmark' of the form 'name@path' will
1196 be created. Using :hg:`merge` will resolve the divergence.
1196 be created. Using :hg:`merge` will resolve the divergence.
1197
1197
1198 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1198 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1199 the active bookmark's name.
1199 the active bookmark's name.
1200
1200
1201 A bookmark named '@' has the special property that :hg:`clone` will
1201 A bookmark named '@' has the special property that :hg:`clone` will
1202 check it out by default if it exists.
1202 check it out by default if it exists.
1203
1203
1204 .. container:: verbose
1204 .. container:: verbose
1205
1205
1206 Template:
1206 Template:
1207
1207
1208 The following keywords are supported in addition to the common template
1208 The following keywords are supported in addition to the common template
1209 keywords and functions such as ``{bookmark}``. See also
1209 keywords and functions such as ``{bookmark}``. See also
1210 :hg:`help templates`.
1210 :hg:`help templates`.
1211
1211
1212 :active: Boolean. True if the bookmark is active.
1212 :active: Boolean. True if the bookmark is active.
1213
1213
1214 Examples:
1214 Examples:
1215
1215
1216 - create an active bookmark for a new line of development::
1216 - create an active bookmark for a new line of development::
1217
1217
1218 hg book new-feature
1218 hg book new-feature
1219
1219
1220 - create an inactive bookmark as a place marker::
1220 - create an inactive bookmark as a place marker::
1221
1221
1222 hg book -i reviewed
1222 hg book -i reviewed
1223
1223
1224 - create an inactive bookmark on another changeset::
1224 - create an inactive bookmark on another changeset::
1225
1225
1226 hg book -r .^ tested
1226 hg book -r .^ tested
1227
1227
1228 - rename bookmark turkey to dinner::
1228 - rename bookmark turkey to dinner::
1229
1229
1230 hg book -m turkey dinner
1230 hg book -m turkey dinner
1231
1231
1232 - move the '@' bookmark from another branch::
1232 - move the '@' bookmark from another branch::
1233
1233
1234 hg book -f @
1234 hg book -f @
1235
1235
1236 - print only the active bookmark name::
1236 - print only the active bookmark name::
1237
1237
1238 hg book -ql .
1238 hg book -ql .
1239 """
1239 """
1240 opts = pycompat.byteskwargs(opts)
1240 opts = pycompat.byteskwargs(opts)
1241 force = opts.get(b'force')
1241 force = opts.get(b'force')
1242 rev = opts.get(b'rev')
1242 rev = opts.get(b'rev')
1243 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1243 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1244
1244
1245 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1245 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1246 if action:
1246 if action:
1247 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1247 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1248 elif names or rev:
1248 elif names or rev:
1249 action = b'add'
1249 action = b'add'
1250 elif inactive:
1250 elif inactive:
1251 action = b'inactive' # meaning deactivate
1251 action = b'inactive' # meaning deactivate
1252 else:
1252 else:
1253 action = b'list'
1253 action = b'list'
1254
1254
1255 cmdutil.check_incompatible_arguments(
1255 cmdutil.check_incompatible_arguments(
1256 opts, b'inactive', [b'delete', b'list']
1256 opts, b'inactive', [b'delete', b'list']
1257 )
1257 )
1258 if not names and action in {b'add', b'delete'}:
1258 if not names and action in {b'add', b'delete'}:
1259 raise error.InputError(_(b"bookmark name required"))
1259 raise error.InputError(_(b"bookmark name required"))
1260
1260
1261 if action in {b'add', b'delete', b'rename', b'inactive'}:
1261 if action in {b'add', b'delete', b'rename', b'inactive'}:
1262 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1262 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1263 if action == b'delete':
1263 if action == b'delete':
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 bookmarks.delete(repo, tr, names)
1265 bookmarks.delete(repo, tr, names)
1266 elif action == b'rename':
1266 elif action == b'rename':
1267 if not names:
1267 if not names:
1268 raise error.InputError(_(b"new bookmark name required"))
1268 raise error.InputError(_(b"new bookmark name required"))
1269 elif len(names) > 1:
1269 elif len(names) > 1:
1270 raise error.InputError(
1270 raise error.InputError(
1271 _(b"only one new bookmark name allowed")
1271 _(b"only one new bookmark name allowed")
1272 )
1272 )
1273 oldname = repo._bookmarks.expandname(opts[b'rename'])
1273 oldname = repo._bookmarks.expandname(opts[b'rename'])
1274 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1274 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1275 elif action == b'add':
1275 elif action == b'add':
1276 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1276 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1277 elif action == b'inactive':
1277 elif action == b'inactive':
1278 if len(repo._bookmarks) == 0:
1278 if len(repo._bookmarks) == 0:
1279 ui.status(_(b"no bookmarks set\n"))
1279 ui.status(_(b"no bookmarks set\n"))
1280 elif not repo._activebookmark:
1280 elif not repo._activebookmark:
1281 ui.status(_(b"no active bookmark\n"))
1281 ui.status(_(b"no active bookmark\n"))
1282 else:
1282 else:
1283 bookmarks.deactivate(repo)
1283 bookmarks.deactivate(repo)
1284 elif action == b'list':
1284 elif action == b'list':
1285 names = pycompat.maplist(repo._bookmarks.expandname, names)
1285 names = pycompat.maplist(repo._bookmarks.expandname, names)
1286 with ui.formatter(b'bookmarks', opts) as fm:
1286 with ui.formatter(b'bookmarks', opts) as fm:
1287 bookmarks.printbookmarks(ui, repo, fm, names)
1287 bookmarks.printbookmarks(ui, repo, fm, names)
1288 else:
1288 else:
1289 raise error.ProgrammingError(b'invalid action: %s' % action)
1289 raise error.ProgrammingError(b'invalid action: %s' % action)
1290
1290
1291
1291
1292 @command(
1292 @command(
1293 b'branch',
1293 b'branch',
1294 [
1294 [
1295 (
1295 (
1296 b'f',
1296 b'f',
1297 b'force',
1297 b'force',
1298 None,
1298 None,
1299 _(b'set branch name even if it shadows an existing branch'),
1299 _(b'set branch name even if it shadows an existing branch'),
1300 ),
1300 ),
1301 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1301 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1302 (
1302 (
1303 b'r',
1303 b'r',
1304 b'rev',
1304 b'rev',
1305 [],
1305 [],
1306 _(b'change branches of the given revs (EXPERIMENTAL)'),
1306 _(b'change branches of the given revs (EXPERIMENTAL)'),
1307 ),
1307 ),
1308 ],
1308 ],
1309 _(b'[-fC] [NAME]'),
1309 _(b'[-fC] [NAME]'),
1310 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1310 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1311 )
1311 )
1312 def branch(ui, repo, label=None, **opts):
1312 def branch(ui, repo, label=None, **opts):
1313 """set or show the current branch name
1313 """set or show the current branch name
1314
1314
1315 .. note::
1315 .. note::
1316
1316
1317 Branch names are permanent and global. Use :hg:`bookmark` to create a
1317 Branch names are permanent and global. Use :hg:`bookmark` to create a
1318 light-weight bookmark instead. See :hg:`help glossary` for more
1318 light-weight bookmark instead. See :hg:`help glossary` for more
1319 information about named branches and bookmarks.
1319 information about named branches and bookmarks.
1320
1320
1321 With no argument, show the current branch name. With one argument,
1321 With no argument, show the current branch name. With one argument,
1322 set the working directory branch name (the branch will not exist
1322 set the working directory branch name (the branch will not exist
1323 in the repository until the next commit). Standard practice
1323 in the repository until the next commit). Standard practice
1324 recommends that primary development take place on the 'default'
1324 recommends that primary development take place on the 'default'
1325 branch.
1325 branch.
1326
1326
1327 Unless -f/--force is specified, branch will not let you set a
1327 Unless -f/--force is specified, branch will not let you set a
1328 branch name that already exists.
1328 branch name that already exists.
1329
1329
1330 Use -C/--clean to reset the working directory branch to that of
1330 Use -C/--clean to reset the working directory branch to that of
1331 the parent of the working directory, negating a previous branch
1331 the parent of the working directory, negating a previous branch
1332 change.
1332 change.
1333
1333
1334 Use the command :hg:`update` to switch to an existing branch. Use
1334 Use the command :hg:`update` to switch to an existing branch. Use
1335 :hg:`commit --close-branch` to mark this branch head as closed.
1335 :hg:`commit --close-branch` to mark this branch head as closed.
1336 When all heads of a branch are closed, the branch will be
1336 When all heads of a branch are closed, the branch will be
1337 considered closed.
1337 considered closed.
1338
1338
1339 Returns 0 on success.
1339 Returns 0 on success.
1340 """
1340 """
1341 opts = pycompat.byteskwargs(opts)
1341 opts = pycompat.byteskwargs(opts)
1342 revs = opts.get(b'rev')
1342 revs = opts.get(b'rev')
1343 if label:
1343 if label:
1344 label = label.strip()
1344 label = label.strip()
1345
1345
1346 if not opts.get(b'clean') and not label:
1346 if not opts.get(b'clean') and not label:
1347 if revs:
1347 if revs:
1348 raise error.InputError(
1348 raise error.InputError(
1349 _(b"no branch name specified for the revisions")
1349 _(b"no branch name specified for the revisions")
1350 )
1350 )
1351 ui.write(b"%s\n" % repo.dirstate.branch())
1351 ui.write(b"%s\n" % repo.dirstate.branch())
1352 return
1352 return
1353
1353
1354 with repo.wlock():
1354 with repo.wlock():
1355 if opts.get(b'clean'):
1355 if opts.get(b'clean'):
1356 label = repo[b'.'].branch()
1356 label = repo[b'.'].branch()
1357 repo.dirstate.setbranch(label)
1357 repo.dirstate.setbranch(label)
1358 ui.status(_(b'reset working directory to branch %s\n') % label)
1358 ui.status(_(b'reset working directory to branch %s\n') % label)
1359 elif label:
1359 elif label:
1360
1360
1361 scmutil.checknewlabel(repo, label, b'branch')
1361 scmutil.checknewlabel(repo, label, b'branch')
1362 if revs:
1362 if revs:
1363 return cmdutil.changebranch(ui, repo, revs, label, opts)
1363 return cmdutil.changebranch(ui, repo, revs, label, opts)
1364
1364
1365 if not opts.get(b'force') and label in repo.branchmap():
1365 if not opts.get(b'force') and label in repo.branchmap():
1366 if label not in [p.branch() for p in repo[None].parents()]:
1366 if label not in [p.branch() for p in repo[None].parents()]:
1367 raise error.InputError(
1367 raise error.InputError(
1368 _(b'a branch of the same name already exists'),
1368 _(b'a branch of the same name already exists'),
1369 # i18n: "it" refers to an existing branch
1369 # i18n: "it" refers to an existing branch
1370 hint=_(b"use 'hg update' to switch to it"),
1370 hint=_(b"use 'hg update' to switch to it"),
1371 )
1371 )
1372
1372
1373 repo.dirstate.setbranch(label)
1373 repo.dirstate.setbranch(label)
1374 ui.status(_(b'marked working directory as branch %s\n') % label)
1374 ui.status(_(b'marked working directory as branch %s\n') % label)
1375
1375
1376 # find any open named branches aside from default
1376 # find any open named branches aside from default
1377 for n, h, t, c in repo.branchmap().iterbranches():
1377 for n, h, t, c in repo.branchmap().iterbranches():
1378 if n != b"default" and not c:
1378 if n != b"default" and not c:
1379 return 0
1379 return 0
1380 ui.status(
1380 ui.status(
1381 _(
1381 _(
1382 b'(branches are permanent and global, '
1382 b'(branches are permanent and global, '
1383 b'did you want a bookmark?)\n'
1383 b'did you want a bookmark?)\n'
1384 )
1384 )
1385 )
1385 )
1386
1386
1387
1387
1388 @command(
1388 @command(
1389 b'branches',
1389 b'branches',
1390 [
1390 [
1391 (
1391 (
1392 b'a',
1392 b'a',
1393 b'active',
1393 b'active',
1394 False,
1394 False,
1395 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1395 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1396 ),
1396 ),
1397 (b'c', b'closed', False, _(b'show normal and closed branches')),
1397 (b'c', b'closed', False, _(b'show normal and closed branches')),
1398 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1398 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1399 ]
1399 ]
1400 + formatteropts,
1400 + formatteropts,
1401 _(b'[-c]'),
1401 _(b'[-c]'),
1402 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1402 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1403 intents={INTENT_READONLY},
1403 intents={INTENT_READONLY},
1404 )
1404 )
1405 def branches(ui, repo, active=False, closed=False, **opts):
1405 def branches(ui, repo, active=False, closed=False, **opts):
1406 """list repository named branches
1406 """list repository named branches
1407
1407
1408 List the repository's named branches, indicating which ones are
1408 List the repository's named branches, indicating which ones are
1409 inactive. If -c/--closed is specified, also list branches which have
1409 inactive. If -c/--closed is specified, also list branches which have
1410 been marked closed (see :hg:`commit --close-branch`).
1410 been marked closed (see :hg:`commit --close-branch`).
1411
1411
1412 Use the command :hg:`update` to switch to an existing branch.
1412 Use the command :hg:`update` to switch to an existing branch.
1413
1413
1414 .. container:: verbose
1414 .. container:: verbose
1415
1415
1416 Template:
1416 Template:
1417
1417
1418 The following keywords are supported in addition to the common template
1418 The following keywords are supported in addition to the common template
1419 keywords and functions such as ``{branch}``. See also
1419 keywords and functions such as ``{branch}``. See also
1420 :hg:`help templates`.
1420 :hg:`help templates`.
1421
1421
1422 :active: Boolean. True if the branch is active.
1422 :active: Boolean. True if the branch is active.
1423 :closed: Boolean. True if the branch is closed.
1423 :closed: Boolean. True if the branch is closed.
1424 :current: Boolean. True if it is the current branch.
1424 :current: Boolean. True if it is the current branch.
1425
1425
1426 Returns 0.
1426 Returns 0.
1427 """
1427 """
1428
1428
1429 opts = pycompat.byteskwargs(opts)
1429 opts = pycompat.byteskwargs(opts)
1430 revs = opts.get(b'rev')
1430 revs = opts.get(b'rev')
1431 selectedbranches = None
1431 selectedbranches = None
1432 if revs:
1432 if revs:
1433 revs = scmutil.revrange(repo, revs)
1433 revs = scmutil.revrange(repo, revs)
1434 getbi = repo.revbranchcache().branchinfo
1434 getbi = repo.revbranchcache().branchinfo
1435 selectedbranches = {getbi(r)[0] for r in revs}
1435 selectedbranches = {getbi(r)[0] for r in revs}
1436
1436
1437 ui.pager(b'branches')
1437 ui.pager(b'branches')
1438 fm = ui.formatter(b'branches', opts)
1438 fm = ui.formatter(b'branches', opts)
1439 hexfunc = fm.hexfunc
1439 hexfunc = fm.hexfunc
1440
1440
1441 allheads = set(repo.heads())
1441 allheads = set(repo.heads())
1442 branches = []
1442 branches = []
1443 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1443 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1444 if selectedbranches is not None and tag not in selectedbranches:
1444 if selectedbranches is not None and tag not in selectedbranches:
1445 continue
1445 continue
1446 isactive = False
1446 isactive = False
1447 if not isclosed:
1447 if not isclosed:
1448 openheads = set(repo.branchmap().iteropen(heads))
1448 openheads = set(repo.branchmap().iteropen(heads))
1449 isactive = bool(openheads & allheads)
1449 isactive = bool(openheads & allheads)
1450 branches.append((tag, repo[tip], isactive, not isclosed))
1450 branches.append((tag, repo[tip], isactive, not isclosed))
1451 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1451 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1452
1452
1453 for tag, ctx, isactive, isopen in branches:
1453 for tag, ctx, isactive, isopen in branches:
1454 if active and not isactive:
1454 if active and not isactive:
1455 continue
1455 continue
1456 if isactive:
1456 if isactive:
1457 label = b'branches.active'
1457 label = b'branches.active'
1458 notice = b''
1458 notice = b''
1459 elif not isopen:
1459 elif not isopen:
1460 if not closed:
1460 if not closed:
1461 continue
1461 continue
1462 label = b'branches.closed'
1462 label = b'branches.closed'
1463 notice = _(b' (closed)')
1463 notice = _(b' (closed)')
1464 else:
1464 else:
1465 label = b'branches.inactive'
1465 label = b'branches.inactive'
1466 notice = _(b' (inactive)')
1466 notice = _(b' (inactive)')
1467 current = tag == repo.dirstate.branch()
1467 current = tag == repo.dirstate.branch()
1468 if current:
1468 if current:
1469 label = b'branches.current'
1469 label = b'branches.current'
1470
1470
1471 fm.startitem()
1471 fm.startitem()
1472 fm.write(b'branch', b'%s', tag, label=label)
1472 fm.write(b'branch', b'%s', tag, label=label)
1473 rev = ctx.rev()
1473 rev = ctx.rev()
1474 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1474 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1475 fmt = b' ' * padsize + b' %d:%s'
1475 fmt = b' ' * padsize + b' %d:%s'
1476 fm.condwrite(
1476 fm.condwrite(
1477 not ui.quiet,
1477 not ui.quiet,
1478 b'rev node',
1478 b'rev node',
1479 fmt,
1479 fmt,
1480 rev,
1480 rev,
1481 hexfunc(ctx.node()),
1481 hexfunc(ctx.node()),
1482 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1482 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1483 )
1483 )
1484 fm.context(ctx=ctx)
1484 fm.context(ctx=ctx)
1485 fm.data(active=isactive, closed=not isopen, current=current)
1485 fm.data(active=isactive, closed=not isopen, current=current)
1486 if not ui.quiet:
1486 if not ui.quiet:
1487 fm.plain(notice)
1487 fm.plain(notice)
1488 fm.plain(b'\n')
1488 fm.plain(b'\n')
1489 fm.end()
1489 fm.end()
1490
1490
1491
1491
1492 @command(
1492 @command(
1493 b'bundle',
1493 b'bundle',
1494 [
1494 [
1495 (
1495 (
1496 b'f',
1496 b'f',
1497 b'force',
1497 b'force',
1498 None,
1498 None,
1499 _(b'run even when the destination is unrelated'),
1499 _(b'run even when the destination is unrelated'),
1500 ),
1500 ),
1501 (
1501 (
1502 b'r',
1502 b'r',
1503 b'rev',
1503 b'rev',
1504 [],
1504 [],
1505 _(b'a changeset intended to be added to the destination'),
1505 _(b'a changeset intended to be added to the destination'),
1506 _(b'REV'),
1506 _(b'REV'),
1507 ),
1507 ),
1508 (
1508 (
1509 b'b',
1509 b'b',
1510 b'branch',
1510 b'branch',
1511 [],
1511 [],
1512 _(b'a specific branch you would like to bundle'),
1512 _(b'a specific branch you would like to bundle'),
1513 _(b'BRANCH'),
1513 _(b'BRANCH'),
1514 ),
1514 ),
1515 (
1515 (
1516 b'',
1516 b'',
1517 b'base',
1517 b'base',
1518 [],
1518 [],
1519 _(b'a base changeset assumed to be available at the destination'),
1519 _(b'a base changeset assumed to be available at the destination'),
1520 _(b'REV'),
1520 _(b'REV'),
1521 ),
1521 ),
1522 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1522 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1523 (
1523 (
1524 b't',
1524 b't',
1525 b'type',
1525 b'type',
1526 b'bzip2',
1526 b'bzip2',
1527 _(b'bundle compression type to use'),
1527 _(b'bundle compression type to use'),
1528 _(b'TYPE'),
1528 _(b'TYPE'),
1529 ),
1529 ),
1530 ]
1530 ]
1531 + remoteopts,
1531 + remoteopts,
1532 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1532 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1533 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1533 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1534 )
1534 )
1535 def bundle(ui, repo, fname, *dests, **opts):
1535 def bundle(ui, repo, fname, *dests, **opts):
1536 """create a bundle file
1536 """create a bundle file
1537
1537
1538 Generate a bundle file containing data to be transferred to another
1538 Generate a bundle file containing data to be transferred to another
1539 repository.
1539 repository.
1540
1540
1541 To create a bundle containing all changesets, use -a/--all
1541 To create a bundle containing all changesets, use -a/--all
1542 (or --base null). Otherwise, hg assumes the destination will have
1542 (or --base null). Otherwise, hg assumes the destination will have
1543 all the nodes you specify with --base parameters. Otherwise, hg
1543 all the nodes you specify with --base parameters. Otherwise, hg
1544 will assume the repository has all the nodes in destination, or
1544 will assume the repository has all the nodes in destination, or
1545 default-push/default if no destination is specified, where destination
1545 default-push/default if no destination is specified, where destination
1546 is the repositories you provide through DEST option.
1546 is the repositories you provide through DEST option.
1547
1547
1548 You can change bundle format with the -t/--type option. See
1548 You can change bundle format with the -t/--type option. See
1549 :hg:`help bundlespec` for documentation on this format. By default,
1549 :hg:`help bundlespec` for documentation on this format. By default,
1550 the most appropriate format is used and compression defaults to
1550 the most appropriate format is used and compression defaults to
1551 bzip2.
1551 bzip2.
1552
1552
1553 The bundle file can then be transferred using conventional means
1553 The bundle file can then be transferred using conventional means
1554 and applied to another repository with the unbundle or pull
1554 and applied to another repository with the unbundle or pull
1555 command. This is useful when direct push and pull are not
1555 command. This is useful when direct push and pull are not
1556 available or when exporting an entire repository is undesirable.
1556 available or when exporting an entire repository is undesirable.
1557
1557
1558 Applying bundles preserves all changeset contents including
1558 Applying bundles preserves all changeset contents including
1559 permissions, copy/rename information, and revision history.
1559 permissions, copy/rename information, and revision history.
1560
1560
1561 Returns 0 on success, 1 if no changes found.
1561 Returns 0 on success, 1 if no changes found.
1562 """
1562 """
1563 opts = pycompat.byteskwargs(opts)
1563 opts = pycompat.byteskwargs(opts)
1564 revs = None
1564 revs = None
1565 if b'rev' in opts:
1565 if b'rev' in opts:
1566 revstrings = opts[b'rev']
1566 revstrings = opts[b'rev']
1567 revs = scmutil.revrange(repo, revstrings)
1567 revs = scmutil.revrange(repo, revstrings)
1568 if revstrings and not revs:
1568 if revstrings and not revs:
1569 raise error.InputError(_(b'no commits to bundle'))
1569 raise error.InputError(_(b'no commits to bundle'))
1570
1570
1571 bundletype = opts.get(b'type', b'bzip2').lower()
1571 bundletype = opts.get(b'type', b'bzip2').lower()
1572 try:
1572 try:
1573 bundlespec = bundlecaches.parsebundlespec(
1573 bundlespec = bundlecaches.parsebundlespec(
1574 repo, bundletype, strict=False
1574 repo, bundletype, strict=False
1575 )
1575 )
1576 except error.UnsupportedBundleSpecification as e:
1576 except error.UnsupportedBundleSpecification as e:
1577 raise error.InputError(
1577 raise error.InputError(
1578 pycompat.bytestr(e),
1578 pycompat.bytestr(e),
1579 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1579 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1580 )
1580 )
1581 cgversion = bundlespec.contentopts[b"cg.version"]
1581 cgversion = bundlespec.contentopts[b"cg.version"]
1582
1582
1583 # Packed bundles are a pseudo bundle format for now.
1583 # Packed bundles are a pseudo bundle format for now.
1584 if cgversion == b's1':
1584 if cgversion == b's1':
1585 raise error.InputError(
1585 raise error.InputError(
1586 _(b'packed bundles cannot be produced by "hg bundle"'),
1586 _(b'packed bundles cannot be produced by "hg bundle"'),
1587 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1587 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1588 )
1588 )
1589
1589
1590 if opts.get(b'all'):
1590 if opts.get(b'all'):
1591 if dests:
1591 if dests:
1592 raise error.InputError(
1592 raise error.InputError(
1593 _(b"--all is incompatible with specifying destinations")
1593 _(b"--all is incompatible with specifying destinations")
1594 )
1594 )
1595 if opts.get(b'base'):
1595 if opts.get(b'base'):
1596 ui.warn(_(b"ignoring --base because --all was specified\n"))
1596 ui.warn(_(b"ignoring --base because --all was specified\n"))
1597 base = [nullrev]
1597 base = [nullrev]
1598 else:
1598 else:
1599 base = scmutil.revrange(repo, opts.get(b'base'))
1599 base = scmutil.revrange(repo, opts.get(b'base'))
1600 if cgversion not in changegroup.supportedoutgoingversions(repo):
1600 if cgversion not in changegroup.supportedoutgoingversions(repo):
1601 raise error.Abort(
1601 raise error.Abort(
1602 _(b"repository does not support bundle version %s") % cgversion
1602 _(b"repository does not support bundle version %s") % cgversion
1603 )
1603 )
1604
1604
1605 if base:
1605 if base:
1606 if dests:
1606 if dests:
1607 raise error.InputError(
1607 raise error.InputError(
1608 _(b"--base is incompatible with specifying destinations")
1608 _(b"--base is incompatible with specifying destinations")
1609 )
1609 )
1610 common = [repo[rev].node() for rev in base]
1610 common = [repo[rev].node() for rev in base]
1611 heads = [repo[r].node() for r in revs] if revs else None
1611 heads = [repo[r].node() for r in revs] if revs else None
1612 outgoing = discovery.outgoing(repo, common, heads)
1612 outgoing = discovery.outgoing(repo, common, heads)
1613 missing = outgoing.missing
1613 missing = outgoing.missing
1614 excluded = outgoing.excluded
1614 excluded = outgoing.excluded
1615 else:
1615 else:
1616 missing = set()
1616 missing = set()
1617 excluded = set()
1617 excluded = set()
1618 for path in urlutil.get_push_paths(repo, ui, dests):
1618 for path in urlutil.get_push_paths(repo, ui, dests):
1619 other = hg.peer(repo, opts, path.rawloc)
1619 other = hg.peer(repo, opts, path.rawloc)
1620 if revs is not None:
1620 if revs is not None:
1621 hex_revs = [repo[r].hex() for r in revs]
1621 hex_revs = [repo[r].hex() for r in revs]
1622 else:
1622 else:
1623 hex_revs = None
1623 hex_revs = None
1624 branches = (path.branch, [])
1624 branches = (path.branch, [])
1625 head_revs, checkout = hg.addbranchrevs(
1625 head_revs, checkout = hg.addbranchrevs(
1626 repo, repo, branches, hex_revs
1626 repo, repo, branches, hex_revs
1627 )
1627 )
1628 heads = (
1628 heads = (
1629 head_revs
1629 head_revs
1630 and pycompat.maplist(repo.lookup, head_revs)
1630 and pycompat.maplist(repo.lookup, head_revs)
1631 or head_revs
1631 or head_revs
1632 )
1632 )
1633 outgoing = discovery.findcommonoutgoing(
1633 outgoing = discovery.findcommonoutgoing(
1634 repo,
1634 repo,
1635 other,
1635 other,
1636 onlyheads=heads,
1636 onlyheads=heads,
1637 force=opts.get(b'force'),
1637 force=opts.get(b'force'),
1638 portable=True,
1638 portable=True,
1639 )
1639 )
1640 missing.update(outgoing.missing)
1640 missing.update(outgoing.missing)
1641 excluded.update(outgoing.excluded)
1641 excluded.update(outgoing.excluded)
1642
1642
1643 if not missing:
1643 if not missing:
1644 scmutil.nochangesfound(ui, repo, not base and excluded)
1644 scmutil.nochangesfound(ui, repo, not base and excluded)
1645 return 1
1645 return 1
1646
1646
1647 if heads:
1647 if heads:
1648 outgoing = discovery.outgoing(
1648 outgoing = discovery.outgoing(
1649 repo, missingroots=missing, ancestorsof=heads
1649 repo, missingroots=missing, ancestorsof=heads
1650 )
1650 )
1651 else:
1651 else:
1652 outgoing = discovery.outgoing(repo, missingroots=missing)
1652 outgoing = discovery.outgoing(repo, missingroots=missing)
1653 outgoing.excluded = sorted(excluded)
1653 outgoing.excluded = sorted(excluded)
1654
1654
1655 if cgversion == b'01': # bundle1
1655 if cgversion == b'01': # bundle1
1656 bversion = b'HG10' + bundlespec.wirecompression
1656 bversion = b'HG10' + bundlespec.wirecompression
1657 bcompression = None
1657 bcompression = None
1658 elif cgversion in (b'02', b'03'):
1658 elif cgversion in (b'02', b'03'):
1659 bversion = b'HG20'
1659 bversion = b'HG20'
1660 bcompression = bundlespec.wirecompression
1660 bcompression = bundlespec.wirecompression
1661 else:
1661 else:
1662 raise error.ProgrammingError(
1662 raise error.ProgrammingError(
1663 b'bundle: unexpected changegroup version %s' % cgversion
1663 b'bundle: unexpected changegroup version %s' % cgversion
1664 )
1664 )
1665
1665
1666 # TODO compression options should be derived from bundlespec parsing.
1666 # TODO compression options should be derived from bundlespec parsing.
1667 # This is a temporary hack to allow adjusting bundle compression
1667 # This is a temporary hack to allow adjusting bundle compression
1668 # level without a) formalizing the bundlespec changes to declare it
1668 # level without a) formalizing the bundlespec changes to declare it
1669 # b) introducing a command flag.
1669 # b) introducing a command flag.
1670 compopts = {}
1670 compopts = {}
1671 complevel = ui.configint(
1671 complevel = ui.configint(
1672 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1672 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1673 )
1673 )
1674 if complevel is None:
1674 if complevel is None:
1675 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1675 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1676 if complevel is not None:
1676 if complevel is not None:
1677 compopts[b'level'] = complevel
1677 compopts[b'level'] = complevel
1678
1678
1679 compthreads = ui.configint(
1679 compthreads = ui.configint(
1680 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1680 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1681 )
1681 )
1682 if compthreads is None:
1682 if compthreads is None:
1683 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1683 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1684 if compthreads is not None:
1684 if compthreads is not None:
1685 compopts[b'threads'] = compthreads
1685 compopts[b'threads'] = compthreads
1686
1686
1687 # Bundling of obsmarker and phases is optional as not all clients
1687 # Bundling of obsmarker and phases is optional as not all clients
1688 # support the necessary features.
1688 # support the necessary features.
1689 cfg = ui.configbool
1689 cfg = ui.configbool
1690 contentopts = {
1690 contentopts = {
1691 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1691 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1692 b'obsolescence-mandatory': cfg(
1692 b'obsolescence-mandatory': cfg(
1693 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1693 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1694 ),
1694 ),
1695 b'phases': cfg(b'experimental', b'bundle-phases'),
1695 b'phases': cfg(b'experimental', b'bundle-phases'),
1696 }
1696 }
1697 bundlespec.contentopts.update(contentopts)
1697 bundlespec.contentopts.update(contentopts)
1698
1698
1699 bundle2.writenewbundle(
1699 bundle2.writenewbundle(
1700 ui,
1700 ui,
1701 repo,
1701 repo,
1702 b'bundle',
1702 b'bundle',
1703 fname,
1703 fname,
1704 bversion,
1704 bversion,
1705 outgoing,
1705 outgoing,
1706 bundlespec.contentopts,
1706 bundlespec.contentopts,
1707 compression=bcompression,
1707 compression=bcompression,
1708 compopts=compopts,
1708 compopts=compopts,
1709 )
1709 )
1710
1710
1711
1711
1712 @command(
1712 @command(
1713 b'cat',
1713 b'cat',
1714 [
1714 [
1715 (
1715 (
1716 b'o',
1716 b'o',
1717 b'output',
1717 b'output',
1718 b'',
1718 b'',
1719 _(b'print output to file with formatted name'),
1719 _(b'print output to file with formatted name'),
1720 _(b'FORMAT'),
1720 _(b'FORMAT'),
1721 ),
1721 ),
1722 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1722 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1723 (b'', b'decode', None, _(b'apply any matching decode filter')),
1723 (b'', b'decode', None, _(b'apply any matching decode filter')),
1724 ]
1724 ]
1725 + walkopts
1725 + walkopts
1726 + formatteropts,
1726 + formatteropts,
1727 _(b'[OPTION]... FILE...'),
1727 _(b'[OPTION]... FILE...'),
1728 helpcategory=command.CATEGORY_FILE_CONTENTS,
1728 helpcategory=command.CATEGORY_FILE_CONTENTS,
1729 inferrepo=True,
1729 inferrepo=True,
1730 intents={INTENT_READONLY},
1730 intents={INTENT_READONLY},
1731 )
1731 )
1732 def cat(ui, repo, file1, *pats, **opts):
1732 def cat(ui, repo, file1, *pats, **opts):
1733 """output the current or given revision of files
1733 """output the current or given revision of files
1734
1734
1735 Print the specified files as they were at the given revision. If
1735 Print the specified files as they were at the given revision. If
1736 no revision is given, the parent of the working directory is used.
1736 no revision is given, the parent of the working directory is used.
1737
1737
1738 Output may be to a file, in which case the name of the file is
1738 Output may be to a file, in which case the name of the file is
1739 given using a template string. See :hg:`help templates`. In addition
1739 given using a template string. See :hg:`help templates`. In addition
1740 to the common template keywords, the following formatting rules are
1740 to the common template keywords, the following formatting rules are
1741 supported:
1741 supported:
1742
1742
1743 :``%%``: literal "%" character
1743 :``%%``: literal "%" character
1744 :``%s``: basename of file being printed
1744 :``%s``: basename of file being printed
1745 :``%d``: dirname of file being printed, or '.' if in repository root
1745 :``%d``: dirname of file being printed, or '.' if in repository root
1746 :``%p``: root-relative path name of file being printed
1746 :``%p``: root-relative path name of file being printed
1747 :``%H``: changeset hash (40 hexadecimal digits)
1747 :``%H``: changeset hash (40 hexadecimal digits)
1748 :``%R``: changeset revision number
1748 :``%R``: changeset revision number
1749 :``%h``: short-form changeset hash (12 hexadecimal digits)
1749 :``%h``: short-form changeset hash (12 hexadecimal digits)
1750 :``%r``: zero-padded changeset revision number
1750 :``%r``: zero-padded changeset revision number
1751 :``%b``: basename of the exporting repository
1751 :``%b``: basename of the exporting repository
1752 :``\\``: literal "\\" character
1752 :``\\``: literal "\\" character
1753
1753
1754 .. container:: verbose
1754 .. container:: verbose
1755
1755
1756 Template:
1756 Template:
1757
1757
1758 The following keywords are supported in addition to the common template
1758 The following keywords are supported in addition to the common template
1759 keywords and functions. See also :hg:`help templates`.
1759 keywords and functions. See also :hg:`help templates`.
1760
1760
1761 :data: String. File content.
1761 :data: String. File content.
1762 :path: String. Repository-absolute path of the file.
1762 :path: String. Repository-absolute path of the file.
1763
1763
1764 Returns 0 on success.
1764 Returns 0 on success.
1765 """
1765 """
1766 opts = pycompat.byteskwargs(opts)
1766 opts = pycompat.byteskwargs(opts)
1767 rev = opts.get(b'rev')
1767 rev = opts.get(b'rev')
1768 if rev:
1768 if rev:
1769 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1769 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1770 ctx = scmutil.revsingle(repo, rev)
1770 ctx = scmutil.revsingle(repo, rev)
1771 m = scmutil.match(ctx, (file1,) + pats, opts)
1771 m = scmutil.match(ctx, (file1,) + pats, opts)
1772 fntemplate = opts.pop(b'output', b'')
1772 fntemplate = opts.pop(b'output', b'')
1773 if cmdutil.isstdiofilename(fntemplate):
1773 if cmdutil.isstdiofilename(fntemplate):
1774 fntemplate = b''
1774 fntemplate = b''
1775
1775
1776 if fntemplate:
1776 if fntemplate:
1777 fm = formatter.nullformatter(ui, b'cat', opts)
1777 fm = formatter.nullformatter(ui, b'cat', opts)
1778 else:
1778 else:
1779 ui.pager(b'cat')
1779 ui.pager(b'cat')
1780 fm = ui.formatter(b'cat', opts)
1780 fm = ui.formatter(b'cat', opts)
1781 with fm:
1781 with fm:
1782 return cmdutil.cat(
1782 return cmdutil.cat(
1783 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1783 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1784 )
1784 )
1785
1785
1786
1786
1787 @command(
1787 @command(
1788 b'clone',
1788 b'clone',
1789 [
1789 [
1790 (
1790 (
1791 b'U',
1791 b'U',
1792 b'noupdate',
1792 b'noupdate',
1793 None,
1793 None,
1794 _(
1794 _(
1795 b'the clone will include an empty working '
1795 b'the clone will include an empty working '
1796 b'directory (only a repository)'
1796 b'directory (only a repository)'
1797 ),
1797 ),
1798 ),
1798 ),
1799 (
1799 (
1800 b'u',
1800 b'u',
1801 b'updaterev',
1801 b'updaterev',
1802 b'',
1802 b'',
1803 _(b'revision, tag, or branch to check out'),
1803 _(b'revision, tag, or branch to check out'),
1804 _(b'REV'),
1804 _(b'REV'),
1805 ),
1805 ),
1806 (
1806 (
1807 b'r',
1807 b'r',
1808 b'rev',
1808 b'rev',
1809 [],
1809 [],
1810 _(
1810 _(
1811 b'do not clone everything, but include this changeset'
1811 b'do not clone everything, but include this changeset'
1812 b' and its ancestors'
1812 b' and its ancestors'
1813 ),
1813 ),
1814 _(b'REV'),
1814 _(b'REV'),
1815 ),
1815 ),
1816 (
1816 (
1817 b'b',
1817 b'b',
1818 b'branch',
1818 b'branch',
1819 [],
1819 [],
1820 _(
1820 _(
1821 b'do not clone everything, but include this branch\'s'
1821 b'do not clone everything, but include this branch\'s'
1822 b' changesets and their ancestors'
1822 b' changesets and their ancestors'
1823 ),
1823 ),
1824 _(b'BRANCH'),
1824 _(b'BRANCH'),
1825 ),
1825 ),
1826 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1826 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1827 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1827 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1828 (b'', b'stream', None, _(b'clone with minimal data processing')),
1828 (b'', b'stream', None, _(b'clone with minimal data processing')),
1829 ]
1829 ]
1830 + remoteopts,
1830 + remoteopts,
1831 _(b'[OPTION]... SOURCE [DEST]'),
1831 _(b'[OPTION]... SOURCE [DEST]'),
1832 helpcategory=command.CATEGORY_REPO_CREATION,
1832 helpcategory=command.CATEGORY_REPO_CREATION,
1833 helpbasic=True,
1833 helpbasic=True,
1834 norepo=True,
1834 norepo=True,
1835 )
1835 )
1836 def clone(ui, source, dest=None, **opts):
1836 def clone(ui, source, dest=None, **opts):
1837 """make a copy of an existing repository
1837 """make a copy of an existing repository
1838
1838
1839 Create a copy of an existing repository in a new directory.
1839 Create a copy of an existing repository in a new directory.
1840
1840
1841 If no destination directory name is specified, it defaults to the
1841 If no destination directory name is specified, it defaults to the
1842 basename of the source.
1842 basename of the source.
1843
1843
1844 The location of the source is added to the new repository's
1844 The location of the source is added to the new repository's
1845 ``.hg/hgrc`` file, as the default to be used for future pulls.
1845 ``.hg/hgrc`` file, as the default to be used for future pulls.
1846
1846
1847 Only local paths and ``ssh://`` URLs are supported as
1847 Only local paths and ``ssh://`` URLs are supported as
1848 destinations. For ``ssh://`` destinations, no working directory or
1848 destinations. For ``ssh://`` destinations, no working directory or
1849 ``.hg/hgrc`` will be created on the remote side.
1849 ``.hg/hgrc`` will be created on the remote side.
1850
1850
1851 If the source repository has a bookmark called '@' set, that
1851 If the source repository has a bookmark called '@' set, that
1852 revision will be checked out in the new repository by default.
1852 revision will be checked out in the new repository by default.
1853
1853
1854 To check out a particular version, use -u/--update, or
1854 To check out a particular version, use -u/--update, or
1855 -U/--noupdate to create a clone with no working directory.
1855 -U/--noupdate to create a clone with no working directory.
1856
1856
1857 To pull only a subset of changesets, specify one or more revisions
1857 To pull only a subset of changesets, specify one or more revisions
1858 identifiers with -r/--rev or branches with -b/--branch. The
1858 identifiers with -r/--rev or branches with -b/--branch. The
1859 resulting clone will contain only the specified changesets and
1859 resulting clone will contain only the specified changesets and
1860 their ancestors. These options (or 'clone src#rev dest') imply
1860 their ancestors. These options (or 'clone src#rev dest') imply
1861 --pull, even for local source repositories.
1861 --pull, even for local source repositories.
1862
1862
1863 In normal clone mode, the remote normalizes repository data into a common
1863 In normal clone mode, the remote normalizes repository data into a common
1864 exchange format and the receiving end translates this data into its local
1864 exchange format and the receiving end translates this data into its local
1865 storage format. --stream activates a different clone mode that essentially
1865 storage format. --stream activates a different clone mode that essentially
1866 copies repository files from the remote with minimal data processing. This
1866 copies repository files from the remote with minimal data processing. This
1867 significantly reduces the CPU cost of a clone both remotely and locally.
1867 significantly reduces the CPU cost of a clone both remotely and locally.
1868 However, it often increases the transferred data size by 30-40%. This can
1868 However, it often increases the transferred data size by 30-40%. This can
1869 result in substantially faster clones where I/O throughput is plentiful,
1869 result in substantially faster clones where I/O throughput is plentiful,
1870 especially for larger repositories. A side-effect of --stream clones is
1870 especially for larger repositories. A side-effect of --stream clones is
1871 that storage settings and requirements on the remote are applied locally:
1871 that storage settings and requirements on the remote are applied locally:
1872 a modern client may inherit legacy or inefficient storage used by the
1872 a modern client may inherit legacy or inefficient storage used by the
1873 remote or a legacy Mercurial client may not be able to clone from a
1873 remote or a legacy Mercurial client may not be able to clone from a
1874 modern Mercurial remote.
1874 modern Mercurial remote.
1875
1875
1876 .. note::
1876 .. note::
1877
1877
1878 Specifying a tag will include the tagged changeset but not the
1878 Specifying a tag will include the tagged changeset but not the
1879 changeset containing the tag.
1879 changeset containing the tag.
1880
1880
1881 .. container:: verbose
1881 .. container:: verbose
1882
1882
1883 For efficiency, hardlinks are used for cloning whenever the
1883 For efficiency, hardlinks are used for cloning whenever the
1884 source and destination are on the same filesystem (note this
1884 source and destination are on the same filesystem (note this
1885 applies only to the repository data, not to the working
1885 applies only to the repository data, not to the working
1886 directory). Some filesystems, such as AFS, implement hardlinking
1886 directory). Some filesystems, such as AFS, implement hardlinking
1887 incorrectly, but do not report errors. In these cases, use the
1887 incorrectly, but do not report errors. In these cases, use the
1888 --pull option to avoid hardlinking.
1888 --pull option to avoid hardlinking.
1889
1889
1890 Mercurial will update the working directory to the first applicable
1890 Mercurial will update the working directory to the first applicable
1891 revision from this list:
1891 revision from this list:
1892
1892
1893 a) null if -U or the source repository has no changesets
1893 a) null if -U or the source repository has no changesets
1894 b) if -u . and the source repository is local, the first parent of
1894 b) if -u . and the source repository is local, the first parent of
1895 the source repository's working directory
1895 the source repository's working directory
1896 c) the changeset specified with -u (if a branch name, this means the
1896 c) the changeset specified with -u (if a branch name, this means the
1897 latest head of that branch)
1897 latest head of that branch)
1898 d) the changeset specified with -r
1898 d) the changeset specified with -r
1899 e) the tipmost head specified with -b
1899 e) the tipmost head specified with -b
1900 f) the tipmost head specified with the url#branch source syntax
1900 f) the tipmost head specified with the url#branch source syntax
1901 g) the revision marked with the '@' bookmark, if present
1901 g) the revision marked with the '@' bookmark, if present
1902 h) the tipmost head of the default branch
1902 h) the tipmost head of the default branch
1903 i) tip
1903 i) tip
1904
1904
1905 When cloning from servers that support it, Mercurial may fetch
1905 When cloning from servers that support it, Mercurial may fetch
1906 pre-generated data from a server-advertised URL or inline from the
1906 pre-generated data from a server-advertised URL or inline from the
1907 same stream. When this is done, hooks operating on incoming changesets
1907 same stream. When this is done, hooks operating on incoming changesets
1908 and changegroups may fire more than once, once for each pre-generated
1908 and changegroups may fire more than once, once for each pre-generated
1909 bundle and as well as for any additional remaining data. In addition,
1909 bundle and as well as for any additional remaining data. In addition,
1910 if an error occurs, the repository may be rolled back to a partial
1910 if an error occurs, the repository may be rolled back to a partial
1911 clone. This behavior may change in future releases.
1911 clone. This behavior may change in future releases.
1912 See :hg:`help -e clonebundles` for more.
1912 See :hg:`help -e clonebundles` for more.
1913
1913
1914 Examples:
1914 Examples:
1915
1915
1916 - clone a remote repository to a new directory named hg/::
1916 - clone a remote repository to a new directory named hg/::
1917
1917
1918 hg clone https://www.mercurial-scm.org/repo/hg/
1918 hg clone https://www.mercurial-scm.org/repo/hg/
1919
1919
1920 - create a lightweight local clone::
1920 - create a lightweight local clone::
1921
1921
1922 hg clone project/ project-feature/
1922 hg clone project/ project-feature/
1923
1923
1924 - clone from an absolute path on an ssh server (note double-slash)::
1924 - clone from an absolute path on an ssh server (note double-slash)::
1925
1925
1926 hg clone ssh://user@server//home/projects/alpha/
1926 hg clone ssh://user@server//home/projects/alpha/
1927
1927
1928 - do a streaming clone while checking out a specified version::
1928 - do a streaming clone while checking out a specified version::
1929
1929
1930 hg clone --stream http://server/repo -u 1.5
1930 hg clone --stream http://server/repo -u 1.5
1931
1931
1932 - create a repository without changesets after a particular revision::
1932 - create a repository without changesets after a particular revision::
1933
1933
1934 hg clone -r 04e544 experimental/ good/
1934 hg clone -r 04e544 experimental/ good/
1935
1935
1936 - clone (and track) a particular named branch::
1936 - clone (and track) a particular named branch::
1937
1937
1938 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1938 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1939
1939
1940 See :hg:`help urls` for details on specifying URLs.
1940 See :hg:`help urls` for details on specifying URLs.
1941
1941
1942 Returns 0 on success.
1942 Returns 0 on success.
1943 """
1943 """
1944 opts = pycompat.byteskwargs(opts)
1944 opts = pycompat.byteskwargs(opts)
1945 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1945 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1946
1946
1947 # --include/--exclude can come from narrow or sparse.
1947 # --include/--exclude can come from narrow or sparse.
1948 includepats, excludepats = None, None
1948 includepats, excludepats = None, None
1949
1949
1950 # hg.clone() differentiates between None and an empty set. So make sure
1950 # hg.clone() differentiates between None and an empty set. So make sure
1951 # patterns are sets if narrow is requested without patterns.
1951 # patterns are sets if narrow is requested without patterns.
1952 if opts.get(b'narrow'):
1952 if opts.get(b'narrow'):
1953 includepats = set()
1953 includepats = set()
1954 excludepats = set()
1954 excludepats = set()
1955
1955
1956 if opts.get(b'include'):
1956 if opts.get(b'include'):
1957 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1957 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1958 if opts.get(b'exclude'):
1958 if opts.get(b'exclude'):
1959 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1959 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1960
1960
1961 r = hg.clone(
1961 r = hg.clone(
1962 ui,
1962 ui,
1963 opts,
1963 opts,
1964 source,
1964 source,
1965 dest,
1965 dest,
1966 pull=opts.get(b'pull'),
1966 pull=opts.get(b'pull'),
1967 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1967 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1968 revs=opts.get(b'rev'),
1968 revs=opts.get(b'rev'),
1969 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1969 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1970 branch=opts.get(b'branch'),
1970 branch=opts.get(b'branch'),
1971 shareopts=opts.get(b'shareopts'),
1971 shareopts=opts.get(b'shareopts'),
1972 storeincludepats=includepats,
1972 storeincludepats=includepats,
1973 storeexcludepats=excludepats,
1973 storeexcludepats=excludepats,
1974 depth=opts.get(b'depth') or None,
1974 depth=opts.get(b'depth') or None,
1975 )
1975 )
1976
1976
1977 return r is None
1977 return r is None
1978
1978
1979
1979
1980 @command(
1980 @command(
1981 b'commit|ci',
1981 b'commit|ci',
1982 [
1982 [
1983 (
1983 (
1984 b'A',
1984 b'A',
1985 b'addremove',
1985 b'addremove',
1986 None,
1986 None,
1987 _(b'mark new/missing files as added/removed before committing'),
1987 _(b'mark new/missing files as added/removed before committing'),
1988 ),
1988 ),
1989 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1989 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1990 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1990 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1991 (b's', b'secret', None, _(b'use the secret phase for committing')),
1991 (b's', b'secret', None, _(b'use the secret phase for committing')),
1992 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1992 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1993 (
1993 (
1994 b'',
1994 b'',
1995 b'force-close-branch',
1995 b'force-close-branch',
1996 None,
1996 None,
1997 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1997 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1998 ),
1998 ),
1999 (b'i', b'interactive', None, _(b'use interactive mode')),
1999 (b'i', b'interactive', None, _(b'use interactive mode')),
2000 ]
2000 ]
2001 + walkopts
2001 + walkopts
2002 + commitopts
2002 + commitopts
2003 + commitopts2
2003 + commitopts2
2004 + subrepoopts,
2004 + subrepoopts,
2005 _(b'[OPTION]... [FILE]...'),
2005 _(b'[OPTION]... [FILE]...'),
2006 helpcategory=command.CATEGORY_COMMITTING,
2006 helpcategory=command.CATEGORY_COMMITTING,
2007 helpbasic=True,
2007 helpbasic=True,
2008 inferrepo=True,
2008 inferrepo=True,
2009 )
2009 )
2010 def commit(ui, repo, *pats, **opts):
2010 def commit(ui, repo, *pats, **opts):
2011 """commit the specified files or all outstanding changes
2011 """commit the specified files or all outstanding changes
2012
2012
2013 Commit changes to the given files into the repository. Unlike a
2013 Commit changes to the given files into the repository. Unlike a
2014 centralized SCM, this operation is a local operation. See
2014 centralized SCM, this operation is a local operation. See
2015 :hg:`push` for a way to actively distribute your changes.
2015 :hg:`push` for a way to actively distribute your changes.
2016
2016
2017 If a list of files is omitted, all changes reported by :hg:`status`
2017 If a list of files is omitted, all changes reported by :hg:`status`
2018 will be committed.
2018 will be committed.
2019
2019
2020 If you are committing the result of a merge, do not provide any
2020 If you are committing the result of a merge, do not provide any
2021 filenames or -I/-X filters.
2021 filenames or -I/-X filters.
2022
2022
2023 If no commit message is specified, Mercurial starts your
2023 If no commit message is specified, Mercurial starts your
2024 configured editor where you can enter a message. In case your
2024 configured editor where you can enter a message. In case your
2025 commit fails, you will find a backup of your message in
2025 commit fails, you will find a backup of your message in
2026 ``.hg/last-message.txt``.
2026 ``.hg/last-message.txt``.
2027
2027
2028 The --close-branch flag can be used to mark the current branch
2028 The --close-branch flag can be used to mark the current branch
2029 head closed. When all heads of a branch are closed, the branch
2029 head closed. When all heads of a branch are closed, the branch
2030 will be considered closed and no longer listed.
2030 will be considered closed and no longer listed.
2031
2031
2032 The --amend flag can be used to amend the parent of the
2032 The --amend flag can be used to amend the parent of the
2033 working directory with a new commit that contains the changes
2033 working directory with a new commit that contains the changes
2034 in the parent in addition to those currently reported by :hg:`status`,
2034 in the parent in addition to those currently reported by :hg:`status`,
2035 if there are any. The old commit is stored in a backup bundle in
2035 if there are any. The old commit is stored in a backup bundle in
2036 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2036 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2037 on how to restore it).
2037 on how to restore it).
2038
2038
2039 Message, user and date are taken from the amended commit unless
2039 Message, user and date are taken from the amended commit unless
2040 specified. When a message isn't specified on the command line,
2040 specified. When a message isn't specified on the command line,
2041 the editor will open with the message of the amended commit.
2041 the editor will open with the message of the amended commit.
2042
2042
2043 It is not possible to amend public changesets (see :hg:`help phases`)
2043 It is not possible to amend public changesets (see :hg:`help phases`)
2044 or changesets that have children.
2044 or changesets that have children.
2045
2045
2046 See :hg:`help dates` for a list of formats valid for -d/--date.
2046 See :hg:`help dates` for a list of formats valid for -d/--date.
2047
2047
2048 Returns 0 on success, 1 if nothing changed.
2048 Returns 0 on success, 1 if nothing changed.
2049
2049
2050 .. container:: verbose
2050 .. container:: verbose
2051
2051
2052 Examples:
2052 Examples:
2053
2053
2054 - commit all files ending in .py::
2054 - commit all files ending in .py::
2055
2055
2056 hg commit --include "set:**.py"
2056 hg commit --include "set:**.py"
2057
2057
2058 - commit all non-binary files::
2058 - commit all non-binary files::
2059
2059
2060 hg commit --exclude "set:binary()"
2060 hg commit --exclude "set:binary()"
2061
2061
2062 - amend the current commit and set the date to now::
2062 - amend the current commit and set the date to now::
2063
2063
2064 hg commit --amend --date now
2064 hg commit --amend --date now
2065 """
2065 """
2066 with repo.wlock(), repo.lock():
2066 with repo.wlock(), repo.lock():
2067 return _docommit(ui, repo, *pats, **opts)
2067 return _docommit(ui, repo, *pats, **opts)
2068
2068
2069
2069
2070 def _docommit(ui, repo, *pats, **opts):
2070 def _docommit(ui, repo, *pats, **opts):
2071 if opts.get('interactive'):
2071 if opts.get('interactive'):
2072 opts.pop('interactive')
2072 opts.pop('interactive')
2073 ret = cmdutil.dorecord(
2073 ret = cmdutil.dorecord(
2074 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2074 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2075 )
2075 )
2076 # ret can be 0 (no changes to record) or the value returned by
2076 # ret can be 0 (no changes to record) or the value returned by
2077 # commit(), 1 if nothing changed or None on success.
2077 # commit(), 1 if nothing changed or None on success.
2078 return 1 if ret == 0 else ret
2078 return 1 if ret == 0 else ret
2079
2079
2080 opts = pycompat.byteskwargs(opts)
2080 opts = pycompat.byteskwargs(opts)
2081 if opts.get(b'subrepos'):
2081 if opts.get(b'subrepos'):
2082 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2082 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2083 # Let --subrepos on the command line override config setting.
2083 # Let --subrepos on the command line override config setting.
2084 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2084 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2085
2085
2086 cmdutil.checkunfinished(repo, commit=True)
2086 cmdutil.checkunfinished(repo, commit=True)
2087
2087
2088 branch = repo[None].branch()
2088 branch = repo[None].branch()
2089 bheads = repo.branchheads(branch)
2089 bheads = repo.branchheads(branch)
2090 tip = repo.changelog.tip()
2090 tip = repo.changelog.tip()
2091
2091
2092 extra = {}
2092 extra = {}
2093 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2093 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2094 extra[b'close'] = b'1'
2094 extra[b'close'] = b'1'
2095
2095
2096 if repo[b'.'].closesbranch():
2096 if repo[b'.'].closesbranch():
2097 raise error.InputError(
2097 raise error.InputError(
2098 _(b'current revision is already a branch closing head')
2098 _(b'current revision is already a branch closing head')
2099 )
2099 )
2100 elif not bheads:
2100 elif not bheads:
2101 raise error.InputError(
2101 raise error.InputError(
2102 _(b'branch "%s" has no heads to close') % branch
2102 _(b'branch "%s" has no heads to close') % branch
2103 )
2103 )
2104 elif (
2104 elif (
2105 branch == repo[b'.'].branch()
2105 branch == repo[b'.'].branch()
2106 and repo[b'.'].node() not in bheads
2106 and repo[b'.'].node() not in bheads
2107 and not opts.get(b'force_close_branch')
2107 and not opts.get(b'force_close_branch')
2108 ):
2108 ):
2109 hint = _(
2109 hint = _(
2110 b'use --force-close-branch to close branch from a non-head'
2110 b'use --force-close-branch to close branch from a non-head'
2111 b' changeset'
2111 b' changeset'
2112 )
2112 )
2113 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2113 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2114 elif opts.get(b'amend'):
2114 elif opts.get(b'amend'):
2115 if (
2115 if (
2116 repo[b'.'].p1().branch() != branch
2116 repo[b'.'].p1().branch() != branch
2117 and repo[b'.'].p2().branch() != branch
2117 and repo[b'.'].p2().branch() != branch
2118 ):
2118 ):
2119 raise error.InputError(_(b'can only close branch heads'))
2119 raise error.InputError(_(b'can only close branch heads'))
2120
2120
2121 if opts.get(b'amend'):
2121 if opts.get(b'amend'):
2122 if ui.configbool(b'ui', b'commitsubrepos'):
2122 if ui.configbool(b'ui', b'commitsubrepos'):
2123 raise error.InputError(
2123 raise error.InputError(
2124 _(b'cannot amend with ui.commitsubrepos enabled')
2124 _(b'cannot amend with ui.commitsubrepos enabled')
2125 )
2125 )
2126
2126
2127 old = repo[b'.']
2127 old = repo[b'.']
2128 rewriteutil.precheck(repo, [old.rev()], b'amend')
2128 rewriteutil.precheck(repo, [old.rev()], b'amend')
2129
2129
2130 # Currently histedit gets confused if an amend happens while histedit
2130 # Currently histedit gets confused if an amend happens while histedit
2131 # is in progress. Since we have a checkunfinished command, we are
2131 # is in progress. Since we have a checkunfinished command, we are
2132 # temporarily honoring it.
2132 # temporarily honoring it.
2133 #
2133 #
2134 # Note: eventually this guard will be removed. Please do not expect
2134 # Note: eventually this guard will be removed. Please do not expect
2135 # this behavior to remain.
2135 # this behavior to remain.
2136 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2136 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2137 cmdutil.checkunfinished(repo)
2137 cmdutil.checkunfinished(repo)
2138
2138
2139 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2139 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2140 if node == old.node():
2140 if node == old.node():
2141 ui.status(_(b"nothing changed\n"))
2141 ui.status(_(b"nothing changed\n"))
2142 return 1
2142 return 1
2143 else:
2143 else:
2144
2144
2145 def commitfunc(ui, repo, message, match, opts):
2145 def commitfunc(ui, repo, message, match, opts):
2146 overrides = {}
2146 overrides = {}
2147 if opts.get(b'secret'):
2147 if opts.get(b'secret'):
2148 overrides[(b'phases', b'new-commit')] = b'secret'
2148 overrides[(b'phases', b'new-commit')] = b'secret'
2149
2149
2150 baseui = repo.baseui
2150 baseui = repo.baseui
2151 with baseui.configoverride(overrides, b'commit'):
2151 with baseui.configoverride(overrides, b'commit'):
2152 with ui.configoverride(overrides, b'commit'):
2152 with ui.configoverride(overrides, b'commit'):
2153 editform = cmdutil.mergeeditform(
2153 editform = cmdutil.mergeeditform(
2154 repo[None], b'commit.normal'
2154 repo[None], b'commit.normal'
2155 )
2155 )
2156 editor = cmdutil.getcommiteditor(
2156 editor = cmdutil.getcommiteditor(
2157 editform=editform, **pycompat.strkwargs(opts)
2157 editform=editform, **pycompat.strkwargs(opts)
2158 )
2158 )
2159 return repo.commit(
2159 return repo.commit(
2160 message,
2160 message,
2161 opts.get(b'user'),
2161 opts.get(b'user'),
2162 opts.get(b'date'),
2162 opts.get(b'date'),
2163 match,
2163 match,
2164 editor=editor,
2164 editor=editor,
2165 extra=extra,
2165 extra=extra,
2166 )
2166 )
2167
2167
2168 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2168 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2169
2169
2170 if not node:
2170 if not node:
2171 stat = cmdutil.postcommitstatus(repo, pats, opts)
2171 stat = cmdutil.postcommitstatus(repo, pats, opts)
2172 if stat.deleted:
2172 if stat.deleted:
2173 ui.status(
2173 ui.status(
2174 _(
2174 _(
2175 b"nothing changed (%d missing files, see "
2175 b"nothing changed (%d missing files, see "
2176 b"'hg status')\n"
2176 b"'hg status')\n"
2177 )
2177 )
2178 % len(stat.deleted)
2178 % len(stat.deleted)
2179 )
2179 )
2180 else:
2180 else:
2181 ui.status(_(b"nothing changed\n"))
2181 ui.status(_(b"nothing changed\n"))
2182 return 1
2182 return 1
2183
2183
2184 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2184 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2185
2185
2186 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2186 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2187 status(
2187 status(
2188 ui,
2188 ui,
2189 repo,
2189 repo,
2190 modified=True,
2190 modified=True,
2191 added=True,
2191 added=True,
2192 removed=True,
2192 removed=True,
2193 deleted=True,
2193 deleted=True,
2194 unknown=True,
2194 unknown=True,
2195 subrepos=opts.get(b'subrepos'),
2195 subrepos=opts.get(b'subrepos'),
2196 )
2196 )
2197
2197
2198
2198
2199 @command(
2199 @command(
2200 b'config|showconfig|debugconfig',
2200 b'config|showconfig|debugconfig',
2201 [
2201 [
2202 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2202 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2203 (b'e', b'edit', None, _(b'edit user config')),
2203 (b'e', b'edit', None, _(b'edit user config')),
2204 (b'l', b'local', None, _(b'edit repository config')),
2204 (b'l', b'local', None, _(b'edit repository config')),
2205 (
2205 (
2206 b'',
2206 b'',
2207 b'shared',
2207 b'shared',
2208 None,
2208 None,
2209 _(b'edit shared source repository config (EXPERIMENTAL)'),
2209 _(b'edit shared source repository config (EXPERIMENTAL)'),
2210 ),
2210 ),
2211 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2211 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2212 (b'g', b'global', None, _(b'edit global config')),
2212 (b'g', b'global', None, _(b'edit global config')),
2213 ]
2213 ]
2214 + formatteropts,
2214 + formatteropts,
2215 _(b'[-u] [NAME]...'),
2215 _(b'[-u] [NAME]...'),
2216 helpcategory=command.CATEGORY_HELP,
2216 helpcategory=command.CATEGORY_HELP,
2217 optionalrepo=True,
2217 optionalrepo=True,
2218 intents={INTENT_READONLY},
2218 intents={INTENT_READONLY},
2219 )
2219 )
2220 def config(ui, repo, *values, **opts):
2220 def config(ui, repo, *values, **opts):
2221 """show combined config settings from all hgrc files
2221 """show combined config settings from all hgrc files
2222
2222
2223 With no arguments, print names and values of all config items.
2223 With no arguments, print names and values of all config items.
2224
2224
2225 With one argument of the form section.name, print just the value
2225 With one argument of the form section.name, print just the value
2226 of that config item.
2226 of that config item.
2227
2227
2228 With multiple arguments, print names and values of all config
2228 With multiple arguments, print names and values of all config
2229 items with matching section names or section.names.
2229 items with matching section names or section.names.
2230
2230
2231 With --edit, start an editor on the user-level config file. With
2231 With --edit, start an editor on the user-level config file. With
2232 --global, edit the system-wide config file. With --local, edit the
2232 --global, edit the system-wide config file. With --local, edit the
2233 repository-level config file.
2233 repository-level config file.
2234
2234
2235 With --debug, the source (filename and line number) is printed
2235 With --debug, the source (filename and line number) is printed
2236 for each config item.
2236 for each config item.
2237
2237
2238 See :hg:`help config` for more information about config files.
2238 See :hg:`help config` for more information about config files.
2239
2239
2240 .. container:: verbose
2240 .. container:: verbose
2241
2241
2242 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2242 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2243 This file is not shared across shares when in share-safe mode.
2243 This file is not shared across shares when in share-safe mode.
2244
2244
2245 Template:
2245 Template:
2246
2246
2247 The following keywords are supported. See also :hg:`help templates`.
2247 The following keywords are supported. See also :hg:`help templates`.
2248
2248
2249 :name: String. Config name.
2249 :name: String. Config name.
2250 :source: String. Filename and line number where the item is defined.
2250 :source: String. Filename and line number where the item is defined.
2251 :value: String. Config value.
2251 :value: String. Config value.
2252
2252
2253 The --shared flag can be used to edit the config file of shared source
2253 The --shared flag can be used to edit the config file of shared source
2254 repository. It only works when you have shared using the experimental
2254 repository. It only works when you have shared using the experimental
2255 share safe feature.
2255 share safe feature.
2256
2256
2257 Returns 0 on success, 1 if NAME does not exist.
2257 Returns 0 on success, 1 if NAME does not exist.
2258
2258
2259 """
2259 """
2260
2260
2261 opts = pycompat.byteskwargs(opts)
2261 opts = pycompat.byteskwargs(opts)
2262 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2262 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2263 if any(opts.get(o) for o in editopts):
2263 if any(opts.get(o) for o in editopts):
2264 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2264 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2265 if opts.get(b'local'):
2265 if opts.get(b'local'):
2266 if not repo:
2266 if not repo:
2267 raise error.InputError(
2267 raise error.InputError(
2268 _(b"can't use --local outside a repository")
2268 _(b"can't use --local outside a repository")
2269 )
2269 )
2270 paths = [repo.vfs.join(b'hgrc')]
2270 paths = [repo.vfs.join(b'hgrc')]
2271 elif opts.get(b'global'):
2271 elif opts.get(b'global'):
2272 paths = rcutil.systemrcpath()
2272 paths = rcutil.systemrcpath()
2273 elif opts.get(b'shared'):
2273 elif opts.get(b'shared'):
2274 if not repo.shared():
2274 if not repo.shared():
2275 raise error.InputError(
2275 raise error.InputError(
2276 _(b"repository is not shared; can't use --shared")
2276 _(b"repository is not shared; can't use --shared")
2277 )
2277 )
2278 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2278 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2279 raise error.InputError(
2279 raise error.InputError(
2280 _(
2280 _(
2281 b"share safe feature not enabled; "
2281 b"share safe feature not enabled; "
2282 b"unable to edit shared source repository config"
2282 b"unable to edit shared source repository config"
2283 )
2283 )
2284 )
2284 )
2285 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2285 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2286 elif opts.get(b'non_shared'):
2286 elif opts.get(b'non_shared'):
2287 paths = [repo.vfs.join(b'hgrc-not-shared')]
2287 paths = [repo.vfs.join(b'hgrc-not-shared')]
2288 else:
2288 else:
2289 paths = rcutil.userrcpath()
2289 paths = rcutil.userrcpath()
2290
2290
2291 for f in paths:
2291 for f in paths:
2292 if os.path.exists(f):
2292 if os.path.exists(f):
2293 break
2293 break
2294 else:
2294 else:
2295 if opts.get(b'global'):
2295 if opts.get(b'global'):
2296 samplehgrc = uimod.samplehgrcs[b'global']
2296 samplehgrc = uimod.samplehgrcs[b'global']
2297 elif opts.get(b'local'):
2297 elif opts.get(b'local'):
2298 samplehgrc = uimod.samplehgrcs[b'local']
2298 samplehgrc = uimod.samplehgrcs[b'local']
2299 else:
2299 else:
2300 samplehgrc = uimod.samplehgrcs[b'user']
2300 samplehgrc = uimod.samplehgrcs[b'user']
2301
2301
2302 f = paths[0]
2302 f = paths[0]
2303 fp = open(f, b"wb")
2303 fp = open(f, b"wb")
2304 fp.write(util.tonativeeol(samplehgrc))
2304 fp.write(util.tonativeeol(samplehgrc))
2305 fp.close()
2305 fp.close()
2306
2306
2307 editor = ui.geteditor()
2307 editor = ui.geteditor()
2308 ui.system(
2308 ui.system(
2309 b"%s \"%s\"" % (editor, f),
2309 b"%s \"%s\"" % (editor, f),
2310 onerr=error.InputError,
2310 onerr=error.InputError,
2311 errprefix=_(b"edit failed"),
2311 errprefix=_(b"edit failed"),
2312 blockedtag=b'config_edit',
2312 blockedtag=b'config_edit',
2313 )
2313 )
2314 return
2314 return
2315 ui.pager(b'config')
2315 ui.pager(b'config')
2316 fm = ui.formatter(b'config', opts)
2316 fm = ui.formatter(b'config', opts)
2317 for t, f in rcutil.rccomponents():
2317 for t, f in rcutil.rccomponents():
2318 if t == b'path':
2318 if t == b'path':
2319 ui.debug(b'read config from: %s\n' % f)
2319 ui.debug(b'read config from: %s\n' % f)
2320 elif t == b'resource':
2320 elif t == b'resource':
2321 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2321 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2322 elif t == b'items':
2322 elif t == b'items':
2323 # Don't print anything for 'items'.
2323 # Don't print anything for 'items'.
2324 pass
2324 pass
2325 else:
2325 else:
2326 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2326 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2327 untrusted = bool(opts.get(b'untrusted'))
2327 untrusted = bool(opts.get(b'untrusted'))
2328
2328
2329 selsections = selentries = []
2329 selsections = selentries = []
2330 if values:
2330 if values:
2331 selsections = [v for v in values if b'.' not in v]
2331 selsections = [v for v in values if b'.' not in v]
2332 selentries = [v for v in values if b'.' in v]
2332 selentries = [v for v in values if b'.' in v]
2333 uniquesel = len(selentries) == 1 and not selsections
2333 uniquesel = len(selentries) == 1 and not selsections
2334 selsections = set(selsections)
2334 selsections = set(selsections)
2335 selentries = set(selentries)
2335 selentries = set(selentries)
2336
2336
2337 matched = False
2337 matched = False
2338 for section, name, value in ui.walkconfig(untrusted=untrusted):
2338 for section, name, value in ui.walkconfig(untrusted=untrusted):
2339 source = ui.configsource(section, name, untrusted)
2339 source = ui.configsource(section, name, untrusted)
2340 value = pycompat.bytestr(value)
2340 value = pycompat.bytestr(value)
2341 defaultvalue = ui.configdefault(section, name)
2341 defaultvalue = ui.configdefault(section, name)
2342 if fm.isplain():
2342 if fm.isplain():
2343 source = source or b'none'
2343 source = source or b'none'
2344 value = value.replace(b'\n', b'\\n')
2344 value = value.replace(b'\n', b'\\n')
2345 entryname = section + b'.' + name
2345 entryname = section + b'.' + name
2346 if values and not (section in selsections or entryname in selentries):
2346 if values and not (section in selsections or entryname in selentries):
2347 continue
2347 continue
2348 fm.startitem()
2348 fm.startitem()
2349 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2349 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2350 if uniquesel:
2350 if uniquesel:
2351 fm.data(name=entryname)
2351 fm.data(name=entryname)
2352 fm.write(b'value', b'%s\n', value)
2352 fm.write(b'value', b'%s\n', value)
2353 else:
2353 else:
2354 fm.write(b'name value', b'%s=%s\n', entryname, value)
2354 fm.write(b'name value', b'%s=%s\n', entryname, value)
2355 if formatter.isprintable(defaultvalue):
2355 if formatter.isprintable(defaultvalue):
2356 fm.data(defaultvalue=defaultvalue)
2356 fm.data(defaultvalue=defaultvalue)
2357 elif isinstance(defaultvalue, list) and all(
2357 elif isinstance(defaultvalue, list) and all(
2358 formatter.isprintable(e) for e in defaultvalue
2358 formatter.isprintable(e) for e in defaultvalue
2359 ):
2359 ):
2360 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2360 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2361 # TODO: no idea how to process unsupported defaultvalue types
2361 # TODO: no idea how to process unsupported defaultvalue types
2362 matched = True
2362 matched = True
2363 fm.end()
2363 fm.end()
2364 if matched:
2364 if matched:
2365 return 0
2365 return 0
2366 return 1
2366 return 1
2367
2367
2368
2368
2369 @command(
2369 @command(
2370 b'continue',
2370 b'continue',
2371 dryrunopts,
2371 dryrunopts,
2372 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2372 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2373 helpbasic=True,
2373 helpbasic=True,
2374 )
2374 )
2375 def continuecmd(ui, repo, **opts):
2375 def continuecmd(ui, repo, **opts):
2376 """resumes an interrupted operation (EXPERIMENTAL)
2376 """resumes an interrupted operation (EXPERIMENTAL)
2377
2377
2378 Finishes a multistep operation like graft, histedit, rebase, merge,
2378 Finishes a multistep operation like graft, histedit, rebase, merge,
2379 and unshelve if they are in an interrupted state.
2379 and unshelve if they are in an interrupted state.
2380
2380
2381 use --dry-run/-n to dry run the command.
2381 use --dry-run/-n to dry run the command.
2382 """
2382 """
2383 dryrun = opts.get('dry_run')
2383 dryrun = opts.get('dry_run')
2384 contstate = cmdutil.getunfinishedstate(repo)
2384 contstate = cmdutil.getunfinishedstate(repo)
2385 if not contstate:
2385 if not contstate:
2386 raise error.StateError(_(b'no operation in progress'))
2386 raise error.StateError(_(b'no operation in progress'))
2387 if not contstate.continuefunc:
2387 if not contstate.continuefunc:
2388 raise error.StateError(
2388 raise error.StateError(
2389 (
2389 (
2390 _(b"%s in progress but does not support 'hg continue'")
2390 _(b"%s in progress but does not support 'hg continue'")
2391 % (contstate._opname)
2391 % (contstate._opname)
2392 ),
2392 ),
2393 hint=contstate.continuemsg(),
2393 hint=contstate.continuemsg(),
2394 )
2394 )
2395 if dryrun:
2395 if dryrun:
2396 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2396 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2397 return
2397 return
2398 return contstate.continuefunc(ui, repo)
2398 return contstate.continuefunc(ui, repo)
2399
2399
2400
2400
2401 @command(
2401 @command(
2402 b'copy|cp',
2402 b'copy|cp',
2403 [
2403 [
2404 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2404 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2405 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2405 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2406 (
2406 (
2407 b'',
2407 b'',
2408 b'at-rev',
2408 b'at-rev',
2409 b'',
2409 b'',
2410 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2410 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2411 _(b'REV'),
2411 _(b'REV'),
2412 ),
2412 ),
2413 (
2413 (
2414 b'f',
2414 b'f',
2415 b'force',
2415 b'force',
2416 None,
2416 None,
2417 _(b'forcibly copy over an existing managed file'),
2417 _(b'forcibly copy over an existing managed file'),
2418 ),
2418 ),
2419 ]
2419 ]
2420 + walkopts
2420 + walkopts
2421 + dryrunopts,
2421 + dryrunopts,
2422 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2422 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2423 helpcategory=command.CATEGORY_FILE_CONTENTS,
2423 helpcategory=command.CATEGORY_FILE_CONTENTS,
2424 )
2424 )
2425 def copy(ui, repo, *pats, **opts):
2425 def copy(ui, repo, *pats, **opts):
2426 """mark files as copied for the next commit
2426 """mark files as copied for the next commit
2427
2427
2428 Mark dest as having copies of source files. If dest is a
2428 Mark dest as having copies of source files. If dest is a
2429 directory, copies are put in that directory. If dest is a file,
2429 directory, copies are put in that directory. If dest is a file,
2430 the source must be a single file.
2430 the source must be a single file.
2431
2431
2432 By default, this command copies the contents of files as they
2432 By default, this command copies the contents of files as they
2433 exist in the working directory. If invoked with -A/--after, the
2433 exist in the working directory. If invoked with -A/--after, the
2434 operation is recorded, but no copying is performed.
2434 operation is recorded, but no copying is performed.
2435
2435
2436 To undo marking a destination file as copied, use --forget. With that
2436 To undo marking a destination file as copied, use --forget. With that
2437 option, all given (positional) arguments are unmarked as copies. The
2437 option, all given (positional) arguments are unmarked as copies. The
2438 destination file(s) will be left in place (still tracked). Note that
2438 destination file(s) will be left in place (still tracked). Note that
2439 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2439 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2440
2440
2441 This command takes effect with the next commit by default.
2441 This command takes effect with the next commit by default.
2442
2442
2443 Returns 0 on success, 1 if errors are encountered.
2443 Returns 0 on success, 1 if errors are encountered.
2444 """
2444 """
2445 opts = pycompat.byteskwargs(opts)
2445 opts = pycompat.byteskwargs(opts)
2446 with repo.wlock():
2446 with repo.wlock():
2447 return cmdutil.copy(ui, repo, pats, opts)
2447 return cmdutil.copy(ui, repo, pats, opts)
2448
2448
2449
2449
2450 @command(
2450 @command(
2451 b'debugcommands',
2451 b'debugcommands',
2452 [],
2452 [],
2453 _(b'[COMMAND]'),
2453 _(b'[COMMAND]'),
2454 helpcategory=command.CATEGORY_HELP,
2454 helpcategory=command.CATEGORY_HELP,
2455 norepo=True,
2455 norepo=True,
2456 )
2456 )
2457 def debugcommands(ui, cmd=b'', *args):
2457 def debugcommands(ui, cmd=b'', *args):
2458 """list all available commands and options"""
2458 """list all available commands and options"""
2459 for cmd, vals in sorted(pycompat.iteritems(table)):
2459 for cmd, vals in sorted(pycompat.iteritems(table)):
2460 cmd = cmd.split(b'|')[0]
2460 cmd = cmd.split(b'|')[0]
2461 opts = b', '.join([i[1] for i in vals[1]])
2461 opts = b', '.join([i[1] for i in vals[1]])
2462 ui.write(b'%s: %s\n' % (cmd, opts))
2462 ui.write(b'%s: %s\n' % (cmd, opts))
2463
2463
2464
2464
2465 @command(
2465 @command(
2466 b'debugcomplete',
2466 b'debugcomplete',
2467 [(b'o', b'options', None, _(b'show the command options'))],
2467 [(b'o', b'options', None, _(b'show the command options'))],
2468 _(b'[-o] CMD'),
2468 _(b'[-o] CMD'),
2469 helpcategory=command.CATEGORY_HELP,
2469 helpcategory=command.CATEGORY_HELP,
2470 norepo=True,
2470 norepo=True,
2471 )
2471 )
2472 def debugcomplete(ui, cmd=b'', **opts):
2472 def debugcomplete(ui, cmd=b'', **opts):
2473 """returns the completion list associated with the given command"""
2473 """returns the completion list associated with the given command"""
2474
2474
2475 if opts.get('options'):
2475 if opts.get('options'):
2476 options = []
2476 options = []
2477 otables = [globalopts]
2477 otables = [globalopts]
2478 if cmd:
2478 if cmd:
2479 aliases, entry = cmdutil.findcmd(cmd, table, False)
2479 aliases, entry = cmdutil.findcmd(cmd, table, False)
2480 otables.append(entry[1])
2480 otables.append(entry[1])
2481 for t in otables:
2481 for t in otables:
2482 for o in t:
2482 for o in t:
2483 if b"(DEPRECATED)" in o[3]:
2483 if b"(DEPRECATED)" in o[3]:
2484 continue
2484 continue
2485 if o[0]:
2485 if o[0]:
2486 options.append(b'-%s' % o[0])
2486 options.append(b'-%s' % o[0])
2487 options.append(b'--%s' % o[1])
2487 options.append(b'--%s' % o[1])
2488 ui.write(b"%s\n" % b"\n".join(options))
2488 ui.write(b"%s\n" % b"\n".join(options))
2489 return
2489 return
2490
2490
2491 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2491 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2492 if ui.verbose:
2492 if ui.verbose:
2493 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2493 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2494 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2494 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2495
2495
2496
2496
2497 @command(
2497 @command(
2498 b'diff',
2498 b'diff',
2499 [
2499 [
2500 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2500 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2501 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2501 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2502 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2502 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2503 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2503 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2504 ]
2504 ]
2505 + diffopts
2505 + diffopts
2506 + diffopts2
2506 + diffopts2
2507 + walkopts
2507 + walkopts
2508 + subrepoopts,
2508 + subrepoopts,
2509 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2509 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2510 helpcategory=command.CATEGORY_FILE_CONTENTS,
2510 helpcategory=command.CATEGORY_FILE_CONTENTS,
2511 helpbasic=True,
2511 helpbasic=True,
2512 inferrepo=True,
2512 inferrepo=True,
2513 intents={INTENT_READONLY},
2513 intents={INTENT_READONLY},
2514 )
2514 )
2515 def diff(ui, repo, *pats, **opts):
2515 def diff(ui, repo, *pats, **opts):
2516 """diff repository (or selected files)
2516 """diff repository (or selected files)
2517
2517
2518 Show differences between revisions for the specified files.
2518 Show differences between revisions for the specified files.
2519
2519
2520 Differences between files are shown using the unified diff format.
2520 Differences between files are shown using the unified diff format.
2521
2521
2522 .. note::
2522 .. note::
2523
2523
2524 :hg:`diff` may generate unexpected results for merges, as it will
2524 :hg:`diff` may generate unexpected results for merges, as it will
2525 default to comparing against the working directory's first
2525 default to comparing against the working directory's first
2526 parent changeset if no revisions are specified.
2526 parent changeset if no revisions are specified.
2527
2527
2528 By default, the working directory files are compared to its first parent. To
2528 By default, the working directory files are compared to its first parent. To
2529 see the differences from another revision, use --from. To see the difference
2529 see the differences from another revision, use --from. To see the difference
2530 to another revision, use --to. For example, :hg:`diff --from .^` will show
2530 to another revision, use --to. For example, :hg:`diff --from .^` will show
2531 the differences from the working copy's grandparent to the working copy,
2531 the differences from the working copy's grandparent to the working copy,
2532 :hg:`diff --to .` will show the diff from the working copy to its parent
2532 :hg:`diff --to .` will show the diff from the working copy to its parent
2533 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2533 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2534 show the diff between those two revisions.
2534 show the diff between those two revisions.
2535
2535
2536 Alternatively you can specify -c/--change with a revision to see the changes
2536 Alternatively you can specify -c/--change with a revision to see the changes
2537 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2537 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2538 equivalent to :hg:`diff --from 42^ --to 42`)
2538 equivalent to :hg:`diff --from 42^ --to 42`)
2539
2539
2540 Without the -a/--text option, diff will avoid generating diffs of
2540 Without the -a/--text option, diff will avoid generating diffs of
2541 files it detects as binary. With -a, diff will generate a diff
2541 files it detects as binary. With -a, diff will generate a diff
2542 anyway, probably with undesirable results.
2542 anyway, probably with undesirable results.
2543
2543
2544 Use the -g/--git option to generate diffs in the git extended diff
2544 Use the -g/--git option to generate diffs in the git extended diff
2545 format. For more information, read :hg:`help diffs`.
2545 format. For more information, read :hg:`help diffs`.
2546
2546
2547 .. container:: verbose
2547 .. container:: verbose
2548
2548
2549 Examples:
2549 Examples:
2550
2550
2551 - compare a file in the current working directory to its parent::
2551 - compare a file in the current working directory to its parent::
2552
2552
2553 hg diff foo.c
2553 hg diff foo.c
2554
2554
2555 - compare two historical versions of a directory, with rename info::
2555 - compare two historical versions of a directory, with rename info::
2556
2556
2557 hg diff --git --from 1.0 --to 1.2 lib/
2557 hg diff --git --from 1.0 --to 1.2 lib/
2558
2558
2559 - get change stats relative to the last change on some date::
2559 - get change stats relative to the last change on some date::
2560
2560
2561 hg diff --stat --from "date('may 2')"
2561 hg diff --stat --from "date('may 2')"
2562
2562
2563 - diff all newly-added files that contain a keyword::
2563 - diff all newly-added files that contain a keyword::
2564
2564
2565 hg diff "set:added() and grep(GNU)"
2565 hg diff "set:added() and grep(GNU)"
2566
2566
2567 - compare a revision and its parents::
2567 - compare a revision and its parents::
2568
2568
2569 hg diff -c 9353 # compare against first parent
2569 hg diff -c 9353 # compare against first parent
2570 hg diff --from 9353^ --to 9353 # same using revset syntax
2570 hg diff --from 9353^ --to 9353 # same using revset syntax
2571 hg diff --from 9353^2 --to 9353 # compare against the second parent
2571 hg diff --from 9353^2 --to 9353 # compare against the second parent
2572
2572
2573 Returns 0 on success.
2573 Returns 0 on success.
2574 """
2574 """
2575
2575
2576 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2576 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2577 opts = pycompat.byteskwargs(opts)
2577 opts = pycompat.byteskwargs(opts)
2578 revs = opts.get(b'rev')
2578 revs = opts.get(b'rev')
2579 change = opts.get(b'change')
2579 change = opts.get(b'change')
2580 from_rev = opts.get(b'from')
2580 from_rev = opts.get(b'from')
2581 to_rev = opts.get(b'to')
2581 to_rev = opts.get(b'to')
2582 stat = opts.get(b'stat')
2582 stat = opts.get(b'stat')
2583 reverse = opts.get(b'reverse')
2583 reverse = opts.get(b'reverse')
2584
2584
2585 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2585 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2586 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2586 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2587 if change:
2587 if change:
2588 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2588 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2589 ctx2 = scmutil.revsingle(repo, change, None)
2589 ctx2 = scmutil.revsingle(repo, change, None)
2590 ctx1 = logcmdutil.diff_parent(ctx2)
2590 ctx1 = logcmdutil.diff_parent(ctx2)
2591 elif from_rev or to_rev:
2591 elif from_rev or to_rev:
2592 repo = scmutil.unhidehashlikerevs(
2592 repo = scmutil.unhidehashlikerevs(
2593 repo, [from_rev] + [to_rev], b'nowarn'
2593 repo, [from_rev] + [to_rev], b'nowarn'
2594 )
2594 )
2595 ctx1 = scmutil.revsingle(repo, from_rev, None)
2595 ctx1 = scmutil.revsingle(repo, from_rev, None)
2596 ctx2 = scmutil.revsingle(repo, to_rev, None)
2596 ctx2 = scmutil.revsingle(repo, to_rev, None)
2597 else:
2597 else:
2598 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2598 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2599 ctx1, ctx2 = scmutil.revpair(repo, revs)
2599 ctx1, ctx2 = scmutil.revpair(repo, revs)
2600
2600
2601 if reverse:
2601 if reverse:
2602 ctxleft = ctx2
2602 ctxleft = ctx2
2603 ctxright = ctx1
2603 ctxright = ctx1
2604 else:
2604 else:
2605 ctxleft = ctx1
2605 ctxleft = ctx1
2606 ctxright = ctx2
2606 ctxright = ctx2
2607
2607
2608 diffopts = patch.diffallopts(ui, opts)
2608 diffopts = patch.diffallopts(ui, opts)
2609 m = scmutil.match(ctx2, pats, opts)
2609 m = scmutil.match(ctx2, pats, opts)
2610 m = repo.narrowmatch(m)
2610 m = repo.narrowmatch(m)
2611 ui.pager(b'diff')
2611 ui.pager(b'diff')
2612 logcmdutil.diffordiffstat(
2612 logcmdutil.diffordiffstat(
2613 ui,
2613 ui,
2614 repo,
2614 repo,
2615 diffopts,
2615 diffopts,
2616 ctxleft,
2616 ctxleft,
2617 ctxright,
2617 ctxright,
2618 m,
2618 m,
2619 stat=stat,
2619 stat=stat,
2620 listsubrepos=opts.get(b'subrepos'),
2620 listsubrepos=opts.get(b'subrepos'),
2621 root=opts.get(b'root'),
2621 root=opts.get(b'root'),
2622 )
2622 )
2623
2623
2624
2624
2625 @command(
2625 @command(
2626 b'export',
2626 b'export',
2627 [
2627 [
2628 (
2628 (
2629 b'B',
2629 b'B',
2630 b'bookmark',
2630 b'bookmark',
2631 b'',
2631 b'',
2632 _(b'export changes only reachable by given bookmark'),
2632 _(b'export changes only reachable by given bookmark'),
2633 _(b'BOOKMARK'),
2633 _(b'BOOKMARK'),
2634 ),
2634 ),
2635 (
2635 (
2636 b'o',
2636 b'o',
2637 b'output',
2637 b'output',
2638 b'',
2638 b'',
2639 _(b'print output to file with formatted name'),
2639 _(b'print output to file with formatted name'),
2640 _(b'FORMAT'),
2640 _(b'FORMAT'),
2641 ),
2641 ),
2642 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2642 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2643 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2643 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2644 ]
2644 ]
2645 + diffopts
2645 + diffopts
2646 + formatteropts,
2646 + formatteropts,
2647 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2647 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2648 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2648 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2649 helpbasic=True,
2649 helpbasic=True,
2650 intents={INTENT_READONLY},
2650 intents={INTENT_READONLY},
2651 )
2651 )
2652 def export(ui, repo, *changesets, **opts):
2652 def export(ui, repo, *changesets, **opts):
2653 """dump the header and diffs for one or more changesets
2653 """dump the header and diffs for one or more changesets
2654
2654
2655 Print the changeset header and diffs for one or more revisions.
2655 Print the changeset header and diffs for one or more revisions.
2656 If no revision is given, the parent of the working directory is used.
2656 If no revision is given, the parent of the working directory is used.
2657
2657
2658 The information shown in the changeset header is: author, date,
2658 The information shown in the changeset header is: author, date,
2659 branch name (if non-default), changeset hash, parent(s) and commit
2659 branch name (if non-default), changeset hash, parent(s) and commit
2660 comment.
2660 comment.
2661
2661
2662 .. note::
2662 .. note::
2663
2663
2664 :hg:`export` may generate unexpected diff output for merge
2664 :hg:`export` may generate unexpected diff output for merge
2665 changesets, as it will compare the merge changeset against its
2665 changesets, as it will compare the merge changeset against its
2666 first parent only.
2666 first parent only.
2667
2667
2668 Output may be to a file, in which case the name of the file is
2668 Output may be to a file, in which case the name of the file is
2669 given using a template string. See :hg:`help templates`. In addition
2669 given using a template string. See :hg:`help templates`. In addition
2670 to the common template keywords, the following formatting rules are
2670 to the common template keywords, the following formatting rules are
2671 supported:
2671 supported:
2672
2672
2673 :``%%``: literal "%" character
2673 :``%%``: literal "%" character
2674 :``%H``: changeset hash (40 hexadecimal digits)
2674 :``%H``: changeset hash (40 hexadecimal digits)
2675 :``%N``: number of patches being generated
2675 :``%N``: number of patches being generated
2676 :``%R``: changeset revision number
2676 :``%R``: changeset revision number
2677 :``%b``: basename of the exporting repository
2677 :``%b``: basename of the exporting repository
2678 :``%h``: short-form changeset hash (12 hexadecimal digits)
2678 :``%h``: short-form changeset hash (12 hexadecimal digits)
2679 :``%m``: first line of the commit message (only alphanumeric characters)
2679 :``%m``: first line of the commit message (only alphanumeric characters)
2680 :``%n``: zero-padded sequence number, starting at 1
2680 :``%n``: zero-padded sequence number, starting at 1
2681 :``%r``: zero-padded changeset revision number
2681 :``%r``: zero-padded changeset revision number
2682 :``\\``: literal "\\" character
2682 :``\\``: literal "\\" character
2683
2683
2684 Without the -a/--text option, export will avoid generating diffs
2684 Without the -a/--text option, export will avoid generating diffs
2685 of files it detects as binary. With -a, export will generate a
2685 of files it detects as binary. With -a, export will generate a
2686 diff anyway, probably with undesirable results.
2686 diff anyway, probably with undesirable results.
2687
2687
2688 With -B/--bookmark changesets reachable by the given bookmark are
2688 With -B/--bookmark changesets reachable by the given bookmark are
2689 selected.
2689 selected.
2690
2690
2691 Use the -g/--git option to generate diffs in the git extended diff
2691 Use the -g/--git option to generate diffs in the git extended diff
2692 format. See :hg:`help diffs` for more information.
2692 format. See :hg:`help diffs` for more information.
2693
2693
2694 With the --switch-parent option, the diff will be against the
2694 With the --switch-parent option, the diff will be against the
2695 second parent. It can be useful to review a merge.
2695 second parent. It can be useful to review a merge.
2696
2696
2697 .. container:: verbose
2697 .. container:: verbose
2698
2698
2699 Template:
2699 Template:
2700
2700
2701 The following keywords are supported in addition to the common template
2701 The following keywords are supported in addition to the common template
2702 keywords and functions. See also :hg:`help templates`.
2702 keywords and functions. See also :hg:`help templates`.
2703
2703
2704 :diff: String. Diff content.
2704 :diff: String. Diff content.
2705 :parents: List of strings. Parent nodes of the changeset.
2705 :parents: List of strings. Parent nodes of the changeset.
2706
2706
2707 Examples:
2707 Examples:
2708
2708
2709 - use export and import to transplant a bugfix to the current
2709 - use export and import to transplant a bugfix to the current
2710 branch::
2710 branch::
2711
2711
2712 hg export -r 9353 | hg import -
2712 hg export -r 9353 | hg import -
2713
2713
2714 - export all the changesets between two revisions to a file with
2714 - export all the changesets between two revisions to a file with
2715 rename information::
2715 rename information::
2716
2716
2717 hg export --git -r 123:150 > changes.txt
2717 hg export --git -r 123:150 > changes.txt
2718
2718
2719 - split outgoing changes into a series of patches with
2719 - split outgoing changes into a series of patches with
2720 descriptive names::
2720 descriptive names::
2721
2721
2722 hg export -r "outgoing()" -o "%n-%m.patch"
2722 hg export -r "outgoing()" -o "%n-%m.patch"
2723
2723
2724 Returns 0 on success.
2724 Returns 0 on success.
2725 """
2725 """
2726 opts = pycompat.byteskwargs(opts)
2726 opts = pycompat.byteskwargs(opts)
2727 bookmark = opts.get(b'bookmark')
2727 bookmark = opts.get(b'bookmark')
2728 changesets += tuple(opts.get(b'rev', []))
2728 changesets += tuple(opts.get(b'rev', []))
2729
2729
2730 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2730 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2731
2731
2732 if bookmark:
2732 if bookmark:
2733 if bookmark not in repo._bookmarks:
2733 if bookmark not in repo._bookmarks:
2734 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2734 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2735
2735
2736 revs = scmutil.bookmarkrevs(repo, bookmark)
2736 revs = scmutil.bookmarkrevs(repo, bookmark)
2737 else:
2737 else:
2738 if not changesets:
2738 if not changesets:
2739 changesets = [b'.']
2739 changesets = [b'.']
2740
2740
2741 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2741 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2742 revs = scmutil.revrange(repo, changesets)
2742 revs = scmutil.revrange(repo, changesets)
2743
2743
2744 if not revs:
2744 if not revs:
2745 raise error.InputError(_(b"export requires at least one changeset"))
2745 raise error.InputError(_(b"export requires at least one changeset"))
2746 if len(revs) > 1:
2746 if len(revs) > 1:
2747 ui.note(_(b'exporting patches:\n'))
2747 ui.note(_(b'exporting patches:\n'))
2748 else:
2748 else:
2749 ui.note(_(b'exporting patch:\n'))
2749 ui.note(_(b'exporting patch:\n'))
2750
2750
2751 fntemplate = opts.get(b'output')
2751 fntemplate = opts.get(b'output')
2752 if cmdutil.isstdiofilename(fntemplate):
2752 if cmdutil.isstdiofilename(fntemplate):
2753 fntemplate = b''
2753 fntemplate = b''
2754
2754
2755 if fntemplate:
2755 if fntemplate:
2756 fm = formatter.nullformatter(ui, b'export', opts)
2756 fm = formatter.nullformatter(ui, b'export', opts)
2757 else:
2757 else:
2758 ui.pager(b'export')
2758 ui.pager(b'export')
2759 fm = ui.formatter(b'export', opts)
2759 fm = ui.formatter(b'export', opts)
2760 with fm:
2760 with fm:
2761 cmdutil.export(
2761 cmdutil.export(
2762 repo,
2762 repo,
2763 revs,
2763 revs,
2764 fm,
2764 fm,
2765 fntemplate=fntemplate,
2765 fntemplate=fntemplate,
2766 switch_parent=opts.get(b'switch_parent'),
2766 switch_parent=opts.get(b'switch_parent'),
2767 opts=patch.diffallopts(ui, opts),
2767 opts=patch.diffallopts(ui, opts),
2768 )
2768 )
2769
2769
2770
2770
2771 @command(
2771 @command(
2772 b'files',
2772 b'files',
2773 [
2773 [
2774 (
2774 (
2775 b'r',
2775 b'r',
2776 b'rev',
2776 b'rev',
2777 b'',
2777 b'',
2778 _(b'search the repository as it is in REV'),
2778 _(b'search the repository as it is in REV'),
2779 _(b'REV'),
2779 _(b'REV'),
2780 ),
2780 ),
2781 (
2781 (
2782 b'0',
2782 b'0',
2783 b'print0',
2783 b'print0',
2784 None,
2784 None,
2785 _(b'end filenames with NUL, for use with xargs'),
2785 _(b'end filenames with NUL, for use with xargs'),
2786 ),
2786 ),
2787 ]
2787 ]
2788 + walkopts
2788 + walkopts
2789 + formatteropts
2789 + formatteropts
2790 + subrepoopts,
2790 + subrepoopts,
2791 _(b'[OPTION]... [FILE]...'),
2791 _(b'[OPTION]... [FILE]...'),
2792 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2792 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2793 intents={INTENT_READONLY},
2793 intents={INTENT_READONLY},
2794 )
2794 )
2795 def files(ui, repo, *pats, **opts):
2795 def files(ui, repo, *pats, **opts):
2796 """list tracked files
2796 """list tracked files
2797
2797
2798 Print files under Mercurial control in the working directory or
2798 Print files under Mercurial control in the working directory or
2799 specified revision for given files (excluding removed files).
2799 specified revision for given files (excluding removed files).
2800 Files can be specified as filenames or filesets.
2800 Files can be specified as filenames or filesets.
2801
2801
2802 If no files are given to match, this command prints the names
2802 If no files are given to match, this command prints the names
2803 of all files under Mercurial control.
2803 of all files under Mercurial control.
2804
2804
2805 .. container:: verbose
2805 .. container:: verbose
2806
2806
2807 Template:
2807 Template:
2808
2808
2809 The following keywords are supported in addition to the common template
2809 The following keywords are supported in addition to the common template
2810 keywords and functions. See also :hg:`help templates`.
2810 keywords and functions. See also :hg:`help templates`.
2811
2811
2812 :flags: String. Character denoting file's symlink and executable bits.
2812 :flags: String. Character denoting file's symlink and executable bits.
2813 :path: String. Repository-absolute path of the file.
2813 :path: String. Repository-absolute path of the file.
2814 :size: Integer. Size of the file in bytes.
2814 :size: Integer. Size of the file in bytes.
2815
2815
2816 Examples:
2816 Examples:
2817
2817
2818 - list all files under the current directory::
2818 - list all files under the current directory::
2819
2819
2820 hg files .
2820 hg files .
2821
2821
2822 - shows sizes and flags for current revision::
2822 - shows sizes and flags for current revision::
2823
2823
2824 hg files -vr .
2824 hg files -vr .
2825
2825
2826 - list all files named README::
2826 - list all files named README::
2827
2827
2828 hg files -I "**/README"
2828 hg files -I "**/README"
2829
2829
2830 - list all binary files::
2830 - list all binary files::
2831
2831
2832 hg files "set:binary()"
2832 hg files "set:binary()"
2833
2833
2834 - find files containing a regular expression::
2834 - find files containing a regular expression::
2835
2835
2836 hg files "set:grep('bob')"
2836 hg files "set:grep('bob')"
2837
2837
2838 - search tracked file contents with xargs and grep::
2838 - search tracked file contents with xargs and grep::
2839
2839
2840 hg files -0 | xargs -0 grep foo
2840 hg files -0 | xargs -0 grep foo
2841
2841
2842 See :hg:`help patterns` and :hg:`help filesets` for more information
2842 See :hg:`help patterns` and :hg:`help filesets` for more information
2843 on specifying file patterns.
2843 on specifying file patterns.
2844
2844
2845 Returns 0 if a match is found, 1 otherwise.
2845 Returns 0 if a match is found, 1 otherwise.
2846
2846
2847 """
2847 """
2848
2848
2849 opts = pycompat.byteskwargs(opts)
2849 opts = pycompat.byteskwargs(opts)
2850 rev = opts.get(b'rev')
2850 rev = opts.get(b'rev')
2851 if rev:
2851 if rev:
2852 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2852 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2853 ctx = scmutil.revsingle(repo, rev, None)
2853 ctx = scmutil.revsingle(repo, rev, None)
2854
2854
2855 end = b'\n'
2855 end = b'\n'
2856 if opts.get(b'print0'):
2856 if opts.get(b'print0'):
2857 end = b'\0'
2857 end = b'\0'
2858 fmt = b'%s' + end
2858 fmt = b'%s' + end
2859
2859
2860 m = scmutil.match(ctx, pats, opts)
2860 m = scmutil.match(ctx, pats, opts)
2861 ui.pager(b'files')
2861 ui.pager(b'files')
2862 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2862 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2863 with ui.formatter(b'files', opts) as fm:
2863 with ui.formatter(b'files', opts) as fm:
2864 return cmdutil.files(
2864 return cmdutil.files(
2865 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2865 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2866 )
2866 )
2867
2867
2868
2868
2869 @command(
2869 @command(
2870 b'forget',
2870 b'forget',
2871 [
2871 [
2872 (b'i', b'interactive', None, _(b'use interactive mode')),
2872 (b'i', b'interactive', None, _(b'use interactive mode')),
2873 ]
2873 ]
2874 + walkopts
2874 + walkopts
2875 + dryrunopts,
2875 + dryrunopts,
2876 _(b'[OPTION]... FILE...'),
2876 _(b'[OPTION]... FILE...'),
2877 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2877 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2878 helpbasic=True,
2878 helpbasic=True,
2879 inferrepo=True,
2879 inferrepo=True,
2880 )
2880 )
2881 def forget(ui, repo, *pats, **opts):
2881 def forget(ui, repo, *pats, **opts):
2882 """forget the specified files on the next commit
2882 """forget the specified files on the next commit
2883
2883
2884 Mark the specified files so they will no longer be tracked
2884 Mark the specified files so they will no longer be tracked
2885 after the next commit.
2885 after the next commit.
2886
2886
2887 This only removes files from the current branch, not from the
2887 This only removes files from the current branch, not from the
2888 entire project history, and it does not delete them from the
2888 entire project history, and it does not delete them from the
2889 working directory.
2889 working directory.
2890
2890
2891 To delete the file from the working directory, see :hg:`remove`.
2891 To delete the file from the working directory, see :hg:`remove`.
2892
2892
2893 To undo a forget before the next commit, see :hg:`add`.
2893 To undo a forget before the next commit, see :hg:`add`.
2894
2894
2895 .. container:: verbose
2895 .. container:: verbose
2896
2896
2897 Examples:
2897 Examples:
2898
2898
2899 - forget newly-added binary files::
2899 - forget newly-added binary files::
2900
2900
2901 hg forget "set:added() and binary()"
2901 hg forget "set:added() and binary()"
2902
2902
2903 - forget files that would be excluded by .hgignore::
2903 - forget files that would be excluded by .hgignore::
2904
2904
2905 hg forget "set:hgignore()"
2905 hg forget "set:hgignore()"
2906
2906
2907 Returns 0 on success.
2907 Returns 0 on success.
2908 """
2908 """
2909
2909
2910 opts = pycompat.byteskwargs(opts)
2910 opts = pycompat.byteskwargs(opts)
2911 if not pats:
2911 if not pats:
2912 raise error.InputError(_(b'no files specified'))
2912 raise error.InputError(_(b'no files specified'))
2913
2913
2914 m = scmutil.match(repo[None], pats, opts)
2914 m = scmutil.match(repo[None], pats, opts)
2915 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2915 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2916 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2916 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2917 rejected = cmdutil.forget(
2917 rejected = cmdutil.forget(
2918 ui,
2918 ui,
2919 repo,
2919 repo,
2920 m,
2920 m,
2921 prefix=b"",
2921 prefix=b"",
2922 uipathfn=uipathfn,
2922 uipathfn=uipathfn,
2923 explicitonly=False,
2923 explicitonly=False,
2924 dryrun=dryrun,
2924 dryrun=dryrun,
2925 interactive=interactive,
2925 interactive=interactive,
2926 )[0]
2926 )[0]
2927 return rejected and 1 or 0
2927 return rejected and 1 or 0
2928
2928
2929
2929
2930 @command(
2930 @command(
2931 b'graft',
2931 b'graft',
2932 [
2932 [
2933 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2933 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2934 (
2934 (
2935 b'',
2935 b'',
2936 b'base',
2936 b'base',
2937 b'',
2937 b'',
2938 _(b'base revision when doing the graft merge (ADVANCED)'),
2938 _(b'base revision when doing the graft merge (ADVANCED)'),
2939 _(b'REV'),
2939 _(b'REV'),
2940 ),
2940 ),
2941 (b'c', b'continue', False, _(b'resume interrupted graft')),
2941 (b'c', b'continue', False, _(b'resume interrupted graft')),
2942 (b'', b'stop', False, _(b'stop interrupted graft')),
2942 (b'', b'stop', False, _(b'stop interrupted graft')),
2943 (b'', b'abort', False, _(b'abort interrupted graft')),
2943 (b'', b'abort', False, _(b'abort interrupted graft')),
2944 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2944 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2945 (b'', b'log', None, _(b'append graft info to log message')),
2945 (b'', b'log', None, _(b'append graft info to log message')),
2946 (
2946 (
2947 b'',
2947 b'',
2948 b'no-commit',
2948 b'no-commit',
2949 None,
2949 None,
2950 _(b"don't commit, just apply the changes in working directory"),
2950 _(b"don't commit, just apply the changes in working directory"),
2951 ),
2951 ),
2952 (b'f', b'force', False, _(b'force graft')),
2952 (b'f', b'force', False, _(b'force graft')),
2953 (
2953 (
2954 b'D',
2954 b'D',
2955 b'currentdate',
2955 b'currentdate',
2956 False,
2956 False,
2957 _(b'record the current date as commit date'),
2957 _(b'record the current date as commit date'),
2958 ),
2958 ),
2959 (
2959 (
2960 b'U',
2960 b'U',
2961 b'currentuser',
2961 b'currentuser',
2962 False,
2962 False,
2963 _(b'record the current user as committer'),
2963 _(b'record the current user as committer'),
2964 ),
2964 ),
2965 ]
2965 ]
2966 + commitopts2
2966 + commitopts2
2967 + mergetoolopts
2967 + mergetoolopts
2968 + dryrunopts,
2968 + dryrunopts,
2969 _(b'[OPTION]... [-r REV]... REV...'),
2969 _(b'[OPTION]... [-r REV]... REV...'),
2970 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2970 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2971 )
2971 )
2972 def graft(ui, repo, *revs, **opts):
2972 def graft(ui, repo, *revs, **opts):
2973 """copy changes from other branches onto the current branch
2973 """copy changes from other branches onto the current branch
2974
2974
2975 This command uses Mercurial's merge logic to copy individual
2975 This command uses Mercurial's merge logic to copy individual
2976 changes from other branches without merging branches in the
2976 changes from other branches without merging branches in the
2977 history graph. This is sometimes known as 'backporting' or
2977 history graph. This is sometimes known as 'backporting' or
2978 'cherry-picking'. By default, graft will copy user, date, and
2978 'cherry-picking'. By default, graft will copy user, date, and
2979 description from the source changesets.
2979 description from the source changesets.
2980
2980
2981 Changesets that are ancestors of the current revision, that have
2981 Changesets that are ancestors of the current revision, that have
2982 already been grafted, or that are merges will be skipped.
2982 already been grafted, or that are merges will be skipped.
2983
2983
2984 If --log is specified, log messages will have a comment appended
2984 If --log is specified, log messages will have a comment appended
2985 of the form::
2985 of the form::
2986
2986
2987 (grafted from CHANGESETHASH)
2987 (grafted from CHANGESETHASH)
2988
2988
2989 If --force is specified, revisions will be grafted even if they
2989 If --force is specified, revisions will be grafted even if they
2990 are already ancestors of, or have been grafted to, the destination.
2990 are already ancestors of, or have been grafted to, the destination.
2991 This is useful when the revisions have since been backed out.
2991 This is useful when the revisions have since been backed out.
2992
2992
2993 If a graft merge results in conflicts, the graft process is
2993 If a graft merge results in conflicts, the graft process is
2994 interrupted so that the current merge can be manually resolved.
2994 interrupted so that the current merge can be manually resolved.
2995 Once all conflicts are addressed, the graft process can be
2995 Once all conflicts are addressed, the graft process can be
2996 continued with the -c/--continue option.
2996 continued with the -c/--continue option.
2997
2997
2998 The -c/--continue option reapplies all the earlier options.
2998 The -c/--continue option reapplies all the earlier options.
2999
2999
3000 .. container:: verbose
3000 .. container:: verbose
3001
3001
3002 The --base option exposes more of how graft internally uses merge with a
3002 The --base option exposes more of how graft internally uses merge with a
3003 custom base revision. --base can be used to specify another ancestor than
3003 custom base revision. --base can be used to specify another ancestor than
3004 the first and only parent.
3004 the first and only parent.
3005
3005
3006 The command::
3006 The command::
3007
3007
3008 hg graft -r 345 --base 234
3008 hg graft -r 345 --base 234
3009
3009
3010 is thus pretty much the same as::
3010 is thus pretty much the same as::
3011
3011
3012 hg diff --from 234 --to 345 | hg import
3012 hg diff --from 234 --to 345 | hg import
3013
3013
3014 but using merge to resolve conflicts and track moved files.
3014 but using merge to resolve conflicts and track moved files.
3015
3015
3016 The result of a merge can thus be backported as a single commit by
3016 The result of a merge can thus be backported as a single commit by
3017 specifying one of the merge parents as base, and thus effectively
3017 specifying one of the merge parents as base, and thus effectively
3018 grafting the changes from the other side.
3018 grafting the changes from the other side.
3019
3019
3020 It is also possible to collapse multiple changesets and clean up history
3020 It is also possible to collapse multiple changesets and clean up history
3021 by specifying another ancestor as base, much like rebase --collapse
3021 by specifying another ancestor as base, much like rebase --collapse
3022 --keep.
3022 --keep.
3023
3023
3024 The commit message can be tweaked after the fact using commit --amend .
3024 The commit message can be tweaked after the fact using commit --amend .
3025
3025
3026 For using non-ancestors as the base to backout changes, see the backout
3026 For using non-ancestors as the base to backout changes, see the backout
3027 command and the hidden --parent option.
3027 command and the hidden --parent option.
3028
3028
3029 .. container:: verbose
3029 .. container:: verbose
3030
3030
3031 Examples:
3031 Examples:
3032
3032
3033 - copy a single change to the stable branch and edit its description::
3033 - copy a single change to the stable branch and edit its description::
3034
3034
3035 hg update stable
3035 hg update stable
3036 hg graft --edit 9393
3036 hg graft --edit 9393
3037
3037
3038 - graft a range of changesets with one exception, updating dates::
3038 - graft a range of changesets with one exception, updating dates::
3039
3039
3040 hg graft -D "2085::2093 and not 2091"
3040 hg graft -D "2085::2093 and not 2091"
3041
3041
3042 - continue a graft after resolving conflicts::
3042 - continue a graft after resolving conflicts::
3043
3043
3044 hg graft -c
3044 hg graft -c
3045
3045
3046 - show the source of a grafted changeset::
3046 - show the source of a grafted changeset::
3047
3047
3048 hg log --debug -r .
3048 hg log --debug -r .
3049
3049
3050 - show revisions sorted by date::
3050 - show revisions sorted by date::
3051
3051
3052 hg log -r "sort(all(), date)"
3052 hg log -r "sort(all(), date)"
3053
3053
3054 - backport the result of a merge as a single commit::
3054 - backport the result of a merge as a single commit::
3055
3055
3056 hg graft -r 123 --base 123^
3056 hg graft -r 123 --base 123^
3057
3057
3058 - land a feature branch as one changeset::
3058 - land a feature branch as one changeset::
3059
3059
3060 hg up -cr default
3060 hg up -cr default
3061 hg graft -r featureX --base "ancestor('featureX', 'default')"
3061 hg graft -r featureX --base "ancestor('featureX', 'default')"
3062
3062
3063 See :hg:`help revisions` for more about specifying revisions.
3063 See :hg:`help revisions` for more about specifying revisions.
3064
3064
3065 Returns 0 on successful completion, 1 if there are unresolved files.
3065 Returns 0 on successful completion, 1 if there are unresolved files.
3066 """
3066 """
3067 with repo.wlock():
3067 with repo.wlock():
3068 return _dograft(ui, repo, *revs, **opts)
3068 return _dograft(ui, repo, *revs, **opts)
3069
3069
3070
3070
3071 def _dograft(ui, repo, *revs, **opts):
3071 def _dograft(ui, repo, *revs, **opts):
3072 opts = pycompat.byteskwargs(opts)
3072 opts = pycompat.byteskwargs(opts)
3073 if revs and opts.get(b'rev'):
3073 if revs and opts.get(b'rev'):
3074 ui.warn(
3074 ui.warn(
3075 _(
3075 _(
3076 b'warning: inconsistent use of --rev might give unexpected '
3076 b'warning: inconsistent use of --rev might give unexpected '
3077 b'revision ordering!\n'
3077 b'revision ordering!\n'
3078 )
3078 )
3079 )
3079 )
3080
3080
3081 revs = list(revs)
3081 revs = list(revs)
3082 revs.extend(opts.get(b'rev'))
3082 revs.extend(opts.get(b'rev'))
3083 # a dict of data to be stored in state file
3083 # a dict of data to be stored in state file
3084 statedata = {}
3084 statedata = {}
3085 # list of new nodes created by ongoing graft
3085 # list of new nodes created by ongoing graft
3086 statedata[b'newnodes'] = []
3086 statedata[b'newnodes'] = []
3087
3087
3088 cmdutil.resolvecommitoptions(ui, opts)
3088 cmdutil.resolvecommitoptions(ui, opts)
3089
3089
3090 editor = cmdutil.getcommiteditor(
3090 editor = cmdutil.getcommiteditor(
3091 editform=b'graft', **pycompat.strkwargs(opts)
3091 editform=b'graft', **pycompat.strkwargs(opts)
3092 )
3092 )
3093
3093
3094 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3094 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3095
3095
3096 cont = False
3096 cont = False
3097 if opts.get(b'no_commit'):
3097 if opts.get(b'no_commit'):
3098 cmdutil.check_incompatible_arguments(
3098 cmdutil.check_incompatible_arguments(
3099 opts,
3099 opts,
3100 b'no_commit',
3100 b'no_commit',
3101 [b'edit', b'currentuser', b'currentdate', b'log'],
3101 [b'edit', b'currentuser', b'currentdate', b'log'],
3102 )
3102 )
3103
3103
3104 graftstate = statemod.cmdstate(repo, b'graftstate')
3104 graftstate = statemod.cmdstate(repo, b'graftstate')
3105
3105
3106 if opts.get(b'stop'):
3106 if opts.get(b'stop'):
3107 cmdutil.check_incompatible_arguments(
3107 cmdutil.check_incompatible_arguments(
3108 opts,
3108 opts,
3109 b'stop',
3109 b'stop',
3110 [
3110 [
3111 b'edit',
3111 b'edit',
3112 b'log',
3112 b'log',
3113 b'user',
3113 b'user',
3114 b'date',
3114 b'date',
3115 b'currentdate',
3115 b'currentdate',
3116 b'currentuser',
3116 b'currentuser',
3117 b'rev',
3117 b'rev',
3118 ],
3118 ],
3119 )
3119 )
3120 return _stopgraft(ui, repo, graftstate)
3120 return _stopgraft(ui, repo, graftstate)
3121 elif opts.get(b'abort'):
3121 elif opts.get(b'abort'):
3122 cmdutil.check_incompatible_arguments(
3122 cmdutil.check_incompatible_arguments(
3123 opts,
3123 opts,
3124 b'abort',
3124 b'abort',
3125 [
3125 [
3126 b'edit',
3126 b'edit',
3127 b'log',
3127 b'log',
3128 b'user',
3128 b'user',
3129 b'date',
3129 b'date',
3130 b'currentdate',
3130 b'currentdate',
3131 b'currentuser',
3131 b'currentuser',
3132 b'rev',
3132 b'rev',
3133 ],
3133 ],
3134 )
3134 )
3135 return cmdutil.abortgraft(ui, repo, graftstate)
3135 return cmdutil.abortgraft(ui, repo, graftstate)
3136 elif opts.get(b'continue'):
3136 elif opts.get(b'continue'):
3137 cont = True
3137 cont = True
3138 if revs:
3138 if revs:
3139 raise error.InputError(_(b"can't specify --continue and revisions"))
3139 raise error.InputError(_(b"can't specify --continue and revisions"))
3140 # read in unfinished revisions
3140 # read in unfinished revisions
3141 if graftstate.exists():
3141 if graftstate.exists():
3142 statedata = cmdutil.readgraftstate(repo, graftstate)
3142 statedata = cmdutil.readgraftstate(repo, graftstate)
3143 if statedata.get(b'date'):
3143 if statedata.get(b'date'):
3144 opts[b'date'] = statedata[b'date']
3144 opts[b'date'] = statedata[b'date']
3145 if statedata.get(b'user'):
3145 if statedata.get(b'user'):
3146 opts[b'user'] = statedata[b'user']
3146 opts[b'user'] = statedata[b'user']
3147 if statedata.get(b'log'):
3147 if statedata.get(b'log'):
3148 opts[b'log'] = True
3148 opts[b'log'] = True
3149 if statedata.get(b'no_commit'):
3149 if statedata.get(b'no_commit'):
3150 opts[b'no_commit'] = statedata.get(b'no_commit')
3150 opts[b'no_commit'] = statedata.get(b'no_commit')
3151 if statedata.get(b'base'):
3151 if statedata.get(b'base'):
3152 opts[b'base'] = statedata.get(b'base')
3152 opts[b'base'] = statedata.get(b'base')
3153 nodes = statedata[b'nodes']
3153 nodes = statedata[b'nodes']
3154 revs = [repo[node].rev() for node in nodes]
3154 revs = [repo[node].rev() for node in nodes]
3155 else:
3155 else:
3156 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3156 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3157 else:
3157 else:
3158 if not revs:
3158 if not revs:
3159 raise error.InputError(_(b'no revisions specified'))
3159 raise error.InputError(_(b'no revisions specified'))
3160 cmdutil.checkunfinished(repo)
3160 cmdutil.checkunfinished(repo)
3161 cmdutil.bailifchanged(repo)
3161 cmdutil.bailifchanged(repo)
3162 revs = scmutil.revrange(repo, revs)
3162 revs = scmutil.revrange(repo, revs)
3163
3163
3164 skipped = set()
3164 skipped = set()
3165 basectx = None
3165 basectx = None
3166 if opts.get(b'base'):
3166 if opts.get(b'base'):
3167 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3167 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3168 if basectx is None:
3168 if basectx is None:
3169 # check for merges
3169 # check for merges
3170 for rev in repo.revs(b'%ld and merge()', revs):
3170 for rev in repo.revs(b'%ld and merge()', revs):
3171 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3171 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3172 skipped.add(rev)
3172 skipped.add(rev)
3173 revs = [r for r in revs if r not in skipped]
3173 revs = [r for r in revs if r not in skipped]
3174 if not revs:
3174 if not revs:
3175 return -1
3175 return -1
3176 if basectx is not None and len(revs) != 1:
3176 if basectx is not None and len(revs) != 1:
3177 raise error.InputError(_(b'only one revision allowed with --base '))
3177 raise error.InputError(_(b'only one revision allowed with --base '))
3178
3178
3179 # Don't check in the --continue case, in effect retaining --force across
3179 # Don't check in the --continue case, in effect retaining --force across
3180 # --continues. That's because without --force, any revisions we decided to
3180 # --continues. That's because without --force, any revisions we decided to
3181 # skip would have been filtered out here, so they wouldn't have made their
3181 # skip would have been filtered out here, so they wouldn't have made their
3182 # way to the graftstate. With --force, any revisions we would have otherwise
3182 # way to the graftstate. With --force, any revisions we would have otherwise
3183 # skipped would not have been filtered out, and if they hadn't been applied
3183 # skipped would not have been filtered out, and if they hadn't been applied
3184 # already, they'd have been in the graftstate.
3184 # already, they'd have been in the graftstate.
3185 if not (cont or opts.get(b'force')) and basectx is None:
3185 if not (cont or opts.get(b'force')) and basectx is None:
3186 # check for ancestors of dest branch
3186 # check for ancestors of dest branch
3187 ancestors = repo.revs(b'%ld & (::.)', revs)
3187 ancestors = repo.revs(b'%ld & (::.)', revs)
3188 for rev in ancestors:
3188 for rev in ancestors:
3189 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3189 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3190
3190
3191 revs = [r for r in revs if r not in ancestors]
3191 revs = [r for r in revs if r not in ancestors]
3192
3192
3193 if not revs:
3193 if not revs:
3194 return -1
3194 return -1
3195
3195
3196 # analyze revs for earlier grafts
3196 # analyze revs for earlier grafts
3197 ids = {}
3197 ids = {}
3198 for ctx in repo.set(b"%ld", revs):
3198 for ctx in repo.set(b"%ld", revs):
3199 ids[ctx.hex()] = ctx.rev()
3199 ids[ctx.hex()] = ctx.rev()
3200 n = ctx.extra().get(b'source')
3200 n = ctx.extra().get(b'source')
3201 if n:
3201 if n:
3202 ids[n] = ctx.rev()
3202 ids[n] = ctx.rev()
3203
3203
3204 # check ancestors for earlier grafts
3204 # check ancestors for earlier grafts
3205 ui.debug(b'scanning for duplicate grafts\n')
3205 ui.debug(b'scanning for duplicate grafts\n')
3206
3206
3207 # The only changesets we can be sure doesn't contain grafts of any
3207 # The only changesets we can be sure doesn't contain grafts of any
3208 # revs, are the ones that are common ancestors of *all* revs:
3208 # revs, are the ones that are common ancestors of *all* revs:
3209 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3209 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3210 ctx = repo[rev]
3210 ctx = repo[rev]
3211 n = ctx.extra().get(b'source')
3211 n = ctx.extra().get(b'source')
3212 if n in ids:
3212 if n in ids:
3213 try:
3213 try:
3214 r = repo[n].rev()
3214 r = repo[n].rev()
3215 except error.RepoLookupError:
3215 except error.RepoLookupError:
3216 r = None
3216 r = None
3217 if r in revs:
3217 if r in revs:
3218 ui.warn(
3218 ui.warn(
3219 _(
3219 _(
3220 b'skipping revision %d:%s '
3220 b'skipping revision %d:%s '
3221 b'(already grafted to %d:%s)\n'
3221 b'(already grafted to %d:%s)\n'
3222 )
3222 )
3223 % (r, repo[r], rev, ctx)
3223 % (r, repo[r], rev, ctx)
3224 )
3224 )
3225 revs.remove(r)
3225 revs.remove(r)
3226 elif ids[n] in revs:
3226 elif ids[n] in revs:
3227 if r is None:
3227 if r is None:
3228 ui.warn(
3228 ui.warn(
3229 _(
3229 _(
3230 b'skipping already grafted revision %d:%s '
3230 b'skipping already grafted revision %d:%s '
3231 b'(%d:%s also has unknown origin %s)\n'
3231 b'(%d:%s also has unknown origin %s)\n'
3232 )
3232 )
3233 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3233 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3234 )
3234 )
3235 else:
3235 else:
3236 ui.warn(
3236 ui.warn(
3237 _(
3237 _(
3238 b'skipping already grafted revision %d:%s '
3238 b'skipping already grafted revision %d:%s '
3239 b'(%d:%s also has origin %d:%s)\n'
3239 b'(%d:%s also has origin %d:%s)\n'
3240 )
3240 )
3241 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3241 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3242 )
3242 )
3243 revs.remove(ids[n])
3243 revs.remove(ids[n])
3244 elif ctx.hex() in ids:
3244 elif ctx.hex() in ids:
3245 r = ids[ctx.hex()]
3245 r = ids[ctx.hex()]
3246 if r in revs:
3246 if r in revs:
3247 ui.warn(
3247 ui.warn(
3248 _(
3248 _(
3249 b'skipping already grafted revision %d:%s '
3249 b'skipping already grafted revision %d:%s '
3250 b'(was grafted from %d:%s)\n'
3250 b'(was grafted from %d:%s)\n'
3251 )
3251 )
3252 % (r, repo[r], rev, ctx)
3252 % (r, repo[r], rev, ctx)
3253 )
3253 )
3254 revs.remove(r)
3254 revs.remove(r)
3255 if not revs:
3255 if not revs:
3256 return -1
3256 return -1
3257
3257
3258 if opts.get(b'no_commit'):
3258 if opts.get(b'no_commit'):
3259 statedata[b'no_commit'] = True
3259 statedata[b'no_commit'] = True
3260 if opts.get(b'base'):
3260 if opts.get(b'base'):
3261 statedata[b'base'] = opts[b'base']
3261 statedata[b'base'] = opts[b'base']
3262 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3262 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3263 desc = b'%d:%s "%s"' % (
3263 desc = b'%d:%s "%s"' % (
3264 ctx.rev(),
3264 ctx.rev(),
3265 ctx,
3265 ctx,
3266 ctx.description().split(b'\n', 1)[0],
3266 ctx.description().split(b'\n', 1)[0],
3267 )
3267 )
3268 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3268 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3269 if names:
3269 if names:
3270 desc += b' (%s)' % b' '.join(names)
3270 desc += b' (%s)' % b' '.join(names)
3271 ui.status(_(b'grafting %s\n') % desc)
3271 ui.status(_(b'grafting %s\n') % desc)
3272 if opts.get(b'dry_run'):
3272 if opts.get(b'dry_run'):
3273 continue
3273 continue
3274
3274
3275 source = ctx.extra().get(b'source')
3275 source = ctx.extra().get(b'source')
3276 extra = {}
3276 extra = {}
3277 if source:
3277 if source:
3278 extra[b'source'] = source
3278 extra[b'source'] = source
3279 extra[b'intermediate-source'] = ctx.hex()
3279 extra[b'intermediate-source'] = ctx.hex()
3280 else:
3280 else:
3281 extra[b'source'] = ctx.hex()
3281 extra[b'source'] = ctx.hex()
3282 user = ctx.user()
3282 user = ctx.user()
3283 if opts.get(b'user'):
3283 if opts.get(b'user'):
3284 user = opts[b'user']
3284 user = opts[b'user']
3285 statedata[b'user'] = user
3285 statedata[b'user'] = user
3286 date = ctx.date()
3286 date = ctx.date()
3287 if opts.get(b'date'):
3287 if opts.get(b'date'):
3288 date = opts[b'date']
3288 date = opts[b'date']
3289 statedata[b'date'] = date
3289 statedata[b'date'] = date
3290 message = ctx.description()
3290 message = ctx.description()
3291 if opts.get(b'log'):
3291 if opts.get(b'log'):
3292 message += b'\n(grafted from %s)' % ctx.hex()
3292 message += b'\n(grafted from %s)' % ctx.hex()
3293 statedata[b'log'] = True
3293 statedata[b'log'] = True
3294
3294
3295 # we don't merge the first commit when continuing
3295 # we don't merge the first commit when continuing
3296 if not cont:
3296 if not cont:
3297 # perform the graft merge with p1(rev) as 'ancestor'
3297 # perform the graft merge with p1(rev) as 'ancestor'
3298 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3298 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3299 base = ctx.p1() if basectx is None else basectx
3299 base = ctx.p1() if basectx is None else basectx
3300 with ui.configoverride(overrides, b'graft'):
3300 with ui.configoverride(overrides, b'graft'):
3301 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3301 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3302 # report any conflicts
3302 # report any conflicts
3303 if stats.unresolvedcount > 0:
3303 if stats.unresolvedcount > 0:
3304 # write out state for --continue
3304 # write out state for --continue
3305 nodes = [repo[rev].hex() for rev in revs[pos:]]
3305 nodes = [repo[rev].hex() for rev in revs[pos:]]
3306 statedata[b'nodes'] = nodes
3306 statedata[b'nodes'] = nodes
3307 stateversion = 1
3307 stateversion = 1
3308 graftstate.save(stateversion, statedata)
3308 graftstate.save(stateversion, statedata)
3309 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3309 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3310 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3310 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3311 return 1
3311 return 1
3312 else:
3312 else:
3313 cont = False
3313 cont = False
3314
3314
3315 # commit if --no-commit is false
3315 # commit if --no-commit is false
3316 if not opts.get(b'no_commit'):
3316 if not opts.get(b'no_commit'):
3317 node = repo.commit(
3317 node = repo.commit(
3318 text=message, user=user, date=date, extra=extra, editor=editor
3318 text=message, user=user, date=date, extra=extra, editor=editor
3319 )
3319 )
3320 if node is None:
3320 if node is None:
3321 ui.warn(
3321 ui.warn(
3322 _(b'note: graft of %d:%s created no changes to commit\n')
3322 _(b'note: graft of %d:%s created no changes to commit\n')
3323 % (ctx.rev(), ctx)
3323 % (ctx.rev(), ctx)
3324 )
3324 )
3325 # checking that newnodes exist because old state files won't have it
3325 # checking that newnodes exist because old state files won't have it
3326 elif statedata.get(b'newnodes') is not None:
3326 elif statedata.get(b'newnodes') is not None:
3327 nn = statedata[b'newnodes'] # type: List[bytes]
3327 nn = statedata[b'newnodes'] # type: List[bytes]
3328 nn.append(node)
3328 nn.append(node)
3329
3329
3330 # remove state when we complete successfully
3330 # remove state when we complete successfully
3331 if not opts.get(b'dry_run'):
3331 if not opts.get(b'dry_run'):
3332 graftstate.delete()
3332 graftstate.delete()
3333
3333
3334 return 0
3334 return 0
3335
3335
3336
3336
3337 def _stopgraft(ui, repo, graftstate):
3337 def _stopgraft(ui, repo, graftstate):
3338 """stop the interrupted graft"""
3338 """stop the interrupted graft"""
3339 if not graftstate.exists():
3339 if not graftstate.exists():
3340 raise error.StateError(_(b"no interrupted graft found"))
3340 raise error.StateError(_(b"no interrupted graft found"))
3341 pctx = repo[b'.']
3341 pctx = repo[b'.']
3342 mergemod.clean_update(pctx)
3342 mergemod.clean_update(pctx)
3343 graftstate.delete()
3343 graftstate.delete()
3344 ui.status(_(b"stopped the interrupted graft\n"))
3344 ui.status(_(b"stopped the interrupted graft\n"))
3345 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3345 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3346 return 0
3346 return 0
3347
3347
3348
3348
3349 statemod.addunfinished(
3349 statemod.addunfinished(
3350 b'graft',
3350 b'graft',
3351 fname=b'graftstate',
3351 fname=b'graftstate',
3352 clearable=True,
3352 clearable=True,
3353 stopflag=True,
3353 stopflag=True,
3354 continueflag=True,
3354 continueflag=True,
3355 abortfunc=cmdutil.hgabortgraft,
3355 abortfunc=cmdutil.hgabortgraft,
3356 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3356 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3357 )
3357 )
3358
3358
3359
3359
3360 @command(
3360 @command(
3361 b'grep',
3361 b'grep',
3362 [
3362 [
3363 (b'0', b'print0', None, _(b'end fields with NUL')),
3363 (b'0', b'print0', None, _(b'end fields with NUL')),
3364 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3364 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3365 (
3365 (
3366 b'',
3366 b'',
3367 b'diff',
3367 b'diff',
3368 None,
3368 None,
3369 _(
3369 _(
3370 b'search revision differences for when the pattern was added '
3370 b'search revision differences for when the pattern was added '
3371 b'or removed'
3371 b'or removed'
3372 ),
3372 ),
3373 ),
3373 ),
3374 (b'a', b'text', None, _(b'treat all files as text')),
3374 (b'a', b'text', None, _(b'treat all files as text')),
3375 (
3375 (
3376 b'f',
3376 b'f',
3377 b'follow',
3377 b'follow',
3378 None,
3378 None,
3379 _(
3379 _(
3380 b'follow changeset history,'
3380 b'follow changeset history,'
3381 b' or file history across copies and renames'
3381 b' or file history across copies and renames'
3382 ),
3382 ),
3383 ),
3383 ),
3384 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3384 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3385 (
3385 (
3386 b'l',
3386 b'l',
3387 b'files-with-matches',
3387 b'files-with-matches',
3388 None,
3388 None,
3389 _(b'print only filenames and revisions that match'),
3389 _(b'print only filenames and revisions that match'),
3390 ),
3390 ),
3391 (b'n', b'line-number', None, _(b'print matching line numbers')),
3391 (b'n', b'line-number', None, _(b'print matching line numbers')),
3392 (
3392 (
3393 b'r',
3393 b'r',
3394 b'rev',
3394 b'rev',
3395 [],
3395 [],
3396 _(b'search files changed within revision range'),
3396 _(b'search files changed within revision range'),
3397 _(b'REV'),
3397 _(b'REV'),
3398 ),
3398 ),
3399 (
3399 (
3400 b'',
3400 b'',
3401 b'all-files',
3401 b'all-files',
3402 None,
3402 None,
3403 _(
3403 _(
3404 b'include all files in the changeset while grepping (DEPRECATED)'
3404 b'include all files in the changeset while grepping (DEPRECATED)'
3405 ),
3405 ),
3406 ),
3406 ),
3407 (b'u', b'user', None, _(b'list the author (long with -v)')),
3407 (b'u', b'user', None, _(b'list the author (long with -v)')),
3408 (b'd', b'date', None, _(b'list the date (short with -q)')),
3408 (b'd', b'date', None, _(b'list the date (short with -q)')),
3409 ]
3409 ]
3410 + formatteropts
3410 + formatteropts
3411 + walkopts,
3411 + walkopts,
3412 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3412 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3413 helpcategory=command.CATEGORY_FILE_CONTENTS,
3413 helpcategory=command.CATEGORY_FILE_CONTENTS,
3414 inferrepo=True,
3414 inferrepo=True,
3415 intents={INTENT_READONLY},
3415 intents={INTENT_READONLY},
3416 )
3416 )
3417 def grep(ui, repo, pattern, *pats, **opts):
3417 def grep(ui, repo, pattern, *pats, **opts):
3418 """search for a pattern in specified files
3418 """search for a pattern in specified files
3419
3419
3420 Search the working directory or revision history for a regular
3420 Search the working directory or revision history for a regular
3421 expression in the specified files for the entire repository.
3421 expression in the specified files for the entire repository.
3422
3422
3423 By default, grep searches the repository files in the working
3423 By default, grep searches the repository files in the working
3424 directory and prints the files where it finds a match. To specify
3424 directory and prints the files where it finds a match. To specify
3425 historical revisions instead of the working directory, use the
3425 historical revisions instead of the working directory, use the
3426 --rev flag.
3426 --rev flag.
3427
3427
3428 To search instead historical revision differences that contains a
3428 To search instead historical revision differences that contains a
3429 change in match status ("-" for a match that becomes a non-match,
3429 change in match status ("-" for a match that becomes a non-match,
3430 or "+" for a non-match that becomes a match), use the --diff flag.
3430 or "+" for a non-match that becomes a match), use the --diff flag.
3431
3431
3432 PATTERN can be any Python (roughly Perl-compatible) regular
3432 PATTERN can be any Python (roughly Perl-compatible) regular
3433 expression.
3433 expression.
3434
3434
3435 If no FILEs are specified and the --rev flag isn't supplied, all
3435 If no FILEs are specified and the --rev flag isn't supplied, all
3436 files in the working directory are searched. When using the --rev
3436 files in the working directory are searched. When using the --rev
3437 flag and specifying FILEs, use the --follow argument to also
3437 flag and specifying FILEs, use the --follow argument to also
3438 follow the specified FILEs across renames and copies.
3438 follow the specified FILEs across renames and copies.
3439
3439
3440 .. container:: verbose
3440 .. container:: verbose
3441
3441
3442 Template:
3442 Template:
3443
3443
3444 The following keywords are supported in addition to the common template
3444 The following keywords are supported in addition to the common template
3445 keywords and functions. See also :hg:`help templates`.
3445 keywords and functions. See also :hg:`help templates`.
3446
3446
3447 :change: String. Character denoting insertion ``+`` or removal ``-``.
3447 :change: String. Character denoting insertion ``+`` or removal ``-``.
3448 Available if ``--diff`` is specified.
3448 Available if ``--diff`` is specified.
3449 :lineno: Integer. Line number of the match.
3449 :lineno: Integer. Line number of the match.
3450 :path: String. Repository-absolute path of the file.
3450 :path: String. Repository-absolute path of the file.
3451 :texts: List of text chunks.
3451 :texts: List of text chunks.
3452
3452
3453 And each entry of ``{texts}`` provides the following sub-keywords.
3453 And each entry of ``{texts}`` provides the following sub-keywords.
3454
3454
3455 :matched: Boolean. True if the chunk matches the specified pattern.
3455 :matched: Boolean. True if the chunk matches the specified pattern.
3456 :text: String. Chunk content.
3456 :text: String. Chunk content.
3457
3457
3458 See :hg:`help templates.operators` for the list expansion syntax.
3458 See :hg:`help templates.operators` for the list expansion syntax.
3459
3459
3460 Returns 0 if a match is found, 1 otherwise.
3460 Returns 0 if a match is found, 1 otherwise.
3461
3461
3462 """
3462 """
3463 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3463 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3464 opts = pycompat.byteskwargs(opts)
3464 opts = pycompat.byteskwargs(opts)
3465 diff = opts.get(b'all') or opts.get(b'diff')
3465 diff = opts.get(b'all') or opts.get(b'diff')
3466 follow = opts.get(b'follow')
3466 follow = opts.get(b'follow')
3467 if opts.get(b'all_files') is None and not diff:
3467 if opts.get(b'all_files') is None and not diff:
3468 opts[b'all_files'] = True
3468 opts[b'all_files'] = True
3469 plaingrep = (
3469 plaingrep = (
3470 opts.get(b'all_files')
3470 opts.get(b'all_files')
3471 and not opts.get(b'rev')
3471 and not opts.get(b'rev')
3472 and not opts.get(b'follow')
3472 and not opts.get(b'follow')
3473 )
3473 )
3474 all_files = opts.get(b'all_files')
3474 all_files = opts.get(b'all_files')
3475 if plaingrep:
3475 if plaingrep:
3476 opts[b'rev'] = [b'wdir()']
3476 opts[b'rev'] = [b'wdir()']
3477
3477
3478 reflags = re.M
3478 reflags = re.M
3479 if opts.get(b'ignore_case'):
3479 if opts.get(b'ignore_case'):
3480 reflags |= re.I
3480 reflags |= re.I
3481 try:
3481 try:
3482 regexp = util.re.compile(pattern, reflags)
3482 regexp = util.re.compile(pattern, reflags)
3483 except re.error as inst:
3483 except re.error as inst:
3484 ui.warn(
3484 ui.warn(
3485 _(b"grep: invalid match pattern: %s\n")
3485 _(b"grep: invalid match pattern: %s\n")
3486 % stringutil.forcebytestr(inst)
3486 % stringutil.forcebytestr(inst)
3487 )
3487 )
3488 return 1
3488 return 1
3489 sep, eol = b':', b'\n'
3489 sep, eol = b':', b'\n'
3490 if opts.get(b'print0'):
3490 if opts.get(b'print0'):
3491 sep = eol = b'\0'
3491 sep = eol = b'\0'
3492
3492
3493 searcher = grepmod.grepsearcher(
3493 searcher = grepmod.grepsearcher(
3494 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3494 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3495 )
3495 )
3496
3496
3497 getfile = searcher._getfile
3497 getfile = searcher._getfile
3498
3498
3499 uipathfn = scmutil.getuipathfn(repo)
3499 uipathfn = scmutil.getuipathfn(repo)
3500
3500
3501 def display(fm, fn, ctx, pstates, states):
3501 def display(fm, fn, ctx, pstates, states):
3502 rev = scmutil.intrev(ctx)
3502 rev = scmutil.intrev(ctx)
3503 if fm.isplain():
3503 if fm.isplain():
3504 formatuser = ui.shortuser
3504 formatuser = ui.shortuser
3505 else:
3505 else:
3506 formatuser = pycompat.bytestr
3506 formatuser = pycompat.bytestr
3507 if ui.quiet:
3507 if ui.quiet:
3508 datefmt = b'%Y-%m-%d'
3508 datefmt = b'%Y-%m-%d'
3509 else:
3509 else:
3510 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3510 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3511 found = False
3511 found = False
3512
3512
3513 @util.cachefunc
3513 @util.cachefunc
3514 def binary():
3514 def binary():
3515 flog = getfile(fn)
3515 flog = getfile(fn)
3516 try:
3516 try:
3517 return stringutil.binary(flog.read(ctx.filenode(fn)))
3517 return stringutil.binary(flog.read(ctx.filenode(fn)))
3518 except error.WdirUnsupported:
3518 except error.WdirUnsupported:
3519 return ctx[fn].isbinary()
3519 return ctx[fn].isbinary()
3520
3520
3521 fieldnamemap = {b'linenumber': b'lineno'}
3521 fieldnamemap = {b'linenumber': b'lineno'}
3522 if diff:
3522 if diff:
3523 iter = grepmod.difflinestates(pstates, states)
3523 iter = grepmod.difflinestates(pstates, states)
3524 else:
3524 else:
3525 iter = [(b'', l) for l in states]
3525 iter = [(b'', l) for l in states]
3526 for change, l in iter:
3526 for change, l in iter:
3527 fm.startitem()
3527 fm.startitem()
3528 fm.context(ctx=ctx)
3528 fm.context(ctx=ctx)
3529 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3529 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3530 fm.plain(uipathfn(fn), label=b'grep.filename')
3530 fm.plain(uipathfn(fn), label=b'grep.filename')
3531
3531
3532 cols = [
3532 cols = [
3533 (b'rev', b'%d', rev, not plaingrep, b''),
3533 (b'rev', b'%d', rev, not plaingrep, b''),
3534 (
3534 (
3535 b'linenumber',
3535 b'linenumber',
3536 b'%d',
3536 b'%d',
3537 l.linenum,
3537 l.linenum,
3538 opts.get(b'line_number'),
3538 opts.get(b'line_number'),
3539 b'',
3539 b'',
3540 ),
3540 ),
3541 ]
3541 ]
3542 if diff:
3542 if diff:
3543 cols.append(
3543 cols.append(
3544 (
3544 (
3545 b'change',
3545 b'change',
3546 b'%s',
3546 b'%s',
3547 change,
3547 change,
3548 True,
3548 True,
3549 b'grep.inserted '
3549 b'grep.inserted '
3550 if change == b'+'
3550 if change == b'+'
3551 else b'grep.deleted ',
3551 else b'grep.deleted ',
3552 )
3552 )
3553 )
3553 )
3554 cols.extend(
3554 cols.extend(
3555 [
3555 [
3556 (
3556 (
3557 b'user',
3557 b'user',
3558 b'%s',
3558 b'%s',
3559 formatuser(ctx.user()),
3559 formatuser(ctx.user()),
3560 opts.get(b'user'),
3560 opts.get(b'user'),
3561 b'',
3561 b'',
3562 ),
3562 ),
3563 (
3563 (
3564 b'date',
3564 b'date',
3565 b'%s',
3565 b'%s',
3566 fm.formatdate(ctx.date(), datefmt),
3566 fm.formatdate(ctx.date(), datefmt),
3567 opts.get(b'date'),
3567 opts.get(b'date'),
3568 b'',
3568 b'',
3569 ),
3569 ),
3570 ]
3570 ]
3571 )
3571 )
3572 for name, fmt, data, cond, extra_label in cols:
3572 for name, fmt, data, cond, extra_label in cols:
3573 if cond:
3573 if cond:
3574 fm.plain(sep, label=b'grep.sep')
3574 fm.plain(sep, label=b'grep.sep')
3575 field = fieldnamemap.get(name, name)
3575 field = fieldnamemap.get(name, name)
3576 label = extra_label + (b'grep.%s' % name)
3576 label = extra_label + (b'grep.%s' % name)
3577 fm.condwrite(cond, field, fmt, data, label=label)
3577 fm.condwrite(cond, field, fmt, data, label=label)
3578 if not opts.get(b'files_with_matches'):
3578 if not opts.get(b'files_with_matches'):
3579 fm.plain(sep, label=b'grep.sep')
3579 fm.plain(sep, label=b'grep.sep')
3580 if not opts.get(b'text') and binary():
3580 if not opts.get(b'text') and binary():
3581 fm.plain(_(b" Binary file matches"))
3581 fm.plain(_(b" Binary file matches"))
3582 else:
3582 else:
3583 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3583 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3584 fm.plain(eol)
3584 fm.plain(eol)
3585 found = True
3585 found = True
3586 if opts.get(b'files_with_matches'):
3586 if opts.get(b'files_with_matches'):
3587 break
3587 break
3588 return found
3588 return found
3589
3589
3590 def displaymatches(fm, l):
3590 def displaymatches(fm, l):
3591 p = 0
3591 p = 0
3592 for s, e in l.findpos(regexp):
3592 for s, e in l.findpos(regexp):
3593 if p < s:
3593 if p < s:
3594 fm.startitem()
3594 fm.startitem()
3595 fm.write(b'text', b'%s', l.line[p:s])
3595 fm.write(b'text', b'%s', l.line[p:s])
3596 fm.data(matched=False)
3596 fm.data(matched=False)
3597 fm.startitem()
3597 fm.startitem()
3598 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3598 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3599 fm.data(matched=True)
3599 fm.data(matched=True)
3600 p = e
3600 p = e
3601 if p < len(l.line):
3601 if p < len(l.line):
3602 fm.startitem()
3602 fm.startitem()
3603 fm.write(b'text', b'%s', l.line[p:])
3603 fm.write(b'text', b'%s', l.line[p:])
3604 fm.data(matched=False)
3604 fm.data(matched=False)
3605 fm.end()
3605 fm.end()
3606
3606
3607 found = False
3607 found = False
3608
3608
3609 wopts = logcmdutil.walkopts(
3609 wopts = logcmdutil.walkopts(
3610 pats=pats,
3610 pats=pats,
3611 opts=opts,
3611 opts=opts,
3612 revspec=opts[b'rev'],
3612 revspec=opts[b'rev'],
3613 include_pats=opts[b'include'],
3613 include_pats=opts[b'include'],
3614 exclude_pats=opts[b'exclude'],
3614 exclude_pats=opts[b'exclude'],
3615 follow=follow,
3615 follow=follow,
3616 force_changelog_traversal=all_files,
3616 force_changelog_traversal=all_files,
3617 filter_revisions_by_pats=not all_files,
3617 filter_revisions_by_pats=not all_files,
3618 )
3618 )
3619 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3619 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3620
3620
3621 ui.pager(b'grep')
3621 ui.pager(b'grep')
3622 fm = ui.formatter(b'grep', opts)
3622 fm = ui.formatter(b'grep', opts)
3623 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3623 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3624 r = display(fm, fn, ctx, pstates, states)
3624 r = display(fm, fn, ctx, pstates, states)
3625 found = found or r
3625 found = found or r
3626 if r and not diff and not all_files:
3626 if r and not diff and not all_files:
3627 searcher.skipfile(fn, ctx.rev())
3627 searcher.skipfile(fn, ctx.rev())
3628 fm.end()
3628 fm.end()
3629
3629
3630 return not found
3630 return not found
3631
3631
3632
3632
3633 @command(
3633 @command(
3634 b'heads',
3634 b'heads',
3635 [
3635 [
3636 (
3636 (
3637 b'r',
3637 b'r',
3638 b'rev',
3638 b'rev',
3639 b'',
3639 b'',
3640 _(b'show only heads which are descendants of STARTREV'),
3640 _(b'show only heads which are descendants of STARTREV'),
3641 _(b'STARTREV'),
3641 _(b'STARTREV'),
3642 ),
3642 ),
3643 (b't', b'topo', False, _(b'show topological heads only')),
3643 (b't', b'topo', False, _(b'show topological heads only')),
3644 (
3644 (
3645 b'a',
3645 b'a',
3646 b'active',
3646 b'active',
3647 False,
3647 False,
3648 _(b'show active branchheads only (DEPRECATED)'),
3648 _(b'show active branchheads only (DEPRECATED)'),
3649 ),
3649 ),
3650 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3650 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3651 ]
3651 ]
3652 + templateopts,
3652 + templateopts,
3653 _(b'[-ct] [-r STARTREV] [REV]...'),
3653 _(b'[-ct] [-r STARTREV] [REV]...'),
3654 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3654 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3655 intents={INTENT_READONLY},
3655 intents={INTENT_READONLY},
3656 )
3656 )
3657 def heads(ui, repo, *branchrevs, **opts):
3657 def heads(ui, repo, *branchrevs, **opts):
3658 """show branch heads
3658 """show branch heads
3659
3659
3660 With no arguments, show all open branch heads in the repository.
3660 With no arguments, show all open branch heads in the repository.
3661 Branch heads are changesets that have no descendants on the
3661 Branch heads are changesets that have no descendants on the
3662 same branch. They are where development generally takes place and
3662 same branch. They are where development generally takes place and
3663 are the usual targets for update and merge operations.
3663 are the usual targets for update and merge operations.
3664
3664
3665 If one or more REVs are given, only open branch heads on the
3665 If one or more REVs are given, only open branch heads on the
3666 branches associated with the specified changesets are shown. This
3666 branches associated with the specified changesets are shown. This
3667 means that you can use :hg:`heads .` to see the heads on the
3667 means that you can use :hg:`heads .` to see the heads on the
3668 currently checked-out branch.
3668 currently checked-out branch.
3669
3669
3670 If -c/--closed is specified, also show branch heads marked closed
3670 If -c/--closed is specified, also show branch heads marked closed
3671 (see :hg:`commit --close-branch`).
3671 (see :hg:`commit --close-branch`).
3672
3672
3673 If STARTREV is specified, only those heads that are descendants of
3673 If STARTREV is specified, only those heads that are descendants of
3674 STARTREV will be displayed.
3674 STARTREV will be displayed.
3675
3675
3676 If -t/--topo is specified, named branch mechanics will be ignored and only
3676 If -t/--topo is specified, named branch mechanics will be ignored and only
3677 topological heads (changesets with no children) will be shown.
3677 topological heads (changesets with no children) will be shown.
3678
3678
3679 Returns 0 if matching heads are found, 1 if not.
3679 Returns 0 if matching heads are found, 1 if not.
3680 """
3680 """
3681
3681
3682 opts = pycompat.byteskwargs(opts)
3682 opts = pycompat.byteskwargs(opts)
3683 start = None
3683 start = None
3684 rev = opts.get(b'rev')
3684 rev = opts.get(b'rev')
3685 if rev:
3685 if rev:
3686 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3686 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3687 start = scmutil.revsingle(repo, rev, None).node()
3687 start = scmutil.revsingle(repo, rev, None).node()
3688
3688
3689 if opts.get(b'topo'):
3689 if opts.get(b'topo'):
3690 heads = [repo[h] for h in repo.heads(start)]
3690 heads = [repo[h] for h in repo.heads(start)]
3691 else:
3691 else:
3692 heads = []
3692 heads = []
3693 for branch in repo.branchmap():
3693 for branch in repo.branchmap():
3694 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3694 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3695 heads = [repo[h] for h in heads]
3695 heads = [repo[h] for h in heads]
3696
3696
3697 if branchrevs:
3697 if branchrevs:
3698 branches = {
3698 branches = {
3699 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3699 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3700 }
3700 }
3701 heads = [h for h in heads if h.branch() in branches]
3701 heads = [h for h in heads if h.branch() in branches]
3702
3702
3703 if opts.get(b'active') and branchrevs:
3703 if opts.get(b'active') and branchrevs:
3704 dagheads = repo.heads(start)
3704 dagheads = repo.heads(start)
3705 heads = [h for h in heads if h.node() in dagheads]
3705 heads = [h for h in heads if h.node() in dagheads]
3706
3706
3707 if branchrevs:
3707 if branchrevs:
3708 haveheads = {h.branch() for h in heads}
3708 haveheads = {h.branch() for h in heads}
3709 if branches - haveheads:
3709 if branches - haveheads:
3710 headless = b', '.join(b for b in branches - haveheads)
3710 headless = b', '.join(b for b in branches - haveheads)
3711 msg = _(b'no open branch heads found on branches %s')
3711 msg = _(b'no open branch heads found on branches %s')
3712 if opts.get(b'rev'):
3712 if opts.get(b'rev'):
3713 msg += _(b' (started at %s)') % opts[b'rev']
3713 msg += _(b' (started at %s)') % opts[b'rev']
3714 ui.warn((msg + b'\n') % headless)
3714 ui.warn((msg + b'\n') % headless)
3715
3715
3716 if not heads:
3716 if not heads:
3717 return 1
3717 return 1
3718
3718
3719 ui.pager(b'heads')
3719 ui.pager(b'heads')
3720 heads = sorted(heads, key=lambda x: -(x.rev()))
3720 heads = sorted(heads, key=lambda x: -(x.rev()))
3721 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3721 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3722 for ctx in heads:
3722 for ctx in heads:
3723 displayer.show(ctx)
3723 displayer.show(ctx)
3724 displayer.close()
3724 displayer.close()
3725
3725
3726
3726
3727 @command(
3727 @command(
3728 b'help',
3728 b'help',
3729 [
3729 [
3730 (b'e', b'extension', None, _(b'show only help for extensions')),
3730 (b'e', b'extension', None, _(b'show only help for extensions')),
3731 (b'c', b'command', None, _(b'show only help for commands')),
3731 (b'c', b'command', None, _(b'show only help for commands')),
3732 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3732 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3733 (
3733 (
3734 b's',
3734 b's',
3735 b'system',
3735 b'system',
3736 [],
3736 [],
3737 _(b'show help for specific platform(s)'),
3737 _(b'show help for specific platform(s)'),
3738 _(b'PLATFORM'),
3738 _(b'PLATFORM'),
3739 ),
3739 ),
3740 ],
3740 ],
3741 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3741 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3742 helpcategory=command.CATEGORY_HELP,
3742 helpcategory=command.CATEGORY_HELP,
3743 norepo=True,
3743 norepo=True,
3744 intents={INTENT_READONLY},
3744 intents={INTENT_READONLY},
3745 )
3745 )
3746 def help_(ui, name=None, **opts):
3746 def help_(ui, name=None, **opts):
3747 """show help for a given topic or a help overview
3747 """show help for a given topic or a help overview
3748
3748
3749 With no arguments, print a list of commands with short help messages.
3749 With no arguments, print a list of commands with short help messages.
3750
3750
3751 Given a topic, extension, or command name, print help for that
3751 Given a topic, extension, or command name, print help for that
3752 topic.
3752 topic.
3753
3753
3754 Returns 0 if successful.
3754 Returns 0 if successful.
3755 """
3755 """
3756
3756
3757 keep = opts.get('system') or []
3757 keep = opts.get('system') or []
3758 if len(keep) == 0:
3758 if len(keep) == 0:
3759 if pycompat.sysplatform.startswith(b'win'):
3759 if pycompat.sysplatform.startswith(b'win'):
3760 keep.append(b'windows')
3760 keep.append(b'windows')
3761 elif pycompat.sysplatform == b'OpenVMS':
3761 elif pycompat.sysplatform == b'OpenVMS':
3762 keep.append(b'vms')
3762 keep.append(b'vms')
3763 elif pycompat.sysplatform == b'plan9':
3763 elif pycompat.sysplatform == b'plan9':
3764 keep.append(b'plan9')
3764 keep.append(b'plan9')
3765 else:
3765 else:
3766 keep.append(b'unix')
3766 keep.append(b'unix')
3767 keep.append(pycompat.sysplatform.lower())
3767 keep.append(pycompat.sysplatform.lower())
3768 if ui.verbose:
3768 if ui.verbose:
3769 keep.append(b'verbose')
3769 keep.append(b'verbose')
3770
3770
3771 commands = sys.modules[__name__]
3771 commands = sys.modules[__name__]
3772 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3772 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3773 ui.pager(b'help')
3773 ui.pager(b'help')
3774 ui.write(formatted)
3774 ui.write(formatted)
3775
3775
3776
3776
3777 @command(
3777 @command(
3778 b'identify|id',
3778 b'identify|id',
3779 [
3779 [
3780 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3780 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3781 (b'n', b'num', None, _(b'show local revision number')),
3781 (b'n', b'num', None, _(b'show local revision number')),
3782 (b'i', b'id', None, _(b'show global revision id')),
3782 (b'i', b'id', None, _(b'show global revision id')),
3783 (b'b', b'branch', None, _(b'show branch')),
3783 (b'b', b'branch', None, _(b'show branch')),
3784 (b't', b'tags', None, _(b'show tags')),
3784 (b't', b'tags', None, _(b'show tags')),
3785 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3785 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3786 ]
3786 ]
3787 + remoteopts
3787 + remoteopts
3788 + formatteropts,
3788 + formatteropts,
3789 _(b'[-nibtB] [-r REV] [SOURCE]'),
3789 _(b'[-nibtB] [-r REV] [SOURCE]'),
3790 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3790 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3791 optionalrepo=True,
3791 optionalrepo=True,
3792 intents={INTENT_READONLY},
3792 intents={INTENT_READONLY},
3793 )
3793 )
3794 def identify(
3794 def identify(
3795 ui,
3795 ui,
3796 repo,
3796 repo,
3797 source=None,
3797 source=None,
3798 rev=None,
3798 rev=None,
3799 num=None,
3799 num=None,
3800 id=None,
3800 id=None,
3801 branch=None,
3801 branch=None,
3802 tags=None,
3802 tags=None,
3803 bookmarks=None,
3803 bookmarks=None,
3804 **opts
3804 **opts
3805 ):
3805 ):
3806 """identify the working directory or specified revision
3806 """identify the working directory or specified revision
3807
3807
3808 Print a summary identifying the repository state at REV using one or
3808 Print a summary identifying the repository state at REV using one or
3809 two parent hash identifiers, followed by a "+" if the working
3809 two parent hash identifiers, followed by a "+" if the working
3810 directory has uncommitted changes, the branch name (if not default),
3810 directory has uncommitted changes, the branch name (if not default),
3811 a list of tags, and a list of bookmarks.
3811 a list of tags, and a list of bookmarks.
3812
3812
3813 When REV is not given, print a summary of the current state of the
3813 When REV is not given, print a summary of the current state of the
3814 repository including the working directory. Specify -r. to get information
3814 repository including the working directory. Specify -r. to get information
3815 of the working directory parent without scanning uncommitted changes.
3815 of the working directory parent without scanning uncommitted changes.
3816
3816
3817 Specifying a path to a repository root or Mercurial bundle will
3817 Specifying a path to a repository root or Mercurial bundle will
3818 cause lookup to operate on that repository/bundle.
3818 cause lookup to operate on that repository/bundle.
3819
3819
3820 .. container:: verbose
3820 .. container:: verbose
3821
3821
3822 Template:
3822 Template:
3823
3823
3824 The following keywords are supported in addition to the common template
3824 The following keywords are supported in addition to the common template
3825 keywords and functions. See also :hg:`help templates`.
3825 keywords and functions. See also :hg:`help templates`.
3826
3826
3827 :dirty: String. Character ``+`` denoting if the working directory has
3827 :dirty: String. Character ``+`` denoting if the working directory has
3828 uncommitted changes.
3828 uncommitted changes.
3829 :id: String. One or two nodes, optionally followed by ``+``.
3829 :id: String. One or two nodes, optionally followed by ``+``.
3830 :parents: List of strings. Parent nodes of the changeset.
3830 :parents: List of strings. Parent nodes of the changeset.
3831
3831
3832 Examples:
3832 Examples:
3833
3833
3834 - generate a build identifier for the working directory::
3834 - generate a build identifier for the working directory::
3835
3835
3836 hg id --id > build-id.dat
3836 hg id --id > build-id.dat
3837
3837
3838 - find the revision corresponding to a tag::
3838 - find the revision corresponding to a tag::
3839
3839
3840 hg id -n -r 1.3
3840 hg id -n -r 1.3
3841
3841
3842 - check the most recent revision of a remote repository::
3842 - check the most recent revision of a remote repository::
3843
3843
3844 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3844 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3845
3845
3846 See :hg:`log` for generating more information about specific revisions,
3846 See :hg:`log` for generating more information about specific revisions,
3847 including full hash identifiers.
3847 including full hash identifiers.
3848
3848
3849 Returns 0 if successful.
3849 Returns 0 if successful.
3850 """
3850 """
3851
3851
3852 opts = pycompat.byteskwargs(opts)
3852 opts = pycompat.byteskwargs(opts)
3853 if not repo and not source:
3853 if not repo and not source:
3854 raise error.InputError(
3854 raise error.InputError(
3855 _(b"there is no Mercurial repository here (.hg not found)")
3855 _(b"there is no Mercurial repository here (.hg not found)")
3856 )
3856 )
3857
3857
3858 default = not (num or id or branch or tags or bookmarks)
3858 default = not (num or id or branch or tags or bookmarks)
3859 output = []
3859 output = []
3860 revs = []
3860 revs = []
3861
3861
3862 peer = None
3862 peer = None
3863 try:
3863 try:
3864 if source:
3864 if source:
3865 source, branches = urlutil.get_unique_pull_path(
3865 source, branches = urlutil.get_unique_pull_path(
3866 b'identify', repo, ui, source
3866 b'identify', repo, ui, source
3867 )
3867 )
3868 # only pass ui when no repo
3868 # only pass ui when no repo
3869 peer = hg.peer(repo or ui, opts, source)
3869 peer = hg.peer(repo or ui, opts, source)
3870 repo = peer.local()
3870 repo = peer.local()
3871 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3871 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3872
3872
3873 fm = ui.formatter(b'identify', opts)
3873 fm = ui.formatter(b'identify', opts)
3874 fm.startitem()
3874 fm.startitem()
3875
3875
3876 if not repo:
3876 if not repo:
3877 if num or branch or tags:
3877 if num or branch or tags:
3878 raise error.InputError(
3878 raise error.InputError(
3879 _(b"can't query remote revision number, branch, or tags")
3879 _(b"can't query remote revision number, branch, or tags")
3880 )
3880 )
3881 if not rev and revs:
3881 if not rev and revs:
3882 rev = revs[0]
3882 rev = revs[0]
3883 if not rev:
3883 if not rev:
3884 rev = b"tip"
3884 rev = b"tip"
3885
3885
3886 remoterev = peer.lookup(rev)
3886 remoterev = peer.lookup(rev)
3887 hexrev = fm.hexfunc(remoterev)
3887 hexrev = fm.hexfunc(remoterev)
3888 if default or id:
3888 if default or id:
3889 output = [hexrev]
3889 output = [hexrev]
3890 fm.data(id=hexrev)
3890 fm.data(id=hexrev)
3891
3891
3892 @util.cachefunc
3892 @util.cachefunc
3893 def getbms():
3893 def getbms():
3894 bms = []
3894 bms = []
3895
3895
3896 if b'bookmarks' in peer.listkeys(b'namespaces'):
3896 if b'bookmarks' in peer.listkeys(b'namespaces'):
3897 hexremoterev = hex(remoterev)
3897 hexremoterev = hex(remoterev)
3898 bms = [
3898 bms = [
3899 bm
3899 bm
3900 for bm, bmr in pycompat.iteritems(
3900 for bm, bmr in pycompat.iteritems(
3901 peer.listkeys(b'bookmarks')
3901 peer.listkeys(b'bookmarks')
3902 )
3902 )
3903 if bmr == hexremoterev
3903 if bmr == hexremoterev
3904 ]
3904 ]
3905
3905
3906 return sorted(bms)
3906 return sorted(bms)
3907
3907
3908 if fm.isplain():
3908 if fm.isplain():
3909 if bookmarks:
3909 if bookmarks:
3910 output.extend(getbms())
3910 output.extend(getbms())
3911 elif default and not ui.quiet:
3911 elif default and not ui.quiet:
3912 # multiple bookmarks for a single parent separated by '/'
3912 # multiple bookmarks for a single parent separated by '/'
3913 bm = b'/'.join(getbms())
3913 bm = b'/'.join(getbms())
3914 if bm:
3914 if bm:
3915 output.append(bm)
3915 output.append(bm)
3916 else:
3916 else:
3917 fm.data(node=hex(remoterev))
3917 fm.data(node=hex(remoterev))
3918 if bookmarks or b'bookmarks' in fm.datahint():
3918 if bookmarks or b'bookmarks' in fm.datahint():
3919 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3919 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3920 else:
3920 else:
3921 if rev:
3921 if rev:
3922 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3922 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3923 ctx = scmutil.revsingle(repo, rev, None)
3923 ctx = scmutil.revsingle(repo, rev, None)
3924
3924
3925 if ctx.rev() is None:
3925 if ctx.rev() is None:
3926 ctx = repo[None]
3926 ctx = repo[None]
3927 parents = ctx.parents()
3927 parents = ctx.parents()
3928 taglist = []
3928 taglist = []
3929 for p in parents:
3929 for p in parents:
3930 taglist.extend(p.tags())
3930 taglist.extend(p.tags())
3931
3931
3932 dirty = b""
3932 dirty = b""
3933 if ctx.dirty(missing=True, merge=False, branch=False):
3933 if ctx.dirty(missing=True, merge=False, branch=False):
3934 dirty = b'+'
3934 dirty = b'+'
3935 fm.data(dirty=dirty)
3935 fm.data(dirty=dirty)
3936
3936
3937 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3937 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3938 if default or id:
3938 if default or id:
3939 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3939 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3940 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3940 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3941
3941
3942 if num:
3942 if num:
3943 numoutput = [b"%d" % p.rev() for p in parents]
3943 numoutput = [b"%d" % p.rev() for p in parents]
3944 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3944 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3945
3945
3946 fm.data(
3946 fm.data(
3947 parents=fm.formatlist(
3947 parents=fm.formatlist(
3948 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3948 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3949 )
3949 )
3950 )
3950 )
3951 else:
3951 else:
3952 hexoutput = fm.hexfunc(ctx.node())
3952 hexoutput = fm.hexfunc(ctx.node())
3953 if default or id:
3953 if default or id:
3954 output = [hexoutput]
3954 output = [hexoutput]
3955 fm.data(id=hexoutput)
3955 fm.data(id=hexoutput)
3956
3956
3957 if num:
3957 if num:
3958 output.append(pycompat.bytestr(ctx.rev()))
3958 output.append(pycompat.bytestr(ctx.rev()))
3959 taglist = ctx.tags()
3959 taglist = ctx.tags()
3960
3960
3961 if default and not ui.quiet:
3961 if default and not ui.quiet:
3962 b = ctx.branch()
3962 b = ctx.branch()
3963 if b != b'default':
3963 if b != b'default':
3964 output.append(b"(%s)" % b)
3964 output.append(b"(%s)" % b)
3965
3965
3966 # multiple tags for a single parent separated by '/'
3966 # multiple tags for a single parent separated by '/'
3967 t = b'/'.join(taglist)
3967 t = b'/'.join(taglist)
3968 if t:
3968 if t:
3969 output.append(t)
3969 output.append(t)
3970
3970
3971 # multiple bookmarks for a single parent separated by '/'
3971 # multiple bookmarks for a single parent separated by '/'
3972 bm = b'/'.join(ctx.bookmarks())
3972 bm = b'/'.join(ctx.bookmarks())
3973 if bm:
3973 if bm:
3974 output.append(bm)
3974 output.append(bm)
3975 else:
3975 else:
3976 if branch:
3976 if branch:
3977 output.append(ctx.branch())
3977 output.append(ctx.branch())
3978
3978
3979 if tags:
3979 if tags:
3980 output.extend(taglist)
3980 output.extend(taglist)
3981
3981
3982 if bookmarks:
3982 if bookmarks:
3983 output.extend(ctx.bookmarks())
3983 output.extend(ctx.bookmarks())
3984
3984
3985 fm.data(node=ctx.hex())
3985 fm.data(node=ctx.hex())
3986 fm.data(branch=ctx.branch())
3986 fm.data(branch=ctx.branch())
3987 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3987 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3988 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3988 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3989 fm.context(ctx=ctx)
3989 fm.context(ctx=ctx)
3990
3990
3991 fm.plain(b"%s\n" % b' '.join(output))
3991 fm.plain(b"%s\n" % b' '.join(output))
3992 fm.end()
3992 fm.end()
3993 finally:
3993 finally:
3994 if peer:
3994 if peer:
3995 peer.close()
3995 peer.close()
3996
3996
3997
3997
3998 @command(
3998 @command(
3999 b'import|patch',
3999 b'import|patch',
4000 [
4000 [
4001 (
4001 (
4002 b'p',
4002 b'p',
4003 b'strip',
4003 b'strip',
4004 1,
4004 1,
4005 _(
4005 _(
4006 b'directory strip option for patch. This has the same '
4006 b'directory strip option for patch. This has the same '
4007 b'meaning as the corresponding patch option'
4007 b'meaning as the corresponding patch option'
4008 ),
4008 ),
4009 _(b'NUM'),
4009 _(b'NUM'),
4010 ),
4010 ),
4011 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4011 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4012 (b'', b'secret', None, _(b'use the secret phase for committing')),
4012 (b'', b'secret', None, _(b'use the secret phase for committing')),
4013 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4013 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4014 (
4014 (
4015 b'f',
4015 b'f',
4016 b'force',
4016 b'force',
4017 None,
4017 None,
4018 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4018 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4019 ),
4019 ),
4020 (
4020 (
4021 b'',
4021 b'',
4022 b'no-commit',
4022 b'no-commit',
4023 None,
4023 None,
4024 _(b"don't commit, just update the working directory"),
4024 _(b"don't commit, just update the working directory"),
4025 ),
4025 ),
4026 (
4026 (
4027 b'',
4027 b'',
4028 b'bypass',
4028 b'bypass',
4029 None,
4029 None,
4030 _(b"apply patch without touching the working directory"),
4030 _(b"apply patch without touching the working directory"),
4031 ),
4031 ),
4032 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4032 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4033 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4033 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4034 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4034 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4035 (
4035 (
4036 b'',
4036 b'',
4037 b'import-branch',
4037 b'import-branch',
4038 None,
4038 None,
4039 _(b'use any branch information in patch (implied by --exact)'),
4039 _(b'use any branch information in patch (implied by --exact)'),
4040 ),
4040 ),
4041 ]
4041 ]
4042 + commitopts
4042 + commitopts
4043 + commitopts2
4043 + commitopts2
4044 + similarityopts,
4044 + similarityopts,
4045 _(b'[OPTION]... PATCH...'),
4045 _(b'[OPTION]... PATCH...'),
4046 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4046 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4047 )
4047 )
4048 def import_(ui, repo, patch1=None, *patches, **opts):
4048 def import_(ui, repo, patch1=None, *patches, **opts):
4049 """import an ordered set of patches
4049 """import an ordered set of patches
4050
4050
4051 Import a list of patches and commit them individually (unless
4051 Import a list of patches and commit them individually (unless
4052 --no-commit is specified).
4052 --no-commit is specified).
4053
4053
4054 To read a patch from standard input (stdin), use "-" as the patch
4054 To read a patch from standard input (stdin), use "-" as the patch
4055 name. If a URL is specified, the patch will be downloaded from
4055 name. If a URL is specified, the patch will be downloaded from
4056 there.
4056 there.
4057
4057
4058 Import first applies changes to the working directory (unless
4058 Import first applies changes to the working directory (unless
4059 --bypass is specified), import will abort if there are outstanding
4059 --bypass is specified), import will abort if there are outstanding
4060 changes.
4060 changes.
4061
4061
4062 Use --bypass to apply and commit patches directly to the
4062 Use --bypass to apply and commit patches directly to the
4063 repository, without affecting the working directory. Without
4063 repository, without affecting the working directory. Without
4064 --exact, patches will be applied on top of the working directory
4064 --exact, patches will be applied on top of the working directory
4065 parent revision.
4065 parent revision.
4066
4066
4067 You can import a patch straight from a mail message. Even patches
4067 You can import a patch straight from a mail message. Even patches
4068 as attachments work (to use the body part, it must have type
4068 as attachments work (to use the body part, it must have type
4069 text/plain or text/x-patch). From and Subject headers of email
4069 text/plain or text/x-patch). From and Subject headers of email
4070 message are used as default committer and commit message. All
4070 message are used as default committer and commit message. All
4071 text/plain body parts before first diff are added to the commit
4071 text/plain body parts before first diff are added to the commit
4072 message.
4072 message.
4073
4073
4074 If the imported patch was generated by :hg:`export`, user and
4074 If the imported patch was generated by :hg:`export`, user and
4075 description from patch override values from message headers and
4075 description from patch override values from message headers and
4076 body. Values given on command line with -m/--message and -u/--user
4076 body. Values given on command line with -m/--message and -u/--user
4077 override these.
4077 override these.
4078
4078
4079 If --exact is specified, import will set the working directory to
4079 If --exact is specified, import will set the working directory to
4080 the parent of each patch before applying it, and will abort if the
4080 the parent of each patch before applying it, and will abort if the
4081 resulting changeset has a different ID than the one recorded in
4081 resulting changeset has a different ID than the one recorded in
4082 the patch. This will guard against various ways that portable
4082 the patch. This will guard against various ways that portable
4083 patch formats and mail systems might fail to transfer Mercurial
4083 patch formats and mail systems might fail to transfer Mercurial
4084 data or metadata. See :hg:`bundle` for lossless transmission.
4084 data or metadata. See :hg:`bundle` for lossless transmission.
4085
4085
4086 Use --partial to ensure a changeset will be created from the patch
4086 Use --partial to ensure a changeset will be created from the patch
4087 even if some hunks fail to apply. Hunks that fail to apply will be
4087 even if some hunks fail to apply. Hunks that fail to apply will be
4088 written to a <target-file>.rej file. Conflicts can then be resolved
4088 written to a <target-file>.rej file. Conflicts can then be resolved
4089 by hand before :hg:`commit --amend` is run to update the created
4089 by hand before :hg:`commit --amend` is run to update the created
4090 changeset. This flag exists to let people import patches that
4090 changeset. This flag exists to let people import patches that
4091 partially apply without losing the associated metadata (author,
4091 partially apply without losing the associated metadata (author,
4092 date, description, ...).
4092 date, description, ...).
4093
4093
4094 .. note::
4094 .. note::
4095
4095
4096 When no hunks apply cleanly, :hg:`import --partial` will create
4096 When no hunks apply cleanly, :hg:`import --partial` will create
4097 an empty changeset, importing only the patch metadata.
4097 an empty changeset, importing only the patch metadata.
4098
4098
4099 With -s/--similarity, hg will attempt to discover renames and
4099 With -s/--similarity, hg will attempt to discover renames and
4100 copies in the patch in the same way as :hg:`addremove`.
4100 copies in the patch in the same way as :hg:`addremove`.
4101
4101
4102 It is possible to use external patch programs to perform the patch
4102 It is possible to use external patch programs to perform the patch
4103 by setting the ``ui.patch`` configuration option. For the default
4103 by setting the ``ui.patch`` configuration option. For the default
4104 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4104 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4105 See :hg:`help config` for more information about configuration
4105 See :hg:`help config` for more information about configuration
4106 files and how to use these options.
4106 files and how to use these options.
4107
4107
4108 See :hg:`help dates` for a list of formats valid for -d/--date.
4108 See :hg:`help dates` for a list of formats valid for -d/--date.
4109
4109
4110 .. container:: verbose
4110 .. container:: verbose
4111
4111
4112 Examples:
4112 Examples:
4113
4113
4114 - import a traditional patch from a website and detect renames::
4114 - import a traditional patch from a website and detect renames::
4115
4115
4116 hg import -s 80 http://example.com/bugfix.patch
4116 hg import -s 80 http://example.com/bugfix.patch
4117
4117
4118 - import a changeset from an hgweb server::
4118 - import a changeset from an hgweb server::
4119
4119
4120 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4120 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4121
4121
4122 - import all the patches in an Unix-style mbox::
4122 - import all the patches in an Unix-style mbox::
4123
4123
4124 hg import incoming-patches.mbox
4124 hg import incoming-patches.mbox
4125
4125
4126 - import patches from stdin::
4126 - import patches from stdin::
4127
4127
4128 hg import -
4128 hg import -
4129
4129
4130 - attempt to exactly restore an exported changeset (not always
4130 - attempt to exactly restore an exported changeset (not always
4131 possible)::
4131 possible)::
4132
4132
4133 hg import --exact proposed-fix.patch
4133 hg import --exact proposed-fix.patch
4134
4134
4135 - use an external tool to apply a patch which is too fuzzy for
4135 - use an external tool to apply a patch which is too fuzzy for
4136 the default internal tool.
4136 the default internal tool.
4137
4137
4138 hg import --config ui.patch="patch --merge" fuzzy.patch
4138 hg import --config ui.patch="patch --merge" fuzzy.patch
4139
4139
4140 - change the default fuzzing from 2 to a less strict 7
4140 - change the default fuzzing from 2 to a less strict 7
4141
4141
4142 hg import --config ui.fuzz=7 fuzz.patch
4142 hg import --config ui.fuzz=7 fuzz.patch
4143
4143
4144 Returns 0 on success, 1 on partial success (see --partial).
4144 Returns 0 on success, 1 on partial success (see --partial).
4145 """
4145 """
4146
4146
4147 cmdutil.check_incompatible_arguments(
4147 cmdutil.check_incompatible_arguments(
4148 opts, 'no_commit', ['bypass', 'secret']
4148 opts, 'no_commit', ['bypass', 'secret']
4149 )
4149 )
4150 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4150 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4151 opts = pycompat.byteskwargs(opts)
4151 opts = pycompat.byteskwargs(opts)
4152 if not patch1:
4152 if not patch1:
4153 raise error.InputError(_(b'need at least one patch to import'))
4153 raise error.InputError(_(b'need at least one patch to import'))
4154
4154
4155 patches = (patch1,) + patches
4155 patches = (patch1,) + patches
4156
4156
4157 date = opts.get(b'date')
4157 date = opts.get(b'date')
4158 if date:
4158 if date:
4159 opts[b'date'] = dateutil.parsedate(date)
4159 opts[b'date'] = dateutil.parsedate(date)
4160
4160
4161 exact = opts.get(b'exact')
4161 exact = opts.get(b'exact')
4162 update = not opts.get(b'bypass')
4162 update = not opts.get(b'bypass')
4163 try:
4163 try:
4164 sim = float(opts.get(b'similarity') or 0)
4164 sim = float(opts.get(b'similarity') or 0)
4165 except ValueError:
4165 except ValueError:
4166 raise error.InputError(_(b'similarity must be a number'))
4166 raise error.InputError(_(b'similarity must be a number'))
4167 if sim < 0 or sim > 100:
4167 if sim < 0 or sim > 100:
4168 raise error.InputError(_(b'similarity must be between 0 and 100'))
4168 raise error.InputError(_(b'similarity must be between 0 and 100'))
4169 if sim and not update:
4169 if sim and not update:
4170 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4170 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4171
4171
4172 base = opts[b"base"]
4172 base = opts[b"base"]
4173 msgs = []
4173 msgs = []
4174 ret = 0
4174 ret = 0
4175
4175
4176 with repo.wlock():
4176 with repo.wlock():
4177 if update:
4177 if update:
4178 cmdutil.checkunfinished(repo)
4178 cmdutil.checkunfinished(repo)
4179 if exact or not opts.get(b'force'):
4179 if exact or not opts.get(b'force'):
4180 cmdutil.bailifchanged(repo)
4180 cmdutil.bailifchanged(repo)
4181
4181
4182 if not opts.get(b'no_commit'):
4182 if not opts.get(b'no_commit'):
4183 lock = repo.lock
4183 lock = repo.lock
4184 tr = lambda: repo.transaction(b'import')
4184 tr = lambda: repo.transaction(b'import')
4185 dsguard = util.nullcontextmanager
4185 dsguard = util.nullcontextmanager
4186 else:
4186 else:
4187 lock = util.nullcontextmanager
4187 lock = util.nullcontextmanager
4188 tr = util.nullcontextmanager
4188 tr = util.nullcontextmanager
4189 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4189 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4190 with lock(), tr(), dsguard():
4190 with lock(), tr(), dsguard():
4191 parents = repo[None].parents()
4191 parents = repo[None].parents()
4192 for patchurl in patches:
4192 for patchurl in patches:
4193 if patchurl == b'-':
4193 if patchurl == b'-':
4194 ui.status(_(b'applying patch from stdin\n'))
4194 ui.status(_(b'applying patch from stdin\n'))
4195 patchfile = ui.fin
4195 patchfile = ui.fin
4196 patchurl = b'stdin' # for error message
4196 patchurl = b'stdin' # for error message
4197 else:
4197 else:
4198 patchurl = os.path.join(base, patchurl)
4198 patchurl = os.path.join(base, patchurl)
4199 ui.status(_(b'applying %s\n') % patchurl)
4199 ui.status(_(b'applying %s\n') % patchurl)
4200 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4200 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4201
4201
4202 haspatch = False
4202 haspatch = False
4203 for hunk in patch.split(patchfile):
4203 for hunk in patch.split(patchfile):
4204 with patch.extract(ui, hunk) as patchdata:
4204 with patch.extract(ui, hunk) as patchdata:
4205 msg, node, rej = cmdutil.tryimportone(
4205 msg, node, rej = cmdutil.tryimportone(
4206 ui, repo, patchdata, parents, opts, msgs, hg.clean
4206 ui, repo, patchdata, parents, opts, msgs, hg.clean
4207 )
4207 )
4208 if msg:
4208 if msg:
4209 haspatch = True
4209 haspatch = True
4210 ui.note(msg + b'\n')
4210 ui.note(msg + b'\n')
4211 if update or exact:
4211 if update or exact:
4212 parents = repo[None].parents()
4212 parents = repo[None].parents()
4213 else:
4213 else:
4214 parents = [repo[node]]
4214 parents = [repo[node]]
4215 if rej:
4215 if rej:
4216 ui.write_err(_(b"patch applied partially\n"))
4216 ui.write_err(_(b"patch applied partially\n"))
4217 ui.write_err(
4217 ui.write_err(
4218 _(
4218 _(
4219 b"(fix the .rej files and run "
4219 b"(fix the .rej files and run "
4220 b"`hg commit --amend`)\n"
4220 b"`hg commit --amend`)\n"
4221 )
4221 )
4222 )
4222 )
4223 ret = 1
4223 ret = 1
4224 break
4224 break
4225
4225
4226 if not haspatch:
4226 if not haspatch:
4227 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4227 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4228
4228
4229 if msgs:
4229 if msgs:
4230 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4230 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4231 return ret
4231 return ret
4232
4232
4233
4233
4234 @command(
4234 @command(
4235 b'incoming|in',
4235 b'incoming|in',
4236 [
4236 [
4237 (
4237 (
4238 b'f',
4238 b'f',
4239 b'force',
4239 b'force',
4240 None,
4240 None,
4241 _(b'run even if remote repository is unrelated'),
4241 _(b'run even if remote repository is unrelated'),
4242 ),
4242 ),
4243 (b'n', b'newest-first', None, _(b'show newest record first')),
4243 (b'n', b'newest-first', None, _(b'show newest record first')),
4244 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4244 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4245 (
4245 (
4246 b'r',
4246 b'r',
4247 b'rev',
4247 b'rev',
4248 [],
4248 [],
4249 _(b'a remote changeset intended to be added'),
4249 _(b'a remote changeset intended to be added'),
4250 _(b'REV'),
4250 _(b'REV'),
4251 ),
4251 ),
4252 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4252 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4253 (
4253 (
4254 b'b',
4254 b'b',
4255 b'branch',
4255 b'branch',
4256 [],
4256 [],
4257 _(b'a specific branch you would like to pull'),
4257 _(b'a specific branch you would like to pull'),
4258 _(b'BRANCH'),
4258 _(b'BRANCH'),
4259 ),
4259 ),
4260 ]
4260 ]
4261 + logopts
4261 + logopts
4262 + remoteopts
4262 + remoteopts
4263 + subrepoopts,
4263 + subrepoopts,
4264 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4264 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4265 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4265 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4266 )
4266 )
4267 def incoming(ui, repo, source=b"default", **opts):
4267 def incoming(ui, repo, source=b"default", **opts):
4268 """show new changesets found in source
4268 """show new changesets found in source
4269
4269
4270 Show new changesets found in the specified path/URL or the default
4270 Show new changesets found in the specified path/URL or the default
4271 pull location. These are the changesets that would have been pulled
4271 pull location. These are the changesets that would have been pulled
4272 by :hg:`pull` at the time you issued this command.
4272 by :hg:`pull` at the time you issued this command.
4273
4273
4274 See pull for valid source format details.
4274 See pull for valid source format details.
4275
4275
4276 .. container:: verbose
4276 .. container:: verbose
4277
4277
4278 With -B/--bookmarks, the result of bookmark comparison between
4278 With -B/--bookmarks, the result of bookmark comparison between
4279 local and remote repositories is displayed. With -v/--verbose,
4279 local and remote repositories is displayed. With -v/--verbose,
4280 status is also displayed for each bookmark like below::
4280 status is also displayed for each bookmark like below::
4281
4281
4282 BM1 01234567890a added
4282 BM1 01234567890a added
4283 BM2 1234567890ab advanced
4283 BM2 1234567890ab advanced
4284 BM3 234567890abc diverged
4284 BM3 234567890abc diverged
4285 BM4 34567890abcd changed
4285 BM4 34567890abcd changed
4286
4286
4287 The action taken locally when pulling depends on the
4287 The action taken locally when pulling depends on the
4288 status of each bookmark:
4288 status of each bookmark:
4289
4289
4290 :``added``: pull will create it
4290 :``added``: pull will create it
4291 :``advanced``: pull will update it
4291 :``advanced``: pull will update it
4292 :``diverged``: pull will create a divergent bookmark
4292 :``diverged``: pull will create a divergent bookmark
4293 :``changed``: result depends on remote changesets
4293 :``changed``: result depends on remote changesets
4294
4294
4295 From the point of view of pulling behavior, bookmark
4295 From the point of view of pulling behavior, bookmark
4296 existing only in the remote repository are treated as ``added``,
4296 existing only in the remote repository are treated as ``added``,
4297 even if it is in fact locally deleted.
4297 even if it is in fact locally deleted.
4298
4298
4299 .. container:: verbose
4299 .. container:: verbose
4300
4300
4301 For remote repository, using --bundle avoids downloading the
4301 For remote repository, using --bundle avoids downloading the
4302 changesets twice if the incoming is followed by a pull.
4302 changesets twice if the incoming is followed by a pull.
4303
4303
4304 Examples:
4304 Examples:
4305
4305
4306 - show incoming changes with patches and full description::
4306 - show incoming changes with patches and full description::
4307
4307
4308 hg incoming -vp
4308 hg incoming -vp
4309
4309
4310 - show incoming changes excluding merges, store a bundle::
4310 - show incoming changes excluding merges, store a bundle::
4311
4311
4312 hg in -vpM --bundle incoming.hg
4312 hg in -vpM --bundle incoming.hg
4313 hg pull incoming.hg
4313 hg pull incoming.hg
4314
4314
4315 - briefly list changes inside a bundle::
4315 - briefly list changes inside a bundle::
4316
4316
4317 hg in changes.hg -T "{desc|firstline}\\n"
4317 hg in changes.hg -T "{desc|firstline}\\n"
4318
4318
4319 Returns 0 if there are incoming changes, 1 otherwise.
4319 Returns 0 if there are incoming changes, 1 otherwise.
4320 """
4320 """
4321 opts = pycompat.byteskwargs(opts)
4321 opts = pycompat.byteskwargs(opts)
4322 if opts.get(b'graph'):
4322 if opts.get(b'graph'):
4323 logcmdutil.checkunsupportedgraphflags([], opts)
4323 logcmdutil.checkunsupportedgraphflags([], opts)
4324
4324
4325 def display(other, chlist, displayer):
4325 def display(other, chlist, displayer):
4326 revdag = logcmdutil.graphrevs(other, chlist, opts)
4326 revdag = logcmdutil.graphrevs(other, chlist, opts)
4327 logcmdutil.displaygraph(
4327 logcmdutil.displaygraph(
4328 ui, repo, revdag, displayer, graphmod.asciiedges
4328 ui, repo, revdag, displayer, graphmod.asciiedges
4329 )
4329 )
4330
4330
4331 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4331 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4332 return 0
4332 return 0
4333
4333
4334 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4334 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4335
4335
4336 if opts.get(b'bookmarks'):
4336 if opts.get(b'bookmarks'):
4337 srcs = urlutil.get_pull_paths(repo, ui, [source], opts.get(b'branch'))
4337 srcs = urlutil.get_pull_paths(repo, ui, [source], opts.get(b'branch'))
4338 for source, branches in srcs:
4338 for source, branches in srcs:
4339 other = hg.peer(repo, opts, source)
4339 other = hg.peer(repo, opts, source)
4340 try:
4340 try:
4341 if b'bookmarks' not in other.listkeys(b'namespaces'):
4341 if b'bookmarks' not in other.listkeys(b'namespaces'):
4342 ui.warn(_(b"remote doesn't support bookmarks\n"))
4342 ui.warn(_(b"remote doesn't support bookmarks\n"))
4343 return 0
4343 return 0
4344 ui.pager(b'incoming')
4344 ui.pager(b'incoming')
4345 ui.status(
4345 ui.status(
4346 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4346 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4347 )
4347 )
4348 return bookmarks.incoming(ui, repo, other)
4348 return bookmarks.incoming(ui, repo, other)
4349 finally:
4349 finally:
4350 other.close()
4350 other.close()
4351
4351
4352 return hg.incoming(ui, repo, source, opts)
4352 return hg.incoming(ui, repo, source, opts)
4353
4353
4354
4354
4355 @command(
4355 @command(
4356 b'init',
4356 b'init',
4357 remoteopts,
4357 remoteopts,
4358 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4358 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4359 helpcategory=command.CATEGORY_REPO_CREATION,
4359 helpcategory=command.CATEGORY_REPO_CREATION,
4360 helpbasic=True,
4360 helpbasic=True,
4361 norepo=True,
4361 norepo=True,
4362 )
4362 )
4363 def init(ui, dest=b".", **opts):
4363 def init(ui, dest=b".", **opts):
4364 """create a new repository in the given directory
4364 """create a new repository in the given directory
4365
4365
4366 Initialize a new repository in the given directory. If the given
4366 Initialize a new repository in the given directory. If the given
4367 directory does not exist, it will be created.
4367 directory does not exist, it will be created.
4368
4368
4369 If no directory is given, the current directory is used.
4369 If no directory is given, the current directory is used.
4370
4370
4371 It is possible to specify an ``ssh://`` URL as the destination.
4371 It is possible to specify an ``ssh://`` URL as the destination.
4372 See :hg:`help urls` for more information.
4372 See :hg:`help urls` for more information.
4373
4373
4374 Returns 0 on success.
4374 Returns 0 on success.
4375 """
4375 """
4376 opts = pycompat.byteskwargs(opts)
4376 opts = pycompat.byteskwargs(opts)
4377 path = urlutil.get_clone_path(ui, dest)[1]
4377 path = urlutil.get_clone_path(ui, dest)[1]
4378 peer = hg.peer(ui, opts, path, create=True)
4378 peer = hg.peer(ui, opts, path, create=True)
4379 peer.close()
4379 peer.close()
4380
4380
4381
4381
4382 @command(
4382 @command(
4383 b'locate',
4383 b'locate',
4384 [
4384 [
4385 (
4385 (
4386 b'r',
4386 b'r',
4387 b'rev',
4387 b'rev',
4388 b'',
4388 b'',
4389 _(b'search the repository as it is in REV'),
4389 _(b'search the repository as it is in REV'),
4390 _(b'REV'),
4390 _(b'REV'),
4391 ),
4391 ),
4392 (
4392 (
4393 b'0',
4393 b'0',
4394 b'print0',
4394 b'print0',
4395 None,
4395 None,
4396 _(b'end filenames with NUL, for use with xargs'),
4396 _(b'end filenames with NUL, for use with xargs'),
4397 ),
4397 ),
4398 (
4398 (
4399 b'f',
4399 b'f',
4400 b'fullpath',
4400 b'fullpath',
4401 None,
4401 None,
4402 _(b'print complete paths from the filesystem root'),
4402 _(b'print complete paths from the filesystem root'),
4403 ),
4403 ),
4404 ]
4404 ]
4405 + walkopts,
4405 + walkopts,
4406 _(b'[OPTION]... [PATTERN]...'),
4406 _(b'[OPTION]... [PATTERN]...'),
4407 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4407 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4408 )
4408 )
4409 def locate(ui, repo, *pats, **opts):
4409 def locate(ui, repo, *pats, **opts):
4410 """locate files matching specific patterns (DEPRECATED)
4410 """locate files matching specific patterns (DEPRECATED)
4411
4411
4412 Print files under Mercurial control in the working directory whose
4412 Print files under Mercurial control in the working directory whose
4413 names match the given patterns.
4413 names match the given patterns.
4414
4414
4415 By default, this command searches all directories in the working
4415 By default, this command searches all directories in the working
4416 directory. To search just the current directory and its
4416 directory. To search just the current directory and its
4417 subdirectories, use "--include .".
4417 subdirectories, use "--include .".
4418
4418
4419 If no patterns are given to match, this command prints the names
4419 If no patterns are given to match, this command prints the names
4420 of all files under Mercurial control in the working directory.
4420 of all files under Mercurial control in the working directory.
4421
4421
4422 If you want to feed the output of this command into the "xargs"
4422 If you want to feed the output of this command into the "xargs"
4423 command, use the -0 option to both this command and "xargs". This
4423 command, use the -0 option to both this command and "xargs". This
4424 will avoid the problem of "xargs" treating single filenames that
4424 will avoid the problem of "xargs" treating single filenames that
4425 contain whitespace as multiple filenames.
4425 contain whitespace as multiple filenames.
4426
4426
4427 See :hg:`help files` for a more versatile command.
4427 See :hg:`help files` for a more versatile command.
4428
4428
4429 Returns 0 if a match is found, 1 otherwise.
4429 Returns 0 if a match is found, 1 otherwise.
4430 """
4430 """
4431 opts = pycompat.byteskwargs(opts)
4431 opts = pycompat.byteskwargs(opts)
4432 if opts.get(b'print0'):
4432 if opts.get(b'print0'):
4433 end = b'\0'
4433 end = b'\0'
4434 else:
4434 else:
4435 end = b'\n'
4435 end = b'\n'
4436 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4436 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4437
4437
4438 ret = 1
4438 ret = 1
4439 m = scmutil.match(
4439 m = scmutil.match(
4440 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4440 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4441 )
4441 )
4442
4442
4443 ui.pager(b'locate')
4443 ui.pager(b'locate')
4444 if ctx.rev() is None:
4444 if ctx.rev() is None:
4445 # When run on the working copy, "locate" includes removed files, so
4445 # When run on the working copy, "locate" includes removed files, so
4446 # we get the list of files from the dirstate.
4446 # we get the list of files from the dirstate.
4447 filesgen = sorted(repo.dirstate.matches(m))
4447 filesgen = sorted(repo.dirstate.matches(m))
4448 else:
4448 else:
4449 filesgen = ctx.matches(m)
4449 filesgen = ctx.matches(m)
4450 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4450 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4451 for abs in filesgen:
4451 for abs in filesgen:
4452 if opts.get(b'fullpath'):
4452 if opts.get(b'fullpath'):
4453 ui.write(repo.wjoin(abs), end)
4453 ui.write(repo.wjoin(abs), end)
4454 else:
4454 else:
4455 ui.write(uipathfn(abs), end)
4455 ui.write(uipathfn(abs), end)
4456 ret = 0
4456 ret = 0
4457
4457
4458 return ret
4458 return ret
4459
4459
4460
4460
4461 @command(
4461 @command(
4462 b'log|history',
4462 b'log|history',
4463 [
4463 [
4464 (
4464 (
4465 b'f',
4465 b'f',
4466 b'follow',
4466 b'follow',
4467 None,
4467 None,
4468 _(
4468 _(
4469 b'follow changeset history, or file history across copies and renames'
4469 b'follow changeset history, or file history across copies and renames'
4470 ),
4470 ),
4471 ),
4471 ),
4472 (
4472 (
4473 b'',
4473 b'',
4474 b'follow-first',
4474 b'follow-first',
4475 None,
4475 None,
4476 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4476 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4477 ),
4477 ),
4478 (
4478 (
4479 b'd',
4479 b'd',
4480 b'date',
4480 b'date',
4481 b'',
4481 b'',
4482 _(b'show revisions matching date spec'),
4482 _(b'show revisions matching date spec'),
4483 _(b'DATE'),
4483 _(b'DATE'),
4484 ),
4484 ),
4485 (b'C', b'copies', None, _(b'show copied files')),
4485 (b'C', b'copies', None, _(b'show copied files')),
4486 (
4486 (
4487 b'k',
4487 b'k',
4488 b'keyword',
4488 b'keyword',
4489 [],
4489 [],
4490 _(b'do case-insensitive search for a given text'),
4490 _(b'do case-insensitive search for a given text'),
4491 _(b'TEXT'),
4491 _(b'TEXT'),
4492 ),
4492 ),
4493 (
4493 (
4494 b'r',
4494 b'r',
4495 b'rev',
4495 b'rev',
4496 [],
4496 [],
4497 _(b'revisions to select or follow from'),
4497 _(b'revisions to select or follow from'),
4498 _(b'REV'),
4498 _(b'REV'),
4499 ),
4499 ),
4500 (
4500 (
4501 b'L',
4501 b'L',
4502 b'line-range',
4502 b'line-range',
4503 [],
4503 [],
4504 _(b'follow line range of specified file (EXPERIMENTAL)'),
4504 _(b'follow line range of specified file (EXPERIMENTAL)'),
4505 _(b'FILE,RANGE'),
4505 _(b'FILE,RANGE'),
4506 ),
4506 ),
4507 (
4507 (
4508 b'',
4508 b'',
4509 b'removed',
4509 b'removed',
4510 None,
4510 None,
4511 _(b'include revisions where files were removed'),
4511 _(b'include revisions where files were removed'),
4512 ),
4512 ),
4513 (
4513 (
4514 b'm',
4514 b'm',
4515 b'only-merges',
4515 b'only-merges',
4516 None,
4516 None,
4517 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4517 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4518 ),
4518 ),
4519 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4519 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4520 (
4520 (
4521 b'',
4521 b'',
4522 b'only-branch',
4522 b'only-branch',
4523 [],
4523 [],
4524 _(
4524 _(
4525 b'show only changesets within the given named branch (DEPRECATED)'
4525 b'show only changesets within the given named branch (DEPRECATED)'
4526 ),
4526 ),
4527 _(b'BRANCH'),
4527 _(b'BRANCH'),
4528 ),
4528 ),
4529 (
4529 (
4530 b'b',
4530 b'b',
4531 b'branch',
4531 b'branch',
4532 [],
4532 [],
4533 _(b'show changesets within the given named branch'),
4533 _(b'show changesets within the given named branch'),
4534 _(b'BRANCH'),
4534 _(b'BRANCH'),
4535 ),
4535 ),
4536 (
4536 (
4537 b'B',
4537 b'B',
4538 b'bookmark',
4538 b'bookmark',
4539 [],
4539 [],
4540 _(b"show changesets within the given bookmark"),
4540 _(b"show changesets within the given bookmark"),
4541 _(b'BOOKMARK'),
4541 _(b'BOOKMARK'),
4542 ),
4542 ),
4543 (
4543 (
4544 b'P',
4544 b'P',
4545 b'prune',
4545 b'prune',
4546 [],
4546 [],
4547 _(b'do not display revision or any of its ancestors'),
4547 _(b'do not display revision or any of its ancestors'),
4548 _(b'REV'),
4548 _(b'REV'),
4549 ),
4549 ),
4550 ]
4550 ]
4551 + logopts
4551 + logopts
4552 + walkopts,
4552 + walkopts,
4553 _(b'[OPTION]... [FILE]'),
4553 _(b'[OPTION]... [FILE]'),
4554 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4554 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4555 helpbasic=True,
4555 helpbasic=True,
4556 inferrepo=True,
4556 inferrepo=True,
4557 intents={INTENT_READONLY},
4557 intents={INTENT_READONLY},
4558 )
4558 )
4559 def log(ui, repo, *pats, **opts):
4559 def log(ui, repo, *pats, **opts):
4560 """show revision history of entire repository or files
4560 """show revision history of entire repository or files
4561
4561
4562 Print the revision history of the specified files or the entire
4562 Print the revision history of the specified files or the entire
4563 project.
4563 project.
4564
4564
4565 If no revision range is specified, the default is ``tip:0`` unless
4565 If no revision range is specified, the default is ``tip:0`` unless
4566 --follow is set.
4566 --follow is set.
4567
4567
4568 File history is shown without following rename or copy history of
4568 File history is shown without following rename or copy history of
4569 files. Use -f/--follow with a filename to follow history across
4569 files. Use -f/--follow with a filename to follow history across
4570 renames and copies. --follow without a filename will only show
4570 renames and copies. --follow without a filename will only show
4571 ancestors of the starting revisions. The starting revisions can be
4571 ancestors of the starting revisions. The starting revisions can be
4572 specified by -r/--rev, which default to the working directory parent.
4572 specified by -r/--rev, which default to the working directory parent.
4573
4573
4574 By default this command prints revision number and changeset id,
4574 By default this command prints revision number and changeset id,
4575 tags, non-trivial parents, user, date and time, and a summary for
4575 tags, non-trivial parents, user, date and time, and a summary for
4576 each commit. When the -v/--verbose switch is used, the list of
4576 each commit. When the -v/--verbose switch is used, the list of
4577 changed files and full commit message are shown.
4577 changed files and full commit message are shown.
4578
4578
4579 With --graph the revisions are shown as an ASCII art DAG with the most
4579 With --graph the revisions are shown as an ASCII art DAG with the most
4580 recent changeset at the top.
4580 recent changeset at the top.
4581 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4581 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4582 involved in an unresolved merge conflict, '_' closes a branch,
4582 involved in an unresolved merge conflict, '_' closes a branch,
4583 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4583 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4584 changeset from the lines below is a parent of the 'o' merge on the same
4584 changeset from the lines below is a parent of the 'o' merge on the same
4585 line.
4585 line.
4586 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4586 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4587 of a '|' indicates one or more revisions in a path are omitted.
4587 of a '|' indicates one or more revisions in a path are omitted.
4588
4588
4589 .. container:: verbose
4589 .. container:: verbose
4590
4590
4591 Use -L/--line-range FILE,M:N options to follow the history of lines
4591 Use -L/--line-range FILE,M:N options to follow the history of lines
4592 from M to N in FILE. With -p/--patch only diff hunks affecting
4592 from M to N in FILE. With -p/--patch only diff hunks affecting
4593 specified line range will be shown. This option requires --follow;
4593 specified line range will be shown. This option requires --follow;
4594 it can be specified multiple times. Currently, this option is not
4594 it can be specified multiple times. Currently, this option is not
4595 compatible with --graph. This option is experimental.
4595 compatible with --graph. This option is experimental.
4596
4596
4597 .. note::
4597 .. note::
4598
4598
4599 :hg:`log --patch` may generate unexpected diff output for merge
4599 :hg:`log --patch` may generate unexpected diff output for merge
4600 changesets, as it will only compare the merge changeset against
4600 changesets, as it will only compare the merge changeset against
4601 its first parent. Also, only files different from BOTH parents
4601 its first parent. Also, only files different from BOTH parents
4602 will appear in files:.
4602 will appear in files:.
4603
4603
4604 .. note::
4604 .. note::
4605
4605
4606 For performance reasons, :hg:`log FILE` may omit duplicate changes
4606 For performance reasons, :hg:`log FILE` may omit duplicate changes
4607 made on branches and will not show removals or mode changes. To
4607 made on branches and will not show removals or mode changes. To
4608 see all such changes, use the --removed switch.
4608 see all such changes, use the --removed switch.
4609
4609
4610 .. container:: verbose
4610 .. container:: verbose
4611
4611
4612 .. note::
4612 .. note::
4613
4613
4614 The history resulting from -L/--line-range options depends on diff
4614 The history resulting from -L/--line-range options depends on diff
4615 options; for instance if white-spaces are ignored, respective changes
4615 options; for instance if white-spaces are ignored, respective changes
4616 with only white-spaces in specified line range will not be listed.
4616 with only white-spaces in specified line range will not be listed.
4617
4617
4618 .. container:: verbose
4618 .. container:: verbose
4619
4619
4620 Some examples:
4620 Some examples:
4621
4621
4622 - changesets with full descriptions and file lists::
4622 - changesets with full descriptions and file lists::
4623
4623
4624 hg log -v
4624 hg log -v
4625
4625
4626 - changesets ancestral to the working directory::
4626 - changesets ancestral to the working directory::
4627
4627
4628 hg log -f
4628 hg log -f
4629
4629
4630 - last 10 commits on the current branch::
4630 - last 10 commits on the current branch::
4631
4631
4632 hg log -l 10 -b .
4632 hg log -l 10 -b .
4633
4633
4634 - changesets showing all modifications of a file, including removals::
4634 - changesets showing all modifications of a file, including removals::
4635
4635
4636 hg log --removed file.c
4636 hg log --removed file.c
4637
4637
4638 - all changesets that touch a directory, with diffs, excluding merges::
4638 - all changesets that touch a directory, with diffs, excluding merges::
4639
4639
4640 hg log -Mp lib/
4640 hg log -Mp lib/
4641
4641
4642 - all revision numbers that match a keyword::
4642 - all revision numbers that match a keyword::
4643
4643
4644 hg log -k bug --template "{rev}\\n"
4644 hg log -k bug --template "{rev}\\n"
4645
4645
4646 - the full hash identifier of the working directory parent::
4646 - the full hash identifier of the working directory parent::
4647
4647
4648 hg log -r . --template "{node}\\n"
4648 hg log -r . --template "{node}\\n"
4649
4649
4650 - list available log templates::
4650 - list available log templates::
4651
4651
4652 hg log -T list
4652 hg log -T list
4653
4653
4654 - check if a given changeset is included in a tagged release::
4654 - check if a given changeset is included in a tagged release::
4655
4655
4656 hg log -r "a21ccf and ancestor(1.9)"
4656 hg log -r "a21ccf and ancestor(1.9)"
4657
4657
4658 - find all changesets by some user in a date range::
4658 - find all changesets by some user in a date range::
4659
4659
4660 hg log -k alice -d "may 2008 to jul 2008"
4660 hg log -k alice -d "may 2008 to jul 2008"
4661
4661
4662 - summary of all changesets after the last tag::
4662 - summary of all changesets after the last tag::
4663
4663
4664 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4664 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4665
4665
4666 - changesets touching lines 13 to 23 for file.c::
4666 - changesets touching lines 13 to 23 for file.c::
4667
4667
4668 hg log -L file.c,13:23
4668 hg log -L file.c,13:23
4669
4669
4670 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4670 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4671 main.c with patch::
4671 main.c with patch::
4672
4672
4673 hg log -L file.c,13:23 -L main.c,2:6 -p
4673 hg log -L file.c,13:23 -L main.c,2:6 -p
4674
4674
4675 See :hg:`help dates` for a list of formats valid for -d/--date.
4675 See :hg:`help dates` for a list of formats valid for -d/--date.
4676
4676
4677 See :hg:`help revisions` for more about specifying and ordering
4677 See :hg:`help revisions` for more about specifying and ordering
4678 revisions.
4678 revisions.
4679
4679
4680 See :hg:`help templates` for more about pre-packaged styles and
4680 See :hg:`help templates` for more about pre-packaged styles and
4681 specifying custom templates. The default template used by the log
4681 specifying custom templates. The default template used by the log
4682 command can be customized via the ``command-templates.log`` configuration
4682 command can be customized via the ``command-templates.log`` configuration
4683 setting.
4683 setting.
4684
4684
4685 Returns 0 on success.
4685 Returns 0 on success.
4686
4686
4687 """
4687 """
4688 opts = pycompat.byteskwargs(opts)
4688 opts = pycompat.byteskwargs(opts)
4689 linerange = opts.get(b'line_range')
4689 linerange = opts.get(b'line_range')
4690
4690
4691 if linerange and not opts.get(b'follow'):
4691 if linerange and not opts.get(b'follow'):
4692 raise error.InputError(_(b'--line-range requires --follow'))
4692 raise error.InputError(_(b'--line-range requires --follow'))
4693
4693
4694 if linerange and pats:
4694 if linerange and pats:
4695 # TODO: take pats as patterns with no line-range filter
4695 # TODO: take pats as patterns with no line-range filter
4696 raise error.InputError(
4696 raise error.InputError(
4697 _(b'FILE arguments are not compatible with --line-range option')
4697 _(b'FILE arguments are not compatible with --line-range option')
4698 )
4698 )
4699
4699
4700 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4700 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4701 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4701 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4702 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4702 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4703 if linerange:
4703 if linerange:
4704 # TODO: should follow file history from logcmdutil._initialrevs(),
4704 # TODO: should follow file history from logcmdutil._initialrevs(),
4705 # then filter the result by logcmdutil._makerevset() and --limit
4705 # then filter the result by logcmdutil._makerevset() and --limit
4706 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4706 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4707
4707
4708 getcopies = None
4708 getcopies = None
4709 if opts.get(b'copies'):
4709 if opts.get(b'copies'):
4710 endrev = None
4710 endrev = None
4711 if revs:
4711 if revs:
4712 endrev = revs.max() + 1
4712 endrev = revs.max() + 1
4713 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4713 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4714
4714
4715 ui.pager(b'log')
4715 ui.pager(b'log')
4716 displayer = logcmdutil.changesetdisplayer(
4716 displayer = logcmdutil.changesetdisplayer(
4717 ui, repo, opts, differ, buffered=True
4717 ui, repo, opts, differ, buffered=True
4718 )
4718 )
4719 if opts.get(b'graph'):
4719 if opts.get(b'graph'):
4720 displayfn = logcmdutil.displaygraphrevs
4720 displayfn = logcmdutil.displaygraphrevs
4721 else:
4721 else:
4722 displayfn = logcmdutil.displayrevs
4722 displayfn = logcmdutil.displayrevs
4723 displayfn(ui, repo, revs, displayer, getcopies)
4723 displayfn(ui, repo, revs, displayer, getcopies)
4724
4724
4725
4725
4726 @command(
4726 @command(
4727 b'manifest',
4727 b'manifest',
4728 [
4728 [
4729 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4729 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4730 (b'', b'all', False, _(b"list files from all revisions")),
4730 (b'', b'all', False, _(b"list files from all revisions")),
4731 ]
4731 ]
4732 + formatteropts,
4732 + formatteropts,
4733 _(b'[-r REV]'),
4733 _(b'[-r REV]'),
4734 helpcategory=command.CATEGORY_MAINTENANCE,
4734 helpcategory=command.CATEGORY_MAINTENANCE,
4735 intents={INTENT_READONLY},
4735 intents={INTENT_READONLY},
4736 )
4736 )
4737 def manifest(ui, repo, node=None, rev=None, **opts):
4737 def manifest(ui, repo, node=None, rev=None, **opts):
4738 """output the current or given revision of the project manifest
4738 """output the current or given revision of the project manifest
4739
4739
4740 Print a list of version controlled files for the given revision.
4740 Print a list of version controlled files for the given revision.
4741 If no revision is given, the first parent of the working directory
4741 If no revision is given, the first parent of the working directory
4742 is used, or the null revision if no revision is checked out.
4742 is used, or the null revision if no revision is checked out.
4743
4743
4744 With -v, print file permissions, symlink and executable bits.
4744 With -v, print file permissions, symlink and executable bits.
4745 With --debug, print file revision hashes.
4745 With --debug, print file revision hashes.
4746
4746
4747 If option --all is specified, the list of all files from all revisions
4747 If option --all is specified, the list of all files from all revisions
4748 is printed. This includes deleted and renamed files.
4748 is printed. This includes deleted and renamed files.
4749
4749
4750 Returns 0 on success.
4750 Returns 0 on success.
4751 """
4751 """
4752 opts = pycompat.byteskwargs(opts)
4752 opts = pycompat.byteskwargs(opts)
4753 fm = ui.formatter(b'manifest', opts)
4753 fm = ui.formatter(b'manifest', opts)
4754
4754
4755 if opts.get(b'all'):
4755 if opts.get(b'all'):
4756 if rev or node:
4756 if rev or node:
4757 raise error.InputError(_(b"can't specify a revision with --all"))
4757 raise error.InputError(_(b"can't specify a revision with --all"))
4758
4758
4759 res = set()
4759 res = set()
4760 for rev in repo:
4760 for rev in repo:
4761 ctx = repo[rev]
4761 ctx = repo[rev]
4762 res |= set(ctx.files())
4762 res |= set(ctx.files())
4763
4763
4764 ui.pager(b'manifest')
4764 ui.pager(b'manifest')
4765 for f in sorted(res):
4765 for f in sorted(res):
4766 fm.startitem()
4766 fm.startitem()
4767 fm.write(b"path", b'%s\n', f)
4767 fm.write(b"path", b'%s\n', f)
4768 fm.end()
4768 fm.end()
4769 return
4769 return
4770
4770
4771 if rev and node:
4771 if rev and node:
4772 raise error.InputError(_(b"please specify just one revision"))
4772 raise error.InputError(_(b"please specify just one revision"))
4773
4773
4774 if not node:
4774 if not node:
4775 node = rev
4775 node = rev
4776
4776
4777 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4777 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4778 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4778 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4779 if node:
4779 if node:
4780 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4780 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4781 ctx = scmutil.revsingle(repo, node)
4781 ctx = scmutil.revsingle(repo, node)
4782 mf = ctx.manifest()
4782 mf = ctx.manifest()
4783 ui.pager(b'manifest')
4783 ui.pager(b'manifest')
4784 for f in ctx:
4784 for f in ctx:
4785 fm.startitem()
4785 fm.startitem()
4786 fm.context(ctx=ctx)
4786 fm.context(ctx=ctx)
4787 fl = ctx[f].flags()
4787 fl = ctx[f].flags()
4788 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4788 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4789 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4789 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4790 fm.write(b'path', b'%s\n', f)
4790 fm.write(b'path', b'%s\n', f)
4791 fm.end()
4791 fm.end()
4792
4792
4793
4793
4794 @command(
4794 @command(
4795 b'merge',
4795 b'merge',
4796 [
4796 [
4797 (
4797 (
4798 b'f',
4798 b'f',
4799 b'force',
4799 b'force',
4800 None,
4800 None,
4801 _(b'force a merge including outstanding changes (DEPRECATED)'),
4801 _(b'force a merge including outstanding changes (DEPRECATED)'),
4802 ),
4802 ),
4803 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4803 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4804 (
4804 (
4805 b'P',
4805 b'P',
4806 b'preview',
4806 b'preview',
4807 None,
4807 None,
4808 _(b'review revisions to merge (no merge is performed)'),
4808 _(b'review revisions to merge (no merge is performed)'),
4809 ),
4809 ),
4810 (b'', b'abort', None, _(b'abort the ongoing merge')),
4810 (b'', b'abort', None, _(b'abort the ongoing merge')),
4811 ]
4811 ]
4812 + mergetoolopts,
4812 + mergetoolopts,
4813 _(b'[-P] [[-r] REV]'),
4813 _(b'[-P] [[-r] REV]'),
4814 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4814 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4815 helpbasic=True,
4815 helpbasic=True,
4816 )
4816 )
4817 def merge(ui, repo, node=None, **opts):
4817 def merge(ui, repo, node=None, **opts):
4818 """merge another revision into working directory
4818 """merge another revision into working directory
4819
4819
4820 The current working directory is updated with all changes made in
4820 The current working directory is updated with all changes made in
4821 the requested revision since the last common predecessor revision.
4821 the requested revision since the last common predecessor revision.
4822
4822
4823 Files that changed between either parent are marked as changed for
4823 Files that changed between either parent are marked as changed for
4824 the next commit and a commit must be performed before any further
4824 the next commit and a commit must be performed before any further
4825 updates to the repository are allowed. The next commit will have
4825 updates to the repository are allowed. The next commit will have
4826 two parents.
4826 two parents.
4827
4827
4828 ``--tool`` can be used to specify the merge tool used for file
4828 ``--tool`` can be used to specify the merge tool used for file
4829 merges. It overrides the HGMERGE environment variable and your
4829 merges. It overrides the HGMERGE environment variable and your
4830 configuration files. See :hg:`help merge-tools` for options.
4830 configuration files. See :hg:`help merge-tools` for options.
4831
4831
4832 If no revision is specified, the working directory's parent is a
4832 If no revision is specified, the working directory's parent is a
4833 head revision, and the current branch contains exactly one other
4833 head revision, and the current branch contains exactly one other
4834 head, the other head is merged with by default. Otherwise, an
4834 head, the other head is merged with by default. Otherwise, an
4835 explicit revision with which to merge must be provided.
4835 explicit revision with which to merge must be provided.
4836
4836
4837 See :hg:`help resolve` for information on handling file conflicts.
4837 See :hg:`help resolve` for information on handling file conflicts.
4838
4838
4839 To undo an uncommitted merge, use :hg:`merge --abort` which
4839 To undo an uncommitted merge, use :hg:`merge --abort` which
4840 will check out a clean copy of the original merge parent, losing
4840 will check out a clean copy of the original merge parent, losing
4841 all changes.
4841 all changes.
4842
4842
4843 Returns 0 on success, 1 if there are unresolved files.
4843 Returns 0 on success, 1 if there are unresolved files.
4844 """
4844 """
4845
4845
4846 opts = pycompat.byteskwargs(opts)
4846 opts = pycompat.byteskwargs(opts)
4847 abort = opts.get(b'abort')
4847 abort = opts.get(b'abort')
4848 if abort and repo.dirstate.p2() == repo.nullid:
4848 if abort and repo.dirstate.p2() == repo.nullid:
4849 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4849 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4850 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4850 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4851 if abort:
4851 if abort:
4852 state = cmdutil.getunfinishedstate(repo)
4852 state = cmdutil.getunfinishedstate(repo)
4853 if state and state._opname != b'merge':
4853 if state and state._opname != b'merge':
4854 raise error.StateError(
4854 raise error.StateError(
4855 _(b'cannot abort merge with %s in progress') % (state._opname),
4855 _(b'cannot abort merge with %s in progress') % (state._opname),
4856 hint=state.hint(),
4856 hint=state.hint(),
4857 )
4857 )
4858 if node:
4858 if node:
4859 raise error.InputError(_(b"cannot specify a node with --abort"))
4859 raise error.InputError(_(b"cannot specify a node with --abort"))
4860 return hg.abortmerge(repo.ui, repo)
4860 return hg.abortmerge(repo.ui, repo)
4861
4861
4862 if opts.get(b'rev') and node:
4862 if opts.get(b'rev') and node:
4863 raise error.InputError(_(b"please specify just one revision"))
4863 raise error.InputError(_(b"please specify just one revision"))
4864 if not node:
4864 if not node:
4865 node = opts.get(b'rev')
4865 node = opts.get(b'rev')
4866
4866
4867 if node:
4867 if node:
4868 ctx = scmutil.revsingle(repo, node)
4868 ctx = scmutil.revsingle(repo, node)
4869 else:
4869 else:
4870 if ui.configbool(b'commands', b'merge.require-rev'):
4870 if ui.configbool(b'commands', b'merge.require-rev'):
4871 raise error.InputError(
4871 raise error.InputError(
4872 _(
4872 _(
4873 b'configuration requires specifying revision to merge '
4873 b'configuration requires specifying revision to merge '
4874 b'with'
4874 b'with'
4875 )
4875 )
4876 )
4876 )
4877 ctx = repo[destutil.destmerge(repo)]
4877 ctx = repo[destutil.destmerge(repo)]
4878
4878
4879 if ctx.node() is None:
4879 if ctx.node() is None:
4880 raise error.InputError(
4880 raise error.InputError(
4881 _(b'merging with the working copy has no effect')
4881 _(b'merging with the working copy has no effect')
4882 )
4882 )
4883
4883
4884 if opts.get(b'preview'):
4884 if opts.get(b'preview'):
4885 # find nodes that are ancestors of p2 but not of p1
4885 # find nodes that are ancestors of p2 but not of p1
4886 p1 = repo[b'.'].node()
4886 p1 = repo[b'.'].node()
4887 p2 = ctx.node()
4887 p2 = ctx.node()
4888 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4888 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4889
4889
4890 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4890 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4891 for node in nodes:
4891 for node in nodes:
4892 displayer.show(repo[node])
4892 displayer.show(repo[node])
4893 displayer.close()
4893 displayer.close()
4894 return 0
4894 return 0
4895
4895
4896 # ui.forcemerge is an internal variable, do not document
4896 # ui.forcemerge is an internal variable, do not document
4897 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4897 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4898 with ui.configoverride(overrides, b'merge'):
4898 with ui.configoverride(overrides, b'merge'):
4899 force = opts.get(b'force')
4899 force = opts.get(b'force')
4900 labels = [b'working copy', b'merge rev']
4900 labels = [b'working copy', b'merge rev']
4901 return hg.merge(ctx, force=force, labels=labels)
4901 return hg.merge(ctx, force=force, labels=labels)
4902
4902
4903
4903
4904 statemod.addunfinished(
4904 statemod.addunfinished(
4905 b'merge',
4905 b'merge',
4906 fname=None,
4906 fname=None,
4907 clearable=True,
4907 clearable=True,
4908 allowcommit=True,
4908 allowcommit=True,
4909 cmdmsg=_(b'outstanding uncommitted merge'),
4909 cmdmsg=_(b'outstanding uncommitted merge'),
4910 abortfunc=hg.abortmerge,
4910 abortfunc=hg.abortmerge,
4911 statushint=_(
4911 statushint=_(
4912 b'To continue: hg commit\nTo abort: hg merge --abort'
4912 b'To continue: hg commit\nTo abort: hg merge --abort'
4913 ),
4913 ),
4914 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4914 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4915 )
4915 )
4916
4916
4917
4917
4918 @command(
4918 @command(
4919 b'outgoing|out',
4919 b'outgoing|out',
4920 [
4920 [
4921 (
4921 (
4922 b'f',
4922 b'f',
4923 b'force',
4923 b'force',
4924 None,
4924 None,
4925 _(b'run even when the destination is unrelated'),
4925 _(b'run even when the destination is unrelated'),
4926 ),
4926 ),
4927 (
4927 (
4928 b'r',
4928 b'r',
4929 b'rev',
4929 b'rev',
4930 [],
4930 [],
4931 _(b'a changeset intended to be included in the destination'),
4931 _(b'a changeset intended to be included in the destination'),
4932 _(b'REV'),
4932 _(b'REV'),
4933 ),
4933 ),
4934 (b'n', b'newest-first', None, _(b'show newest record first')),
4934 (b'n', b'newest-first', None, _(b'show newest record first')),
4935 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4935 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4936 (
4936 (
4937 b'b',
4937 b'b',
4938 b'branch',
4938 b'branch',
4939 [],
4939 [],
4940 _(b'a specific branch you would like to push'),
4940 _(b'a specific branch you would like to push'),
4941 _(b'BRANCH'),
4941 _(b'BRANCH'),
4942 ),
4942 ),
4943 ]
4943 ]
4944 + logopts
4944 + logopts
4945 + remoteopts
4945 + remoteopts
4946 + subrepoopts,
4946 + subrepoopts,
4947 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4947 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4948 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4948 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4949 )
4949 )
4950 def outgoing(ui, repo, *dests, **opts):
4950 def outgoing(ui, repo, *dests, **opts):
4951 """show changesets not found in the destination
4951 """show changesets not found in the destination
4952
4952
4953 Show changesets not found in the specified destination repository
4953 Show changesets not found in the specified destination repository
4954 or the default push location. These are the changesets that would
4954 or the default push location. These are the changesets that would
4955 be pushed if a push was requested.
4955 be pushed if a push was requested.
4956
4956
4957 See pull for details of valid destination formats.
4957 See pull for details of valid destination formats.
4958
4958
4959 .. container:: verbose
4959 .. container:: verbose
4960
4960
4961 With -B/--bookmarks, the result of bookmark comparison between
4961 With -B/--bookmarks, the result of bookmark comparison between
4962 local and remote repositories is displayed. With -v/--verbose,
4962 local and remote repositories is displayed. With -v/--verbose,
4963 status is also displayed for each bookmark like below::
4963 status is also displayed for each bookmark like below::
4964
4964
4965 BM1 01234567890a added
4965 BM1 01234567890a added
4966 BM2 deleted
4966 BM2 deleted
4967 BM3 234567890abc advanced
4967 BM3 234567890abc advanced
4968 BM4 34567890abcd diverged
4968 BM4 34567890abcd diverged
4969 BM5 4567890abcde changed
4969 BM5 4567890abcde changed
4970
4970
4971 The action taken when pushing depends on the
4971 The action taken when pushing depends on the
4972 status of each bookmark:
4972 status of each bookmark:
4973
4973
4974 :``added``: push with ``-B`` will create it
4974 :``added``: push with ``-B`` will create it
4975 :``deleted``: push with ``-B`` will delete it
4975 :``deleted``: push with ``-B`` will delete it
4976 :``advanced``: push will update it
4976 :``advanced``: push will update it
4977 :``diverged``: push with ``-B`` will update it
4977 :``diverged``: push with ``-B`` will update it
4978 :``changed``: push with ``-B`` will update it
4978 :``changed``: push with ``-B`` will update it
4979
4979
4980 From the point of view of pushing behavior, bookmarks
4980 From the point of view of pushing behavior, bookmarks
4981 existing only in the remote repository are treated as
4981 existing only in the remote repository are treated as
4982 ``deleted``, even if it is in fact added remotely.
4982 ``deleted``, even if it is in fact added remotely.
4983
4983
4984 Returns 0 if there are outgoing changes, 1 otherwise.
4984 Returns 0 if there are outgoing changes, 1 otherwise.
4985 """
4985 """
4986 opts = pycompat.byteskwargs(opts)
4986 opts = pycompat.byteskwargs(opts)
4987 if opts.get(b'bookmarks'):
4987 if opts.get(b'bookmarks'):
4988 for path in urlutil.get_push_paths(repo, ui, dests):
4988 for path in urlutil.get_push_paths(repo, ui, dests):
4989 dest = path.pushloc or path.loc
4989 dest = path.pushloc or path.loc
4990 other = hg.peer(repo, opts, dest)
4990 other = hg.peer(repo, opts, dest)
4991 try:
4991 try:
4992 if b'bookmarks' not in other.listkeys(b'namespaces'):
4992 if b'bookmarks' not in other.listkeys(b'namespaces'):
4993 ui.warn(_(b"remote doesn't support bookmarks\n"))
4993 ui.warn(_(b"remote doesn't support bookmarks\n"))
4994 return 0
4994 return 0
4995 ui.status(
4995 ui.status(
4996 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
4996 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
4997 )
4997 )
4998 ui.pager(b'outgoing')
4998 ui.pager(b'outgoing')
4999 return bookmarks.outgoing(ui, repo, other)
4999 return bookmarks.outgoing(ui, repo, other)
5000 finally:
5000 finally:
5001 other.close()
5001 other.close()
5002
5002
5003 return hg.outgoing(ui, repo, dests, opts)
5003 return hg.outgoing(ui, repo, dests, opts)
5004
5004
5005
5005
5006 @command(
5006 @command(
5007 b'parents',
5007 b'parents',
5008 [
5008 [
5009 (
5009 (
5010 b'r',
5010 b'r',
5011 b'rev',
5011 b'rev',
5012 b'',
5012 b'',
5013 _(b'show parents of the specified revision'),
5013 _(b'show parents of the specified revision'),
5014 _(b'REV'),
5014 _(b'REV'),
5015 ),
5015 ),
5016 ]
5016 ]
5017 + templateopts,
5017 + templateopts,
5018 _(b'[-r REV] [FILE]'),
5018 _(b'[-r REV] [FILE]'),
5019 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5019 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5020 inferrepo=True,
5020 inferrepo=True,
5021 )
5021 )
5022 def parents(ui, repo, file_=None, **opts):
5022 def parents(ui, repo, file_=None, **opts):
5023 """show the parents of the working directory or revision (DEPRECATED)
5023 """show the parents of the working directory or revision (DEPRECATED)
5024
5024
5025 Print the working directory's parent revisions. If a revision is
5025 Print the working directory's parent revisions. If a revision is
5026 given via -r/--rev, the parent of that revision will be printed.
5026 given via -r/--rev, the parent of that revision will be printed.
5027 If a file argument is given, the revision in which the file was
5027 If a file argument is given, the revision in which the file was
5028 last changed (before the working directory revision or the
5028 last changed (before the working directory revision or the
5029 argument to --rev if given) is printed.
5029 argument to --rev if given) is printed.
5030
5030
5031 This command is equivalent to::
5031 This command is equivalent to::
5032
5032
5033 hg log -r "p1()+p2()" or
5033 hg log -r "p1()+p2()" or
5034 hg log -r "p1(REV)+p2(REV)" or
5034 hg log -r "p1(REV)+p2(REV)" or
5035 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5035 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5036 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5036 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5037
5037
5038 See :hg:`summary` and :hg:`help revsets` for related information.
5038 See :hg:`summary` and :hg:`help revsets` for related information.
5039
5039
5040 Returns 0 on success.
5040 Returns 0 on success.
5041 """
5041 """
5042
5042
5043 opts = pycompat.byteskwargs(opts)
5043 opts = pycompat.byteskwargs(opts)
5044 rev = opts.get(b'rev')
5044 rev = opts.get(b'rev')
5045 if rev:
5045 if rev:
5046 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5046 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5047 ctx = scmutil.revsingle(repo, rev, None)
5047 ctx = scmutil.revsingle(repo, rev, None)
5048
5048
5049 if file_:
5049 if file_:
5050 m = scmutil.match(ctx, (file_,), opts)
5050 m = scmutil.match(ctx, (file_,), opts)
5051 if m.anypats() or len(m.files()) != 1:
5051 if m.anypats() or len(m.files()) != 1:
5052 raise error.InputError(_(b'can only specify an explicit filename'))
5052 raise error.InputError(_(b'can only specify an explicit filename'))
5053 file_ = m.files()[0]
5053 file_ = m.files()[0]
5054 filenodes = []
5054 filenodes = []
5055 for cp in ctx.parents():
5055 for cp in ctx.parents():
5056 if not cp:
5056 if not cp:
5057 continue
5057 continue
5058 try:
5058 try:
5059 filenodes.append(cp.filenode(file_))
5059 filenodes.append(cp.filenode(file_))
5060 except error.LookupError:
5060 except error.LookupError:
5061 pass
5061 pass
5062 if not filenodes:
5062 if not filenodes:
5063 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5063 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5064 p = []
5064 p = []
5065 for fn in filenodes:
5065 for fn in filenodes:
5066 fctx = repo.filectx(file_, fileid=fn)
5066 fctx = repo.filectx(file_, fileid=fn)
5067 p.append(fctx.node())
5067 p.append(fctx.node())
5068 else:
5068 else:
5069 p = [cp.node() for cp in ctx.parents()]
5069 p = [cp.node() for cp in ctx.parents()]
5070
5070
5071 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5071 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5072 for n in p:
5072 for n in p:
5073 if n != repo.nullid:
5073 if n != repo.nullid:
5074 displayer.show(repo[n])
5074 displayer.show(repo[n])
5075 displayer.close()
5075 displayer.close()
5076
5076
5077
5077
5078 @command(
5078 @command(
5079 b'paths',
5079 b'paths',
5080 formatteropts,
5080 formatteropts,
5081 _(b'[NAME]'),
5081 _(b'[NAME]'),
5082 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5082 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5083 optionalrepo=True,
5083 optionalrepo=True,
5084 intents={INTENT_READONLY},
5084 intents={INTENT_READONLY},
5085 )
5085 )
5086 def paths(ui, repo, search=None, **opts):
5086 def paths(ui, repo, search=None, **opts):
5087 """show aliases for remote repositories
5087 """show aliases for remote repositories
5088
5088
5089 Show definition of symbolic path name NAME. If no name is given,
5089 Show definition of symbolic path name NAME. If no name is given,
5090 show definition of all available names.
5090 show definition of all available names.
5091
5091
5092 Option -q/--quiet suppresses all output when searching for NAME
5092 Option -q/--quiet suppresses all output when searching for NAME
5093 and shows only the path names when listing all definitions.
5093 and shows only the path names when listing all definitions.
5094
5094
5095 Path names are defined in the [paths] section of your
5095 Path names are defined in the [paths] section of your
5096 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5096 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5097 repository, ``.hg/hgrc`` is used, too.
5097 repository, ``.hg/hgrc`` is used, too.
5098
5098
5099 The path names ``default`` and ``default-push`` have a special
5099 The path names ``default`` and ``default-push`` have a special
5100 meaning. When performing a push or pull operation, they are used
5100 meaning. When performing a push or pull operation, they are used
5101 as fallbacks if no location is specified on the command-line.
5101 as fallbacks if no location is specified on the command-line.
5102 When ``default-push`` is set, it will be used for push and
5102 When ``default-push`` is set, it will be used for push and
5103 ``default`` will be used for pull; otherwise ``default`` is used
5103 ``default`` will be used for pull; otherwise ``default`` is used
5104 as the fallback for both. When cloning a repository, the clone
5104 as the fallback for both. When cloning a repository, the clone
5105 source is written as ``default`` in ``.hg/hgrc``.
5105 source is written as ``default`` in ``.hg/hgrc``.
5106
5106
5107 .. note::
5107 .. note::
5108
5108
5109 ``default`` and ``default-push`` apply to all inbound (e.g.
5109 ``default`` and ``default-push`` apply to all inbound (e.g.
5110 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5110 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5111 and :hg:`bundle`) operations.
5111 and :hg:`bundle`) operations.
5112
5112
5113 See :hg:`help urls` for more information.
5113 See :hg:`help urls` for more information.
5114
5114
5115 .. container:: verbose
5115 .. container:: verbose
5116
5116
5117 Template:
5117 Template:
5118
5118
5119 The following keywords are supported. See also :hg:`help templates`.
5119 The following keywords are supported. See also :hg:`help templates`.
5120
5120
5121 :name: String. Symbolic name of the path alias.
5121 :name: String. Symbolic name of the path alias.
5122 :pushurl: String. URL for push operations.
5122 :pushurl: String. URL for push operations.
5123 :url: String. URL or directory path for the other operations.
5123 :url: String. URL or directory path for the other operations.
5124
5124
5125 Returns 0 on success.
5125 Returns 0 on success.
5126 """
5126 """
5127
5127
5128 opts = pycompat.byteskwargs(opts)
5128 opts = pycompat.byteskwargs(opts)
5129
5130 pathitems = urlutil.list_paths(ui, search)
5129 ui.pager(b'paths')
5131 ui.pager(b'paths')
5130 if search:
5131 pathitems = [
5132 (name, path)
5133 for name, path in pycompat.iteritems(ui.paths)
5134 if name == search
5135 ]
5136 else:
5137 pathitems = sorted(pycompat.iteritems(ui.paths))
5138
5132
5139 fm = ui.formatter(b'paths', opts)
5133 fm = ui.formatter(b'paths', opts)
5140 if fm.isplain():
5134 if fm.isplain():
5141 hidepassword = urlutil.hidepassword
5135 hidepassword = urlutil.hidepassword
5142 else:
5136 else:
5143 hidepassword = bytes
5137 hidepassword = bytes
5144 if ui.quiet:
5138 if ui.quiet:
5145 namefmt = b'%s\n'
5139 namefmt = b'%s\n'
5146 else:
5140 else:
5147 namefmt = b'%s = '
5141 namefmt = b'%s = '
5148 showsubopts = not search and not ui.quiet
5142 showsubopts = not search and not ui.quiet
5149
5143
5150 for name, path in pathitems:
5144 for name, path in pathitems:
5151 fm.startitem()
5145 fm.startitem()
5152 fm.condwrite(not search, b'name', namefmt, name)
5146 fm.condwrite(not search, b'name', namefmt, name)
5153 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5147 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5154 for subopt, value in sorted(path.suboptions.items()):
5148 for subopt, value in sorted(path.suboptions.items()):
5155 assert subopt not in (b'name', b'url')
5149 assert subopt not in (b'name', b'url')
5156 if showsubopts:
5150 if showsubopts:
5157 fm.plain(b'%s:%s = ' % (name, subopt))
5151 fm.plain(b'%s:%s = ' % (name, subopt))
5158 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5152 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5159
5153
5160 fm.end()
5154 fm.end()
5161
5155
5162 if search and not pathitems:
5156 if search and not pathitems:
5163 if not ui.quiet:
5157 if not ui.quiet:
5164 ui.warn(_(b"not found!\n"))
5158 ui.warn(_(b"not found!\n"))
5165 return 1
5159 return 1
5166 else:
5160 else:
5167 return 0
5161 return 0
5168
5162
5169
5163
5170 @command(
5164 @command(
5171 b'phase',
5165 b'phase',
5172 [
5166 [
5173 (b'p', b'public', False, _(b'set changeset phase to public')),
5167 (b'p', b'public', False, _(b'set changeset phase to public')),
5174 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5168 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5175 (b's', b'secret', False, _(b'set changeset phase to secret')),
5169 (b's', b'secret', False, _(b'set changeset phase to secret')),
5176 (b'f', b'force', False, _(b'allow to move boundary backward')),
5170 (b'f', b'force', False, _(b'allow to move boundary backward')),
5177 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5171 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5178 ],
5172 ],
5179 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5173 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5180 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5174 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5181 )
5175 )
5182 def phase(ui, repo, *revs, **opts):
5176 def phase(ui, repo, *revs, **opts):
5183 """set or show the current phase name
5177 """set or show the current phase name
5184
5178
5185 With no argument, show the phase name of the current revision(s).
5179 With no argument, show the phase name of the current revision(s).
5186
5180
5187 With one of -p/--public, -d/--draft or -s/--secret, change the
5181 With one of -p/--public, -d/--draft or -s/--secret, change the
5188 phase value of the specified revisions.
5182 phase value of the specified revisions.
5189
5183
5190 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5184 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5191 lower phase to a higher phase. Phases are ordered as follows::
5185 lower phase to a higher phase. Phases are ordered as follows::
5192
5186
5193 public < draft < secret
5187 public < draft < secret
5194
5188
5195 Returns 0 on success, 1 if some phases could not be changed.
5189 Returns 0 on success, 1 if some phases could not be changed.
5196
5190
5197 (For more information about the phases concept, see :hg:`help phases`.)
5191 (For more information about the phases concept, see :hg:`help phases`.)
5198 """
5192 """
5199 opts = pycompat.byteskwargs(opts)
5193 opts = pycompat.byteskwargs(opts)
5200 # search for a unique phase argument
5194 # search for a unique phase argument
5201 targetphase = None
5195 targetphase = None
5202 for idx, name in enumerate(phases.cmdphasenames):
5196 for idx, name in enumerate(phases.cmdphasenames):
5203 if opts[name]:
5197 if opts[name]:
5204 if targetphase is not None:
5198 if targetphase is not None:
5205 raise error.InputError(_(b'only one phase can be specified'))
5199 raise error.InputError(_(b'only one phase can be specified'))
5206 targetphase = idx
5200 targetphase = idx
5207
5201
5208 # look for specified revision
5202 # look for specified revision
5209 revs = list(revs)
5203 revs = list(revs)
5210 revs.extend(opts[b'rev'])
5204 revs.extend(opts[b'rev'])
5211 if not revs:
5205 if not revs:
5212 # display both parents as the second parent phase can influence
5206 # display both parents as the second parent phase can influence
5213 # the phase of a merge commit
5207 # the phase of a merge commit
5214 revs = [c.rev() for c in repo[None].parents()]
5208 revs = [c.rev() for c in repo[None].parents()]
5215
5209
5216 revs = scmutil.revrange(repo, revs)
5210 revs = scmutil.revrange(repo, revs)
5217
5211
5218 ret = 0
5212 ret = 0
5219 if targetphase is None:
5213 if targetphase is None:
5220 # display
5214 # display
5221 for r in revs:
5215 for r in revs:
5222 ctx = repo[r]
5216 ctx = repo[r]
5223 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5217 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5224 else:
5218 else:
5225 with repo.lock(), repo.transaction(b"phase") as tr:
5219 with repo.lock(), repo.transaction(b"phase") as tr:
5226 # set phase
5220 # set phase
5227 if not revs:
5221 if not revs:
5228 raise error.InputError(_(b'empty revision set'))
5222 raise error.InputError(_(b'empty revision set'))
5229 nodes = [repo[r].node() for r in revs]
5223 nodes = [repo[r].node() for r in revs]
5230 # moving revision from public to draft may hide them
5224 # moving revision from public to draft may hide them
5231 # We have to check result on an unfiltered repository
5225 # We have to check result on an unfiltered repository
5232 unfi = repo.unfiltered()
5226 unfi = repo.unfiltered()
5233 getphase = unfi._phasecache.phase
5227 getphase = unfi._phasecache.phase
5234 olddata = [getphase(unfi, r) for r in unfi]
5228 olddata = [getphase(unfi, r) for r in unfi]
5235 phases.advanceboundary(repo, tr, targetphase, nodes)
5229 phases.advanceboundary(repo, tr, targetphase, nodes)
5236 if opts[b'force']:
5230 if opts[b'force']:
5237 phases.retractboundary(repo, tr, targetphase, nodes)
5231 phases.retractboundary(repo, tr, targetphase, nodes)
5238 getphase = unfi._phasecache.phase
5232 getphase = unfi._phasecache.phase
5239 newdata = [getphase(unfi, r) for r in unfi]
5233 newdata = [getphase(unfi, r) for r in unfi]
5240 changes = sum(newdata[r] != olddata[r] for r in unfi)
5234 changes = sum(newdata[r] != olddata[r] for r in unfi)
5241 cl = unfi.changelog
5235 cl = unfi.changelog
5242 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5236 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5243 if rejected:
5237 if rejected:
5244 ui.warn(
5238 ui.warn(
5245 _(
5239 _(
5246 b'cannot move %i changesets to a higher '
5240 b'cannot move %i changesets to a higher '
5247 b'phase, use --force\n'
5241 b'phase, use --force\n'
5248 )
5242 )
5249 % len(rejected)
5243 % len(rejected)
5250 )
5244 )
5251 ret = 1
5245 ret = 1
5252 if changes:
5246 if changes:
5253 msg = _(b'phase changed for %i changesets\n') % changes
5247 msg = _(b'phase changed for %i changesets\n') % changes
5254 if ret:
5248 if ret:
5255 ui.status(msg)
5249 ui.status(msg)
5256 else:
5250 else:
5257 ui.note(msg)
5251 ui.note(msg)
5258 else:
5252 else:
5259 ui.warn(_(b'no phases changed\n'))
5253 ui.warn(_(b'no phases changed\n'))
5260 return ret
5254 return ret
5261
5255
5262
5256
5263 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5257 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5264 """Run after a changegroup has been added via pull/unbundle
5258 """Run after a changegroup has been added via pull/unbundle
5265
5259
5266 This takes arguments below:
5260 This takes arguments below:
5267
5261
5268 :modheads: change of heads by pull/unbundle
5262 :modheads: change of heads by pull/unbundle
5269 :optupdate: updating working directory is needed or not
5263 :optupdate: updating working directory is needed or not
5270 :checkout: update destination revision (or None to default destination)
5264 :checkout: update destination revision (or None to default destination)
5271 :brev: a name, which might be a bookmark to be activated after updating
5265 :brev: a name, which might be a bookmark to be activated after updating
5272
5266
5273 return True if update raise any conflict, False otherwise.
5267 return True if update raise any conflict, False otherwise.
5274 """
5268 """
5275 if modheads == 0:
5269 if modheads == 0:
5276 return False
5270 return False
5277 if optupdate:
5271 if optupdate:
5278 try:
5272 try:
5279 return hg.updatetotally(ui, repo, checkout, brev)
5273 return hg.updatetotally(ui, repo, checkout, brev)
5280 except error.UpdateAbort as inst:
5274 except error.UpdateAbort as inst:
5281 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5275 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5282 hint = inst.hint
5276 hint = inst.hint
5283 raise error.UpdateAbort(msg, hint=hint)
5277 raise error.UpdateAbort(msg, hint=hint)
5284 if modheads is not None and modheads > 1:
5278 if modheads is not None and modheads > 1:
5285 currentbranchheads = len(repo.branchheads())
5279 currentbranchheads = len(repo.branchheads())
5286 if currentbranchheads == modheads:
5280 if currentbranchheads == modheads:
5287 ui.status(
5281 ui.status(
5288 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5282 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5289 )
5283 )
5290 elif currentbranchheads > 1:
5284 elif currentbranchheads > 1:
5291 ui.status(
5285 ui.status(
5292 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5286 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5293 )
5287 )
5294 else:
5288 else:
5295 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5289 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5296 elif not ui.configbool(b'commands', b'update.requiredest'):
5290 elif not ui.configbool(b'commands', b'update.requiredest'):
5297 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5291 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5298 return False
5292 return False
5299
5293
5300
5294
5301 @command(
5295 @command(
5302 b'pull',
5296 b'pull',
5303 [
5297 [
5304 (
5298 (
5305 b'u',
5299 b'u',
5306 b'update',
5300 b'update',
5307 None,
5301 None,
5308 _(b'update to new branch head if new descendants were pulled'),
5302 _(b'update to new branch head if new descendants were pulled'),
5309 ),
5303 ),
5310 (
5304 (
5311 b'f',
5305 b'f',
5312 b'force',
5306 b'force',
5313 None,
5307 None,
5314 _(b'run even when remote repository is unrelated'),
5308 _(b'run even when remote repository is unrelated'),
5315 ),
5309 ),
5316 (
5310 (
5317 b'',
5311 b'',
5318 b'confirm',
5312 b'confirm',
5319 None,
5313 None,
5320 _(b'confirm pull before applying changes'),
5314 _(b'confirm pull before applying changes'),
5321 ),
5315 ),
5322 (
5316 (
5323 b'r',
5317 b'r',
5324 b'rev',
5318 b'rev',
5325 [],
5319 [],
5326 _(b'a remote changeset intended to be added'),
5320 _(b'a remote changeset intended to be added'),
5327 _(b'REV'),
5321 _(b'REV'),
5328 ),
5322 ),
5329 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5323 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5330 (
5324 (
5331 b'b',
5325 b'b',
5332 b'branch',
5326 b'branch',
5333 [],
5327 [],
5334 _(b'a specific branch you would like to pull'),
5328 _(b'a specific branch you would like to pull'),
5335 _(b'BRANCH'),
5329 _(b'BRANCH'),
5336 ),
5330 ),
5337 ]
5331 ]
5338 + remoteopts,
5332 + remoteopts,
5339 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5333 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5340 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5334 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5341 helpbasic=True,
5335 helpbasic=True,
5342 )
5336 )
5343 def pull(ui, repo, *sources, **opts):
5337 def pull(ui, repo, *sources, **opts):
5344 """pull changes from the specified source
5338 """pull changes from the specified source
5345
5339
5346 Pull changes from a remote repository to a local one.
5340 Pull changes from a remote repository to a local one.
5347
5341
5348 This finds all changes from the repository at the specified path
5342 This finds all changes from the repository at the specified path
5349 or URL and adds them to a local repository (the current one unless
5343 or URL and adds them to a local repository (the current one unless
5350 -R is specified). By default, this does not update the copy of the
5344 -R is specified). By default, this does not update the copy of the
5351 project in the working directory.
5345 project in the working directory.
5352
5346
5353 When cloning from servers that support it, Mercurial may fetch
5347 When cloning from servers that support it, Mercurial may fetch
5354 pre-generated data. When this is done, hooks operating on incoming
5348 pre-generated data. When this is done, hooks operating on incoming
5355 changesets and changegroups may fire more than once, once for each
5349 changesets and changegroups may fire more than once, once for each
5356 pre-generated bundle and as well as for any additional remaining
5350 pre-generated bundle and as well as for any additional remaining
5357 data. See :hg:`help -e clonebundles` for more.
5351 data. See :hg:`help -e clonebundles` for more.
5358
5352
5359 Use :hg:`incoming` if you want to see what would have been added
5353 Use :hg:`incoming` if you want to see what would have been added
5360 by a pull at the time you issued this command. If you then decide
5354 by a pull at the time you issued this command. If you then decide
5361 to add those changes to the repository, you should use :hg:`pull
5355 to add those changes to the repository, you should use :hg:`pull
5362 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5356 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5363
5357
5364 If SOURCE is omitted, the 'default' path will be used.
5358 If SOURCE is omitted, the 'default' path will be used.
5365 See :hg:`help urls` for more information.
5359 See :hg:`help urls` for more information.
5366
5360
5367 If multiple sources are specified, they will be pulled sequentially as if
5361 If multiple sources are specified, they will be pulled sequentially as if
5368 the command was run multiple time. If --update is specify and the command
5362 the command was run multiple time. If --update is specify and the command
5369 will stop at the first failed --update.
5363 will stop at the first failed --update.
5370
5364
5371 Specifying bookmark as ``.`` is equivalent to specifying the active
5365 Specifying bookmark as ``.`` is equivalent to specifying the active
5372 bookmark's name.
5366 bookmark's name.
5373
5367
5374 Returns 0 on success, 1 if an update had unresolved files.
5368 Returns 0 on success, 1 if an update had unresolved files.
5375 """
5369 """
5376
5370
5377 opts = pycompat.byteskwargs(opts)
5371 opts = pycompat.byteskwargs(opts)
5378 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5372 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5379 b'update'
5373 b'update'
5380 ):
5374 ):
5381 msg = _(b'update destination required by configuration')
5375 msg = _(b'update destination required by configuration')
5382 hint = _(b'use hg pull followed by hg update DEST')
5376 hint = _(b'use hg pull followed by hg update DEST')
5383 raise error.InputError(msg, hint=hint)
5377 raise error.InputError(msg, hint=hint)
5384
5378
5385 sources = urlutil.get_pull_paths(repo, ui, sources, opts.get(b'branch'))
5379 sources = urlutil.get_pull_paths(repo, ui, sources, opts.get(b'branch'))
5386 for source, branches in sources:
5380 for source, branches in sources:
5387 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5381 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5388 ui.flush()
5382 ui.flush()
5389 other = hg.peer(repo, opts, source)
5383 other = hg.peer(repo, opts, source)
5390 update_conflict = None
5384 update_conflict = None
5391 try:
5385 try:
5392 revs, checkout = hg.addbranchrevs(
5386 revs, checkout = hg.addbranchrevs(
5393 repo, other, branches, opts.get(b'rev')
5387 repo, other, branches, opts.get(b'rev')
5394 )
5388 )
5395
5389
5396 pullopargs = {}
5390 pullopargs = {}
5397
5391
5398 nodes = None
5392 nodes = None
5399 if opts.get(b'bookmark') or revs:
5393 if opts.get(b'bookmark') or revs:
5400 # The list of bookmark used here is the same used to actually update
5394 # The list of bookmark used here is the same used to actually update
5401 # the bookmark names, to avoid the race from issue 4689 and we do
5395 # the bookmark names, to avoid the race from issue 4689 and we do
5402 # all lookup and bookmark queries in one go so they see the same
5396 # all lookup and bookmark queries in one go so they see the same
5403 # version of the server state (issue 4700).
5397 # version of the server state (issue 4700).
5404 nodes = []
5398 nodes = []
5405 fnodes = []
5399 fnodes = []
5406 revs = revs or []
5400 revs = revs or []
5407 if revs and not other.capable(b'lookup'):
5401 if revs and not other.capable(b'lookup'):
5408 err = _(
5402 err = _(
5409 b"other repository doesn't support revision lookup, "
5403 b"other repository doesn't support revision lookup, "
5410 b"so a rev cannot be specified."
5404 b"so a rev cannot be specified."
5411 )
5405 )
5412 raise error.Abort(err)
5406 raise error.Abort(err)
5413 with other.commandexecutor() as e:
5407 with other.commandexecutor() as e:
5414 fremotebookmarks = e.callcommand(
5408 fremotebookmarks = e.callcommand(
5415 b'listkeys', {b'namespace': b'bookmarks'}
5409 b'listkeys', {b'namespace': b'bookmarks'}
5416 )
5410 )
5417 for r in revs:
5411 for r in revs:
5418 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5412 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5419 remotebookmarks = fremotebookmarks.result()
5413 remotebookmarks = fremotebookmarks.result()
5420 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5414 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5421 pullopargs[b'remotebookmarks'] = remotebookmarks
5415 pullopargs[b'remotebookmarks'] = remotebookmarks
5422 for b in opts.get(b'bookmark', []):
5416 for b in opts.get(b'bookmark', []):
5423 b = repo._bookmarks.expandname(b)
5417 b = repo._bookmarks.expandname(b)
5424 if b not in remotebookmarks:
5418 if b not in remotebookmarks:
5425 raise error.InputError(
5419 raise error.InputError(
5426 _(b'remote bookmark %s not found!') % b
5420 _(b'remote bookmark %s not found!') % b
5427 )
5421 )
5428 nodes.append(remotebookmarks[b])
5422 nodes.append(remotebookmarks[b])
5429 for i, rev in enumerate(revs):
5423 for i, rev in enumerate(revs):
5430 node = fnodes[i].result()
5424 node = fnodes[i].result()
5431 nodes.append(node)
5425 nodes.append(node)
5432 if rev == checkout:
5426 if rev == checkout:
5433 checkout = node
5427 checkout = node
5434
5428
5435 wlock = util.nullcontextmanager()
5429 wlock = util.nullcontextmanager()
5436 if opts.get(b'update'):
5430 if opts.get(b'update'):
5437 wlock = repo.wlock()
5431 wlock = repo.wlock()
5438 with wlock:
5432 with wlock:
5439 pullopargs.update(opts.get(b'opargs', {}))
5433 pullopargs.update(opts.get(b'opargs', {}))
5440 modheads = exchange.pull(
5434 modheads = exchange.pull(
5441 repo,
5435 repo,
5442 other,
5436 other,
5443 heads=nodes,
5437 heads=nodes,
5444 force=opts.get(b'force'),
5438 force=opts.get(b'force'),
5445 bookmarks=opts.get(b'bookmark', ()),
5439 bookmarks=opts.get(b'bookmark', ()),
5446 opargs=pullopargs,
5440 opargs=pullopargs,
5447 confirm=opts.get(b'confirm'),
5441 confirm=opts.get(b'confirm'),
5448 ).cgresult
5442 ).cgresult
5449
5443
5450 # brev is a name, which might be a bookmark to be activated at
5444 # brev is a name, which might be a bookmark to be activated at
5451 # the end of the update. In other words, it is an explicit
5445 # the end of the update. In other words, it is an explicit
5452 # destination of the update
5446 # destination of the update
5453 brev = None
5447 brev = None
5454
5448
5455 if checkout:
5449 if checkout:
5456 checkout = repo.unfiltered().changelog.rev(checkout)
5450 checkout = repo.unfiltered().changelog.rev(checkout)
5457
5451
5458 # order below depends on implementation of
5452 # order below depends on implementation of
5459 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5453 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5460 # because 'checkout' is determined without it.
5454 # because 'checkout' is determined without it.
5461 if opts.get(b'rev'):
5455 if opts.get(b'rev'):
5462 brev = opts[b'rev'][0]
5456 brev = opts[b'rev'][0]
5463 elif opts.get(b'branch'):
5457 elif opts.get(b'branch'):
5464 brev = opts[b'branch'][0]
5458 brev = opts[b'branch'][0]
5465 else:
5459 else:
5466 brev = branches[0]
5460 brev = branches[0]
5467 repo._subtoppath = source
5461 repo._subtoppath = source
5468 try:
5462 try:
5469 update_conflict = postincoming(
5463 update_conflict = postincoming(
5470 ui, repo, modheads, opts.get(b'update'), checkout, brev
5464 ui, repo, modheads, opts.get(b'update'), checkout, brev
5471 )
5465 )
5472 except error.FilteredRepoLookupError as exc:
5466 except error.FilteredRepoLookupError as exc:
5473 msg = _(b'cannot update to target: %s') % exc.args[0]
5467 msg = _(b'cannot update to target: %s') % exc.args[0]
5474 exc.args = (msg,) + exc.args[1:]
5468 exc.args = (msg,) + exc.args[1:]
5475 raise
5469 raise
5476 finally:
5470 finally:
5477 del repo._subtoppath
5471 del repo._subtoppath
5478
5472
5479 finally:
5473 finally:
5480 other.close()
5474 other.close()
5481 # skip the remaining pull source if they are some conflict.
5475 # skip the remaining pull source if they are some conflict.
5482 if update_conflict:
5476 if update_conflict:
5483 break
5477 break
5484 if update_conflict:
5478 if update_conflict:
5485 return 1
5479 return 1
5486 else:
5480 else:
5487 return 0
5481 return 0
5488
5482
5489
5483
5490 @command(
5484 @command(
5491 b'purge|clean',
5485 b'purge|clean',
5492 [
5486 [
5493 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5487 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5494 (b'', b'all', None, _(b'purge ignored files too')),
5488 (b'', b'all', None, _(b'purge ignored files too')),
5495 (b'i', b'ignored', None, _(b'purge only ignored files')),
5489 (b'i', b'ignored', None, _(b'purge only ignored files')),
5496 (b'', b'dirs', None, _(b'purge empty directories')),
5490 (b'', b'dirs', None, _(b'purge empty directories')),
5497 (b'', b'files', None, _(b'purge files')),
5491 (b'', b'files', None, _(b'purge files')),
5498 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5492 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5499 (
5493 (
5500 b'0',
5494 b'0',
5501 b'print0',
5495 b'print0',
5502 None,
5496 None,
5503 _(
5497 _(
5504 b'end filenames with NUL, for use with xargs'
5498 b'end filenames with NUL, for use with xargs'
5505 b' (implies -p/--print)'
5499 b' (implies -p/--print)'
5506 ),
5500 ),
5507 ),
5501 ),
5508 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5502 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5509 ]
5503 ]
5510 + cmdutil.walkopts,
5504 + cmdutil.walkopts,
5511 _(b'hg purge [OPTION]... [DIR]...'),
5505 _(b'hg purge [OPTION]... [DIR]...'),
5512 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5506 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5513 )
5507 )
5514 def purge(ui, repo, *dirs, **opts):
5508 def purge(ui, repo, *dirs, **opts):
5515 """removes files not tracked by Mercurial
5509 """removes files not tracked by Mercurial
5516
5510
5517 Delete files not known to Mercurial. This is useful to test local
5511 Delete files not known to Mercurial. This is useful to test local
5518 and uncommitted changes in an otherwise-clean source tree.
5512 and uncommitted changes in an otherwise-clean source tree.
5519
5513
5520 This means that purge will delete the following by default:
5514 This means that purge will delete the following by default:
5521
5515
5522 - Unknown files: files marked with "?" by :hg:`status`
5516 - Unknown files: files marked with "?" by :hg:`status`
5523 - Empty directories: in fact Mercurial ignores directories unless
5517 - Empty directories: in fact Mercurial ignores directories unless
5524 they contain files under source control management
5518 they contain files under source control management
5525
5519
5526 But it will leave untouched:
5520 But it will leave untouched:
5527
5521
5528 - Modified and unmodified tracked files
5522 - Modified and unmodified tracked files
5529 - Ignored files (unless -i or --all is specified)
5523 - Ignored files (unless -i or --all is specified)
5530 - New files added to the repository (with :hg:`add`)
5524 - New files added to the repository (with :hg:`add`)
5531
5525
5532 The --files and --dirs options can be used to direct purge to delete
5526 The --files and --dirs options can be used to direct purge to delete
5533 only files, only directories, or both. If neither option is given,
5527 only files, only directories, or both. If neither option is given,
5534 both will be deleted.
5528 both will be deleted.
5535
5529
5536 If directories are given on the command line, only files in these
5530 If directories are given on the command line, only files in these
5537 directories are considered.
5531 directories are considered.
5538
5532
5539 Be careful with purge, as you could irreversibly delete some files
5533 Be careful with purge, as you could irreversibly delete some files
5540 you forgot to add to the repository. If you only want to print the
5534 you forgot to add to the repository. If you only want to print the
5541 list of files that this program would delete, use the --print
5535 list of files that this program would delete, use the --print
5542 option.
5536 option.
5543 """
5537 """
5544 opts = pycompat.byteskwargs(opts)
5538 opts = pycompat.byteskwargs(opts)
5545 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5539 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5546
5540
5547 act = not opts.get(b'print')
5541 act = not opts.get(b'print')
5548 eol = b'\n'
5542 eol = b'\n'
5549 if opts.get(b'print0'):
5543 if opts.get(b'print0'):
5550 eol = b'\0'
5544 eol = b'\0'
5551 act = False # --print0 implies --print
5545 act = False # --print0 implies --print
5552 if opts.get(b'all', False):
5546 if opts.get(b'all', False):
5553 ignored = True
5547 ignored = True
5554 unknown = True
5548 unknown = True
5555 else:
5549 else:
5556 ignored = opts.get(b'ignored', False)
5550 ignored = opts.get(b'ignored', False)
5557 unknown = not ignored
5551 unknown = not ignored
5558
5552
5559 removefiles = opts.get(b'files')
5553 removefiles = opts.get(b'files')
5560 removedirs = opts.get(b'dirs')
5554 removedirs = opts.get(b'dirs')
5561 confirm = opts.get(b'confirm')
5555 confirm = opts.get(b'confirm')
5562 if confirm is None:
5556 if confirm is None:
5563 try:
5557 try:
5564 extensions.find(b'purge')
5558 extensions.find(b'purge')
5565 confirm = False
5559 confirm = False
5566 except KeyError:
5560 except KeyError:
5567 confirm = True
5561 confirm = True
5568
5562
5569 if not removefiles and not removedirs:
5563 if not removefiles and not removedirs:
5570 removefiles = True
5564 removefiles = True
5571 removedirs = True
5565 removedirs = True
5572
5566
5573 match = scmutil.match(repo[None], dirs, opts)
5567 match = scmutil.match(repo[None], dirs, opts)
5574
5568
5575 paths = mergemod.purge(
5569 paths = mergemod.purge(
5576 repo,
5570 repo,
5577 match,
5571 match,
5578 unknown=unknown,
5572 unknown=unknown,
5579 ignored=ignored,
5573 ignored=ignored,
5580 removeemptydirs=removedirs,
5574 removeemptydirs=removedirs,
5581 removefiles=removefiles,
5575 removefiles=removefiles,
5582 abortonerror=opts.get(b'abort_on_err'),
5576 abortonerror=opts.get(b'abort_on_err'),
5583 noop=not act,
5577 noop=not act,
5584 confirm=confirm,
5578 confirm=confirm,
5585 )
5579 )
5586
5580
5587 for path in paths:
5581 for path in paths:
5588 if not act:
5582 if not act:
5589 ui.write(b'%s%s' % (path, eol))
5583 ui.write(b'%s%s' % (path, eol))
5590
5584
5591
5585
5592 @command(
5586 @command(
5593 b'push',
5587 b'push',
5594 [
5588 [
5595 (b'f', b'force', None, _(b'force push')),
5589 (b'f', b'force', None, _(b'force push')),
5596 (
5590 (
5597 b'r',
5591 b'r',
5598 b'rev',
5592 b'rev',
5599 [],
5593 [],
5600 _(b'a changeset intended to be included in the destination'),
5594 _(b'a changeset intended to be included in the destination'),
5601 _(b'REV'),
5595 _(b'REV'),
5602 ),
5596 ),
5603 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5597 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5604 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5598 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5605 (
5599 (
5606 b'b',
5600 b'b',
5607 b'branch',
5601 b'branch',
5608 [],
5602 [],
5609 _(b'a specific branch you would like to push'),
5603 _(b'a specific branch you would like to push'),
5610 _(b'BRANCH'),
5604 _(b'BRANCH'),
5611 ),
5605 ),
5612 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5606 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5613 (
5607 (
5614 b'',
5608 b'',
5615 b'pushvars',
5609 b'pushvars',
5616 [],
5610 [],
5617 _(b'variables that can be sent to server (ADVANCED)'),
5611 _(b'variables that can be sent to server (ADVANCED)'),
5618 ),
5612 ),
5619 (
5613 (
5620 b'',
5614 b'',
5621 b'publish',
5615 b'publish',
5622 False,
5616 False,
5623 _(b'push the changeset as public (EXPERIMENTAL)'),
5617 _(b'push the changeset as public (EXPERIMENTAL)'),
5624 ),
5618 ),
5625 ]
5619 ]
5626 + remoteopts,
5620 + remoteopts,
5627 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5621 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5628 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5622 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5629 helpbasic=True,
5623 helpbasic=True,
5630 )
5624 )
5631 def push(ui, repo, *dests, **opts):
5625 def push(ui, repo, *dests, **opts):
5632 """push changes to the specified destination
5626 """push changes to the specified destination
5633
5627
5634 Push changesets from the local repository to the specified
5628 Push changesets from the local repository to the specified
5635 destination.
5629 destination.
5636
5630
5637 This operation is symmetrical to pull: it is identical to a pull
5631 This operation is symmetrical to pull: it is identical to a pull
5638 in the destination repository from the current one.
5632 in the destination repository from the current one.
5639
5633
5640 By default, push will not allow creation of new heads at the
5634 By default, push will not allow creation of new heads at the
5641 destination, since multiple heads would make it unclear which head
5635 destination, since multiple heads would make it unclear which head
5642 to use. In this situation, it is recommended to pull and merge
5636 to use. In this situation, it is recommended to pull and merge
5643 before pushing.
5637 before pushing.
5644
5638
5645 Use --new-branch if you want to allow push to create a new named
5639 Use --new-branch if you want to allow push to create a new named
5646 branch that is not present at the destination. This allows you to
5640 branch that is not present at the destination. This allows you to
5647 only create a new branch without forcing other changes.
5641 only create a new branch without forcing other changes.
5648
5642
5649 .. note::
5643 .. note::
5650
5644
5651 Extra care should be taken with the -f/--force option,
5645 Extra care should be taken with the -f/--force option,
5652 which will push all new heads on all branches, an action which will
5646 which will push all new heads on all branches, an action which will
5653 almost always cause confusion for collaborators.
5647 almost always cause confusion for collaborators.
5654
5648
5655 If -r/--rev is used, the specified revision and all its ancestors
5649 If -r/--rev is used, the specified revision and all its ancestors
5656 will be pushed to the remote repository.
5650 will be pushed to the remote repository.
5657
5651
5658 If -B/--bookmark is used, the specified bookmarked revision, its
5652 If -B/--bookmark is used, the specified bookmarked revision, its
5659 ancestors, and the bookmark will be pushed to the remote
5653 ancestors, and the bookmark will be pushed to the remote
5660 repository. Specifying ``.`` is equivalent to specifying the active
5654 repository. Specifying ``.`` is equivalent to specifying the active
5661 bookmark's name. Use the --all-bookmarks option for pushing all
5655 bookmark's name. Use the --all-bookmarks option for pushing all
5662 current bookmarks.
5656 current bookmarks.
5663
5657
5664 Please see :hg:`help urls` for important details about ``ssh://``
5658 Please see :hg:`help urls` for important details about ``ssh://``
5665 URLs. If DESTINATION is omitted, a default path will be used.
5659 URLs. If DESTINATION is omitted, a default path will be used.
5666
5660
5667 When passed multiple destinations, push will process them one after the
5661 When passed multiple destinations, push will process them one after the
5668 other, but stop should an error occur.
5662 other, but stop should an error occur.
5669
5663
5670 .. container:: verbose
5664 .. container:: verbose
5671
5665
5672 The --pushvars option sends strings to the server that become
5666 The --pushvars option sends strings to the server that become
5673 environment variables prepended with ``HG_USERVAR_``. For example,
5667 environment variables prepended with ``HG_USERVAR_``. For example,
5674 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5668 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5675 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5669 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5676
5670
5677 pushvars can provide for user-overridable hooks as well as set debug
5671 pushvars can provide for user-overridable hooks as well as set debug
5678 levels. One example is having a hook that blocks commits containing
5672 levels. One example is having a hook that blocks commits containing
5679 conflict markers, but enables the user to override the hook if the file
5673 conflict markers, but enables the user to override the hook if the file
5680 is using conflict markers for testing purposes or the file format has
5674 is using conflict markers for testing purposes or the file format has
5681 strings that look like conflict markers.
5675 strings that look like conflict markers.
5682
5676
5683 By default, servers will ignore `--pushvars`. To enable it add the
5677 By default, servers will ignore `--pushvars`. To enable it add the
5684 following to your configuration file::
5678 following to your configuration file::
5685
5679
5686 [push]
5680 [push]
5687 pushvars.server = true
5681 pushvars.server = true
5688
5682
5689 Returns 0 if push was successful, 1 if nothing to push.
5683 Returns 0 if push was successful, 1 if nothing to push.
5690 """
5684 """
5691
5685
5692 opts = pycompat.byteskwargs(opts)
5686 opts = pycompat.byteskwargs(opts)
5693
5687
5694 if opts.get(b'all_bookmarks'):
5688 if opts.get(b'all_bookmarks'):
5695 cmdutil.check_incompatible_arguments(
5689 cmdutil.check_incompatible_arguments(
5696 opts,
5690 opts,
5697 b'all_bookmarks',
5691 b'all_bookmarks',
5698 [b'bookmark', b'rev'],
5692 [b'bookmark', b'rev'],
5699 )
5693 )
5700 opts[b'bookmark'] = list(repo._bookmarks)
5694 opts[b'bookmark'] = list(repo._bookmarks)
5701
5695
5702 if opts.get(b'bookmark'):
5696 if opts.get(b'bookmark'):
5703 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5697 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5704 for b in opts[b'bookmark']:
5698 for b in opts[b'bookmark']:
5705 # translate -B options to -r so changesets get pushed
5699 # translate -B options to -r so changesets get pushed
5706 b = repo._bookmarks.expandname(b)
5700 b = repo._bookmarks.expandname(b)
5707 if b in repo._bookmarks:
5701 if b in repo._bookmarks:
5708 opts.setdefault(b'rev', []).append(b)
5702 opts.setdefault(b'rev', []).append(b)
5709 else:
5703 else:
5710 # if we try to push a deleted bookmark, translate it to null
5704 # if we try to push a deleted bookmark, translate it to null
5711 # this lets simultaneous -r, -b options continue working
5705 # this lets simultaneous -r, -b options continue working
5712 opts.setdefault(b'rev', []).append(b"null")
5706 opts.setdefault(b'rev', []).append(b"null")
5713
5707
5714 some_pushed = False
5708 some_pushed = False
5715 result = 0
5709 result = 0
5716 for path in urlutil.get_push_paths(repo, ui, dests):
5710 for path in urlutil.get_push_paths(repo, ui, dests):
5717 dest = path.pushloc or path.loc
5711 dest = path.pushloc or path.loc
5718 branches = (path.branch, opts.get(b'branch') or [])
5712 branches = (path.branch, opts.get(b'branch') or [])
5719 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5713 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5720 revs, checkout = hg.addbranchrevs(
5714 revs, checkout = hg.addbranchrevs(
5721 repo, repo, branches, opts.get(b'rev')
5715 repo, repo, branches, opts.get(b'rev')
5722 )
5716 )
5723 other = hg.peer(repo, opts, dest)
5717 other = hg.peer(repo, opts, dest)
5724
5718
5725 try:
5719 try:
5726 if revs:
5720 if revs:
5727 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5721 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5728 if not revs:
5722 if not revs:
5729 raise error.InputError(
5723 raise error.InputError(
5730 _(b"specified revisions evaluate to an empty set"),
5724 _(b"specified revisions evaluate to an empty set"),
5731 hint=_(b"use different revision arguments"),
5725 hint=_(b"use different revision arguments"),
5732 )
5726 )
5733 elif path.pushrev:
5727 elif path.pushrev:
5734 # It doesn't make any sense to specify ancestor revisions. So limit
5728 # It doesn't make any sense to specify ancestor revisions. So limit
5735 # to DAG heads to make discovery simpler.
5729 # to DAG heads to make discovery simpler.
5736 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5730 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5737 revs = scmutil.revrange(repo, [expr])
5731 revs = scmutil.revrange(repo, [expr])
5738 revs = [repo[rev].node() for rev in revs]
5732 revs = [repo[rev].node() for rev in revs]
5739 if not revs:
5733 if not revs:
5740 raise error.InputError(
5734 raise error.InputError(
5741 _(
5735 _(
5742 b'default push revset for path evaluates to an empty set'
5736 b'default push revset for path evaluates to an empty set'
5743 )
5737 )
5744 )
5738 )
5745 elif ui.configbool(b'commands', b'push.require-revs'):
5739 elif ui.configbool(b'commands', b'push.require-revs'):
5746 raise error.InputError(
5740 raise error.InputError(
5747 _(b'no revisions specified to push'),
5741 _(b'no revisions specified to push'),
5748 hint=_(b'did you mean "hg push -r ."?'),
5742 hint=_(b'did you mean "hg push -r ."?'),
5749 )
5743 )
5750
5744
5751 repo._subtoppath = dest
5745 repo._subtoppath = dest
5752 try:
5746 try:
5753 # push subrepos depth-first for coherent ordering
5747 # push subrepos depth-first for coherent ordering
5754 c = repo[b'.']
5748 c = repo[b'.']
5755 subs = c.substate # only repos that are committed
5749 subs = c.substate # only repos that are committed
5756 for s in sorted(subs):
5750 for s in sorted(subs):
5757 sub_result = c.sub(s).push(opts)
5751 sub_result = c.sub(s).push(opts)
5758 if sub_result == 0:
5752 if sub_result == 0:
5759 return 1
5753 return 1
5760 finally:
5754 finally:
5761 del repo._subtoppath
5755 del repo._subtoppath
5762
5756
5763 opargs = dict(
5757 opargs = dict(
5764 opts.get(b'opargs', {})
5758 opts.get(b'opargs', {})
5765 ) # copy opargs since we may mutate it
5759 ) # copy opargs since we may mutate it
5766 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5760 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5767
5761
5768 pushop = exchange.push(
5762 pushop = exchange.push(
5769 repo,
5763 repo,
5770 other,
5764 other,
5771 opts.get(b'force'),
5765 opts.get(b'force'),
5772 revs=revs,
5766 revs=revs,
5773 newbranch=opts.get(b'new_branch'),
5767 newbranch=opts.get(b'new_branch'),
5774 bookmarks=opts.get(b'bookmark', ()),
5768 bookmarks=opts.get(b'bookmark', ()),
5775 publish=opts.get(b'publish'),
5769 publish=opts.get(b'publish'),
5776 opargs=opargs,
5770 opargs=opargs,
5777 )
5771 )
5778
5772
5779 if pushop.cgresult == 0:
5773 if pushop.cgresult == 0:
5780 result = 1
5774 result = 1
5781 elif pushop.cgresult is not None:
5775 elif pushop.cgresult is not None:
5782 some_pushed = True
5776 some_pushed = True
5783
5777
5784 if pushop.bkresult is not None:
5778 if pushop.bkresult is not None:
5785 if pushop.bkresult == 2:
5779 if pushop.bkresult == 2:
5786 result = 2
5780 result = 2
5787 elif not result and pushop.bkresult:
5781 elif not result and pushop.bkresult:
5788 result = 2
5782 result = 2
5789
5783
5790 if result:
5784 if result:
5791 break
5785 break
5792
5786
5793 finally:
5787 finally:
5794 other.close()
5788 other.close()
5795 if result == 0 and not some_pushed:
5789 if result == 0 and not some_pushed:
5796 result = 1
5790 result = 1
5797 return result
5791 return result
5798
5792
5799
5793
5800 @command(
5794 @command(
5801 b'recover',
5795 b'recover',
5802 [
5796 [
5803 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5797 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5804 ],
5798 ],
5805 helpcategory=command.CATEGORY_MAINTENANCE,
5799 helpcategory=command.CATEGORY_MAINTENANCE,
5806 )
5800 )
5807 def recover(ui, repo, **opts):
5801 def recover(ui, repo, **opts):
5808 """roll back an interrupted transaction
5802 """roll back an interrupted transaction
5809
5803
5810 Recover from an interrupted commit or pull.
5804 Recover from an interrupted commit or pull.
5811
5805
5812 This command tries to fix the repository status after an
5806 This command tries to fix the repository status after an
5813 interrupted operation. It should only be necessary when Mercurial
5807 interrupted operation. It should only be necessary when Mercurial
5814 suggests it.
5808 suggests it.
5815
5809
5816 Returns 0 if successful, 1 if nothing to recover or verify fails.
5810 Returns 0 if successful, 1 if nothing to recover or verify fails.
5817 """
5811 """
5818 ret = repo.recover()
5812 ret = repo.recover()
5819 if ret:
5813 if ret:
5820 if opts['verify']:
5814 if opts['verify']:
5821 return hg.verify(repo)
5815 return hg.verify(repo)
5822 else:
5816 else:
5823 msg = _(
5817 msg = _(
5824 b"(verify step skipped, run `hg verify` to check your "
5818 b"(verify step skipped, run `hg verify` to check your "
5825 b"repository content)\n"
5819 b"repository content)\n"
5826 )
5820 )
5827 ui.warn(msg)
5821 ui.warn(msg)
5828 return 0
5822 return 0
5829 return 1
5823 return 1
5830
5824
5831
5825
5832 @command(
5826 @command(
5833 b'remove|rm',
5827 b'remove|rm',
5834 [
5828 [
5835 (b'A', b'after', None, _(b'record delete for missing files')),
5829 (b'A', b'after', None, _(b'record delete for missing files')),
5836 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5830 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5837 ]
5831 ]
5838 + subrepoopts
5832 + subrepoopts
5839 + walkopts
5833 + walkopts
5840 + dryrunopts,
5834 + dryrunopts,
5841 _(b'[OPTION]... FILE...'),
5835 _(b'[OPTION]... FILE...'),
5842 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5836 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5843 helpbasic=True,
5837 helpbasic=True,
5844 inferrepo=True,
5838 inferrepo=True,
5845 )
5839 )
5846 def remove(ui, repo, *pats, **opts):
5840 def remove(ui, repo, *pats, **opts):
5847 """remove the specified files on the next commit
5841 """remove the specified files on the next commit
5848
5842
5849 Schedule the indicated files for removal from the current branch.
5843 Schedule the indicated files for removal from the current branch.
5850
5844
5851 This command schedules the files to be removed at the next commit.
5845 This command schedules the files to be removed at the next commit.
5852 To undo a remove before that, see :hg:`revert`. To undo added
5846 To undo a remove before that, see :hg:`revert`. To undo added
5853 files, see :hg:`forget`.
5847 files, see :hg:`forget`.
5854
5848
5855 .. container:: verbose
5849 .. container:: verbose
5856
5850
5857 -A/--after can be used to remove only files that have already
5851 -A/--after can be used to remove only files that have already
5858 been deleted, -f/--force can be used to force deletion, and -Af
5852 been deleted, -f/--force can be used to force deletion, and -Af
5859 can be used to remove files from the next revision without
5853 can be used to remove files from the next revision without
5860 deleting them from the working directory.
5854 deleting them from the working directory.
5861
5855
5862 The following table details the behavior of remove for different
5856 The following table details the behavior of remove for different
5863 file states (columns) and option combinations (rows). The file
5857 file states (columns) and option combinations (rows). The file
5864 states are Added [A], Clean [C], Modified [M] and Missing [!]
5858 states are Added [A], Clean [C], Modified [M] and Missing [!]
5865 (as reported by :hg:`status`). The actions are Warn, Remove
5859 (as reported by :hg:`status`). The actions are Warn, Remove
5866 (from branch) and Delete (from disk):
5860 (from branch) and Delete (from disk):
5867
5861
5868 ========= == == == ==
5862 ========= == == == ==
5869 opt/state A C M !
5863 opt/state A C M !
5870 ========= == == == ==
5864 ========= == == == ==
5871 none W RD W R
5865 none W RD W R
5872 -f R RD RD R
5866 -f R RD RD R
5873 -A W W W R
5867 -A W W W R
5874 -Af R R R R
5868 -Af R R R R
5875 ========= == == == ==
5869 ========= == == == ==
5876
5870
5877 .. note::
5871 .. note::
5878
5872
5879 :hg:`remove` never deletes files in Added [A] state from the
5873 :hg:`remove` never deletes files in Added [A] state from the
5880 working directory, not even if ``--force`` is specified.
5874 working directory, not even if ``--force`` is specified.
5881
5875
5882 Returns 0 on success, 1 if any warnings encountered.
5876 Returns 0 on success, 1 if any warnings encountered.
5883 """
5877 """
5884
5878
5885 opts = pycompat.byteskwargs(opts)
5879 opts = pycompat.byteskwargs(opts)
5886 after, force = opts.get(b'after'), opts.get(b'force')
5880 after, force = opts.get(b'after'), opts.get(b'force')
5887 dryrun = opts.get(b'dry_run')
5881 dryrun = opts.get(b'dry_run')
5888 if not pats and not after:
5882 if not pats and not after:
5889 raise error.InputError(_(b'no files specified'))
5883 raise error.InputError(_(b'no files specified'))
5890
5884
5891 m = scmutil.match(repo[None], pats, opts)
5885 m = scmutil.match(repo[None], pats, opts)
5892 subrepos = opts.get(b'subrepos')
5886 subrepos = opts.get(b'subrepos')
5893 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5887 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5894 return cmdutil.remove(
5888 return cmdutil.remove(
5895 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5889 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5896 )
5890 )
5897
5891
5898
5892
5899 @command(
5893 @command(
5900 b'rename|move|mv',
5894 b'rename|move|mv',
5901 [
5895 [
5902 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5896 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5903 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5897 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5904 (
5898 (
5905 b'',
5899 b'',
5906 b'at-rev',
5900 b'at-rev',
5907 b'',
5901 b'',
5908 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5902 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5909 _(b'REV'),
5903 _(b'REV'),
5910 ),
5904 ),
5911 (
5905 (
5912 b'f',
5906 b'f',
5913 b'force',
5907 b'force',
5914 None,
5908 None,
5915 _(b'forcibly move over an existing managed file'),
5909 _(b'forcibly move over an existing managed file'),
5916 ),
5910 ),
5917 ]
5911 ]
5918 + walkopts
5912 + walkopts
5919 + dryrunopts,
5913 + dryrunopts,
5920 _(b'[OPTION]... SOURCE... DEST'),
5914 _(b'[OPTION]... SOURCE... DEST'),
5921 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5915 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5922 )
5916 )
5923 def rename(ui, repo, *pats, **opts):
5917 def rename(ui, repo, *pats, **opts):
5924 """rename files; equivalent of copy + remove
5918 """rename files; equivalent of copy + remove
5925
5919
5926 Mark dest as copies of sources; mark sources for deletion. If dest
5920 Mark dest as copies of sources; mark sources for deletion. If dest
5927 is a directory, copies are put in that directory. If dest is a
5921 is a directory, copies are put in that directory. If dest is a
5928 file, there can only be one source.
5922 file, there can only be one source.
5929
5923
5930 By default, this command copies the contents of files as they
5924 By default, this command copies the contents of files as they
5931 exist in the working directory. If invoked with -A/--after, the
5925 exist in the working directory. If invoked with -A/--after, the
5932 operation is recorded, but no copying is performed.
5926 operation is recorded, but no copying is performed.
5933
5927
5934 To undo marking a destination file as renamed, use --forget. With that
5928 To undo marking a destination file as renamed, use --forget. With that
5935 option, all given (positional) arguments are unmarked as renames. The
5929 option, all given (positional) arguments are unmarked as renames. The
5936 destination file(s) will be left in place (still tracked). The source
5930 destination file(s) will be left in place (still tracked). The source
5937 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5931 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5938 the same way as :hg:`copy --forget`.
5932 the same way as :hg:`copy --forget`.
5939
5933
5940 This command takes effect with the next commit by default.
5934 This command takes effect with the next commit by default.
5941
5935
5942 Returns 0 on success, 1 if errors are encountered.
5936 Returns 0 on success, 1 if errors are encountered.
5943 """
5937 """
5944 opts = pycompat.byteskwargs(opts)
5938 opts = pycompat.byteskwargs(opts)
5945 with repo.wlock():
5939 with repo.wlock():
5946 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5940 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5947
5941
5948
5942
5949 @command(
5943 @command(
5950 b'resolve',
5944 b'resolve',
5951 [
5945 [
5952 (b'a', b'all', None, _(b'select all unresolved files')),
5946 (b'a', b'all', None, _(b'select all unresolved files')),
5953 (b'l', b'list', None, _(b'list state of files needing merge')),
5947 (b'l', b'list', None, _(b'list state of files needing merge')),
5954 (b'm', b'mark', None, _(b'mark files as resolved')),
5948 (b'm', b'mark', None, _(b'mark files as resolved')),
5955 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5949 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5956 (b'n', b'no-status', None, _(b'hide status prefix')),
5950 (b'n', b'no-status', None, _(b'hide status prefix')),
5957 (b'', b're-merge', None, _(b're-merge files')),
5951 (b'', b're-merge', None, _(b're-merge files')),
5958 ]
5952 ]
5959 + mergetoolopts
5953 + mergetoolopts
5960 + walkopts
5954 + walkopts
5961 + formatteropts,
5955 + formatteropts,
5962 _(b'[OPTION]... [FILE]...'),
5956 _(b'[OPTION]... [FILE]...'),
5963 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5957 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5964 inferrepo=True,
5958 inferrepo=True,
5965 )
5959 )
5966 def resolve(ui, repo, *pats, **opts):
5960 def resolve(ui, repo, *pats, **opts):
5967 """redo merges or set/view the merge status of files
5961 """redo merges or set/view the merge status of files
5968
5962
5969 Merges with unresolved conflicts are often the result of
5963 Merges with unresolved conflicts are often the result of
5970 non-interactive merging using the ``internal:merge`` configuration
5964 non-interactive merging using the ``internal:merge`` configuration
5971 setting, or a command-line merge tool like ``diff3``. The resolve
5965 setting, or a command-line merge tool like ``diff3``. The resolve
5972 command is used to manage the files involved in a merge, after
5966 command is used to manage the files involved in a merge, after
5973 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5967 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5974 working directory must have two parents). See :hg:`help
5968 working directory must have two parents). See :hg:`help
5975 merge-tools` for information on configuring merge tools.
5969 merge-tools` for information on configuring merge tools.
5976
5970
5977 The resolve command can be used in the following ways:
5971 The resolve command can be used in the following ways:
5978
5972
5979 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5973 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5980 the specified files, discarding any previous merge attempts. Re-merging
5974 the specified files, discarding any previous merge attempts. Re-merging
5981 is not performed for files already marked as resolved. Use ``--all/-a``
5975 is not performed for files already marked as resolved. Use ``--all/-a``
5982 to select all unresolved files. ``--tool`` can be used to specify
5976 to select all unresolved files. ``--tool`` can be used to specify
5983 the merge tool used for the given files. It overrides the HGMERGE
5977 the merge tool used for the given files. It overrides the HGMERGE
5984 environment variable and your configuration files. Previous file
5978 environment variable and your configuration files. Previous file
5985 contents are saved with a ``.orig`` suffix.
5979 contents are saved with a ``.orig`` suffix.
5986
5980
5987 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5981 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5988 (e.g. after having manually fixed-up the files). The default is
5982 (e.g. after having manually fixed-up the files). The default is
5989 to mark all unresolved files.
5983 to mark all unresolved files.
5990
5984
5991 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5985 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5992 default is to mark all resolved files.
5986 default is to mark all resolved files.
5993
5987
5994 - :hg:`resolve -l`: list files which had or still have conflicts.
5988 - :hg:`resolve -l`: list files which had or still have conflicts.
5995 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5989 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5996 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5990 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5997 the list. See :hg:`help filesets` for details.
5991 the list. See :hg:`help filesets` for details.
5998
5992
5999 .. note::
5993 .. note::
6000
5994
6001 Mercurial will not let you commit files with unresolved merge
5995 Mercurial will not let you commit files with unresolved merge
6002 conflicts. You must use :hg:`resolve -m ...` before you can
5996 conflicts. You must use :hg:`resolve -m ...` before you can
6003 commit after a conflicting merge.
5997 commit after a conflicting merge.
6004
5998
6005 .. container:: verbose
5999 .. container:: verbose
6006
6000
6007 Template:
6001 Template:
6008
6002
6009 The following keywords are supported in addition to the common template
6003 The following keywords are supported in addition to the common template
6010 keywords and functions. See also :hg:`help templates`.
6004 keywords and functions. See also :hg:`help templates`.
6011
6005
6012 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6006 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6013 :path: String. Repository-absolute path of the file.
6007 :path: String. Repository-absolute path of the file.
6014
6008
6015 Returns 0 on success, 1 if any files fail a resolve attempt.
6009 Returns 0 on success, 1 if any files fail a resolve attempt.
6016 """
6010 """
6017
6011
6018 opts = pycompat.byteskwargs(opts)
6012 opts = pycompat.byteskwargs(opts)
6019 confirm = ui.configbool(b'commands', b'resolve.confirm')
6013 confirm = ui.configbool(b'commands', b'resolve.confirm')
6020 flaglist = b'all mark unmark list no_status re_merge'.split()
6014 flaglist = b'all mark unmark list no_status re_merge'.split()
6021 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6015 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6022
6016
6023 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6017 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6024 if actioncount > 1:
6018 if actioncount > 1:
6025 raise error.InputError(_(b"too many actions specified"))
6019 raise error.InputError(_(b"too many actions specified"))
6026 elif actioncount == 0 and ui.configbool(
6020 elif actioncount == 0 and ui.configbool(
6027 b'commands', b'resolve.explicit-re-merge'
6021 b'commands', b'resolve.explicit-re-merge'
6028 ):
6022 ):
6029 hint = _(b'use --mark, --unmark, --list or --re-merge')
6023 hint = _(b'use --mark, --unmark, --list or --re-merge')
6030 raise error.InputError(_(b'no action specified'), hint=hint)
6024 raise error.InputError(_(b'no action specified'), hint=hint)
6031 if pats and all:
6025 if pats and all:
6032 raise error.InputError(_(b"can't specify --all and patterns"))
6026 raise error.InputError(_(b"can't specify --all and patterns"))
6033 if not (all or pats or show or mark or unmark):
6027 if not (all or pats or show or mark or unmark):
6034 raise error.InputError(
6028 raise error.InputError(
6035 _(b'no files or directories specified'),
6029 _(b'no files or directories specified'),
6036 hint=b'use --all to re-merge all unresolved files',
6030 hint=b'use --all to re-merge all unresolved files',
6037 )
6031 )
6038
6032
6039 if confirm:
6033 if confirm:
6040 if all:
6034 if all:
6041 if ui.promptchoice(
6035 if ui.promptchoice(
6042 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6036 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6043 ):
6037 ):
6044 raise error.CanceledError(_(b'user quit'))
6038 raise error.CanceledError(_(b'user quit'))
6045 if mark and not pats:
6039 if mark and not pats:
6046 if ui.promptchoice(
6040 if ui.promptchoice(
6047 _(
6041 _(
6048 b'mark all unresolved files as resolved (yn)?'
6042 b'mark all unresolved files as resolved (yn)?'
6049 b'$$ &Yes $$ &No'
6043 b'$$ &Yes $$ &No'
6050 )
6044 )
6051 ):
6045 ):
6052 raise error.CanceledError(_(b'user quit'))
6046 raise error.CanceledError(_(b'user quit'))
6053 if unmark and not pats:
6047 if unmark and not pats:
6054 if ui.promptchoice(
6048 if ui.promptchoice(
6055 _(
6049 _(
6056 b'mark all resolved files as unresolved (yn)?'
6050 b'mark all resolved files as unresolved (yn)?'
6057 b'$$ &Yes $$ &No'
6051 b'$$ &Yes $$ &No'
6058 )
6052 )
6059 ):
6053 ):
6060 raise error.CanceledError(_(b'user quit'))
6054 raise error.CanceledError(_(b'user quit'))
6061
6055
6062 uipathfn = scmutil.getuipathfn(repo)
6056 uipathfn = scmutil.getuipathfn(repo)
6063
6057
6064 if show:
6058 if show:
6065 ui.pager(b'resolve')
6059 ui.pager(b'resolve')
6066 fm = ui.formatter(b'resolve', opts)
6060 fm = ui.formatter(b'resolve', opts)
6067 ms = mergestatemod.mergestate.read(repo)
6061 ms = mergestatemod.mergestate.read(repo)
6068 wctx = repo[None]
6062 wctx = repo[None]
6069 m = scmutil.match(wctx, pats, opts)
6063 m = scmutil.match(wctx, pats, opts)
6070
6064
6071 # Labels and keys based on merge state. Unresolved path conflicts show
6065 # Labels and keys based on merge state. Unresolved path conflicts show
6072 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6066 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6073 # resolved conflicts.
6067 # resolved conflicts.
6074 mergestateinfo = {
6068 mergestateinfo = {
6075 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6069 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6076 b'resolve.unresolved',
6070 b'resolve.unresolved',
6077 b'U',
6071 b'U',
6078 ),
6072 ),
6079 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6073 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6080 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6074 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6081 b'resolve.unresolved',
6075 b'resolve.unresolved',
6082 b'P',
6076 b'P',
6083 ),
6077 ),
6084 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6078 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6085 b'resolve.resolved',
6079 b'resolve.resolved',
6086 b'R',
6080 b'R',
6087 ),
6081 ),
6088 }
6082 }
6089
6083
6090 for f in ms:
6084 for f in ms:
6091 if not m(f):
6085 if not m(f):
6092 continue
6086 continue
6093
6087
6094 label, key = mergestateinfo[ms[f]]
6088 label, key = mergestateinfo[ms[f]]
6095 fm.startitem()
6089 fm.startitem()
6096 fm.context(ctx=wctx)
6090 fm.context(ctx=wctx)
6097 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6091 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6098 fm.data(path=f)
6092 fm.data(path=f)
6099 fm.plain(b'%s\n' % uipathfn(f), label=label)
6093 fm.plain(b'%s\n' % uipathfn(f), label=label)
6100 fm.end()
6094 fm.end()
6101 return 0
6095 return 0
6102
6096
6103 with repo.wlock():
6097 with repo.wlock():
6104 ms = mergestatemod.mergestate.read(repo)
6098 ms = mergestatemod.mergestate.read(repo)
6105
6099
6106 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6100 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6107 raise error.StateError(
6101 raise error.StateError(
6108 _(b'resolve command not applicable when not merging')
6102 _(b'resolve command not applicable when not merging')
6109 )
6103 )
6110
6104
6111 wctx = repo[None]
6105 wctx = repo[None]
6112 m = scmutil.match(wctx, pats, opts)
6106 m = scmutil.match(wctx, pats, opts)
6113 ret = 0
6107 ret = 0
6114 didwork = False
6108 didwork = False
6115
6109
6116 tocomplete = []
6110 tocomplete = []
6117 hasconflictmarkers = []
6111 hasconflictmarkers = []
6118 if mark:
6112 if mark:
6119 markcheck = ui.config(b'commands', b'resolve.mark-check')
6113 markcheck = ui.config(b'commands', b'resolve.mark-check')
6120 if markcheck not in [b'warn', b'abort']:
6114 if markcheck not in [b'warn', b'abort']:
6121 # Treat all invalid / unrecognized values as 'none'.
6115 # Treat all invalid / unrecognized values as 'none'.
6122 markcheck = False
6116 markcheck = False
6123 for f in ms:
6117 for f in ms:
6124 if not m(f):
6118 if not m(f):
6125 continue
6119 continue
6126
6120
6127 didwork = True
6121 didwork = True
6128
6122
6129 # path conflicts must be resolved manually
6123 # path conflicts must be resolved manually
6130 if ms[f] in (
6124 if ms[f] in (
6131 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6125 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6132 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6126 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6133 ):
6127 ):
6134 if mark:
6128 if mark:
6135 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6129 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6136 elif unmark:
6130 elif unmark:
6137 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6131 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6138 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6132 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6139 ui.warn(
6133 ui.warn(
6140 _(b'%s: path conflict must be resolved manually\n')
6134 _(b'%s: path conflict must be resolved manually\n')
6141 % uipathfn(f)
6135 % uipathfn(f)
6142 )
6136 )
6143 continue
6137 continue
6144
6138
6145 if mark:
6139 if mark:
6146 if markcheck:
6140 if markcheck:
6147 fdata = repo.wvfs.tryread(f)
6141 fdata = repo.wvfs.tryread(f)
6148 if (
6142 if (
6149 filemerge.hasconflictmarkers(fdata)
6143 filemerge.hasconflictmarkers(fdata)
6150 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6144 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6151 ):
6145 ):
6152 hasconflictmarkers.append(f)
6146 hasconflictmarkers.append(f)
6153 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6147 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6154 elif unmark:
6148 elif unmark:
6155 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6149 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6156 else:
6150 else:
6157 # backup pre-resolve (merge uses .orig for its own purposes)
6151 # backup pre-resolve (merge uses .orig for its own purposes)
6158 a = repo.wjoin(f)
6152 a = repo.wjoin(f)
6159 try:
6153 try:
6160 util.copyfile(a, a + b".resolve")
6154 util.copyfile(a, a + b".resolve")
6161 except (IOError, OSError) as inst:
6155 except (IOError, OSError) as inst:
6162 if inst.errno != errno.ENOENT:
6156 if inst.errno != errno.ENOENT:
6163 raise
6157 raise
6164
6158
6165 try:
6159 try:
6166 # preresolve file
6160 # preresolve file
6167 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6161 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6168 with ui.configoverride(overrides, b'resolve'):
6162 with ui.configoverride(overrides, b'resolve'):
6169 complete, r = ms.preresolve(f, wctx)
6163 complete, r = ms.preresolve(f, wctx)
6170 if not complete:
6164 if not complete:
6171 tocomplete.append(f)
6165 tocomplete.append(f)
6172 elif r:
6166 elif r:
6173 ret = 1
6167 ret = 1
6174 finally:
6168 finally:
6175 ms.commit()
6169 ms.commit()
6176
6170
6177 # replace filemerge's .orig file with our resolve file, but only
6171 # replace filemerge's .orig file with our resolve file, but only
6178 # for merges that are complete
6172 # for merges that are complete
6179 if complete:
6173 if complete:
6180 try:
6174 try:
6181 util.rename(
6175 util.rename(
6182 a + b".resolve", scmutil.backuppath(ui, repo, f)
6176 a + b".resolve", scmutil.backuppath(ui, repo, f)
6183 )
6177 )
6184 except OSError as inst:
6178 except OSError as inst:
6185 if inst.errno != errno.ENOENT:
6179 if inst.errno != errno.ENOENT:
6186 raise
6180 raise
6187
6181
6188 if hasconflictmarkers:
6182 if hasconflictmarkers:
6189 ui.warn(
6183 ui.warn(
6190 _(
6184 _(
6191 b'warning: the following files still have conflict '
6185 b'warning: the following files still have conflict '
6192 b'markers:\n'
6186 b'markers:\n'
6193 )
6187 )
6194 + b''.join(
6188 + b''.join(
6195 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6189 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6196 )
6190 )
6197 )
6191 )
6198 if markcheck == b'abort' and not all and not pats:
6192 if markcheck == b'abort' and not all and not pats:
6199 raise error.StateError(
6193 raise error.StateError(
6200 _(b'conflict markers detected'),
6194 _(b'conflict markers detected'),
6201 hint=_(b'use --all to mark anyway'),
6195 hint=_(b'use --all to mark anyway'),
6202 )
6196 )
6203
6197
6204 for f in tocomplete:
6198 for f in tocomplete:
6205 try:
6199 try:
6206 # resolve file
6200 # resolve file
6207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6201 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6208 with ui.configoverride(overrides, b'resolve'):
6202 with ui.configoverride(overrides, b'resolve'):
6209 r = ms.resolve(f, wctx)
6203 r = ms.resolve(f, wctx)
6210 if r:
6204 if r:
6211 ret = 1
6205 ret = 1
6212 finally:
6206 finally:
6213 ms.commit()
6207 ms.commit()
6214
6208
6215 # replace filemerge's .orig file with our resolve file
6209 # replace filemerge's .orig file with our resolve file
6216 a = repo.wjoin(f)
6210 a = repo.wjoin(f)
6217 try:
6211 try:
6218 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6212 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6219 except OSError as inst:
6213 except OSError as inst:
6220 if inst.errno != errno.ENOENT:
6214 if inst.errno != errno.ENOENT:
6221 raise
6215 raise
6222
6216
6223 ms.commit()
6217 ms.commit()
6224 branchmerge = repo.dirstate.p2() != repo.nullid
6218 branchmerge = repo.dirstate.p2() != repo.nullid
6225 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6219 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6226
6220
6227 if not didwork and pats:
6221 if not didwork and pats:
6228 hint = None
6222 hint = None
6229 if not any([p for p in pats if p.find(b':') >= 0]):
6223 if not any([p for p in pats if p.find(b':') >= 0]):
6230 pats = [b'path:%s' % p for p in pats]
6224 pats = [b'path:%s' % p for p in pats]
6231 m = scmutil.match(wctx, pats, opts)
6225 m = scmutil.match(wctx, pats, opts)
6232 for f in ms:
6226 for f in ms:
6233 if not m(f):
6227 if not m(f):
6234 continue
6228 continue
6235
6229
6236 def flag(o):
6230 def flag(o):
6237 if o == b're_merge':
6231 if o == b're_merge':
6238 return b'--re-merge '
6232 return b'--re-merge '
6239 return b'-%s ' % o[0:1]
6233 return b'-%s ' % o[0:1]
6240
6234
6241 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6235 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6242 hint = _(b"(try: hg resolve %s%s)\n") % (
6236 hint = _(b"(try: hg resolve %s%s)\n") % (
6243 flags,
6237 flags,
6244 b' '.join(pats),
6238 b' '.join(pats),
6245 )
6239 )
6246 break
6240 break
6247 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6241 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6248 if hint:
6242 if hint:
6249 ui.warn(hint)
6243 ui.warn(hint)
6250
6244
6251 unresolvedf = ms.unresolvedcount()
6245 unresolvedf = ms.unresolvedcount()
6252 if not unresolvedf:
6246 if not unresolvedf:
6253 ui.status(_(b'(no more unresolved files)\n'))
6247 ui.status(_(b'(no more unresolved files)\n'))
6254 cmdutil.checkafterresolved(repo)
6248 cmdutil.checkafterresolved(repo)
6255
6249
6256 return ret
6250 return ret
6257
6251
6258
6252
6259 @command(
6253 @command(
6260 b'revert',
6254 b'revert',
6261 [
6255 [
6262 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6256 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6263 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6257 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6264 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6258 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6265 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6259 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6266 (b'i', b'interactive', None, _(b'interactively select the changes')),
6260 (b'i', b'interactive', None, _(b'interactively select the changes')),
6267 ]
6261 ]
6268 + walkopts
6262 + walkopts
6269 + dryrunopts,
6263 + dryrunopts,
6270 _(b'[OPTION]... [-r REV] [NAME]...'),
6264 _(b'[OPTION]... [-r REV] [NAME]...'),
6271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6272 )
6266 )
6273 def revert(ui, repo, *pats, **opts):
6267 def revert(ui, repo, *pats, **opts):
6274 """restore files to their checkout state
6268 """restore files to their checkout state
6275
6269
6276 .. note::
6270 .. note::
6277
6271
6278 To check out earlier revisions, you should use :hg:`update REV`.
6272 To check out earlier revisions, you should use :hg:`update REV`.
6279 To cancel an uncommitted merge (and lose your changes),
6273 To cancel an uncommitted merge (and lose your changes),
6280 use :hg:`merge --abort`.
6274 use :hg:`merge --abort`.
6281
6275
6282 With no revision specified, revert the specified files or directories
6276 With no revision specified, revert the specified files or directories
6283 to the contents they had in the parent of the working directory.
6277 to the contents they had in the parent of the working directory.
6284 This restores the contents of files to an unmodified
6278 This restores the contents of files to an unmodified
6285 state and unschedules adds, removes, copies, and renames. If the
6279 state and unschedules adds, removes, copies, and renames. If the
6286 working directory has two parents, you must explicitly specify a
6280 working directory has two parents, you must explicitly specify a
6287 revision.
6281 revision.
6288
6282
6289 Using the -r/--rev or -d/--date options, revert the given files or
6283 Using the -r/--rev or -d/--date options, revert the given files or
6290 directories to their states as of a specific revision. Because
6284 directories to their states as of a specific revision. Because
6291 revert does not change the working directory parents, this will
6285 revert does not change the working directory parents, this will
6292 cause these files to appear modified. This can be helpful to "back
6286 cause these files to appear modified. This can be helpful to "back
6293 out" some or all of an earlier change. See :hg:`backout` for a
6287 out" some or all of an earlier change. See :hg:`backout` for a
6294 related method.
6288 related method.
6295
6289
6296 Modified files are saved with a .orig suffix before reverting.
6290 Modified files are saved with a .orig suffix before reverting.
6297 To disable these backups, use --no-backup. It is possible to store
6291 To disable these backups, use --no-backup. It is possible to store
6298 the backup files in a custom directory relative to the root of the
6292 the backup files in a custom directory relative to the root of the
6299 repository by setting the ``ui.origbackuppath`` configuration
6293 repository by setting the ``ui.origbackuppath`` configuration
6300 option.
6294 option.
6301
6295
6302 See :hg:`help dates` for a list of formats valid for -d/--date.
6296 See :hg:`help dates` for a list of formats valid for -d/--date.
6303
6297
6304 See :hg:`help backout` for a way to reverse the effect of an
6298 See :hg:`help backout` for a way to reverse the effect of an
6305 earlier changeset.
6299 earlier changeset.
6306
6300
6307 Returns 0 on success.
6301 Returns 0 on success.
6308 """
6302 """
6309
6303
6310 opts = pycompat.byteskwargs(opts)
6304 opts = pycompat.byteskwargs(opts)
6311 if opts.get(b"date"):
6305 if opts.get(b"date"):
6312 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6306 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6313 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6307 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6314
6308
6315 parent, p2 = repo.dirstate.parents()
6309 parent, p2 = repo.dirstate.parents()
6316 if not opts.get(b'rev') and p2 != repo.nullid:
6310 if not opts.get(b'rev') and p2 != repo.nullid:
6317 # revert after merge is a trap for new users (issue2915)
6311 # revert after merge is a trap for new users (issue2915)
6318 raise error.InputError(
6312 raise error.InputError(
6319 _(b'uncommitted merge with no revision specified'),
6313 _(b'uncommitted merge with no revision specified'),
6320 hint=_(b"use 'hg update' or see 'hg help revert'"),
6314 hint=_(b"use 'hg update' or see 'hg help revert'"),
6321 )
6315 )
6322
6316
6323 rev = opts.get(b'rev')
6317 rev = opts.get(b'rev')
6324 if rev:
6318 if rev:
6325 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6319 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6326 ctx = scmutil.revsingle(repo, rev)
6320 ctx = scmutil.revsingle(repo, rev)
6327
6321
6328 if not (
6322 if not (
6329 pats
6323 pats
6330 or opts.get(b'include')
6324 or opts.get(b'include')
6331 or opts.get(b'exclude')
6325 or opts.get(b'exclude')
6332 or opts.get(b'all')
6326 or opts.get(b'all')
6333 or opts.get(b'interactive')
6327 or opts.get(b'interactive')
6334 ):
6328 ):
6335 msg = _(b"no files or directories specified")
6329 msg = _(b"no files or directories specified")
6336 if p2 != repo.nullid:
6330 if p2 != repo.nullid:
6337 hint = _(
6331 hint = _(
6338 b"uncommitted merge, use --all to discard all changes,"
6332 b"uncommitted merge, use --all to discard all changes,"
6339 b" or 'hg update -C .' to abort the merge"
6333 b" or 'hg update -C .' to abort the merge"
6340 )
6334 )
6341 raise error.InputError(msg, hint=hint)
6335 raise error.InputError(msg, hint=hint)
6342 dirty = any(repo.status())
6336 dirty = any(repo.status())
6343 node = ctx.node()
6337 node = ctx.node()
6344 if node != parent:
6338 if node != parent:
6345 if dirty:
6339 if dirty:
6346 hint = (
6340 hint = (
6347 _(
6341 _(
6348 b"uncommitted changes, use --all to discard all"
6342 b"uncommitted changes, use --all to discard all"
6349 b" changes, or 'hg update %d' to update"
6343 b" changes, or 'hg update %d' to update"
6350 )
6344 )
6351 % ctx.rev()
6345 % ctx.rev()
6352 )
6346 )
6353 else:
6347 else:
6354 hint = (
6348 hint = (
6355 _(
6349 _(
6356 b"use --all to revert all files,"
6350 b"use --all to revert all files,"
6357 b" or 'hg update %d' to update"
6351 b" or 'hg update %d' to update"
6358 )
6352 )
6359 % ctx.rev()
6353 % ctx.rev()
6360 )
6354 )
6361 elif dirty:
6355 elif dirty:
6362 hint = _(b"uncommitted changes, use --all to discard all changes")
6356 hint = _(b"uncommitted changes, use --all to discard all changes")
6363 else:
6357 else:
6364 hint = _(b"use --all to revert all files")
6358 hint = _(b"use --all to revert all files")
6365 raise error.InputError(msg, hint=hint)
6359 raise error.InputError(msg, hint=hint)
6366
6360
6367 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6361 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6368
6362
6369
6363
6370 @command(
6364 @command(
6371 b'rollback',
6365 b'rollback',
6372 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6366 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6373 helpcategory=command.CATEGORY_MAINTENANCE,
6367 helpcategory=command.CATEGORY_MAINTENANCE,
6374 )
6368 )
6375 def rollback(ui, repo, **opts):
6369 def rollback(ui, repo, **opts):
6376 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6370 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6377
6371
6378 Please use :hg:`commit --amend` instead of rollback to correct
6372 Please use :hg:`commit --amend` instead of rollback to correct
6379 mistakes in the last commit.
6373 mistakes in the last commit.
6380
6374
6381 This command should be used with care. There is only one level of
6375 This command should be used with care. There is only one level of
6382 rollback, and there is no way to undo a rollback. It will also
6376 rollback, and there is no way to undo a rollback. It will also
6383 restore the dirstate at the time of the last transaction, losing
6377 restore the dirstate at the time of the last transaction, losing
6384 any dirstate changes since that time. This command does not alter
6378 any dirstate changes since that time. This command does not alter
6385 the working directory.
6379 the working directory.
6386
6380
6387 Transactions are used to encapsulate the effects of all commands
6381 Transactions are used to encapsulate the effects of all commands
6388 that create new changesets or propagate existing changesets into a
6382 that create new changesets or propagate existing changesets into a
6389 repository.
6383 repository.
6390
6384
6391 .. container:: verbose
6385 .. container:: verbose
6392
6386
6393 For example, the following commands are transactional, and their
6387 For example, the following commands are transactional, and their
6394 effects can be rolled back:
6388 effects can be rolled back:
6395
6389
6396 - commit
6390 - commit
6397 - import
6391 - import
6398 - pull
6392 - pull
6399 - push (with this repository as the destination)
6393 - push (with this repository as the destination)
6400 - unbundle
6394 - unbundle
6401
6395
6402 To avoid permanent data loss, rollback will refuse to rollback a
6396 To avoid permanent data loss, rollback will refuse to rollback a
6403 commit transaction if it isn't checked out. Use --force to
6397 commit transaction if it isn't checked out. Use --force to
6404 override this protection.
6398 override this protection.
6405
6399
6406 The rollback command can be entirely disabled by setting the
6400 The rollback command can be entirely disabled by setting the
6407 ``ui.rollback`` configuration setting to false. If you're here
6401 ``ui.rollback`` configuration setting to false. If you're here
6408 because you want to use rollback and it's disabled, you can
6402 because you want to use rollback and it's disabled, you can
6409 re-enable the command by setting ``ui.rollback`` to true.
6403 re-enable the command by setting ``ui.rollback`` to true.
6410
6404
6411 This command is not intended for use on public repositories. Once
6405 This command is not intended for use on public repositories. Once
6412 changes are visible for pull by other users, rolling a transaction
6406 changes are visible for pull by other users, rolling a transaction
6413 back locally is ineffective (someone else may already have pulled
6407 back locally is ineffective (someone else may already have pulled
6414 the changes). Furthermore, a race is possible with readers of the
6408 the changes). Furthermore, a race is possible with readers of the
6415 repository; for example an in-progress pull from the repository
6409 repository; for example an in-progress pull from the repository
6416 may fail if a rollback is performed.
6410 may fail if a rollback is performed.
6417
6411
6418 Returns 0 on success, 1 if no rollback data is available.
6412 Returns 0 on success, 1 if no rollback data is available.
6419 """
6413 """
6420 if not ui.configbool(b'ui', b'rollback'):
6414 if not ui.configbool(b'ui', b'rollback'):
6421 raise error.Abort(
6415 raise error.Abort(
6422 _(b'rollback is disabled because it is unsafe'),
6416 _(b'rollback is disabled because it is unsafe'),
6423 hint=b'see `hg help -v rollback` for information',
6417 hint=b'see `hg help -v rollback` for information',
6424 )
6418 )
6425 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6419 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6426
6420
6427
6421
6428 @command(
6422 @command(
6429 b'root',
6423 b'root',
6430 [] + formatteropts,
6424 [] + formatteropts,
6431 intents={INTENT_READONLY},
6425 intents={INTENT_READONLY},
6432 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6426 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6433 )
6427 )
6434 def root(ui, repo, **opts):
6428 def root(ui, repo, **opts):
6435 """print the root (top) of the current working directory
6429 """print the root (top) of the current working directory
6436
6430
6437 Print the root directory of the current repository.
6431 Print the root directory of the current repository.
6438
6432
6439 .. container:: verbose
6433 .. container:: verbose
6440
6434
6441 Template:
6435 Template:
6442
6436
6443 The following keywords are supported in addition to the common template
6437 The following keywords are supported in addition to the common template
6444 keywords and functions. See also :hg:`help templates`.
6438 keywords and functions. See also :hg:`help templates`.
6445
6439
6446 :hgpath: String. Path to the .hg directory.
6440 :hgpath: String. Path to the .hg directory.
6447 :storepath: String. Path to the directory holding versioned data.
6441 :storepath: String. Path to the directory holding versioned data.
6448
6442
6449 Returns 0 on success.
6443 Returns 0 on success.
6450 """
6444 """
6451 opts = pycompat.byteskwargs(opts)
6445 opts = pycompat.byteskwargs(opts)
6452 with ui.formatter(b'root', opts) as fm:
6446 with ui.formatter(b'root', opts) as fm:
6453 fm.startitem()
6447 fm.startitem()
6454 fm.write(b'reporoot', b'%s\n', repo.root)
6448 fm.write(b'reporoot', b'%s\n', repo.root)
6455 fm.data(hgpath=repo.path, storepath=repo.spath)
6449 fm.data(hgpath=repo.path, storepath=repo.spath)
6456
6450
6457
6451
6458 @command(
6452 @command(
6459 b'serve',
6453 b'serve',
6460 [
6454 [
6461 (
6455 (
6462 b'A',
6456 b'A',
6463 b'accesslog',
6457 b'accesslog',
6464 b'',
6458 b'',
6465 _(b'name of access log file to write to'),
6459 _(b'name of access log file to write to'),
6466 _(b'FILE'),
6460 _(b'FILE'),
6467 ),
6461 ),
6468 (b'd', b'daemon', None, _(b'run server in background')),
6462 (b'd', b'daemon', None, _(b'run server in background')),
6469 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6463 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6470 (
6464 (
6471 b'E',
6465 b'E',
6472 b'errorlog',
6466 b'errorlog',
6473 b'',
6467 b'',
6474 _(b'name of error log file to write to'),
6468 _(b'name of error log file to write to'),
6475 _(b'FILE'),
6469 _(b'FILE'),
6476 ),
6470 ),
6477 # use string type, then we can check if something was passed
6471 # use string type, then we can check if something was passed
6478 (
6472 (
6479 b'p',
6473 b'p',
6480 b'port',
6474 b'port',
6481 b'',
6475 b'',
6482 _(b'port to listen on (default: 8000)'),
6476 _(b'port to listen on (default: 8000)'),
6483 _(b'PORT'),
6477 _(b'PORT'),
6484 ),
6478 ),
6485 (
6479 (
6486 b'a',
6480 b'a',
6487 b'address',
6481 b'address',
6488 b'',
6482 b'',
6489 _(b'address to listen on (default: all interfaces)'),
6483 _(b'address to listen on (default: all interfaces)'),
6490 _(b'ADDR'),
6484 _(b'ADDR'),
6491 ),
6485 ),
6492 (
6486 (
6493 b'',
6487 b'',
6494 b'prefix',
6488 b'prefix',
6495 b'',
6489 b'',
6496 _(b'prefix path to serve from (default: server root)'),
6490 _(b'prefix path to serve from (default: server root)'),
6497 _(b'PREFIX'),
6491 _(b'PREFIX'),
6498 ),
6492 ),
6499 (
6493 (
6500 b'n',
6494 b'n',
6501 b'name',
6495 b'name',
6502 b'',
6496 b'',
6503 _(b'name to show in web pages (default: working directory)'),
6497 _(b'name to show in web pages (default: working directory)'),
6504 _(b'NAME'),
6498 _(b'NAME'),
6505 ),
6499 ),
6506 (
6500 (
6507 b'',
6501 b'',
6508 b'web-conf',
6502 b'web-conf',
6509 b'',
6503 b'',
6510 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6504 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6511 _(b'FILE'),
6505 _(b'FILE'),
6512 ),
6506 ),
6513 (
6507 (
6514 b'',
6508 b'',
6515 b'webdir-conf',
6509 b'webdir-conf',
6516 b'',
6510 b'',
6517 _(b'name of the hgweb config file (DEPRECATED)'),
6511 _(b'name of the hgweb config file (DEPRECATED)'),
6518 _(b'FILE'),
6512 _(b'FILE'),
6519 ),
6513 ),
6520 (
6514 (
6521 b'',
6515 b'',
6522 b'pid-file',
6516 b'pid-file',
6523 b'',
6517 b'',
6524 _(b'name of file to write process ID to'),
6518 _(b'name of file to write process ID to'),
6525 _(b'FILE'),
6519 _(b'FILE'),
6526 ),
6520 ),
6527 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6521 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6528 (
6522 (
6529 b'',
6523 b'',
6530 b'cmdserver',
6524 b'cmdserver',
6531 b'',
6525 b'',
6532 _(b'for remote clients (ADVANCED)'),
6526 _(b'for remote clients (ADVANCED)'),
6533 _(b'MODE'),
6527 _(b'MODE'),
6534 ),
6528 ),
6535 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6529 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6536 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6530 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6537 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6531 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6538 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6532 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6539 (b'', b'print-url', None, _(b'start and print only the URL')),
6533 (b'', b'print-url', None, _(b'start and print only the URL')),
6540 ]
6534 ]
6541 + subrepoopts,
6535 + subrepoopts,
6542 _(b'[OPTION]...'),
6536 _(b'[OPTION]...'),
6543 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6537 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6544 helpbasic=True,
6538 helpbasic=True,
6545 optionalrepo=True,
6539 optionalrepo=True,
6546 )
6540 )
6547 def serve(ui, repo, **opts):
6541 def serve(ui, repo, **opts):
6548 """start stand-alone webserver
6542 """start stand-alone webserver
6549
6543
6550 Start a local HTTP repository browser and pull server. You can use
6544 Start a local HTTP repository browser and pull server. You can use
6551 this for ad-hoc sharing and browsing of repositories. It is
6545 this for ad-hoc sharing and browsing of repositories. It is
6552 recommended to use a real web server to serve a repository for
6546 recommended to use a real web server to serve a repository for
6553 longer periods of time.
6547 longer periods of time.
6554
6548
6555 Please note that the server does not implement access control.
6549 Please note that the server does not implement access control.
6556 This means that, by default, anybody can read from the server and
6550 This means that, by default, anybody can read from the server and
6557 nobody can write to it by default. Set the ``web.allow-push``
6551 nobody can write to it by default. Set the ``web.allow-push``
6558 option to ``*`` to allow everybody to push to the server. You
6552 option to ``*`` to allow everybody to push to the server. You
6559 should use a real web server if you need to authenticate users.
6553 should use a real web server if you need to authenticate users.
6560
6554
6561 By default, the server logs accesses to stdout and errors to
6555 By default, the server logs accesses to stdout and errors to
6562 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6556 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6563 files.
6557 files.
6564
6558
6565 To have the server choose a free port number to listen on, specify
6559 To have the server choose a free port number to listen on, specify
6566 a port number of 0; in this case, the server will print the port
6560 a port number of 0; in this case, the server will print the port
6567 number it uses.
6561 number it uses.
6568
6562
6569 Returns 0 on success.
6563 Returns 0 on success.
6570 """
6564 """
6571
6565
6572 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6566 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6573 opts = pycompat.byteskwargs(opts)
6567 opts = pycompat.byteskwargs(opts)
6574 if opts[b"print_url"] and ui.verbose:
6568 if opts[b"print_url"] and ui.verbose:
6575 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6569 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6576
6570
6577 if opts[b"stdio"]:
6571 if opts[b"stdio"]:
6578 if repo is None:
6572 if repo is None:
6579 raise error.RepoError(
6573 raise error.RepoError(
6580 _(b"there is no Mercurial repository here (.hg not found)")
6574 _(b"there is no Mercurial repository here (.hg not found)")
6581 )
6575 )
6582 s = wireprotoserver.sshserver(ui, repo)
6576 s = wireprotoserver.sshserver(ui, repo)
6583 s.serve_forever()
6577 s.serve_forever()
6584 return
6578 return
6585
6579
6586 service = server.createservice(ui, repo, opts)
6580 service = server.createservice(ui, repo, opts)
6587 return server.runservice(opts, initfn=service.init, runfn=service.run)
6581 return server.runservice(opts, initfn=service.init, runfn=service.run)
6588
6582
6589
6583
6590 @command(
6584 @command(
6591 b'shelve',
6585 b'shelve',
6592 [
6586 [
6593 (
6587 (
6594 b'A',
6588 b'A',
6595 b'addremove',
6589 b'addremove',
6596 None,
6590 None,
6597 _(b'mark new/missing files as added/removed before shelving'),
6591 _(b'mark new/missing files as added/removed before shelving'),
6598 ),
6592 ),
6599 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6593 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6600 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6594 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6601 (
6595 (
6602 b'',
6596 b'',
6603 b'date',
6597 b'date',
6604 b'',
6598 b'',
6605 _(b'shelve with the specified commit date'),
6599 _(b'shelve with the specified commit date'),
6606 _(b'DATE'),
6600 _(b'DATE'),
6607 ),
6601 ),
6608 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6602 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6609 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6603 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6610 (
6604 (
6611 b'k',
6605 b'k',
6612 b'keep',
6606 b'keep',
6613 False,
6607 False,
6614 _(b'shelve, but keep changes in the working directory'),
6608 _(b'shelve, but keep changes in the working directory'),
6615 ),
6609 ),
6616 (b'l', b'list', None, _(b'list current shelves')),
6610 (b'l', b'list', None, _(b'list current shelves')),
6617 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6611 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6618 (
6612 (
6619 b'n',
6613 b'n',
6620 b'name',
6614 b'name',
6621 b'',
6615 b'',
6622 _(b'use the given name for the shelved commit'),
6616 _(b'use the given name for the shelved commit'),
6623 _(b'NAME'),
6617 _(b'NAME'),
6624 ),
6618 ),
6625 (
6619 (
6626 b'p',
6620 b'p',
6627 b'patch',
6621 b'patch',
6628 None,
6622 None,
6629 _(
6623 _(
6630 b'output patches for changes (provide the names of the shelved '
6624 b'output patches for changes (provide the names of the shelved '
6631 b'changes as positional arguments)'
6625 b'changes as positional arguments)'
6632 ),
6626 ),
6633 ),
6627 ),
6634 (b'i', b'interactive', None, _(b'interactive mode')),
6628 (b'i', b'interactive', None, _(b'interactive mode')),
6635 (
6629 (
6636 b'',
6630 b'',
6637 b'stat',
6631 b'stat',
6638 None,
6632 None,
6639 _(
6633 _(
6640 b'output diffstat-style summary of changes (provide the names of '
6634 b'output diffstat-style summary of changes (provide the names of '
6641 b'the shelved changes as positional arguments)'
6635 b'the shelved changes as positional arguments)'
6642 ),
6636 ),
6643 ),
6637 ),
6644 ]
6638 ]
6645 + cmdutil.walkopts,
6639 + cmdutil.walkopts,
6646 _(b'hg shelve [OPTION]... [FILE]...'),
6640 _(b'hg shelve [OPTION]... [FILE]...'),
6647 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6641 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6648 )
6642 )
6649 def shelve(ui, repo, *pats, **opts):
6643 def shelve(ui, repo, *pats, **opts):
6650 """save and set aside changes from the working directory
6644 """save and set aside changes from the working directory
6651
6645
6652 Shelving takes files that "hg status" reports as not clean, saves
6646 Shelving takes files that "hg status" reports as not clean, saves
6653 the modifications to a bundle (a shelved change), and reverts the
6647 the modifications to a bundle (a shelved change), and reverts the
6654 files so that their state in the working directory becomes clean.
6648 files so that their state in the working directory becomes clean.
6655
6649
6656 To restore these changes to the working directory, using "hg
6650 To restore these changes to the working directory, using "hg
6657 unshelve"; this will work even if you switch to a different
6651 unshelve"; this will work even if you switch to a different
6658 commit.
6652 commit.
6659
6653
6660 When no files are specified, "hg shelve" saves all not-clean
6654 When no files are specified, "hg shelve" saves all not-clean
6661 files. If specific files or directories are named, only changes to
6655 files. If specific files or directories are named, only changes to
6662 those files are shelved.
6656 those files are shelved.
6663
6657
6664 In bare shelve (when no files are specified, without interactive,
6658 In bare shelve (when no files are specified, without interactive,
6665 include and exclude option), shelving remembers information if the
6659 include and exclude option), shelving remembers information if the
6666 working directory was on newly created branch, in other words working
6660 working directory was on newly created branch, in other words working
6667 directory was on different branch than its first parent. In this
6661 directory was on different branch than its first parent. In this
6668 situation unshelving restores branch information to the working directory.
6662 situation unshelving restores branch information to the working directory.
6669
6663
6670 Each shelved change has a name that makes it easier to find later.
6664 Each shelved change has a name that makes it easier to find later.
6671 The name of a shelved change defaults to being based on the active
6665 The name of a shelved change defaults to being based on the active
6672 bookmark, or if there is no active bookmark, the current named
6666 bookmark, or if there is no active bookmark, the current named
6673 branch. To specify a different name, use ``--name``.
6667 branch. To specify a different name, use ``--name``.
6674
6668
6675 To see a list of existing shelved changes, use the ``--list``
6669 To see a list of existing shelved changes, use the ``--list``
6676 option. For each shelved change, this will print its name, age,
6670 option. For each shelved change, this will print its name, age,
6677 and description; use ``--patch`` or ``--stat`` for more details.
6671 and description; use ``--patch`` or ``--stat`` for more details.
6678
6672
6679 To delete specific shelved changes, use ``--delete``. To delete
6673 To delete specific shelved changes, use ``--delete``. To delete
6680 all shelved changes, use ``--cleanup``.
6674 all shelved changes, use ``--cleanup``.
6681 """
6675 """
6682 opts = pycompat.byteskwargs(opts)
6676 opts = pycompat.byteskwargs(opts)
6683 allowables = [
6677 allowables = [
6684 (b'addremove', {b'create'}), # 'create' is pseudo action
6678 (b'addremove', {b'create'}), # 'create' is pseudo action
6685 (b'unknown', {b'create'}),
6679 (b'unknown', {b'create'}),
6686 (b'cleanup', {b'cleanup'}),
6680 (b'cleanup', {b'cleanup'}),
6687 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6681 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6688 (b'delete', {b'delete'}),
6682 (b'delete', {b'delete'}),
6689 (b'edit', {b'create'}),
6683 (b'edit', {b'create'}),
6690 (b'keep', {b'create'}),
6684 (b'keep', {b'create'}),
6691 (b'list', {b'list'}),
6685 (b'list', {b'list'}),
6692 (b'message', {b'create'}),
6686 (b'message', {b'create'}),
6693 (b'name', {b'create'}),
6687 (b'name', {b'create'}),
6694 (b'patch', {b'patch', b'list'}),
6688 (b'patch', {b'patch', b'list'}),
6695 (b'stat', {b'stat', b'list'}),
6689 (b'stat', {b'stat', b'list'}),
6696 ]
6690 ]
6697
6691
6698 def checkopt(opt):
6692 def checkopt(opt):
6699 if opts.get(opt):
6693 if opts.get(opt):
6700 for i, allowable in allowables:
6694 for i, allowable in allowables:
6701 if opts[i] and opt not in allowable:
6695 if opts[i] and opt not in allowable:
6702 raise error.InputError(
6696 raise error.InputError(
6703 _(
6697 _(
6704 b"options '--%s' and '--%s' may not be "
6698 b"options '--%s' and '--%s' may not be "
6705 b"used together"
6699 b"used together"
6706 )
6700 )
6707 % (opt, i)
6701 % (opt, i)
6708 )
6702 )
6709 return True
6703 return True
6710
6704
6711 if checkopt(b'cleanup'):
6705 if checkopt(b'cleanup'):
6712 if pats:
6706 if pats:
6713 raise error.InputError(
6707 raise error.InputError(
6714 _(b"cannot specify names when using '--cleanup'")
6708 _(b"cannot specify names when using '--cleanup'")
6715 )
6709 )
6716 return shelvemod.cleanupcmd(ui, repo)
6710 return shelvemod.cleanupcmd(ui, repo)
6717 elif checkopt(b'delete'):
6711 elif checkopt(b'delete'):
6718 return shelvemod.deletecmd(ui, repo, pats)
6712 return shelvemod.deletecmd(ui, repo, pats)
6719 elif checkopt(b'list'):
6713 elif checkopt(b'list'):
6720 return shelvemod.listcmd(ui, repo, pats, opts)
6714 return shelvemod.listcmd(ui, repo, pats, opts)
6721 elif checkopt(b'patch') or checkopt(b'stat'):
6715 elif checkopt(b'patch') or checkopt(b'stat'):
6722 return shelvemod.patchcmds(ui, repo, pats, opts)
6716 return shelvemod.patchcmds(ui, repo, pats, opts)
6723 else:
6717 else:
6724 return shelvemod.createcmd(ui, repo, pats, opts)
6718 return shelvemod.createcmd(ui, repo, pats, opts)
6725
6719
6726
6720
6727 _NOTTERSE = b'nothing'
6721 _NOTTERSE = b'nothing'
6728
6722
6729
6723
6730 @command(
6724 @command(
6731 b'status|st',
6725 b'status|st',
6732 [
6726 [
6733 (b'A', b'all', None, _(b'show status of all files')),
6727 (b'A', b'all', None, _(b'show status of all files')),
6734 (b'm', b'modified', None, _(b'show only modified files')),
6728 (b'm', b'modified', None, _(b'show only modified files')),
6735 (b'a', b'added', None, _(b'show only added files')),
6729 (b'a', b'added', None, _(b'show only added files')),
6736 (b'r', b'removed', None, _(b'show only removed files')),
6730 (b'r', b'removed', None, _(b'show only removed files')),
6737 (b'd', b'deleted', None, _(b'show only missing files')),
6731 (b'd', b'deleted', None, _(b'show only missing files')),
6738 (b'c', b'clean', None, _(b'show only files without changes')),
6732 (b'c', b'clean', None, _(b'show only files without changes')),
6739 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6733 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6740 (b'i', b'ignored', None, _(b'show only ignored files')),
6734 (b'i', b'ignored', None, _(b'show only ignored files')),
6741 (b'n', b'no-status', None, _(b'hide status prefix')),
6735 (b'n', b'no-status', None, _(b'hide status prefix')),
6742 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6736 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6743 (
6737 (
6744 b'C',
6738 b'C',
6745 b'copies',
6739 b'copies',
6746 None,
6740 None,
6747 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6741 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6748 ),
6742 ),
6749 (
6743 (
6750 b'0',
6744 b'0',
6751 b'print0',
6745 b'print0',
6752 None,
6746 None,
6753 _(b'end filenames with NUL, for use with xargs'),
6747 _(b'end filenames with NUL, for use with xargs'),
6754 ),
6748 ),
6755 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6749 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6756 (
6750 (
6757 b'',
6751 b'',
6758 b'change',
6752 b'change',
6759 b'',
6753 b'',
6760 _(b'list the changed files of a revision'),
6754 _(b'list the changed files of a revision'),
6761 _(b'REV'),
6755 _(b'REV'),
6762 ),
6756 ),
6763 ]
6757 ]
6764 + walkopts
6758 + walkopts
6765 + subrepoopts
6759 + subrepoopts
6766 + formatteropts,
6760 + formatteropts,
6767 _(b'[OPTION]... [FILE]...'),
6761 _(b'[OPTION]... [FILE]...'),
6768 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6762 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6769 helpbasic=True,
6763 helpbasic=True,
6770 inferrepo=True,
6764 inferrepo=True,
6771 intents={INTENT_READONLY},
6765 intents={INTENT_READONLY},
6772 )
6766 )
6773 def status(ui, repo, *pats, **opts):
6767 def status(ui, repo, *pats, **opts):
6774 """show changed files in the working directory
6768 """show changed files in the working directory
6775
6769
6776 Show status of files in the repository. If names are given, only
6770 Show status of files in the repository. If names are given, only
6777 files that match are shown. Files that are clean or ignored or
6771 files that match are shown. Files that are clean or ignored or
6778 the source of a copy/move operation, are not listed unless
6772 the source of a copy/move operation, are not listed unless
6779 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6773 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6780 Unless options described with "show only ..." are given, the
6774 Unless options described with "show only ..." are given, the
6781 options -mardu are used.
6775 options -mardu are used.
6782
6776
6783 Option -q/--quiet hides untracked (unknown and ignored) files
6777 Option -q/--quiet hides untracked (unknown and ignored) files
6784 unless explicitly requested with -u/--unknown or -i/--ignored.
6778 unless explicitly requested with -u/--unknown or -i/--ignored.
6785
6779
6786 .. note::
6780 .. note::
6787
6781
6788 :hg:`status` may appear to disagree with diff if permissions have
6782 :hg:`status` may appear to disagree with diff if permissions have
6789 changed or a merge has occurred. The standard diff format does
6783 changed or a merge has occurred. The standard diff format does
6790 not report permission changes and diff only reports changes
6784 not report permission changes and diff only reports changes
6791 relative to one merge parent.
6785 relative to one merge parent.
6792
6786
6793 If one revision is given, it is used as the base revision.
6787 If one revision is given, it is used as the base revision.
6794 If two revisions are given, the differences between them are
6788 If two revisions are given, the differences between them are
6795 shown. The --change option can also be used as a shortcut to list
6789 shown. The --change option can also be used as a shortcut to list
6796 the changed files of a revision from its first parent.
6790 the changed files of a revision from its first parent.
6797
6791
6798 The codes used to show the status of files are::
6792 The codes used to show the status of files are::
6799
6793
6800 M = modified
6794 M = modified
6801 A = added
6795 A = added
6802 R = removed
6796 R = removed
6803 C = clean
6797 C = clean
6804 ! = missing (deleted by non-hg command, but still tracked)
6798 ! = missing (deleted by non-hg command, but still tracked)
6805 ? = not tracked
6799 ? = not tracked
6806 I = ignored
6800 I = ignored
6807 = origin of the previous file (with --copies)
6801 = origin of the previous file (with --copies)
6808
6802
6809 .. container:: verbose
6803 .. container:: verbose
6810
6804
6811 The -t/--terse option abbreviates the output by showing only the directory
6805 The -t/--terse option abbreviates the output by showing only the directory
6812 name if all the files in it share the same status. The option takes an
6806 name if all the files in it share the same status. The option takes an
6813 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6807 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6814 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6808 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6815 for 'ignored' and 'c' for clean.
6809 for 'ignored' and 'c' for clean.
6816
6810
6817 It abbreviates only those statuses which are passed. Note that clean and
6811 It abbreviates only those statuses which are passed. Note that clean and
6818 ignored files are not displayed with '--terse ic' unless the -c/--clean
6812 ignored files are not displayed with '--terse ic' unless the -c/--clean
6819 and -i/--ignored options are also used.
6813 and -i/--ignored options are also used.
6820
6814
6821 The -v/--verbose option shows information when the repository is in an
6815 The -v/--verbose option shows information when the repository is in an
6822 unfinished merge, shelve, rebase state etc. You can have this behavior
6816 unfinished merge, shelve, rebase state etc. You can have this behavior
6823 turned on by default by enabling the ``commands.status.verbose`` option.
6817 turned on by default by enabling the ``commands.status.verbose`` option.
6824
6818
6825 You can skip displaying some of these states by setting
6819 You can skip displaying some of these states by setting
6826 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6820 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6827 'histedit', 'merge', 'rebase', or 'unshelve'.
6821 'histedit', 'merge', 'rebase', or 'unshelve'.
6828
6822
6829 Template:
6823 Template:
6830
6824
6831 The following keywords are supported in addition to the common template
6825 The following keywords are supported in addition to the common template
6832 keywords and functions. See also :hg:`help templates`.
6826 keywords and functions. See also :hg:`help templates`.
6833
6827
6834 :path: String. Repository-absolute path of the file.
6828 :path: String. Repository-absolute path of the file.
6835 :source: String. Repository-absolute path of the file originated from.
6829 :source: String. Repository-absolute path of the file originated from.
6836 Available if ``--copies`` is specified.
6830 Available if ``--copies`` is specified.
6837 :status: String. Character denoting file's status.
6831 :status: String. Character denoting file's status.
6838
6832
6839 Examples:
6833 Examples:
6840
6834
6841 - show changes in the working directory relative to a
6835 - show changes in the working directory relative to a
6842 changeset::
6836 changeset::
6843
6837
6844 hg status --rev 9353
6838 hg status --rev 9353
6845
6839
6846 - show changes in the working directory relative to the
6840 - show changes in the working directory relative to the
6847 current directory (see :hg:`help patterns` for more information)::
6841 current directory (see :hg:`help patterns` for more information)::
6848
6842
6849 hg status re:
6843 hg status re:
6850
6844
6851 - show all changes including copies in an existing changeset::
6845 - show all changes including copies in an existing changeset::
6852
6846
6853 hg status --copies --change 9353
6847 hg status --copies --change 9353
6854
6848
6855 - get a NUL separated list of added files, suitable for xargs::
6849 - get a NUL separated list of added files, suitable for xargs::
6856
6850
6857 hg status -an0
6851 hg status -an0
6858
6852
6859 - show more information about the repository status, abbreviating
6853 - show more information about the repository status, abbreviating
6860 added, removed, modified, deleted, and untracked paths::
6854 added, removed, modified, deleted, and untracked paths::
6861
6855
6862 hg status -v -t mardu
6856 hg status -v -t mardu
6863
6857
6864 Returns 0 on success.
6858 Returns 0 on success.
6865
6859
6866 """
6860 """
6867
6861
6868 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6862 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6869 opts = pycompat.byteskwargs(opts)
6863 opts = pycompat.byteskwargs(opts)
6870 revs = opts.get(b'rev')
6864 revs = opts.get(b'rev')
6871 change = opts.get(b'change')
6865 change = opts.get(b'change')
6872 terse = opts.get(b'terse')
6866 terse = opts.get(b'terse')
6873 if terse is _NOTTERSE:
6867 if terse is _NOTTERSE:
6874 if revs:
6868 if revs:
6875 terse = b''
6869 terse = b''
6876 else:
6870 else:
6877 terse = ui.config(b'commands', b'status.terse')
6871 terse = ui.config(b'commands', b'status.terse')
6878
6872
6879 if revs and terse:
6873 if revs and terse:
6880 msg = _(b'cannot use --terse with --rev')
6874 msg = _(b'cannot use --terse with --rev')
6881 raise error.InputError(msg)
6875 raise error.InputError(msg)
6882 elif change:
6876 elif change:
6883 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6877 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6884 ctx2 = scmutil.revsingle(repo, change, None)
6878 ctx2 = scmutil.revsingle(repo, change, None)
6885 ctx1 = ctx2.p1()
6879 ctx1 = ctx2.p1()
6886 else:
6880 else:
6887 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6881 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6888 ctx1, ctx2 = scmutil.revpair(repo, revs)
6882 ctx1, ctx2 = scmutil.revpair(repo, revs)
6889
6883
6890 forcerelativevalue = None
6884 forcerelativevalue = None
6891 if ui.hasconfig(b'commands', b'status.relative'):
6885 if ui.hasconfig(b'commands', b'status.relative'):
6892 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6886 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6893 uipathfn = scmutil.getuipathfn(
6887 uipathfn = scmutil.getuipathfn(
6894 repo,
6888 repo,
6895 legacyrelativevalue=bool(pats),
6889 legacyrelativevalue=bool(pats),
6896 forcerelativevalue=forcerelativevalue,
6890 forcerelativevalue=forcerelativevalue,
6897 )
6891 )
6898
6892
6899 if opts.get(b'print0'):
6893 if opts.get(b'print0'):
6900 end = b'\0'
6894 end = b'\0'
6901 else:
6895 else:
6902 end = b'\n'
6896 end = b'\n'
6903 states = b'modified added removed deleted unknown ignored clean'.split()
6897 states = b'modified added removed deleted unknown ignored clean'.split()
6904 show = [k for k in states if opts.get(k)]
6898 show = [k for k in states if opts.get(k)]
6905 if opts.get(b'all'):
6899 if opts.get(b'all'):
6906 show += ui.quiet and (states[:4] + [b'clean']) or states
6900 show += ui.quiet and (states[:4] + [b'clean']) or states
6907
6901
6908 if not show:
6902 if not show:
6909 if ui.quiet:
6903 if ui.quiet:
6910 show = states[:4]
6904 show = states[:4]
6911 else:
6905 else:
6912 show = states[:5]
6906 show = states[:5]
6913
6907
6914 m = scmutil.match(ctx2, pats, opts)
6908 m = scmutil.match(ctx2, pats, opts)
6915 if terse:
6909 if terse:
6916 # we need to compute clean and unknown to terse
6910 # we need to compute clean and unknown to terse
6917 stat = repo.status(
6911 stat = repo.status(
6918 ctx1.node(),
6912 ctx1.node(),
6919 ctx2.node(),
6913 ctx2.node(),
6920 m,
6914 m,
6921 b'ignored' in show or b'i' in terse,
6915 b'ignored' in show or b'i' in terse,
6922 clean=True,
6916 clean=True,
6923 unknown=True,
6917 unknown=True,
6924 listsubrepos=opts.get(b'subrepos'),
6918 listsubrepos=opts.get(b'subrepos'),
6925 )
6919 )
6926
6920
6927 stat = cmdutil.tersedir(stat, terse)
6921 stat = cmdutil.tersedir(stat, terse)
6928 else:
6922 else:
6929 stat = repo.status(
6923 stat = repo.status(
6930 ctx1.node(),
6924 ctx1.node(),
6931 ctx2.node(),
6925 ctx2.node(),
6932 m,
6926 m,
6933 b'ignored' in show,
6927 b'ignored' in show,
6934 b'clean' in show,
6928 b'clean' in show,
6935 b'unknown' in show,
6929 b'unknown' in show,
6936 opts.get(b'subrepos'),
6930 opts.get(b'subrepos'),
6937 )
6931 )
6938
6932
6939 changestates = zip(
6933 changestates = zip(
6940 states,
6934 states,
6941 pycompat.iterbytestr(b'MAR!?IC'),
6935 pycompat.iterbytestr(b'MAR!?IC'),
6942 [getattr(stat, s.decode('utf8')) for s in states],
6936 [getattr(stat, s.decode('utf8')) for s in states],
6943 )
6937 )
6944
6938
6945 copy = {}
6939 copy = {}
6946 if (
6940 if (
6947 opts.get(b'all')
6941 opts.get(b'all')
6948 or opts.get(b'copies')
6942 or opts.get(b'copies')
6949 or ui.configbool(b'ui', b'statuscopies')
6943 or ui.configbool(b'ui', b'statuscopies')
6950 ) and not opts.get(b'no_status'):
6944 ) and not opts.get(b'no_status'):
6951 copy = copies.pathcopies(ctx1, ctx2, m)
6945 copy = copies.pathcopies(ctx1, ctx2, m)
6952
6946
6953 morestatus = None
6947 morestatus = None
6954 if (
6948 if (
6955 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6949 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6956 and not ui.plain()
6950 and not ui.plain()
6957 and not opts.get(b'print0')
6951 and not opts.get(b'print0')
6958 ):
6952 ):
6959 morestatus = cmdutil.readmorestatus(repo)
6953 morestatus = cmdutil.readmorestatus(repo)
6960
6954
6961 ui.pager(b'status')
6955 ui.pager(b'status')
6962 fm = ui.formatter(b'status', opts)
6956 fm = ui.formatter(b'status', opts)
6963 fmt = b'%s' + end
6957 fmt = b'%s' + end
6964 showchar = not opts.get(b'no_status')
6958 showchar = not opts.get(b'no_status')
6965
6959
6966 for state, char, files in changestates:
6960 for state, char, files in changestates:
6967 if state in show:
6961 if state in show:
6968 label = b'status.' + state
6962 label = b'status.' + state
6969 for f in files:
6963 for f in files:
6970 fm.startitem()
6964 fm.startitem()
6971 fm.context(ctx=ctx2)
6965 fm.context(ctx=ctx2)
6972 fm.data(itemtype=b'file', path=f)
6966 fm.data(itemtype=b'file', path=f)
6973 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6967 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6974 fm.plain(fmt % uipathfn(f), label=label)
6968 fm.plain(fmt % uipathfn(f), label=label)
6975 if f in copy:
6969 if f in copy:
6976 fm.data(source=copy[f])
6970 fm.data(source=copy[f])
6977 fm.plain(
6971 fm.plain(
6978 (b' %s' + end) % uipathfn(copy[f]),
6972 (b' %s' + end) % uipathfn(copy[f]),
6979 label=b'status.copied',
6973 label=b'status.copied',
6980 )
6974 )
6981 if morestatus:
6975 if morestatus:
6982 morestatus.formatfile(f, fm)
6976 morestatus.formatfile(f, fm)
6983
6977
6984 if morestatus:
6978 if morestatus:
6985 morestatus.formatfooter(fm)
6979 morestatus.formatfooter(fm)
6986 fm.end()
6980 fm.end()
6987
6981
6988
6982
6989 @command(
6983 @command(
6990 b'summary|sum',
6984 b'summary|sum',
6991 [(b'', b'remote', None, _(b'check for push and pull'))],
6985 [(b'', b'remote', None, _(b'check for push and pull'))],
6992 b'[--remote]',
6986 b'[--remote]',
6993 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6987 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6994 helpbasic=True,
6988 helpbasic=True,
6995 intents={INTENT_READONLY},
6989 intents={INTENT_READONLY},
6996 )
6990 )
6997 def summary(ui, repo, **opts):
6991 def summary(ui, repo, **opts):
6998 """summarize working directory state
6992 """summarize working directory state
6999
6993
7000 This generates a brief summary of the working directory state,
6994 This generates a brief summary of the working directory state,
7001 including parents, branch, commit status, phase and available updates.
6995 including parents, branch, commit status, phase and available updates.
7002
6996
7003 With the --remote option, this will check the default paths for
6997 With the --remote option, this will check the default paths for
7004 incoming and outgoing changes. This can be time-consuming.
6998 incoming and outgoing changes. This can be time-consuming.
7005
6999
7006 Returns 0 on success.
7000 Returns 0 on success.
7007 """
7001 """
7008
7002
7009 opts = pycompat.byteskwargs(opts)
7003 opts = pycompat.byteskwargs(opts)
7010 ui.pager(b'summary')
7004 ui.pager(b'summary')
7011 ctx = repo[None]
7005 ctx = repo[None]
7012 parents = ctx.parents()
7006 parents = ctx.parents()
7013 pnode = parents[0].node()
7007 pnode = parents[0].node()
7014 marks = []
7008 marks = []
7015
7009
7016 try:
7010 try:
7017 ms = mergestatemod.mergestate.read(repo)
7011 ms = mergestatemod.mergestate.read(repo)
7018 except error.UnsupportedMergeRecords as e:
7012 except error.UnsupportedMergeRecords as e:
7019 s = b' '.join(e.recordtypes)
7013 s = b' '.join(e.recordtypes)
7020 ui.warn(
7014 ui.warn(
7021 _(b'warning: merge state has unsupported record types: %s\n') % s
7015 _(b'warning: merge state has unsupported record types: %s\n') % s
7022 )
7016 )
7023 unresolved = []
7017 unresolved = []
7024 else:
7018 else:
7025 unresolved = list(ms.unresolved())
7019 unresolved = list(ms.unresolved())
7026
7020
7027 for p in parents:
7021 for p in parents:
7028 # label with log.changeset (instead of log.parent) since this
7022 # label with log.changeset (instead of log.parent) since this
7029 # shows a working directory parent *changeset*:
7023 # shows a working directory parent *changeset*:
7030 # i18n: column positioning for "hg summary"
7024 # i18n: column positioning for "hg summary"
7031 ui.write(
7025 ui.write(
7032 _(b'parent: %d:%s ') % (p.rev(), p),
7026 _(b'parent: %d:%s ') % (p.rev(), p),
7033 label=logcmdutil.changesetlabels(p),
7027 label=logcmdutil.changesetlabels(p),
7034 )
7028 )
7035 ui.write(b' '.join(p.tags()), label=b'log.tag')
7029 ui.write(b' '.join(p.tags()), label=b'log.tag')
7036 if p.bookmarks():
7030 if p.bookmarks():
7037 marks.extend(p.bookmarks())
7031 marks.extend(p.bookmarks())
7038 if p.rev() == -1:
7032 if p.rev() == -1:
7039 if not len(repo):
7033 if not len(repo):
7040 ui.write(_(b' (empty repository)'))
7034 ui.write(_(b' (empty repository)'))
7041 else:
7035 else:
7042 ui.write(_(b' (no revision checked out)'))
7036 ui.write(_(b' (no revision checked out)'))
7043 if p.obsolete():
7037 if p.obsolete():
7044 ui.write(_(b' (obsolete)'))
7038 ui.write(_(b' (obsolete)'))
7045 if p.isunstable():
7039 if p.isunstable():
7046 instabilities = (
7040 instabilities = (
7047 ui.label(instability, b'trouble.%s' % instability)
7041 ui.label(instability, b'trouble.%s' % instability)
7048 for instability in p.instabilities()
7042 for instability in p.instabilities()
7049 )
7043 )
7050 ui.write(b' (' + b', '.join(instabilities) + b')')
7044 ui.write(b' (' + b', '.join(instabilities) + b')')
7051 ui.write(b'\n')
7045 ui.write(b'\n')
7052 if p.description():
7046 if p.description():
7053 ui.status(
7047 ui.status(
7054 b' ' + p.description().splitlines()[0].strip() + b'\n',
7048 b' ' + p.description().splitlines()[0].strip() + b'\n',
7055 label=b'log.summary',
7049 label=b'log.summary',
7056 )
7050 )
7057
7051
7058 branch = ctx.branch()
7052 branch = ctx.branch()
7059 bheads = repo.branchheads(branch)
7053 bheads = repo.branchheads(branch)
7060 # i18n: column positioning for "hg summary"
7054 # i18n: column positioning for "hg summary"
7061 m = _(b'branch: %s\n') % branch
7055 m = _(b'branch: %s\n') % branch
7062 if branch != b'default':
7056 if branch != b'default':
7063 ui.write(m, label=b'log.branch')
7057 ui.write(m, label=b'log.branch')
7064 else:
7058 else:
7065 ui.status(m, label=b'log.branch')
7059 ui.status(m, label=b'log.branch')
7066
7060
7067 if marks:
7061 if marks:
7068 active = repo._activebookmark
7062 active = repo._activebookmark
7069 # i18n: column positioning for "hg summary"
7063 # i18n: column positioning for "hg summary"
7070 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7064 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7071 if active is not None:
7065 if active is not None:
7072 if active in marks:
7066 if active in marks:
7073 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7067 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7074 marks.remove(active)
7068 marks.remove(active)
7075 else:
7069 else:
7076 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7070 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7077 for m in marks:
7071 for m in marks:
7078 ui.write(b' ' + m, label=b'log.bookmark')
7072 ui.write(b' ' + m, label=b'log.bookmark')
7079 ui.write(b'\n', label=b'log.bookmark')
7073 ui.write(b'\n', label=b'log.bookmark')
7080
7074
7081 status = repo.status(unknown=True)
7075 status = repo.status(unknown=True)
7082
7076
7083 c = repo.dirstate.copies()
7077 c = repo.dirstate.copies()
7084 copied, renamed = [], []
7078 copied, renamed = [], []
7085 for d, s in pycompat.iteritems(c):
7079 for d, s in pycompat.iteritems(c):
7086 if s in status.removed:
7080 if s in status.removed:
7087 status.removed.remove(s)
7081 status.removed.remove(s)
7088 renamed.append(d)
7082 renamed.append(d)
7089 else:
7083 else:
7090 copied.append(d)
7084 copied.append(d)
7091 if d in status.added:
7085 if d in status.added:
7092 status.added.remove(d)
7086 status.added.remove(d)
7093
7087
7094 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7088 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7095
7089
7096 labels = [
7090 labels = [
7097 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7091 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7098 (ui.label(_(b'%d added'), b'status.added'), status.added),
7092 (ui.label(_(b'%d added'), b'status.added'), status.added),
7099 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7093 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7100 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7094 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7101 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7095 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7102 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7096 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7103 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7097 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7104 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7098 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7105 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7099 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7106 ]
7100 ]
7107 t = []
7101 t = []
7108 for l, s in labels:
7102 for l, s in labels:
7109 if s:
7103 if s:
7110 t.append(l % len(s))
7104 t.append(l % len(s))
7111
7105
7112 t = b', '.join(t)
7106 t = b', '.join(t)
7113 cleanworkdir = False
7107 cleanworkdir = False
7114
7108
7115 if repo.vfs.exists(b'graftstate'):
7109 if repo.vfs.exists(b'graftstate'):
7116 t += _(b' (graft in progress)')
7110 t += _(b' (graft in progress)')
7117 if repo.vfs.exists(b'updatestate'):
7111 if repo.vfs.exists(b'updatestate'):
7118 t += _(b' (interrupted update)')
7112 t += _(b' (interrupted update)')
7119 elif len(parents) > 1:
7113 elif len(parents) > 1:
7120 t += _(b' (merge)')
7114 t += _(b' (merge)')
7121 elif branch != parents[0].branch():
7115 elif branch != parents[0].branch():
7122 t += _(b' (new branch)')
7116 t += _(b' (new branch)')
7123 elif parents[0].closesbranch() and pnode in repo.branchheads(
7117 elif parents[0].closesbranch() and pnode in repo.branchheads(
7124 branch, closed=True
7118 branch, closed=True
7125 ):
7119 ):
7126 t += _(b' (head closed)')
7120 t += _(b' (head closed)')
7127 elif not (
7121 elif not (
7128 status.modified
7122 status.modified
7129 or status.added
7123 or status.added
7130 or status.removed
7124 or status.removed
7131 or renamed
7125 or renamed
7132 or copied
7126 or copied
7133 or subs
7127 or subs
7134 ):
7128 ):
7135 t += _(b' (clean)')
7129 t += _(b' (clean)')
7136 cleanworkdir = True
7130 cleanworkdir = True
7137 elif pnode not in bheads:
7131 elif pnode not in bheads:
7138 t += _(b' (new branch head)')
7132 t += _(b' (new branch head)')
7139
7133
7140 if parents:
7134 if parents:
7141 pendingphase = max(p.phase() for p in parents)
7135 pendingphase = max(p.phase() for p in parents)
7142 else:
7136 else:
7143 pendingphase = phases.public
7137 pendingphase = phases.public
7144
7138
7145 if pendingphase > phases.newcommitphase(ui):
7139 if pendingphase > phases.newcommitphase(ui):
7146 t += b' (%s)' % phases.phasenames[pendingphase]
7140 t += b' (%s)' % phases.phasenames[pendingphase]
7147
7141
7148 if cleanworkdir:
7142 if cleanworkdir:
7149 # i18n: column positioning for "hg summary"
7143 # i18n: column positioning for "hg summary"
7150 ui.status(_(b'commit: %s\n') % t.strip())
7144 ui.status(_(b'commit: %s\n') % t.strip())
7151 else:
7145 else:
7152 # i18n: column positioning for "hg summary"
7146 # i18n: column positioning for "hg summary"
7153 ui.write(_(b'commit: %s\n') % t.strip())
7147 ui.write(_(b'commit: %s\n') % t.strip())
7154
7148
7155 # all ancestors of branch heads - all ancestors of parent = new csets
7149 # all ancestors of branch heads - all ancestors of parent = new csets
7156 new = len(
7150 new = len(
7157 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7151 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7158 )
7152 )
7159
7153
7160 if new == 0:
7154 if new == 0:
7161 # i18n: column positioning for "hg summary"
7155 # i18n: column positioning for "hg summary"
7162 ui.status(_(b'update: (current)\n'))
7156 ui.status(_(b'update: (current)\n'))
7163 elif pnode not in bheads:
7157 elif pnode not in bheads:
7164 # i18n: column positioning for "hg summary"
7158 # i18n: column positioning for "hg summary"
7165 ui.write(_(b'update: %d new changesets (update)\n') % new)
7159 ui.write(_(b'update: %d new changesets (update)\n') % new)
7166 else:
7160 else:
7167 # i18n: column positioning for "hg summary"
7161 # i18n: column positioning for "hg summary"
7168 ui.write(
7162 ui.write(
7169 _(b'update: %d new changesets, %d branch heads (merge)\n')
7163 _(b'update: %d new changesets, %d branch heads (merge)\n')
7170 % (new, len(bheads))
7164 % (new, len(bheads))
7171 )
7165 )
7172
7166
7173 t = []
7167 t = []
7174 draft = len(repo.revs(b'draft()'))
7168 draft = len(repo.revs(b'draft()'))
7175 if draft:
7169 if draft:
7176 t.append(_(b'%d draft') % draft)
7170 t.append(_(b'%d draft') % draft)
7177 secret = len(repo.revs(b'secret()'))
7171 secret = len(repo.revs(b'secret()'))
7178 if secret:
7172 if secret:
7179 t.append(_(b'%d secret') % secret)
7173 t.append(_(b'%d secret') % secret)
7180
7174
7181 if draft or secret:
7175 if draft or secret:
7182 ui.status(_(b'phases: %s\n') % b', '.join(t))
7176 ui.status(_(b'phases: %s\n') % b', '.join(t))
7183
7177
7184 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7178 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7185 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7179 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7186 numtrouble = len(repo.revs(trouble + b"()"))
7180 numtrouble = len(repo.revs(trouble + b"()"))
7187 # We write all the possibilities to ease translation
7181 # We write all the possibilities to ease translation
7188 troublemsg = {
7182 troublemsg = {
7189 b"orphan": _(b"orphan: %d changesets"),
7183 b"orphan": _(b"orphan: %d changesets"),
7190 b"contentdivergent": _(b"content-divergent: %d changesets"),
7184 b"contentdivergent": _(b"content-divergent: %d changesets"),
7191 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7185 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7192 }
7186 }
7193 if numtrouble > 0:
7187 if numtrouble > 0:
7194 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7188 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7195
7189
7196 cmdutil.summaryhooks(ui, repo)
7190 cmdutil.summaryhooks(ui, repo)
7197
7191
7198 if opts.get(b'remote'):
7192 if opts.get(b'remote'):
7199 needsincoming, needsoutgoing = True, True
7193 needsincoming, needsoutgoing = True, True
7200 else:
7194 else:
7201 needsincoming, needsoutgoing = False, False
7195 needsincoming, needsoutgoing = False, False
7202 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7196 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7203 if i:
7197 if i:
7204 needsincoming = True
7198 needsincoming = True
7205 if o:
7199 if o:
7206 needsoutgoing = True
7200 needsoutgoing = True
7207 if not needsincoming and not needsoutgoing:
7201 if not needsincoming and not needsoutgoing:
7208 return
7202 return
7209
7203
7210 def getincoming():
7204 def getincoming():
7211 # XXX We should actually skip this if no default is specified, instead
7205 # XXX We should actually skip this if no default is specified, instead
7212 # of passing "default" which will resolve as "./default/" if no default
7206 # of passing "default" which will resolve as "./default/" if no default
7213 # path is defined.
7207 # path is defined.
7214 source, branches = urlutil.get_unique_pull_path(
7208 source, branches = urlutil.get_unique_pull_path(
7215 b'summary', repo, ui, b'default'
7209 b'summary', repo, ui, b'default'
7216 )
7210 )
7217 sbranch = branches[0]
7211 sbranch = branches[0]
7218 try:
7212 try:
7219 other = hg.peer(repo, {}, source)
7213 other = hg.peer(repo, {}, source)
7220 except error.RepoError:
7214 except error.RepoError:
7221 if opts.get(b'remote'):
7215 if opts.get(b'remote'):
7222 raise
7216 raise
7223 return source, sbranch, None, None, None
7217 return source, sbranch, None, None, None
7224 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7218 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7225 if revs:
7219 if revs:
7226 revs = [other.lookup(rev) for rev in revs]
7220 revs = [other.lookup(rev) for rev in revs]
7227 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7221 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7228 repo.ui.pushbuffer()
7222 repo.ui.pushbuffer()
7229 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7223 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7230 repo.ui.popbuffer()
7224 repo.ui.popbuffer()
7231 return source, sbranch, other, commoninc, commoninc[1]
7225 return source, sbranch, other, commoninc, commoninc[1]
7232
7226
7233 if needsincoming:
7227 if needsincoming:
7234 source, sbranch, sother, commoninc, incoming = getincoming()
7228 source, sbranch, sother, commoninc, incoming = getincoming()
7235 else:
7229 else:
7236 source = sbranch = sother = commoninc = incoming = None
7230 source = sbranch = sother = commoninc = incoming = None
7237
7231
7238 def getoutgoing():
7232 def getoutgoing():
7239 # XXX We should actually skip this if no default is specified, instead
7233 # XXX We should actually skip this if no default is specified, instead
7240 # of passing "default" which will resolve as "./default/" if no default
7234 # of passing "default" which will resolve as "./default/" if no default
7241 # path is defined.
7235 # path is defined.
7242 d = None
7236 d = None
7243 if b'default-push' in ui.paths:
7237 if b'default-push' in ui.paths:
7244 d = b'default-push'
7238 d = b'default-push'
7245 elif b'default' in ui.paths:
7239 elif b'default' in ui.paths:
7246 d = b'default'
7240 d = b'default'
7247 if d is not None:
7241 if d is not None:
7248 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7242 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7249 dest = path.pushloc or path.loc
7243 dest = path.pushloc or path.loc
7250 dbranch = path.branch
7244 dbranch = path.branch
7251 else:
7245 else:
7252 dest = b'default'
7246 dest = b'default'
7253 dbranch = None
7247 dbranch = None
7254 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7248 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7255 if source != dest:
7249 if source != dest:
7256 try:
7250 try:
7257 dother = hg.peer(repo, {}, dest)
7251 dother = hg.peer(repo, {}, dest)
7258 except error.RepoError:
7252 except error.RepoError:
7259 if opts.get(b'remote'):
7253 if opts.get(b'remote'):
7260 raise
7254 raise
7261 return dest, dbranch, None, None
7255 return dest, dbranch, None, None
7262 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7256 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7263 elif sother is None:
7257 elif sother is None:
7264 # there is no explicit destination peer, but source one is invalid
7258 # there is no explicit destination peer, but source one is invalid
7265 return dest, dbranch, None, None
7259 return dest, dbranch, None, None
7266 else:
7260 else:
7267 dother = sother
7261 dother = sother
7268 if source != dest or (sbranch is not None and sbranch != dbranch):
7262 if source != dest or (sbranch is not None and sbranch != dbranch):
7269 common = None
7263 common = None
7270 else:
7264 else:
7271 common = commoninc
7265 common = commoninc
7272 if revs:
7266 if revs:
7273 revs = [repo.lookup(rev) for rev in revs]
7267 revs = [repo.lookup(rev) for rev in revs]
7274 repo.ui.pushbuffer()
7268 repo.ui.pushbuffer()
7275 outgoing = discovery.findcommonoutgoing(
7269 outgoing = discovery.findcommonoutgoing(
7276 repo, dother, onlyheads=revs, commoninc=common
7270 repo, dother, onlyheads=revs, commoninc=common
7277 )
7271 )
7278 repo.ui.popbuffer()
7272 repo.ui.popbuffer()
7279 return dest, dbranch, dother, outgoing
7273 return dest, dbranch, dother, outgoing
7280
7274
7281 if needsoutgoing:
7275 if needsoutgoing:
7282 dest, dbranch, dother, outgoing = getoutgoing()
7276 dest, dbranch, dother, outgoing = getoutgoing()
7283 else:
7277 else:
7284 dest = dbranch = dother = outgoing = None
7278 dest = dbranch = dother = outgoing = None
7285
7279
7286 if opts.get(b'remote'):
7280 if opts.get(b'remote'):
7287 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7281 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7288 # The former always sets `sother` (or raises an exception if it can't);
7282 # The former always sets `sother` (or raises an exception if it can't);
7289 # the latter always sets `outgoing`.
7283 # the latter always sets `outgoing`.
7290 assert sother is not None
7284 assert sother is not None
7291 assert outgoing is not None
7285 assert outgoing is not None
7292
7286
7293 t = []
7287 t = []
7294 if incoming:
7288 if incoming:
7295 t.append(_(b'1 or more incoming'))
7289 t.append(_(b'1 or more incoming'))
7296 o = outgoing.missing
7290 o = outgoing.missing
7297 if o:
7291 if o:
7298 t.append(_(b'%d outgoing') % len(o))
7292 t.append(_(b'%d outgoing') % len(o))
7299 other = dother or sother
7293 other = dother or sother
7300 if b'bookmarks' in other.listkeys(b'namespaces'):
7294 if b'bookmarks' in other.listkeys(b'namespaces'):
7301 counts = bookmarks.summary(repo, other)
7295 counts = bookmarks.summary(repo, other)
7302 if counts[0] > 0:
7296 if counts[0] > 0:
7303 t.append(_(b'%d incoming bookmarks') % counts[0])
7297 t.append(_(b'%d incoming bookmarks') % counts[0])
7304 if counts[1] > 0:
7298 if counts[1] > 0:
7305 t.append(_(b'%d outgoing bookmarks') % counts[1])
7299 t.append(_(b'%d outgoing bookmarks') % counts[1])
7306
7300
7307 if t:
7301 if t:
7308 # i18n: column positioning for "hg summary"
7302 # i18n: column positioning for "hg summary"
7309 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7303 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7310 else:
7304 else:
7311 # i18n: column positioning for "hg summary"
7305 # i18n: column positioning for "hg summary"
7312 ui.status(_(b'remote: (synced)\n'))
7306 ui.status(_(b'remote: (synced)\n'))
7313
7307
7314 cmdutil.summaryremotehooks(
7308 cmdutil.summaryremotehooks(
7315 ui,
7309 ui,
7316 repo,
7310 repo,
7317 opts,
7311 opts,
7318 (
7312 (
7319 (source, sbranch, sother, commoninc),
7313 (source, sbranch, sother, commoninc),
7320 (dest, dbranch, dother, outgoing),
7314 (dest, dbranch, dother, outgoing),
7321 ),
7315 ),
7322 )
7316 )
7323
7317
7324
7318
7325 @command(
7319 @command(
7326 b'tag',
7320 b'tag',
7327 [
7321 [
7328 (b'f', b'force', None, _(b'force tag')),
7322 (b'f', b'force', None, _(b'force tag')),
7329 (b'l', b'local', None, _(b'make the tag local')),
7323 (b'l', b'local', None, _(b'make the tag local')),
7330 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7324 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7331 (b'', b'remove', None, _(b'remove a tag')),
7325 (b'', b'remove', None, _(b'remove a tag')),
7332 # -l/--local is already there, commitopts cannot be used
7326 # -l/--local is already there, commitopts cannot be used
7333 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7327 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7334 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7328 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7335 ]
7329 ]
7336 + commitopts2,
7330 + commitopts2,
7337 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7331 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7338 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7332 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7339 )
7333 )
7340 def tag(ui, repo, name1, *names, **opts):
7334 def tag(ui, repo, name1, *names, **opts):
7341 """add one or more tags for the current or given revision
7335 """add one or more tags for the current or given revision
7342
7336
7343 Name a particular revision using <name>.
7337 Name a particular revision using <name>.
7344
7338
7345 Tags are used to name particular revisions of the repository and are
7339 Tags are used to name particular revisions of the repository and are
7346 very useful to compare different revisions, to go back to significant
7340 very useful to compare different revisions, to go back to significant
7347 earlier versions or to mark branch points as releases, etc. Changing
7341 earlier versions or to mark branch points as releases, etc. Changing
7348 an existing tag is normally disallowed; use -f/--force to override.
7342 an existing tag is normally disallowed; use -f/--force to override.
7349
7343
7350 If no revision is given, the parent of the working directory is
7344 If no revision is given, the parent of the working directory is
7351 used.
7345 used.
7352
7346
7353 To facilitate version control, distribution, and merging of tags,
7347 To facilitate version control, distribution, and merging of tags,
7354 they are stored as a file named ".hgtags" which is managed similarly
7348 they are stored as a file named ".hgtags" which is managed similarly
7355 to other project files and can be hand-edited if necessary. This
7349 to other project files and can be hand-edited if necessary. This
7356 also means that tagging creates a new commit. The file
7350 also means that tagging creates a new commit. The file
7357 ".hg/localtags" is used for local tags (not shared among
7351 ".hg/localtags" is used for local tags (not shared among
7358 repositories).
7352 repositories).
7359
7353
7360 Tag commits are usually made at the head of a branch. If the parent
7354 Tag commits are usually made at the head of a branch. If the parent
7361 of the working directory is not a branch head, :hg:`tag` aborts; use
7355 of the working directory is not a branch head, :hg:`tag` aborts; use
7362 -f/--force to force the tag commit to be based on a non-head
7356 -f/--force to force the tag commit to be based on a non-head
7363 changeset.
7357 changeset.
7364
7358
7365 See :hg:`help dates` for a list of formats valid for -d/--date.
7359 See :hg:`help dates` for a list of formats valid for -d/--date.
7366
7360
7367 Since tag names have priority over branch names during revision
7361 Since tag names have priority over branch names during revision
7368 lookup, using an existing branch name as a tag name is discouraged.
7362 lookup, using an existing branch name as a tag name is discouraged.
7369
7363
7370 Returns 0 on success.
7364 Returns 0 on success.
7371 """
7365 """
7372 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7366 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7373 opts = pycompat.byteskwargs(opts)
7367 opts = pycompat.byteskwargs(opts)
7374 with repo.wlock(), repo.lock():
7368 with repo.wlock(), repo.lock():
7375 rev_ = b"."
7369 rev_ = b"."
7376 names = [t.strip() for t in (name1,) + names]
7370 names = [t.strip() for t in (name1,) + names]
7377 if len(names) != len(set(names)):
7371 if len(names) != len(set(names)):
7378 raise error.InputError(_(b'tag names must be unique'))
7372 raise error.InputError(_(b'tag names must be unique'))
7379 for n in names:
7373 for n in names:
7380 scmutil.checknewlabel(repo, n, b'tag')
7374 scmutil.checknewlabel(repo, n, b'tag')
7381 if not n:
7375 if not n:
7382 raise error.InputError(
7376 raise error.InputError(
7383 _(b'tag names cannot consist entirely of whitespace')
7377 _(b'tag names cannot consist entirely of whitespace')
7384 )
7378 )
7385 if opts.get(b'rev'):
7379 if opts.get(b'rev'):
7386 rev_ = opts[b'rev']
7380 rev_ = opts[b'rev']
7387 message = opts.get(b'message')
7381 message = opts.get(b'message')
7388 if opts.get(b'remove'):
7382 if opts.get(b'remove'):
7389 if opts.get(b'local'):
7383 if opts.get(b'local'):
7390 expectedtype = b'local'
7384 expectedtype = b'local'
7391 else:
7385 else:
7392 expectedtype = b'global'
7386 expectedtype = b'global'
7393
7387
7394 for n in names:
7388 for n in names:
7395 if repo.tagtype(n) == b'global':
7389 if repo.tagtype(n) == b'global':
7396 alltags = tagsmod.findglobaltags(ui, repo)
7390 alltags = tagsmod.findglobaltags(ui, repo)
7397 if alltags[n][0] == repo.nullid:
7391 if alltags[n][0] == repo.nullid:
7398 raise error.InputError(
7392 raise error.InputError(
7399 _(b"tag '%s' is already removed") % n
7393 _(b"tag '%s' is already removed") % n
7400 )
7394 )
7401 if not repo.tagtype(n):
7395 if not repo.tagtype(n):
7402 raise error.InputError(_(b"tag '%s' does not exist") % n)
7396 raise error.InputError(_(b"tag '%s' does not exist") % n)
7403 if repo.tagtype(n) != expectedtype:
7397 if repo.tagtype(n) != expectedtype:
7404 if expectedtype == b'global':
7398 if expectedtype == b'global':
7405 raise error.InputError(
7399 raise error.InputError(
7406 _(b"tag '%s' is not a global tag") % n
7400 _(b"tag '%s' is not a global tag") % n
7407 )
7401 )
7408 else:
7402 else:
7409 raise error.InputError(
7403 raise error.InputError(
7410 _(b"tag '%s' is not a local tag") % n
7404 _(b"tag '%s' is not a local tag") % n
7411 )
7405 )
7412 rev_ = b'null'
7406 rev_ = b'null'
7413 if not message:
7407 if not message:
7414 # we don't translate commit messages
7408 # we don't translate commit messages
7415 message = b'Removed tag %s' % b', '.join(names)
7409 message = b'Removed tag %s' % b', '.join(names)
7416 elif not opts.get(b'force'):
7410 elif not opts.get(b'force'):
7417 for n in names:
7411 for n in names:
7418 if n in repo.tags():
7412 if n in repo.tags():
7419 raise error.InputError(
7413 raise error.InputError(
7420 _(b"tag '%s' already exists (use -f to force)") % n
7414 _(b"tag '%s' already exists (use -f to force)") % n
7421 )
7415 )
7422 if not opts.get(b'local'):
7416 if not opts.get(b'local'):
7423 p1, p2 = repo.dirstate.parents()
7417 p1, p2 = repo.dirstate.parents()
7424 if p2 != repo.nullid:
7418 if p2 != repo.nullid:
7425 raise error.StateError(_(b'uncommitted merge'))
7419 raise error.StateError(_(b'uncommitted merge'))
7426 bheads = repo.branchheads()
7420 bheads = repo.branchheads()
7427 if not opts.get(b'force') and bheads and p1 not in bheads:
7421 if not opts.get(b'force') and bheads and p1 not in bheads:
7428 raise error.InputError(
7422 raise error.InputError(
7429 _(
7423 _(
7430 b'working directory is not at a branch head '
7424 b'working directory is not at a branch head '
7431 b'(use -f to force)'
7425 b'(use -f to force)'
7432 )
7426 )
7433 )
7427 )
7434 node = scmutil.revsingle(repo, rev_).node()
7428 node = scmutil.revsingle(repo, rev_).node()
7435
7429
7436 if not message:
7430 if not message:
7437 # we don't translate commit messages
7431 # we don't translate commit messages
7438 message = b'Added tag %s for changeset %s' % (
7432 message = b'Added tag %s for changeset %s' % (
7439 b', '.join(names),
7433 b', '.join(names),
7440 short(node),
7434 short(node),
7441 )
7435 )
7442
7436
7443 date = opts.get(b'date')
7437 date = opts.get(b'date')
7444 if date:
7438 if date:
7445 date = dateutil.parsedate(date)
7439 date = dateutil.parsedate(date)
7446
7440
7447 if opts.get(b'remove'):
7441 if opts.get(b'remove'):
7448 editform = b'tag.remove'
7442 editform = b'tag.remove'
7449 else:
7443 else:
7450 editform = b'tag.add'
7444 editform = b'tag.add'
7451 editor = cmdutil.getcommiteditor(
7445 editor = cmdutil.getcommiteditor(
7452 editform=editform, **pycompat.strkwargs(opts)
7446 editform=editform, **pycompat.strkwargs(opts)
7453 )
7447 )
7454
7448
7455 # don't allow tagging the null rev
7449 # don't allow tagging the null rev
7456 if (
7450 if (
7457 not opts.get(b'remove')
7451 not opts.get(b'remove')
7458 and scmutil.revsingle(repo, rev_).rev() == nullrev
7452 and scmutil.revsingle(repo, rev_).rev() == nullrev
7459 ):
7453 ):
7460 raise error.InputError(_(b"cannot tag null revision"))
7454 raise error.InputError(_(b"cannot tag null revision"))
7461
7455
7462 tagsmod.tag(
7456 tagsmod.tag(
7463 repo,
7457 repo,
7464 names,
7458 names,
7465 node,
7459 node,
7466 message,
7460 message,
7467 opts.get(b'local'),
7461 opts.get(b'local'),
7468 opts.get(b'user'),
7462 opts.get(b'user'),
7469 date,
7463 date,
7470 editor=editor,
7464 editor=editor,
7471 )
7465 )
7472
7466
7473
7467
7474 @command(
7468 @command(
7475 b'tags',
7469 b'tags',
7476 formatteropts,
7470 formatteropts,
7477 b'',
7471 b'',
7478 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7472 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7479 intents={INTENT_READONLY},
7473 intents={INTENT_READONLY},
7480 )
7474 )
7481 def tags(ui, repo, **opts):
7475 def tags(ui, repo, **opts):
7482 """list repository tags
7476 """list repository tags
7483
7477
7484 This lists both regular and local tags. When the -v/--verbose
7478 This lists both regular and local tags. When the -v/--verbose
7485 switch is used, a third column "local" is printed for local tags.
7479 switch is used, a third column "local" is printed for local tags.
7486 When the -q/--quiet switch is used, only the tag name is printed.
7480 When the -q/--quiet switch is used, only the tag name is printed.
7487
7481
7488 .. container:: verbose
7482 .. container:: verbose
7489
7483
7490 Template:
7484 Template:
7491
7485
7492 The following keywords are supported in addition to the common template
7486 The following keywords are supported in addition to the common template
7493 keywords and functions such as ``{tag}``. See also
7487 keywords and functions such as ``{tag}``. See also
7494 :hg:`help templates`.
7488 :hg:`help templates`.
7495
7489
7496 :type: String. ``local`` for local tags.
7490 :type: String. ``local`` for local tags.
7497
7491
7498 Returns 0 on success.
7492 Returns 0 on success.
7499 """
7493 """
7500
7494
7501 opts = pycompat.byteskwargs(opts)
7495 opts = pycompat.byteskwargs(opts)
7502 ui.pager(b'tags')
7496 ui.pager(b'tags')
7503 fm = ui.formatter(b'tags', opts)
7497 fm = ui.formatter(b'tags', opts)
7504 hexfunc = fm.hexfunc
7498 hexfunc = fm.hexfunc
7505
7499
7506 for t, n in reversed(repo.tagslist()):
7500 for t, n in reversed(repo.tagslist()):
7507 hn = hexfunc(n)
7501 hn = hexfunc(n)
7508 label = b'tags.normal'
7502 label = b'tags.normal'
7509 tagtype = repo.tagtype(t)
7503 tagtype = repo.tagtype(t)
7510 if not tagtype or tagtype == b'global':
7504 if not tagtype or tagtype == b'global':
7511 tagtype = b''
7505 tagtype = b''
7512 else:
7506 else:
7513 label = b'tags.' + tagtype
7507 label = b'tags.' + tagtype
7514
7508
7515 fm.startitem()
7509 fm.startitem()
7516 fm.context(repo=repo)
7510 fm.context(repo=repo)
7517 fm.write(b'tag', b'%s', t, label=label)
7511 fm.write(b'tag', b'%s', t, label=label)
7518 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7512 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7519 fm.condwrite(
7513 fm.condwrite(
7520 not ui.quiet,
7514 not ui.quiet,
7521 b'rev node',
7515 b'rev node',
7522 fmt,
7516 fmt,
7523 repo.changelog.rev(n),
7517 repo.changelog.rev(n),
7524 hn,
7518 hn,
7525 label=label,
7519 label=label,
7526 )
7520 )
7527 fm.condwrite(
7521 fm.condwrite(
7528 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7522 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7529 )
7523 )
7530 fm.plain(b'\n')
7524 fm.plain(b'\n')
7531 fm.end()
7525 fm.end()
7532
7526
7533
7527
7534 @command(
7528 @command(
7535 b'tip',
7529 b'tip',
7536 [
7530 [
7537 (b'p', b'patch', None, _(b'show patch')),
7531 (b'p', b'patch', None, _(b'show patch')),
7538 (b'g', b'git', None, _(b'use git extended diff format')),
7532 (b'g', b'git', None, _(b'use git extended diff format')),
7539 ]
7533 ]
7540 + templateopts,
7534 + templateopts,
7541 _(b'[-p] [-g]'),
7535 _(b'[-p] [-g]'),
7542 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7536 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7543 )
7537 )
7544 def tip(ui, repo, **opts):
7538 def tip(ui, repo, **opts):
7545 """show the tip revision (DEPRECATED)
7539 """show the tip revision (DEPRECATED)
7546
7540
7547 The tip revision (usually just called the tip) is the changeset
7541 The tip revision (usually just called the tip) is the changeset
7548 most recently added to the repository (and therefore the most
7542 most recently added to the repository (and therefore the most
7549 recently changed head).
7543 recently changed head).
7550
7544
7551 If you have just made a commit, that commit will be the tip. If
7545 If you have just made a commit, that commit will be the tip. If
7552 you have just pulled changes from another repository, the tip of
7546 you have just pulled changes from another repository, the tip of
7553 that repository becomes the current tip. The "tip" tag is special
7547 that repository becomes the current tip. The "tip" tag is special
7554 and cannot be renamed or assigned to a different changeset.
7548 and cannot be renamed or assigned to a different changeset.
7555
7549
7556 This command is deprecated, please use :hg:`heads` instead.
7550 This command is deprecated, please use :hg:`heads` instead.
7557
7551
7558 Returns 0 on success.
7552 Returns 0 on success.
7559 """
7553 """
7560 opts = pycompat.byteskwargs(opts)
7554 opts = pycompat.byteskwargs(opts)
7561 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7555 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7562 displayer.show(repo[b'tip'])
7556 displayer.show(repo[b'tip'])
7563 displayer.close()
7557 displayer.close()
7564
7558
7565
7559
7566 @command(
7560 @command(
7567 b'unbundle',
7561 b'unbundle',
7568 [
7562 [
7569 (
7563 (
7570 b'u',
7564 b'u',
7571 b'update',
7565 b'update',
7572 None,
7566 None,
7573 _(b'update to new branch head if changesets were unbundled'),
7567 _(b'update to new branch head if changesets were unbundled'),
7574 )
7568 )
7575 ],
7569 ],
7576 _(b'[-u] FILE...'),
7570 _(b'[-u] FILE...'),
7577 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7571 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7578 )
7572 )
7579 def unbundle(ui, repo, fname1, *fnames, **opts):
7573 def unbundle(ui, repo, fname1, *fnames, **opts):
7580 """apply one or more bundle files
7574 """apply one or more bundle files
7581
7575
7582 Apply one or more bundle files generated by :hg:`bundle`.
7576 Apply one or more bundle files generated by :hg:`bundle`.
7583
7577
7584 Returns 0 on success, 1 if an update has unresolved files.
7578 Returns 0 on success, 1 if an update has unresolved files.
7585 """
7579 """
7586 fnames = (fname1,) + fnames
7580 fnames = (fname1,) + fnames
7587
7581
7588 with repo.lock():
7582 with repo.lock():
7589 for fname in fnames:
7583 for fname in fnames:
7590 f = hg.openpath(ui, fname)
7584 f = hg.openpath(ui, fname)
7591 gen = exchange.readbundle(ui, f, fname)
7585 gen = exchange.readbundle(ui, f, fname)
7592 if isinstance(gen, streamclone.streamcloneapplier):
7586 if isinstance(gen, streamclone.streamcloneapplier):
7593 raise error.InputError(
7587 raise error.InputError(
7594 _(
7588 _(
7595 b'packed bundles cannot be applied with '
7589 b'packed bundles cannot be applied with '
7596 b'"hg unbundle"'
7590 b'"hg unbundle"'
7597 ),
7591 ),
7598 hint=_(b'use "hg debugapplystreamclonebundle"'),
7592 hint=_(b'use "hg debugapplystreamclonebundle"'),
7599 )
7593 )
7600 url = b'bundle:' + fname
7594 url = b'bundle:' + fname
7601 try:
7595 try:
7602 txnname = b'unbundle'
7596 txnname = b'unbundle'
7603 if not isinstance(gen, bundle2.unbundle20):
7597 if not isinstance(gen, bundle2.unbundle20):
7604 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7598 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7605 with repo.transaction(txnname) as tr:
7599 with repo.transaction(txnname) as tr:
7606 op = bundle2.applybundle(
7600 op = bundle2.applybundle(
7607 repo, gen, tr, source=b'unbundle', url=url
7601 repo, gen, tr, source=b'unbundle', url=url
7608 )
7602 )
7609 except error.BundleUnknownFeatureError as exc:
7603 except error.BundleUnknownFeatureError as exc:
7610 raise error.Abort(
7604 raise error.Abort(
7611 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7605 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7612 hint=_(
7606 hint=_(
7613 b"see https://mercurial-scm.org/"
7607 b"see https://mercurial-scm.org/"
7614 b"wiki/BundleFeature for more "
7608 b"wiki/BundleFeature for more "
7615 b"information"
7609 b"information"
7616 ),
7610 ),
7617 )
7611 )
7618 modheads = bundle2.combinechangegroupresults(op)
7612 modheads = bundle2.combinechangegroupresults(op)
7619
7613
7620 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7614 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7621 return 1
7615 return 1
7622 else:
7616 else:
7623 return 0
7617 return 0
7624
7618
7625
7619
7626 @command(
7620 @command(
7627 b'unshelve',
7621 b'unshelve',
7628 [
7622 [
7629 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7623 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7630 (
7624 (
7631 b'c',
7625 b'c',
7632 b'continue',
7626 b'continue',
7633 None,
7627 None,
7634 _(b'continue an incomplete unshelve operation'),
7628 _(b'continue an incomplete unshelve operation'),
7635 ),
7629 ),
7636 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7630 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7637 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7631 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7638 (
7632 (
7639 b'n',
7633 b'n',
7640 b'name',
7634 b'name',
7641 b'',
7635 b'',
7642 _(b'restore shelved change with given name'),
7636 _(b'restore shelved change with given name'),
7643 _(b'NAME'),
7637 _(b'NAME'),
7644 ),
7638 ),
7645 (b't', b'tool', b'', _(b'specify merge tool')),
7639 (b't', b'tool', b'', _(b'specify merge tool')),
7646 (
7640 (
7647 b'',
7641 b'',
7648 b'date',
7642 b'date',
7649 b'',
7643 b'',
7650 _(b'set date for temporary commits (DEPRECATED)'),
7644 _(b'set date for temporary commits (DEPRECATED)'),
7651 _(b'DATE'),
7645 _(b'DATE'),
7652 ),
7646 ),
7653 ],
7647 ],
7654 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7648 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7655 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7649 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7656 )
7650 )
7657 def unshelve(ui, repo, *shelved, **opts):
7651 def unshelve(ui, repo, *shelved, **opts):
7658 """restore a shelved change to the working directory
7652 """restore a shelved change to the working directory
7659
7653
7660 This command accepts an optional name of a shelved change to
7654 This command accepts an optional name of a shelved change to
7661 restore. If none is given, the most recent shelved change is used.
7655 restore. If none is given, the most recent shelved change is used.
7662
7656
7663 If a shelved change is applied successfully, the bundle that
7657 If a shelved change is applied successfully, the bundle that
7664 contains the shelved changes is moved to a backup location
7658 contains the shelved changes is moved to a backup location
7665 (.hg/shelve-backup).
7659 (.hg/shelve-backup).
7666
7660
7667 Since you can restore a shelved change on top of an arbitrary
7661 Since you can restore a shelved change on top of an arbitrary
7668 commit, it is possible that unshelving will result in a conflict
7662 commit, it is possible that unshelving will result in a conflict
7669 between your changes and the commits you are unshelving onto. If
7663 between your changes and the commits you are unshelving onto. If
7670 this occurs, you must resolve the conflict, then use
7664 this occurs, you must resolve the conflict, then use
7671 ``--continue`` to complete the unshelve operation. (The bundle
7665 ``--continue`` to complete the unshelve operation. (The bundle
7672 will not be moved until you successfully complete the unshelve.)
7666 will not be moved until you successfully complete the unshelve.)
7673
7667
7674 (Alternatively, you can use ``--abort`` to abandon an unshelve
7668 (Alternatively, you can use ``--abort`` to abandon an unshelve
7675 that causes a conflict. This reverts the unshelved changes, and
7669 that causes a conflict. This reverts the unshelved changes, and
7676 leaves the bundle in place.)
7670 leaves the bundle in place.)
7677
7671
7678 If bare shelved change (without interactive, include and exclude
7672 If bare shelved change (without interactive, include and exclude
7679 option) was done on newly created branch it would restore branch
7673 option) was done on newly created branch it would restore branch
7680 information to the working directory.
7674 information to the working directory.
7681
7675
7682 After a successful unshelve, the shelved changes are stored in a
7676 After a successful unshelve, the shelved changes are stored in a
7683 backup directory. Only the N most recent backups are kept. N
7677 backup directory. Only the N most recent backups are kept. N
7684 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7678 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7685 configuration option.
7679 configuration option.
7686
7680
7687 .. container:: verbose
7681 .. container:: verbose
7688
7682
7689 Timestamp in seconds is used to decide order of backups. More
7683 Timestamp in seconds is used to decide order of backups. More
7690 than ``maxbackups`` backups are kept, if same timestamp
7684 than ``maxbackups`` backups are kept, if same timestamp
7691 prevents from deciding exact order of them, for safety.
7685 prevents from deciding exact order of them, for safety.
7692
7686
7693 Selected changes can be unshelved with ``--interactive`` flag.
7687 Selected changes can be unshelved with ``--interactive`` flag.
7694 The working directory is updated with the selected changes, and
7688 The working directory is updated with the selected changes, and
7695 only the unselected changes remain shelved.
7689 only the unselected changes remain shelved.
7696 Note: The whole shelve is applied to working directory first before
7690 Note: The whole shelve is applied to working directory first before
7697 running interactively. So, this will bring up all the conflicts between
7691 running interactively. So, this will bring up all the conflicts between
7698 working directory and the shelve, irrespective of which changes will be
7692 working directory and the shelve, irrespective of which changes will be
7699 unshelved.
7693 unshelved.
7700 """
7694 """
7701 with repo.wlock():
7695 with repo.wlock():
7702 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7696 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7703
7697
7704
7698
7705 statemod.addunfinished(
7699 statemod.addunfinished(
7706 b'unshelve',
7700 b'unshelve',
7707 fname=b'shelvedstate',
7701 fname=b'shelvedstate',
7708 continueflag=True,
7702 continueflag=True,
7709 abortfunc=shelvemod.hgabortunshelve,
7703 abortfunc=shelvemod.hgabortunshelve,
7710 continuefunc=shelvemod.hgcontinueunshelve,
7704 continuefunc=shelvemod.hgcontinueunshelve,
7711 cmdmsg=_(b'unshelve already in progress'),
7705 cmdmsg=_(b'unshelve already in progress'),
7712 )
7706 )
7713
7707
7714
7708
7715 @command(
7709 @command(
7716 b'update|up|checkout|co',
7710 b'update|up|checkout|co',
7717 [
7711 [
7718 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7712 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7719 (b'c', b'check', None, _(b'require clean working directory')),
7713 (b'c', b'check', None, _(b'require clean working directory')),
7720 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7714 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7721 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7715 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7722 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7716 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7723 ]
7717 ]
7724 + mergetoolopts,
7718 + mergetoolopts,
7725 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7719 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7726 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7720 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7727 helpbasic=True,
7721 helpbasic=True,
7728 )
7722 )
7729 def update(ui, repo, node=None, **opts):
7723 def update(ui, repo, node=None, **opts):
7730 """update working directory (or switch revisions)
7724 """update working directory (or switch revisions)
7731
7725
7732 Update the repository's working directory to the specified
7726 Update the repository's working directory to the specified
7733 changeset. If no changeset is specified, update to the tip of the
7727 changeset. If no changeset is specified, update to the tip of the
7734 current named branch and move the active bookmark (see :hg:`help
7728 current named branch and move the active bookmark (see :hg:`help
7735 bookmarks`).
7729 bookmarks`).
7736
7730
7737 Update sets the working directory's parent revision to the specified
7731 Update sets the working directory's parent revision to the specified
7738 changeset (see :hg:`help parents`).
7732 changeset (see :hg:`help parents`).
7739
7733
7740 If the changeset is not a descendant or ancestor of the working
7734 If the changeset is not a descendant or ancestor of the working
7741 directory's parent and there are uncommitted changes, the update is
7735 directory's parent and there are uncommitted changes, the update is
7742 aborted. With the -c/--check option, the working directory is checked
7736 aborted. With the -c/--check option, the working directory is checked
7743 for uncommitted changes; if none are found, the working directory is
7737 for uncommitted changes; if none are found, the working directory is
7744 updated to the specified changeset.
7738 updated to the specified changeset.
7745
7739
7746 .. container:: verbose
7740 .. container:: verbose
7747
7741
7748 The -C/--clean, -c/--check, and -m/--merge options control what
7742 The -C/--clean, -c/--check, and -m/--merge options control what
7749 happens if the working directory contains uncommitted changes.
7743 happens if the working directory contains uncommitted changes.
7750 At most of one of them can be specified.
7744 At most of one of them can be specified.
7751
7745
7752 1. If no option is specified, and if
7746 1. If no option is specified, and if
7753 the requested changeset is an ancestor or descendant of
7747 the requested changeset is an ancestor or descendant of
7754 the working directory's parent, the uncommitted changes
7748 the working directory's parent, the uncommitted changes
7755 are merged into the requested changeset and the merged
7749 are merged into the requested changeset and the merged
7756 result is left uncommitted. If the requested changeset is
7750 result is left uncommitted. If the requested changeset is
7757 not an ancestor or descendant (that is, it is on another
7751 not an ancestor or descendant (that is, it is on another
7758 branch), the update is aborted and the uncommitted changes
7752 branch), the update is aborted and the uncommitted changes
7759 are preserved.
7753 are preserved.
7760
7754
7761 2. With the -m/--merge option, the update is allowed even if the
7755 2. With the -m/--merge option, the update is allowed even if the
7762 requested changeset is not an ancestor or descendant of
7756 requested changeset is not an ancestor or descendant of
7763 the working directory's parent.
7757 the working directory's parent.
7764
7758
7765 3. With the -c/--check option, the update is aborted and the
7759 3. With the -c/--check option, the update is aborted and the
7766 uncommitted changes are preserved.
7760 uncommitted changes are preserved.
7767
7761
7768 4. With the -C/--clean option, uncommitted changes are discarded and
7762 4. With the -C/--clean option, uncommitted changes are discarded and
7769 the working directory is updated to the requested changeset.
7763 the working directory is updated to the requested changeset.
7770
7764
7771 To cancel an uncommitted merge (and lose your changes), use
7765 To cancel an uncommitted merge (and lose your changes), use
7772 :hg:`merge --abort`.
7766 :hg:`merge --abort`.
7773
7767
7774 Use null as the changeset to remove the working directory (like
7768 Use null as the changeset to remove the working directory (like
7775 :hg:`clone -U`).
7769 :hg:`clone -U`).
7776
7770
7777 If you want to revert just one file to an older revision, use
7771 If you want to revert just one file to an older revision, use
7778 :hg:`revert [-r REV] NAME`.
7772 :hg:`revert [-r REV] NAME`.
7779
7773
7780 See :hg:`help dates` for a list of formats valid for -d/--date.
7774 See :hg:`help dates` for a list of formats valid for -d/--date.
7781
7775
7782 Returns 0 on success, 1 if there are unresolved files.
7776 Returns 0 on success, 1 if there are unresolved files.
7783 """
7777 """
7784 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7778 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7785 rev = opts.get('rev')
7779 rev = opts.get('rev')
7786 date = opts.get('date')
7780 date = opts.get('date')
7787 clean = opts.get('clean')
7781 clean = opts.get('clean')
7788 check = opts.get('check')
7782 check = opts.get('check')
7789 merge = opts.get('merge')
7783 merge = opts.get('merge')
7790 if rev and node:
7784 if rev and node:
7791 raise error.InputError(_(b"please specify just one revision"))
7785 raise error.InputError(_(b"please specify just one revision"))
7792
7786
7793 if ui.configbool(b'commands', b'update.requiredest'):
7787 if ui.configbool(b'commands', b'update.requiredest'):
7794 if not node and not rev and not date:
7788 if not node and not rev and not date:
7795 raise error.InputError(
7789 raise error.InputError(
7796 _(b'you must specify a destination'),
7790 _(b'you must specify a destination'),
7797 hint=_(b'for example: hg update ".::"'),
7791 hint=_(b'for example: hg update ".::"'),
7798 )
7792 )
7799
7793
7800 if rev is None or rev == b'':
7794 if rev is None or rev == b'':
7801 rev = node
7795 rev = node
7802
7796
7803 if date and rev is not None:
7797 if date and rev is not None:
7804 raise error.InputError(_(b"you can't specify a revision and a date"))
7798 raise error.InputError(_(b"you can't specify a revision and a date"))
7805
7799
7806 updatecheck = None
7800 updatecheck = None
7807 if check:
7801 if check:
7808 updatecheck = b'abort'
7802 updatecheck = b'abort'
7809 elif merge:
7803 elif merge:
7810 updatecheck = b'none'
7804 updatecheck = b'none'
7811
7805
7812 with repo.wlock():
7806 with repo.wlock():
7813 cmdutil.clearunfinished(repo)
7807 cmdutil.clearunfinished(repo)
7814 if date:
7808 if date:
7815 rev = cmdutil.finddate(ui, repo, date)
7809 rev = cmdutil.finddate(ui, repo, date)
7816
7810
7817 # if we defined a bookmark, we have to remember the original name
7811 # if we defined a bookmark, we have to remember the original name
7818 brev = rev
7812 brev = rev
7819 if rev:
7813 if rev:
7820 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7814 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7821 ctx = scmutil.revsingle(repo, rev, default=None)
7815 ctx = scmutil.revsingle(repo, rev, default=None)
7822 rev = ctx.rev()
7816 rev = ctx.rev()
7823 hidden = ctx.hidden()
7817 hidden = ctx.hidden()
7824 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7818 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7825 with ui.configoverride(overrides, b'update'):
7819 with ui.configoverride(overrides, b'update'):
7826 ret = hg.updatetotally(
7820 ret = hg.updatetotally(
7827 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7821 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7828 )
7822 )
7829 if hidden:
7823 if hidden:
7830 ctxstr = ctx.hex()[:12]
7824 ctxstr = ctx.hex()[:12]
7831 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7825 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7832
7826
7833 if ctx.obsolete():
7827 if ctx.obsolete():
7834 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7828 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7835 ui.warn(b"(%s)\n" % obsfatemsg)
7829 ui.warn(b"(%s)\n" % obsfatemsg)
7836 return ret
7830 return ret
7837
7831
7838
7832
7839 @command(
7833 @command(
7840 b'verify',
7834 b'verify',
7841 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7835 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7842 helpcategory=command.CATEGORY_MAINTENANCE,
7836 helpcategory=command.CATEGORY_MAINTENANCE,
7843 )
7837 )
7844 def verify(ui, repo, **opts):
7838 def verify(ui, repo, **opts):
7845 """verify the integrity of the repository
7839 """verify the integrity of the repository
7846
7840
7847 Verify the integrity of the current repository.
7841 Verify the integrity of the current repository.
7848
7842
7849 This will perform an extensive check of the repository's
7843 This will perform an extensive check of the repository's
7850 integrity, validating the hashes and checksums of each entry in
7844 integrity, validating the hashes and checksums of each entry in
7851 the changelog, manifest, and tracked files, as well as the
7845 the changelog, manifest, and tracked files, as well as the
7852 integrity of their crosslinks and indices.
7846 integrity of their crosslinks and indices.
7853
7847
7854 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7848 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7855 for more information about recovery from corruption of the
7849 for more information about recovery from corruption of the
7856 repository.
7850 repository.
7857
7851
7858 Returns 0 on success, 1 if errors are encountered.
7852 Returns 0 on success, 1 if errors are encountered.
7859 """
7853 """
7860 opts = pycompat.byteskwargs(opts)
7854 opts = pycompat.byteskwargs(opts)
7861
7855
7862 level = None
7856 level = None
7863 if opts[b'full']:
7857 if opts[b'full']:
7864 level = verifymod.VERIFY_FULL
7858 level = verifymod.VERIFY_FULL
7865 return hg.verify(repo, level)
7859 return hg.verify(repo, level)
7866
7860
7867
7861
7868 @command(
7862 @command(
7869 b'version',
7863 b'version',
7870 [] + formatteropts,
7864 [] + formatteropts,
7871 helpcategory=command.CATEGORY_HELP,
7865 helpcategory=command.CATEGORY_HELP,
7872 norepo=True,
7866 norepo=True,
7873 intents={INTENT_READONLY},
7867 intents={INTENT_READONLY},
7874 )
7868 )
7875 def version_(ui, **opts):
7869 def version_(ui, **opts):
7876 """output version and copyright information
7870 """output version and copyright information
7877
7871
7878 .. container:: verbose
7872 .. container:: verbose
7879
7873
7880 Template:
7874 Template:
7881
7875
7882 The following keywords are supported. See also :hg:`help templates`.
7876 The following keywords are supported. See also :hg:`help templates`.
7883
7877
7884 :extensions: List of extensions.
7878 :extensions: List of extensions.
7885 :ver: String. Version number.
7879 :ver: String. Version number.
7886
7880
7887 And each entry of ``{extensions}`` provides the following sub-keywords
7881 And each entry of ``{extensions}`` provides the following sub-keywords
7888 in addition to ``{ver}``.
7882 in addition to ``{ver}``.
7889
7883
7890 :bundled: Boolean. True if included in the release.
7884 :bundled: Boolean. True if included in the release.
7891 :name: String. Extension name.
7885 :name: String. Extension name.
7892 """
7886 """
7893 opts = pycompat.byteskwargs(opts)
7887 opts = pycompat.byteskwargs(opts)
7894 if ui.verbose:
7888 if ui.verbose:
7895 ui.pager(b'version')
7889 ui.pager(b'version')
7896 fm = ui.formatter(b"version", opts)
7890 fm = ui.formatter(b"version", opts)
7897 fm.startitem()
7891 fm.startitem()
7898 fm.write(
7892 fm.write(
7899 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7893 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7900 )
7894 )
7901 license = _(
7895 license = _(
7902 b"(see https://mercurial-scm.org for more information)\n"
7896 b"(see https://mercurial-scm.org for more information)\n"
7903 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7897 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7904 b"This is free software; see the source for copying conditions. "
7898 b"This is free software; see the source for copying conditions. "
7905 b"There is NO\nwarranty; "
7899 b"There is NO\nwarranty; "
7906 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7900 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7907 )
7901 )
7908 if not ui.quiet:
7902 if not ui.quiet:
7909 fm.plain(license)
7903 fm.plain(license)
7910
7904
7911 if ui.verbose:
7905 if ui.verbose:
7912 fm.plain(_(b"\nEnabled extensions:\n\n"))
7906 fm.plain(_(b"\nEnabled extensions:\n\n"))
7913 # format names and versions into columns
7907 # format names and versions into columns
7914 names = []
7908 names = []
7915 vers = []
7909 vers = []
7916 isinternals = []
7910 isinternals = []
7917 for name, module in sorted(extensions.extensions()):
7911 for name, module in sorted(extensions.extensions()):
7918 names.append(name)
7912 names.append(name)
7919 vers.append(extensions.moduleversion(module) or None)
7913 vers.append(extensions.moduleversion(module) or None)
7920 isinternals.append(extensions.ismoduleinternal(module))
7914 isinternals.append(extensions.ismoduleinternal(module))
7921 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7915 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7922 if names:
7916 if names:
7923 namefmt = b" %%-%ds " % max(len(n) for n in names)
7917 namefmt = b" %%-%ds " % max(len(n) for n in names)
7924 places = [_(b"external"), _(b"internal")]
7918 places = [_(b"external"), _(b"internal")]
7925 for n, v, p in zip(names, vers, isinternals):
7919 for n, v, p in zip(names, vers, isinternals):
7926 fn.startitem()
7920 fn.startitem()
7927 fn.condwrite(ui.verbose, b"name", namefmt, n)
7921 fn.condwrite(ui.verbose, b"name", namefmt, n)
7928 if ui.verbose:
7922 if ui.verbose:
7929 fn.plain(b"%s " % places[p])
7923 fn.plain(b"%s " % places[p])
7930 fn.data(bundled=p)
7924 fn.data(bundled=p)
7931 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7925 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7932 if ui.verbose:
7926 if ui.verbose:
7933 fn.plain(b"\n")
7927 fn.plain(b"\n")
7934 fn.end()
7928 fn.end()
7935 fm.end()
7929 fm.end()
7936
7930
7937
7931
7938 def loadcmdtable(ui, name, cmdtable):
7932 def loadcmdtable(ui, name, cmdtable):
7939 """Load command functions from specified cmdtable"""
7933 """Load command functions from specified cmdtable"""
7940 overrides = [cmd for cmd in cmdtable if cmd in table]
7934 overrides = [cmd for cmd in cmdtable if cmd in table]
7941 if overrides:
7935 if overrides:
7942 ui.warn(
7936 ui.warn(
7943 _(b"extension '%s' overrides commands: %s\n")
7937 _(b"extension '%s' overrides commands: %s\n")
7944 % (name, b" ".join(overrides))
7938 % (name, b" ".join(overrides))
7945 )
7939 )
7946 table.update(cmdtable)
7940 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now