##// END OF EJS Templates
typing: convert an annotation to an assertion in commands.py...
Matt Harbison -
r48563:76dccbbe stable
parent child Browse files
Show More
@@ -1,7973 +1,7968 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:
79 from typing import (
80 List,
81 )
82
83
84 table = {}
78 table = {}
85 table.update(debugcommandsmod.command._table)
79 table.update(debugcommandsmod.command._table)
86
80
87 command = registrar.command(table)
81 command = registrar.command(table)
88 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
89
83
90 # common command options
84 # common command options
91
85
92 globalopts = [
86 globalopts = [
93 (
87 (
94 b'R',
88 b'R',
95 b'repository',
89 b'repository',
96 b'',
90 b'',
97 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
98 _(b'REPO'),
92 _(b'REPO'),
99 ),
93 ),
100 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
101 (
95 (
102 b'y',
96 b'y',
103 b'noninteractive',
97 b'noninteractive',
104 None,
98 None,
105 _(
99 _(
106 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
107 ),
101 ),
108 ),
102 ),
109 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
110 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
111 (
105 (
112 b'',
106 b'',
113 b'color',
107 b'color',
114 b'',
108 b'',
115 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
116 # and should not be translated
110 # and should not be translated
117 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
118 _(b'TYPE'),
112 _(b'TYPE'),
119 ),
113 ),
120 (
114 (
121 b'',
115 b'',
122 b'config',
116 b'config',
123 [],
117 [],
124 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
125 _(b'CONFIG'),
119 _(b'CONFIG'),
126 ),
120 ),
127 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
128 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
129 (
123 (
130 b'',
124 b'',
131 b'encoding',
125 b'encoding',
132 encoding.encoding,
126 encoding.encoding,
133 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
134 _(b'ENCODE'),
128 _(b'ENCODE'),
135 ),
129 ),
136 (
130 (
137 b'',
131 b'',
138 b'encodingmode',
132 b'encodingmode',
139 encoding.encodingmode,
133 encoding.encodingmode,
140 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
141 _(b'MODE'),
135 _(b'MODE'),
142 ),
136 ),
143 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
144 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
145 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
146 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
147 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
148 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
149 (
143 (
150 b'',
144 b'',
151 b'pager',
145 b'pager',
152 b'auto',
146 b'auto',
153 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
154 _(b'TYPE'),
148 _(b'TYPE'),
155 ),
149 ),
156 ]
150 ]
157
151
158 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
159 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
160 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
161 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
162 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
163 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
164 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
165 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
166 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
167 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
168 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
169 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
170 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
171 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
172 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
173 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
174
168
175 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
176
170
177
171
178 @command(
172 @command(
179 b'abort',
173 b'abort',
180 dryrunopts,
174 dryrunopts,
181 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
182 helpbasic=True,
176 helpbasic=True,
183 )
177 )
184 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
185 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
186
180
187 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
188 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
189
183
190 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
191 """
185 """
192 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
193 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
194 if not abortstate:
188 if not abortstate:
195 raise error.StateError(_(b'no operation in progress'))
189 raise error.StateError(_(b'no operation in progress'))
196 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
197 raise error.InputError(
191 raise error.InputError(
198 (
192 (
199 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
200 % (abortstate._opname)
194 % (abortstate._opname)
201 ),
195 ),
202 hint=abortstate.hint(),
196 hint=abortstate.hint(),
203 )
197 )
204 if dryrun:
198 if dryrun:
205 ui.status(
199 ui.status(
206 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
207 )
201 )
208 return
202 return
209 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
210
204
211
205
212 @command(
206 @command(
213 b'add',
207 b'add',
214 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
215 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
216 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
217 helpbasic=True,
211 helpbasic=True,
218 inferrepo=True,
212 inferrepo=True,
219 )
213 )
220 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
221 """add the specified files on the next commit
215 """add the specified files on the next commit
222
216
223 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
224 repository.
218 repository.
225
219
226 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
227 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
228
222
229 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
230 files matching ``.hgignore``).
224 files matching ``.hgignore``).
231
225
232 .. container:: verbose
226 .. container:: verbose
233
227
234 Examples:
228 Examples:
235
229
236 - New (unknown) files are added
230 - New (unknown) files are added
237 automatically by :hg:`add`::
231 automatically by :hg:`add`::
238
232
239 $ ls
233 $ ls
240 foo.c
234 foo.c
241 $ hg status
235 $ hg status
242 ? foo.c
236 ? foo.c
243 $ hg add
237 $ hg add
244 adding foo.c
238 adding foo.c
245 $ hg status
239 $ hg status
246 A foo.c
240 A foo.c
247
241
248 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
249
243
250 $ ls
244 $ ls
251 bar.c foo.c
245 bar.c foo.c
252 $ hg status
246 $ hg status
253 ? bar.c
247 ? bar.c
254 ? foo.c
248 ? foo.c
255 $ hg add bar.c
249 $ hg add bar.c
256 $ hg status
250 $ hg status
257 A bar.c
251 A bar.c
258 ? foo.c
252 ? foo.c
259
253
260 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
261 """
255 """
262
256
263 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
264 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
265 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
266 return rejected and 1 or 0
260 return rejected and 1 or 0
267
261
268
262
269 @command(
263 @command(
270 b'addremove',
264 b'addremove',
271 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
272 _(b'[OPTION]... [FILE]...'),
266 _(b'[OPTION]... [FILE]...'),
273 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
274 inferrepo=True,
268 inferrepo=True,
275 )
269 )
276 def addremove(ui, repo, *pats, **opts):
270 def addremove(ui, repo, *pats, **opts):
277 """add all new files, delete all missing files
271 """add all new files, delete all missing files
278
272
279 Add all new files and remove all missing files from the
273 Add all new files and remove all missing files from the
280 repository.
274 repository.
281
275
282 Unless names are given, new files are ignored if they match any of
276 Unless names are given, new files are ignored if they match any of
283 the patterns in ``.hgignore``. As with add, these changes take
277 the patterns in ``.hgignore``. As with add, these changes take
284 effect at the next commit.
278 effect at the next commit.
285
279
286 Use the -s/--similarity option to detect renamed files. This
280 Use the -s/--similarity option to detect renamed files. This
287 option takes a percentage between 0 (disabled) and 100 (files must
281 option takes a percentage between 0 (disabled) and 100 (files must
288 be identical) as its parameter. With a parameter greater than 0,
282 be identical) as its parameter. With a parameter greater than 0,
289 this compares every removed file with every added file and records
283 this compares every removed file with every added file and records
290 those similar enough as renames. Detecting renamed files this way
284 those similar enough as renames. Detecting renamed files this way
291 can be expensive. After using this option, :hg:`status -C` can be
285 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
286 used to check which files were identified as moved or renamed. If
293 not specified, -s/--similarity defaults to 100 and only renames of
287 not specified, -s/--similarity defaults to 100 and only renames of
294 identical files are detected.
288 identical files are detected.
295
289
296 .. container:: verbose
290 .. container:: verbose
297
291
298 Examples:
292 Examples:
299
293
300 - A number of files (bar.c and foo.c) are new,
294 - A number of files (bar.c and foo.c) are new,
301 while foobar.c has been removed (without using :hg:`remove`)
295 while foobar.c has been removed (without using :hg:`remove`)
302 from the repository::
296 from the repository::
303
297
304 $ ls
298 $ ls
305 bar.c foo.c
299 bar.c foo.c
306 $ hg status
300 $ hg status
307 ! foobar.c
301 ! foobar.c
308 ? bar.c
302 ? bar.c
309 ? foo.c
303 ? foo.c
310 $ hg addremove
304 $ hg addremove
311 adding bar.c
305 adding bar.c
312 adding foo.c
306 adding foo.c
313 removing foobar.c
307 removing foobar.c
314 $ hg status
308 $ hg status
315 A bar.c
309 A bar.c
316 A foo.c
310 A foo.c
317 R foobar.c
311 R foobar.c
318
312
319 - A file foobar.c was moved to foo.c without using :hg:`rename`.
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 Afterwards, it was edited slightly::
314 Afterwards, it was edited slightly::
321
315
322 $ ls
316 $ ls
323 foo.c
317 foo.c
324 $ hg status
318 $ hg status
325 ! foobar.c
319 ! foobar.c
326 ? foo.c
320 ? foo.c
327 $ hg addremove --similarity 90
321 $ hg addremove --similarity 90
328 removing foobar.c
322 removing foobar.c
329 adding foo.c
323 adding foo.c
330 recording removal of foobar.c as rename to foo.c (94% similar)
324 recording removal of foobar.c as rename to foo.c (94% similar)
331 $ hg status -C
325 $ hg status -C
332 A foo.c
326 A foo.c
333 foobar.c
327 foobar.c
334 R foobar.c
328 R foobar.c
335
329
336 Returns 0 if all files are successfully added.
330 Returns 0 if all files are successfully added.
337 """
331 """
338 opts = pycompat.byteskwargs(opts)
332 opts = pycompat.byteskwargs(opts)
339 if not opts.get(b'similarity'):
333 if not opts.get(b'similarity'):
340 opts[b'similarity'] = b'100'
334 opts[b'similarity'] = b'100'
341 matcher = scmutil.match(repo[None], pats, opts)
335 matcher = scmutil.match(repo[None], pats, opts)
342 relative = scmutil.anypats(pats, opts)
336 relative = scmutil.anypats(pats, opts)
343 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
344 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
345
339
346
340
347 @command(
341 @command(
348 b'annotate|blame',
342 b'annotate|blame',
349 [
343 [
350 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
351 (
345 (
352 b'',
346 b'',
353 b'follow',
347 b'follow',
354 None,
348 None,
355 _(b'follow copies/renames and list the filename (DEPRECATED)'),
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
356 ),
350 ),
357 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
358 (b'a', b'text', None, _(b'treat all files as text')),
352 (b'a', b'text', None, _(b'treat all files as text')),
359 (b'u', b'user', None, _(b'list the author (long with -v)')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
360 (b'f', b'file', None, _(b'list the filename')),
354 (b'f', b'file', None, _(b'list the filename')),
361 (b'd', b'date', None, _(b'list the date (short with -q)')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
362 (b'n', b'number', None, _(b'list the revision number (default)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
363 (b'c', b'changeset', None, _(b'list the changeset')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
364 (
358 (
365 b'l',
359 b'l',
366 b'line-number',
360 b'line-number',
367 None,
361 None,
368 _(b'show line number at the first appearance'),
362 _(b'show line number at the first appearance'),
369 ),
363 ),
370 (
364 (
371 b'',
365 b'',
372 b'skip',
366 b'skip',
373 [],
367 [],
374 _(b'revset to not display (EXPERIMENTAL)'),
368 _(b'revset to not display (EXPERIMENTAL)'),
375 _(b'REV'),
369 _(b'REV'),
376 ),
370 ),
377 ]
371 ]
378 + diffwsopts
372 + diffwsopts
379 + walkopts
373 + walkopts
380 + formatteropts,
374 + formatteropts,
381 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
382 helpcategory=command.CATEGORY_FILE_CONTENTS,
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
383 helpbasic=True,
377 helpbasic=True,
384 inferrepo=True,
378 inferrepo=True,
385 )
379 )
386 def annotate(ui, repo, *pats, **opts):
380 def annotate(ui, repo, *pats, **opts):
387 """show changeset information by line for each file
381 """show changeset information by line for each file
388
382
389 List changes in files, showing the revision id responsible for
383 List changes in files, showing the revision id responsible for
390 each line.
384 each line.
391
385
392 This command is useful for discovering when a change was made and
386 This command is useful for discovering when a change was made and
393 by whom.
387 by whom.
394
388
395 If you include --file, --user, or --date, the revision number is
389 If you include --file, --user, or --date, the revision number is
396 suppressed unless you also include --number.
390 suppressed unless you also include --number.
397
391
398 Without the -a/--text option, annotate will avoid processing files
392 Without the -a/--text option, annotate will avoid processing files
399 it detects as binary. With -a, annotate will annotate the file
393 it detects as binary. With -a, annotate will annotate the file
400 anyway, although the results will probably be neither useful
394 anyway, although the results will probably be neither useful
401 nor desirable.
395 nor desirable.
402
396
403 .. container:: verbose
397 .. container:: verbose
404
398
405 Template:
399 Template:
406
400
407 The following keywords are supported in addition to the common template
401 The following keywords are supported in addition to the common template
408 keywords and functions. See also :hg:`help templates`.
402 keywords and functions. See also :hg:`help templates`.
409
403
410 :lines: List of lines with annotation data.
404 :lines: List of lines with annotation data.
411 :path: String. Repository-absolute path of the specified file.
405 :path: String. Repository-absolute path of the specified file.
412
406
413 And each entry of ``{lines}`` provides the following sub-keywords in
407 And each entry of ``{lines}`` provides the following sub-keywords in
414 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
415
409
416 :line: String. Line content.
410 :line: String. Line content.
417 :lineno: Integer. Line number at that revision.
411 :lineno: Integer. Line number at that revision.
418 :path: String. Repository-absolute path of the file at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
419
413
420 See :hg:`help templates.operators` for the list expansion syntax.
414 See :hg:`help templates.operators` for the list expansion syntax.
421
415
422 Returns 0 on success.
416 Returns 0 on success.
423 """
417 """
424 opts = pycompat.byteskwargs(opts)
418 opts = pycompat.byteskwargs(opts)
425 if not pats:
419 if not pats:
426 raise error.InputError(
420 raise error.InputError(
427 _(b'at least one filename or pattern is required')
421 _(b'at least one filename or pattern is required')
428 )
422 )
429
423
430 if opts.get(b'follow'):
424 if opts.get(b'follow'):
431 # --follow is deprecated and now just an alias for -f/--file
425 # --follow is deprecated and now just an alias for -f/--file
432 # to mimic the behavior of Mercurial before version 1.5
426 # to mimic the behavior of Mercurial before version 1.5
433 opts[b'file'] = True
427 opts[b'file'] = True
434
428
435 if (
429 if (
436 not opts.get(b'user')
430 not opts.get(b'user')
437 and not opts.get(b'changeset')
431 and not opts.get(b'changeset')
438 and not opts.get(b'date')
432 and not opts.get(b'date')
439 and not opts.get(b'file')
433 and not opts.get(b'file')
440 ):
434 ):
441 opts[b'number'] = True
435 opts[b'number'] = True
442
436
443 linenumber = opts.get(b'line_number') is not None
437 linenumber = opts.get(b'line_number') is not None
444 if (
438 if (
445 linenumber
439 linenumber
446 and (not opts.get(b'changeset'))
440 and (not opts.get(b'changeset'))
447 and (not opts.get(b'number'))
441 and (not opts.get(b'number'))
448 ):
442 ):
449 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
443 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
450
444
451 rev = opts.get(b'rev')
445 rev = opts.get(b'rev')
452 if rev:
446 if rev:
453 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
454 ctx = scmutil.revsingle(repo, rev)
448 ctx = scmutil.revsingle(repo, rev)
455
449
456 ui.pager(b'annotate')
450 ui.pager(b'annotate')
457 rootfm = ui.formatter(b'annotate', opts)
451 rootfm = ui.formatter(b'annotate', opts)
458 if ui.debugflag:
452 if ui.debugflag:
459 shorthex = pycompat.identity
453 shorthex = pycompat.identity
460 else:
454 else:
461
455
462 def shorthex(h):
456 def shorthex(h):
463 return h[:12]
457 return h[:12]
464
458
465 if ui.quiet:
459 if ui.quiet:
466 datefunc = dateutil.shortdate
460 datefunc = dateutil.shortdate
467 else:
461 else:
468 datefunc = dateutil.datestr
462 datefunc = dateutil.datestr
469 if ctx.rev() is None:
463 if ctx.rev() is None:
470 if opts.get(b'changeset'):
464 if opts.get(b'changeset'):
471 # omit "+" suffix which is appended to node hex
465 # omit "+" suffix which is appended to node hex
472 def formatrev(rev):
466 def formatrev(rev):
473 if rev == wdirrev:
467 if rev == wdirrev:
474 return b'%d' % ctx.p1().rev()
468 return b'%d' % ctx.p1().rev()
475 else:
469 else:
476 return b'%d' % rev
470 return b'%d' % rev
477
471
478 else:
472 else:
479
473
480 def formatrev(rev):
474 def formatrev(rev):
481 if rev == wdirrev:
475 if rev == wdirrev:
482 return b'%d+' % ctx.p1().rev()
476 return b'%d+' % ctx.p1().rev()
483 else:
477 else:
484 return b'%d ' % rev
478 return b'%d ' % rev
485
479
486 def formathex(h):
480 def formathex(h):
487 if h == repo.nodeconstants.wdirhex:
481 if h == repo.nodeconstants.wdirhex:
488 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 return b'%s+' % shorthex(hex(ctx.p1().node()))
489 else:
483 else:
490 return b'%s ' % shorthex(h)
484 return b'%s ' % shorthex(h)
491
485
492 else:
486 else:
493 formatrev = b'%d'.__mod__
487 formatrev = b'%d'.__mod__
494 formathex = shorthex
488 formathex = shorthex
495
489
496 opmap = [
490 opmap = [
497 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
498 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
499 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
500 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
501 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
502 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
503 ]
497 ]
504 opnamemap = {
498 opnamemap = {
505 b'rev': b'number',
499 b'rev': b'number',
506 b'node': b'changeset',
500 b'node': b'changeset',
507 b'path': b'file',
501 b'path': b'file',
508 b'lineno': b'line_number',
502 b'lineno': b'line_number',
509 }
503 }
510
504
511 if rootfm.isplain():
505 if rootfm.isplain():
512
506
513 def makefunc(get, fmt):
507 def makefunc(get, fmt):
514 return lambda x: fmt(get(x))
508 return lambda x: fmt(get(x))
515
509
516 else:
510 else:
517
511
518 def makefunc(get, fmt):
512 def makefunc(get, fmt):
519 return get
513 return get
520
514
521 datahint = rootfm.datahint()
515 datahint = rootfm.datahint()
522 funcmap = [
516 funcmap = [
523 (makefunc(get, fmt), sep)
517 (makefunc(get, fmt), sep)
524 for fn, sep, get, fmt in opmap
518 for fn, sep, get, fmt in opmap
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 ]
520 ]
527 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
528 fields = b' '.join(
522 fields = b' '.join(
529 fn
523 fn
530 for fn, sep, get, fmt in opmap
524 for fn, sep, get, fmt in opmap
531 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
532 )
526 )
533
527
534 def bad(x, y):
528 def bad(x, y):
535 raise error.Abort(b"%s: %s" % (x, y))
529 raise error.Abort(b"%s: %s" % (x, y))
536
530
537 m = scmutil.match(ctx, pats, opts, badfn=bad)
531 m = scmutil.match(ctx, pats, opts, badfn=bad)
538
532
539 follow = not opts.get(b'no_follow')
533 follow = not opts.get(b'no_follow')
540 diffopts = patch.difffeatureopts(
534 diffopts = patch.difffeatureopts(
541 ui, opts, section=b'annotate', whitespace=True
535 ui, opts, section=b'annotate', whitespace=True
542 )
536 )
543 skiprevs = opts.get(b'skip')
537 skiprevs = opts.get(b'skip')
544 if skiprevs:
538 if skiprevs:
545 skiprevs = scmutil.revrange(repo, skiprevs)
539 skiprevs = scmutil.revrange(repo, skiprevs)
546
540
547 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
548 for abs in ctx.walk(m):
542 for abs in ctx.walk(m):
549 fctx = ctx[abs]
543 fctx = ctx[abs]
550 rootfm.startitem()
544 rootfm.startitem()
551 rootfm.data(path=abs)
545 rootfm.data(path=abs)
552 if not opts.get(b'text') and fctx.isbinary():
546 if not opts.get(b'text') and fctx.isbinary():
553 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
554 continue
548 continue
555
549
556 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
557 lines = fctx.annotate(
551 lines = fctx.annotate(
558 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 follow=follow, skiprevs=skiprevs, diffopts=diffopts
559 )
553 )
560 if not lines:
554 if not lines:
561 fm.end()
555 fm.end()
562 continue
556 continue
563 formats = []
557 formats = []
564 pieces = []
558 pieces = []
565
559
566 for f, sep in funcmap:
560 for f, sep in funcmap:
567 l = [f(n) for n in lines]
561 l = [f(n) for n in lines]
568 if fm.isplain():
562 if fm.isplain():
569 sizes = [encoding.colwidth(x) for x in l]
563 sizes = [encoding.colwidth(x) for x in l]
570 ml = max(sizes)
564 ml = max(sizes)
571 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
572 else:
566 else:
573 formats.append([b'%s'] * len(l))
567 formats.append([b'%s'] * len(l))
574 pieces.append(l)
568 pieces.append(l)
575
569
576 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
577 fm.startitem()
571 fm.startitem()
578 fm.context(fctx=n.fctx)
572 fm.context(fctx=n.fctx)
579 fm.write(fields, b"".join(f), *p)
573 fm.write(fields, b"".join(f), *p)
580 if n.skip:
574 if n.skip:
581 fmt = b"* %s"
575 fmt = b"* %s"
582 else:
576 else:
583 fmt = b": %s"
577 fmt = b": %s"
584 fm.write(b'line', fmt, n.text)
578 fm.write(b'line', fmt, n.text)
585
579
586 if not lines[-1].text.endswith(b'\n'):
580 if not lines[-1].text.endswith(b'\n'):
587 fm.plain(b'\n')
581 fm.plain(b'\n')
588 fm.end()
582 fm.end()
589
583
590 rootfm.end()
584 rootfm.end()
591
585
592
586
593 @command(
587 @command(
594 b'archive',
588 b'archive',
595 [
589 [
596 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
597 (
591 (
598 b'p',
592 b'p',
599 b'prefix',
593 b'prefix',
600 b'',
594 b'',
601 _(b'directory prefix for files in archive'),
595 _(b'directory prefix for files in archive'),
602 _(b'PREFIX'),
596 _(b'PREFIX'),
603 ),
597 ),
604 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
598 (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')),
599 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
606 ]
600 ]
607 + subrepoopts
601 + subrepoopts
608 + walkopts,
602 + walkopts,
609 _(b'[OPTION]... DEST'),
603 _(b'[OPTION]... DEST'),
610 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 helpcategory=command.CATEGORY_IMPORT_EXPORT,
611 )
605 )
612 def archive(ui, repo, dest, **opts):
606 def archive(ui, repo, dest, **opts):
613 """create an unversioned archive of a repository revision
607 """create an unversioned archive of a repository revision
614
608
615 By default, the revision used is the parent of the working
609 By default, the revision used is the parent of the working
616 directory; use -r/--rev to specify a different revision.
610 directory; use -r/--rev to specify a different revision.
617
611
618 The archive type is automatically detected based on file
612 The archive type is automatically detected based on file
619 extension (to override, use -t/--type).
613 extension (to override, use -t/--type).
620
614
621 .. container:: verbose
615 .. container:: verbose
622
616
623 Examples:
617 Examples:
624
618
625 - create a zip file containing the 1.0 release::
619 - create a zip file containing the 1.0 release::
626
620
627 hg archive -r 1.0 project-1.0.zip
621 hg archive -r 1.0 project-1.0.zip
628
622
629 - create a tarball excluding .hg files::
623 - create a tarball excluding .hg files::
630
624
631 hg archive project.tar.gz -X ".hg*"
625 hg archive project.tar.gz -X ".hg*"
632
626
633 Valid types are:
627 Valid types are:
634
628
635 :``files``: a directory full of files (default)
629 :``files``: a directory full of files (default)
636 :``tar``: tar archive, uncompressed
630 :``tar``: tar archive, uncompressed
637 :``tbz2``: tar archive, compressed using bzip2
631 :``tbz2``: tar archive, compressed using bzip2
638 :``tgz``: tar archive, compressed using gzip
632 :``tgz``: tar archive, compressed using gzip
639 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``txz``: tar archive, compressed using lzma (only in Python 3)
640 :``uzip``: zip archive, uncompressed
634 :``uzip``: zip archive, uncompressed
641 :``zip``: zip archive, compressed using deflate
635 :``zip``: zip archive, compressed using deflate
642
636
643 The exact name of the destination archive or directory is given
637 The exact name of the destination archive or directory is given
644 using a format string; see :hg:`help export` for details.
638 using a format string; see :hg:`help export` for details.
645
639
646 Each member added to an archive file has a directory prefix
640 Each member added to an archive file has a directory prefix
647 prepended. Use -p/--prefix to specify a format string for the
641 prepended. Use -p/--prefix to specify a format string for the
648 prefix. The default is the basename of the archive, with suffixes
642 prefix. The default is the basename of the archive, with suffixes
649 removed.
643 removed.
650
644
651 Returns 0 on success.
645 Returns 0 on success.
652 """
646 """
653
647
654 opts = pycompat.byteskwargs(opts)
648 opts = pycompat.byteskwargs(opts)
655 rev = opts.get(b'rev')
649 rev = opts.get(b'rev')
656 if rev:
650 if rev:
657 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
658 ctx = scmutil.revsingle(repo, rev)
652 ctx = scmutil.revsingle(repo, rev)
659 if not ctx:
653 if not ctx:
660 raise error.InputError(
654 raise error.InputError(
661 _(b'no working directory: please specify a revision')
655 _(b'no working directory: please specify a revision')
662 )
656 )
663 node = ctx.node()
657 node = ctx.node()
664 dest = cmdutil.makefilename(ctx, dest)
658 dest = cmdutil.makefilename(ctx, dest)
665 if os.path.realpath(dest) == repo.root:
659 if os.path.realpath(dest) == repo.root:
666 raise error.InputError(_(b'repository root cannot be destination'))
660 raise error.InputError(_(b'repository root cannot be destination'))
667
661
668 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
662 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
669 prefix = opts.get(b'prefix')
663 prefix = opts.get(b'prefix')
670
664
671 if dest == b'-':
665 if dest == b'-':
672 if kind == b'files':
666 if kind == b'files':
673 raise error.InputError(_(b'cannot archive plain files to stdout'))
667 raise error.InputError(_(b'cannot archive plain files to stdout'))
674 dest = cmdutil.makefileobj(ctx, dest)
668 dest = cmdutil.makefileobj(ctx, dest)
675 if not prefix:
669 if not prefix:
676 prefix = os.path.basename(repo.root) + b'-%h'
670 prefix = os.path.basename(repo.root) + b'-%h'
677
671
678 prefix = cmdutil.makefilename(ctx, prefix)
672 prefix = cmdutil.makefilename(ctx, prefix)
679 match = scmutil.match(ctx, [], opts)
673 match = scmutil.match(ctx, [], opts)
680 archival.archive(
674 archival.archive(
681 repo,
675 repo,
682 dest,
676 dest,
683 node,
677 node,
684 kind,
678 kind,
685 not opts.get(b'no_decode'),
679 not opts.get(b'no_decode'),
686 match,
680 match,
687 prefix,
681 prefix,
688 subrepos=opts.get(b'subrepos'),
682 subrepos=opts.get(b'subrepos'),
689 )
683 )
690
684
691
685
692 @command(
686 @command(
693 b'backout',
687 b'backout',
694 [
688 [
695 (
689 (
696 b'',
690 b'',
697 b'merge',
691 b'merge',
698 None,
692 None,
699 _(b'merge with old dirstate parent after backout'),
693 _(b'merge with old dirstate parent after backout'),
700 ),
694 ),
701 (
695 (
702 b'',
696 b'',
703 b'commit',
697 b'commit',
704 None,
698 None,
705 _(b'commit if no conflicts were encountered (DEPRECATED)'),
699 _(b'commit if no conflicts were encountered (DEPRECATED)'),
706 ),
700 ),
707 (b'', b'no-commit', None, _(b'do not commit')),
701 (b'', b'no-commit', None, _(b'do not commit')),
708 (
702 (
709 b'',
703 b'',
710 b'parent',
704 b'parent',
711 b'',
705 b'',
712 _(b'parent to choose when backing out merge (DEPRECATED)'),
706 _(b'parent to choose when backing out merge (DEPRECATED)'),
713 _(b'REV'),
707 _(b'REV'),
714 ),
708 ),
715 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
709 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
716 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
710 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
717 ]
711 ]
718 + mergetoolopts
712 + mergetoolopts
719 + walkopts
713 + walkopts
720 + commitopts
714 + commitopts
721 + commitopts2,
715 + commitopts2,
722 _(b'[OPTION]... [-r] REV'),
716 _(b'[OPTION]... [-r] REV'),
723 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
717 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
724 )
718 )
725 def backout(ui, repo, node=None, rev=None, **opts):
719 def backout(ui, repo, node=None, rev=None, **opts):
726 """reverse effect of earlier changeset
720 """reverse effect of earlier changeset
727
721
728 Prepare a new changeset with the effect of REV undone in the
722 Prepare a new changeset with the effect of REV undone in the
729 current working directory. If no conflicts were encountered,
723 current working directory. If no conflicts were encountered,
730 it will be committed immediately.
724 it will be committed immediately.
731
725
732 If REV is the parent of the working directory, then this new changeset
726 If REV is the parent of the working directory, then this new changeset
733 is committed automatically (unless --no-commit is specified).
727 is committed automatically (unless --no-commit is specified).
734
728
735 .. note::
729 .. note::
736
730
737 :hg:`backout` cannot be used to fix either an unwanted or
731 :hg:`backout` cannot be used to fix either an unwanted or
738 incorrect merge.
732 incorrect merge.
739
733
740 .. container:: verbose
734 .. container:: verbose
741
735
742 Examples:
736 Examples:
743
737
744 - Reverse the effect of the parent of the working directory.
738 - Reverse the effect of the parent of the working directory.
745 This backout will be committed immediately::
739 This backout will be committed immediately::
746
740
747 hg backout -r .
741 hg backout -r .
748
742
749 - Reverse the effect of previous bad revision 23::
743 - Reverse the effect of previous bad revision 23::
750
744
751 hg backout -r 23
745 hg backout -r 23
752
746
753 - Reverse the effect of previous bad revision 23 and
747 - Reverse the effect of previous bad revision 23 and
754 leave changes uncommitted::
748 leave changes uncommitted::
755
749
756 hg backout -r 23 --no-commit
750 hg backout -r 23 --no-commit
757 hg commit -m "Backout revision 23"
751 hg commit -m "Backout revision 23"
758
752
759 By default, the pending changeset will have one parent,
753 By default, the pending changeset will have one parent,
760 maintaining a linear history. With --merge, the pending
754 maintaining a linear history. With --merge, the pending
761 changeset will instead have two parents: the old parent of the
755 changeset will instead have two parents: the old parent of the
762 working directory and a new child of REV that simply undoes REV.
756 working directory and a new child of REV that simply undoes REV.
763
757
764 Before version 1.7, the behavior without --merge was equivalent
758 Before version 1.7, the behavior without --merge was equivalent
765 to specifying --merge followed by :hg:`update --clean .` to
759 to specifying --merge followed by :hg:`update --clean .` to
766 cancel the merge and leave the child of REV as a head to be
760 cancel the merge and leave the child of REV as a head to be
767 merged separately.
761 merged separately.
768
762
769 See :hg:`help dates` for a list of formats valid for -d/--date.
763 See :hg:`help dates` for a list of formats valid for -d/--date.
770
764
771 See :hg:`help revert` for a way to restore files to the state
765 See :hg:`help revert` for a way to restore files to the state
772 of another revision.
766 of another revision.
773
767
774 Returns 0 on success, 1 if nothing to backout or there are unresolved
768 Returns 0 on success, 1 if nothing to backout or there are unresolved
775 files.
769 files.
776 """
770 """
777 with repo.wlock(), repo.lock():
771 with repo.wlock(), repo.lock():
778 return _dobackout(ui, repo, node, rev, **opts)
772 return _dobackout(ui, repo, node, rev, **opts)
779
773
780
774
781 def _dobackout(ui, repo, node=None, rev=None, **opts):
775 def _dobackout(ui, repo, node=None, rev=None, **opts):
782 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
776 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
783 opts = pycompat.byteskwargs(opts)
777 opts = pycompat.byteskwargs(opts)
784
778
785 if rev and node:
779 if rev and node:
786 raise error.InputError(_(b"please specify just one revision"))
780 raise error.InputError(_(b"please specify just one revision"))
787
781
788 if not rev:
782 if not rev:
789 rev = node
783 rev = node
790
784
791 if not rev:
785 if not rev:
792 raise error.InputError(_(b"please specify a revision to backout"))
786 raise error.InputError(_(b"please specify a revision to backout"))
793
787
794 date = opts.get(b'date')
788 date = opts.get(b'date')
795 if date:
789 if date:
796 opts[b'date'] = dateutil.parsedate(date)
790 opts[b'date'] = dateutil.parsedate(date)
797
791
798 cmdutil.checkunfinished(repo)
792 cmdutil.checkunfinished(repo)
799 cmdutil.bailifchanged(repo)
793 cmdutil.bailifchanged(repo)
800 ctx = scmutil.revsingle(repo, rev)
794 ctx = scmutil.revsingle(repo, rev)
801 node = ctx.node()
795 node = ctx.node()
802
796
803 op1, op2 = repo.dirstate.parents()
797 op1, op2 = repo.dirstate.parents()
804 if not repo.changelog.isancestor(node, op1):
798 if not repo.changelog.isancestor(node, op1):
805 raise error.InputError(
799 raise error.InputError(
806 _(b'cannot backout change that is not an ancestor')
800 _(b'cannot backout change that is not an ancestor')
807 )
801 )
808
802
809 p1, p2 = repo.changelog.parents(node)
803 p1, p2 = repo.changelog.parents(node)
810 if p1 == repo.nullid:
804 if p1 == repo.nullid:
811 raise error.InputError(_(b'cannot backout a change with no parents'))
805 raise error.InputError(_(b'cannot backout a change with no parents'))
812 if p2 != repo.nullid:
806 if p2 != repo.nullid:
813 if not opts.get(b'parent'):
807 if not opts.get(b'parent'):
814 raise error.InputError(_(b'cannot backout a merge changeset'))
808 raise error.InputError(_(b'cannot backout a merge changeset'))
815 p = repo.lookup(opts[b'parent'])
809 p = repo.lookup(opts[b'parent'])
816 if p not in (p1, p2):
810 if p not in (p1, p2):
817 raise error.InputError(
811 raise error.InputError(
818 _(b'%s is not a parent of %s') % (short(p), short(node))
812 _(b'%s is not a parent of %s') % (short(p), short(node))
819 )
813 )
820 parent = p
814 parent = p
821 else:
815 else:
822 if opts.get(b'parent'):
816 if opts.get(b'parent'):
823 raise error.InputError(
817 raise error.InputError(
824 _(b'cannot use --parent on non-merge changeset')
818 _(b'cannot use --parent on non-merge changeset')
825 )
819 )
826 parent = p1
820 parent = p1
827
821
828 # the backout should appear on the same branch
822 # the backout should appear on the same branch
829 branch = repo.dirstate.branch()
823 branch = repo.dirstate.branch()
830 bheads = repo.branchheads(branch)
824 bheads = repo.branchheads(branch)
831 rctx = scmutil.revsingle(repo, hex(parent))
825 rctx = scmutil.revsingle(repo, hex(parent))
832 if not opts.get(b'merge') and op1 != node:
826 if not opts.get(b'merge') and op1 != node:
833 with dirstateguard.dirstateguard(repo, b'backout'):
827 with dirstateguard.dirstateguard(repo, b'backout'):
834 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
828 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
835 with ui.configoverride(overrides, b'backout'):
829 with ui.configoverride(overrides, b'backout'):
836 stats = mergemod.back_out(ctx, parent=repo[parent])
830 stats = mergemod.back_out(ctx, parent=repo[parent])
837 repo.setparents(op1, op2)
831 repo.setparents(op1, op2)
838 hg._showstats(repo, stats)
832 hg._showstats(repo, stats)
839 if stats.unresolvedcount:
833 if stats.unresolvedcount:
840 repo.ui.status(
834 repo.ui.status(
841 _(b"use 'hg resolve' to retry unresolved file merges\n")
835 _(b"use 'hg resolve' to retry unresolved file merges\n")
842 )
836 )
843 return 1
837 return 1
844 else:
838 else:
845 hg.clean(repo, node, show_stats=False)
839 hg.clean(repo, node, show_stats=False)
846 repo.dirstate.setbranch(branch)
840 repo.dirstate.setbranch(branch)
847 cmdutil.revert(ui, repo, rctx)
841 cmdutil.revert(ui, repo, rctx)
848
842
849 if opts.get(b'no_commit'):
843 if opts.get(b'no_commit'):
850 msg = _(b"changeset %s backed out, don't forget to commit.\n")
844 msg = _(b"changeset %s backed out, don't forget to commit.\n")
851 ui.status(msg % short(node))
845 ui.status(msg % short(node))
852 return 0
846 return 0
853
847
854 def commitfunc(ui, repo, message, match, opts):
848 def commitfunc(ui, repo, message, match, opts):
855 editform = b'backout'
849 editform = b'backout'
856 e = cmdutil.getcommiteditor(
850 e = cmdutil.getcommiteditor(
857 editform=editform, **pycompat.strkwargs(opts)
851 editform=editform, **pycompat.strkwargs(opts)
858 )
852 )
859 if not message:
853 if not message:
860 # we don't translate commit messages
854 # we don't translate commit messages
861 message = b"Backed out changeset %s" % short(node)
855 message = b"Backed out changeset %s" % short(node)
862 e = cmdutil.getcommiteditor(edit=True, editform=editform)
856 e = cmdutil.getcommiteditor(edit=True, editform=editform)
863 return repo.commit(
857 return repo.commit(
864 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
858 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
865 )
859 )
866
860
867 # save to detect changes
861 # save to detect changes
868 tip = repo.changelog.tip()
862 tip = repo.changelog.tip()
869
863
870 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
864 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
871 if not newnode:
865 if not newnode:
872 ui.status(_(b"nothing changed\n"))
866 ui.status(_(b"nothing changed\n"))
873 return 1
867 return 1
874 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
868 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
875
869
876 def nice(node):
870 def nice(node):
877 return b'%d:%s' % (repo.changelog.rev(node), short(node))
871 return b'%d:%s' % (repo.changelog.rev(node), short(node))
878
872
879 ui.status(
873 ui.status(
880 _(b'changeset %s backs out changeset %s\n')
874 _(b'changeset %s backs out changeset %s\n')
881 % (nice(newnode), nice(node))
875 % (nice(newnode), nice(node))
882 )
876 )
883 if opts.get(b'merge') and op1 != node:
877 if opts.get(b'merge') and op1 != node:
884 hg.clean(repo, op1, show_stats=False)
878 hg.clean(repo, op1, show_stats=False)
885 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
879 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
886 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
880 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
887 with ui.configoverride(overrides, b'backout'):
881 with ui.configoverride(overrides, b'backout'):
888 return hg.merge(repo[b'tip'])
882 return hg.merge(repo[b'tip'])
889 return 0
883 return 0
890
884
891
885
892 @command(
886 @command(
893 b'bisect',
887 b'bisect',
894 [
888 [
895 (b'r', b'reset', False, _(b'reset bisect state')),
889 (b'r', b'reset', False, _(b'reset bisect state')),
896 (b'g', b'good', False, _(b'mark changeset good')),
890 (b'g', b'good', False, _(b'mark changeset good')),
897 (b'b', b'bad', False, _(b'mark changeset bad')),
891 (b'b', b'bad', False, _(b'mark changeset bad')),
898 (b's', b'skip', False, _(b'skip testing changeset')),
892 (b's', b'skip', False, _(b'skip testing changeset')),
899 (b'e', b'extend', False, _(b'extend the bisect range')),
893 (b'e', b'extend', False, _(b'extend the bisect range')),
900 (
894 (
901 b'c',
895 b'c',
902 b'command',
896 b'command',
903 b'',
897 b'',
904 _(b'use command to check changeset state'),
898 _(b'use command to check changeset state'),
905 _(b'CMD'),
899 _(b'CMD'),
906 ),
900 ),
907 (b'U', b'noupdate', False, _(b'do not update to target')),
901 (b'U', b'noupdate', False, _(b'do not update to target')),
908 ],
902 ],
909 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
903 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
910 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
904 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
911 )
905 )
912 def bisect(
906 def bisect(
913 ui,
907 ui,
914 repo,
908 repo,
915 positional_1=None,
909 positional_1=None,
916 positional_2=None,
910 positional_2=None,
917 command=None,
911 command=None,
918 reset=None,
912 reset=None,
919 good=None,
913 good=None,
920 bad=None,
914 bad=None,
921 skip=None,
915 skip=None,
922 extend=None,
916 extend=None,
923 noupdate=None,
917 noupdate=None,
924 ):
918 ):
925 """subdivision search of changesets
919 """subdivision search of changesets
926
920
927 This command helps to find changesets which introduce problems. To
921 This command helps to find changesets which introduce problems. To
928 use, mark the earliest changeset you know exhibits the problem as
922 use, mark the earliest changeset you know exhibits the problem as
929 bad, then mark the latest changeset which is free from the problem
923 bad, then mark the latest changeset which is free from the problem
930 as good. Bisect will update your working directory to a revision
924 as good. Bisect will update your working directory to a revision
931 for testing (unless the -U/--noupdate option is specified). Once
925 for testing (unless the -U/--noupdate option is specified). Once
932 you have performed tests, mark the working directory as good or
926 you have performed tests, mark the working directory as good or
933 bad, and bisect will either update to another candidate changeset
927 bad, and bisect will either update to another candidate changeset
934 or announce that it has found the bad revision.
928 or announce that it has found the bad revision.
935
929
936 As a shortcut, you can also use the revision argument to mark a
930 As a shortcut, you can also use the revision argument to mark a
937 revision as good or bad without checking it out first.
931 revision as good or bad without checking it out first.
938
932
939 If you supply a command, it will be used for automatic bisection.
933 If you supply a command, it will be used for automatic bisection.
940 The environment variable HG_NODE will contain the ID of the
934 The environment variable HG_NODE will contain the ID of the
941 changeset being tested. The exit status of the command will be
935 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
936 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
937 means to skip the revision, 127 (command not found) will abort the
944 bisection, and any other non-zero exit status means the revision
938 bisection, and any other non-zero exit status means the revision
945 is bad.
939 is bad.
946
940
947 .. container:: verbose
941 .. container:: verbose
948
942
949 Some examples:
943 Some examples:
950
944
951 - start a bisection with known bad revision 34, and good revision 12::
945 - start a bisection with known bad revision 34, and good revision 12::
952
946
953 hg bisect --bad 34
947 hg bisect --bad 34
954 hg bisect --good 12
948 hg bisect --good 12
955
949
956 - advance the current bisection by marking current revision as good or
950 - advance the current bisection by marking current revision as good or
957 bad::
951 bad::
958
952
959 hg bisect --good
953 hg bisect --good
960 hg bisect --bad
954 hg bisect --bad
961
955
962 - mark the current revision, or a known revision, to be skipped (e.g. if
956 - mark the current revision, or a known revision, to be skipped (e.g. if
963 that revision is not usable because of another issue)::
957 that revision is not usable because of another issue)::
964
958
965 hg bisect --skip
959 hg bisect --skip
966 hg bisect --skip 23
960 hg bisect --skip 23
967
961
968 - skip all revisions that do not touch directories ``foo`` or ``bar``::
962 - skip all revisions that do not touch directories ``foo`` or ``bar``::
969
963
970 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
964 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
971
965
972 - forget the current bisection::
966 - forget the current bisection::
973
967
974 hg bisect --reset
968 hg bisect --reset
975
969
976 - use 'make && make tests' to automatically find the first broken
970 - use 'make && make tests' to automatically find the first broken
977 revision::
971 revision::
978
972
979 hg bisect --reset
973 hg bisect --reset
980 hg bisect --bad 34
974 hg bisect --bad 34
981 hg bisect --good 12
975 hg bisect --good 12
982 hg bisect --command "make && make tests"
976 hg bisect --command "make && make tests"
983
977
984 - see all changesets whose states are already known in the current
978 - see all changesets whose states are already known in the current
985 bisection::
979 bisection::
986
980
987 hg log -r "bisect(pruned)"
981 hg log -r "bisect(pruned)"
988
982
989 - see the changeset currently being bisected (especially useful
983 - see the changeset currently being bisected (especially useful
990 if running with -U/--noupdate)::
984 if running with -U/--noupdate)::
991
985
992 hg log -r "bisect(current)"
986 hg log -r "bisect(current)"
993
987
994 - see all changesets that took part in the current bisection::
988 - see all changesets that took part in the current bisection::
995
989
996 hg log -r "bisect(range)"
990 hg log -r "bisect(range)"
997
991
998 - you can even get a nice graph::
992 - you can even get a nice graph::
999
993
1000 hg log --graph -r "bisect(range)"
994 hg log --graph -r "bisect(range)"
1001
995
1002 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
996 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1003
997
1004 Returns 0 on success.
998 Returns 0 on success.
1005 """
999 """
1006 rev = []
1000 rev = []
1007 # backward compatibility
1001 # backward compatibility
1008 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1002 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1009 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1003 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1010 cmd = positional_1
1004 cmd = positional_1
1011 rev.append(positional_2)
1005 rev.append(positional_2)
1012 if cmd == b"good":
1006 if cmd == b"good":
1013 good = True
1007 good = True
1014 elif cmd == b"bad":
1008 elif cmd == b"bad":
1015 bad = True
1009 bad = True
1016 else:
1010 else:
1017 reset = True
1011 reset = True
1018 elif positional_2:
1012 elif positional_2:
1019 raise error.InputError(_(b'incompatible arguments'))
1013 raise error.InputError(_(b'incompatible arguments'))
1020 elif positional_1 is not None:
1014 elif positional_1 is not None:
1021 rev.append(positional_1)
1015 rev.append(positional_1)
1022
1016
1023 incompatibles = {
1017 incompatibles = {
1024 b'--bad': bad,
1018 b'--bad': bad,
1025 b'--command': bool(command),
1019 b'--command': bool(command),
1026 b'--extend': extend,
1020 b'--extend': extend,
1027 b'--good': good,
1021 b'--good': good,
1028 b'--reset': reset,
1022 b'--reset': reset,
1029 b'--skip': skip,
1023 b'--skip': skip,
1030 }
1024 }
1031
1025
1032 enabled = [x for x in incompatibles if incompatibles[x]]
1026 enabled = [x for x in incompatibles if incompatibles[x]]
1033
1027
1034 if len(enabled) > 1:
1028 if len(enabled) > 1:
1035 raise error.InputError(
1029 raise error.InputError(
1036 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1030 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1037 )
1031 )
1038
1032
1039 if reset:
1033 if reset:
1040 hbisect.resetstate(repo)
1034 hbisect.resetstate(repo)
1041 return
1035 return
1042
1036
1043 state = hbisect.load_state(repo)
1037 state = hbisect.load_state(repo)
1044
1038
1045 if rev:
1039 if rev:
1046 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1040 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1047 else:
1041 else:
1048 nodes = [repo.lookup(b'.')]
1042 nodes = [repo.lookup(b'.')]
1049
1043
1050 # update state
1044 # update state
1051 if good or bad or skip:
1045 if good or bad or skip:
1052 if good:
1046 if good:
1053 state[b'good'] += nodes
1047 state[b'good'] += nodes
1054 elif bad:
1048 elif bad:
1055 state[b'bad'] += nodes
1049 state[b'bad'] += nodes
1056 elif skip:
1050 elif skip:
1057 state[b'skip'] += nodes
1051 state[b'skip'] += nodes
1058 hbisect.save_state(repo, state)
1052 hbisect.save_state(repo, state)
1059 if not (state[b'good'] and state[b'bad']):
1053 if not (state[b'good'] and state[b'bad']):
1060 return
1054 return
1061
1055
1062 def mayupdate(repo, node, show_stats=True):
1056 def mayupdate(repo, node, show_stats=True):
1063 """common used update sequence"""
1057 """common used update sequence"""
1064 if noupdate:
1058 if noupdate:
1065 return
1059 return
1066 cmdutil.checkunfinished(repo)
1060 cmdutil.checkunfinished(repo)
1067 cmdutil.bailifchanged(repo)
1061 cmdutil.bailifchanged(repo)
1068 return hg.clean(repo, node, show_stats=show_stats)
1062 return hg.clean(repo, node, show_stats=show_stats)
1069
1063
1070 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1064 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1071
1065
1072 if command:
1066 if command:
1073 changesets = 1
1067 changesets = 1
1074 if noupdate:
1068 if noupdate:
1075 try:
1069 try:
1076 node = state[b'current'][0]
1070 node = state[b'current'][0]
1077 except LookupError:
1071 except LookupError:
1078 raise error.StateError(
1072 raise error.StateError(
1079 _(
1073 _(
1080 b'current bisect revision is unknown - '
1074 b'current bisect revision is unknown - '
1081 b'start a new bisect to fix'
1075 b'start a new bisect to fix'
1082 )
1076 )
1083 )
1077 )
1084 else:
1078 else:
1085 node, p2 = repo.dirstate.parents()
1079 node, p2 = repo.dirstate.parents()
1086 if p2 != repo.nullid:
1080 if p2 != repo.nullid:
1087 raise error.StateError(_(b'current bisect revision is a merge'))
1081 raise error.StateError(_(b'current bisect revision is a merge'))
1088 if rev:
1082 if rev:
1089 if not nodes:
1083 if not nodes:
1090 raise error.Abort(_(b'empty revision set'))
1084 raise error.Abort(_(b'empty revision set'))
1091 node = repo[nodes[-1]].node()
1085 node = repo[nodes[-1]].node()
1092 with hbisect.restore_state(repo, state, node):
1086 with hbisect.restore_state(repo, state, node):
1093 while changesets:
1087 while changesets:
1094 # update state
1088 # update state
1095 state[b'current'] = [node]
1089 state[b'current'] = [node]
1096 hbisect.save_state(repo, state)
1090 hbisect.save_state(repo, state)
1097 status = ui.system(
1091 status = ui.system(
1098 command,
1092 command,
1099 environ={b'HG_NODE': hex(node)},
1093 environ={b'HG_NODE': hex(node)},
1100 blockedtag=b'bisect_check',
1094 blockedtag=b'bisect_check',
1101 )
1095 )
1102 if status == 125:
1096 if status == 125:
1103 transition = b"skip"
1097 transition = b"skip"
1104 elif status == 0:
1098 elif status == 0:
1105 transition = b"good"
1099 transition = b"good"
1106 # status < 0 means process was killed
1100 # status < 0 means process was killed
1107 elif status == 127:
1101 elif status == 127:
1108 raise error.Abort(_(b"failed to execute %s") % command)
1102 raise error.Abort(_(b"failed to execute %s") % command)
1109 elif status < 0:
1103 elif status < 0:
1110 raise error.Abort(_(b"%s killed") % command)
1104 raise error.Abort(_(b"%s killed") % command)
1111 else:
1105 else:
1112 transition = b"bad"
1106 transition = b"bad"
1113 state[transition].append(node)
1107 state[transition].append(node)
1114 ctx = repo[node]
1108 ctx = repo[node]
1115 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1109 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1116 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1110 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1117 hbisect.checkstate(state)
1111 hbisect.checkstate(state)
1118 # bisect
1112 # bisect
1119 nodes, changesets, bgood = hbisect.bisect(repo, state)
1113 nodes, changesets, bgood = hbisect.bisect(repo, state)
1120 # update to next check
1114 # update to next check
1121 node = nodes[0]
1115 node = nodes[0]
1122 mayupdate(repo, node, show_stats=False)
1116 mayupdate(repo, node, show_stats=False)
1123 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1117 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1124 return
1118 return
1125
1119
1126 hbisect.checkstate(state)
1120 hbisect.checkstate(state)
1127
1121
1128 # actually bisect
1122 # actually bisect
1129 nodes, changesets, good = hbisect.bisect(repo, state)
1123 nodes, changesets, good = hbisect.bisect(repo, state)
1130 if extend:
1124 if extend:
1131 if not changesets:
1125 if not changesets:
1132 extendctx = hbisect.extendrange(repo, state, nodes, good)
1126 extendctx = hbisect.extendrange(repo, state, nodes, good)
1133 if extendctx is not None:
1127 if extendctx is not None:
1134 ui.write(
1128 ui.write(
1135 _(b"Extending search to changeset %s\n")
1129 _(b"Extending search to changeset %s\n")
1136 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1130 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1137 )
1131 )
1138 state[b'current'] = [extendctx.node()]
1132 state[b'current'] = [extendctx.node()]
1139 hbisect.save_state(repo, state)
1133 hbisect.save_state(repo, state)
1140 return mayupdate(repo, extendctx.node())
1134 return mayupdate(repo, extendctx.node())
1141 raise error.StateError(_(b"nothing to extend"))
1135 raise error.StateError(_(b"nothing to extend"))
1142
1136
1143 if changesets == 0:
1137 if changesets == 0:
1144 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1138 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1145 else:
1139 else:
1146 assert len(nodes) == 1 # only a single node can be tested next
1140 assert len(nodes) == 1 # only a single node can be tested next
1147 node = nodes[0]
1141 node = nodes[0]
1148 # compute the approximate number of remaining tests
1142 # compute the approximate number of remaining tests
1149 tests, size = 0, 2
1143 tests, size = 0, 2
1150 while size <= changesets:
1144 while size <= changesets:
1151 tests, size = tests + 1, size * 2
1145 tests, size = tests + 1, size * 2
1152 rev = repo.changelog.rev(node)
1146 rev = repo.changelog.rev(node)
1153 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1147 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1154 ui.write(
1148 ui.write(
1155 _(
1149 _(
1156 b"Testing changeset %s "
1150 b"Testing changeset %s "
1157 b"(%d changesets remaining, ~%d tests)\n"
1151 b"(%d changesets remaining, ~%d tests)\n"
1158 )
1152 )
1159 % (summary, changesets, tests)
1153 % (summary, changesets, tests)
1160 )
1154 )
1161 state[b'current'] = [node]
1155 state[b'current'] = [node]
1162 hbisect.save_state(repo, state)
1156 hbisect.save_state(repo, state)
1163 return mayupdate(repo, node)
1157 return mayupdate(repo, node)
1164
1158
1165
1159
1166 @command(
1160 @command(
1167 b'bookmarks|bookmark',
1161 b'bookmarks|bookmark',
1168 [
1162 [
1169 (b'f', b'force', False, _(b'force')),
1163 (b'f', b'force', False, _(b'force')),
1170 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1164 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1171 (b'd', b'delete', False, _(b'delete a given bookmark')),
1165 (b'd', b'delete', False, _(b'delete a given bookmark')),
1172 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1166 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1173 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1167 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1174 (b'l', b'list', False, _(b'list existing bookmarks')),
1168 (b'l', b'list', False, _(b'list existing bookmarks')),
1175 ]
1169 ]
1176 + formatteropts,
1170 + formatteropts,
1177 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1171 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1178 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1172 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1179 )
1173 )
1180 def bookmark(ui, repo, *names, **opts):
1174 def bookmark(ui, repo, *names, **opts):
1181 """create a new bookmark or list existing bookmarks
1175 """create a new bookmark or list existing bookmarks
1182
1176
1183 Bookmarks are labels on changesets to help track lines of development.
1177 Bookmarks are labels on changesets to help track lines of development.
1184 Bookmarks are unversioned and can be moved, renamed and deleted.
1178 Bookmarks are unversioned and can be moved, renamed and deleted.
1185 Deleting or moving a bookmark has no effect on the associated changesets.
1179 Deleting or moving a bookmark has no effect on the associated changesets.
1186
1180
1187 Creating or updating to a bookmark causes it to be marked as 'active'.
1181 Creating or updating to a bookmark causes it to be marked as 'active'.
1188 The active bookmark is indicated with a '*'.
1182 The active bookmark is indicated with a '*'.
1189 When a commit is made, the active bookmark will advance to the new commit.
1183 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.
1184 A plain :hg:`update` will also advance an active bookmark, if possible.
1191 Updating away from a bookmark will cause it to be deactivated.
1185 Updating away from a bookmark will cause it to be deactivated.
1192
1186
1193 Bookmarks can be pushed and pulled between repositories (see
1187 Bookmarks can be pushed and pulled between repositories (see
1194 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1188 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1195 diverged, a new 'divergent bookmark' of the form 'name@path' will
1189 diverged, a new 'divergent bookmark' of the form 'name@path' will
1196 be created. Using :hg:`merge` will resolve the divergence.
1190 be created. Using :hg:`merge` will resolve the divergence.
1197
1191
1198 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1192 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1199 the active bookmark's name.
1193 the active bookmark's name.
1200
1194
1201 A bookmark named '@' has the special property that :hg:`clone` will
1195 A bookmark named '@' has the special property that :hg:`clone` will
1202 check it out by default if it exists.
1196 check it out by default if it exists.
1203
1197
1204 .. container:: verbose
1198 .. container:: verbose
1205
1199
1206 Template:
1200 Template:
1207
1201
1208 The following keywords are supported in addition to the common template
1202 The following keywords are supported in addition to the common template
1209 keywords and functions such as ``{bookmark}``. See also
1203 keywords and functions such as ``{bookmark}``. See also
1210 :hg:`help templates`.
1204 :hg:`help templates`.
1211
1205
1212 :active: Boolean. True if the bookmark is active.
1206 :active: Boolean. True if the bookmark is active.
1213
1207
1214 Examples:
1208 Examples:
1215
1209
1216 - create an active bookmark for a new line of development::
1210 - create an active bookmark for a new line of development::
1217
1211
1218 hg book new-feature
1212 hg book new-feature
1219
1213
1220 - create an inactive bookmark as a place marker::
1214 - create an inactive bookmark as a place marker::
1221
1215
1222 hg book -i reviewed
1216 hg book -i reviewed
1223
1217
1224 - create an inactive bookmark on another changeset::
1218 - create an inactive bookmark on another changeset::
1225
1219
1226 hg book -r .^ tested
1220 hg book -r .^ tested
1227
1221
1228 - rename bookmark turkey to dinner::
1222 - rename bookmark turkey to dinner::
1229
1223
1230 hg book -m turkey dinner
1224 hg book -m turkey dinner
1231
1225
1232 - move the '@' bookmark from another branch::
1226 - move the '@' bookmark from another branch::
1233
1227
1234 hg book -f @
1228 hg book -f @
1235
1229
1236 - print only the active bookmark name::
1230 - print only the active bookmark name::
1237
1231
1238 hg book -ql .
1232 hg book -ql .
1239 """
1233 """
1240 opts = pycompat.byteskwargs(opts)
1234 opts = pycompat.byteskwargs(opts)
1241 force = opts.get(b'force')
1235 force = opts.get(b'force')
1242 rev = opts.get(b'rev')
1236 rev = opts.get(b'rev')
1243 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1237 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1244
1238
1245 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1239 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1246 if action:
1240 if action:
1247 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1241 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1248 elif names or rev:
1242 elif names or rev:
1249 action = b'add'
1243 action = b'add'
1250 elif inactive:
1244 elif inactive:
1251 action = b'inactive' # meaning deactivate
1245 action = b'inactive' # meaning deactivate
1252 else:
1246 else:
1253 action = b'list'
1247 action = b'list'
1254
1248
1255 cmdutil.check_incompatible_arguments(
1249 cmdutil.check_incompatible_arguments(
1256 opts, b'inactive', [b'delete', b'list']
1250 opts, b'inactive', [b'delete', b'list']
1257 )
1251 )
1258 if not names and action in {b'add', b'delete'}:
1252 if not names and action in {b'add', b'delete'}:
1259 raise error.InputError(_(b"bookmark name required"))
1253 raise error.InputError(_(b"bookmark name required"))
1260
1254
1261 if action in {b'add', b'delete', b'rename', b'inactive'}:
1255 if action in {b'add', b'delete', b'rename', b'inactive'}:
1262 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1256 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1263 if action == b'delete':
1257 if action == b'delete':
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1258 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 bookmarks.delete(repo, tr, names)
1259 bookmarks.delete(repo, tr, names)
1266 elif action == b'rename':
1260 elif action == b'rename':
1267 if not names:
1261 if not names:
1268 raise error.InputError(_(b"new bookmark name required"))
1262 raise error.InputError(_(b"new bookmark name required"))
1269 elif len(names) > 1:
1263 elif len(names) > 1:
1270 raise error.InputError(
1264 raise error.InputError(
1271 _(b"only one new bookmark name allowed")
1265 _(b"only one new bookmark name allowed")
1272 )
1266 )
1273 oldname = repo._bookmarks.expandname(opts[b'rename'])
1267 oldname = repo._bookmarks.expandname(opts[b'rename'])
1274 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1268 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1275 elif action == b'add':
1269 elif action == b'add':
1276 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1270 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1277 elif action == b'inactive':
1271 elif action == b'inactive':
1278 if len(repo._bookmarks) == 0:
1272 if len(repo._bookmarks) == 0:
1279 ui.status(_(b"no bookmarks set\n"))
1273 ui.status(_(b"no bookmarks set\n"))
1280 elif not repo._activebookmark:
1274 elif not repo._activebookmark:
1281 ui.status(_(b"no active bookmark\n"))
1275 ui.status(_(b"no active bookmark\n"))
1282 else:
1276 else:
1283 bookmarks.deactivate(repo)
1277 bookmarks.deactivate(repo)
1284 elif action == b'list':
1278 elif action == b'list':
1285 names = pycompat.maplist(repo._bookmarks.expandname, names)
1279 names = pycompat.maplist(repo._bookmarks.expandname, names)
1286 with ui.formatter(b'bookmarks', opts) as fm:
1280 with ui.formatter(b'bookmarks', opts) as fm:
1287 bookmarks.printbookmarks(ui, repo, fm, names)
1281 bookmarks.printbookmarks(ui, repo, fm, names)
1288 else:
1282 else:
1289 raise error.ProgrammingError(b'invalid action: %s' % action)
1283 raise error.ProgrammingError(b'invalid action: %s' % action)
1290
1284
1291
1285
1292 @command(
1286 @command(
1293 b'branch',
1287 b'branch',
1294 [
1288 [
1295 (
1289 (
1296 b'f',
1290 b'f',
1297 b'force',
1291 b'force',
1298 None,
1292 None,
1299 _(b'set branch name even if it shadows an existing branch'),
1293 _(b'set branch name even if it shadows an existing branch'),
1300 ),
1294 ),
1301 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1295 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1302 (
1296 (
1303 b'r',
1297 b'r',
1304 b'rev',
1298 b'rev',
1305 [],
1299 [],
1306 _(b'change branches of the given revs (EXPERIMENTAL)'),
1300 _(b'change branches of the given revs (EXPERIMENTAL)'),
1307 ),
1301 ),
1308 ],
1302 ],
1309 _(b'[-fC] [NAME]'),
1303 _(b'[-fC] [NAME]'),
1310 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1304 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1311 )
1305 )
1312 def branch(ui, repo, label=None, **opts):
1306 def branch(ui, repo, label=None, **opts):
1313 """set or show the current branch name
1307 """set or show the current branch name
1314
1308
1315 .. note::
1309 .. note::
1316
1310
1317 Branch names are permanent and global. Use :hg:`bookmark` to create a
1311 Branch names are permanent and global. Use :hg:`bookmark` to create a
1318 light-weight bookmark instead. See :hg:`help glossary` for more
1312 light-weight bookmark instead. See :hg:`help glossary` for more
1319 information about named branches and bookmarks.
1313 information about named branches and bookmarks.
1320
1314
1321 With no argument, show the current branch name. With one argument,
1315 With no argument, show the current branch name. With one argument,
1322 set the working directory branch name (the branch will not exist
1316 set the working directory branch name (the branch will not exist
1323 in the repository until the next commit). Standard practice
1317 in the repository until the next commit). Standard practice
1324 recommends that primary development take place on the 'default'
1318 recommends that primary development take place on the 'default'
1325 branch.
1319 branch.
1326
1320
1327 Unless -f/--force is specified, branch will not let you set a
1321 Unless -f/--force is specified, branch will not let you set a
1328 branch name that already exists.
1322 branch name that already exists.
1329
1323
1330 Use -C/--clean to reset the working directory branch to that of
1324 Use -C/--clean to reset the working directory branch to that of
1331 the parent of the working directory, negating a previous branch
1325 the parent of the working directory, negating a previous branch
1332 change.
1326 change.
1333
1327
1334 Use the command :hg:`update` to switch to an existing branch. Use
1328 Use the command :hg:`update` to switch to an existing branch. Use
1335 :hg:`commit --close-branch` to mark this branch head as closed.
1329 :hg:`commit --close-branch` to mark this branch head as closed.
1336 When all heads of a branch are closed, the branch will be
1330 When all heads of a branch are closed, the branch will be
1337 considered closed.
1331 considered closed.
1338
1332
1339 Returns 0 on success.
1333 Returns 0 on success.
1340 """
1334 """
1341 opts = pycompat.byteskwargs(opts)
1335 opts = pycompat.byteskwargs(opts)
1342 revs = opts.get(b'rev')
1336 revs = opts.get(b'rev')
1343 if label:
1337 if label:
1344 label = label.strip()
1338 label = label.strip()
1345
1339
1346 if not opts.get(b'clean') and not label:
1340 if not opts.get(b'clean') and not label:
1347 if revs:
1341 if revs:
1348 raise error.InputError(
1342 raise error.InputError(
1349 _(b"no branch name specified for the revisions")
1343 _(b"no branch name specified for the revisions")
1350 )
1344 )
1351 ui.write(b"%s\n" % repo.dirstate.branch())
1345 ui.write(b"%s\n" % repo.dirstate.branch())
1352 return
1346 return
1353
1347
1354 with repo.wlock():
1348 with repo.wlock():
1355 if opts.get(b'clean'):
1349 if opts.get(b'clean'):
1356 label = repo[b'.'].branch()
1350 label = repo[b'.'].branch()
1357 repo.dirstate.setbranch(label)
1351 repo.dirstate.setbranch(label)
1358 ui.status(_(b'reset working directory to branch %s\n') % label)
1352 ui.status(_(b'reset working directory to branch %s\n') % label)
1359 elif label:
1353 elif label:
1360
1354
1361 scmutil.checknewlabel(repo, label, b'branch')
1355 scmutil.checknewlabel(repo, label, b'branch')
1362 if revs:
1356 if revs:
1363 return cmdutil.changebranch(ui, repo, revs, label, opts)
1357 return cmdutil.changebranch(ui, repo, revs, label, opts)
1364
1358
1365 if not opts.get(b'force') and label in repo.branchmap():
1359 if not opts.get(b'force') and label in repo.branchmap():
1366 if label not in [p.branch() for p in repo[None].parents()]:
1360 if label not in [p.branch() for p in repo[None].parents()]:
1367 raise error.InputError(
1361 raise error.InputError(
1368 _(b'a branch of the same name already exists'),
1362 _(b'a branch of the same name already exists'),
1369 # i18n: "it" refers to an existing branch
1363 # i18n: "it" refers to an existing branch
1370 hint=_(b"use 'hg update' to switch to it"),
1364 hint=_(b"use 'hg update' to switch to it"),
1371 )
1365 )
1372
1366
1373 repo.dirstate.setbranch(label)
1367 repo.dirstate.setbranch(label)
1374 ui.status(_(b'marked working directory as branch %s\n') % label)
1368 ui.status(_(b'marked working directory as branch %s\n') % label)
1375
1369
1376 # find any open named branches aside from default
1370 # find any open named branches aside from default
1377 for n, h, t, c in repo.branchmap().iterbranches():
1371 for n, h, t, c in repo.branchmap().iterbranches():
1378 if n != b"default" and not c:
1372 if n != b"default" and not c:
1379 return 0
1373 return 0
1380 ui.status(
1374 ui.status(
1381 _(
1375 _(
1382 b'(branches are permanent and global, '
1376 b'(branches are permanent and global, '
1383 b'did you want a bookmark?)\n'
1377 b'did you want a bookmark?)\n'
1384 )
1378 )
1385 )
1379 )
1386
1380
1387
1381
1388 @command(
1382 @command(
1389 b'branches',
1383 b'branches',
1390 [
1384 [
1391 (
1385 (
1392 b'a',
1386 b'a',
1393 b'active',
1387 b'active',
1394 False,
1388 False,
1395 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1389 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1396 ),
1390 ),
1397 (b'c', b'closed', False, _(b'show normal and closed branches')),
1391 (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')),
1392 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1399 ]
1393 ]
1400 + formatteropts,
1394 + formatteropts,
1401 _(b'[-c]'),
1395 _(b'[-c]'),
1402 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1396 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1403 intents={INTENT_READONLY},
1397 intents={INTENT_READONLY},
1404 )
1398 )
1405 def branches(ui, repo, active=False, closed=False, **opts):
1399 def branches(ui, repo, active=False, closed=False, **opts):
1406 """list repository named branches
1400 """list repository named branches
1407
1401
1408 List the repository's named branches, indicating which ones are
1402 List the repository's named branches, indicating which ones are
1409 inactive. If -c/--closed is specified, also list branches which have
1403 inactive. If -c/--closed is specified, also list branches which have
1410 been marked closed (see :hg:`commit --close-branch`).
1404 been marked closed (see :hg:`commit --close-branch`).
1411
1405
1412 Use the command :hg:`update` to switch to an existing branch.
1406 Use the command :hg:`update` to switch to an existing branch.
1413
1407
1414 .. container:: verbose
1408 .. container:: verbose
1415
1409
1416 Template:
1410 Template:
1417
1411
1418 The following keywords are supported in addition to the common template
1412 The following keywords are supported in addition to the common template
1419 keywords and functions such as ``{branch}``. See also
1413 keywords and functions such as ``{branch}``. See also
1420 :hg:`help templates`.
1414 :hg:`help templates`.
1421
1415
1422 :active: Boolean. True if the branch is active.
1416 :active: Boolean. True if the branch is active.
1423 :closed: Boolean. True if the branch is closed.
1417 :closed: Boolean. True if the branch is closed.
1424 :current: Boolean. True if it is the current branch.
1418 :current: Boolean. True if it is the current branch.
1425
1419
1426 Returns 0.
1420 Returns 0.
1427 """
1421 """
1428
1422
1429 opts = pycompat.byteskwargs(opts)
1423 opts = pycompat.byteskwargs(opts)
1430 revs = opts.get(b'rev')
1424 revs = opts.get(b'rev')
1431 selectedbranches = None
1425 selectedbranches = None
1432 if revs:
1426 if revs:
1433 revs = scmutil.revrange(repo, revs)
1427 revs = scmutil.revrange(repo, revs)
1434 getbi = repo.revbranchcache().branchinfo
1428 getbi = repo.revbranchcache().branchinfo
1435 selectedbranches = {getbi(r)[0] for r in revs}
1429 selectedbranches = {getbi(r)[0] for r in revs}
1436
1430
1437 ui.pager(b'branches')
1431 ui.pager(b'branches')
1438 fm = ui.formatter(b'branches', opts)
1432 fm = ui.formatter(b'branches', opts)
1439 hexfunc = fm.hexfunc
1433 hexfunc = fm.hexfunc
1440
1434
1441 allheads = set(repo.heads())
1435 allheads = set(repo.heads())
1442 branches = []
1436 branches = []
1443 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1437 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1444 if selectedbranches is not None and tag not in selectedbranches:
1438 if selectedbranches is not None and tag not in selectedbranches:
1445 continue
1439 continue
1446 isactive = False
1440 isactive = False
1447 if not isclosed:
1441 if not isclosed:
1448 openheads = set(repo.branchmap().iteropen(heads))
1442 openheads = set(repo.branchmap().iteropen(heads))
1449 isactive = bool(openheads & allheads)
1443 isactive = bool(openheads & allheads)
1450 branches.append((tag, repo[tip], isactive, not isclosed))
1444 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)
1445 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1452
1446
1453 for tag, ctx, isactive, isopen in branches:
1447 for tag, ctx, isactive, isopen in branches:
1454 if active and not isactive:
1448 if active and not isactive:
1455 continue
1449 continue
1456 if isactive:
1450 if isactive:
1457 label = b'branches.active'
1451 label = b'branches.active'
1458 notice = b''
1452 notice = b''
1459 elif not isopen:
1453 elif not isopen:
1460 if not closed:
1454 if not closed:
1461 continue
1455 continue
1462 label = b'branches.closed'
1456 label = b'branches.closed'
1463 notice = _(b' (closed)')
1457 notice = _(b' (closed)')
1464 else:
1458 else:
1465 label = b'branches.inactive'
1459 label = b'branches.inactive'
1466 notice = _(b' (inactive)')
1460 notice = _(b' (inactive)')
1467 current = tag == repo.dirstate.branch()
1461 current = tag == repo.dirstate.branch()
1468 if current:
1462 if current:
1469 label = b'branches.current'
1463 label = b'branches.current'
1470
1464
1471 fm.startitem()
1465 fm.startitem()
1472 fm.write(b'branch', b'%s', tag, label=label)
1466 fm.write(b'branch', b'%s', tag, label=label)
1473 rev = ctx.rev()
1467 rev = ctx.rev()
1474 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1468 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1475 fmt = b' ' * padsize + b' %d:%s'
1469 fmt = b' ' * padsize + b' %d:%s'
1476 fm.condwrite(
1470 fm.condwrite(
1477 not ui.quiet,
1471 not ui.quiet,
1478 b'rev node',
1472 b'rev node',
1479 fmt,
1473 fmt,
1480 rev,
1474 rev,
1481 hexfunc(ctx.node()),
1475 hexfunc(ctx.node()),
1482 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1476 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1483 )
1477 )
1484 fm.context(ctx=ctx)
1478 fm.context(ctx=ctx)
1485 fm.data(active=isactive, closed=not isopen, current=current)
1479 fm.data(active=isactive, closed=not isopen, current=current)
1486 if not ui.quiet:
1480 if not ui.quiet:
1487 fm.plain(notice)
1481 fm.plain(notice)
1488 fm.plain(b'\n')
1482 fm.plain(b'\n')
1489 fm.end()
1483 fm.end()
1490
1484
1491
1485
1492 @command(
1486 @command(
1493 b'bundle',
1487 b'bundle',
1494 [
1488 [
1495 (
1489 (
1496 b'f',
1490 b'f',
1497 b'force',
1491 b'force',
1498 None,
1492 None,
1499 _(b'run even when the destination is unrelated'),
1493 _(b'run even when the destination is unrelated'),
1500 ),
1494 ),
1501 (
1495 (
1502 b'r',
1496 b'r',
1503 b'rev',
1497 b'rev',
1504 [],
1498 [],
1505 _(b'a changeset intended to be added to the destination'),
1499 _(b'a changeset intended to be added to the destination'),
1506 _(b'REV'),
1500 _(b'REV'),
1507 ),
1501 ),
1508 (
1502 (
1509 b'b',
1503 b'b',
1510 b'branch',
1504 b'branch',
1511 [],
1505 [],
1512 _(b'a specific branch you would like to bundle'),
1506 _(b'a specific branch you would like to bundle'),
1513 _(b'BRANCH'),
1507 _(b'BRANCH'),
1514 ),
1508 ),
1515 (
1509 (
1516 b'',
1510 b'',
1517 b'base',
1511 b'base',
1518 [],
1512 [],
1519 _(b'a base changeset assumed to be available at the destination'),
1513 _(b'a base changeset assumed to be available at the destination'),
1520 _(b'REV'),
1514 _(b'REV'),
1521 ),
1515 ),
1522 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1516 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1523 (
1517 (
1524 b't',
1518 b't',
1525 b'type',
1519 b'type',
1526 b'bzip2',
1520 b'bzip2',
1527 _(b'bundle compression type to use'),
1521 _(b'bundle compression type to use'),
1528 _(b'TYPE'),
1522 _(b'TYPE'),
1529 ),
1523 ),
1530 ]
1524 ]
1531 + remoteopts,
1525 + remoteopts,
1532 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1526 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1533 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1527 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1534 )
1528 )
1535 def bundle(ui, repo, fname, *dests, **opts):
1529 def bundle(ui, repo, fname, *dests, **opts):
1536 """create a bundle file
1530 """create a bundle file
1537
1531
1538 Generate a bundle file containing data to be transferred to another
1532 Generate a bundle file containing data to be transferred to another
1539 repository.
1533 repository.
1540
1534
1541 To create a bundle containing all changesets, use -a/--all
1535 To create a bundle containing all changesets, use -a/--all
1542 (or --base null). Otherwise, hg assumes the destination will have
1536 (or --base null). Otherwise, hg assumes the destination will have
1543 all the nodes you specify with --base parameters. Otherwise, hg
1537 all the nodes you specify with --base parameters. Otherwise, hg
1544 will assume the repository has all the nodes in destination, or
1538 will assume the repository has all the nodes in destination, or
1545 default-push/default if no destination is specified, where destination
1539 default-push/default if no destination is specified, where destination
1546 is the repositories you provide through DEST option.
1540 is the repositories you provide through DEST option.
1547
1541
1548 You can change bundle format with the -t/--type option. See
1542 You can change bundle format with the -t/--type option. See
1549 :hg:`help bundlespec` for documentation on this format. By default,
1543 :hg:`help bundlespec` for documentation on this format. By default,
1550 the most appropriate format is used and compression defaults to
1544 the most appropriate format is used and compression defaults to
1551 bzip2.
1545 bzip2.
1552
1546
1553 The bundle file can then be transferred using conventional means
1547 The bundle file can then be transferred using conventional means
1554 and applied to another repository with the unbundle or pull
1548 and applied to another repository with the unbundle or pull
1555 command. This is useful when direct push and pull are not
1549 command. This is useful when direct push and pull are not
1556 available or when exporting an entire repository is undesirable.
1550 available or when exporting an entire repository is undesirable.
1557
1551
1558 Applying bundles preserves all changeset contents including
1552 Applying bundles preserves all changeset contents including
1559 permissions, copy/rename information, and revision history.
1553 permissions, copy/rename information, and revision history.
1560
1554
1561 Returns 0 on success, 1 if no changes found.
1555 Returns 0 on success, 1 if no changes found.
1562 """
1556 """
1563 opts = pycompat.byteskwargs(opts)
1557 opts = pycompat.byteskwargs(opts)
1564 revs = None
1558 revs = None
1565 if b'rev' in opts:
1559 if b'rev' in opts:
1566 revstrings = opts[b'rev']
1560 revstrings = opts[b'rev']
1567 revs = scmutil.revrange(repo, revstrings)
1561 revs = scmutil.revrange(repo, revstrings)
1568 if revstrings and not revs:
1562 if revstrings and not revs:
1569 raise error.InputError(_(b'no commits to bundle'))
1563 raise error.InputError(_(b'no commits to bundle'))
1570
1564
1571 bundletype = opts.get(b'type', b'bzip2').lower()
1565 bundletype = opts.get(b'type', b'bzip2').lower()
1572 try:
1566 try:
1573 bundlespec = bundlecaches.parsebundlespec(
1567 bundlespec = bundlecaches.parsebundlespec(
1574 repo, bundletype, strict=False
1568 repo, bundletype, strict=False
1575 )
1569 )
1576 except error.UnsupportedBundleSpecification as e:
1570 except error.UnsupportedBundleSpecification as e:
1577 raise error.InputError(
1571 raise error.InputError(
1578 pycompat.bytestr(e),
1572 pycompat.bytestr(e),
1579 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1573 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1580 )
1574 )
1581 cgversion = bundlespec.contentopts[b"cg.version"]
1575 cgversion = bundlespec.contentopts[b"cg.version"]
1582
1576
1583 # Packed bundles are a pseudo bundle format for now.
1577 # Packed bundles are a pseudo bundle format for now.
1584 if cgversion == b's1':
1578 if cgversion == b's1':
1585 raise error.InputError(
1579 raise error.InputError(
1586 _(b'packed bundles cannot be produced by "hg bundle"'),
1580 _(b'packed bundles cannot be produced by "hg bundle"'),
1587 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1581 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1588 )
1582 )
1589
1583
1590 if opts.get(b'all'):
1584 if opts.get(b'all'):
1591 if dests:
1585 if dests:
1592 raise error.InputError(
1586 raise error.InputError(
1593 _(b"--all is incompatible with specifying destinations")
1587 _(b"--all is incompatible with specifying destinations")
1594 )
1588 )
1595 if opts.get(b'base'):
1589 if opts.get(b'base'):
1596 ui.warn(_(b"ignoring --base because --all was specified\n"))
1590 ui.warn(_(b"ignoring --base because --all was specified\n"))
1597 base = [nullrev]
1591 base = [nullrev]
1598 else:
1592 else:
1599 base = scmutil.revrange(repo, opts.get(b'base'))
1593 base = scmutil.revrange(repo, opts.get(b'base'))
1600 if cgversion not in changegroup.supportedoutgoingversions(repo):
1594 if cgversion not in changegroup.supportedoutgoingversions(repo):
1601 raise error.Abort(
1595 raise error.Abort(
1602 _(b"repository does not support bundle version %s") % cgversion
1596 _(b"repository does not support bundle version %s") % cgversion
1603 )
1597 )
1604
1598
1605 if base:
1599 if base:
1606 if dests:
1600 if dests:
1607 raise error.InputError(
1601 raise error.InputError(
1608 _(b"--base is incompatible with specifying destinations")
1602 _(b"--base is incompatible with specifying destinations")
1609 )
1603 )
1610 common = [repo[rev].node() for rev in base]
1604 common = [repo[rev].node() for rev in base]
1611 heads = [repo[r].node() for r in revs] if revs else None
1605 heads = [repo[r].node() for r in revs] if revs else None
1612 outgoing = discovery.outgoing(repo, common, heads)
1606 outgoing = discovery.outgoing(repo, common, heads)
1613 missing = outgoing.missing
1607 missing = outgoing.missing
1614 excluded = outgoing.excluded
1608 excluded = outgoing.excluded
1615 else:
1609 else:
1616 missing = set()
1610 missing = set()
1617 excluded = set()
1611 excluded = set()
1618 for path in urlutil.get_push_paths(repo, ui, dests):
1612 for path in urlutil.get_push_paths(repo, ui, dests):
1619 other = hg.peer(repo, opts, path.rawloc)
1613 other = hg.peer(repo, opts, path.rawloc)
1620 if revs is not None:
1614 if revs is not None:
1621 hex_revs = [repo[r].hex() for r in revs]
1615 hex_revs = [repo[r].hex() for r in revs]
1622 else:
1616 else:
1623 hex_revs = None
1617 hex_revs = None
1624 branches = (path.branch, [])
1618 branches = (path.branch, [])
1625 head_revs, checkout = hg.addbranchrevs(
1619 head_revs, checkout = hg.addbranchrevs(
1626 repo, repo, branches, hex_revs
1620 repo, repo, branches, hex_revs
1627 )
1621 )
1628 heads = (
1622 heads = (
1629 head_revs
1623 head_revs
1630 and pycompat.maplist(repo.lookup, head_revs)
1624 and pycompat.maplist(repo.lookup, head_revs)
1631 or head_revs
1625 or head_revs
1632 )
1626 )
1633 outgoing = discovery.findcommonoutgoing(
1627 outgoing = discovery.findcommonoutgoing(
1634 repo,
1628 repo,
1635 other,
1629 other,
1636 onlyheads=heads,
1630 onlyheads=heads,
1637 force=opts.get(b'force'),
1631 force=opts.get(b'force'),
1638 portable=True,
1632 portable=True,
1639 )
1633 )
1640 missing.update(outgoing.missing)
1634 missing.update(outgoing.missing)
1641 excluded.update(outgoing.excluded)
1635 excluded.update(outgoing.excluded)
1642
1636
1643 if not missing:
1637 if not missing:
1644 scmutil.nochangesfound(ui, repo, not base and excluded)
1638 scmutil.nochangesfound(ui, repo, not base and excluded)
1645 return 1
1639 return 1
1646
1640
1647 if heads:
1641 if heads:
1648 outgoing = discovery.outgoing(
1642 outgoing = discovery.outgoing(
1649 repo, missingroots=missing, ancestorsof=heads
1643 repo, missingroots=missing, ancestorsof=heads
1650 )
1644 )
1651 else:
1645 else:
1652 outgoing = discovery.outgoing(repo, missingroots=missing)
1646 outgoing = discovery.outgoing(repo, missingroots=missing)
1653 outgoing.excluded = sorted(excluded)
1647 outgoing.excluded = sorted(excluded)
1654
1648
1655 if cgversion == b'01': # bundle1
1649 if cgversion == b'01': # bundle1
1656 bversion = b'HG10' + bundlespec.wirecompression
1650 bversion = b'HG10' + bundlespec.wirecompression
1657 bcompression = None
1651 bcompression = None
1658 elif cgversion in (b'02', b'03'):
1652 elif cgversion in (b'02', b'03'):
1659 bversion = b'HG20'
1653 bversion = b'HG20'
1660 bcompression = bundlespec.wirecompression
1654 bcompression = bundlespec.wirecompression
1661 else:
1655 else:
1662 raise error.ProgrammingError(
1656 raise error.ProgrammingError(
1663 b'bundle: unexpected changegroup version %s' % cgversion
1657 b'bundle: unexpected changegroup version %s' % cgversion
1664 )
1658 )
1665
1659
1666 # TODO compression options should be derived from bundlespec parsing.
1660 # TODO compression options should be derived from bundlespec parsing.
1667 # This is a temporary hack to allow adjusting bundle compression
1661 # This is a temporary hack to allow adjusting bundle compression
1668 # level without a) formalizing the bundlespec changes to declare it
1662 # level without a) formalizing the bundlespec changes to declare it
1669 # b) introducing a command flag.
1663 # b) introducing a command flag.
1670 compopts = {}
1664 compopts = {}
1671 complevel = ui.configint(
1665 complevel = ui.configint(
1672 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1666 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1673 )
1667 )
1674 if complevel is None:
1668 if complevel is None:
1675 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1669 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1676 if complevel is not None:
1670 if complevel is not None:
1677 compopts[b'level'] = complevel
1671 compopts[b'level'] = complevel
1678
1672
1679 compthreads = ui.configint(
1673 compthreads = ui.configint(
1680 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1674 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1681 )
1675 )
1682 if compthreads is None:
1676 if compthreads is None:
1683 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1677 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1684 if compthreads is not None:
1678 if compthreads is not None:
1685 compopts[b'threads'] = compthreads
1679 compopts[b'threads'] = compthreads
1686
1680
1687 # Bundling of obsmarker and phases is optional as not all clients
1681 # Bundling of obsmarker and phases is optional as not all clients
1688 # support the necessary features.
1682 # support the necessary features.
1689 cfg = ui.configbool
1683 cfg = ui.configbool
1690 contentopts = {
1684 contentopts = {
1691 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1685 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1692 b'obsolescence-mandatory': cfg(
1686 b'obsolescence-mandatory': cfg(
1693 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1687 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1694 ),
1688 ),
1695 b'phases': cfg(b'experimental', b'bundle-phases'),
1689 b'phases': cfg(b'experimental', b'bundle-phases'),
1696 }
1690 }
1697 bundlespec.contentopts.update(contentopts)
1691 bundlespec.contentopts.update(contentopts)
1698
1692
1699 bundle2.writenewbundle(
1693 bundle2.writenewbundle(
1700 ui,
1694 ui,
1701 repo,
1695 repo,
1702 b'bundle',
1696 b'bundle',
1703 fname,
1697 fname,
1704 bversion,
1698 bversion,
1705 outgoing,
1699 outgoing,
1706 bundlespec.contentopts,
1700 bundlespec.contentopts,
1707 compression=bcompression,
1701 compression=bcompression,
1708 compopts=compopts,
1702 compopts=compopts,
1709 )
1703 )
1710
1704
1711
1705
1712 @command(
1706 @command(
1713 b'cat',
1707 b'cat',
1714 [
1708 [
1715 (
1709 (
1716 b'o',
1710 b'o',
1717 b'output',
1711 b'output',
1718 b'',
1712 b'',
1719 _(b'print output to file with formatted name'),
1713 _(b'print output to file with formatted name'),
1720 _(b'FORMAT'),
1714 _(b'FORMAT'),
1721 ),
1715 ),
1722 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1716 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1723 (b'', b'decode', None, _(b'apply any matching decode filter')),
1717 (b'', b'decode', None, _(b'apply any matching decode filter')),
1724 ]
1718 ]
1725 + walkopts
1719 + walkopts
1726 + formatteropts,
1720 + formatteropts,
1727 _(b'[OPTION]... FILE...'),
1721 _(b'[OPTION]... FILE...'),
1728 helpcategory=command.CATEGORY_FILE_CONTENTS,
1722 helpcategory=command.CATEGORY_FILE_CONTENTS,
1729 inferrepo=True,
1723 inferrepo=True,
1730 intents={INTENT_READONLY},
1724 intents={INTENT_READONLY},
1731 )
1725 )
1732 def cat(ui, repo, file1, *pats, **opts):
1726 def cat(ui, repo, file1, *pats, **opts):
1733 """output the current or given revision of files
1727 """output the current or given revision of files
1734
1728
1735 Print the specified files as they were at the given revision. If
1729 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.
1730 no revision is given, the parent of the working directory is used.
1737
1731
1738 Output may be to a file, in which case the name of the file is
1732 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
1733 given using a template string. See :hg:`help templates`. In addition
1740 to the common template keywords, the following formatting rules are
1734 to the common template keywords, the following formatting rules are
1741 supported:
1735 supported:
1742
1736
1743 :``%%``: literal "%" character
1737 :``%%``: literal "%" character
1744 :``%s``: basename of file being printed
1738 :``%s``: basename of file being printed
1745 :``%d``: dirname of file being printed, or '.' if in repository root
1739 :``%d``: dirname of file being printed, or '.' if in repository root
1746 :``%p``: root-relative path name of file being printed
1740 :``%p``: root-relative path name of file being printed
1747 :``%H``: changeset hash (40 hexadecimal digits)
1741 :``%H``: changeset hash (40 hexadecimal digits)
1748 :``%R``: changeset revision number
1742 :``%R``: changeset revision number
1749 :``%h``: short-form changeset hash (12 hexadecimal digits)
1743 :``%h``: short-form changeset hash (12 hexadecimal digits)
1750 :``%r``: zero-padded changeset revision number
1744 :``%r``: zero-padded changeset revision number
1751 :``%b``: basename of the exporting repository
1745 :``%b``: basename of the exporting repository
1752 :``\\``: literal "\\" character
1746 :``\\``: literal "\\" character
1753
1747
1754 .. container:: verbose
1748 .. container:: verbose
1755
1749
1756 Template:
1750 Template:
1757
1751
1758 The following keywords are supported in addition to the common template
1752 The following keywords are supported in addition to the common template
1759 keywords and functions. See also :hg:`help templates`.
1753 keywords and functions. See also :hg:`help templates`.
1760
1754
1761 :data: String. File content.
1755 :data: String. File content.
1762 :path: String. Repository-absolute path of the file.
1756 :path: String. Repository-absolute path of the file.
1763
1757
1764 Returns 0 on success.
1758 Returns 0 on success.
1765 """
1759 """
1766 opts = pycompat.byteskwargs(opts)
1760 opts = pycompat.byteskwargs(opts)
1767 rev = opts.get(b'rev')
1761 rev = opts.get(b'rev')
1768 if rev:
1762 if rev:
1769 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1770 ctx = scmutil.revsingle(repo, rev)
1764 ctx = scmutil.revsingle(repo, rev)
1771 m = scmutil.match(ctx, (file1,) + pats, opts)
1765 m = scmutil.match(ctx, (file1,) + pats, opts)
1772 fntemplate = opts.pop(b'output', b'')
1766 fntemplate = opts.pop(b'output', b'')
1773 if cmdutil.isstdiofilename(fntemplate):
1767 if cmdutil.isstdiofilename(fntemplate):
1774 fntemplate = b''
1768 fntemplate = b''
1775
1769
1776 if fntemplate:
1770 if fntemplate:
1777 fm = formatter.nullformatter(ui, b'cat', opts)
1771 fm = formatter.nullformatter(ui, b'cat', opts)
1778 else:
1772 else:
1779 ui.pager(b'cat')
1773 ui.pager(b'cat')
1780 fm = ui.formatter(b'cat', opts)
1774 fm = ui.formatter(b'cat', opts)
1781 with fm:
1775 with fm:
1782 return cmdutil.cat(
1776 return cmdutil.cat(
1783 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1777 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1784 )
1778 )
1785
1779
1786
1780
1787 @command(
1781 @command(
1788 b'clone',
1782 b'clone',
1789 [
1783 [
1790 (
1784 (
1791 b'U',
1785 b'U',
1792 b'noupdate',
1786 b'noupdate',
1793 None,
1787 None,
1794 _(
1788 _(
1795 b'the clone will include an empty working '
1789 b'the clone will include an empty working '
1796 b'directory (only a repository)'
1790 b'directory (only a repository)'
1797 ),
1791 ),
1798 ),
1792 ),
1799 (
1793 (
1800 b'u',
1794 b'u',
1801 b'updaterev',
1795 b'updaterev',
1802 b'',
1796 b'',
1803 _(b'revision, tag, or branch to check out'),
1797 _(b'revision, tag, or branch to check out'),
1804 _(b'REV'),
1798 _(b'REV'),
1805 ),
1799 ),
1806 (
1800 (
1807 b'r',
1801 b'r',
1808 b'rev',
1802 b'rev',
1809 [],
1803 [],
1810 _(
1804 _(
1811 b'do not clone everything, but include this changeset'
1805 b'do not clone everything, but include this changeset'
1812 b' and its ancestors'
1806 b' and its ancestors'
1813 ),
1807 ),
1814 _(b'REV'),
1808 _(b'REV'),
1815 ),
1809 ),
1816 (
1810 (
1817 b'b',
1811 b'b',
1818 b'branch',
1812 b'branch',
1819 [],
1813 [],
1820 _(
1814 _(
1821 b'do not clone everything, but include this branch\'s'
1815 b'do not clone everything, but include this branch\'s'
1822 b' changesets and their ancestors'
1816 b' changesets and their ancestors'
1823 ),
1817 ),
1824 _(b'BRANCH'),
1818 _(b'BRANCH'),
1825 ),
1819 ),
1826 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1820 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1827 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1821 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1828 (b'', b'stream', None, _(b'clone with minimal data processing')),
1822 (b'', b'stream', None, _(b'clone with minimal data processing')),
1829 ]
1823 ]
1830 + remoteopts,
1824 + remoteopts,
1831 _(b'[OPTION]... SOURCE [DEST]'),
1825 _(b'[OPTION]... SOURCE [DEST]'),
1832 helpcategory=command.CATEGORY_REPO_CREATION,
1826 helpcategory=command.CATEGORY_REPO_CREATION,
1833 helpbasic=True,
1827 helpbasic=True,
1834 norepo=True,
1828 norepo=True,
1835 )
1829 )
1836 def clone(ui, source, dest=None, **opts):
1830 def clone(ui, source, dest=None, **opts):
1837 """make a copy of an existing repository
1831 """make a copy of an existing repository
1838
1832
1839 Create a copy of an existing repository in a new directory.
1833 Create a copy of an existing repository in a new directory.
1840
1834
1841 If no destination directory name is specified, it defaults to the
1835 If no destination directory name is specified, it defaults to the
1842 basename of the source.
1836 basename of the source.
1843
1837
1844 The location of the source is added to the new repository's
1838 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.
1839 ``.hg/hgrc`` file, as the default to be used for future pulls.
1846
1840
1847 Only local paths and ``ssh://`` URLs are supported as
1841 Only local paths and ``ssh://`` URLs are supported as
1848 destinations. For ``ssh://`` destinations, no working directory or
1842 destinations. For ``ssh://`` destinations, no working directory or
1849 ``.hg/hgrc`` will be created on the remote side.
1843 ``.hg/hgrc`` will be created on the remote side.
1850
1844
1851 If the source repository has a bookmark called '@' set, that
1845 If the source repository has a bookmark called '@' set, that
1852 revision will be checked out in the new repository by default.
1846 revision will be checked out in the new repository by default.
1853
1847
1854 To check out a particular version, use -u/--update, or
1848 To check out a particular version, use -u/--update, or
1855 -U/--noupdate to create a clone with no working directory.
1849 -U/--noupdate to create a clone with no working directory.
1856
1850
1857 To pull only a subset of changesets, specify one or more revisions
1851 To pull only a subset of changesets, specify one or more revisions
1858 identifiers with -r/--rev or branches with -b/--branch. The
1852 identifiers with -r/--rev or branches with -b/--branch. The
1859 resulting clone will contain only the specified changesets and
1853 resulting clone will contain only the specified changesets and
1860 their ancestors. These options (or 'clone src#rev dest') imply
1854 their ancestors. These options (or 'clone src#rev dest') imply
1861 --pull, even for local source repositories.
1855 --pull, even for local source repositories.
1862
1856
1863 In normal clone mode, the remote normalizes repository data into a common
1857 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
1858 exchange format and the receiving end translates this data into its local
1865 storage format. --stream activates a different clone mode that essentially
1859 storage format. --stream activates a different clone mode that essentially
1866 copies repository files from the remote with minimal data processing. This
1860 copies repository files from the remote with minimal data processing. This
1867 significantly reduces the CPU cost of a clone both remotely and locally.
1861 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
1862 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,
1863 result in substantially faster clones where I/O throughput is plentiful,
1870 especially for larger repositories. A side-effect of --stream clones is
1864 especially for larger repositories. A side-effect of --stream clones is
1871 that storage settings and requirements on the remote are applied locally:
1865 that storage settings and requirements on the remote are applied locally:
1872 a modern client may inherit legacy or inefficient storage used by the
1866 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
1867 remote or a legacy Mercurial client may not be able to clone from a
1874 modern Mercurial remote.
1868 modern Mercurial remote.
1875
1869
1876 .. note::
1870 .. note::
1877
1871
1878 Specifying a tag will include the tagged changeset but not the
1872 Specifying a tag will include the tagged changeset but not the
1879 changeset containing the tag.
1873 changeset containing the tag.
1880
1874
1881 .. container:: verbose
1875 .. container:: verbose
1882
1876
1883 For efficiency, hardlinks are used for cloning whenever the
1877 For efficiency, hardlinks are used for cloning whenever the
1884 source and destination are on the same filesystem (note this
1878 source and destination are on the same filesystem (note this
1885 applies only to the repository data, not to the working
1879 applies only to the repository data, not to the working
1886 directory). Some filesystems, such as AFS, implement hardlinking
1880 directory). Some filesystems, such as AFS, implement hardlinking
1887 incorrectly, but do not report errors. In these cases, use the
1881 incorrectly, but do not report errors. In these cases, use the
1888 --pull option to avoid hardlinking.
1882 --pull option to avoid hardlinking.
1889
1883
1890 Mercurial will update the working directory to the first applicable
1884 Mercurial will update the working directory to the first applicable
1891 revision from this list:
1885 revision from this list:
1892
1886
1893 a) null if -U or the source repository has no changesets
1887 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
1888 b) if -u . and the source repository is local, the first parent of
1895 the source repository's working directory
1889 the source repository's working directory
1896 c) the changeset specified with -u (if a branch name, this means the
1890 c) the changeset specified with -u (if a branch name, this means the
1897 latest head of that branch)
1891 latest head of that branch)
1898 d) the changeset specified with -r
1892 d) the changeset specified with -r
1899 e) the tipmost head specified with -b
1893 e) the tipmost head specified with -b
1900 f) the tipmost head specified with the url#branch source syntax
1894 f) the tipmost head specified with the url#branch source syntax
1901 g) the revision marked with the '@' bookmark, if present
1895 g) the revision marked with the '@' bookmark, if present
1902 h) the tipmost head of the default branch
1896 h) the tipmost head of the default branch
1903 i) tip
1897 i) tip
1904
1898
1905 When cloning from servers that support it, Mercurial may fetch
1899 When cloning from servers that support it, Mercurial may fetch
1906 pre-generated data from a server-advertised URL or inline from the
1900 pre-generated data from a server-advertised URL or inline from the
1907 same stream. When this is done, hooks operating on incoming changesets
1901 same stream. When this is done, hooks operating on incoming changesets
1908 and changegroups may fire more than once, once for each pre-generated
1902 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,
1903 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
1904 if an error occurs, the repository may be rolled back to a partial
1911 clone. This behavior may change in future releases.
1905 clone. This behavior may change in future releases.
1912 See :hg:`help -e clonebundles` for more.
1906 See :hg:`help -e clonebundles` for more.
1913
1907
1914 Examples:
1908 Examples:
1915
1909
1916 - clone a remote repository to a new directory named hg/::
1910 - clone a remote repository to a new directory named hg/::
1917
1911
1918 hg clone https://www.mercurial-scm.org/repo/hg/
1912 hg clone https://www.mercurial-scm.org/repo/hg/
1919
1913
1920 - create a lightweight local clone::
1914 - create a lightweight local clone::
1921
1915
1922 hg clone project/ project-feature/
1916 hg clone project/ project-feature/
1923
1917
1924 - clone from an absolute path on an ssh server (note double-slash)::
1918 - clone from an absolute path on an ssh server (note double-slash)::
1925
1919
1926 hg clone ssh://user@server//home/projects/alpha/
1920 hg clone ssh://user@server//home/projects/alpha/
1927
1921
1928 - do a streaming clone while checking out a specified version::
1922 - do a streaming clone while checking out a specified version::
1929
1923
1930 hg clone --stream http://server/repo -u 1.5
1924 hg clone --stream http://server/repo -u 1.5
1931
1925
1932 - create a repository without changesets after a particular revision::
1926 - create a repository without changesets after a particular revision::
1933
1927
1934 hg clone -r 04e544 experimental/ good/
1928 hg clone -r 04e544 experimental/ good/
1935
1929
1936 - clone (and track) a particular named branch::
1930 - clone (and track) a particular named branch::
1937
1931
1938 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1932 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1939
1933
1940 See :hg:`help urls` for details on specifying URLs.
1934 See :hg:`help urls` for details on specifying URLs.
1941
1935
1942 Returns 0 on success.
1936 Returns 0 on success.
1943 """
1937 """
1944 opts = pycompat.byteskwargs(opts)
1938 opts = pycompat.byteskwargs(opts)
1945 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1939 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1946
1940
1947 # --include/--exclude can come from narrow or sparse.
1941 # --include/--exclude can come from narrow or sparse.
1948 includepats, excludepats = None, None
1942 includepats, excludepats = None, None
1949
1943
1950 # hg.clone() differentiates between None and an empty set. So make sure
1944 # hg.clone() differentiates between None and an empty set. So make sure
1951 # patterns are sets if narrow is requested without patterns.
1945 # patterns are sets if narrow is requested without patterns.
1952 if opts.get(b'narrow'):
1946 if opts.get(b'narrow'):
1953 includepats = set()
1947 includepats = set()
1954 excludepats = set()
1948 excludepats = set()
1955
1949
1956 if opts.get(b'include'):
1950 if opts.get(b'include'):
1957 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1951 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1958 if opts.get(b'exclude'):
1952 if opts.get(b'exclude'):
1959 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1953 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1960
1954
1961 r = hg.clone(
1955 r = hg.clone(
1962 ui,
1956 ui,
1963 opts,
1957 opts,
1964 source,
1958 source,
1965 dest,
1959 dest,
1966 pull=opts.get(b'pull'),
1960 pull=opts.get(b'pull'),
1967 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1961 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1968 revs=opts.get(b'rev'),
1962 revs=opts.get(b'rev'),
1969 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1963 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1970 branch=opts.get(b'branch'),
1964 branch=opts.get(b'branch'),
1971 shareopts=opts.get(b'shareopts'),
1965 shareopts=opts.get(b'shareopts'),
1972 storeincludepats=includepats,
1966 storeincludepats=includepats,
1973 storeexcludepats=excludepats,
1967 storeexcludepats=excludepats,
1974 depth=opts.get(b'depth') or None,
1968 depth=opts.get(b'depth') or None,
1975 )
1969 )
1976
1970
1977 return r is None
1971 return r is None
1978
1972
1979
1973
1980 @command(
1974 @command(
1981 b'commit|ci',
1975 b'commit|ci',
1982 [
1976 [
1983 (
1977 (
1984 b'A',
1978 b'A',
1985 b'addremove',
1979 b'addremove',
1986 None,
1980 None,
1987 _(b'mark new/missing files as added/removed before committing'),
1981 _(b'mark new/missing files as added/removed before committing'),
1988 ),
1982 ),
1989 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1983 (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')),
1984 (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')),
1985 (b's', b'secret', None, _(b'use the secret phase for committing')),
1992 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1986 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1993 (
1987 (
1994 b'',
1988 b'',
1995 b'force-close-branch',
1989 b'force-close-branch',
1996 None,
1990 None,
1997 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1991 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1998 ),
1992 ),
1999 (b'i', b'interactive', None, _(b'use interactive mode')),
1993 (b'i', b'interactive', None, _(b'use interactive mode')),
2000 ]
1994 ]
2001 + walkopts
1995 + walkopts
2002 + commitopts
1996 + commitopts
2003 + commitopts2
1997 + commitopts2
2004 + subrepoopts,
1998 + subrepoopts,
2005 _(b'[OPTION]... [FILE]...'),
1999 _(b'[OPTION]... [FILE]...'),
2006 helpcategory=command.CATEGORY_COMMITTING,
2000 helpcategory=command.CATEGORY_COMMITTING,
2007 helpbasic=True,
2001 helpbasic=True,
2008 inferrepo=True,
2002 inferrepo=True,
2009 )
2003 )
2010 def commit(ui, repo, *pats, **opts):
2004 def commit(ui, repo, *pats, **opts):
2011 """commit the specified files or all outstanding changes
2005 """commit the specified files or all outstanding changes
2012
2006
2013 Commit changes to the given files into the repository. Unlike a
2007 Commit changes to the given files into the repository. Unlike a
2014 centralized SCM, this operation is a local operation. See
2008 centralized SCM, this operation is a local operation. See
2015 :hg:`push` for a way to actively distribute your changes.
2009 :hg:`push` for a way to actively distribute your changes.
2016
2010
2017 If a list of files is omitted, all changes reported by :hg:`status`
2011 If a list of files is omitted, all changes reported by :hg:`status`
2018 will be committed.
2012 will be committed.
2019
2013
2020 If you are committing the result of a merge, do not provide any
2014 If you are committing the result of a merge, do not provide any
2021 filenames or -I/-X filters.
2015 filenames or -I/-X filters.
2022
2016
2023 If no commit message is specified, Mercurial starts your
2017 If no commit message is specified, Mercurial starts your
2024 configured editor where you can enter a message. In case your
2018 configured editor where you can enter a message. In case your
2025 commit fails, you will find a backup of your message in
2019 commit fails, you will find a backup of your message in
2026 ``.hg/last-message.txt``.
2020 ``.hg/last-message.txt``.
2027
2021
2028 The --close-branch flag can be used to mark the current branch
2022 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
2023 head closed. When all heads of a branch are closed, the branch
2030 will be considered closed and no longer listed.
2024 will be considered closed and no longer listed.
2031
2025
2032 The --amend flag can be used to amend the parent of the
2026 The --amend flag can be used to amend the parent of the
2033 working directory with a new commit that contains the changes
2027 working directory with a new commit that contains the changes
2034 in the parent in addition to those currently reported by :hg:`status`,
2028 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
2029 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`
2030 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2037 on how to restore it).
2031 on how to restore it).
2038
2032
2039 Message, user and date are taken from the amended commit unless
2033 Message, user and date are taken from the amended commit unless
2040 specified. When a message isn't specified on the command line,
2034 specified. When a message isn't specified on the command line,
2041 the editor will open with the message of the amended commit.
2035 the editor will open with the message of the amended commit.
2042
2036
2043 It is not possible to amend public changesets (see :hg:`help phases`)
2037 It is not possible to amend public changesets (see :hg:`help phases`)
2044 or changesets that have children.
2038 or changesets that have children.
2045
2039
2046 See :hg:`help dates` for a list of formats valid for -d/--date.
2040 See :hg:`help dates` for a list of formats valid for -d/--date.
2047
2041
2048 Returns 0 on success, 1 if nothing changed.
2042 Returns 0 on success, 1 if nothing changed.
2049
2043
2050 .. container:: verbose
2044 .. container:: verbose
2051
2045
2052 Examples:
2046 Examples:
2053
2047
2054 - commit all files ending in .py::
2048 - commit all files ending in .py::
2055
2049
2056 hg commit --include "set:**.py"
2050 hg commit --include "set:**.py"
2057
2051
2058 - commit all non-binary files::
2052 - commit all non-binary files::
2059
2053
2060 hg commit --exclude "set:binary()"
2054 hg commit --exclude "set:binary()"
2061
2055
2062 - amend the current commit and set the date to now::
2056 - amend the current commit and set the date to now::
2063
2057
2064 hg commit --amend --date now
2058 hg commit --amend --date now
2065 """
2059 """
2066 with repo.wlock(), repo.lock():
2060 with repo.wlock(), repo.lock():
2067 return _docommit(ui, repo, *pats, **opts)
2061 return _docommit(ui, repo, *pats, **opts)
2068
2062
2069
2063
2070 def _docommit(ui, repo, *pats, **opts):
2064 def _docommit(ui, repo, *pats, **opts):
2071 if opts.get('interactive'):
2065 if opts.get('interactive'):
2072 opts.pop('interactive')
2066 opts.pop('interactive')
2073 ret = cmdutil.dorecord(
2067 ret = cmdutil.dorecord(
2074 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2068 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2075 )
2069 )
2076 # ret can be 0 (no changes to record) or the value returned by
2070 # ret can be 0 (no changes to record) or the value returned by
2077 # commit(), 1 if nothing changed or None on success.
2071 # commit(), 1 if nothing changed or None on success.
2078 return 1 if ret == 0 else ret
2072 return 1 if ret == 0 else ret
2079
2073
2080 if opts.get('subrepos'):
2074 if opts.get('subrepos'):
2081 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2075 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2082 # Let --subrepos on the command line override config setting.
2076 # Let --subrepos on the command line override config setting.
2083 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2077 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2084
2078
2085 cmdutil.checkunfinished(repo, commit=True)
2079 cmdutil.checkunfinished(repo, commit=True)
2086
2080
2087 branch = repo[None].branch()
2081 branch = repo[None].branch()
2088 bheads = repo.branchheads(branch)
2082 bheads = repo.branchheads(branch)
2089 tip = repo.changelog.tip()
2083 tip = repo.changelog.tip()
2090
2084
2091 extra = {}
2085 extra = {}
2092 if opts.get('close_branch') or opts.get('force_close_branch'):
2086 if opts.get('close_branch') or opts.get('force_close_branch'):
2093 extra[b'close'] = b'1'
2087 extra[b'close'] = b'1'
2094
2088
2095 if repo[b'.'].closesbranch():
2089 if repo[b'.'].closesbranch():
2096 raise error.InputError(
2090 raise error.InputError(
2097 _(b'current revision is already a branch closing head')
2091 _(b'current revision is already a branch closing head')
2098 )
2092 )
2099 elif not bheads:
2093 elif not bheads:
2100 raise error.InputError(
2094 raise error.InputError(
2101 _(b'branch "%s" has no heads to close') % branch
2095 _(b'branch "%s" has no heads to close') % branch
2102 )
2096 )
2103 elif (
2097 elif (
2104 branch == repo[b'.'].branch()
2098 branch == repo[b'.'].branch()
2105 and repo[b'.'].node() not in bheads
2099 and repo[b'.'].node() not in bheads
2106 and not opts.get('force_close_branch')
2100 and not opts.get('force_close_branch')
2107 ):
2101 ):
2108 hint = _(
2102 hint = _(
2109 b'use --force-close-branch to close branch from a non-head'
2103 b'use --force-close-branch to close branch from a non-head'
2110 b' changeset'
2104 b' changeset'
2111 )
2105 )
2112 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2106 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2113 elif opts.get('amend'):
2107 elif opts.get('amend'):
2114 if (
2108 if (
2115 repo[b'.'].p1().branch() != branch
2109 repo[b'.'].p1().branch() != branch
2116 and repo[b'.'].p2().branch() != branch
2110 and repo[b'.'].p2().branch() != branch
2117 ):
2111 ):
2118 raise error.InputError(_(b'can only close branch heads'))
2112 raise error.InputError(_(b'can only close branch heads'))
2119
2113
2120 if opts.get('amend'):
2114 if opts.get('amend'):
2121 if ui.configbool(b'ui', b'commitsubrepos'):
2115 if ui.configbool(b'ui', b'commitsubrepos'):
2122 raise error.InputError(
2116 raise error.InputError(
2123 _(b'cannot amend with ui.commitsubrepos enabled')
2117 _(b'cannot amend with ui.commitsubrepos enabled')
2124 )
2118 )
2125
2119
2126 old = repo[b'.']
2120 old = repo[b'.']
2127 rewriteutil.precheck(repo, [old.rev()], b'amend')
2121 rewriteutil.precheck(repo, [old.rev()], b'amend')
2128
2122
2129 # Currently histedit gets confused if an amend happens while histedit
2123 # Currently histedit gets confused if an amend happens while histedit
2130 # is in progress. Since we have a checkunfinished command, we are
2124 # is in progress. Since we have a checkunfinished command, we are
2131 # temporarily honoring it.
2125 # temporarily honoring it.
2132 #
2126 #
2133 # Note: eventually this guard will be removed. Please do not expect
2127 # Note: eventually this guard will be removed. Please do not expect
2134 # this behavior to remain.
2128 # this behavior to remain.
2135 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2129 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2136 cmdutil.checkunfinished(repo)
2130 cmdutil.checkunfinished(repo)
2137
2131
2138 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2132 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2139 opts = pycompat.byteskwargs(opts)
2133 opts = pycompat.byteskwargs(opts)
2140 if node == old.node():
2134 if node == old.node():
2141 ui.status(_(b"nothing changed\n"))
2135 ui.status(_(b"nothing changed\n"))
2142 return 1
2136 return 1
2143 else:
2137 else:
2144
2138
2145 def commitfunc(ui, repo, message, match, opts):
2139 def commitfunc(ui, repo, message, match, opts):
2146 overrides = {}
2140 overrides = {}
2147 if opts.get(b'secret'):
2141 if opts.get(b'secret'):
2148 overrides[(b'phases', b'new-commit')] = b'secret'
2142 overrides[(b'phases', b'new-commit')] = b'secret'
2149
2143
2150 baseui = repo.baseui
2144 baseui = repo.baseui
2151 with baseui.configoverride(overrides, b'commit'):
2145 with baseui.configoverride(overrides, b'commit'):
2152 with ui.configoverride(overrides, b'commit'):
2146 with ui.configoverride(overrides, b'commit'):
2153 editform = cmdutil.mergeeditform(
2147 editform = cmdutil.mergeeditform(
2154 repo[None], b'commit.normal'
2148 repo[None], b'commit.normal'
2155 )
2149 )
2156 editor = cmdutil.getcommiteditor(
2150 editor = cmdutil.getcommiteditor(
2157 editform=editform, **pycompat.strkwargs(opts)
2151 editform=editform, **pycompat.strkwargs(opts)
2158 )
2152 )
2159 return repo.commit(
2153 return repo.commit(
2160 message,
2154 message,
2161 opts.get(b'user'),
2155 opts.get(b'user'),
2162 opts.get(b'date'),
2156 opts.get(b'date'),
2163 match,
2157 match,
2164 editor=editor,
2158 editor=editor,
2165 extra=extra,
2159 extra=extra,
2166 )
2160 )
2167
2161
2168 opts = pycompat.byteskwargs(opts)
2162 opts = pycompat.byteskwargs(opts)
2169 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2163 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2170
2164
2171 if not node:
2165 if not node:
2172 stat = cmdutil.postcommitstatus(repo, pats, opts)
2166 stat = cmdutil.postcommitstatus(repo, pats, opts)
2173 if stat.deleted:
2167 if stat.deleted:
2174 ui.status(
2168 ui.status(
2175 _(
2169 _(
2176 b"nothing changed (%d missing files, see "
2170 b"nothing changed (%d missing files, see "
2177 b"'hg status')\n"
2171 b"'hg status')\n"
2178 )
2172 )
2179 % len(stat.deleted)
2173 % len(stat.deleted)
2180 )
2174 )
2181 else:
2175 else:
2182 ui.status(_(b"nothing changed\n"))
2176 ui.status(_(b"nothing changed\n"))
2183 return 1
2177 return 1
2184
2178
2185 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2179 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2186
2180
2187 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2181 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2188 status(
2182 status(
2189 ui,
2183 ui,
2190 repo,
2184 repo,
2191 modified=True,
2185 modified=True,
2192 added=True,
2186 added=True,
2193 removed=True,
2187 removed=True,
2194 deleted=True,
2188 deleted=True,
2195 unknown=True,
2189 unknown=True,
2196 subrepos=opts.get(b'subrepos'),
2190 subrepos=opts.get(b'subrepos'),
2197 )
2191 )
2198
2192
2199
2193
2200 @command(
2194 @command(
2201 b'config|showconfig|debugconfig',
2195 b'config|showconfig|debugconfig',
2202 [
2196 [
2203 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2197 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2204 # This is experimental because we need
2198 # This is experimental because we need
2205 # * reasonable behavior around aliases,
2199 # * reasonable behavior around aliases,
2206 # * decide if we display [debug] [experimental] and [devel] section par
2200 # * decide if we display [debug] [experimental] and [devel] section par
2207 # default
2201 # default
2208 # * some way to display "generic" config entry (the one matching
2202 # * some way to display "generic" config entry (the one matching
2209 # regexp,
2203 # regexp,
2210 # * proper display of the different value type
2204 # * proper display of the different value type
2211 # * a better way to handle <DYNAMIC> values (and variable types),
2205 # * a better way to handle <DYNAMIC> values (and variable types),
2212 # * maybe some type information ?
2206 # * maybe some type information ?
2213 (
2207 (
2214 b'',
2208 b'',
2215 b'exp-all-known',
2209 b'exp-all-known',
2216 None,
2210 None,
2217 _(b'show all known config option (EXPERIMENTAL)'),
2211 _(b'show all known config option (EXPERIMENTAL)'),
2218 ),
2212 ),
2219 (b'e', b'edit', None, _(b'edit user config')),
2213 (b'e', b'edit', None, _(b'edit user config')),
2220 (b'l', b'local', None, _(b'edit repository config')),
2214 (b'l', b'local', None, _(b'edit repository config')),
2221 (b'', b'source', None, _(b'show source of configuration value')),
2215 (b'', b'source', None, _(b'show source of configuration value')),
2222 (
2216 (
2223 b'',
2217 b'',
2224 b'shared',
2218 b'shared',
2225 None,
2219 None,
2226 _(b'edit shared source repository config (EXPERIMENTAL)'),
2220 _(b'edit shared source repository config (EXPERIMENTAL)'),
2227 ),
2221 ),
2228 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2222 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2229 (b'g', b'global', None, _(b'edit global config')),
2223 (b'g', b'global', None, _(b'edit global config')),
2230 ]
2224 ]
2231 + formatteropts,
2225 + formatteropts,
2232 _(b'[-u] [NAME]...'),
2226 _(b'[-u] [NAME]...'),
2233 helpcategory=command.CATEGORY_HELP,
2227 helpcategory=command.CATEGORY_HELP,
2234 optionalrepo=True,
2228 optionalrepo=True,
2235 intents={INTENT_READONLY},
2229 intents={INTENT_READONLY},
2236 )
2230 )
2237 def config(ui, repo, *values, **opts):
2231 def config(ui, repo, *values, **opts):
2238 """show combined config settings from all hgrc files
2232 """show combined config settings from all hgrc files
2239
2233
2240 With no arguments, print names and values of all config items.
2234 With no arguments, print names and values of all config items.
2241
2235
2242 With one argument of the form section.name, print just the value
2236 With one argument of the form section.name, print just the value
2243 of that config item.
2237 of that config item.
2244
2238
2245 With multiple arguments, print names and values of all config
2239 With multiple arguments, print names and values of all config
2246 items with matching section names or section.names.
2240 items with matching section names or section.names.
2247
2241
2248 With --edit, start an editor on the user-level config file. With
2242 With --edit, start an editor on the user-level config file. With
2249 --global, edit the system-wide config file. With --local, edit the
2243 --global, edit the system-wide config file. With --local, edit the
2250 repository-level config file.
2244 repository-level config file.
2251
2245
2252 With --source, the source (filename and line number) is printed
2246 With --source, the source (filename and line number) is printed
2253 for each config item.
2247 for each config item.
2254
2248
2255 See :hg:`help config` for more information about config files.
2249 See :hg:`help config` for more information about config files.
2256
2250
2257 .. container:: verbose
2251 .. container:: verbose
2258
2252
2259 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2253 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2260 This file is not shared across shares when in share-safe mode.
2254 This file is not shared across shares when in share-safe mode.
2261
2255
2262 Template:
2256 Template:
2263
2257
2264 The following keywords are supported. See also :hg:`help templates`.
2258 The following keywords are supported. See also :hg:`help templates`.
2265
2259
2266 :name: String. Config name.
2260 :name: String. Config name.
2267 :source: String. Filename and line number where the item is defined.
2261 :source: String. Filename and line number where the item is defined.
2268 :value: String. Config value.
2262 :value: String. Config value.
2269
2263
2270 The --shared flag can be used to edit the config file of shared source
2264 The --shared flag can be used to edit the config file of shared source
2271 repository. It only works when you have shared using the experimental
2265 repository. It only works when you have shared using the experimental
2272 share safe feature.
2266 share safe feature.
2273
2267
2274 Returns 0 on success, 1 if NAME does not exist.
2268 Returns 0 on success, 1 if NAME does not exist.
2275
2269
2276 """
2270 """
2277
2271
2278 opts = pycompat.byteskwargs(opts)
2272 opts = pycompat.byteskwargs(opts)
2279 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2273 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2280 if any(opts.get(o) for o in editopts):
2274 if any(opts.get(o) for o in editopts):
2281 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2275 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2282 if opts.get(b'local'):
2276 if opts.get(b'local'):
2283 if not repo:
2277 if not repo:
2284 raise error.InputError(
2278 raise error.InputError(
2285 _(b"can't use --local outside a repository")
2279 _(b"can't use --local outside a repository")
2286 )
2280 )
2287 paths = [repo.vfs.join(b'hgrc')]
2281 paths = [repo.vfs.join(b'hgrc')]
2288 elif opts.get(b'global'):
2282 elif opts.get(b'global'):
2289 paths = rcutil.systemrcpath()
2283 paths = rcutil.systemrcpath()
2290 elif opts.get(b'shared'):
2284 elif opts.get(b'shared'):
2291 if not repo.shared():
2285 if not repo.shared():
2292 raise error.InputError(
2286 raise error.InputError(
2293 _(b"repository is not shared; can't use --shared")
2287 _(b"repository is not shared; can't use --shared")
2294 )
2288 )
2295 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2289 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2296 raise error.InputError(
2290 raise error.InputError(
2297 _(
2291 _(
2298 b"share safe feature not enabled; "
2292 b"share safe feature not enabled; "
2299 b"unable to edit shared source repository config"
2293 b"unable to edit shared source repository config"
2300 )
2294 )
2301 )
2295 )
2302 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2296 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2303 elif opts.get(b'non_shared'):
2297 elif opts.get(b'non_shared'):
2304 paths = [repo.vfs.join(b'hgrc-not-shared')]
2298 paths = [repo.vfs.join(b'hgrc-not-shared')]
2305 else:
2299 else:
2306 paths = rcutil.userrcpath()
2300 paths = rcutil.userrcpath()
2307
2301
2308 for f in paths:
2302 for f in paths:
2309 if os.path.exists(f):
2303 if os.path.exists(f):
2310 break
2304 break
2311 else:
2305 else:
2312 if opts.get(b'global'):
2306 if opts.get(b'global'):
2313 samplehgrc = uimod.samplehgrcs[b'global']
2307 samplehgrc = uimod.samplehgrcs[b'global']
2314 elif opts.get(b'local'):
2308 elif opts.get(b'local'):
2315 samplehgrc = uimod.samplehgrcs[b'local']
2309 samplehgrc = uimod.samplehgrcs[b'local']
2316 else:
2310 else:
2317 samplehgrc = uimod.samplehgrcs[b'user']
2311 samplehgrc = uimod.samplehgrcs[b'user']
2318
2312
2319 f = paths[0]
2313 f = paths[0]
2320 fp = open(f, b"wb")
2314 fp = open(f, b"wb")
2321 fp.write(util.tonativeeol(samplehgrc))
2315 fp.write(util.tonativeeol(samplehgrc))
2322 fp.close()
2316 fp.close()
2323
2317
2324 editor = ui.geteditor()
2318 editor = ui.geteditor()
2325 ui.system(
2319 ui.system(
2326 b"%s \"%s\"" % (editor, f),
2320 b"%s \"%s\"" % (editor, f),
2327 onerr=error.InputError,
2321 onerr=error.InputError,
2328 errprefix=_(b"edit failed"),
2322 errprefix=_(b"edit failed"),
2329 blockedtag=b'config_edit',
2323 blockedtag=b'config_edit',
2330 )
2324 )
2331 return
2325 return
2332 ui.pager(b'config')
2326 ui.pager(b'config')
2333 fm = ui.formatter(b'config', opts)
2327 fm = ui.formatter(b'config', opts)
2334 for t, f in rcutil.rccomponents():
2328 for t, f in rcutil.rccomponents():
2335 if t == b'path':
2329 if t == b'path':
2336 ui.debug(b'read config from: %s\n' % f)
2330 ui.debug(b'read config from: %s\n' % f)
2337 elif t == b'resource':
2331 elif t == b'resource':
2338 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2332 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2339 elif t == b'items':
2333 elif t == b'items':
2340 # Don't print anything for 'items'.
2334 # Don't print anything for 'items'.
2341 pass
2335 pass
2342 else:
2336 else:
2343 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2337 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2344 untrusted = bool(opts.get(b'untrusted'))
2338 untrusted = bool(opts.get(b'untrusted'))
2345
2339
2346 selsections = selentries = []
2340 selsections = selentries = []
2347 if values:
2341 if values:
2348 selsections = [v for v in values if b'.' not in v]
2342 selsections = [v for v in values if b'.' not in v]
2349 selentries = [v for v in values if b'.' in v]
2343 selentries = [v for v in values if b'.' in v]
2350 uniquesel = len(selentries) == 1 and not selsections
2344 uniquesel = len(selentries) == 1 and not selsections
2351 selsections = set(selsections)
2345 selsections = set(selsections)
2352 selentries = set(selentries)
2346 selentries = set(selentries)
2353
2347
2354 matched = False
2348 matched = False
2355 all_known = opts[b'exp_all_known']
2349 all_known = opts[b'exp_all_known']
2356 show_source = ui.debugflag or opts.get(b'source')
2350 show_source = ui.debugflag or opts.get(b'source')
2357 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2351 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2358 for section, name, value in entries:
2352 for section, name, value in entries:
2359 source = ui.configsource(section, name, untrusted)
2353 source = ui.configsource(section, name, untrusted)
2360 value = pycompat.bytestr(value)
2354 value = pycompat.bytestr(value)
2361 defaultvalue = ui.configdefault(section, name)
2355 defaultvalue = ui.configdefault(section, name)
2362 if fm.isplain():
2356 if fm.isplain():
2363 source = source or b'none'
2357 source = source or b'none'
2364 value = value.replace(b'\n', b'\\n')
2358 value = value.replace(b'\n', b'\\n')
2365 entryname = section + b'.' + name
2359 entryname = section + b'.' + name
2366 if values and not (section in selsections or entryname in selentries):
2360 if values and not (section in selsections or entryname in selentries):
2367 continue
2361 continue
2368 fm.startitem()
2362 fm.startitem()
2369 fm.condwrite(show_source, b'source', b'%s: ', source)
2363 fm.condwrite(show_source, b'source', b'%s: ', source)
2370 if uniquesel:
2364 if uniquesel:
2371 fm.data(name=entryname)
2365 fm.data(name=entryname)
2372 fm.write(b'value', b'%s\n', value)
2366 fm.write(b'value', b'%s\n', value)
2373 else:
2367 else:
2374 fm.write(b'name value', b'%s=%s\n', entryname, value)
2368 fm.write(b'name value', b'%s=%s\n', entryname, value)
2375 if formatter.isprintable(defaultvalue):
2369 if formatter.isprintable(defaultvalue):
2376 fm.data(defaultvalue=defaultvalue)
2370 fm.data(defaultvalue=defaultvalue)
2377 elif isinstance(defaultvalue, list) and all(
2371 elif isinstance(defaultvalue, list) and all(
2378 formatter.isprintable(e) for e in defaultvalue
2372 formatter.isprintable(e) for e in defaultvalue
2379 ):
2373 ):
2380 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2374 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2381 # TODO: no idea how to process unsupported defaultvalue types
2375 # TODO: no idea how to process unsupported defaultvalue types
2382 matched = True
2376 matched = True
2383 fm.end()
2377 fm.end()
2384 if matched:
2378 if matched:
2385 return 0
2379 return 0
2386 return 1
2380 return 1
2387
2381
2388
2382
2389 @command(
2383 @command(
2390 b'continue',
2384 b'continue',
2391 dryrunopts,
2385 dryrunopts,
2392 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2386 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2393 helpbasic=True,
2387 helpbasic=True,
2394 )
2388 )
2395 def continuecmd(ui, repo, **opts):
2389 def continuecmd(ui, repo, **opts):
2396 """resumes an interrupted operation (EXPERIMENTAL)
2390 """resumes an interrupted operation (EXPERIMENTAL)
2397
2391
2398 Finishes a multistep operation like graft, histedit, rebase, merge,
2392 Finishes a multistep operation like graft, histedit, rebase, merge,
2399 and unshelve if they are in an interrupted state.
2393 and unshelve if they are in an interrupted state.
2400
2394
2401 use --dry-run/-n to dry run the command.
2395 use --dry-run/-n to dry run the command.
2402 """
2396 """
2403 dryrun = opts.get('dry_run')
2397 dryrun = opts.get('dry_run')
2404 contstate = cmdutil.getunfinishedstate(repo)
2398 contstate = cmdutil.getunfinishedstate(repo)
2405 if not contstate:
2399 if not contstate:
2406 raise error.StateError(_(b'no operation in progress'))
2400 raise error.StateError(_(b'no operation in progress'))
2407 if not contstate.continuefunc:
2401 if not contstate.continuefunc:
2408 raise error.StateError(
2402 raise error.StateError(
2409 (
2403 (
2410 _(b"%s in progress but does not support 'hg continue'")
2404 _(b"%s in progress but does not support 'hg continue'")
2411 % (contstate._opname)
2405 % (contstate._opname)
2412 ),
2406 ),
2413 hint=contstate.continuemsg(),
2407 hint=contstate.continuemsg(),
2414 )
2408 )
2415 if dryrun:
2409 if dryrun:
2416 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2410 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2417 return
2411 return
2418 return contstate.continuefunc(ui, repo)
2412 return contstate.continuefunc(ui, repo)
2419
2413
2420
2414
2421 @command(
2415 @command(
2422 b'copy|cp',
2416 b'copy|cp',
2423 [
2417 [
2424 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2418 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2425 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2419 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2426 (
2420 (
2427 b'',
2421 b'',
2428 b'at-rev',
2422 b'at-rev',
2429 b'',
2423 b'',
2430 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2424 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2431 _(b'REV'),
2425 _(b'REV'),
2432 ),
2426 ),
2433 (
2427 (
2434 b'f',
2428 b'f',
2435 b'force',
2429 b'force',
2436 None,
2430 None,
2437 _(b'forcibly copy over an existing managed file'),
2431 _(b'forcibly copy over an existing managed file'),
2438 ),
2432 ),
2439 ]
2433 ]
2440 + walkopts
2434 + walkopts
2441 + dryrunopts,
2435 + dryrunopts,
2442 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2436 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2443 helpcategory=command.CATEGORY_FILE_CONTENTS,
2437 helpcategory=command.CATEGORY_FILE_CONTENTS,
2444 )
2438 )
2445 def copy(ui, repo, *pats, **opts):
2439 def copy(ui, repo, *pats, **opts):
2446 """mark files as copied for the next commit
2440 """mark files as copied for the next commit
2447
2441
2448 Mark dest as having copies of source files. If dest is a
2442 Mark dest as having copies of source files. If dest is a
2449 directory, copies are put in that directory. If dest is a file,
2443 directory, copies are put in that directory. If dest is a file,
2450 the source must be a single file.
2444 the source must be a single file.
2451
2445
2452 By default, this command copies the contents of files as they
2446 By default, this command copies the contents of files as they
2453 exist in the working directory. If invoked with -A/--after, the
2447 exist in the working directory. If invoked with -A/--after, the
2454 operation is recorded, but no copying is performed.
2448 operation is recorded, but no copying is performed.
2455
2449
2456 To undo marking a destination file as copied, use --forget. With that
2450 To undo marking a destination file as copied, use --forget. With that
2457 option, all given (positional) arguments are unmarked as copies. The
2451 option, all given (positional) arguments are unmarked as copies. The
2458 destination file(s) will be left in place (still tracked). Note that
2452 destination file(s) will be left in place (still tracked). Note that
2459 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2453 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2460
2454
2461 This command takes effect with the next commit by default.
2455 This command takes effect with the next commit by default.
2462
2456
2463 Returns 0 on success, 1 if errors are encountered.
2457 Returns 0 on success, 1 if errors are encountered.
2464 """
2458 """
2465 opts = pycompat.byteskwargs(opts)
2459 opts = pycompat.byteskwargs(opts)
2466 with repo.wlock():
2460 with repo.wlock():
2467 return cmdutil.copy(ui, repo, pats, opts)
2461 return cmdutil.copy(ui, repo, pats, opts)
2468
2462
2469
2463
2470 @command(
2464 @command(
2471 b'debugcommands',
2465 b'debugcommands',
2472 [],
2466 [],
2473 _(b'[COMMAND]'),
2467 _(b'[COMMAND]'),
2474 helpcategory=command.CATEGORY_HELP,
2468 helpcategory=command.CATEGORY_HELP,
2475 norepo=True,
2469 norepo=True,
2476 )
2470 )
2477 def debugcommands(ui, cmd=b'', *args):
2471 def debugcommands(ui, cmd=b'', *args):
2478 """list all available commands and options"""
2472 """list all available commands and options"""
2479 for cmd, vals in sorted(pycompat.iteritems(table)):
2473 for cmd, vals in sorted(pycompat.iteritems(table)):
2480 cmd = cmd.split(b'|')[0]
2474 cmd = cmd.split(b'|')[0]
2481 opts = b', '.join([i[1] for i in vals[1]])
2475 opts = b', '.join([i[1] for i in vals[1]])
2482 ui.write(b'%s: %s\n' % (cmd, opts))
2476 ui.write(b'%s: %s\n' % (cmd, opts))
2483
2477
2484
2478
2485 @command(
2479 @command(
2486 b'debugcomplete',
2480 b'debugcomplete',
2487 [(b'o', b'options', None, _(b'show the command options'))],
2481 [(b'o', b'options', None, _(b'show the command options'))],
2488 _(b'[-o] CMD'),
2482 _(b'[-o] CMD'),
2489 helpcategory=command.CATEGORY_HELP,
2483 helpcategory=command.CATEGORY_HELP,
2490 norepo=True,
2484 norepo=True,
2491 )
2485 )
2492 def debugcomplete(ui, cmd=b'', **opts):
2486 def debugcomplete(ui, cmd=b'', **opts):
2493 """returns the completion list associated with the given command"""
2487 """returns the completion list associated with the given command"""
2494
2488
2495 if opts.get('options'):
2489 if opts.get('options'):
2496 options = []
2490 options = []
2497 otables = [globalopts]
2491 otables = [globalopts]
2498 if cmd:
2492 if cmd:
2499 aliases, entry = cmdutil.findcmd(cmd, table, False)
2493 aliases, entry = cmdutil.findcmd(cmd, table, False)
2500 otables.append(entry[1])
2494 otables.append(entry[1])
2501 for t in otables:
2495 for t in otables:
2502 for o in t:
2496 for o in t:
2503 if b"(DEPRECATED)" in o[3]:
2497 if b"(DEPRECATED)" in o[3]:
2504 continue
2498 continue
2505 if o[0]:
2499 if o[0]:
2506 options.append(b'-%s' % o[0])
2500 options.append(b'-%s' % o[0])
2507 options.append(b'--%s' % o[1])
2501 options.append(b'--%s' % o[1])
2508 ui.write(b"%s\n" % b"\n".join(options))
2502 ui.write(b"%s\n" % b"\n".join(options))
2509 return
2503 return
2510
2504
2511 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2505 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2512 if ui.verbose:
2506 if ui.verbose:
2513 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2507 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2514 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2508 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2515
2509
2516
2510
2517 @command(
2511 @command(
2518 b'diff',
2512 b'diff',
2519 [
2513 [
2520 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2514 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2521 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2515 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2522 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2516 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2523 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2517 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2524 ]
2518 ]
2525 + diffopts
2519 + diffopts
2526 + diffopts2
2520 + diffopts2
2527 + walkopts
2521 + walkopts
2528 + subrepoopts,
2522 + subrepoopts,
2529 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2523 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2530 helpcategory=command.CATEGORY_FILE_CONTENTS,
2524 helpcategory=command.CATEGORY_FILE_CONTENTS,
2531 helpbasic=True,
2525 helpbasic=True,
2532 inferrepo=True,
2526 inferrepo=True,
2533 intents={INTENT_READONLY},
2527 intents={INTENT_READONLY},
2534 )
2528 )
2535 def diff(ui, repo, *pats, **opts):
2529 def diff(ui, repo, *pats, **opts):
2536 """diff repository (or selected files)
2530 """diff repository (or selected files)
2537
2531
2538 Show differences between revisions for the specified files.
2532 Show differences between revisions for the specified files.
2539
2533
2540 Differences between files are shown using the unified diff format.
2534 Differences between files are shown using the unified diff format.
2541
2535
2542 .. note::
2536 .. note::
2543
2537
2544 :hg:`diff` may generate unexpected results for merges, as it will
2538 :hg:`diff` may generate unexpected results for merges, as it will
2545 default to comparing against the working directory's first
2539 default to comparing against the working directory's first
2546 parent changeset if no revisions are specified.
2540 parent changeset if no revisions are specified.
2547
2541
2548 By default, the working directory files are compared to its first parent. To
2542 By default, the working directory files are compared to its first parent. To
2549 see the differences from another revision, use --from. To see the difference
2543 see the differences from another revision, use --from. To see the difference
2550 to another revision, use --to. For example, :hg:`diff --from .^` will show
2544 to another revision, use --to. For example, :hg:`diff --from .^` will show
2551 the differences from the working copy's grandparent to the working copy,
2545 the differences from the working copy's grandparent to the working copy,
2552 :hg:`diff --to .` will show the diff from the working copy to its parent
2546 :hg:`diff --to .` will show the diff from the working copy to its parent
2553 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2547 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2554 show the diff between those two revisions.
2548 show the diff between those two revisions.
2555
2549
2556 Alternatively you can specify -c/--change with a revision to see the changes
2550 Alternatively you can specify -c/--change with a revision to see the changes
2557 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2551 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2558 equivalent to :hg:`diff --from 42^ --to 42`)
2552 equivalent to :hg:`diff --from 42^ --to 42`)
2559
2553
2560 Without the -a/--text option, diff will avoid generating diffs of
2554 Without the -a/--text option, diff will avoid generating diffs of
2561 files it detects as binary. With -a, diff will generate a diff
2555 files it detects as binary. With -a, diff will generate a diff
2562 anyway, probably with undesirable results.
2556 anyway, probably with undesirable results.
2563
2557
2564 Use the -g/--git option to generate diffs in the git extended diff
2558 Use the -g/--git option to generate diffs in the git extended diff
2565 format. For more information, read :hg:`help diffs`.
2559 format. For more information, read :hg:`help diffs`.
2566
2560
2567 .. container:: verbose
2561 .. container:: verbose
2568
2562
2569 Examples:
2563 Examples:
2570
2564
2571 - compare a file in the current working directory to its parent::
2565 - compare a file in the current working directory to its parent::
2572
2566
2573 hg diff foo.c
2567 hg diff foo.c
2574
2568
2575 - compare two historical versions of a directory, with rename info::
2569 - compare two historical versions of a directory, with rename info::
2576
2570
2577 hg diff --git --from 1.0 --to 1.2 lib/
2571 hg diff --git --from 1.0 --to 1.2 lib/
2578
2572
2579 - get change stats relative to the last change on some date::
2573 - get change stats relative to the last change on some date::
2580
2574
2581 hg diff --stat --from "date('may 2')"
2575 hg diff --stat --from "date('may 2')"
2582
2576
2583 - diff all newly-added files that contain a keyword::
2577 - diff all newly-added files that contain a keyword::
2584
2578
2585 hg diff "set:added() and grep(GNU)"
2579 hg diff "set:added() and grep(GNU)"
2586
2580
2587 - compare a revision and its parents::
2581 - compare a revision and its parents::
2588
2582
2589 hg diff -c 9353 # compare against first parent
2583 hg diff -c 9353 # compare against first parent
2590 hg diff --from 9353^ --to 9353 # same using revset syntax
2584 hg diff --from 9353^ --to 9353 # same using revset syntax
2591 hg diff --from 9353^2 --to 9353 # compare against the second parent
2585 hg diff --from 9353^2 --to 9353 # compare against the second parent
2592
2586
2593 Returns 0 on success.
2587 Returns 0 on success.
2594 """
2588 """
2595
2589
2596 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2590 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2597 opts = pycompat.byteskwargs(opts)
2591 opts = pycompat.byteskwargs(opts)
2598 revs = opts.get(b'rev')
2592 revs = opts.get(b'rev')
2599 change = opts.get(b'change')
2593 change = opts.get(b'change')
2600 from_rev = opts.get(b'from')
2594 from_rev = opts.get(b'from')
2601 to_rev = opts.get(b'to')
2595 to_rev = opts.get(b'to')
2602 stat = opts.get(b'stat')
2596 stat = opts.get(b'stat')
2603 reverse = opts.get(b'reverse')
2597 reverse = opts.get(b'reverse')
2604
2598
2605 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2599 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2606 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2600 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2607 if change:
2601 if change:
2608 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2602 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2609 ctx2 = scmutil.revsingle(repo, change, None)
2603 ctx2 = scmutil.revsingle(repo, change, None)
2610 ctx1 = logcmdutil.diff_parent(ctx2)
2604 ctx1 = logcmdutil.diff_parent(ctx2)
2611 elif from_rev or to_rev:
2605 elif from_rev or to_rev:
2612 repo = scmutil.unhidehashlikerevs(
2606 repo = scmutil.unhidehashlikerevs(
2613 repo, [from_rev] + [to_rev], b'nowarn'
2607 repo, [from_rev] + [to_rev], b'nowarn'
2614 )
2608 )
2615 ctx1 = scmutil.revsingle(repo, from_rev, None)
2609 ctx1 = scmutil.revsingle(repo, from_rev, None)
2616 ctx2 = scmutil.revsingle(repo, to_rev, None)
2610 ctx2 = scmutil.revsingle(repo, to_rev, None)
2617 else:
2611 else:
2618 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2612 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2619 ctx1, ctx2 = scmutil.revpair(repo, revs)
2613 ctx1, ctx2 = scmutil.revpair(repo, revs)
2620
2614
2621 if reverse:
2615 if reverse:
2622 ctxleft = ctx2
2616 ctxleft = ctx2
2623 ctxright = ctx1
2617 ctxright = ctx1
2624 else:
2618 else:
2625 ctxleft = ctx1
2619 ctxleft = ctx1
2626 ctxright = ctx2
2620 ctxright = ctx2
2627
2621
2628 diffopts = patch.diffallopts(ui, opts)
2622 diffopts = patch.diffallopts(ui, opts)
2629 m = scmutil.match(ctx2, pats, opts)
2623 m = scmutil.match(ctx2, pats, opts)
2630 m = repo.narrowmatch(m)
2624 m = repo.narrowmatch(m)
2631 ui.pager(b'diff')
2625 ui.pager(b'diff')
2632 logcmdutil.diffordiffstat(
2626 logcmdutil.diffordiffstat(
2633 ui,
2627 ui,
2634 repo,
2628 repo,
2635 diffopts,
2629 diffopts,
2636 ctxleft,
2630 ctxleft,
2637 ctxright,
2631 ctxright,
2638 m,
2632 m,
2639 stat=stat,
2633 stat=stat,
2640 listsubrepos=opts.get(b'subrepos'),
2634 listsubrepos=opts.get(b'subrepos'),
2641 root=opts.get(b'root'),
2635 root=opts.get(b'root'),
2642 )
2636 )
2643
2637
2644
2638
2645 @command(
2639 @command(
2646 b'export',
2640 b'export',
2647 [
2641 [
2648 (
2642 (
2649 b'B',
2643 b'B',
2650 b'bookmark',
2644 b'bookmark',
2651 b'',
2645 b'',
2652 _(b'export changes only reachable by given bookmark'),
2646 _(b'export changes only reachable by given bookmark'),
2653 _(b'BOOKMARK'),
2647 _(b'BOOKMARK'),
2654 ),
2648 ),
2655 (
2649 (
2656 b'o',
2650 b'o',
2657 b'output',
2651 b'output',
2658 b'',
2652 b'',
2659 _(b'print output to file with formatted name'),
2653 _(b'print output to file with formatted name'),
2660 _(b'FORMAT'),
2654 _(b'FORMAT'),
2661 ),
2655 ),
2662 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2656 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2663 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2657 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2664 ]
2658 ]
2665 + diffopts
2659 + diffopts
2666 + formatteropts,
2660 + formatteropts,
2667 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2661 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2668 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2662 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2669 helpbasic=True,
2663 helpbasic=True,
2670 intents={INTENT_READONLY},
2664 intents={INTENT_READONLY},
2671 )
2665 )
2672 def export(ui, repo, *changesets, **opts):
2666 def export(ui, repo, *changesets, **opts):
2673 """dump the header and diffs for one or more changesets
2667 """dump the header and diffs for one or more changesets
2674
2668
2675 Print the changeset header and diffs for one or more revisions.
2669 Print the changeset header and diffs for one or more revisions.
2676 If no revision is given, the parent of the working directory is used.
2670 If no revision is given, the parent of the working directory is used.
2677
2671
2678 The information shown in the changeset header is: author, date,
2672 The information shown in the changeset header is: author, date,
2679 branch name (if non-default), changeset hash, parent(s) and commit
2673 branch name (if non-default), changeset hash, parent(s) and commit
2680 comment.
2674 comment.
2681
2675
2682 .. note::
2676 .. note::
2683
2677
2684 :hg:`export` may generate unexpected diff output for merge
2678 :hg:`export` may generate unexpected diff output for merge
2685 changesets, as it will compare the merge changeset against its
2679 changesets, as it will compare the merge changeset against its
2686 first parent only.
2680 first parent only.
2687
2681
2688 Output may be to a file, in which case the name of the file is
2682 Output may be to a file, in which case the name of the file is
2689 given using a template string. See :hg:`help templates`. In addition
2683 given using a template string. See :hg:`help templates`. In addition
2690 to the common template keywords, the following formatting rules are
2684 to the common template keywords, the following formatting rules are
2691 supported:
2685 supported:
2692
2686
2693 :``%%``: literal "%" character
2687 :``%%``: literal "%" character
2694 :``%H``: changeset hash (40 hexadecimal digits)
2688 :``%H``: changeset hash (40 hexadecimal digits)
2695 :``%N``: number of patches being generated
2689 :``%N``: number of patches being generated
2696 :``%R``: changeset revision number
2690 :``%R``: changeset revision number
2697 :``%b``: basename of the exporting repository
2691 :``%b``: basename of the exporting repository
2698 :``%h``: short-form changeset hash (12 hexadecimal digits)
2692 :``%h``: short-form changeset hash (12 hexadecimal digits)
2699 :``%m``: first line of the commit message (only alphanumeric characters)
2693 :``%m``: first line of the commit message (only alphanumeric characters)
2700 :``%n``: zero-padded sequence number, starting at 1
2694 :``%n``: zero-padded sequence number, starting at 1
2701 :``%r``: zero-padded changeset revision number
2695 :``%r``: zero-padded changeset revision number
2702 :``\\``: literal "\\" character
2696 :``\\``: literal "\\" character
2703
2697
2704 Without the -a/--text option, export will avoid generating diffs
2698 Without the -a/--text option, export will avoid generating diffs
2705 of files it detects as binary. With -a, export will generate a
2699 of files it detects as binary. With -a, export will generate a
2706 diff anyway, probably with undesirable results.
2700 diff anyway, probably with undesirable results.
2707
2701
2708 With -B/--bookmark changesets reachable by the given bookmark are
2702 With -B/--bookmark changesets reachable by the given bookmark are
2709 selected.
2703 selected.
2710
2704
2711 Use the -g/--git option to generate diffs in the git extended diff
2705 Use the -g/--git option to generate diffs in the git extended diff
2712 format. See :hg:`help diffs` for more information.
2706 format. See :hg:`help diffs` for more information.
2713
2707
2714 With the --switch-parent option, the diff will be against the
2708 With the --switch-parent option, the diff will be against the
2715 second parent. It can be useful to review a merge.
2709 second parent. It can be useful to review a merge.
2716
2710
2717 .. container:: verbose
2711 .. container:: verbose
2718
2712
2719 Template:
2713 Template:
2720
2714
2721 The following keywords are supported in addition to the common template
2715 The following keywords are supported in addition to the common template
2722 keywords and functions. See also :hg:`help templates`.
2716 keywords and functions. See also :hg:`help templates`.
2723
2717
2724 :diff: String. Diff content.
2718 :diff: String. Diff content.
2725 :parents: List of strings. Parent nodes of the changeset.
2719 :parents: List of strings. Parent nodes of the changeset.
2726
2720
2727 Examples:
2721 Examples:
2728
2722
2729 - use export and import to transplant a bugfix to the current
2723 - use export and import to transplant a bugfix to the current
2730 branch::
2724 branch::
2731
2725
2732 hg export -r 9353 | hg import -
2726 hg export -r 9353 | hg import -
2733
2727
2734 - export all the changesets between two revisions to a file with
2728 - export all the changesets between two revisions to a file with
2735 rename information::
2729 rename information::
2736
2730
2737 hg export --git -r 123:150 > changes.txt
2731 hg export --git -r 123:150 > changes.txt
2738
2732
2739 - split outgoing changes into a series of patches with
2733 - split outgoing changes into a series of patches with
2740 descriptive names::
2734 descriptive names::
2741
2735
2742 hg export -r "outgoing()" -o "%n-%m.patch"
2736 hg export -r "outgoing()" -o "%n-%m.patch"
2743
2737
2744 Returns 0 on success.
2738 Returns 0 on success.
2745 """
2739 """
2746 opts = pycompat.byteskwargs(opts)
2740 opts = pycompat.byteskwargs(opts)
2747 bookmark = opts.get(b'bookmark')
2741 bookmark = opts.get(b'bookmark')
2748 changesets += tuple(opts.get(b'rev', []))
2742 changesets += tuple(opts.get(b'rev', []))
2749
2743
2750 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2744 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2751
2745
2752 if bookmark:
2746 if bookmark:
2753 if bookmark not in repo._bookmarks:
2747 if bookmark not in repo._bookmarks:
2754 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2748 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2755
2749
2756 revs = scmutil.bookmarkrevs(repo, bookmark)
2750 revs = scmutil.bookmarkrevs(repo, bookmark)
2757 else:
2751 else:
2758 if not changesets:
2752 if not changesets:
2759 changesets = [b'.']
2753 changesets = [b'.']
2760
2754
2761 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2755 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2762 revs = scmutil.revrange(repo, changesets)
2756 revs = scmutil.revrange(repo, changesets)
2763
2757
2764 if not revs:
2758 if not revs:
2765 raise error.InputError(_(b"export requires at least one changeset"))
2759 raise error.InputError(_(b"export requires at least one changeset"))
2766 if len(revs) > 1:
2760 if len(revs) > 1:
2767 ui.note(_(b'exporting patches:\n'))
2761 ui.note(_(b'exporting patches:\n'))
2768 else:
2762 else:
2769 ui.note(_(b'exporting patch:\n'))
2763 ui.note(_(b'exporting patch:\n'))
2770
2764
2771 fntemplate = opts.get(b'output')
2765 fntemplate = opts.get(b'output')
2772 if cmdutil.isstdiofilename(fntemplate):
2766 if cmdutil.isstdiofilename(fntemplate):
2773 fntemplate = b''
2767 fntemplate = b''
2774
2768
2775 if fntemplate:
2769 if fntemplate:
2776 fm = formatter.nullformatter(ui, b'export', opts)
2770 fm = formatter.nullformatter(ui, b'export', opts)
2777 else:
2771 else:
2778 ui.pager(b'export')
2772 ui.pager(b'export')
2779 fm = ui.formatter(b'export', opts)
2773 fm = ui.formatter(b'export', opts)
2780 with fm:
2774 with fm:
2781 cmdutil.export(
2775 cmdutil.export(
2782 repo,
2776 repo,
2783 revs,
2777 revs,
2784 fm,
2778 fm,
2785 fntemplate=fntemplate,
2779 fntemplate=fntemplate,
2786 switch_parent=opts.get(b'switch_parent'),
2780 switch_parent=opts.get(b'switch_parent'),
2787 opts=patch.diffallopts(ui, opts),
2781 opts=patch.diffallopts(ui, opts),
2788 )
2782 )
2789
2783
2790
2784
2791 @command(
2785 @command(
2792 b'files',
2786 b'files',
2793 [
2787 [
2794 (
2788 (
2795 b'r',
2789 b'r',
2796 b'rev',
2790 b'rev',
2797 b'',
2791 b'',
2798 _(b'search the repository as it is in REV'),
2792 _(b'search the repository as it is in REV'),
2799 _(b'REV'),
2793 _(b'REV'),
2800 ),
2794 ),
2801 (
2795 (
2802 b'0',
2796 b'0',
2803 b'print0',
2797 b'print0',
2804 None,
2798 None,
2805 _(b'end filenames with NUL, for use with xargs'),
2799 _(b'end filenames with NUL, for use with xargs'),
2806 ),
2800 ),
2807 ]
2801 ]
2808 + walkopts
2802 + walkopts
2809 + formatteropts
2803 + formatteropts
2810 + subrepoopts,
2804 + subrepoopts,
2811 _(b'[OPTION]... [FILE]...'),
2805 _(b'[OPTION]... [FILE]...'),
2812 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2806 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2813 intents={INTENT_READONLY},
2807 intents={INTENT_READONLY},
2814 )
2808 )
2815 def files(ui, repo, *pats, **opts):
2809 def files(ui, repo, *pats, **opts):
2816 """list tracked files
2810 """list tracked files
2817
2811
2818 Print files under Mercurial control in the working directory or
2812 Print files under Mercurial control in the working directory or
2819 specified revision for given files (excluding removed files).
2813 specified revision for given files (excluding removed files).
2820 Files can be specified as filenames or filesets.
2814 Files can be specified as filenames or filesets.
2821
2815
2822 If no files are given to match, this command prints the names
2816 If no files are given to match, this command prints the names
2823 of all files under Mercurial control.
2817 of all files under Mercurial control.
2824
2818
2825 .. container:: verbose
2819 .. container:: verbose
2826
2820
2827 Template:
2821 Template:
2828
2822
2829 The following keywords are supported in addition to the common template
2823 The following keywords are supported in addition to the common template
2830 keywords and functions. See also :hg:`help templates`.
2824 keywords and functions. See also :hg:`help templates`.
2831
2825
2832 :flags: String. Character denoting file's symlink and executable bits.
2826 :flags: String. Character denoting file's symlink and executable bits.
2833 :path: String. Repository-absolute path of the file.
2827 :path: String. Repository-absolute path of the file.
2834 :size: Integer. Size of the file in bytes.
2828 :size: Integer. Size of the file in bytes.
2835
2829
2836 Examples:
2830 Examples:
2837
2831
2838 - list all files under the current directory::
2832 - list all files under the current directory::
2839
2833
2840 hg files .
2834 hg files .
2841
2835
2842 - shows sizes and flags for current revision::
2836 - shows sizes and flags for current revision::
2843
2837
2844 hg files -vr .
2838 hg files -vr .
2845
2839
2846 - list all files named README::
2840 - list all files named README::
2847
2841
2848 hg files -I "**/README"
2842 hg files -I "**/README"
2849
2843
2850 - list all binary files::
2844 - list all binary files::
2851
2845
2852 hg files "set:binary()"
2846 hg files "set:binary()"
2853
2847
2854 - find files containing a regular expression::
2848 - find files containing a regular expression::
2855
2849
2856 hg files "set:grep('bob')"
2850 hg files "set:grep('bob')"
2857
2851
2858 - search tracked file contents with xargs and grep::
2852 - search tracked file contents with xargs and grep::
2859
2853
2860 hg files -0 | xargs -0 grep foo
2854 hg files -0 | xargs -0 grep foo
2861
2855
2862 See :hg:`help patterns` and :hg:`help filesets` for more information
2856 See :hg:`help patterns` and :hg:`help filesets` for more information
2863 on specifying file patterns.
2857 on specifying file patterns.
2864
2858
2865 Returns 0 if a match is found, 1 otherwise.
2859 Returns 0 if a match is found, 1 otherwise.
2866
2860
2867 """
2861 """
2868
2862
2869 opts = pycompat.byteskwargs(opts)
2863 opts = pycompat.byteskwargs(opts)
2870 rev = opts.get(b'rev')
2864 rev = opts.get(b'rev')
2871 if rev:
2865 if rev:
2872 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2866 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2873 ctx = scmutil.revsingle(repo, rev, None)
2867 ctx = scmutil.revsingle(repo, rev, None)
2874
2868
2875 end = b'\n'
2869 end = b'\n'
2876 if opts.get(b'print0'):
2870 if opts.get(b'print0'):
2877 end = b'\0'
2871 end = b'\0'
2878 fmt = b'%s' + end
2872 fmt = b'%s' + end
2879
2873
2880 m = scmutil.match(ctx, pats, opts)
2874 m = scmutil.match(ctx, pats, opts)
2881 ui.pager(b'files')
2875 ui.pager(b'files')
2882 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2876 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2883 with ui.formatter(b'files', opts) as fm:
2877 with ui.formatter(b'files', opts) as fm:
2884 return cmdutil.files(
2878 return cmdutil.files(
2885 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2879 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2886 )
2880 )
2887
2881
2888
2882
2889 @command(
2883 @command(
2890 b'forget',
2884 b'forget',
2891 [
2885 [
2892 (b'i', b'interactive', None, _(b'use interactive mode')),
2886 (b'i', b'interactive', None, _(b'use interactive mode')),
2893 ]
2887 ]
2894 + walkopts
2888 + walkopts
2895 + dryrunopts,
2889 + dryrunopts,
2896 _(b'[OPTION]... FILE...'),
2890 _(b'[OPTION]... FILE...'),
2897 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2891 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2898 helpbasic=True,
2892 helpbasic=True,
2899 inferrepo=True,
2893 inferrepo=True,
2900 )
2894 )
2901 def forget(ui, repo, *pats, **opts):
2895 def forget(ui, repo, *pats, **opts):
2902 """forget the specified files on the next commit
2896 """forget the specified files on the next commit
2903
2897
2904 Mark the specified files so they will no longer be tracked
2898 Mark the specified files so they will no longer be tracked
2905 after the next commit.
2899 after the next commit.
2906
2900
2907 This only removes files from the current branch, not from the
2901 This only removes files from the current branch, not from the
2908 entire project history, and it does not delete them from the
2902 entire project history, and it does not delete them from the
2909 working directory.
2903 working directory.
2910
2904
2911 To delete the file from the working directory, see :hg:`remove`.
2905 To delete the file from the working directory, see :hg:`remove`.
2912
2906
2913 To undo a forget before the next commit, see :hg:`add`.
2907 To undo a forget before the next commit, see :hg:`add`.
2914
2908
2915 .. container:: verbose
2909 .. container:: verbose
2916
2910
2917 Examples:
2911 Examples:
2918
2912
2919 - forget newly-added binary files::
2913 - forget newly-added binary files::
2920
2914
2921 hg forget "set:added() and binary()"
2915 hg forget "set:added() and binary()"
2922
2916
2923 - forget files that would be excluded by .hgignore::
2917 - forget files that would be excluded by .hgignore::
2924
2918
2925 hg forget "set:hgignore()"
2919 hg forget "set:hgignore()"
2926
2920
2927 Returns 0 on success.
2921 Returns 0 on success.
2928 """
2922 """
2929
2923
2930 opts = pycompat.byteskwargs(opts)
2924 opts = pycompat.byteskwargs(opts)
2931 if not pats:
2925 if not pats:
2932 raise error.InputError(_(b'no files specified'))
2926 raise error.InputError(_(b'no files specified'))
2933
2927
2934 m = scmutil.match(repo[None], pats, opts)
2928 m = scmutil.match(repo[None], pats, opts)
2935 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2929 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2936 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2930 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2937 rejected = cmdutil.forget(
2931 rejected = cmdutil.forget(
2938 ui,
2932 ui,
2939 repo,
2933 repo,
2940 m,
2934 m,
2941 prefix=b"",
2935 prefix=b"",
2942 uipathfn=uipathfn,
2936 uipathfn=uipathfn,
2943 explicitonly=False,
2937 explicitonly=False,
2944 dryrun=dryrun,
2938 dryrun=dryrun,
2945 interactive=interactive,
2939 interactive=interactive,
2946 )[0]
2940 )[0]
2947 return rejected and 1 or 0
2941 return rejected and 1 or 0
2948
2942
2949
2943
2950 @command(
2944 @command(
2951 b'graft',
2945 b'graft',
2952 [
2946 [
2953 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2947 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2954 (
2948 (
2955 b'',
2949 b'',
2956 b'base',
2950 b'base',
2957 b'',
2951 b'',
2958 _(b'base revision when doing the graft merge (ADVANCED)'),
2952 _(b'base revision when doing the graft merge (ADVANCED)'),
2959 _(b'REV'),
2953 _(b'REV'),
2960 ),
2954 ),
2961 (b'c', b'continue', False, _(b'resume interrupted graft')),
2955 (b'c', b'continue', False, _(b'resume interrupted graft')),
2962 (b'', b'stop', False, _(b'stop interrupted graft')),
2956 (b'', b'stop', False, _(b'stop interrupted graft')),
2963 (b'', b'abort', False, _(b'abort interrupted graft')),
2957 (b'', b'abort', False, _(b'abort interrupted graft')),
2964 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2958 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2965 (b'', b'log', None, _(b'append graft info to log message')),
2959 (b'', b'log', None, _(b'append graft info to log message')),
2966 (
2960 (
2967 b'',
2961 b'',
2968 b'no-commit',
2962 b'no-commit',
2969 None,
2963 None,
2970 _(b"don't commit, just apply the changes in working directory"),
2964 _(b"don't commit, just apply the changes in working directory"),
2971 ),
2965 ),
2972 (b'f', b'force', False, _(b'force graft')),
2966 (b'f', b'force', False, _(b'force graft')),
2973 (
2967 (
2974 b'D',
2968 b'D',
2975 b'currentdate',
2969 b'currentdate',
2976 False,
2970 False,
2977 _(b'record the current date as commit date'),
2971 _(b'record the current date as commit date'),
2978 ),
2972 ),
2979 (
2973 (
2980 b'U',
2974 b'U',
2981 b'currentuser',
2975 b'currentuser',
2982 False,
2976 False,
2983 _(b'record the current user as committer'),
2977 _(b'record the current user as committer'),
2984 ),
2978 ),
2985 ]
2979 ]
2986 + commitopts2
2980 + commitopts2
2987 + mergetoolopts
2981 + mergetoolopts
2988 + dryrunopts,
2982 + dryrunopts,
2989 _(b'[OPTION]... [-r REV]... REV...'),
2983 _(b'[OPTION]... [-r REV]... REV...'),
2990 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2984 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2991 )
2985 )
2992 def graft(ui, repo, *revs, **opts):
2986 def graft(ui, repo, *revs, **opts):
2993 """copy changes from other branches onto the current branch
2987 """copy changes from other branches onto the current branch
2994
2988
2995 This command uses Mercurial's merge logic to copy individual
2989 This command uses Mercurial's merge logic to copy individual
2996 changes from other branches without merging branches in the
2990 changes from other branches without merging branches in the
2997 history graph. This is sometimes known as 'backporting' or
2991 history graph. This is sometimes known as 'backporting' or
2998 'cherry-picking'. By default, graft will copy user, date, and
2992 'cherry-picking'. By default, graft will copy user, date, and
2999 description from the source changesets.
2993 description from the source changesets.
3000
2994
3001 Changesets that are ancestors of the current revision, that have
2995 Changesets that are ancestors of the current revision, that have
3002 already been grafted, or that are merges will be skipped.
2996 already been grafted, or that are merges will be skipped.
3003
2997
3004 If --log is specified, log messages will have a comment appended
2998 If --log is specified, log messages will have a comment appended
3005 of the form::
2999 of the form::
3006
3000
3007 (grafted from CHANGESETHASH)
3001 (grafted from CHANGESETHASH)
3008
3002
3009 If --force is specified, revisions will be grafted even if they
3003 If --force is specified, revisions will be grafted even if they
3010 are already ancestors of, or have been grafted to, the destination.
3004 are already ancestors of, or have been grafted to, the destination.
3011 This is useful when the revisions have since been backed out.
3005 This is useful when the revisions have since been backed out.
3012
3006
3013 If a graft merge results in conflicts, the graft process is
3007 If a graft merge results in conflicts, the graft process is
3014 interrupted so that the current merge can be manually resolved.
3008 interrupted so that the current merge can be manually resolved.
3015 Once all conflicts are addressed, the graft process can be
3009 Once all conflicts are addressed, the graft process can be
3016 continued with the -c/--continue option.
3010 continued with the -c/--continue option.
3017
3011
3018 The -c/--continue option reapplies all the earlier options.
3012 The -c/--continue option reapplies all the earlier options.
3019
3013
3020 .. container:: verbose
3014 .. container:: verbose
3021
3015
3022 The --base option exposes more of how graft internally uses merge with a
3016 The --base option exposes more of how graft internally uses merge with a
3023 custom base revision. --base can be used to specify another ancestor than
3017 custom base revision. --base can be used to specify another ancestor than
3024 the first and only parent.
3018 the first and only parent.
3025
3019
3026 The command::
3020 The command::
3027
3021
3028 hg graft -r 345 --base 234
3022 hg graft -r 345 --base 234
3029
3023
3030 is thus pretty much the same as::
3024 is thus pretty much the same as::
3031
3025
3032 hg diff --from 234 --to 345 | hg import
3026 hg diff --from 234 --to 345 | hg import
3033
3027
3034 but using merge to resolve conflicts and track moved files.
3028 but using merge to resolve conflicts and track moved files.
3035
3029
3036 The result of a merge can thus be backported as a single commit by
3030 The result of a merge can thus be backported as a single commit by
3037 specifying one of the merge parents as base, and thus effectively
3031 specifying one of the merge parents as base, and thus effectively
3038 grafting the changes from the other side.
3032 grafting the changes from the other side.
3039
3033
3040 It is also possible to collapse multiple changesets and clean up history
3034 It is also possible to collapse multiple changesets and clean up history
3041 by specifying another ancestor as base, much like rebase --collapse
3035 by specifying another ancestor as base, much like rebase --collapse
3042 --keep.
3036 --keep.
3043
3037
3044 The commit message can be tweaked after the fact using commit --amend .
3038 The commit message can be tweaked after the fact using commit --amend .
3045
3039
3046 For using non-ancestors as the base to backout changes, see the backout
3040 For using non-ancestors as the base to backout changes, see the backout
3047 command and the hidden --parent option.
3041 command and the hidden --parent option.
3048
3042
3049 .. container:: verbose
3043 .. container:: verbose
3050
3044
3051 Examples:
3045 Examples:
3052
3046
3053 - copy a single change to the stable branch and edit its description::
3047 - copy a single change to the stable branch and edit its description::
3054
3048
3055 hg update stable
3049 hg update stable
3056 hg graft --edit 9393
3050 hg graft --edit 9393
3057
3051
3058 - graft a range of changesets with one exception, updating dates::
3052 - graft a range of changesets with one exception, updating dates::
3059
3053
3060 hg graft -D "2085::2093 and not 2091"
3054 hg graft -D "2085::2093 and not 2091"
3061
3055
3062 - continue a graft after resolving conflicts::
3056 - continue a graft after resolving conflicts::
3063
3057
3064 hg graft -c
3058 hg graft -c
3065
3059
3066 - show the source of a grafted changeset::
3060 - show the source of a grafted changeset::
3067
3061
3068 hg log --debug -r .
3062 hg log --debug -r .
3069
3063
3070 - show revisions sorted by date::
3064 - show revisions sorted by date::
3071
3065
3072 hg log -r "sort(all(), date)"
3066 hg log -r "sort(all(), date)"
3073
3067
3074 - backport the result of a merge as a single commit::
3068 - backport the result of a merge as a single commit::
3075
3069
3076 hg graft -r 123 --base 123^
3070 hg graft -r 123 --base 123^
3077
3071
3078 - land a feature branch as one changeset::
3072 - land a feature branch as one changeset::
3079
3073
3080 hg up -cr default
3074 hg up -cr default
3081 hg graft -r featureX --base "ancestor('featureX', 'default')"
3075 hg graft -r featureX --base "ancestor('featureX', 'default')"
3082
3076
3083 See :hg:`help revisions` for more about specifying revisions.
3077 See :hg:`help revisions` for more about specifying revisions.
3084
3078
3085 Returns 0 on successful completion, 1 if there are unresolved files.
3079 Returns 0 on successful completion, 1 if there are unresolved files.
3086 """
3080 """
3087 with repo.wlock():
3081 with repo.wlock():
3088 return _dograft(ui, repo, *revs, **opts)
3082 return _dograft(ui, repo, *revs, **opts)
3089
3083
3090
3084
3091 def _dograft(ui, repo, *revs, **opts):
3085 def _dograft(ui, repo, *revs, **opts):
3092 if revs and opts.get('rev'):
3086 if revs and opts.get('rev'):
3093 ui.warn(
3087 ui.warn(
3094 _(
3088 _(
3095 b'warning: inconsistent use of --rev might give unexpected '
3089 b'warning: inconsistent use of --rev might give unexpected '
3096 b'revision ordering!\n'
3090 b'revision ordering!\n'
3097 )
3091 )
3098 )
3092 )
3099
3093
3100 revs = list(revs)
3094 revs = list(revs)
3101 revs.extend(opts.get('rev'))
3095 revs.extend(opts.get('rev'))
3102 # a dict of data to be stored in state file
3096 # a dict of data to be stored in state file
3103 statedata = {}
3097 statedata = {}
3104 # list of new nodes created by ongoing graft
3098 # list of new nodes created by ongoing graft
3105 statedata[b'newnodes'] = []
3099 statedata[b'newnodes'] = []
3106
3100
3107 cmdutil.resolve_commit_options(ui, opts)
3101 cmdutil.resolve_commit_options(ui, opts)
3108
3102
3109 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3103 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3110
3104
3111 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3105 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3112
3106
3113 cont = False
3107 cont = False
3114 if opts.get('no_commit'):
3108 if opts.get('no_commit'):
3115 cmdutil.check_incompatible_arguments(
3109 cmdutil.check_incompatible_arguments(
3116 opts,
3110 opts,
3117 'no_commit',
3111 'no_commit',
3118 ['edit', 'currentuser', 'currentdate', 'log'],
3112 ['edit', 'currentuser', 'currentdate', 'log'],
3119 )
3113 )
3120
3114
3121 graftstate = statemod.cmdstate(repo, b'graftstate')
3115 graftstate = statemod.cmdstate(repo, b'graftstate')
3122
3116
3123 if opts.get('stop'):
3117 if opts.get('stop'):
3124 cmdutil.check_incompatible_arguments(
3118 cmdutil.check_incompatible_arguments(
3125 opts,
3119 opts,
3126 'stop',
3120 'stop',
3127 [
3121 [
3128 'edit',
3122 'edit',
3129 'log',
3123 'log',
3130 'user',
3124 'user',
3131 'date',
3125 'date',
3132 'currentdate',
3126 'currentdate',
3133 'currentuser',
3127 'currentuser',
3134 'rev',
3128 'rev',
3135 ],
3129 ],
3136 )
3130 )
3137 return _stopgraft(ui, repo, graftstate)
3131 return _stopgraft(ui, repo, graftstate)
3138 elif opts.get('abort'):
3132 elif opts.get('abort'):
3139 cmdutil.check_incompatible_arguments(
3133 cmdutil.check_incompatible_arguments(
3140 opts,
3134 opts,
3141 'abort',
3135 'abort',
3142 [
3136 [
3143 'edit',
3137 'edit',
3144 'log',
3138 'log',
3145 'user',
3139 'user',
3146 'date',
3140 'date',
3147 'currentdate',
3141 'currentdate',
3148 'currentuser',
3142 'currentuser',
3149 'rev',
3143 'rev',
3150 ],
3144 ],
3151 )
3145 )
3152 return cmdutil.abortgraft(ui, repo, graftstate)
3146 return cmdutil.abortgraft(ui, repo, graftstate)
3153 elif opts.get('continue'):
3147 elif opts.get('continue'):
3154 cont = True
3148 cont = True
3155 if revs:
3149 if revs:
3156 raise error.InputError(_(b"can't specify --continue and revisions"))
3150 raise error.InputError(_(b"can't specify --continue and revisions"))
3157 # read in unfinished revisions
3151 # read in unfinished revisions
3158 if graftstate.exists():
3152 if graftstate.exists():
3159 statedata = cmdutil.readgraftstate(repo, graftstate)
3153 statedata = cmdutil.readgraftstate(repo, graftstate)
3160 if statedata.get(b'date'):
3154 if statedata.get(b'date'):
3161 opts['date'] = statedata[b'date']
3155 opts['date'] = statedata[b'date']
3162 if statedata.get(b'user'):
3156 if statedata.get(b'user'):
3163 opts['user'] = statedata[b'user']
3157 opts['user'] = statedata[b'user']
3164 if statedata.get(b'log'):
3158 if statedata.get(b'log'):
3165 opts['log'] = True
3159 opts['log'] = True
3166 if statedata.get(b'no_commit'):
3160 if statedata.get(b'no_commit'):
3167 opts['no_commit'] = statedata.get(b'no_commit')
3161 opts['no_commit'] = statedata.get(b'no_commit')
3168 if statedata.get(b'base'):
3162 if statedata.get(b'base'):
3169 opts['base'] = statedata.get(b'base')
3163 opts['base'] = statedata.get(b'base')
3170 nodes = statedata[b'nodes']
3164 nodes = statedata[b'nodes']
3171 revs = [repo[node].rev() for node in nodes]
3165 revs = [repo[node].rev() for node in nodes]
3172 else:
3166 else:
3173 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3167 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3174 else:
3168 else:
3175 if not revs:
3169 if not revs:
3176 raise error.InputError(_(b'no revisions specified'))
3170 raise error.InputError(_(b'no revisions specified'))
3177 cmdutil.checkunfinished(repo)
3171 cmdutil.checkunfinished(repo)
3178 cmdutil.bailifchanged(repo)
3172 cmdutil.bailifchanged(repo)
3179 revs = scmutil.revrange(repo, revs)
3173 revs = scmutil.revrange(repo, revs)
3180
3174
3181 skipped = set()
3175 skipped = set()
3182 basectx = None
3176 basectx = None
3183 if opts.get('base'):
3177 if opts.get('base'):
3184 basectx = scmutil.revsingle(repo, opts['base'], None)
3178 basectx = scmutil.revsingle(repo, opts['base'], None)
3185 if basectx is None:
3179 if basectx is None:
3186 # check for merges
3180 # check for merges
3187 for rev in repo.revs(b'%ld and merge()', revs):
3181 for rev in repo.revs(b'%ld and merge()', revs):
3188 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3182 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3189 skipped.add(rev)
3183 skipped.add(rev)
3190 revs = [r for r in revs if r not in skipped]
3184 revs = [r for r in revs if r not in skipped]
3191 if not revs:
3185 if not revs:
3192 return -1
3186 return -1
3193 if basectx is not None and len(revs) != 1:
3187 if basectx is not None and len(revs) != 1:
3194 raise error.InputError(_(b'only one revision allowed with --base '))
3188 raise error.InputError(_(b'only one revision allowed with --base '))
3195
3189
3196 # Don't check in the --continue case, in effect retaining --force across
3190 # Don't check in the --continue case, in effect retaining --force across
3197 # --continues. That's because without --force, any revisions we decided to
3191 # --continues. That's because without --force, any revisions we decided to
3198 # skip would have been filtered out here, so they wouldn't have made their
3192 # skip would have been filtered out here, so they wouldn't have made their
3199 # way to the graftstate. With --force, any revisions we would have otherwise
3193 # way to the graftstate. With --force, any revisions we would have otherwise
3200 # skipped would not have been filtered out, and if they hadn't been applied
3194 # skipped would not have been filtered out, and if they hadn't been applied
3201 # already, they'd have been in the graftstate.
3195 # already, they'd have been in the graftstate.
3202 if not (cont or opts.get('force')) and basectx is None:
3196 if not (cont or opts.get('force')) and basectx is None:
3203 # check for ancestors of dest branch
3197 # check for ancestors of dest branch
3204 ancestors = repo.revs(b'%ld & (::.)', revs)
3198 ancestors = repo.revs(b'%ld & (::.)', revs)
3205 for rev in ancestors:
3199 for rev in ancestors:
3206 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3200 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3207
3201
3208 revs = [r for r in revs if r not in ancestors]
3202 revs = [r for r in revs if r not in ancestors]
3209
3203
3210 if not revs:
3204 if not revs:
3211 return -1
3205 return -1
3212
3206
3213 # analyze revs for earlier grafts
3207 # analyze revs for earlier grafts
3214 ids = {}
3208 ids = {}
3215 for ctx in repo.set(b"%ld", revs):
3209 for ctx in repo.set(b"%ld", revs):
3216 ids[ctx.hex()] = ctx.rev()
3210 ids[ctx.hex()] = ctx.rev()
3217 n = ctx.extra().get(b'source')
3211 n = ctx.extra().get(b'source')
3218 if n:
3212 if n:
3219 ids[n] = ctx.rev()
3213 ids[n] = ctx.rev()
3220
3214
3221 # check ancestors for earlier grafts
3215 # check ancestors for earlier grafts
3222 ui.debug(b'scanning for duplicate grafts\n')
3216 ui.debug(b'scanning for duplicate grafts\n')
3223
3217
3224 # The only changesets we can be sure doesn't contain grafts of any
3218 # The only changesets we can be sure doesn't contain grafts of any
3225 # revs, are the ones that are common ancestors of *all* revs:
3219 # revs, are the ones that are common ancestors of *all* revs:
3226 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3220 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3227 ctx = repo[rev]
3221 ctx = repo[rev]
3228 n = ctx.extra().get(b'source')
3222 n = ctx.extra().get(b'source')
3229 if n in ids:
3223 if n in ids:
3230 try:
3224 try:
3231 r = repo[n].rev()
3225 r = repo[n].rev()
3232 except error.RepoLookupError:
3226 except error.RepoLookupError:
3233 r = None
3227 r = None
3234 if r in revs:
3228 if r in revs:
3235 ui.warn(
3229 ui.warn(
3236 _(
3230 _(
3237 b'skipping revision %d:%s '
3231 b'skipping revision %d:%s '
3238 b'(already grafted to %d:%s)\n'
3232 b'(already grafted to %d:%s)\n'
3239 )
3233 )
3240 % (r, repo[r], rev, ctx)
3234 % (r, repo[r], rev, ctx)
3241 )
3235 )
3242 revs.remove(r)
3236 revs.remove(r)
3243 elif ids[n] in revs:
3237 elif ids[n] in revs:
3244 if r is None:
3238 if r is None:
3245 ui.warn(
3239 ui.warn(
3246 _(
3240 _(
3247 b'skipping already grafted revision %d:%s '
3241 b'skipping already grafted revision %d:%s '
3248 b'(%d:%s also has unknown origin %s)\n'
3242 b'(%d:%s also has unknown origin %s)\n'
3249 )
3243 )
3250 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3244 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3251 )
3245 )
3252 else:
3246 else:
3253 ui.warn(
3247 ui.warn(
3254 _(
3248 _(
3255 b'skipping already grafted revision %d:%s '
3249 b'skipping already grafted revision %d:%s '
3256 b'(%d:%s also has origin %d:%s)\n'
3250 b'(%d:%s also has origin %d:%s)\n'
3257 )
3251 )
3258 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3252 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3259 )
3253 )
3260 revs.remove(ids[n])
3254 revs.remove(ids[n])
3261 elif ctx.hex() in ids:
3255 elif ctx.hex() in ids:
3262 r = ids[ctx.hex()]
3256 r = ids[ctx.hex()]
3263 if r in revs:
3257 if r in revs:
3264 ui.warn(
3258 ui.warn(
3265 _(
3259 _(
3266 b'skipping already grafted revision %d:%s '
3260 b'skipping already grafted revision %d:%s '
3267 b'(was grafted from %d:%s)\n'
3261 b'(was grafted from %d:%s)\n'
3268 )
3262 )
3269 % (r, repo[r], rev, ctx)
3263 % (r, repo[r], rev, ctx)
3270 )
3264 )
3271 revs.remove(r)
3265 revs.remove(r)
3272 if not revs:
3266 if not revs:
3273 return -1
3267 return -1
3274
3268
3275 if opts.get('no_commit'):
3269 if opts.get('no_commit'):
3276 statedata[b'no_commit'] = True
3270 statedata[b'no_commit'] = True
3277 if opts.get('base'):
3271 if opts.get('base'):
3278 statedata[b'base'] = opts['base']
3272 statedata[b'base'] = opts['base']
3279 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3273 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3280 desc = b'%d:%s "%s"' % (
3274 desc = b'%d:%s "%s"' % (
3281 ctx.rev(),
3275 ctx.rev(),
3282 ctx,
3276 ctx,
3283 ctx.description().split(b'\n', 1)[0],
3277 ctx.description().split(b'\n', 1)[0],
3284 )
3278 )
3285 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3279 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3286 if names:
3280 if names:
3287 desc += b' (%s)' % b' '.join(names)
3281 desc += b' (%s)' % b' '.join(names)
3288 ui.status(_(b'grafting %s\n') % desc)
3282 ui.status(_(b'grafting %s\n') % desc)
3289 if opts.get('dry_run'):
3283 if opts.get('dry_run'):
3290 continue
3284 continue
3291
3285
3292 source = ctx.extra().get(b'source')
3286 source = ctx.extra().get(b'source')
3293 extra = {}
3287 extra = {}
3294 if source:
3288 if source:
3295 extra[b'source'] = source
3289 extra[b'source'] = source
3296 extra[b'intermediate-source'] = ctx.hex()
3290 extra[b'intermediate-source'] = ctx.hex()
3297 else:
3291 else:
3298 extra[b'source'] = ctx.hex()
3292 extra[b'source'] = ctx.hex()
3299 user = ctx.user()
3293 user = ctx.user()
3300 if opts.get('user'):
3294 if opts.get('user'):
3301 user = opts['user']
3295 user = opts['user']
3302 statedata[b'user'] = user
3296 statedata[b'user'] = user
3303 date = ctx.date()
3297 date = ctx.date()
3304 if opts.get('date'):
3298 if opts.get('date'):
3305 date = opts['date']
3299 date = opts['date']
3306 statedata[b'date'] = date
3300 statedata[b'date'] = date
3307 message = ctx.description()
3301 message = ctx.description()
3308 if opts.get('log'):
3302 if opts.get('log'):
3309 message += b'\n(grafted from %s)' % ctx.hex()
3303 message += b'\n(grafted from %s)' % ctx.hex()
3310 statedata[b'log'] = True
3304 statedata[b'log'] = True
3311
3305
3312 # we don't merge the first commit when continuing
3306 # we don't merge the first commit when continuing
3313 if not cont:
3307 if not cont:
3314 # perform the graft merge with p1(rev) as 'ancestor'
3308 # perform the graft merge with p1(rev) as 'ancestor'
3315 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3309 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3316 base = ctx.p1() if basectx is None else basectx
3310 base = ctx.p1() if basectx is None else basectx
3317 with ui.configoverride(overrides, b'graft'):
3311 with ui.configoverride(overrides, b'graft'):
3318 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3312 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3319 # report any conflicts
3313 # report any conflicts
3320 if stats.unresolvedcount > 0:
3314 if stats.unresolvedcount > 0:
3321 # write out state for --continue
3315 # write out state for --continue
3322 nodes = [repo[rev].hex() for rev in revs[pos:]]
3316 nodes = [repo[rev].hex() for rev in revs[pos:]]
3323 statedata[b'nodes'] = nodes
3317 statedata[b'nodes'] = nodes
3324 stateversion = 1
3318 stateversion = 1
3325 graftstate.save(stateversion, statedata)
3319 graftstate.save(stateversion, statedata)
3326 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3320 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3327 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3321 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3328 return 1
3322 return 1
3329 else:
3323 else:
3330 cont = False
3324 cont = False
3331
3325
3332 # commit if --no-commit is false
3326 # commit if --no-commit is false
3333 if not opts.get('no_commit'):
3327 if not opts.get('no_commit'):
3334 node = repo.commit(
3328 node = repo.commit(
3335 text=message, user=user, date=date, extra=extra, editor=editor
3329 text=message, user=user, date=date, extra=extra, editor=editor
3336 )
3330 )
3337 if node is None:
3331 if node is None:
3338 ui.warn(
3332 ui.warn(
3339 _(b'note: graft of %d:%s created no changes to commit\n')
3333 _(b'note: graft of %d:%s created no changes to commit\n')
3340 % (ctx.rev(), ctx)
3334 % (ctx.rev(), ctx)
3341 )
3335 )
3342 # checking that newnodes exist because old state files won't have it
3336 # checking that newnodes exist because old state files won't have it
3343 elif statedata.get(b'newnodes') is not None:
3337 elif statedata.get(b'newnodes') is not None:
3344 nn = statedata[b'newnodes'] # type: List[bytes]
3338 nn = statedata[b'newnodes']
3339 assert isinstance(nn, list) # list of bytes
3345 nn.append(node)
3340 nn.append(node)
3346
3341
3347 # remove state when we complete successfully
3342 # remove state when we complete successfully
3348 if not opts.get('dry_run'):
3343 if not opts.get('dry_run'):
3349 graftstate.delete()
3344 graftstate.delete()
3350
3345
3351 return 0
3346 return 0
3352
3347
3353
3348
3354 def _stopgraft(ui, repo, graftstate):
3349 def _stopgraft(ui, repo, graftstate):
3355 """stop the interrupted graft"""
3350 """stop the interrupted graft"""
3356 if not graftstate.exists():
3351 if not graftstate.exists():
3357 raise error.StateError(_(b"no interrupted graft found"))
3352 raise error.StateError(_(b"no interrupted graft found"))
3358 pctx = repo[b'.']
3353 pctx = repo[b'.']
3359 mergemod.clean_update(pctx)
3354 mergemod.clean_update(pctx)
3360 graftstate.delete()
3355 graftstate.delete()
3361 ui.status(_(b"stopped the interrupted graft\n"))
3356 ui.status(_(b"stopped the interrupted graft\n"))
3362 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3357 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3363 return 0
3358 return 0
3364
3359
3365
3360
3366 statemod.addunfinished(
3361 statemod.addunfinished(
3367 b'graft',
3362 b'graft',
3368 fname=b'graftstate',
3363 fname=b'graftstate',
3369 clearable=True,
3364 clearable=True,
3370 stopflag=True,
3365 stopflag=True,
3371 continueflag=True,
3366 continueflag=True,
3372 abortfunc=cmdutil.hgabortgraft,
3367 abortfunc=cmdutil.hgabortgraft,
3373 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3368 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3374 )
3369 )
3375
3370
3376
3371
3377 @command(
3372 @command(
3378 b'grep',
3373 b'grep',
3379 [
3374 [
3380 (b'0', b'print0', None, _(b'end fields with NUL')),
3375 (b'0', b'print0', None, _(b'end fields with NUL')),
3381 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3376 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3382 (
3377 (
3383 b'',
3378 b'',
3384 b'diff',
3379 b'diff',
3385 None,
3380 None,
3386 _(
3381 _(
3387 b'search revision differences for when the pattern was added '
3382 b'search revision differences for when the pattern was added '
3388 b'or removed'
3383 b'or removed'
3389 ),
3384 ),
3390 ),
3385 ),
3391 (b'a', b'text', None, _(b'treat all files as text')),
3386 (b'a', b'text', None, _(b'treat all files as text')),
3392 (
3387 (
3393 b'f',
3388 b'f',
3394 b'follow',
3389 b'follow',
3395 None,
3390 None,
3396 _(
3391 _(
3397 b'follow changeset history,'
3392 b'follow changeset history,'
3398 b' or file history across copies and renames'
3393 b' or file history across copies and renames'
3399 ),
3394 ),
3400 ),
3395 ),
3401 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3396 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3402 (
3397 (
3403 b'l',
3398 b'l',
3404 b'files-with-matches',
3399 b'files-with-matches',
3405 None,
3400 None,
3406 _(b'print only filenames and revisions that match'),
3401 _(b'print only filenames and revisions that match'),
3407 ),
3402 ),
3408 (b'n', b'line-number', None, _(b'print matching line numbers')),
3403 (b'n', b'line-number', None, _(b'print matching line numbers')),
3409 (
3404 (
3410 b'r',
3405 b'r',
3411 b'rev',
3406 b'rev',
3412 [],
3407 [],
3413 _(b'search files changed within revision range'),
3408 _(b'search files changed within revision range'),
3414 _(b'REV'),
3409 _(b'REV'),
3415 ),
3410 ),
3416 (
3411 (
3417 b'',
3412 b'',
3418 b'all-files',
3413 b'all-files',
3419 None,
3414 None,
3420 _(
3415 _(
3421 b'include all files in the changeset while grepping (DEPRECATED)'
3416 b'include all files in the changeset while grepping (DEPRECATED)'
3422 ),
3417 ),
3423 ),
3418 ),
3424 (b'u', b'user', None, _(b'list the author (long with -v)')),
3419 (b'u', b'user', None, _(b'list the author (long with -v)')),
3425 (b'd', b'date', None, _(b'list the date (short with -q)')),
3420 (b'd', b'date', None, _(b'list the date (short with -q)')),
3426 ]
3421 ]
3427 + formatteropts
3422 + formatteropts
3428 + walkopts,
3423 + walkopts,
3429 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3424 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3430 helpcategory=command.CATEGORY_FILE_CONTENTS,
3425 helpcategory=command.CATEGORY_FILE_CONTENTS,
3431 inferrepo=True,
3426 inferrepo=True,
3432 intents={INTENT_READONLY},
3427 intents={INTENT_READONLY},
3433 )
3428 )
3434 def grep(ui, repo, pattern, *pats, **opts):
3429 def grep(ui, repo, pattern, *pats, **opts):
3435 """search for a pattern in specified files
3430 """search for a pattern in specified files
3436
3431
3437 Search the working directory or revision history for a regular
3432 Search the working directory or revision history for a regular
3438 expression in the specified files for the entire repository.
3433 expression in the specified files for the entire repository.
3439
3434
3440 By default, grep searches the repository files in the working
3435 By default, grep searches the repository files in the working
3441 directory and prints the files where it finds a match. To specify
3436 directory and prints the files where it finds a match. To specify
3442 historical revisions instead of the working directory, use the
3437 historical revisions instead of the working directory, use the
3443 --rev flag.
3438 --rev flag.
3444
3439
3445 To search instead historical revision differences that contains a
3440 To search instead historical revision differences that contains a
3446 change in match status ("-" for a match that becomes a non-match,
3441 change in match status ("-" for a match that becomes a non-match,
3447 or "+" for a non-match that becomes a match), use the --diff flag.
3442 or "+" for a non-match that becomes a match), use the --diff flag.
3448
3443
3449 PATTERN can be any Python (roughly Perl-compatible) regular
3444 PATTERN can be any Python (roughly Perl-compatible) regular
3450 expression.
3445 expression.
3451
3446
3452 If no FILEs are specified and the --rev flag isn't supplied, all
3447 If no FILEs are specified and the --rev flag isn't supplied, all
3453 files in the working directory are searched. When using the --rev
3448 files in the working directory are searched. When using the --rev
3454 flag and specifying FILEs, use the --follow argument to also
3449 flag and specifying FILEs, use the --follow argument to also
3455 follow the specified FILEs across renames and copies.
3450 follow the specified FILEs across renames and copies.
3456
3451
3457 .. container:: verbose
3452 .. container:: verbose
3458
3453
3459 Template:
3454 Template:
3460
3455
3461 The following keywords are supported in addition to the common template
3456 The following keywords are supported in addition to the common template
3462 keywords and functions. See also :hg:`help templates`.
3457 keywords and functions. See also :hg:`help templates`.
3463
3458
3464 :change: String. Character denoting insertion ``+`` or removal ``-``.
3459 :change: String. Character denoting insertion ``+`` or removal ``-``.
3465 Available if ``--diff`` is specified.
3460 Available if ``--diff`` is specified.
3466 :lineno: Integer. Line number of the match.
3461 :lineno: Integer. Line number of the match.
3467 :path: String. Repository-absolute path of the file.
3462 :path: String. Repository-absolute path of the file.
3468 :texts: List of text chunks.
3463 :texts: List of text chunks.
3469
3464
3470 And each entry of ``{texts}`` provides the following sub-keywords.
3465 And each entry of ``{texts}`` provides the following sub-keywords.
3471
3466
3472 :matched: Boolean. True if the chunk matches the specified pattern.
3467 :matched: Boolean. True if the chunk matches the specified pattern.
3473 :text: String. Chunk content.
3468 :text: String. Chunk content.
3474
3469
3475 See :hg:`help templates.operators` for the list expansion syntax.
3470 See :hg:`help templates.operators` for the list expansion syntax.
3476
3471
3477 Returns 0 if a match is found, 1 otherwise.
3472 Returns 0 if a match is found, 1 otherwise.
3478
3473
3479 """
3474 """
3480 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3475 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3481 opts = pycompat.byteskwargs(opts)
3476 opts = pycompat.byteskwargs(opts)
3482 diff = opts.get(b'all') or opts.get(b'diff')
3477 diff = opts.get(b'all') or opts.get(b'diff')
3483 follow = opts.get(b'follow')
3478 follow = opts.get(b'follow')
3484 if opts.get(b'all_files') is None and not diff:
3479 if opts.get(b'all_files') is None and not diff:
3485 opts[b'all_files'] = True
3480 opts[b'all_files'] = True
3486 plaingrep = (
3481 plaingrep = (
3487 opts.get(b'all_files')
3482 opts.get(b'all_files')
3488 and not opts.get(b'rev')
3483 and not opts.get(b'rev')
3489 and not opts.get(b'follow')
3484 and not opts.get(b'follow')
3490 )
3485 )
3491 all_files = opts.get(b'all_files')
3486 all_files = opts.get(b'all_files')
3492 if plaingrep:
3487 if plaingrep:
3493 opts[b'rev'] = [b'wdir()']
3488 opts[b'rev'] = [b'wdir()']
3494
3489
3495 reflags = re.M
3490 reflags = re.M
3496 if opts.get(b'ignore_case'):
3491 if opts.get(b'ignore_case'):
3497 reflags |= re.I
3492 reflags |= re.I
3498 try:
3493 try:
3499 regexp = util.re.compile(pattern, reflags)
3494 regexp = util.re.compile(pattern, reflags)
3500 except re.error as inst:
3495 except re.error as inst:
3501 ui.warn(
3496 ui.warn(
3502 _(b"grep: invalid match pattern: %s\n")
3497 _(b"grep: invalid match pattern: %s\n")
3503 % stringutil.forcebytestr(inst)
3498 % stringutil.forcebytestr(inst)
3504 )
3499 )
3505 return 1
3500 return 1
3506 sep, eol = b':', b'\n'
3501 sep, eol = b':', b'\n'
3507 if opts.get(b'print0'):
3502 if opts.get(b'print0'):
3508 sep = eol = b'\0'
3503 sep = eol = b'\0'
3509
3504
3510 searcher = grepmod.grepsearcher(
3505 searcher = grepmod.grepsearcher(
3511 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3506 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3512 )
3507 )
3513
3508
3514 getfile = searcher._getfile
3509 getfile = searcher._getfile
3515
3510
3516 uipathfn = scmutil.getuipathfn(repo)
3511 uipathfn = scmutil.getuipathfn(repo)
3517
3512
3518 def display(fm, fn, ctx, pstates, states):
3513 def display(fm, fn, ctx, pstates, states):
3519 rev = scmutil.intrev(ctx)
3514 rev = scmutil.intrev(ctx)
3520 if fm.isplain():
3515 if fm.isplain():
3521 formatuser = ui.shortuser
3516 formatuser = ui.shortuser
3522 else:
3517 else:
3523 formatuser = pycompat.bytestr
3518 formatuser = pycompat.bytestr
3524 if ui.quiet:
3519 if ui.quiet:
3525 datefmt = b'%Y-%m-%d'
3520 datefmt = b'%Y-%m-%d'
3526 else:
3521 else:
3527 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3522 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3528 found = False
3523 found = False
3529
3524
3530 @util.cachefunc
3525 @util.cachefunc
3531 def binary():
3526 def binary():
3532 flog = getfile(fn)
3527 flog = getfile(fn)
3533 try:
3528 try:
3534 return stringutil.binary(flog.read(ctx.filenode(fn)))
3529 return stringutil.binary(flog.read(ctx.filenode(fn)))
3535 except error.WdirUnsupported:
3530 except error.WdirUnsupported:
3536 return ctx[fn].isbinary()
3531 return ctx[fn].isbinary()
3537
3532
3538 fieldnamemap = {b'linenumber': b'lineno'}
3533 fieldnamemap = {b'linenumber': b'lineno'}
3539 if diff:
3534 if diff:
3540 iter = grepmod.difflinestates(pstates, states)
3535 iter = grepmod.difflinestates(pstates, states)
3541 else:
3536 else:
3542 iter = [(b'', l) for l in states]
3537 iter = [(b'', l) for l in states]
3543 for change, l in iter:
3538 for change, l in iter:
3544 fm.startitem()
3539 fm.startitem()
3545 fm.context(ctx=ctx)
3540 fm.context(ctx=ctx)
3546 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3541 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3547 fm.plain(uipathfn(fn), label=b'grep.filename')
3542 fm.plain(uipathfn(fn), label=b'grep.filename')
3548
3543
3549 cols = [
3544 cols = [
3550 (b'rev', b'%d', rev, not plaingrep, b''),
3545 (b'rev', b'%d', rev, not plaingrep, b''),
3551 (
3546 (
3552 b'linenumber',
3547 b'linenumber',
3553 b'%d',
3548 b'%d',
3554 l.linenum,
3549 l.linenum,
3555 opts.get(b'line_number'),
3550 opts.get(b'line_number'),
3556 b'',
3551 b'',
3557 ),
3552 ),
3558 ]
3553 ]
3559 if diff:
3554 if diff:
3560 cols.append(
3555 cols.append(
3561 (
3556 (
3562 b'change',
3557 b'change',
3563 b'%s',
3558 b'%s',
3564 change,
3559 change,
3565 True,
3560 True,
3566 b'grep.inserted '
3561 b'grep.inserted '
3567 if change == b'+'
3562 if change == b'+'
3568 else b'grep.deleted ',
3563 else b'grep.deleted ',
3569 )
3564 )
3570 )
3565 )
3571 cols.extend(
3566 cols.extend(
3572 [
3567 [
3573 (
3568 (
3574 b'user',
3569 b'user',
3575 b'%s',
3570 b'%s',
3576 formatuser(ctx.user()),
3571 formatuser(ctx.user()),
3577 opts.get(b'user'),
3572 opts.get(b'user'),
3578 b'',
3573 b'',
3579 ),
3574 ),
3580 (
3575 (
3581 b'date',
3576 b'date',
3582 b'%s',
3577 b'%s',
3583 fm.formatdate(ctx.date(), datefmt),
3578 fm.formatdate(ctx.date(), datefmt),
3584 opts.get(b'date'),
3579 opts.get(b'date'),
3585 b'',
3580 b'',
3586 ),
3581 ),
3587 ]
3582 ]
3588 )
3583 )
3589 for name, fmt, data, cond, extra_label in cols:
3584 for name, fmt, data, cond, extra_label in cols:
3590 if cond:
3585 if cond:
3591 fm.plain(sep, label=b'grep.sep')
3586 fm.plain(sep, label=b'grep.sep')
3592 field = fieldnamemap.get(name, name)
3587 field = fieldnamemap.get(name, name)
3593 label = extra_label + (b'grep.%s' % name)
3588 label = extra_label + (b'grep.%s' % name)
3594 fm.condwrite(cond, field, fmt, data, label=label)
3589 fm.condwrite(cond, field, fmt, data, label=label)
3595 if not opts.get(b'files_with_matches'):
3590 if not opts.get(b'files_with_matches'):
3596 fm.plain(sep, label=b'grep.sep')
3591 fm.plain(sep, label=b'grep.sep')
3597 if not opts.get(b'text') and binary():
3592 if not opts.get(b'text') and binary():
3598 fm.plain(_(b" Binary file matches"))
3593 fm.plain(_(b" Binary file matches"))
3599 else:
3594 else:
3600 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3595 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3601 fm.plain(eol)
3596 fm.plain(eol)
3602 found = True
3597 found = True
3603 if opts.get(b'files_with_matches'):
3598 if opts.get(b'files_with_matches'):
3604 break
3599 break
3605 return found
3600 return found
3606
3601
3607 def displaymatches(fm, l):
3602 def displaymatches(fm, l):
3608 p = 0
3603 p = 0
3609 for s, e in l.findpos(regexp):
3604 for s, e in l.findpos(regexp):
3610 if p < s:
3605 if p < s:
3611 fm.startitem()
3606 fm.startitem()
3612 fm.write(b'text', b'%s', l.line[p:s])
3607 fm.write(b'text', b'%s', l.line[p:s])
3613 fm.data(matched=False)
3608 fm.data(matched=False)
3614 fm.startitem()
3609 fm.startitem()
3615 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3610 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3616 fm.data(matched=True)
3611 fm.data(matched=True)
3617 p = e
3612 p = e
3618 if p < len(l.line):
3613 if p < len(l.line):
3619 fm.startitem()
3614 fm.startitem()
3620 fm.write(b'text', b'%s', l.line[p:])
3615 fm.write(b'text', b'%s', l.line[p:])
3621 fm.data(matched=False)
3616 fm.data(matched=False)
3622 fm.end()
3617 fm.end()
3623
3618
3624 found = False
3619 found = False
3625
3620
3626 wopts = logcmdutil.walkopts(
3621 wopts = logcmdutil.walkopts(
3627 pats=pats,
3622 pats=pats,
3628 opts=opts,
3623 opts=opts,
3629 revspec=opts[b'rev'],
3624 revspec=opts[b'rev'],
3630 include_pats=opts[b'include'],
3625 include_pats=opts[b'include'],
3631 exclude_pats=opts[b'exclude'],
3626 exclude_pats=opts[b'exclude'],
3632 follow=follow,
3627 follow=follow,
3633 force_changelog_traversal=all_files,
3628 force_changelog_traversal=all_files,
3634 filter_revisions_by_pats=not all_files,
3629 filter_revisions_by_pats=not all_files,
3635 )
3630 )
3636 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3631 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3637
3632
3638 ui.pager(b'grep')
3633 ui.pager(b'grep')
3639 fm = ui.formatter(b'grep', opts)
3634 fm = ui.formatter(b'grep', opts)
3640 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3635 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3641 r = display(fm, fn, ctx, pstates, states)
3636 r = display(fm, fn, ctx, pstates, states)
3642 found = found or r
3637 found = found or r
3643 if r and not diff and not all_files:
3638 if r and not diff and not all_files:
3644 searcher.skipfile(fn, ctx.rev())
3639 searcher.skipfile(fn, ctx.rev())
3645 fm.end()
3640 fm.end()
3646
3641
3647 return not found
3642 return not found
3648
3643
3649
3644
3650 @command(
3645 @command(
3651 b'heads',
3646 b'heads',
3652 [
3647 [
3653 (
3648 (
3654 b'r',
3649 b'r',
3655 b'rev',
3650 b'rev',
3656 b'',
3651 b'',
3657 _(b'show only heads which are descendants of STARTREV'),
3652 _(b'show only heads which are descendants of STARTREV'),
3658 _(b'STARTREV'),
3653 _(b'STARTREV'),
3659 ),
3654 ),
3660 (b't', b'topo', False, _(b'show topological heads only')),
3655 (b't', b'topo', False, _(b'show topological heads only')),
3661 (
3656 (
3662 b'a',
3657 b'a',
3663 b'active',
3658 b'active',
3664 False,
3659 False,
3665 _(b'show active branchheads only (DEPRECATED)'),
3660 _(b'show active branchheads only (DEPRECATED)'),
3666 ),
3661 ),
3667 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3662 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3668 ]
3663 ]
3669 + templateopts,
3664 + templateopts,
3670 _(b'[-ct] [-r STARTREV] [REV]...'),
3665 _(b'[-ct] [-r STARTREV] [REV]...'),
3671 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3666 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3672 intents={INTENT_READONLY},
3667 intents={INTENT_READONLY},
3673 )
3668 )
3674 def heads(ui, repo, *branchrevs, **opts):
3669 def heads(ui, repo, *branchrevs, **opts):
3675 """show branch heads
3670 """show branch heads
3676
3671
3677 With no arguments, show all open branch heads in the repository.
3672 With no arguments, show all open branch heads in the repository.
3678 Branch heads are changesets that have no descendants on the
3673 Branch heads are changesets that have no descendants on the
3679 same branch. They are where development generally takes place and
3674 same branch. They are where development generally takes place and
3680 are the usual targets for update and merge operations.
3675 are the usual targets for update and merge operations.
3681
3676
3682 If one or more REVs are given, only open branch heads on the
3677 If one or more REVs are given, only open branch heads on the
3683 branches associated with the specified changesets are shown. This
3678 branches associated with the specified changesets are shown. This
3684 means that you can use :hg:`heads .` to see the heads on the
3679 means that you can use :hg:`heads .` to see the heads on the
3685 currently checked-out branch.
3680 currently checked-out branch.
3686
3681
3687 If -c/--closed is specified, also show branch heads marked closed
3682 If -c/--closed is specified, also show branch heads marked closed
3688 (see :hg:`commit --close-branch`).
3683 (see :hg:`commit --close-branch`).
3689
3684
3690 If STARTREV is specified, only those heads that are descendants of
3685 If STARTREV is specified, only those heads that are descendants of
3691 STARTREV will be displayed.
3686 STARTREV will be displayed.
3692
3687
3693 If -t/--topo is specified, named branch mechanics will be ignored and only
3688 If -t/--topo is specified, named branch mechanics will be ignored and only
3694 topological heads (changesets with no children) will be shown.
3689 topological heads (changesets with no children) will be shown.
3695
3690
3696 Returns 0 if matching heads are found, 1 if not.
3691 Returns 0 if matching heads are found, 1 if not.
3697 """
3692 """
3698
3693
3699 opts = pycompat.byteskwargs(opts)
3694 opts = pycompat.byteskwargs(opts)
3700 start = None
3695 start = None
3701 rev = opts.get(b'rev')
3696 rev = opts.get(b'rev')
3702 if rev:
3697 if rev:
3703 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3698 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3704 start = scmutil.revsingle(repo, rev, None).node()
3699 start = scmutil.revsingle(repo, rev, None).node()
3705
3700
3706 if opts.get(b'topo'):
3701 if opts.get(b'topo'):
3707 heads = [repo[h] for h in repo.heads(start)]
3702 heads = [repo[h] for h in repo.heads(start)]
3708 else:
3703 else:
3709 heads = []
3704 heads = []
3710 for branch in repo.branchmap():
3705 for branch in repo.branchmap():
3711 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3706 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3712 heads = [repo[h] for h in heads]
3707 heads = [repo[h] for h in heads]
3713
3708
3714 if branchrevs:
3709 if branchrevs:
3715 branches = {
3710 branches = {
3716 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3711 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3717 }
3712 }
3718 heads = [h for h in heads if h.branch() in branches]
3713 heads = [h for h in heads if h.branch() in branches]
3719
3714
3720 if opts.get(b'active') and branchrevs:
3715 if opts.get(b'active') and branchrevs:
3721 dagheads = repo.heads(start)
3716 dagheads = repo.heads(start)
3722 heads = [h for h in heads if h.node() in dagheads]
3717 heads = [h for h in heads if h.node() in dagheads]
3723
3718
3724 if branchrevs:
3719 if branchrevs:
3725 haveheads = {h.branch() for h in heads}
3720 haveheads = {h.branch() for h in heads}
3726 if branches - haveheads:
3721 if branches - haveheads:
3727 headless = b', '.join(b for b in branches - haveheads)
3722 headless = b', '.join(b for b in branches - haveheads)
3728 msg = _(b'no open branch heads found on branches %s')
3723 msg = _(b'no open branch heads found on branches %s')
3729 if opts.get(b'rev'):
3724 if opts.get(b'rev'):
3730 msg += _(b' (started at %s)') % opts[b'rev']
3725 msg += _(b' (started at %s)') % opts[b'rev']
3731 ui.warn((msg + b'\n') % headless)
3726 ui.warn((msg + b'\n') % headless)
3732
3727
3733 if not heads:
3728 if not heads:
3734 return 1
3729 return 1
3735
3730
3736 ui.pager(b'heads')
3731 ui.pager(b'heads')
3737 heads = sorted(heads, key=lambda x: -(x.rev()))
3732 heads = sorted(heads, key=lambda x: -(x.rev()))
3738 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3733 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3739 for ctx in heads:
3734 for ctx in heads:
3740 displayer.show(ctx)
3735 displayer.show(ctx)
3741 displayer.close()
3736 displayer.close()
3742
3737
3743
3738
3744 @command(
3739 @command(
3745 b'help',
3740 b'help',
3746 [
3741 [
3747 (b'e', b'extension', None, _(b'show only help for extensions')),
3742 (b'e', b'extension', None, _(b'show only help for extensions')),
3748 (b'c', b'command', None, _(b'show only help for commands')),
3743 (b'c', b'command', None, _(b'show only help for commands')),
3749 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3744 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3750 (
3745 (
3751 b's',
3746 b's',
3752 b'system',
3747 b'system',
3753 [],
3748 [],
3754 _(b'show help for specific platform(s)'),
3749 _(b'show help for specific platform(s)'),
3755 _(b'PLATFORM'),
3750 _(b'PLATFORM'),
3756 ),
3751 ),
3757 ],
3752 ],
3758 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3753 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3759 helpcategory=command.CATEGORY_HELP,
3754 helpcategory=command.CATEGORY_HELP,
3760 norepo=True,
3755 norepo=True,
3761 intents={INTENT_READONLY},
3756 intents={INTENT_READONLY},
3762 )
3757 )
3763 def help_(ui, name=None, **opts):
3758 def help_(ui, name=None, **opts):
3764 """show help for a given topic or a help overview
3759 """show help for a given topic or a help overview
3765
3760
3766 With no arguments, print a list of commands with short help messages.
3761 With no arguments, print a list of commands with short help messages.
3767
3762
3768 Given a topic, extension, or command name, print help for that
3763 Given a topic, extension, or command name, print help for that
3769 topic.
3764 topic.
3770
3765
3771 Returns 0 if successful.
3766 Returns 0 if successful.
3772 """
3767 """
3773
3768
3774 keep = opts.get('system') or []
3769 keep = opts.get('system') or []
3775 if len(keep) == 0:
3770 if len(keep) == 0:
3776 if pycompat.sysplatform.startswith(b'win'):
3771 if pycompat.sysplatform.startswith(b'win'):
3777 keep.append(b'windows')
3772 keep.append(b'windows')
3778 elif pycompat.sysplatform == b'OpenVMS':
3773 elif pycompat.sysplatform == b'OpenVMS':
3779 keep.append(b'vms')
3774 keep.append(b'vms')
3780 elif pycompat.sysplatform == b'plan9':
3775 elif pycompat.sysplatform == b'plan9':
3781 keep.append(b'plan9')
3776 keep.append(b'plan9')
3782 else:
3777 else:
3783 keep.append(b'unix')
3778 keep.append(b'unix')
3784 keep.append(pycompat.sysplatform.lower())
3779 keep.append(pycompat.sysplatform.lower())
3785 if ui.verbose:
3780 if ui.verbose:
3786 keep.append(b'verbose')
3781 keep.append(b'verbose')
3787
3782
3788 commands = sys.modules[__name__]
3783 commands = sys.modules[__name__]
3789 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3784 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3790 ui.pager(b'help')
3785 ui.pager(b'help')
3791 ui.write(formatted)
3786 ui.write(formatted)
3792
3787
3793
3788
3794 @command(
3789 @command(
3795 b'identify|id',
3790 b'identify|id',
3796 [
3791 [
3797 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3792 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3798 (b'n', b'num', None, _(b'show local revision number')),
3793 (b'n', b'num', None, _(b'show local revision number')),
3799 (b'i', b'id', None, _(b'show global revision id')),
3794 (b'i', b'id', None, _(b'show global revision id')),
3800 (b'b', b'branch', None, _(b'show branch')),
3795 (b'b', b'branch', None, _(b'show branch')),
3801 (b't', b'tags', None, _(b'show tags')),
3796 (b't', b'tags', None, _(b'show tags')),
3802 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3797 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3803 ]
3798 ]
3804 + remoteopts
3799 + remoteopts
3805 + formatteropts,
3800 + formatteropts,
3806 _(b'[-nibtB] [-r REV] [SOURCE]'),
3801 _(b'[-nibtB] [-r REV] [SOURCE]'),
3807 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3802 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3808 optionalrepo=True,
3803 optionalrepo=True,
3809 intents={INTENT_READONLY},
3804 intents={INTENT_READONLY},
3810 )
3805 )
3811 def identify(
3806 def identify(
3812 ui,
3807 ui,
3813 repo,
3808 repo,
3814 source=None,
3809 source=None,
3815 rev=None,
3810 rev=None,
3816 num=None,
3811 num=None,
3817 id=None,
3812 id=None,
3818 branch=None,
3813 branch=None,
3819 tags=None,
3814 tags=None,
3820 bookmarks=None,
3815 bookmarks=None,
3821 **opts
3816 **opts
3822 ):
3817 ):
3823 """identify the working directory or specified revision
3818 """identify the working directory or specified revision
3824
3819
3825 Print a summary identifying the repository state at REV using one or
3820 Print a summary identifying the repository state at REV using one or
3826 two parent hash identifiers, followed by a "+" if the working
3821 two parent hash identifiers, followed by a "+" if the working
3827 directory has uncommitted changes, the branch name (if not default),
3822 directory has uncommitted changes, the branch name (if not default),
3828 a list of tags, and a list of bookmarks.
3823 a list of tags, and a list of bookmarks.
3829
3824
3830 When REV is not given, print a summary of the current state of the
3825 When REV is not given, print a summary of the current state of the
3831 repository including the working directory. Specify -r. to get information
3826 repository including the working directory. Specify -r. to get information
3832 of the working directory parent without scanning uncommitted changes.
3827 of the working directory parent without scanning uncommitted changes.
3833
3828
3834 Specifying a path to a repository root or Mercurial bundle will
3829 Specifying a path to a repository root or Mercurial bundle will
3835 cause lookup to operate on that repository/bundle.
3830 cause lookup to operate on that repository/bundle.
3836
3831
3837 .. container:: verbose
3832 .. container:: verbose
3838
3833
3839 Template:
3834 Template:
3840
3835
3841 The following keywords are supported in addition to the common template
3836 The following keywords are supported in addition to the common template
3842 keywords and functions. See also :hg:`help templates`.
3837 keywords and functions. See also :hg:`help templates`.
3843
3838
3844 :dirty: String. Character ``+`` denoting if the working directory has
3839 :dirty: String. Character ``+`` denoting if the working directory has
3845 uncommitted changes.
3840 uncommitted changes.
3846 :id: String. One or two nodes, optionally followed by ``+``.
3841 :id: String. One or two nodes, optionally followed by ``+``.
3847 :parents: List of strings. Parent nodes of the changeset.
3842 :parents: List of strings. Parent nodes of the changeset.
3848
3843
3849 Examples:
3844 Examples:
3850
3845
3851 - generate a build identifier for the working directory::
3846 - generate a build identifier for the working directory::
3852
3847
3853 hg id --id > build-id.dat
3848 hg id --id > build-id.dat
3854
3849
3855 - find the revision corresponding to a tag::
3850 - find the revision corresponding to a tag::
3856
3851
3857 hg id -n -r 1.3
3852 hg id -n -r 1.3
3858
3853
3859 - check the most recent revision of a remote repository::
3854 - check the most recent revision of a remote repository::
3860
3855
3861 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3856 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3862
3857
3863 See :hg:`log` for generating more information about specific revisions,
3858 See :hg:`log` for generating more information about specific revisions,
3864 including full hash identifiers.
3859 including full hash identifiers.
3865
3860
3866 Returns 0 if successful.
3861 Returns 0 if successful.
3867 """
3862 """
3868
3863
3869 opts = pycompat.byteskwargs(opts)
3864 opts = pycompat.byteskwargs(opts)
3870 if not repo and not source:
3865 if not repo and not source:
3871 raise error.InputError(
3866 raise error.InputError(
3872 _(b"there is no Mercurial repository here (.hg not found)")
3867 _(b"there is no Mercurial repository here (.hg not found)")
3873 )
3868 )
3874
3869
3875 default = not (num or id or branch or tags or bookmarks)
3870 default = not (num or id or branch or tags or bookmarks)
3876 output = []
3871 output = []
3877 revs = []
3872 revs = []
3878
3873
3879 peer = None
3874 peer = None
3880 try:
3875 try:
3881 if source:
3876 if source:
3882 source, branches = urlutil.get_unique_pull_path(
3877 source, branches = urlutil.get_unique_pull_path(
3883 b'identify', repo, ui, source
3878 b'identify', repo, ui, source
3884 )
3879 )
3885 # only pass ui when no repo
3880 # only pass ui when no repo
3886 peer = hg.peer(repo or ui, opts, source)
3881 peer = hg.peer(repo or ui, opts, source)
3887 repo = peer.local()
3882 repo = peer.local()
3888 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3883 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3889
3884
3890 fm = ui.formatter(b'identify', opts)
3885 fm = ui.formatter(b'identify', opts)
3891 fm.startitem()
3886 fm.startitem()
3892
3887
3893 if not repo:
3888 if not repo:
3894 if num or branch or tags:
3889 if num or branch or tags:
3895 raise error.InputError(
3890 raise error.InputError(
3896 _(b"can't query remote revision number, branch, or tags")
3891 _(b"can't query remote revision number, branch, or tags")
3897 )
3892 )
3898 if not rev and revs:
3893 if not rev and revs:
3899 rev = revs[0]
3894 rev = revs[0]
3900 if not rev:
3895 if not rev:
3901 rev = b"tip"
3896 rev = b"tip"
3902
3897
3903 remoterev = peer.lookup(rev)
3898 remoterev = peer.lookup(rev)
3904 hexrev = fm.hexfunc(remoterev)
3899 hexrev = fm.hexfunc(remoterev)
3905 if default or id:
3900 if default or id:
3906 output = [hexrev]
3901 output = [hexrev]
3907 fm.data(id=hexrev)
3902 fm.data(id=hexrev)
3908
3903
3909 @util.cachefunc
3904 @util.cachefunc
3910 def getbms():
3905 def getbms():
3911 bms = []
3906 bms = []
3912
3907
3913 if b'bookmarks' in peer.listkeys(b'namespaces'):
3908 if b'bookmarks' in peer.listkeys(b'namespaces'):
3914 hexremoterev = hex(remoterev)
3909 hexremoterev = hex(remoterev)
3915 bms = [
3910 bms = [
3916 bm
3911 bm
3917 for bm, bmr in pycompat.iteritems(
3912 for bm, bmr in pycompat.iteritems(
3918 peer.listkeys(b'bookmarks')
3913 peer.listkeys(b'bookmarks')
3919 )
3914 )
3920 if bmr == hexremoterev
3915 if bmr == hexremoterev
3921 ]
3916 ]
3922
3917
3923 return sorted(bms)
3918 return sorted(bms)
3924
3919
3925 if fm.isplain():
3920 if fm.isplain():
3926 if bookmarks:
3921 if bookmarks:
3927 output.extend(getbms())
3922 output.extend(getbms())
3928 elif default and not ui.quiet:
3923 elif default and not ui.quiet:
3929 # multiple bookmarks for a single parent separated by '/'
3924 # multiple bookmarks for a single parent separated by '/'
3930 bm = b'/'.join(getbms())
3925 bm = b'/'.join(getbms())
3931 if bm:
3926 if bm:
3932 output.append(bm)
3927 output.append(bm)
3933 else:
3928 else:
3934 fm.data(node=hex(remoterev))
3929 fm.data(node=hex(remoterev))
3935 if bookmarks or b'bookmarks' in fm.datahint():
3930 if bookmarks or b'bookmarks' in fm.datahint():
3936 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3931 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3937 else:
3932 else:
3938 if rev:
3933 if rev:
3939 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3934 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3940 ctx = scmutil.revsingle(repo, rev, None)
3935 ctx = scmutil.revsingle(repo, rev, None)
3941
3936
3942 if ctx.rev() is None:
3937 if ctx.rev() is None:
3943 ctx = repo[None]
3938 ctx = repo[None]
3944 parents = ctx.parents()
3939 parents = ctx.parents()
3945 taglist = []
3940 taglist = []
3946 for p in parents:
3941 for p in parents:
3947 taglist.extend(p.tags())
3942 taglist.extend(p.tags())
3948
3943
3949 dirty = b""
3944 dirty = b""
3950 if ctx.dirty(missing=True, merge=False, branch=False):
3945 if ctx.dirty(missing=True, merge=False, branch=False):
3951 dirty = b'+'
3946 dirty = b'+'
3952 fm.data(dirty=dirty)
3947 fm.data(dirty=dirty)
3953
3948
3954 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3949 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3955 if default or id:
3950 if default or id:
3956 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3951 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3957 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3952 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3958
3953
3959 if num:
3954 if num:
3960 numoutput = [b"%d" % p.rev() for p in parents]
3955 numoutput = [b"%d" % p.rev() for p in parents]
3961 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3956 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3962
3957
3963 fm.data(
3958 fm.data(
3964 parents=fm.formatlist(
3959 parents=fm.formatlist(
3965 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3960 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3966 )
3961 )
3967 )
3962 )
3968 else:
3963 else:
3969 hexoutput = fm.hexfunc(ctx.node())
3964 hexoutput = fm.hexfunc(ctx.node())
3970 if default or id:
3965 if default or id:
3971 output = [hexoutput]
3966 output = [hexoutput]
3972 fm.data(id=hexoutput)
3967 fm.data(id=hexoutput)
3973
3968
3974 if num:
3969 if num:
3975 output.append(pycompat.bytestr(ctx.rev()))
3970 output.append(pycompat.bytestr(ctx.rev()))
3976 taglist = ctx.tags()
3971 taglist = ctx.tags()
3977
3972
3978 if default and not ui.quiet:
3973 if default and not ui.quiet:
3979 b = ctx.branch()
3974 b = ctx.branch()
3980 if b != b'default':
3975 if b != b'default':
3981 output.append(b"(%s)" % b)
3976 output.append(b"(%s)" % b)
3982
3977
3983 # multiple tags for a single parent separated by '/'
3978 # multiple tags for a single parent separated by '/'
3984 t = b'/'.join(taglist)
3979 t = b'/'.join(taglist)
3985 if t:
3980 if t:
3986 output.append(t)
3981 output.append(t)
3987
3982
3988 # multiple bookmarks for a single parent separated by '/'
3983 # multiple bookmarks for a single parent separated by '/'
3989 bm = b'/'.join(ctx.bookmarks())
3984 bm = b'/'.join(ctx.bookmarks())
3990 if bm:
3985 if bm:
3991 output.append(bm)
3986 output.append(bm)
3992 else:
3987 else:
3993 if branch:
3988 if branch:
3994 output.append(ctx.branch())
3989 output.append(ctx.branch())
3995
3990
3996 if tags:
3991 if tags:
3997 output.extend(taglist)
3992 output.extend(taglist)
3998
3993
3999 if bookmarks:
3994 if bookmarks:
4000 output.extend(ctx.bookmarks())
3995 output.extend(ctx.bookmarks())
4001
3996
4002 fm.data(node=ctx.hex())
3997 fm.data(node=ctx.hex())
4003 fm.data(branch=ctx.branch())
3998 fm.data(branch=ctx.branch())
4004 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3999 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4005 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4000 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4006 fm.context(ctx=ctx)
4001 fm.context(ctx=ctx)
4007
4002
4008 fm.plain(b"%s\n" % b' '.join(output))
4003 fm.plain(b"%s\n" % b' '.join(output))
4009 fm.end()
4004 fm.end()
4010 finally:
4005 finally:
4011 if peer:
4006 if peer:
4012 peer.close()
4007 peer.close()
4013
4008
4014
4009
4015 @command(
4010 @command(
4016 b'import|patch',
4011 b'import|patch',
4017 [
4012 [
4018 (
4013 (
4019 b'p',
4014 b'p',
4020 b'strip',
4015 b'strip',
4021 1,
4016 1,
4022 _(
4017 _(
4023 b'directory strip option for patch. This has the same '
4018 b'directory strip option for patch. This has the same '
4024 b'meaning as the corresponding patch option'
4019 b'meaning as the corresponding patch option'
4025 ),
4020 ),
4026 _(b'NUM'),
4021 _(b'NUM'),
4027 ),
4022 ),
4028 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4023 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4029 (b'', b'secret', None, _(b'use the secret phase for committing')),
4024 (b'', b'secret', None, _(b'use the secret phase for committing')),
4030 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4025 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4031 (
4026 (
4032 b'f',
4027 b'f',
4033 b'force',
4028 b'force',
4034 None,
4029 None,
4035 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4030 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4036 ),
4031 ),
4037 (
4032 (
4038 b'',
4033 b'',
4039 b'no-commit',
4034 b'no-commit',
4040 None,
4035 None,
4041 _(b"don't commit, just update the working directory"),
4036 _(b"don't commit, just update the working directory"),
4042 ),
4037 ),
4043 (
4038 (
4044 b'',
4039 b'',
4045 b'bypass',
4040 b'bypass',
4046 None,
4041 None,
4047 _(b"apply patch without touching the working directory"),
4042 _(b"apply patch without touching the working directory"),
4048 ),
4043 ),
4049 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4044 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4050 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4045 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4051 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4046 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4052 (
4047 (
4053 b'',
4048 b'',
4054 b'import-branch',
4049 b'import-branch',
4055 None,
4050 None,
4056 _(b'use any branch information in patch (implied by --exact)'),
4051 _(b'use any branch information in patch (implied by --exact)'),
4057 ),
4052 ),
4058 ]
4053 ]
4059 + commitopts
4054 + commitopts
4060 + commitopts2
4055 + commitopts2
4061 + similarityopts,
4056 + similarityopts,
4062 _(b'[OPTION]... PATCH...'),
4057 _(b'[OPTION]... PATCH...'),
4063 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4058 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4064 )
4059 )
4065 def import_(ui, repo, patch1=None, *patches, **opts):
4060 def import_(ui, repo, patch1=None, *patches, **opts):
4066 """import an ordered set of patches
4061 """import an ordered set of patches
4067
4062
4068 Import a list of patches and commit them individually (unless
4063 Import a list of patches and commit them individually (unless
4069 --no-commit is specified).
4064 --no-commit is specified).
4070
4065
4071 To read a patch from standard input (stdin), use "-" as the patch
4066 To read a patch from standard input (stdin), use "-" as the patch
4072 name. If a URL is specified, the patch will be downloaded from
4067 name. If a URL is specified, the patch will be downloaded from
4073 there.
4068 there.
4074
4069
4075 Import first applies changes to the working directory (unless
4070 Import first applies changes to the working directory (unless
4076 --bypass is specified), import will abort if there are outstanding
4071 --bypass is specified), import will abort if there are outstanding
4077 changes.
4072 changes.
4078
4073
4079 Use --bypass to apply and commit patches directly to the
4074 Use --bypass to apply and commit patches directly to the
4080 repository, without affecting the working directory. Without
4075 repository, without affecting the working directory. Without
4081 --exact, patches will be applied on top of the working directory
4076 --exact, patches will be applied on top of the working directory
4082 parent revision.
4077 parent revision.
4083
4078
4084 You can import a patch straight from a mail message. Even patches
4079 You can import a patch straight from a mail message. Even patches
4085 as attachments work (to use the body part, it must have type
4080 as attachments work (to use the body part, it must have type
4086 text/plain or text/x-patch). From and Subject headers of email
4081 text/plain or text/x-patch). From and Subject headers of email
4087 message are used as default committer and commit message. All
4082 message are used as default committer and commit message. All
4088 text/plain body parts before first diff are added to the commit
4083 text/plain body parts before first diff are added to the commit
4089 message.
4084 message.
4090
4085
4091 If the imported patch was generated by :hg:`export`, user and
4086 If the imported patch was generated by :hg:`export`, user and
4092 description from patch override values from message headers and
4087 description from patch override values from message headers and
4093 body. Values given on command line with -m/--message and -u/--user
4088 body. Values given on command line with -m/--message and -u/--user
4094 override these.
4089 override these.
4095
4090
4096 If --exact is specified, import will set the working directory to
4091 If --exact is specified, import will set the working directory to
4097 the parent of each patch before applying it, and will abort if the
4092 the parent of each patch before applying it, and will abort if the
4098 resulting changeset has a different ID than the one recorded in
4093 resulting changeset has a different ID than the one recorded in
4099 the patch. This will guard against various ways that portable
4094 the patch. This will guard against various ways that portable
4100 patch formats and mail systems might fail to transfer Mercurial
4095 patch formats and mail systems might fail to transfer Mercurial
4101 data or metadata. See :hg:`bundle` for lossless transmission.
4096 data or metadata. See :hg:`bundle` for lossless transmission.
4102
4097
4103 Use --partial to ensure a changeset will be created from the patch
4098 Use --partial to ensure a changeset will be created from the patch
4104 even if some hunks fail to apply. Hunks that fail to apply will be
4099 even if some hunks fail to apply. Hunks that fail to apply will be
4105 written to a <target-file>.rej file. Conflicts can then be resolved
4100 written to a <target-file>.rej file. Conflicts can then be resolved
4106 by hand before :hg:`commit --amend` is run to update the created
4101 by hand before :hg:`commit --amend` is run to update the created
4107 changeset. This flag exists to let people import patches that
4102 changeset. This flag exists to let people import patches that
4108 partially apply without losing the associated metadata (author,
4103 partially apply without losing the associated metadata (author,
4109 date, description, ...).
4104 date, description, ...).
4110
4105
4111 .. note::
4106 .. note::
4112
4107
4113 When no hunks apply cleanly, :hg:`import --partial` will create
4108 When no hunks apply cleanly, :hg:`import --partial` will create
4114 an empty changeset, importing only the patch metadata.
4109 an empty changeset, importing only the patch metadata.
4115
4110
4116 With -s/--similarity, hg will attempt to discover renames and
4111 With -s/--similarity, hg will attempt to discover renames and
4117 copies in the patch in the same way as :hg:`addremove`.
4112 copies in the patch in the same way as :hg:`addremove`.
4118
4113
4119 It is possible to use external patch programs to perform the patch
4114 It is possible to use external patch programs to perform the patch
4120 by setting the ``ui.patch`` configuration option. For the default
4115 by setting the ``ui.patch`` configuration option. For the default
4121 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4116 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4122 See :hg:`help config` for more information about configuration
4117 See :hg:`help config` for more information about configuration
4123 files and how to use these options.
4118 files and how to use these options.
4124
4119
4125 See :hg:`help dates` for a list of formats valid for -d/--date.
4120 See :hg:`help dates` for a list of formats valid for -d/--date.
4126
4121
4127 .. container:: verbose
4122 .. container:: verbose
4128
4123
4129 Examples:
4124 Examples:
4130
4125
4131 - import a traditional patch from a website and detect renames::
4126 - import a traditional patch from a website and detect renames::
4132
4127
4133 hg import -s 80 http://example.com/bugfix.patch
4128 hg import -s 80 http://example.com/bugfix.patch
4134
4129
4135 - import a changeset from an hgweb server::
4130 - import a changeset from an hgweb server::
4136
4131
4137 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4132 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4138
4133
4139 - import all the patches in an Unix-style mbox::
4134 - import all the patches in an Unix-style mbox::
4140
4135
4141 hg import incoming-patches.mbox
4136 hg import incoming-patches.mbox
4142
4137
4143 - import patches from stdin::
4138 - import patches from stdin::
4144
4139
4145 hg import -
4140 hg import -
4146
4141
4147 - attempt to exactly restore an exported changeset (not always
4142 - attempt to exactly restore an exported changeset (not always
4148 possible)::
4143 possible)::
4149
4144
4150 hg import --exact proposed-fix.patch
4145 hg import --exact proposed-fix.patch
4151
4146
4152 - use an external tool to apply a patch which is too fuzzy for
4147 - use an external tool to apply a patch which is too fuzzy for
4153 the default internal tool.
4148 the default internal tool.
4154
4149
4155 hg import --config ui.patch="patch --merge" fuzzy.patch
4150 hg import --config ui.patch="patch --merge" fuzzy.patch
4156
4151
4157 - change the default fuzzing from 2 to a less strict 7
4152 - change the default fuzzing from 2 to a less strict 7
4158
4153
4159 hg import --config ui.fuzz=7 fuzz.patch
4154 hg import --config ui.fuzz=7 fuzz.patch
4160
4155
4161 Returns 0 on success, 1 on partial success (see --partial).
4156 Returns 0 on success, 1 on partial success (see --partial).
4162 """
4157 """
4163
4158
4164 cmdutil.check_incompatible_arguments(
4159 cmdutil.check_incompatible_arguments(
4165 opts, 'no_commit', ['bypass', 'secret']
4160 opts, 'no_commit', ['bypass', 'secret']
4166 )
4161 )
4167 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4162 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4168 opts = pycompat.byteskwargs(opts)
4163 opts = pycompat.byteskwargs(opts)
4169 if not patch1:
4164 if not patch1:
4170 raise error.InputError(_(b'need at least one patch to import'))
4165 raise error.InputError(_(b'need at least one patch to import'))
4171
4166
4172 patches = (patch1,) + patches
4167 patches = (patch1,) + patches
4173
4168
4174 date = opts.get(b'date')
4169 date = opts.get(b'date')
4175 if date:
4170 if date:
4176 opts[b'date'] = dateutil.parsedate(date)
4171 opts[b'date'] = dateutil.parsedate(date)
4177
4172
4178 exact = opts.get(b'exact')
4173 exact = opts.get(b'exact')
4179 update = not opts.get(b'bypass')
4174 update = not opts.get(b'bypass')
4180 try:
4175 try:
4181 sim = float(opts.get(b'similarity') or 0)
4176 sim = float(opts.get(b'similarity') or 0)
4182 except ValueError:
4177 except ValueError:
4183 raise error.InputError(_(b'similarity must be a number'))
4178 raise error.InputError(_(b'similarity must be a number'))
4184 if sim < 0 or sim > 100:
4179 if sim < 0 or sim > 100:
4185 raise error.InputError(_(b'similarity must be between 0 and 100'))
4180 raise error.InputError(_(b'similarity must be between 0 and 100'))
4186 if sim and not update:
4181 if sim and not update:
4187 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4182 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4188
4183
4189 base = opts[b"base"]
4184 base = opts[b"base"]
4190 msgs = []
4185 msgs = []
4191 ret = 0
4186 ret = 0
4192
4187
4193 with repo.wlock():
4188 with repo.wlock():
4194 if update:
4189 if update:
4195 cmdutil.checkunfinished(repo)
4190 cmdutil.checkunfinished(repo)
4196 if exact or not opts.get(b'force'):
4191 if exact or not opts.get(b'force'):
4197 cmdutil.bailifchanged(repo)
4192 cmdutil.bailifchanged(repo)
4198
4193
4199 if not opts.get(b'no_commit'):
4194 if not opts.get(b'no_commit'):
4200 lock = repo.lock
4195 lock = repo.lock
4201 tr = lambda: repo.transaction(b'import')
4196 tr = lambda: repo.transaction(b'import')
4202 dsguard = util.nullcontextmanager
4197 dsguard = util.nullcontextmanager
4203 else:
4198 else:
4204 lock = util.nullcontextmanager
4199 lock = util.nullcontextmanager
4205 tr = util.nullcontextmanager
4200 tr = util.nullcontextmanager
4206 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4201 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4207 with lock(), tr(), dsguard():
4202 with lock(), tr(), dsguard():
4208 parents = repo[None].parents()
4203 parents = repo[None].parents()
4209 for patchurl in patches:
4204 for patchurl in patches:
4210 if patchurl == b'-':
4205 if patchurl == b'-':
4211 ui.status(_(b'applying patch from stdin\n'))
4206 ui.status(_(b'applying patch from stdin\n'))
4212 patchfile = ui.fin
4207 patchfile = ui.fin
4213 patchurl = b'stdin' # for error message
4208 patchurl = b'stdin' # for error message
4214 else:
4209 else:
4215 patchurl = os.path.join(base, patchurl)
4210 patchurl = os.path.join(base, patchurl)
4216 ui.status(_(b'applying %s\n') % patchurl)
4211 ui.status(_(b'applying %s\n') % patchurl)
4217 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4212 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4218
4213
4219 haspatch = False
4214 haspatch = False
4220 for hunk in patch.split(patchfile):
4215 for hunk in patch.split(patchfile):
4221 with patch.extract(ui, hunk) as patchdata:
4216 with patch.extract(ui, hunk) as patchdata:
4222 msg, node, rej = cmdutil.tryimportone(
4217 msg, node, rej = cmdutil.tryimportone(
4223 ui, repo, patchdata, parents, opts, msgs, hg.clean
4218 ui, repo, patchdata, parents, opts, msgs, hg.clean
4224 )
4219 )
4225 if msg:
4220 if msg:
4226 haspatch = True
4221 haspatch = True
4227 ui.note(msg + b'\n')
4222 ui.note(msg + b'\n')
4228 if update or exact:
4223 if update or exact:
4229 parents = repo[None].parents()
4224 parents = repo[None].parents()
4230 else:
4225 else:
4231 parents = [repo[node]]
4226 parents = [repo[node]]
4232 if rej:
4227 if rej:
4233 ui.write_err(_(b"patch applied partially\n"))
4228 ui.write_err(_(b"patch applied partially\n"))
4234 ui.write_err(
4229 ui.write_err(
4235 _(
4230 _(
4236 b"(fix the .rej files and run "
4231 b"(fix the .rej files and run "
4237 b"`hg commit --amend`)\n"
4232 b"`hg commit --amend`)\n"
4238 )
4233 )
4239 )
4234 )
4240 ret = 1
4235 ret = 1
4241 break
4236 break
4242
4237
4243 if not haspatch:
4238 if not haspatch:
4244 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4239 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4245
4240
4246 if msgs:
4241 if msgs:
4247 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4242 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4248 return ret
4243 return ret
4249
4244
4250
4245
4251 @command(
4246 @command(
4252 b'incoming|in',
4247 b'incoming|in',
4253 [
4248 [
4254 (
4249 (
4255 b'f',
4250 b'f',
4256 b'force',
4251 b'force',
4257 None,
4252 None,
4258 _(b'run even if remote repository is unrelated'),
4253 _(b'run even if remote repository is unrelated'),
4259 ),
4254 ),
4260 (b'n', b'newest-first', None, _(b'show newest record first')),
4255 (b'n', b'newest-first', None, _(b'show newest record first')),
4261 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4256 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4262 (
4257 (
4263 b'r',
4258 b'r',
4264 b'rev',
4259 b'rev',
4265 [],
4260 [],
4266 _(b'a remote changeset intended to be added'),
4261 _(b'a remote changeset intended to be added'),
4267 _(b'REV'),
4262 _(b'REV'),
4268 ),
4263 ),
4269 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4264 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4270 (
4265 (
4271 b'b',
4266 b'b',
4272 b'branch',
4267 b'branch',
4273 [],
4268 [],
4274 _(b'a specific branch you would like to pull'),
4269 _(b'a specific branch you would like to pull'),
4275 _(b'BRANCH'),
4270 _(b'BRANCH'),
4276 ),
4271 ),
4277 ]
4272 ]
4278 + logopts
4273 + logopts
4279 + remoteopts
4274 + remoteopts
4280 + subrepoopts,
4275 + subrepoopts,
4281 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4276 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4282 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4277 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4283 )
4278 )
4284 def incoming(ui, repo, source=b"default", **opts):
4279 def incoming(ui, repo, source=b"default", **opts):
4285 """show new changesets found in source
4280 """show new changesets found in source
4286
4281
4287 Show new changesets found in the specified path/URL or the default
4282 Show new changesets found in the specified path/URL or the default
4288 pull location. These are the changesets that would have been pulled
4283 pull location. These are the changesets that would have been pulled
4289 by :hg:`pull` at the time you issued this command.
4284 by :hg:`pull` at the time you issued this command.
4290
4285
4291 See pull for valid source format details.
4286 See pull for valid source format details.
4292
4287
4293 .. container:: verbose
4288 .. container:: verbose
4294
4289
4295 With -B/--bookmarks, the result of bookmark comparison between
4290 With -B/--bookmarks, the result of bookmark comparison between
4296 local and remote repositories is displayed. With -v/--verbose,
4291 local and remote repositories is displayed. With -v/--verbose,
4297 status is also displayed for each bookmark like below::
4292 status is also displayed for each bookmark like below::
4298
4293
4299 BM1 01234567890a added
4294 BM1 01234567890a added
4300 BM2 1234567890ab advanced
4295 BM2 1234567890ab advanced
4301 BM3 234567890abc diverged
4296 BM3 234567890abc diverged
4302 BM4 34567890abcd changed
4297 BM4 34567890abcd changed
4303
4298
4304 The action taken locally when pulling depends on the
4299 The action taken locally when pulling depends on the
4305 status of each bookmark:
4300 status of each bookmark:
4306
4301
4307 :``added``: pull will create it
4302 :``added``: pull will create it
4308 :``advanced``: pull will update it
4303 :``advanced``: pull will update it
4309 :``diverged``: pull will create a divergent bookmark
4304 :``diverged``: pull will create a divergent bookmark
4310 :``changed``: result depends on remote changesets
4305 :``changed``: result depends on remote changesets
4311
4306
4312 From the point of view of pulling behavior, bookmark
4307 From the point of view of pulling behavior, bookmark
4313 existing only in the remote repository are treated as ``added``,
4308 existing only in the remote repository are treated as ``added``,
4314 even if it is in fact locally deleted.
4309 even if it is in fact locally deleted.
4315
4310
4316 .. container:: verbose
4311 .. container:: verbose
4317
4312
4318 For remote repository, using --bundle avoids downloading the
4313 For remote repository, using --bundle avoids downloading the
4319 changesets twice if the incoming is followed by a pull.
4314 changesets twice if the incoming is followed by a pull.
4320
4315
4321 Examples:
4316 Examples:
4322
4317
4323 - show incoming changes with patches and full description::
4318 - show incoming changes with patches and full description::
4324
4319
4325 hg incoming -vp
4320 hg incoming -vp
4326
4321
4327 - show incoming changes excluding merges, store a bundle::
4322 - show incoming changes excluding merges, store a bundle::
4328
4323
4329 hg in -vpM --bundle incoming.hg
4324 hg in -vpM --bundle incoming.hg
4330 hg pull incoming.hg
4325 hg pull incoming.hg
4331
4326
4332 - briefly list changes inside a bundle::
4327 - briefly list changes inside a bundle::
4333
4328
4334 hg in changes.hg -T "{desc|firstline}\\n"
4329 hg in changes.hg -T "{desc|firstline}\\n"
4335
4330
4336 Returns 0 if there are incoming changes, 1 otherwise.
4331 Returns 0 if there are incoming changes, 1 otherwise.
4337 """
4332 """
4338 opts = pycompat.byteskwargs(opts)
4333 opts = pycompat.byteskwargs(opts)
4339 if opts.get(b'graph'):
4334 if opts.get(b'graph'):
4340 logcmdutil.checkunsupportedgraphflags([], opts)
4335 logcmdutil.checkunsupportedgraphflags([], opts)
4341
4336
4342 def display(other, chlist, displayer):
4337 def display(other, chlist, displayer):
4343 revdag = logcmdutil.graphrevs(other, chlist, opts)
4338 revdag = logcmdutil.graphrevs(other, chlist, opts)
4344 logcmdutil.displaygraph(
4339 logcmdutil.displaygraph(
4345 ui, repo, revdag, displayer, graphmod.asciiedges
4340 ui, repo, revdag, displayer, graphmod.asciiedges
4346 )
4341 )
4347
4342
4348 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4343 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4349 return 0
4344 return 0
4350
4345
4351 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4346 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4352
4347
4353 if opts.get(b'bookmarks'):
4348 if opts.get(b'bookmarks'):
4354 srcs = urlutil.get_pull_paths(repo, ui, [source], opts.get(b'branch'))
4349 srcs = urlutil.get_pull_paths(repo, ui, [source], opts.get(b'branch'))
4355 for source, branches in srcs:
4350 for source, branches in srcs:
4356 other = hg.peer(repo, opts, source)
4351 other = hg.peer(repo, opts, source)
4357 try:
4352 try:
4358 if b'bookmarks' not in other.listkeys(b'namespaces'):
4353 if b'bookmarks' not in other.listkeys(b'namespaces'):
4359 ui.warn(_(b"remote doesn't support bookmarks\n"))
4354 ui.warn(_(b"remote doesn't support bookmarks\n"))
4360 return 0
4355 return 0
4361 ui.pager(b'incoming')
4356 ui.pager(b'incoming')
4362 ui.status(
4357 ui.status(
4363 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4358 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4364 )
4359 )
4365 return bookmarks.incoming(ui, repo, other)
4360 return bookmarks.incoming(ui, repo, other)
4366 finally:
4361 finally:
4367 other.close()
4362 other.close()
4368
4363
4369 return hg.incoming(ui, repo, source, opts)
4364 return hg.incoming(ui, repo, source, opts)
4370
4365
4371
4366
4372 @command(
4367 @command(
4373 b'init',
4368 b'init',
4374 remoteopts,
4369 remoteopts,
4375 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4370 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4376 helpcategory=command.CATEGORY_REPO_CREATION,
4371 helpcategory=command.CATEGORY_REPO_CREATION,
4377 helpbasic=True,
4372 helpbasic=True,
4378 norepo=True,
4373 norepo=True,
4379 )
4374 )
4380 def init(ui, dest=b".", **opts):
4375 def init(ui, dest=b".", **opts):
4381 """create a new repository in the given directory
4376 """create a new repository in the given directory
4382
4377
4383 Initialize a new repository in the given directory. If the given
4378 Initialize a new repository in the given directory. If the given
4384 directory does not exist, it will be created.
4379 directory does not exist, it will be created.
4385
4380
4386 If no directory is given, the current directory is used.
4381 If no directory is given, the current directory is used.
4387
4382
4388 It is possible to specify an ``ssh://`` URL as the destination.
4383 It is possible to specify an ``ssh://`` URL as the destination.
4389 See :hg:`help urls` for more information.
4384 See :hg:`help urls` for more information.
4390
4385
4391 Returns 0 on success.
4386 Returns 0 on success.
4392 """
4387 """
4393 opts = pycompat.byteskwargs(opts)
4388 opts = pycompat.byteskwargs(opts)
4394 path = urlutil.get_clone_path(ui, dest)[1]
4389 path = urlutil.get_clone_path(ui, dest)[1]
4395 peer = hg.peer(ui, opts, path, create=True)
4390 peer = hg.peer(ui, opts, path, create=True)
4396 peer.close()
4391 peer.close()
4397
4392
4398
4393
4399 @command(
4394 @command(
4400 b'locate',
4395 b'locate',
4401 [
4396 [
4402 (
4397 (
4403 b'r',
4398 b'r',
4404 b'rev',
4399 b'rev',
4405 b'',
4400 b'',
4406 _(b'search the repository as it is in REV'),
4401 _(b'search the repository as it is in REV'),
4407 _(b'REV'),
4402 _(b'REV'),
4408 ),
4403 ),
4409 (
4404 (
4410 b'0',
4405 b'0',
4411 b'print0',
4406 b'print0',
4412 None,
4407 None,
4413 _(b'end filenames with NUL, for use with xargs'),
4408 _(b'end filenames with NUL, for use with xargs'),
4414 ),
4409 ),
4415 (
4410 (
4416 b'f',
4411 b'f',
4417 b'fullpath',
4412 b'fullpath',
4418 None,
4413 None,
4419 _(b'print complete paths from the filesystem root'),
4414 _(b'print complete paths from the filesystem root'),
4420 ),
4415 ),
4421 ]
4416 ]
4422 + walkopts,
4417 + walkopts,
4423 _(b'[OPTION]... [PATTERN]...'),
4418 _(b'[OPTION]... [PATTERN]...'),
4424 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4419 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4425 )
4420 )
4426 def locate(ui, repo, *pats, **opts):
4421 def locate(ui, repo, *pats, **opts):
4427 """locate files matching specific patterns (DEPRECATED)
4422 """locate files matching specific patterns (DEPRECATED)
4428
4423
4429 Print files under Mercurial control in the working directory whose
4424 Print files under Mercurial control in the working directory whose
4430 names match the given patterns.
4425 names match the given patterns.
4431
4426
4432 By default, this command searches all directories in the working
4427 By default, this command searches all directories in the working
4433 directory. To search just the current directory and its
4428 directory. To search just the current directory and its
4434 subdirectories, use "--include .".
4429 subdirectories, use "--include .".
4435
4430
4436 If no patterns are given to match, this command prints the names
4431 If no patterns are given to match, this command prints the names
4437 of all files under Mercurial control in the working directory.
4432 of all files under Mercurial control in the working directory.
4438
4433
4439 If you want to feed the output of this command into the "xargs"
4434 If you want to feed the output of this command into the "xargs"
4440 command, use the -0 option to both this command and "xargs". This
4435 command, use the -0 option to both this command and "xargs". This
4441 will avoid the problem of "xargs" treating single filenames that
4436 will avoid the problem of "xargs" treating single filenames that
4442 contain whitespace as multiple filenames.
4437 contain whitespace as multiple filenames.
4443
4438
4444 See :hg:`help files` for a more versatile command.
4439 See :hg:`help files` for a more versatile command.
4445
4440
4446 Returns 0 if a match is found, 1 otherwise.
4441 Returns 0 if a match is found, 1 otherwise.
4447 """
4442 """
4448 opts = pycompat.byteskwargs(opts)
4443 opts = pycompat.byteskwargs(opts)
4449 if opts.get(b'print0'):
4444 if opts.get(b'print0'):
4450 end = b'\0'
4445 end = b'\0'
4451 else:
4446 else:
4452 end = b'\n'
4447 end = b'\n'
4453 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4448 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4454
4449
4455 ret = 1
4450 ret = 1
4456 m = scmutil.match(
4451 m = scmutil.match(
4457 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4452 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4458 )
4453 )
4459
4454
4460 ui.pager(b'locate')
4455 ui.pager(b'locate')
4461 if ctx.rev() is None:
4456 if ctx.rev() is None:
4462 # When run on the working copy, "locate" includes removed files, so
4457 # When run on the working copy, "locate" includes removed files, so
4463 # we get the list of files from the dirstate.
4458 # we get the list of files from the dirstate.
4464 filesgen = sorted(repo.dirstate.matches(m))
4459 filesgen = sorted(repo.dirstate.matches(m))
4465 else:
4460 else:
4466 filesgen = ctx.matches(m)
4461 filesgen = ctx.matches(m)
4467 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4462 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4468 for abs in filesgen:
4463 for abs in filesgen:
4469 if opts.get(b'fullpath'):
4464 if opts.get(b'fullpath'):
4470 ui.write(repo.wjoin(abs), end)
4465 ui.write(repo.wjoin(abs), end)
4471 else:
4466 else:
4472 ui.write(uipathfn(abs), end)
4467 ui.write(uipathfn(abs), end)
4473 ret = 0
4468 ret = 0
4474
4469
4475 return ret
4470 return ret
4476
4471
4477
4472
4478 @command(
4473 @command(
4479 b'log|history',
4474 b'log|history',
4480 [
4475 [
4481 (
4476 (
4482 b'f',
4477 b'f',
4483 b'follow',
4478 b'follow',
4484 None,
4479 None,
4485 _(
4480 _(
4486 b'follow changeset history, or file history across copies and renames'
4481 b'follow changeset history, or file history across copies and renames'
4487 ),
4482 ),
4488 ),
4483 ),
4489 (
4484 (
4490 b'',
4485 b'',
4491 b'follow-first',
4486 b'follow-first',
4492 None,
4487 None,
4493 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4488 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4494 ),
4489 ),
4495 (
4490 (
4496 b'd',
4491 b'd',
4497 b'date',
4492 b'date',
4498 b'',
4493 b'',
4499 _(b'show revisions matching date spec'),
4494 _(b'show revisions matching date spec'),
4500 _(b'DATE'),
4495 _(b'DATE'),
4501 ),
4496 ),
4502 (b'C', b'copies', None, _(b'show copied files')),
4497 (b'C', b'copies', None, _(b'show copied files')),
4503 (
4498 (
4504 b'k',
4499 b'k',
4505 b'keyword',
4500 b'keyword',
4506 [],
4501 [],
4507 _(b'do case-insensitive search for a given text'),
4502 _(b'do case-insensitive search for a given text'),
4508 _(b'TEXT'),
4503 _(b'TEXT'),
4509 ),
4504 ),
4510 (
4505 (
4511 b'r',
4506 b'r',
4512 b'rev',
4507 b'rev',
4513 [],
4508 [],
4514 _(b'revisions to select or follow from'),
4509 _(b'revisions to select or follow from'),
4515 _(b'REV'),
4510 _(b'REV'),
4516 ),
4511 ),
4517 (
4512 (
4518 b'L',
4513 b'L',
4519 b'line-range',
4514 b'line-range',
4520 [],
4515 [],
4521 _(b'follow line range of specified file (EXPERIMENTAL)'),
4516 _(b'follow line range of specified file (EXPERIMENTAL)'),
4522 _(b'FILE,RANGE'),
4517 _(b'FILE,RANGE'),
4523 ),
4518 ),
4524 (
4519 (
4525 b'',
4520 b'',
4526 b'removed',
4521 b'removed',
4527 None,
4522 None,
4528 _(b'include revisions where files were removed'),
4523 _(b'include revisions where files were removed'),
4529 ),
4524 ),
4530 (
4525 (
4531 b'm',
4526 b'm',
4532 b'only-merges',
4527 b'only-merges',
4533 None,
4528 None,
4534 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4529 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4535 ),
4530 ),
4536 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4531 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4537 (
4532 (
4538 b'',
4533 b'',
4539 b'only-branch',
4534 b'only-branch',
4540 [],
4535 [],
4541 _(
4536 _(
4542 b'show only changesets within the given named branch (DEPRECATED)'
4537 b'show only changesets within the given named branch (DEPRECATED)'
4543 ),
4538 ),
4544 _(b'BRANCH'),
4539 _(b'BRANCH'),
4545 ),
4540 ),
4546 (
4541 (
4547 b'b',
4542 b'b',
4548 b'branch',
4543 b'branch',
4549 [],
4544 [],
4550 _(b'show changesets within the given named branch'),
4545 _(b'show changesets within the given named branch'),
4551 _(b'BRANCH'),
4546 _(b'BRANCH'),
4552 ),
4547 ),
4553 (
4548 (
4554 b'B',
4549 b'B',
4555 b'bookmark',
4550 b'bookmark',
4556 [],
4551 [],
4557 _(b"show changesets within the given bookmark"),
4552 _(b"show changesets within the given bookmark"),
4558 _(b'BOOKMARK'),
4553 _(b'BOOKMARK'),
4559 ),
4554 ),
4560 (
4555 (
4561 b'P',
4556 b'P',
4562 b'prune',
4557 b'prune',
4563 [],
4558 [],
4564 _(b'do not display revision or any of its ancestors'),
4559 _(b'do not display revision or any of its ancestors'),
4565 _(b'REV'),
4560 _(b'REV'),
4566 ),
4561 ),
4567 ]
4562 ]
4568 + logopts
4563 + logopts
4569 + walkopts,
4564 + walkopts,
4570 _(b'[OPTION]... [FILE]'),
4565 _(b'[OPTION]... [FILE]'),
4571 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4566 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4572 helpbasic=True,
4567 helpbasic=True,
4573 inferrepo=True,
4568 inferrepo=True,
4574 intents={INTENT_READONLY},
4569 intents={INTENT_READONLY},
4575 )
4570 )
4576 def log(ui, repo, *pats, **opts):
4571 def log(ui, repo, *pats, **opts):
4577 """show revision history of entire repository or files
4572 """show revision history of entire repository or files
4578
4573
4579 Print the revision history of the specified files or the entire
4574 Print the revision history of the specified files or the entire
4580 project.
4575 project.
4581
4576
4582 If no revision range is specified, the default is ``tip:0`` unless
4577 If no revision range is specified, the default is ``tip:0`` unless
4583 --follow is set.
4578 --follow is set.
4584
4579
4585 File history is shown without following rename or copy history of
4580 File history is shown without following rename or copy history of
4586 files. Use -f/--follow with a filename to follow history across
4581 files. Use -f/--follow with a filename to follow history across
4587 renames and copies. --follow without a filename will only show
4582 renames and copies. --follow without a filename will only show
4588 ancestors of the starting revisions. The starting revisions can be
4583 ancestors of the starting revisions. The starting revisions can be
4589 specified by -r/--rev, which default to the working directory parent.
4584 specified by -r/--rev, which default to the working directory parent.
4590
4585
4591 By default this command prints revision number and changeset id,
4586 By default this command prints revision number and changeset id,
4592 tags, non-trivial parents, user, date and time, and a summary for
4587 tags, non-trivial parents, user, date and time, and a summary for
4593 each commit. When the -v/--verbose switch is used, the list of
4588 each commit. When the -v/--verbose switch is used, the list of
4594 changed files and full commit message are shown.
4589 changed files and full commit message are shown.
4595
4590
4596 With --graph the revisions are shown as an ASCII art DAG with the most
4591 With --graph the revisions are shown as an ASCII art DAG with the most
4597 recent changeset at the top.
4592 recent changeset at the top.
4598 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4593 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4599 involved in an unresolved merge conflict, '_' closes a branch,
4594 involved in an unresolved merge conflict, '_' closes a branch,
4600 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4595 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4601 changeset from the lines below is a parent of the 'o' merge on the same
4596 changeset from the lines below is a parent of the 'o' merge on the same
4602 line.
4597 line.
4603 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4598 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4604 of a '|' indicates one or more revisions in a path are omitted.
4599 of a '|' indicates one or more revisions in a path are omitted.
4605
4600
4606 .. container:: verbose
4601 .. container:: verbose
4607
4602
4608 Use -L/--line-range FILE,M:N options to follow the history of lines
4603 Use -L/--line-range FILE,M:N options to follow the history of lines
4609 from M to N in FILE. With -p/--patch only diff hunks affecting
4604 from M to N in FILE. With -p/--patch only diff hunks affecting
4610 specified line range will be shown. This option requires --follow;
4605 specified line range will be shown. This option requires --follow;
4611 it can be specified multiple times. Currently, this option is not
4606 it can be specified multiple times. Currently, this option is not
4612 compatible with --graph. This option is experimental.
4607 compatible with --graph. This option is experimental.
4613
4608
4614 .. note::
4609 .. note::
4615
4610
4616 :hg:`log --patch` may generate unexpected diff output for merge
4611 :hg:`log --patch` may generate unexpected diff output for merge
4617 changesets, as it will only compare the merge changeset against
4612 changesets, as it will only compare the merge changeset against
4618 its first parent. Also, only files different from BOTH parents
4613 its first parent. Also, only files different from BOTH parents
4619 will appear in files:.
4614 will appear in files:.
4620
4615
4621 .. note::
4616 .. note::
4622
4617
4623 For performance reasons, :hg:`log FILE` may omit duplicate changes
4618 For performance reasons, :hg:`log FILE` may omit duplicate changes
4624 made on branches and will not show removals or mode changes. To
4619 made on branches and will not show removals or mode changes. To
4625 see all such changes, use the --removed switch.
4620 see all such changes, use the --removed switch.
4626
4621
4627 .. container:: verbose
4622 .. container:: verbose
4628
4623
4629 .. note::
4624 .. note::
4630
4625
4631 The history resulting from -L/--line-range options depends on diff
4626 The history resulting from -L/--line-range options depends on diff
4632 options; for instance if white-spaces are ignored, respective changes
4627 options; for instance if white-spaces are ignored, respective changes
4633 with only white-spaces in specified line range will not be listed.
4628 with only white-spaces in specified line range will not be listed.
4634
4629
4635 .. container:: verbose
4630 .. container:: verbose
4636
4631
4637 Some examples:
4632 Some examples:
4638
4633
4639 - changesets with full descriptions and file lists::
4634 - changesets with full descriptions and file lists::
4640
4635
4641 hg log -v
4636 hg log -v
4642
4637
4643 - changesets ancestral to the working directory::
4638 - changesets ancestral to the working directory::
4644
4639
4645 hg log -f
4640 hg log -f
4646
4641
4647 - last 10 commits on the current branch::
4642 - last 10 commits on the current branch::
4648
4643
4649 hg log -l 10 -b .
4644 hg log -l 10 -b .
4650
4645
4651 - changesets showing all modifications of a file, including removals::
4646 - changesets showing all modifications of a file, including removals::
4652
4647
4653 hg log --removed file.c
4648 hg log --removed file.c
4654
4649
4655 - all changesets that touch a directory, with diffs, excluding merges::
4650 - all changesets that touch a directory, with diffs, excluding merges::
4656
4651
4657 hg log -Mp lib/
4652 hg log -Mp lib/
4658
4653
4659 - all revision numbers that match a keyword::
4654 - all revision numbers that match a keyword::
4660
4655
4661 hg log -k bug --template "{rev}\\n"
4656 hg log -k bug --template "{rev}\\n"
4662
4657
4663 - the full hash identifier of the working directory parent::
4658 - the full hash identifier of the working directory parent::
4664
4659
4665 hg log -r . --template "{node}\\n"
4660 hg log -r . --template "{node}\\n"
4666
4661
4667 - list available log templates::
4662 - list available log templates::
4668
4663
4669 hg log -T list
4664 hg log -T list
4670
4665
4671 - check if a given changeset is included in a tagged release::
4666 - check if a given changeset is included in a tagged release::
4672
4667
4673 hg log -r "a21ccf and ancestor(1.9)"
4668 hg log -r "a21ccf and ancestor(1.9)"
4674
4669
4675 - find all changesets by some user in a date range::
4670 - find all changesets by some user in a date range::
4676
4671
4677 hg log -k alice -d "may 2008 to jul 2008"
4672 hg log -k alice -d "may 2008 to jul 2008"
4678
4673
4679 - summary of all changesets after the last tag::
4674 - summary of all changesets after the last tag::
4680
4675
4681 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4676 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4682
4677
4683 - changesets touching lines 13 to 23 for file.c::
4678 - changesets touching lines 13 to 23 for file.c::
4684
4679
4685 hg log -L file.c,13:23
4680 hg log -L file.c,13:23
4686
4681
4687 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4682 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4688 main.c with patch::
4683 main.c with patch::
4689
4684
4690 hg log -L file.c,13:23 -L main.c,2:6 -p
4685 hg log -L file.c,13:23 -L main.c,2:6 -p
4691
4686
4692 See :hg:`help dates` for a list of formats valid for -d/--date.
4687 See :hg:`help dates` for a list of formats valid for -d/--date.
4693
4688
4694 See :hg:`help revisions` for more about specifying and ordering
4689 See :hg:`help revisions` for more about specifying and ordering
4695 revisions.
4690 revisions.
4696
4691
4697 See :hg:`help templates` for more about pre-packaged styles and
4692 See :hg:`help templates` for more about pre-packaged styles and
4698 specifying custom templates. The default template used by the log
4693 specifying custom templates. The default template used by the log
4699 command can be customized via the ``command-templates.log`` configuration
4694 command can be customized via the ``command-templates.log`` configuration
4700 setting.
4695 setting.
4701
4696
4702 Returns 0 on success.
4697 Returns 0 on success.
4703
4698
4704 """
4699 """
4705 opts = pycompat.byteskwargs(opts)
4700 opts = pycompat.byteskwargs(opts)
4706 linerange = opts.get(b'line_range')
4701 linerange = opts.get(b'line_range')
4707
4702
4708 if linerange and not opts.get(b'follow'):
4703 if linerange and not opts.get(b'follow'):
4709 raise error.InputError(_(b'--line-range requires --follow'))
4704 raise error.InputError(_(b'--line-range requires --follow'))
4710
4705
4711 if linerange and pats:
4706 if linerange and pats:
4712 # TODO: take pats as patterns with no line-range filter
4707 # TODO: take pats as patterns with no line-range filter
4713 raise error.InputError(
4708 raise error.InputError(
4714 _(b'FILE arguments are not compatible with --line-range option')
4709 _(b'FILE arguments are not compatible with --line-range option')
4715 )
4710 )
4716
4711
4717 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4712 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4718 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4713 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4719 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4714 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4720 if linerange:
4715 if linerange:
4721 # TODO: should follow file history from logcmdutil._initialrevs(),
4716 # TODO: should follow file history from logcmdutil._initialrevs(),
4722 # then filter the result by logcmdutil._makerevset() and --limit
4717 # then filter the result by logcmdutil._makerevset() and --limit
4723 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4718 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4724
4719
4725 getcopies = None
4720 getcopies = None
4726 if opts.get(b'copies'):
4721 if opts.get(b'copies'):
4727 endrev = None
4722 endrev = None
4728 if revs:
4723 if revs:
4729 endrev = revs.max() + 1
4724 endrev = revs.max() + 1
4730 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4725 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4731
4726
4732 ui.pager(b'log')
4727 ui.pager(b'log')
4733 displayer = logcmdutil.changesetdisplayer(
4728 displayer = logcmdutil.changesetdisplayer(
4734 ui, repo, opts, differ, buffered=True
4729 ui, repo, opts, differ, buffered=True
4735 )
4730 )
4736 if opts.get(b'graph'):
4731 if opts.get(b'graph'):
4737 displayfn = logcmdutil.displaygraphrevs
4732 displayfn = logcmdutil.displaygraphrevs
4738 else:
4733 else:
4739 displayfn = logcmdutil.displayrevs
4734 displayfn = logcmdutil.displayrevs
4740 displayfn(ui, repo, revs, displayer, getcopies)
4735 displayfn(ui, repo, revs, displayer, getcopies)
4741
4736
4742
4737
4743 @command(
4738 @command(
4744 b'manifest',
4739 b'manifest',
4745 [
4740 [
4746 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4741 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4747 (b'', b'all', False, _(b"list files from all revisions")),
4742 (b'', b'all', False, _(b"list files from all revisions")),
4748 ]
4743 ]
4749 + formatteropts,
4744 + formatteropts,
4750 _(b'[-r REV]'),
4745 _(b'[-r REV]'),
4751 helpcategory=command.CATEGORY_MAINTENANCE,
4746 helpcategory=command.CATEGORY_MAINTENANCE,
4752 intents={INTENT_READONLY},
4747 intents={INTENT_READONLY},
4753 )
4748 )
4754 def manifest(ui, repo, node=None, rev=None, **opts):
4749 def manifest(ui, repo, node=None, rev=None, **opts):
4755 """output the current or given revision of the project manifest
4750 """output the current or given revision of the project manifest
4756
4751
4757 Print a list of version controlled files for the given revision.
4752 Print a list of version controlled files for the given revision.
4758 If no revision is given, the first parent of the working directory
4753 If no revision is given, the first parent of the working directory
4759 is used, or the null revision if no revision is checked out.
4754 is used, or the null revision if no revision is checked out.
4760
4755
4761 With -v, print file permissions, symlink and executable bits.
4756 With -v, print file permissions, symlink and executable bits.
4762 With --debug, print file revision hashes.
4757 With --debug, print file revision hashes.
4763
4758
4764 If option --all is specified, the list of all files from all revisions
4759 If option --all is specified, the list of all files from all revisions
4765 is printed. This includes deleted and renamed files.
4760 is printed. This includes deleted and renamed files.
4766
4761
4767 Returns 0 on success.
4762 Returns 0 on success.
4768 """
4763 """
4769 opts = pycompat.byteskwargs(opts)
4764 opts = pycompat.byteskwargs(opts)
4770 fm = ui.formatter(b'manifest', opts)
4765 fm = ui.formatter(b'manifest', opts)
4771
4766
4772 if opts.get(b'all'):
4767 if opts.get(b'all'):
4773 if rev or node:
4768 if rev or node:
4774 raise error.InputError(_(b"can't specify a revision with --all"))
4769 raise error.InputError(_(b"can't specify a revision with --all"))
4775
4770
4776 res = set()
4771 res = set()
4777 for rev in repo:
4772 for rev in repo:
4778 ctx = repo[rev]
4773 ctx = repo[rev]
4779 res |= set(ctx.files())
4774 res |= set(ctx.files())
4780
4775
4781 ui.pager(b'manifest')
4776 ui.pager(b'manifest')
4782 for f in sorted(res):
4777 for f in sorted(res):
4783 fm.startitem()
4778 fm.startitem()
4784 fm.write(b"path", b'%s\n', f)
4779 fm.write(b"path", b'%s\n', f)
4785 fm.end()
4780 fm.end()
4786 return
4781 return
4787
4782
4788 if rev and node:
4783 if rev and node:
4789 raise error.InputError(_(b"please specify just one revision"))
4784 raise error.InputError(_(b"please specify just one revision"))
4790
4785
4791 if not node:
4786 if not node:
4792 node = rev
4787 node = rev
4793
4788
4794 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4789 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4795 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4790 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4796 if node:
4791 if node:
4797 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4792 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4798 ctx = scmutil.revsingle(repo, node)
4793 ctx = scmutil.revsingle(repo, node)
4799 mf = ctx.manifest()
4794 mf = ctx.manifest()
4800 ui.pager(b'manifest')
4795 ui.pager(b'manifest')
4801 for f in ctx:
4796 for f in ctx:
4802 fm.startitem()
4797 fm.startitem()
4803 fm.context(ctx=ctx)
4798 fm.context(ctx=ctx)
4804 fl = ctx[f].flags()
4799 fl = ctx[f].flags()
4805 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4800 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4806 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4801 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4807 fm.write(b'path', b'%s\n', f)
4802 fm.write(b'path', b'%s\n', f)
4808 fm.end()
4803 fm.end()
4809
4804
4810
4805
4811 @command(
4806 @command(
4812 b'merge',
4807 b'merge',
4813 [
4808 [
4814 (
4809 (
4815 b'f',
4810 b'f',
4816 b'force',
4811 b'force',
4817 None,
4812 None,
4818 _(b'force a merge including outstanding changes (DEPRECATED)'),
4813 _(b'force a merge including outstanding changes (DEPRECATED)'),
4819 ),
4814 ),
4820 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4815 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4821 (
4816 (
4822 b'P',
4817 b'P',
4823 b'preview',
4818 b'preview',
4824 None,
4819 None,
4825 _(b'review revisions to merge (no merge is performed)'),
4820 _(b'review revisions to merge (no merge is performed)'),
4826 ),
4821 ),
4827 (b'', b'abort', None, _(b'abort the ongoing merge')),
4822 (b'', b'abort', None, _(b'abort the ongoing merge')),
4828 ]
4823 ]
4829 + mergetoolopts,
4824 + mergetoolopts,
4830 _(b'[-P] [[-r] REV]'),
4825 _(b'[-P] [[-r] REV]'),
4831 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4826 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4832 helpbasic=True,
4827 helpbasic=True,
4833 )
4828 )
4834 def merge(ui, repo, node=None, **opts):
4829 def merge(ui, repo, node=None, **opts):
4835 """merge another revision into working directory
4830 """merge another revision into working directory
4836
4831
4837 The current working directory is updated with all changes made in
4832 The current working directory is updated with all changes made in
4838 the requested revision since the last common predecessor revision.
4833 the requested revision since the last common predecessor revision.
4839
4834
4840 Files that changed between either parent are marked as changed for
4835 Files that changed between either parent are marked as changed for
4841 the next commit and a commit must be performed before any further
4836 the next commit and a commit must be performed before any further
4842 updates to the repository are allowed. The next commit will have
4837 updates to the repository are allowed. The next commit will have
4843 two parents.
4838 two parents.
4844
4839
4845 ``--tool`` can be used to specify the merge tool used for file
4840 ``--tool`` can be used to specify the merge tool used for file
4846 merges. It overrides the HGMERGE environment variable and your
4841 merges. It overrides the HGMERGE environment variable and your
4847 configuration files. See :hg:`help merge-tools` for options.
4842 configuration files. See :hg:`help merge-tools` for options.
4848
4843
4849 If no revision is specified, the working directory's parent is a
4844 If no revision is specified, the working directory's parent is a
4850 head revision, and the current branch contains exactly one other
4845 head revision, and the current branch contains exactly one other
4851 head, the other head is merged with by default. Otherwise, an
4846 head, the other head is merged with by default. Otherwise, an
4852 explicit revision with which to merge must be provided.
4847 explicit revision with which to merge must be provided.
4853
4848
4854 See :hg:`help resolve` for information on handling file conflicts.
4849 See :hg:`help resolve` for information on handling file conflicts.
4855
4850
4856 To undo an uncommitted merge, use :hg:`merge --abort` which
4851 To undo an uncommitted merge, use :hg:`merge --abort` which
4857 will check out a clean copy of the original merge parent, losing
4852 will check out a clean copy of the original merge parent, losing
4858 all changes.
4853 all changes.
4859
4854
4860 Returns 0 on success, 1 if there are unresolved files.
4855 Returns 0 on success, 1 if there are unresolved files.
4861 """
4856 """
4862
4857
4863 opts = pycompat.byteskwargs(opts)
4858 opts = pycompat.byteskwargs(opts)
4864 abort = opts.get(b'abort')
4859 abort = opts.get(b'abort')
4865 if abort and repo.dirstate.p2() == repo.nullid:
4860 if abort and repo.dirstate.p2() == repo.nullid:
4866 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4861 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4867 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4862 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4868 if abort:
4863 if abort:
4869 state = cmdutil.getunfinishedstate(repo)
4864 state = cmdutil.getunfinishedstate(repo)
4870 if state and state._opname != b'merge':
4865 if state and state._opname != b'merge':
4871 raise error.StateError(
4866 raise error.StateError(
4872 _(b'cannot abort merge with %s in progress') % (state._opname),
4867 _(b'cannot abort merge with %s in progress') % (state._opname),
4873 hint=state.hint(),
4868 hint=state.hint(),
4874 )
4869 )
4875 if node:
4870 if node:
4876 raise error.InputError(_(b"cannot specify a node with --abort"))
4871 raise error.InputError(_(b"cannot specify a node with --abort"))
4877 return hg.abortmerge(repo.ui, repo)
4872 return hg.abortmerge(repo.ui, repo)
4878
4873
4879 if opts.get(b'rev') and node:
4874 if opts.get(b'rev') and node:
4880 raise error.InputError(_(b"please specify just one revision"))
4875 raise error.InputError(_(b"please specify just one revision"))
4881 if not node:
4876 if not node:
4882 node = opts.get(b'rev')
4877 node = opts.get(b'rev')
4883
4878
4884 if node:
4879 if node:
4885 ctx = scmutil.revsingle(repo, node)
4880 ctx = scmutil.revsingle(repo, node)
4886 else:
4881 else:
4887 if ui.configbool(b'commands', b'merge.require-rev'):
4882 if ui.configbool(b'commands', b'merge.require-rev'):
4888 raise error.InputError(
4883 raise error.InputError(
4889 _(
4884 _(
4890 b'configuration requires specifying revision to merge '
4885 b'configuration requires specifying revision to merge '
4891 b'with'
4886 b'with'
4892 )
4887 )
4893 )
4888 )
4894 ctx = repo[destutil.destmerge(repo)]
4889 ctx = repo[destutil.destmerge(repo)]
4895
4890
4896 if ctx.node() is None:
4891 if ctx.node() is None:
4897 raise error.InputError(
4892 raise error.InputError(
4898 _(b'merging with the working copy has no effect')
4893 _(b'merging with the working copy has no effect')
4899 )
4894 )
4900
4895
4901 if opts.get(b'preview'):
4896 if opts.get(b'preview'):
4902 # find nodes that are ancestors of p2 but not of p1
4897 # find nodes that are ancestors of p2 but not of p1
4903 p1 = repo[b'.'].node()
4898 p1 = repo[b'.'].node()
4904 p2 = ctx.node()
4899 p2 = ctx.node()
4905 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4900 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4906
4901
4907 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4902 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4908 for node in nodes:
4903 for node in nodes:
4909 displayer.show(repo[node])
4904 displayer.show(repo[node])
4910 displayer.close()
4905 displayer.close()
4911 return 0
4906 return 0
4912
4907
4913 # ui.forcemerge is an internal variable, do not document
4908 # ui.forcemerge is an internal variable, do not document
4914 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4909 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4915 with ui.configoverride(overrides, b'merge'):
4910 with ui.configoverride(overrides, b'merge'):
4916 force = opts.get(b'force')
4911 force = opts.get(b'force')
4917 labels = [b'working copy', b'merge rev']
4912 labels = [b'working copy', b'merge rev']
4918 return hg.merge(ctx, force=force, labels=labels)
4913 return hg.merge(ctx, force=force, labels=labels)
4919
4914
4920
4915
4921 statemod.addunfinished(
4916 statemod.addunfinished(
4922 b'merge',
4917 b'merge',
4923 fname=None,
4918 fname=None,
4924 clearable=True,
4919 clearable=True,
4925 allowcommit=True,
4920 allowcommit=True,
4926 cmdmsg=_(b'outstanding uncommitted merge'),
4921 cmdmsg=_(b'outstanding uncommitted merge'),
4927 abortfunc=hg.abortmerge,
4922 abortfunc=hg.abortmerge,
4928 statushint=_(
4923 statushint=_(
4929 b'To continue: hg commit\nTo abort: hg merge --abort'
4924 b'To continue: hg commit\nTo abort: hg merge --abort'
4930 ),
4925 ),
4931 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4926 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4932 )
4927 )
4933
4928
4934
4929
4935 @command(
4930 @command(
4936 b'outgoing|out',
4931 b'outgoing|out',
4937 [
4932 [
4938 (
4933 (
4939 b'f',
4934 b'f',
4940 b'force',
4935 b'force',
4941 None,
4936 None,
4942 _(b'run even when the destination is unrelated'),
4937 _(b'run even when the destination is unrelated'),
4943 ),
4938 ),
4944 (
4939 (
4945 b'r',
4940 b'r',
4946 b'rev',
4941 b'rev',
4947 [],
4942 [],
4948 _(b'a changeset intended to be included in the destination'),
4943 _(b'a changeset intended to be included in the destination'),
4949 _(b'REV'),
4944 _(b'REV'),
4950 ),
4945 ),
4951 (b'n', b'newest-first', None, _(b'show newest record first')),
4946 (b'n', b'newest-first', None, _(b'show newest record first')),
4952 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4947 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4953 (
4948 (
4954 b'b',
4949 b'b',
4955 b'branch',
4950 b'branch',
4956 [],
4951 [],
4957 _(b'a specific branch you would like to push'),
4952 _(b'a specific branch you would like to push'),
4958 _(b'BRANCH'),
4953 _(b'BRANCH'),
4959 ),
4954 ),
4960 ]
4955 ]
4961 + logopts
4956 + logopts
4962 + remoteopts
4957 + remoteopts
4963 + subrepoopts,
4958 + subrepoopts,
4964 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4959 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4965 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4960 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4966 )
4961 )
4967 def outgoing(ui, repo, *dests, **opts):
4962 def outgoing(ui, repo, *dests, **opts):
4968 """show changesets not found in the destination
4963 """show changesets not found in the destination
4969
4964
4970 Show changesets not found in the specified destination repository
4965 Show changesets not found in the specified destination repository
4971 or the default push location. These are the changesets that would
4966 or the default push location. These are the changesets that would
4972 be pushed if a push was requested.
4967 be pushed if a push was requested.
4973
4968
4974 See pull for details of valid destination formats.
4969 See pull for details of valid destination formats.
4975
4970
4976 .. container:: verbose
4971 .. container:: verbose
4977
4972
4978 With -B/--bookmarks, the result of bookmark comparison between
4973 With -B/--bookmarks, the result of bookmark comparison between
4979 local and remote repositories is displayed. With -v/--verbose,
4974 local and remote repositories is displayed. With -v/--verbose,
4980 status is also displayed for each bookmark like below::
4975 status is also displayed for each bookmark like below::
4981
4976
4982 BM1 01234567890a added
4977 BM1 01234567890a added
4983 BM2 deleted
4978 BM2 deleted
4984 BM3 234567890abc advanced
4979 BM3 234567890abc advanced
4985 BM4 34567890abcd diverged
4980 BM4 34567890abcd diverged
4986 BM5 4567890abcde changed
4981 BM5 4567890abcde changed
4987
4982
4988 The action taken when pushing depends on the
4983 The action taken when pushing depends on the
4989 status of each bookmark:
4984 status of each bookmark:
4990
4985
4991 :``added``: push with ``-B`` will create it
4986 :``added``: push with ``-B`` will create it
4992 :``deleted``: push with ``-B`` will delete it
4987 :``deleted``: push with ``-B`` will delete it
4993 :``advanced``: push will update it
4988 :``advanced``: push will update it
4994 :``diverged``: push with ``-B`` will update it
4989 :``diverged``: push with ``-B`` will update it
4995 :``changed``: push with ``-B`` will update it
4990 :``changed``: push with ``-B`` will update it
4996
4991
4997 From the point of view of pushing behavior, bookmarks
4992 From the point of view of pushing behavior, bookmarks
4998 existing only in the remote repository are treated as
4993 existing only in the remote repository are treated as
4999 ``deleted``, even if it is in fact added remotely.
4994 ``deleted``, even if it is in fact added remotely.
5000
4995
5001 Returns 0 if there are outgoing changes, 1 otherwise.
4996 Returns 0 if there are outgoing changes, 1 otherwise.
5002 """
4997 """
5003 opts = pycompat.byteskwargs(opts)
4998 opts = pycompat.byteskwargs(opts)
5004 if opts.get(b'bookmarks'):
4999 if opts.get(b'bookmarks'):
5005 for path in urlutil.get_push_paths(repo, ui, dests):
5000 for path in urlutil.get_push_paths(repo, ui, dests):
5006 dest = path.pushloc or path.loc
5001 dest = path.pushloc or path.loc
5007 other = hg.peer(repo, opts, dest)
5002 other = hg.peer(repo, opts, dest)
5008 try:
5003 try:
5009 if b'bookmarks' not in other.listkeys(b'namespaces'):
5004 if b'bookmarks' not in other.listkeys(b'namespaces'):
5010 ui.warn(_(b"remote doesn't support bookmarks\n"))
5005 ui.warn(_(b"remote doesn't support bookmarks\n"))
5011 return 0
5006 return 0
5012 ui.status(
5007 ui.status(
5013 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5008 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5014 )
5009 )
5015 ui.pager(b'outgoing')
5010 ui.pager(b'outgoing')
5016 return bookmarks.outgoing(ui, repo, other)
5011 return bookmarks.outgoing(ui, repo, other)
5017 finally:
5012 finally:
5018 other.close()
5013 other.close()
5019
5014
5020 return hg.outgoing(ui, repo, dests, opts)
5015 return hg.outgoing(ui, repo, dests, opts)
5021
5016
5022
5017
5023 @command(
5018 @command(
5024 b'parents',
5019 b'parents',
5025 [
5020 [
5026 (
5021 (
5027 b'r',
5022 b'r',
5028 b'rev',
5023 b'rev',
5029 b'',
5024 b'',
5030 _(b'show parents of the specified revision'),
5025 _(b'show parents of the specified revision'),
5031 _(b'REV'),
5026 _(b'REV'),
5032 ),
5027 ),
5033 ]
5028 ]
5034 + templateopts,
5029 + templateopts,
5035 _(b'[-r REV] [FILE]'),
5030 _(b'[-r REV] [FILE]'),
5036 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5031 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5037 inferrepo=True,
5032 inferrepo=True,
5038 )
5033 )
5039 def parents(ui, repo, file_=None, **opts):
5034 def parents(ui, repo, file_=None, **opts):
5040 """show the parents of the working directory or revision (DEPRECATED)
5035 """show the parents of the working directory or revision (DEPRECATED)
5041
5036
5042 Print the working directory's parent revisions. If a revision is
5037 Print the working directory's parent revisions. If a revision is
5043 given via -r/--rev, the parent of that revision will be printed.
5038 given via -r/--rev, the parent of that revision will be printed.
5044 If a file argument is given, the revision in which the file was
5039 If a file argument is given, the revision in which the file was
5045 last changed (before the working directory revision or the
5040 last changed (before the working directory revision or the
5046 argument to --rev if given) is printed.
5041 argument to --rev if given) is printed.
5047
5042
5048 This command is equivalent to::
5043 This command is equivalent to::
5049
5044
5050 hg log -r "p1()+p2()" or
5045 hg log -r "p1()+p2()" or
5051 hg log -r "p1(REV)+p2(REV)" or
5046 hg log -r "p1(REV)+p2(REV)" or
5052 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5047 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5053 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5048 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5054
5049
5055 See :hg:`summary` and :hg:`help revsets` for related information.
5050 See :hg:`summary` and :hg:`help revsets` for related information.
5056
5051
5057 Returns 0 on success.
5052 Returns 0 on success.
5058 """
5053 """
5059
5054
5060 opts = pycompat.byteskwargs(opts)
5055 opts = pycompat.byteskwargs(opts)
5061 rev = opts.get(b'rev')
5056 rev = opts.get(b'rev')
5062 if rev:
5057 if rev:
5063 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5058 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5064 ctx = scmutil.revsingle(repo, rev, None)
5059 ctx = scmutil.revsingle(repo, rev, None)
5065
5060
5066 if file_:
5061 if file_:
5067 m = scmutil.match(ctx, (file_,), opts)
5062 m = scmutil.match(ctx, (file_,), opts)
5068 if m.anypats() or len(m.files()) != 1:
5063 if m.anypats() or len(m.files()) != 1:
5069 raise error.InputError(_(b'can only specify an explicit filename'))
5064 raise error.InputError(_(b'can only specify an explicit filename'))
5070 file_ = m.files()[0]
5065 file_ = m.files()[0]
5071 filenodes = []
5066 filenodes = []
5072 for cp in ctx.parents():
5067 for cp in ctx.parents():
5073 if not cp:
5068 if not cp:
5074 continue
5069 continue
5075 try:
5070 try:
5076 filenodes.append(cp.filenode(file_))
5071 filenodes.append(cp.filenode(file_))
5077 except error.LookupError:
5072 except error.LookupError:
5078 pass
5073 pass
5079 if not filenodes:
5074 if not filenodes:
5080 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5075 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5081 p = []
5076 p = []
5082 for fn in filenodes:
5077 for fn in filenodes:
5083 fctx = repo.filectx(file_, fileid=fn)
5078 fctx = repo.filectx(file_, fileid=fn)
5084 p.append(fctx.node())
5079 p.append(fctx.node())
5085 else:
5080 else:
5086 p = [cp.node() for cp in ctx.parents()]
5081 p = [cp.node() for cp in ctx.parents()]
5087
5082
5088 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5083 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5089 for n in p:
5084 for n in p:
5090 if n != repo.nullid:
5085 if n != repo.nullid:
5091 displayer.show(repo[n])
5086 displayer.show(repo[n])
5092 displayer.close()
5087 displayer.close()
5093
5088
5094
5089
5095 @command(
5090 @command(
5096 b'paths',
5091 b'paths',
5097 formatteropts,
5092 formatteropts,
5098 _(b'[NAME]'),
5093 _(b'[NAME]'),
5099 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5094 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5100 optionalrepo=True,
5095 optionalrepo=True,
5101 intents={INTENT_READONLY},
5096 intents={INTENT_READONLY},
5102 )
5097 )
5103 def paths(ui, repo, search=None, **opts):
5098 def paths(ui, repo, search=None, **opts):
5104 """show aliases for remote repositories
5099 """show aliases for remote repositories
5105
5100
5106 Show definition of symbolic path name NAME. If no name is given,
5101 Show definition of symbolic path name NAME. If no name is given,
5107 show definition of all available names.
5102 show definition of all available names.
5108
5103
5109 Option -q/--quiet suppresses all output when searching for NAME
5104 Option -q/--quiet suppresses all output when searching for NAME
5110 and shows only the path names when listing all definitions.
5105 and shows only the path names when listing all definitions.
5111
5106
5112 Path names are defined in the [paths] section of your
5107 Path names are defined in the [paths] section of your
5113 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5108 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5114 repository, ``.hg/hgrc`` is used, too.
5109 repository, ``.hg/hgrc`` is used, too.
5115
5110
5116 The path names ``default`` and ``default-push`` have a special
5111 The path names ``default`` and ``default-push`` have a special
5117 meaning. When performing a push or pull operation, they are used
5112 meaning. When performing a push or pull operation, they are used
5118 as fallbacks if no location is specified on the command-line.
5113 as fallbacks if no location is specified on the command-line.
5119 When ``default-push`` is set, it will be used for push and
5114 When ``default-push`` is set, it will be used for push and
5120 ``default`` will be used for pull; otherwise ``default`` is used
5115 ``default`` will be used for pull; otherwise ``default`` is used
5121 as the fallback for both. When cloning a repository, the clone
5116 as the fallback for both. When cloning a repository, the clone
5122 source is written as ``default`` in ``.hg/hgrc``.
5117 source is written as ``default`` in ``.hg/hgrc``.
5123
5118
5124 .. note::
5119 .. note::
5125
5120
5126 ``default`` and ``default-push`` apply to all inbound (e.g.
5121 ``default`` and ``default-push`` apply to all inbound (e.g.
5127 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5122 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5128 and :hg:`bundle`) operations.
5123 and :hg:`bundle`) operations.
5129
5124
5130 See :hg:`help urls` for more information.
5125 See :hg:`help urls` for more information.
5131
5126
5132 .. container:: verbose
5127 .. container:: verbose
5133
5128
5134 Template:
5129 Template:
5135
5130
5136 The following keywords are supported. See also :hg:`help templates`.
5131 The following keywords are supported. See also :hg:`help templates`.
5137
5132
5138 :name: String. Symbolic name of the path alias.
5133 :name: String. Symbolic name of the path alias.
5139 :pushurl: String. URL for push operations.
5134 :pushurl: String. URL for push operations.
5140 :url: String. URL or directory path for the other operations.
5135 :url: String. URL or directory path for the other operations.
5141
5136
5142 Returns 0 on success.
5137 Returns 0 on success.
5143 """
5138 """
5144
5139
5145 opts = pycompat.byteskwargs(opts)
5140 opts = pycompat.byteskwargs(opts)
5146
5141
5147 pathitems = urlutil.list_paths(ui, search)
5142 pathitems = urlutil.list_paths(ui, search)
5148 ui.pager(b'paths')
5143 ui.pager(b'paths')
5149
5144
5150 fm = ui.formatter(b'paths', opts)
5145 fm = ui.formatter(b'paths', opts)
5151 if fm.isplain():
5146 if fm.isplain():
5152 hidepassword = urlutil.hidepassword
5147 hidepassword = urlutil.hidepassword
5153 else:
5148 else:
5154 hidepassword = bytes
5149 hidepassword = bytes
5155 if ui.quiet:
5150 if ui.quiet:
5156 namefmt = b'%s\n'
5151 namefmt = b'%s\n'
5157 else:
5152 else:
5158 namefmt = b'%s = '
5153 namefmt = b'%s = '
5159 showsubopts = not search and not ui.quiet
5154 showsubopts = not search and not ui.quiet
5160
5155
5161 for name, path in pathitems:
5156 for name, path in pathitems:
5162 fm.startitem()
5157 fm.startitem()
5163 fm.condwrite(not search, b'name', namefmt, name)
5158 fm.condwrite(not search, b'name', namefmt, name)
5164 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5159 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5165 for subopt, value in sorted(path.suboptions.items()):
5160 for subopt, value in sorted(path.suboptions.items()):
5166 assert subopt not in (b'name', b'url')
5161 assert subopt not in (b'name', b'url')
5167 if showsubopts:
5162 if showsubopts:
5168 fm.plain(b'%s:%s = ' % (name, subopt))
5163 fm.plain(b'%s:%s = ' % (name, subopt))
5169 if isinstance(value, bool):
5164 if isinstance(value, bool):
5170 if value:
5165 if value:
5171 value = b'yes'
5166 value = b'yes'
5172 else:
5167 else:
5173 value = b'no'
5168 value = b'no'
5174 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5169 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5175
5170
5176 fm.end()
5171 fm.end()
5177
5172
5178 if search and not pathitems:
5173 if search and not pathitems:
5179 if not ui.quiet:
5174 if not ui.quiet:
5180 ui.warn(_(b"not found!\n"))
5175 ui.warn(_(b"not found!\n"))
5181 return 1
5176 return 1
5182 else:
5177 else:
5183 return 0
5178 return 0
5184
5179
5185
5180
5186 @command(
5181 @command(
5187 b'phase',
5182 b'phase',
5188 [
5183 [
5189 (b'p', b'public', False, _(b'set changeset phase to public')),
5184 (b'p', b'public', False, _(b'set changeset phase to public')),
5190 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5185 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5191 (b's', b'secret', False, _(b'set changeset phase to secret')),
5186 (b's', b'secret', False, _(b'set changeset phase to secret')),
5192 (b'f', b'force', False, _(b'allow to move boundary backward')),
5187 (b'f', b'force', False, _(b'allow to move boundary backward')),
5193 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5188 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5194 ],
5189 ],
5195 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5190 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5196 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5191 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5197 )
5192 )
5198 def phase(ui, repo, *revs, **opts):
5193 def phase(ui, repo, *revs, **opts):
5199 """set or show the current phase name
5194 """set or show the current phase name
5200
5195
5201 With no argument, show the phase name of the current revision(s).
5196 With no argument, show the phase name of the current revision(s).
5202
5197
5203 With one of -p/--public, -d/--draft or -s/--secret, change the
5198 With one of -p/--public, -d/--draft or -s/--secret, change the
5204 phase value of the specified revisions.
5199 phase value of the specified revisions.
5205
5200
5206 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5201 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5207 lower phase to a higher phase. Phases are ordered as follows::
5202 lower phase to a higher phase. Phases are ordered as follows::
5208
5203
5209 public < draft < secret
5204 public < draft < secret
5210
5205
5211 Returns 0 on success, 1 if some phases could not be changed.
5206 Returns 0 on success, 1 if some phases could not be changed.
5212
5207
5213 (For more information about the phases concept, see :hg:`help phases`.)
5208 (For more information about the phases concept, see :hg:`help phases`.)
5214 """
5209 """
5215 opts = pycompat.byteskwargs(opts)
5210 opts = pycompat.byteskwargs(opts)
5216 # search for a unique phase argument
5211 # search for a unique phase argument
5217 targetphase = None
5212 targetphase = None
5218 for idx, name in enumerate(phases.cmdphasenames):
5213 for idx, name in enumerate(phases.cmdphasenames):
5219 if opts[name]:
5214 if opts[name]:
5220 if targetphase is not None:
5215 if targetphase is not None:
5221 raise error.InputError(_(b'only one phase can be specified'))
5216 raise error.InputError(_(b'only one phase can be specified'))
5222 targetphase = idx
5217 targetphase = idx
5223
5218
5224 # look for specified revision
5219 # look for specified revision
5225 revs = list(revs)
5220 revs = list(revs)
5226 revs.extend(opts[b'rev'])
5221 revs.extend(opts[b'rev'])
5227 if not revs:
5222 if not revs:
5228 # display both parents as the second parent phase can influence
5223 # display both parents as the second parent phase can influence
5229 # the phase of a merge commit
5224 # the phase of a merge commit
5230 revs = [c.rev() for c in repo[None].parents()]
5225 revs = [c.rev() for c in repo[None].parents()]
5231
5226
5232 revs = scmutil.revrange(repo, revs)
5227 revs = scmutil.revrange(repo, revs)
5233
5228
5234 ret = 0
5229 ret = 0
5235 if targetphase is None:
5230 if targetphase is None:
5236 # display
5231 # display
5237 for r in revs:
5232 for r in revs:
5238 ctx = repo[r]
5233 ctx = repo[r]
5239 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5234 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5240 else:
5235 else:
5241 with repo.lock(), repo.transaction(b"phase") as tr:
5236 with repo.lock(), repo.transaction(b"phase") as tr:
5242 # set phase
5237 # set phase
5243 if not revs:
5238 if not revs:
5244 raise error.InputError(_(b'empty revision set'))
5239 raise error.InputError(_(b'empty revision set'))
5245 nodes = [repo[r].node() for r in revs]
5240 nodes = [repo[r].node() for r in revs]
5246 # moving revision from public to draft may hide them
5241 # moving revision from public to draft may hide them
5247 # We have to check result on an unfiltered repository
5242 # We have to check result on an unfiltered repository
5248 unfi = repo.unfiltered()
5243 unfi = repo.unfiltered()
5249 getphase = unfi._phasecache.phase
5244 getphase = unfi._phasecache.phase
5250 olddata = [getphase(unfi, r) for r in unfi]
5245 olddata = [getphase(unfi, r) for r in unfi]
5251 phases.advanceboundary(repo, tr, targetphase, nodes)
5246 phases.advanceboundary(repo, tr, targetphase, nodes)
5252 if opts[b'force']:
5247 if opts[b'force']:
5253 phases.retractboundary(repo, tr, targetphase, nodes)
5248 phases.retractboundary(repo, tr, targetphase, nodes)
5254 getphase = unfi._phasecache.phase
5249 getphase = unfi._phasecache.phase
5255 newdata = [getphase(unfi, r) for r in unfi]
5250 newdata = [getphase(unfi, r) for r in unfi]
5256 changes = sum(newdata[r] != olddata[r] for r in unfi)
5251 changes = sum(newdata[r] != olddata[r] for r in unfi)
5257 cl = unfi.changelog
5252 cl = unfi.changelog
5258 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5253 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5259 if rejected:
5254 if rejected:
5260 ui.warn(
5255 ui.warn(
5261 _(
5256 _(
5262 b'cannot move %i changesets to a higher '
5257 b'cannot move %i changesets to a higher '
5263 b'phase, use --force\n'
5258 b'phase, use --force\n'
5264 )
5259 )
5265 % len(rejected)
5260 % len(rejected)
5266 )
5261 )
5267 ret = 1
5262 ret = 1
5268 if changes:
5263 if changes:
5269 msg = _(b'phase changed for %i changesets\n') % changes
5264 msg = _(b'phase changed for %i changesets\n') % changes
5270 if ret:
5265 if ret:
5271 ui.status(msg)
5266 ui.status(msg)
5272 else:
5267 else:
5273 ui.note(msg)
5268 ui.note(msg)
5274 else:
5269 else:
5275 ui.warn(_(b'no phases changed\n'))
5270 ui.warn(_(b'no phases changed\n'))
5276 return ret
5271 return ret
5277
5272
5278
5273
5279 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5274 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5280 """Run after a changegroup has been added via pull/unbundle
5275 """Run after a changegroup has been added via pull/unbundle
5281
5276
5282 This takes arguments below:
5277 This takes arguments below:
5283
5278
5284 :modheads: change of heads by pull/unbundle
5279 :modheads: change of heads by pull/unbundle
5285 :optupdate: updating working directory is needed or not
5280 :optupdate: updating working directory is needed or not
5286 :checkout: update destination revision (or None to default destination)
5281 :checkout: update destination revision (or None to default destination)
5287 :brev: a name, which might be a bookmark to be activated after updating
5282 :brev: a name, which might be a bookmark to be activated after updating
5288
5283
5289 return True if update raise any conflict, False otherwise.
5284 return True if update raise any conflict, False otherwise.
5290 """
5285 """
5291 if modheads == 0:
5286 if modheads == 0:
5292 return False
5287 return False
5293 if optupdate:
5288 if optupdate:
5294 try:
5289 try:
5295 return hg.updatetotally(ui, repo, checkout, brev)
5290 return hg.updatetotally(ui, repo, checkout, brev)
5296 except error.UpdateAbort as inst:
5291 except error.UpdateAbort as inst:
5297 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5292 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5298 hint = inst.hint
5293 hint = inst.hint
5299 raise error.UpdateAbort(msg, hint=hint)
5294 raise error.UpdateAbort(msg, hint=hint)
5300 if modheads is not None and modheads > 1:
5295 if modheads is not None and modheads > 1:
5301 currentbranchheads = len(repo.branchheads())
5296 currentbranchheads = len(repo.branchheads())
5302 if currentbranchheads == modheads:
5297 if currentbranchheads == modheads:
5303 ui.status(
5298 ui.status(
5304 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5299 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5305 )
5300 )
5306 elif currentbranchheads > 1:
5301 elif currentbranchheads > 1:
5307 ui.status(
5302 ui.status(
5308 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5303 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5309 )
5304 )
5310 else:
5305 else:
5311 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5306 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5312 elif not ui.configbool(b'commands', b'update.requiredest'):
5307 elif not ui.configbool(b'commands', b'update.requiredest'):
5313 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5308 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5314 return False
5309 return False
5315
5310
5316
5311
5317 @command(
5312 @command(
5318 b'pull',
5313 b'pull',
5319 [
5314 [
5320 (
5315 (
5321 b'u',
5316 b'u',
5322 b'update',
5317 b'update',
5323 None,
5318 None,
5324 _(b'update to new branch head if new descendants were pulled'),
5319 _(b'update to new branch head if new descendants were pulled'),
5325 ),
5320 ),
5326 (
5321 (
5327 b'f',
5322 b'f',
5328 b'force',
5323 b'force',
5329 None,
5324 None,
5330 _(b'run even when remote repository is unrelated'),
5325 _(b'run even when remote repository is unrelated'),
5331 ),
5326 ),
5332 (
5327 (
5333 b'',
5328 b'',
5334 b'confirm',
5329 b'confirm',
5335 None,
5330 None,
5336 _(b'confirm pull before applying changes'),
5331 _(b'confirm pull before applying changes'),
5337 ),
5332 ),
5338 (
5333 (
5339 b'r',
5334 b'r',
5340 b'rev',
5335 b'rev',
5341 [],
5336 [],
5342 _(b'a remote changeset intended to be added'),
5337 _(b'a remote changeset intended to be added'),
5343 _(b'REV'),
5338 _(b'REV'),
5344 ),
5339 ),
5345 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5340 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5346 (
5341 (
5347 b'b',
5342 b'b',
5348 b'branch',
5343 b'branch',
5349 [],
5344 [],
5350 _(b'a specific branch you would like to pull'),
5345 _(b'a specific branch you would like to pull'),
5351 _(b'BRANCH'),
5346 _(b'BRANCH'),
5352 ),
5347 ),
5353 ]
5348 ]
5354 + remoteopts,
5349 + remoteopts,
5355 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5350 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5356 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5351 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5357 helpbasic=True,
5352 helpbasic=True,
5358 )
5353 )
5359 def pull(ui, repo, *sources, **opts):
5354 def pull(ui, repo, *sources, **opts):
5360 """pull changes from the specified source
5355 """pull changes from the specified source
5361
5356
5362 Pull changes from a remote repository to a local one.
5357 Pull changes from a remote repository to a local one.
5363
5358
5364 This finds all changes from the repository at the specified path
5359 This finds all changes from the repository at the specified path
5365 or URL and adds them to a local repository (the current one unless
5360 or URL and adds them to a local repository (the current one unless
5366 -R is specified). By default, this does not update the copy of the
5361 -R is specified). By default, this does not update the copy of the
5367 project in the working directory.
5362 project in the working directory.
5368
5363
5369 When cloning from servers that support it, Mercurial may fetch
5364 When cloning from servers that support it, Mercurial may fetch
5370 pre-generated data. When this is done, hooks operating on incoming
5365 pre-generated data. When this is done, hooks operating on incoming
5371 changesets and changegroups may fire more than once, once for each
5366 changesets and changegroups may fire more than once, once for each
5372 pre-generated bundle and as well as for any additional remaining
5367 pre-generated bundle and as well as for any additional remaining
5373 data. See :hg:`help -e clonebundles` for more.
5368 data. See :hg:`help -e clonebundles` for more.
5374
5369
5375 Use :hg:`incoming` if you want to see what would have been added
5370 Use :hg:`incoming` if you want to see what would have been added
5376 by a pull at the time you issued this command. If you then decide
5371 by a pull at the time you issued this command. If you then decide
5377 to add those changes to the repository, you should use :hg:`pull
5372 to add those changes to the repository, you should use :hg:`pull
5378 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5373 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5379
5374
5380 If SOURCE is omitted, the 'default' path will be used.
5375 If SOURCE is omitted, the 'default' path will be used.
5381 See :hg:`help urls` for more information.
5376 See :hg:`help urls` for more information.
5382
5377
5383 If multiple sources are specified, they will be pulled sequentially as if
5378 If multiple sources are specified, they will be pulled sequentially as if
5384 the command was run multiple time. If --update is specify and the command
5379 the command was run multiple time. If --update is specify and the command
5385 will stop at the first failed --update.
5380 will stop at the first failed --update.
5386
5381
5387 Specifying bookmark as ``.`` is equivalent to specifying the active
5382 Specifying bookmark as ``.`` is equivalent to specifying the active
5388 bookmark's name.
5383 bookmark's name.
5389
5384
5390 Returns 0 on success, 1 if an update had unresolved files.
5385 Returns 0 on success, 1 if an update had unresolved files.
5391 """
5386 """
5392
5387
5393 opts = pycompat.byteskwargs(opts)
5388 opts = pycompat.byteskwargs(opts)
5394 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5389 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5395 b'update'
5390 b'update'
5396 ):
5391 ):
5397 msg = _(b'update destination required by configuration')
5392 msg = _(b'update destination required by configuration')
5398 hint = _(b'use hg pull followed by hg update DEST')
5393 hint = _(b'use hg pull followed by hg update DEST')
5399 raise error.InputError(msg, hint=hint)
5394 raise error.InputError(msg, hint=hint)
5400
5395
5401 sources = urlutil.get_pull_paths(repo, ui, sources, opts.get(b'branch'))
5396 sources = urlutil.get_pull_paths(repo, ui, sources, opts.get(b'branch'))
5402 for source, branches in sources:
5397 for source, branches in sources:
5403 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5398 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5404 ui.flush()
5399 ui.flush()
5405 other = hg.peer(repo, opts, source)
5400 other = hg.peer(repo, opts, source)
5406 update_conflict = None
5401 update_conflict = None
5407 try:
5402 try:
5408 revs, checkout = hg.addbranchrevs(
5403 revs, checkout = hg.addbranchrevs(
5409 repo, other, branches, opts.get(b'rev')
5404 repo, other, branches, opts.get(b'rev')
5410 )
5405 )
5411
5406
5412 pullopargs = {}
5407 pullopargs = {}
5413
5408
5414 nodes = None
5409 nodes = None
5415 if opts.get(b'bookmark') or revs:
5410 if opts.get(b'bookmark') or revs:
5416 # The list of bookmark used here is the same used to actually update
5411 # The list of bookmark used here is the same used to actually update
5417 # the bookmark names, to avoid the race from issue 4689 and we do
5412 # the bookmark names, to avoid the race from issue 4689 and we do
5418 # all lookup and bookmark queries in one go so they see the same
5413 # all lookup and bookmark queries in one go so they see the same
5419 # version of the server state (issue 4700).
5414 # version of the server state (issue 4700).
5420 nodes = []
5415 nodes = []
5421 fnodes = []
5416 fnodes = []
5422 revs = revs or []
5417 revs = revs or []
5423 if revs and not other.capable(b'lookup'):
5418 if revs and not other.capable(b'lookup'):
5424 err = _(
5419 err = _(
5425 b"other repository doesn't support revision lookup, "
5420 b"other repository doesn't support revision lookup, "
5426 b"so a rev cannot be specified."
5421 b"so a rev cannot be specified."
5427 )
5422 )
5428 raise error.Abort(err)
5423 raise error.Abort(err)
5429 with other.commandexecutor() as e:
5424 with other.commandexecutor() as e:
5430 fremotebookmarks = e.callcommand(
5425 fremotebookmarks = e.callcommand(
5431 b'listkeys', {b'namespace': b'bookmarks'}
5426 b'listkeys', {b'namespace': b'bookmarks'}
5432 )
5427 )
5433 for r in revs:
5428 for r in revs:
5434 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5429 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5435 remotebookmarks = fremotebookmarks.result()
5430 remotebookmarks = fremotebookmarks.result()
5436 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5431 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5437 pullopargs[b'remotebookmarks'] = remotebookmarks
5432 pullopargs[b'remotebookmarks'] = remotebookmarks
5438 for b in opts.get(b'bookmark', []):
5433 for b in opts.get(b'bookmark', []):
5439 b = repo._bookmarks.expandname(b)
5434 b = repo._bookmarks.expandname(b)
5440 if b not in remotebookmarks:
5435 if b not in remotebookmarks:
5441 raise error.InputError(
5436 raise error.InputError(
5442 _(b'remote bookmark %s not found!') % b
5437 _(b'remote bookmark %s not found!') % b
5443 )
5438 )
5444 nodes.append(remotebookmarks[b])
5439 nodes.append(remotebookmarks[b])
5445 for i, rev in enumerate(revs):
5440 for i, rev in enumerate(revs):
5446 node = fnodes[i].result()
5441 node = fnodes[i].result()
5447 nodes.append(node)
5442 nodes.append(node)
5448 if rev == checkout:
5443 if rev == checkout:
5449 checkout = node
5444 checkout = node
5450
5445
5451 wlock = util.nullcontextmanager()
5446 wlock = util.nullcontextmanager()
5452 if opts.get(b'update'):
5447 if opts.get(b'update'):
5453 wlock = repo.wlock()
5448 wlock = repo.wlock()
5454 with wlock:
5449 with wlock:
5455 pullopargs.update(opts.get(b'opargs', {}))
5450 pullopargs.update(opts.get(b'opargs', {}))
5456 modheads = exchange.pull(
5451 modheads = exchange.pull(
5457 repo,
5452 repo,
5458 other,
5453 other,
5459 heads=nodes,
5454 heads=nodes,
5460 force=opts.get(b'force'),
5455 force=opts.get(b'force'),
5461 bookmarks=opts.get(b'bookmark', ()),
5456 bookmarks=opts.get(b'bookmark', ()),
5462 opargs=pullopargs,
5457 opargs=pullopargs,
5463 confirm=opts.get(b'confirm'),
5458 confirm=opts.get(b'confirm'),
5464 ).cgresult
5459 ).cgresult
5465
5460
5466 # brev is a name, which might be a bookmark to be activated at
5461 # brev is a name, which might be a bookmark to be activated at
5467 # the end of the update. In other words, it is an explicit
5462 # the end of the update. In other words, it is an explicit
5468 # destination of the update
5463 # destination of the update
5469 brev = None
5464 brev = None
5470
5465
5471 if checkout:
5466 if checkout:
5472 checkout = repo.unfiltered().changelog.rev(checkout)
5467 checkout = repo.unfiltered().changelog.rev(checkout)
5473
5468
5474 # order below depends on implementation of
5469 # order below depends on implementation of
5475 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5470 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5476 # because 'checkout' is determined without it.
5471 # because 'checkout' is determined without it.
5477 if opts.get(b'rev'):
5472 if opts.get(b'rev'):
5478 brev = opts[b'rev'][0]
5473 brev = opts[b'rev'][0]
5479 elif opts.get(b'branch'):
5474 elif opts.get(b'branch'):
5480 brev = opts[b'branch'][0]
5475 brev = opts[b'branch'][0]
5481 else:
5476 else:
5482 brev = branches[0]
5477 brev = branches[0]
5483 repo._subtoppath = source
5478 repo._subtoppath = source
5484 try:
5479 try:
5485 update_conflict = postincoming(
5480 update_conflict = postincoming(
5486 ui, repo, modheads, opts.get(b'update'), checkout, brev
5481 ui, repo, modheads, opts.get(b'update'), checkout, brev
5487 )
5482 )
5488 except error.FilteredRepoLookupError as exc:
5483 except error.FilteredRepoLookupError as exc:
5489 msg = _(b'cannot update to target: %s') % exc.args[0]
5484 msg = _(b'cannot update to target: %s') % exc.args[0]
5490 exc.args = (msg,) + exc.args[1:]
5485 exc.args = (msg,) + exc.args[1:]
5491 raise
5486 raise
5492 finally:
5487 finally:
5493 del repo._subtoppath
5488 del repo._subtoppath
5494
5489
5495 finally:
5490 finally:
5496 other.close()
5491 other.close()
5497 # skip the remaining pull source if they are some conflict.
5492 # skip the remaining pull source if they are some conflict.
5498 if update_conflict:
5493 if update_conflict:
5499 break
5494 break
5500 if update_conflict:
5495 if update_conflict:
5501 return 1
5496 return 1
5502 else:
5497 else:
5503 return 0
5498 return 0
5504
5499
5505
5500
5506 @command(
5501 @command(
5507 b'purge|clean',
5502 b'purge|clean',
5508 [
5503 [
5509 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5504 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5510 (b'', b'all', None, _(b'purge ignored files too')),
5505 (b'', b'all', None, _(b'purge ignored files too')),
5511 (b'i', b'ignored', None, _(b'purge only ignored files')),
5506 (b'i', b'ignored', None, _(b'purge only ignored files')),
5512 (b'', b'dirs', None, _(b'purge empty directories')),
5507 (b'', b'dirs', None, _(b'purge empty directories')),
5513 (b'', b'files', None, _(b'purge files')),
5508 (b'', b'files', None, _(b'purge files')),
5514 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5509 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5515 (
5510 (
5516 b'0',
5511 b'0',
5517 b'print0',
5512 b'print0',
5518 None,
5513 None,
5519 _(
5514 _(
5520 b'end filenames with NUL, for use with xargs'
5515 b'end filenames with NUL, for use with xargs'
5521 b' (implies -p/--print)'
5516 b' (implies -p/--print)'
5522 ),
5517 ),
5523 ),
5518 ),
5524 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5519 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5525 ]
5520 ]
5526 + cmdutil.walkopts,
5521 + cmdutil.walkopts,
5527 _(b'hg purge [OPTION]... [DIR]...'),
5522 _(b'hg purge [OPTION]... [DIR]...'),
5528 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5523 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5529 )
5524 )
5530 def purge(ui, repo, *dirs, **opts):
5525 def purge(ui, repo, *dirs, **opts):
5531 """removes files not tracked by Mercurial
5526 """removes files not tracked by Mercurial
5532
5527
5533 Delete files not known to Mercurial. This is useful to test local
5528 Delete files not known to Mercurial. This is useful to test local
5534 and uncommitted changes in an otherwise-clean source tree.
5529 and uncommitted changes in an otherwise-clean source tree.
5535
5530
5536 This means that purge will delete the following by default:
5531 This means that purge will delete the following by default:
5537
5532
5538 - Unknown files: files marked with "?" by :hg:`status`
5533 - Unknown files: files marked with "?" by :hg:`status`
5539 - Empty directories: in fact Mercurial ignores directories unless
5534 - Empty directories: in fact Mercurial ignores directories unless
5540 they contain files under source control management
5535 they contain files under source control management
5541
5536
5542 But it will leave untouched:
5537 But it will leave untouched:
5543
5538
5544 - Modified and unmodified tracked files
5539 - Modified and unmodified tracked files
5545 - Ignored files (unless -i or --all is specified)
5540 - Ignored files (unless -i or --all is specified)
5546 - New files added to the repository (with :hg:`add`)
5541 - New files added to the repository (with :hg:`add`)
5547
5542
5548 The --files and --dirs options can be used to direct purge to delete
5543 The --files and --dirs options can be used to direct purge to delete
5549 only files, only directories, or both. If neither option is given,
5544 only files, only directories, or both. If neither option is given,
5550 both will be deleted.
5545 both will be deleted.
5551
5546
5552 If directories are given on the command line, only files in these
5547 If directories are given on the command line, only files in these
5553 directories are considered.
5548 directories are considered.
5554
5549
5555 Be careful with purge, as you could irreversibly delete some files
5550 Be careful with purge, as you could irreversibly delete some files
5556 you forgot to add to the repository. If you only want to print the
5551 you forgot to add to the repository. If you only want to print the
5557 list of files that this program would delete, use the --print
5552 list of files that this program would delete, use the --print
5558 option.
5553 option.
5559 """
5554 """
5560 opts = pycompat.byteskwargs(opts)
5555 opts = pycompat.byteskwargs(opts)
5561 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5556 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5562
5557
5563 act = not opts.get(b'print')
5558 act = not opts.get(b'print')
5564 eol = b'\n'
5559 eol = b'\n'
5565 if opts.get(b'print0'):
5560 if opts.get(b'print0'):
5566 eol = b'\0'
5561 eol = b'\0'
5567 act = False # --print0 implies --print
5562 act = False # --print0 implies --print
5568 if opts.get(b'all', False):
5563 if opts.get(b'all', False):
5569 ignored = True
5564 ignored = True
5570 unknown = True
5565 unknown = True
5571 else:
5566 else:
5572 ignored = opts.get(b'ignored', False)
5567 ignored = opts.get(b'ignored', False)
5573 unknown = not ignored
5568 unknown = not ignored
5574
5569
5575 removefiles = opts.get(b'files')
5570 removefiles = opts.get(b'files')
5576 removedirs = opts.get(b'dirs')
5571 removedirs = opts.get(b'dirs')
5577 confirm = opts.get(b'confirm')
5572 confirm = opts.get(b'confirm')
5578 if confirm is None:
5573 if confirm is None:
5579 try:
5574 try:
5580 extensions.find(b'purge')
5575 extensions.find(b'purge')
5581 confirm = False
5576 confirm = False
5582 except KeyError:
5577 except KeyError:
5583 confirm = True
5578 confirm = True
5584
5579
5585 if not removefiles and not removedirs:
5580 if not removefiles and not removedirs:
5586 removefiles = True
5581 removefiles = True
5587 removedirs = True
5582 removedirs = True
5588
5583
5589 match = scmutil.match(repo[None], dirs, opts)
5584 match = scmutil.match(repo[None], dirs, opts)
5590
5585
5591 paths = mergemod.purge(
5586 paths = mergemod.purge(
5592 repo,
5587 repo,
5593 match,
5588 match,
5594 unknown=unknown,
5589 unknown=unknown,
5595 ignored=ignored,
5590 ignored=ignored,
5596 removeemptydirs=removedirs,
5591 removeemptydirs=removedirs,
5597 removefiles=removefiles,
5592 removefiles=removefiles,
5598 abortonerror=opts.get(b'abort_on_err'),
5593 abortonerror=opts.get(b'abort_on_err'),
5599 noop=not act,
5594 noop=not act,
5600 confirm=confirm,
5595 confirm=confirm,
5601 )
5596 )
5602
5597
5603 for path in paths:
5598 for path in paths:
5604 if not act:
5599 if not act:
5605 ui.write(b'%s%s' % (path, eol))
5600 ui.write(b'%s%s' % (path, eol))
5606
5601
5607
5602
5608 @command(
5603 @command(
5609 b'push',
5604 b'push',
5610 [
5605 [
5611 (b'f', b'force', None, _(b'force push')),
5606 (b'f', b'force', None, _(b'force push')),
5612 (
5607 (
5613 b'r',
5608 b'r',
5614 b'rev',
5609 b'rev',
5615 [],
5610 [],
5616 _(b'a changeset intended to be included in the destination'),
5611 _(b'a changeset intended to be included in the destination'),
5617 _(b'REV'),
5612 _(b'REV'),
5618 ),
5613 ),
5619 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5614 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5620 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5615 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5621 (
5616 (
5622 b'b',
5617 b'b',
5623 b'branch',
5618 b'branch',
5624 [],
5619 [],
5625 _(b'a specific branch you would like to push'),
5620 _(b'a specific branch you would like to push'),
5626 _(b'BRANCH'),
5621 _(b'BRANCH'),
5627 ),
5622 ),
5628 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5623 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5629 (
5624 (
5630 b'',
5625 b'',
5631 b'pushvars',
5626 b'pushvars',
5632 [],
5627 [],
5633 _(b'variables that can be sent to server (ADVANCED)'),
5628 _(b'variables that can be sent to server (ADVANCED)'),
5634 ),
5629 ),
5635 (
5630 (
5636 b'',
5631 b'',
5637 b'publish',
5632 b'publish',
5638 False,
5633 False,
5639 _(b'push the changeset as public (EXPERIMENTAL)'),
5634 _(b'push the changeset as public (EXPERIMENTAL)'),
5640 ),
5635 ),
5641 ]
5636 ]
5642 + remoteopts,
5637 + remoteopts,
5643 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5638 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5644 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5639 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5645 helpbasic=True,
5640 helpbasic=True,
5646 )
5641 )
5647 def push(ui, repo, *dests, **opts):
5642 def push(ui, repo, *dests, **opts):
5648 """push changes to the specified destination
5643 """push changes to the specified destination
5649
5644
5650 Push changesets from the local repository to the specified
5645 Push changesets from the local repository to the specified
5651 destination.
5646 destination.
5652
5647
5653 This operation is symmetrical to pull: it is identical to a pull
5648 This operation is symmetrical to pull: it is identical to a pull
5654 in the destination repository from the current one.
5649 in the destination repository from the current one.
5655
5650
5656 By default, push will not allow creation of new heads at the
5651 By default, push will not allow creation of new heads at the
5657 destination, since multiple heads would make it unclear which head
5652 destination, since multiple heads would make it unclear which head
5658 to use. In this situation, it is recommended to pull and merge
5653 to use. In this situation, it is recommended to pull and merge
5659 before pushing.
5654 before pushing.
5660
5655
5661 Use --new-branch if you want to allow push to create a new named
5656 Use --new-branch if you want to allow push to create a new named
5662 branch that is not present at the destination. This allows you to
5657 branch that is not present at the destination. This allows you to
5663 only create a new branch without forcing other changes.
5658 only create a new branch without forcing other changes.
5664
5659
5665 .. note::
5660 .. note::
5666
5661
5667 Extra care should be taken with the -f/--force option,
5662 Extra care should be taken with the -f/--force option,
5668 which will push all new heads on all branches, an action which will
5663 which will push all new heads on all branches, an action which will
5669 almost always cause confusion for collaborators.
5664 almost always cause confusion for collaborators.
5670
5665
5671 If -r/--rev is used, the specified revision and all its ancestors
5666 If -r/--rev is used, the specified revision and all its ancestors
5672 will be pushed to the remote repository.
5667 will be pushed to the remote repository.
5673
5668
5674 If -B/--bookmark is used, the specified bookmarked revision, its
5669 If -B/--bookmark is used, the specified bookmarked revision, its
5675 ancestors, and the bookmark will be pushed to the remote
5670 ancestors, and the bookmark will be pushed to the remote
5676 repository. Specifying ``.`` is equivalent to specifying the active
5671 repository. Specifying ``.`` is equivalent to specifying the active
5677 bookmark's name. Use the --all-bookmarks option for pushing all
5672 bookmark's name. Use the --all-bookmarks option for pushing all
5678 current bookmarks.
5673 current bookmarks.
5679
5674
5680 Please see :hg:`help urls` for important details about ``ssh://``
5675 Please see :hg:`help urls` for important details about ``ssh://``
5681 URLs. If DESTINATION is omitted, a default path will be used.
5676 URLs. If DESTINATION is omitted, a default path will be used.
5682
5677
5683 When passed multiple destinations, push will process them one after the
5678 When passed multiple destinations, push will process them one after the
5684 other, but stop should an error occur.
5679 other, but stop should an error occur.
5685
5680
5686 .. container:: verbose
5681 .. container:: verbose
5687
5682
5688 The --pushvars option sends strings to the server that become
5683 The --pushvars option sends strings to the server that become
5689 environment variables prepended with ``HG_USERVAR_``. For example,
5684 environment variables prepended with ``HG_USERVAR_``. For example,
5690 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5685 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5691 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5686 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5692
5687
5693 pushvars can provide for user-overridable hooks as well as set debug
5688 pushvars can provide for user-overridable hooks as well as set debug
5694 levels. One example is having a hook that blocks commits containing
5689 levels. One example is having a hook that blocks commits containing
5695 conflict markers, but enables the user to override the hook if the file
5690 conflict markers, but enables the user to override the hook if the file
5696 is using conflict markers for testing purposes or the file format has
5691 is using conflict markers for testing purposes or the file format has
5697 strings that look like conflict markers.
5692 strings that look like conflict markers.
5698
5693
5699 By default, servers will ignore `--pushvars`. To enable it add the
5694 By default, servers will ignore `--pushvars`. To enable it add the
5700 following to your configuration file::
5695 following to your configuration file::
5701
5696
5702 [push]
5697 [push]
5703 pushvars.server = true
5698 pushvars.server = true
5704
5699
5705 Returns 0 if push was successful, 1 if nothing to push.
5700 Returns 0 if push was successful, 1 if nothing to push.
5706 """
5701 """
5707
5702
5708 opts = pycompat.byteskwargs(opts)
5703 opts = pycompat.byteskwargs(opts)
5709
5704
5710 if opts.get(b'all_bookmarks'):
5705 if opts.get(b'all_bookmarks'):
5711 cmdutil.check_incompatible_arguments(
5706 cmdutil.check_incompatible_arguments(
5712 opts,
5707 opts,
5713 b'all_bookmarks',
5708 b'all_bookmarks',
5714 [b'bookmark', b'rev'],
5709 [b'bookmark', b'rev'],
5715 )
5710 )
5716 opts[b'bookmark'] = list(repo._bookmarks)
5711 opts[b'bookmark'] = list(repo._bookmarks)
5717
5712
5718 if opts.get(b'bookmark'):
5713 if opts.get(b'bookmark'):
5719 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5714 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5720 for b in opts[b'bookmark']:
5715 for b in opts[b'bookmark']:
5721 # translate -B options to -r so changesets get pushed
5716 # translate -B options to -r so changesets get pushed
5722 b = repo._bookmarks.expandname(b)
5717 b = repo._bookmarks.expandname(b)
5723 if b in repo._bookmarks:
5718 if b in repo._bookmarks:
5724 opts.setdefault(b'rev', []).append(b)
5719 opts.setdefault(b'rev', []).append(b)
5725 else:
5720 else:
5726 # if we try to push a deleted bookmark, translate it to null
5721 # if we try to push a deleted bookmark, translate it to null
5727 # this lets simultaneous -r, -b options continue working
5722 # this lets simultaneous -r, -b options continue working
5728 opts.setdefault(b'rev', []).append(b"null")
5723 opts.setdefault(b'rev', []).append(b"null")
5729
5724
5730 some_pushed = False
5725 some_pushed = False
5731 result = 0
5726 result = 0
5732 for path in urlutil.get_push_paths(repo, ui, dests):
5727 for path in urlutil.get_push_paths(repo, ui, dests):
5733 dest = path.pushloc or path.loc
5728 dest = path.pushloc or path.loc
5734 branches = (path.branch, opts.get(b'branch') or [])
5729 branches = (path.branch, opts.get(b'branch') or [])
5735 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5730 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5736 revs, checkout = hg.addbranchrevs(
5731 revs, checkout = hg.addbranchrevs(
5737 repo, repo, branches, opts.get(b'rev')
5732 repo, repo, branches, opts.get(b'rev')
5738 )
5733 )
5739 other = hg.peer(repo, opts, dest)
5734 other = hg.peer(repo, opts, dest)
5740
5735
5741 try:
5736 try:
5742 if revs:
5737 if revs:
5743 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5738 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5744 if not revs:
5739 if not revs:
5745 raise error.InputError(
5740 raise error.InputError(
5746 _(b"specified revisions evaluate to an empty set"),
5741 _(b"specified revisions evaluate to an empty set"),
5747 hint=_(b"use different revision arguments"),
5742 hint=_(b"use different revision arguments"),
5748 )
5743 )
5749 elif path.pushrev:
5744 elif path.pushrev:
5750 # It doesn't make any sense to specify ancestor revisions. So limit
5745 # It doesn't make any sense to specify ancestor revisions. So limit
5751 # to DAG heads to make discovery simpler.
5746 # to DAG heads to make discovery simpler.
5752 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5747 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5753 revs = scmutil.revrange(repo, [expr])
5748 revs = scmutil.revrange(repo, [expr])
5754 revs = [repo[rev].node() for rev in revs]
5749 revs = [repo[rev].node() for rev in revs]
5755 if not revs:
5750 if not revs:
5756 raise error.InputError(
5751 raise error.InputError(
5757 _(
5752 _(
5758 b'default push revset for path evaluates to an empty set'
5753 b'default push revset for path evaluates to an empty set'
5759 )
5754 )
5760 )
5755 )
5761 elif ui.configbool(b'commands', b'push.require-revs'):
5756 elif ui.configbool(b'commands', b'push.require-revs'):
5762 raise error.InputError(
5757 raise error.InputError(
5763 _(b'no revisions specified to push'),
5758 _(b'no revisions specified to push'),
5764 hint=_(b'did you mean "hg push -r ."?'),
5759 hint=_(b'did you mean "hg push -r ."?'),
5765 )
5760 )
5766
5761
5767 repo._subtoppath = dest
5762 repo._subtoppath = dest
5768 try:
5763 try:
5769 # push subrepos depth-first for coherent ordering
5764 # push subrepos depth-first for coherent ordering
5770 c = repo[b'.']
5765 c = repo[b'.']
5771 subs = c.substate # only repos that are committed
5766 subs = c.substate # only repos that are committed
5772 for s in sorted(subs):
5767 for s in sorted(subs):
5773 sub_result = c.sub(s).push(opts)
5768 sub_result = c.sub(s).push(opts)
5774 if sub_result == 0:
5769 if sub_result == 0:
5775 return 1
5770 return 1
5776 finally:
5771 finally:
5777 del repo._subtoppath
5772 del repo._subtoppath
5778
5773
5779 opargs = dict(
5774 opargs = dict(
5780 opts.get(b'opargs', {})
5775 opts.get(b'opargs', {})
5781 ) # copy opargs since we may mutate it
5776 ) # copy opargs since we may mutate it
5782 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5777 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5783
5778
5784 pushop = exchange.push(
5779 pushop = exchange.push(
5785 repo,
5780 repo,
5786 other,
5781 other,
5787 opts.get(b'force'),
5782 opts.get(b'force'),
5788 revs=revs,
5783 revs=revs,
5789 newbranch=opts.get(b'new_branch'),
5784 newbranch=opts.get(b'new_branch'),
5790 bookmarks=opts.get(b'bookmark', ()),
5785 bookmarks=opts.get(b'bookmark', ()),
5791 publish=opts.get(b'publish'),
5786 publish=opts.get(b'publish'),
5792 opargs=opargs,
5787 opargs=opargs,
5793 )
5788 )
5794
5789
5795 if pushop.cgresult == 0:
5790 if pushop.cgresult == 0:
5796 result = 1
5791 result = 1
5797 elif pushop.cgresult is not None:
5792 elif pushop.cgresult is not None:
5798 some_pushed = True
5793 some_pushed = True
5799
5794
5800 if pushop.bkresult is not None:
5795 if pushop.bkresult is not None:
5801 if pushop.bkresult == 2:
5796 if pushop.bkresult == 2:
5802 result = 2
5797 result = 2
5803 elif not result and pushop.bkresult:
5798 elif not result and pushop.bkresult:
5804 result = 2
5799 result = 2
5805
5800
5806 if result:
5801 if result:
5807 break
5802 break
5808
5803
5809 finally:
5804 finally:
5810 other.close()
5805 other.close()
5811 if result == 0 and not some_pushed:
5806 if result == 0 and not some_pushed:
5812 result = 1
5807 result = 1
5813 return result
5808 return result
5814
5809
5815
5810
5816 @command(
5811 @command(
5817 b'recover',
5812 b'recover',
5818 [
5813 [
5819 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5814 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5820 ],
5815 ],
5821 helpcategory=command.CATEGORY_MAINTENANCE,
5816 helpcategory=command.CATEGORY_MAINTENANCE,
5822 )
5817 )
5823 def recover(ui, repo, **opts):
5818 def recover(ui, repo, **opts):
5824 """roll back an interrupted transaction
5819 """roll back an interrupted transaction
5825
5820
5826 Recover from an interrupted commit or pull.
5821 Recover from an interrupted commit or pull.
5827
5822
5828 This command tries to fix the repository status after an
5823 This command tries to fix the repository status after an
5829 interrupted operation. It should only be necessary when Mercurial
5824 interrupted operation. It should only be necessary when Mercurial
5830 suggests it.
5825 suggests it.
5831
5826
5832 Returns 0 if successful, 1 if nothing to recover or verify fails.
5827 Returns 0 if successful, 1 if nothing to recover or verify fails.
5833 """
5828 """
5834 ret = repo.recover()
5829 ret = repo.recover()
5835 if ret:
5830 if ret:
5836 if opts['verify']:
5831 if opts['verify']:
5837 return hg.verify(repo)
5832 return hg.verify(repo)
5838 else:
5833 else:
5839 msg = _(
5834 msg = _(
5840 b"(verify step skipped, run `hg verify` to check your "
5835 b"(verify step skipped, run `hg verify` to check your "
5841 b"repository content)\n"
5836 b"repository content)\n"
5842 )
5837 )
5843 ui.warn(msg)
5838 ui.warn(msg)
5844 return 0
5839 return 0
5845 return 1
5840 return 1
5846
5841
5847
5842
5848 @command(
5843 @command(
5849 b'remove|rm',
5844 b'remove|rm',
5850 [
5845 [
5851 (b'A', b'after', None, _(b'record delete for missing files')),
5846 (b'A', b'after', None, _(b'record delete for missing files')),
5852 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5847 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5853 ]
5848 ]
5854 + subrepoopts
5849 + subrepoopts
5855 + walkopts
5850 + walkopts
5856 + dryrunopts,
5851 + dryrunopts,
5857 _(b'[OPTION]... FILE...'),
5852 _(b'[OPTION]... FILE...'),
5858 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5853 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5859 helpbasic=True,
5854 helpbasic=True,
5860 inferrepo=True,
5855 inferrepo=True,
5861 )
5856 )
5862 def remove(ui, repo, *pats, **opts):
5857 def remove(ui, repo, *pats, **opts):
5863 """remove the specified files on the next commit
5858 """remove the specified files on the next commit
5864
5859
5865 Schedule the indicated files for removal from the current branch.
5860 Schedule the indicated files for removal from the current branch.
5866
5861
5867 This command schedules the files to be removed at the next commit.
5862 This command schedules the files to be removed at the next commit.
5868 To undo a remove before that, see :hg:`revert`. To undo added
5863 To undo a remove before that, see :hg:`revert`. To undo added
5869 files, see :hg:`forget`.
5864 files, see :hg:`forget`.
5870
5865
5871 .. container:: verbose
5866 .. container:: verbose
5872
5867
5873 -A/--after can be used to remove only files that have already
5868 -A/--after can be used to remove only files that have already
5874 been deleted, -f/--force can be used to force deletion, and -Af
5869 been deleted, -f/--force can be used to force deletion, and -Af
5875 can be used to remove files from the next revision without
5870 can be used to remove files from the next revision without
5876 deleting them from the working directory.
5871 deleting them from the working directory.
5877
5872
5878 The following table details the behavior of remove for different
5873 The following table details the behavior of remove for different
5879 file states (columns) and option combinations (rows). The file
5874 file states (columns) and option combinations (rows). The file
5880 states are Added [A], Clean [C], Modified [M] and Missing [!]
5875 states are Added [A], Clean [C], Modified [M] and Missing [!]
5881 (as reported by :hg:`status`). The actions are Warn, Remove
5876 (as reported by :hg:`status`). The actions are Warn, Remove
5882 (from branch) and Delete (from disk):
5877 (from branch) and Delete (from disk):
5883
5878
5884 ========= == == == ==
5879 ========= == == == ==
5885 opt/state A C M !
5880 opt/state A C M !
5886 ========= == == == ==
5881 ========= == == == ==
5887 none W RD W R
5882 none W RD W R
5888 -f R RD RD R
5883 -f R RD RD R
5889 -A W W W R
5884 -A W W W R
5890 -Af R R R R
5885 -Af R R R R
5891 ========= == == == ==
5886 ========= == == == ==
5892
5887
5893 .. note::
5888 .. note::
5894
5889
5895 :hg:`remove` never deletes files in Added [A] state from the
5890 :hg:`remove` never deletes files in Added [A] state from the
5896 working directory, not even if ``--force`` is specified.
5891 working directory, not even if ``--force`` is specified.
5897
5892
5898 Returns 0 on success, 1 if any warnings encountered.
5893 Returns 0 on success, 1 if any warnings encountered.
5899 """
5894 """
5900
5895
5901 opts = pycompat.byteskwargs(opts)
5896 opts = pycompat.byteskwargs(opts)
5902 after, force = opts.get(b'after'), opts.get(b'force')
5897 after, force = opts.get(b'after'), opts.get(b'force')
5903 dryrun = opts.get(b'dry_run')
5898 dryrun = opts.get(b'dry_run')
5904 if not pats and not after:
5899 if not pats and not after:
5905 raise error.InputError(_(b'no files specified'))
5900 raise error.InputError(_(b'no files specified'))
5906
5901
5907 m = scmutil.match(repo[None], pats, opts)
5902 m = scmutil.match(repo[None], pats, opts)
5908 subrepos = opts.get(b'subrepos')
5903 subrepos = opts.get(b'subrepos')
5909 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5904 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5910 return cmdutil.remove(
5905 return cmdutil.remove(
5911 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5906 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5912 )
5907 )
5913
5908
5914
5909
5915 @command(
5910 @command(
5916 b'rename|move|mv',
5911 b'rename|move|mv',
5917 [
5912 [
5918 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5913 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5919 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5914 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5920 (
5915 (
5921 b'',
5916 b'',
5922 b'at-rev',
5917 b'at-rev',
5923 b'',
5918 b'',
5924 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5919 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5925 _(b'REV'),
5920 _(b'REV'),
5926 ),
5921 ),
5927 (
5922 (
5928 b'f',
5923 b'f',
5929 b'force',
5924 b'force',
5930 None,
5925 None,
5931 _(b'forcibly move over an existing managed file'),
5926 _(b'forcibly move over an existing managed file'),
5932 ),
5927 ),
5933 ]
5928 ]
5934 + walkopts
5929 + walkopts
5935 + dryrunopts,
5930 + dryrunopts,
5936 _(b'[OPTION]... SOURCE... DEST'),
5931 _(b'[OPTION]... SOURCE... DEST'),
5937 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5932 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5938 )
5933 )
5939 def rename(ui, repo, *pats, **opts):
5934 def rename(ui, repo, *pats, **opts):
5940 """rename files; equivalent of copy + remove
5935 """rename files; equivalent of copy + remove
5941
5936
5942 Mark dest as copies of sources; mark sources for deletion. If dest
5937 Mark dest as copies of sources; mark sources for deletion. If dest
5943 is a directory, copies are put in that directory. If dest is a
5938 is a directory, copies are put in that directory. If dest is a
5944 file, there can only be one source.
5939 file, there can only be one source.
5945
5940
5946 By default, this command copies the contents of files as they
5941 By default, this command copies the contents of files as they
5947 exist in the working directory. If invoked with -A/--after, the
5942 exist in the working directory. If invoked with -A/--after, the
5948 operation is recorded, but no copying is performed.
5943 operation is recorded, but no copying is performed.
5949
5944
5950 To undo marking a destination file as renamed, use --forget. With that
5945 To undo marking a destination file as renamed, use --forget. With that
5951 option, all given (positional) arguments are unmarked as renames. The
5946 option, all given (positional) arguments are unmarked as renames. The
5952 destination file(s) will be left in place (still tracked). The source
5947 destination file(s) will be left in place (still tracked). The source
5953 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5948 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5954 the same way as :hg:`copy --forget`.
5949 the same way as :hg:`copy --forget`.
5955
5950
5956 This command takes effect with the next commit by default.
5951 This command takes effect with the next commit by default.
5957
5952
5958 Returns 0 on success, 1 if errors are encountered.
5953 Returns 0 on success, 1 if errors are encountered.
5959 """
5954 """
5960 opts = pycompat.byteskwargs(opts)
5955 opts = pycompat.byteskwargs(opts)
5961 with repo.wlock():
5956 with repo.wlock():
5962 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5957 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5963
5958
5964
5959
5965 @command(
5960 @command(
5966 b'resolve',
5961 b'resolve',
5967 [
5962 [
5968 (b'a', b'all', None, _(b'select all unresolved files')),
5963 (b'a', b'all', None, _(b'select all unresolved files')),
5969 (b'l', b'list', None, _(b'list state of files needing merge')),
5964 (b'l', b'list', None, _(b'list state of files needing merge')),
5970 (b'm', b'mark', None, _(b'mark files as resolved')),
5965 (b'm', b'mark', None, _(b'mark files as resolved')),
5971 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5966 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5972 (b'n', b'no-status', None, _(b'hide status prefix')),
5967 (b'n', b'no-status', None, _(b'hide status prefix')),
5973 (b'', b're-merge', None, _(b're-merge files')),
5968 (b'', b're-merge', None, _(b're-merge files')),
5974 ]
5969 ]
5975 + mergetoolopts
5970 + mergetoolopts
5976 + walkopts
5971 + walkopts
5977 + formatteropts,
5972 + formatteropts,
5978 _(b'[OPTION]... [FILE]...'),
5973 _(b'[OPTION]... [FILE]...'),
5979 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5974 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5980 inferrepo=True,
5975 inferrepo=True,
5981 )
5976 )
5982 def resolve(ui, repo, *pats, **opts):
5977 def resolve(ui, repo, *pats, **opts):
5983 """redo merges or set/view the merge status of files
5978 """redo merges or set/view the merge status of files
5984
5979
5985 Merges with unresolved conflicts are often the result of
5980 Merges with unresolved conflicts are often the result of
5986 non-interactive merging using the ``internal:merge`` configuration
5981 non-interactive merging using the ``internal:merge`` configuration
5987 setting, or a command-line merge tool like ``diff3``. The resolve
5982 setting, or a command-line merge tool like ``diff3``. The resolve
5988 command is used to manage the files involved in a merge, after
5983 command is used to manage the files involved in a merge, after
5989 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5984 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5990 working directory must have two parents). See :hg:`help
5985 working directory must have two parents). See :hg:`help
5991 merge-tools` for information on configuring merge tools.
5986 merge-tools` for information on configuring merge tools.
5992
5987
5993 The resolve command can be used in the following ways:
5988 The resolve command can be used in the following ways:
5994
5989
5995 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5990 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5996 the specified files, discarding any previous merge attempts. Re-merging
5991 the specified files, discarding any previous merge attempts. Re-merging
5997 is not performed for files already marked as resolved. Use ``--all/-a``
5992 is not performed for files already marked as resolved. Use ``--all/-a``
5998 to select all unresolved files. ``--tool`` can be used to specify
5993 to select all unresolved files. ``--tool`` can be used to specify
5999 the merge tool used for the given files. It overrides the HGMERGE
5994 the merge tool used for the given files. It overrides the HGMERGE
6000 environment variable and your configuration files. Previous file
5995 environment variable and your configuration files. Previous file
6001 contents are saved with a ``.orig`` suffix.
5996 contents are saved with a ``.orig`` suffix.
6002
5997
6003 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5998 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6004 (e.g. after having manually fixed-up the files). The default is
5999 (e.g. after having manually fixed-up the files). The default is
6005 to mark all unresolved files.
6000 to mark all unresolved files.
6006
6001
6007 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6002 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6008 default is to mark all resolved files.
6003 default is to mark all resolved files.
6009
6004
6010 - :hg:`resolve -l`: list files which had or still have conflicts.
6005 - :hg:`resolve -l`: list files which had or still have conflicts.
6011 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6006 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6012 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6007 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6013 the list. See :hg:`help filesets` for details.
6008 the list. See :hg:`help filesets` for details.
6014
6009
6015 .. note::
6010 .. note::
6016
6011
6017 Mercurial will not let you commit files with unresolved merge
6012 Mercurial will not let you commit files with unresolved merge
6018 conflicts. You must use :hg:`resolve -m ...` before you can
6013 conflicts. You must use :hg:`resolve -m ...` before you can
6019 commit after a conflicting merge.
6014 commit after a conflicting merge.
6020
6015
6021 .. container:: verbose
6016 .. container:: verbose
6022
6017
6023 Template:
6018 Template:
6024
6019
6025 The following keywords are supported in addition to the common template
6020 The following keywords are supported in addition to the common template
6026 keywords and functions. See also :hg:`help templates`.
6021 keywords and functions. See also :hg:`help templates`.
6027
6022
6028 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6023 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6029 :path: String. Repository-absolute path of the file.
6024 :path: String. Repository-absolute path of the file.
6030
6025
6031 Returns 0 on success, 1 if any files fail a resolve attempt.
6026 Returns 0 on success, 1 if any files fail a resolve attempt.
6032 """
6027 """
6033
6028
6034 opts = pycompat.byteskwargs(opts)
6029 opts = pycompat.byteskwargs(opts)
6035 confirm = ui.configbool(b'commands', b'resolve.confirm')
6030 confirm = ui.configbool(b'commands', b'resolve.confirm')
6036 flaglist = b'all mark unmark list no_status re_merge'.split()
6031 flaglist = b'all mark unmark list no_status re_merge'.split()
6037 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6032 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6038
6033
6039 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6034 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6040 if actioncount > 1:
6035 if actioncount > 1:
6041 raise error.InputError(_(b"too many actions specified"))
6036 raise error.InputError(_(b"too many actions specified"))
6042 elif actioncount == 0 and ui.configbool(
6037 elif actioncount == 0 and ui.configbool(
6043 b'commands', b'resolve.explicit-re-merge'
6038 b'commands', b'resolve.explicit-re-merge'
6044 ):
6039 ):
6045 hint = _(b'use --mark, --unmark, --list or --re-merge')
6040 hint = _(b'use --mark, --unmark, --list or --re-merge')
6046 raise error.InputError(_(b'no action specified'), hint=hint)
6041 raise error.InputError(_(b'no action specified'), hint=hint)
6047 if pats and all:
6042 if pats and all:
6048 raise error.InputError(_(b"can't specify --all and patterns"))
6043 raise error.InputError(_(b"can't specify --all and patterns"))
6049 if not (all or pats or show or mark or unmark):
6044 if not (all or pats or show or mark or unmark):
6050 raise error.InputError(
6045 raise error.InputError(
6051 _(b'no files or directories specified'),
6046 _(b'no files or directories specified'),
6052 hint=b'use --all to re-merge all unresolved files',
6047 hint=b'use --all to re-merge all unresolved files',
6053 )
6048 )
6054
6049
6055 if confirm:
6050 if confirm:
6056 if all:
6051 if all:
6057 if ui.promptchoice(
6052 if ui.promptchoice(
6058 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6053 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6059 ):
6054 ):
6060 raise error.CanceledError(_(b'user quit'))
6055 raise error.CanceledError(_(b'user quit'))
6061 if mark and not pats:
6056 if mark and not pats:
6062 if ui.promptchoice(
6057 if ui.promptchoice(
6063 _(
6058 _(
6064 b'mark all unresolved files as resolved (yn)?'
6059 b'mark all unresolved files as resolved (yn)?'
6065 b'$$ &Yes $$ &No'
6060 b'$$ &Yes $$ &No'
6066 )
6061 )
6067 ):
6062 ):
6068 raise error.CanceledError(_(b'user quit'))
6063 raise error.CanceledError(_(b'user quit'))
6069 if unmark and not pats:
6064 if unmark and not pats:
6070 if ui.promptchoice(
6065 if ui.promptchoice(
6071 _(
6066 _(
6072 b'mark all resolved files as unresolved (yn)?'
6067 b'mark all resolved files as unresolved (yn)?'
6073 b'$$ &Yes $$ &No'
6068 b'$$ &Yes $$ &No'
6074 )
6069 )
6075 ):
6070 ):
6076 raise error.CanceledError(_(b'user quit'))
6071 raise error.CanceledError(_(b'user quit'))
6077
6072
6078 uipathfn = scmutil.getuipathfn(repo)
6073 uipathfn = scmutil.getuipathfn(repo)
6079
6074
6080 if show:
6075 if show:
6081 ui.pager(b'resolve')
6076 ui.pager(b'resolve')
6082 fm = ui.formatter(b'resolve', opts)
6077 fm = ui.formatter(b'resolve', opts)
6083 ms = mergestatemod.mergestate.read(repo)
6078 ms = mergestatemod.mergestate.read(repo)
6084 wctx = repo[None]
6079 wctx = repo[None]
6085 m = scmutil.match(wctx, pats, opts)
6080 m = scmutil.match(wctx, pats, opts)
6086
6081
6087 # Labels and keys based on merge state. Unresolved path conflicts show
6082 # Labels and keys based on merge state. Unresolved path conflicts show
6088 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6083 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6089 # resolved conflicts.
6084 # resolved conflicts.
6090 mergestateinfo = {
6085 mergestateinfo = {
6091 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6086 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6092 b'resolve.unresolved',
6087 b'resolve.unresolved',
6093 b'U',
6088 b'U',
6094 ),
6089 ),
6095 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6090 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6096 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6091 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6097 b'resolve.unresolved',
6092 b'resolve.unresolved',
6098 b'P',
6093 b'P',
6099 ),
6094 ),
6100 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6095 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6101 b'resolve.resolved',
6096 b'resolve.resolved',
6102 b'R',
6097 b'R',
6103 ),
6098 ),
6104 }
6099 }
6105
6100
6106 for f in ms:
6101 for f in ms:
6107 if not m(f):
6102 if not m(f):
6108 continue
6103 continue
6109
6104
6110 label, key = mergestateinfo[ms[f]]
6105 label, key = mergestateinfo[ms[f]]
6111 fm.startitem()
6106 fm.startitem()
6112 fm.context(ctx=wctx)
6107 fm.context(ctx=wctx)
6113 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6108 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6114 fm.data(path=f)
6109 fm.data(path=f)
6115 fm.plain(b'%s\n' % uipathfn(f), label=label)
6110 fm.plain(b'%s\n' % uipathfn(f), label=label)
6116 fm.end()
6111 fm.end()
6117 return 0
6112 return 0
6118
6113
6119 with repo.wlock():
6114 with repo.wlock():
6120 ms = mergestatemod.mergestate.read(repo)
6115 ms = mergestatemod.mergestate.read(repo)
6121
6116
6122 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6117 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6123 raise error.StateError(
6118 raise error.StateError(
6124 _(b'resolve command not applicable when not merging')
6119 _(b'resolve command not applicable when not merging')
6125 )
6120 )
6126
6121
6127 wctx = repo[None]
6122 wctx = repo[None]
6128 m = scmutil.match(wctx, pats, opts)
6123 m = scmutil.match(wctx, pats, opts)
6129 ret = 0
6124 ret = 0
6130 didwork = False
6125 didwork = False
6131
6126
6132 tocomplete = []
6127 tocomplete = []
6133 hasconflictmarkers = []
6128 hasconflictmarkers = []
6134 if mark:
6129 if mark:
6135 markcheck = ui.config(b'commands', b'resolve.mark-check')
6130 markcheck = ui.config(b'commands', b'resolve.mark-check')
6136 if markcheck not in [b'warn', b'abort']:
6131 if markcheck not in [b'warn', b'abort']:
6137 # Treat all invalid / unrecognized values as 'none'.
6132 # Treat all invalid / unrecognized values as 'none'.
6138 markcheck = False
6133 markcheck = False
6139 for f in ms:
6134 for f in ms:
6140 if not m(f):
6135 if not m(f):
6141 continue
6136 continue
6142
6137
6143 didwork = True
6138 didwork = True
6144
6139
6145 # path conflicts must be resolved manually
6140 # path conflicts must be resolved manually
6146 if ms[f] in (
6141 if ms[f] in (
6147 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6142 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6148 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6143 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6149 ):
6144 ):
6150 if mark:
6145 if mark:
6151 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6146 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6152 elif unmark:
6147 elif unmark:
6153 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6148 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6154 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6149 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6155 ui.warn(
6150 ui.warn(
6156 _(b'%s: path conflict must be resolved manually\n')
6151 _(b'%s: path conflict must be resolved manually\n')
6157 % uipathfn(f)
6152 % uipathfn(f)
6158 )
6153 )
6159 continue
6154 continue
6160
6155
6161 if mark:
6156 if mark:
6162 if markcheck:
6157 if markcheck:
6163 fdata = repo.wvfs.tryread(f)
6158 fdata = repo.wvfs.tryread(f)
6164 if (
6159 if (
6165 filemerge.hasconflictmarkers(fdata)
6160 filemerge.hasconflictmarkers(fdata)
6166 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6161 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6167 ):
6162 ):
6168 hasconflictmarkers.append(f)
6163 hasconflictmarkers.append(f)
6169 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6164 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6170 elif unmark:
6165 elif unmark:
6171 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6166 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6172 else:
6167 else:
6173 # backup pre-resolve (merge uses .orig for its own purposes)
6168 # backup pre-resolve (merge uses .orig for its own purposes)
6174 a = repo.wjoin(f)
6169 a = repo.wjoin(f)
6175 try:
6170 try:
6176 util.copyfile(a, a + b".resolve")
6171 util.copyfile(a, a + b".resolve")
6177 except (IOError, OSError) as inst:
6172 except (IOError, OSError) as inst:
6178 if inst.errno != errno.ENOENT:
6173 if inst.errno != errno.ENOENT:
6179 raise
6174 raise
6180
6175
6181 try:
6176 try:
6182 # preresolve file
6177 # preresolve file
6183 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6178 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6184 with ui.configoverride(overrides, b'resolve'):
6179 with ui.configoverride(overrides, b'resolve'):
6185 complete, r = ms.preresolve(f, wctx)
6180 complete, r = ms.preresolve(f, wctx)
6186 if not complete:
6181 if not complete:
6187 tocomplete.append(f)
6182 tocomplete.append(f)
6188 elif r:
6183 elif r:
6189 ret = 1
6184 ret = 1
6190 finally:
6185 finally:
6191 ms.commit()
6186 ms.commit()
6192
6187
6193 # replace filemerge's .orig file with our resolve file, but only
6188 # replace filemerge's .orig file with our resolve file, but only
6194 # for merges that are complete
6189 # for merges that are complete
6195 if complete:
6190 if complete:
6196 try:
6191 try:
6197 util.rename(
6192 util.rename(
6198 a + b".resolve", scmutil.backuppath(ui, repo, f)
6193 a + b".resolve", scmutil.backuppath(ui, repo, f)
6199 )
6194 )
6200 except OSError as inst:
6195 except OSError as inst:
6201 if inst.errno != errno.ENOENT:
6196 if inst.errno != errno.ENOENT:
6202 raise
6197 raise
6203
6198
6204 if hasconflictmarkers:
6199 if hasconflictmarkers:
6205 ui.warn(
6200 ui.warn(
6206 _(
6201 _(
6207 b'warning: the following files still have conflict '
6202 b'warning: the following files still have conflict '
6208 b'markers:\n'
6203 b'markers:\n'
6209 )
6204 )
6210 + b''.join(
6205 + b''.join(
6211 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6206 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6212 )
6207 )
6213 )
6208 )
6214 if markcheck == b'abort' and not all and not pats:
6209 if markcheck == b'abort' and not all and not pats:
6215 raise error.StateError(
6210 raise error.StateError(
6216 _(b'conflict markers detected'),
6211 _(b'conflict markers detected'),
6217 hint=_(b'use --all to mark anyway'),
6212 hint=_(b'use --all to mark anyway'),
6218 )
6213 )
6219
6214
6220 for f in tocomplete:
6215 for f in tocomplete:
6221 try:
6216 try:
6222 # resolve file
6217 # resolve file
6223 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6218 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6224 with ui.configoverride(overrides, b'resolve'):
6219 with ui.configoverride(overrides, b'resolve'):
6225 r = ms.resolve(f, wctx)
6220 r = ms.resolve(f, wctx)
6226 if r:
6221 if r:
6227 ret = 1
6222 ret = 1
6228 finally:
6223 finally:
6229 ms.commit()
6224 ms.commit()
6230
6225
6231 # replace filemerge's .orig file with our resolve file
6226 # replace filemerge's .orig file with our resolve file
6232 a = repo.wjoin(f)
6227 a = repo.wjoin(f)
6233 try:
6228 try:
6234 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6229 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6235 except OSError as inst:
6230 except OSError as inst:
6236 if inst.errno != errno.ENOENT:
6231 if inst.errno != errno.ENOENT:
6237 raise
6232 raise
6238
6233
6239 ms.commit()
6234 ms.commit()
6240 branchmerge = repo.dirstate.p2() != repo.nullid
6235 branchmerge = repo.dirstate.p2() != repo.nullid
6241 # resolve is not doing a parent change here, however, `record updates`
6236 # resolve is not doing a parent change here, however, `record updates`
6242 # will call some dirstate API that at intended for parent changes call.
6237 # will call some dirstate API that at intended for parent changes call.
6243 # Ideally we would not need this and could implement a lighter version
6238 # Ideally we would not need this and could implement a lighter version
6244 # of the recordupdateslogic that will not have to deal with the part
6239 # of the recordupdateslogic that will not have to deal with the part
6245 # related to parent changes. However this would requires that:
6240 # related to parent changes. However this would requires that:
6246 # - we are sure we passed around enough information at update/merge
6241 # - we are sure we passed around enough information at update/merge
6247 # time to no longer needs it at `hg resolve time`
6242 # time to no longer needs it at `hg resolve time`
6248 # - we are sure we store that information well enough to be able to reuse it
6243 # - we are sure we store that information well enough to be able to reuse it
6249 # - we are the necessary logic to reuse it right.
6244 # - we are the necessary logic to reuse it right.
6250 #
6245 #
6251 # All this should eventually happens, but in the mean time, we use this
6246 # All this should eventually happens, but in the mean time, we use this
6252 # context manager slightly out of the context it should be.
6247 # context manager slightly out of the context it should be.
6253 with repo.dirstate.parentchange():
6248 with repo.dirstate.parentchange():
6254 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6249 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6255
6250
6256 if not didwork and pats:
6251 if not didwork and pats:
6257 hint = None
6252 hint = None
6258 if not any([p for p in pats if p.find(b':') >= 0]):
6253 if not any([p for p in pats if p.find(b':') >= 0]):
6259 pats = [b'path:%s' % p for p in pats]
6254 pats = [b'path:%s' % p for p in pats]
6260 m = scmutil.match(wctx, pats, opts)
6255 m = scmutil.match(wctx, pats, opts)
6261 for f in ms:
6256 for f in ms:
6262 if not m(f):
6257 if not m(f):
6263 continue
6258 continue
6264
6259
6265 def flag(o):
6260 def flag(o):
6266 if o == b're_merge':
6261 if o == b're_merge':
6267 return b'--re-merge '
6262 return b'--re-merge '
6268 return b'-%s ' % o[0:1]
6263 return b'-%s ' % o[0:1]
6269
6264
6270 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6265 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6271 hint = _(b"(try: hg resolve %s%s)\n") % (
6266 hint = _(b"(try: hg resolve %s%s)\n") % (
6272 flags,
6267 flags,
6273 b' '.join(pats),
6268 b' '.join(pats),
6274 )
6269 )
6275 break
6270 break
6276 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6271 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6277 if hint:
6272 if hint:
6278 ui.warn(hint)
6273 ui.warn(hint)
6279
6274
6280 unresolvedf = ms.unresolvedcount()
6275 unresolvedf = ms.unresolvedcount()
6281 if not unresolvedf:
6276 if not unresolvedf:
6282 ui.status(_(b'(no more unresolved files)\n'))
6277 ui.status(_(b'(no more unresolved files)\n'))
6283 cmdutil.checkafterresolved(repo)
6278 cmdutil.checkafterresolved(repo)
6284
6279
6285 return ret
6280 return ret
6286
6281
6287
6282
6288 @command(
6283 @command(
6289 b'revert',
6284 b'revert',
6290 [
6285 [
6291 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6286 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6292 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6287 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6293 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6288 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6294 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6289 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6295 (b'i', b'interactive', None, _(b'interactively select the changes')),
6290 (b'i', b'interactive', None, _(b'interactively select the changes')),
6296 ]
6291 ]
6297 + walkopts
6292 + walkopts
6298 + dryrunopts,
6293 + dryrunopts,
6299 _(b'[OPTION]... [-r REV] [NAME]...'),
6294 _(b'[OPTION]... [-r REV] [NAME]...'),
6300 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6295 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6301 )
6296 )
6302 def revert(ui, repo, *pats, **opts):
6297 def revert(ui, repo, *pats, **opts):
6303 """restore files to their checkout state
6298 """restore files to their checkout state
6304
6299
6305 .. note::
6300 .. note::
6306
6301
6307 To check out earlier revisions, you should use :hg:`update REV`.
6302 To check out earlier revisions, you should use :hg:`update REV`.
6308 To cancel an uncommitted merge (and lose your changes),
6303 To cancel an uncommitted merge (and lose your changes),
6309 use :hg:`merge --abort`.
6304 use :hg:`merge --abort`.
6310
6305
6311 With no revision specified, revert the specified files or directories
6306 With no revision specified, revert the specified files or directories
6312 to the contents they had in the parent of the working directory.
6307 to the contents they had in the parent of the working directory.
6313 This restores the contents of files to an unmodified
6308 This restores the contents of files to an unmodified
6314 state and unschedules adds, removes, copies, and renames. If the
6309 state and unschedules adds, removes, copies, and renames. If the
6315 working directory has two parents, you must explicitly specify a
6310 working directory has two parents, you must explicitly specify a
6316 revision.
6311 revision.
6317
6312
6318 Using the -r/--rev or -d/--date options, revert the given files or
6313 Using the -r/--rev or -d/--date options, revert the given files or
6319 directories to their states as of a specific revision. Because
6314 directories to their states as of a specific revision. Because
6320 revert does not change the working directory parents, this will
6315 revert does not change the working directory parents, this will
6321 cause these files to appear modified. This can be helpful to "back
6316 cause these files to appear modified. This can be helpful to "back
6322 out" some or all of an earlier change. See :hg:`backout` for a
6317 out" some or all of an earlier change. See :hg:`backout` for a
6323 related method.
6318 related method.
6324
6319
6325 Modified files are saved with a .orig suffix before reverting.
6320 Modified files are saved with a .orig suffix before reverting.
6326 To disable these backups, use --no-backup. It is possible to store
6321 To disable these backups, use --no-backup. It is possible to store
6327 the backup files in a custom directory relative to the root of the
6322 the backup files in a custom directory relative to the root of the
6328 repository by setting the ``ui.origbackuppath`` configuration
6323 repository by setting the ``ui.origbackuppath`` configuration
6329 option.
6324 option.
6330
6325
6331 See :hg:`help dates` for a list of formats valid for -d/--date.
6326 See :hg:`help dates` for a list of formats valid for -d/--date.
6332
6327
6333 See :hg:`help backout` for a way to reverse the effect of an
6328 See :hg:`help backout` for a way to reverse the effect of an
6334 earlier changeset.
6329 earlier changeset.
6335
6330
6336 Returns 0 on success.
6331 Returns 0 on success.
6337 """
6332 """
6338
6333
6339 opts = pycompat.byteskwargs(opts)
6334 opts = pycompat.byteskwargs(opts)
6340 if opts.get(b"date"):
6335 if opts.get(b"date"):
6341 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6336 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6342 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6337 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6343
6338
6344 parent, p2 = repo.dirstate.parents()
6339 parent, p2 = repo.dirstate.parents()
6345 if not opts.get(b'rev') and p2 != repo.nullid:
6340 if not opts.get(b'rev') and p2 != repo.nullid:
6346 # revert after merge is a trap for new users (issue2915)
6341 # revert after merge is a trap for new users (issue2915)
6347 raise error.InputError(
6342 raise error.InputError(
6348 _(b'uncommitted merge with no revision specified'),
6343 _(b'uncommitted merge with no revision specified'),
6349 hint=_(b"use 'hg update' or see 'hg help revert'"),
6344 hint=_(b"use 'hg update' or see 'hg help revert'"),
6350 )
6345 )
6351
6346
6352 rev = opts.get(b'rev')
6347 rev = opts.get(b'rev')
6353 if rev:
6348 if rev:
6354 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6349 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6355 ctx = scmutil.revsingle(repo, rev)
6350 ctx = scmutil.revsingle(repo, rev)
6356
6351
6357 if not (
6352 if not (
6358 pats
6353 pats
6359 or opts.get(b'include')
6354 or opts.get(b'include')
6360 or opts.get(b'exclude')
6355 or opts.get(b'exclude')
6361 or opts.get(b'all')
6356 or opts.get(b'all')
6362 or opts.get(b'interactive')
6357 or opts.get(b'interactive')
6363 ):
6358 ):
6364 msg = _(b"no files or directories specified")
6359 msg = _(b"no files or directories specified")
6365 if p2 != repo.nullid:
6360 if p2 != repo.nullid:
6366 hint = _(
6361 hint = _(
6367 b"uncommitted merge, use --all to discard all changes,"
6362 b"uncommitted merge, use --all to discard all changes,"
6368 b" or 'hg update -C .' to abort the merge"
6363 b" or 'hg update -C .' to abort the merge"
6369 )
6364 )
6370 raise error.InputError(msg, hint=hint)
6365 raise error.InputError(msg, hint=hint)
6371 dirty = any(repo.status())
6366 dirty = any(repo.status())
6372 node = ctx.node()
6367 node = ctx.node()
6373 if node != parent:
6368 if node != parent:
6374 if dirty:
6369 if dirty:
6375 hint = (
6370 hint = (
6376 _(
6371 _(
6377 b"uncommitted changes, use --all to discard all"
6372 b"uncommitted changes, use --all to discard all"
6378 b" changes, or 'hg update %d' to update"
6373 b" changes, or 'hg update %d' to update"
6379 )
6374 )
6380 % ctx.rev()
6375 % ctx.rev()
6381 )
6376 )
6382 else:
6377 else:
6383 hint = (
6378 hint = (
6384 _(
6379 _(
6385 b"use --all to revert all files,"
6380 b"use --all to revert all files,"
6386 b" or 'hg update %d' to update"
6381 b" or 'hg update %d' to update"
6387 )
6382 )
6388 % ctx.rev()
6383 % ctx.rev()
6389 )
6384 )
6390 elif dirty:
6385 elif dirty:
6391 hint = _(b"uncommitted changes, use --all to discard all changes")
6386 hint = _(b"uncommitted changes, use --all to discard all changes")
6392 else:
6387 else:
6393 hint = _(b"use --all to revert all files")
6388 hint = _(b"use --all to revert all files")
6394 raise error.InputError(msg, hint=hint)
6389 raise error.InputError(msg, hint=hint)
6395
6390
6396 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6391 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6397
6392
6398
6393
6399 @command(
6394 @command(
6400 b'rollback',
6395 b'rollback',
6401 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6396 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6402 helpcategory=command.CATEGORY_MAINTENANCE,
6397 helpcategory=command.CATEGORY_MAINTENANCE,
6403 )
6398 )
6404 def rollback(ui, repo, **opts):
6399 def rollback(ui, repo, **opts):
6405 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6400 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6406
6401
6407 Please use :hg:`commit --amend` instead of rollback to correct
6402 Please use :hg:`commit --amend` instead of rollback to correct
6408 mistakes in the last commit.
6403 mistakes in the last commit.
6409
6404
6410 This command should be used with care. There is only one level of
6405 This command should be used with care. There is only one level of
6411 rollback, and there is no way to undo a rollback. It will also
6406 rollback, and there is no way to undo a rollback. It will also
6412 restore the dirstate at the time of the last transaction, losing
6407 restore the dirstate at the time of the last transaction, losing
6413 any dirstate changes since that time. This command does not alter
6408 any dirstate changes since that time. This command does not alter
6414 the working directory.
6409 the working directory.
6415
6410
6416 Transactions are used to encapsulate the effects of all commands
6411 Transactions are used to encapsulate the effects of all commands
6417 that create new changesets or propagate existing changesets into a
6412 that create new changesets or propagate existing changesets into a
6418 repository.
6413 repository.
6419
6414
6420 .. container:: verbose
6415 .. container:: verbose
6421
6416
6422 For example, the following commands are transactional, and their
6417 For example, the following commands are transactional, and their
6423 effects can be rolled back:
6418 effects can be rolled back:
6424
6419
6425 - commit
6420 - commit
6426 - import
6421 - import
6427 - pull
6422 - pull
6428 - push (with this repository as the destination)
6423 - push (with this repository as the destination)
6429 - unbundle
6424 - unbundle
6430
6425
6431 To avoid permanent data loss, rollback will refuse to rollback a
6426 To avoid permanent data loss, rollback will refuse to rollback a
6432 commit transaction if it isn't checked out. Use --force to
6427 commit transaction if it isn't checked out. Use --force to
6433 override this protection.
6428 override this protection.
6434
6429
6435 The rollback command can be entirely disabled by setting the
6430 The rollback command can be entirely disabled by setting the
6436 ``ui.rollback`` configuration setting to false. If you're here
6431 ``ui.rollback`` configuration setting to false. If you're here
6437 because you want to use rollback and it's disabled, you can
6432 because you want to use rollback and it's disabled, you can
6438 re-enable the command by setting ``ui.rollback`` to true.
6433 re-enable the command by setting ``ui.rollback`` to true.
6439
6434
6440 This command is not intended for use on public repositories. Once
6435 This command is not intended for use on public repositories. Once
6441 changes are visible for pull by other users, rolling a transaction
6436 changes are visible for pull by other users, rolling a transaction
6442 back locally is ineffective (someone else may already have pulled
6437 back locally is ineffective (someone else may already have pulled
6443 the changes). Furthermore, a race is possible with readers of the
6438 the changes). Furthermore, a race is possible with readers of the
6444 repository; for example an in-progress pull from the repository
6439 repository; for example an in-progress pull from the repository
6445 may fail if a rollback is performed.
6440 may fail if a rollback is performed.
6446
6441
6447 Returns 0 on success, 1 if no rollback data is available.
6442 Returns 0 on success, 1 if no rollback data is available.
6448 """
6443 """
6449 if not ui.configbool(b'ui', b'rollback'):
6444 if not ui.configbool(b'ui', b'rollback'):
6450 raise error.Abort(
6445 raise error.Abort(
6451 _(b'rollback is disabled because it is unsafe'),
6446 _(b'rollback is disabled because it is unsafe'),
6452 hint=b'see `hg help -v rollback` for information',
6447 hint=b'see `hg help -v rollback` for information',
6453 )
6448 )
6454 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6449 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6455
6450
6456
6451
6457 @command(
6452 @command(
6458 b'root',
6453 b'root',
6459 [] + formatteropts,
6454 [] + formatteropts,
6460 intents={INTENT_READONLY},
6455 intents={INTENT_READONLY},
6461 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6456 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6462 )
6457 )
6463 def root(ui, repo, **opts):
6458 def root(ui, repo, **opts):
6464 """print the root (top) of the current working directory
6459 """print the root (top) of the current working directory
6465
6460
6466 Print the root directory of the current repository.
6461 Print the root directory of the current repository.
6467
6462
6468 .. container:: verbose
6463 .. container:: verbose
6469
6464
6470 Template:
6465 Template:
6471
6466
6472 The following keywords are supported in addition to the common template
6467 The following keywords are supported in addition to the common template
6473 keywords and functions. See also :hg:`help templates`.
6468 keywords and functions. See also :hg:`help templates`.
6474
6469
6475 :hgpath: String. Path to the .hg directory.
6470 :hgpath: String. Path to the .hg directory.
6476 :storepath: String. Path to the directory holding versioned data.
6471 :storepath: String. Path to the directory holding versioned data.
6477
6472
6478 Returns 0 on success.
6473 Returns 0 on success.
6479 """
6474 """
6480 opts = pycompat.byteskwargs(opts)
6475 opts = pycompat.byteskwargs(opts)
6481 with ui.formatter(b'root', opts) as fm:
6476 with ui.formatter(b'root', opts) as fm:
6482 fm.startitem()
6477 fm.startitem()
6483 fm.write(b'reporoot', b'%s\n', repo.root)
6478 fm.write(b'reporoot', b'%s\n', repo.root)
6484 fm.data(hgpath=repo.path, storepath=repo.spath)
6479 fm.data(hgpath=repo.path, storepath=repo.spath)
6485
6480
6486
6481
6487 @command(
6482 @command(
6488 b'serve',
6483 b'serve',
6489 [
6484 [
6490 (
6485 (
6491 b'A',
6486 b'A',
6492 b'accesslog',
6487 b'accesslog',
6493 b'',
6488 b'',
6494 _(b'name of access log file to write to'),
6489 _(b'name of access log file to write to'),
6495 _(b'FILE'),
6490 _(b'FILE'),
6496 ),
6491 ),
6497 (b'd', b'daemon', None, _(b'run server in background')),
6492 (b'd', b'daemon', None, _(b'run server in background')),
6498 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6493 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6499 (
6494 (
6500 b'E',
6495 b'E',
6501 b'errorlog',
6496 b'errorlog',
6502 b'',
6497 b'',
6503 _(b'name of error log file to write to'),
6498 _(b'name of error log file to write to'),
6504 _(b'FILE'),
6499 _(b'FILE'),
6505 ),
6500 ),
6506 # use string type, then we can check if something was passed
6501 # use string type, then we can check if something was passed
6507 (
6502 (
6508 b'p',
6503 b'p',
6509 b'port',
6504 b'port',
6510 b'',
6505 b'',
6511 _(b'port to listen on (default: 8000)'),
6506 _(b'port to listen on (default: 8000)'),
6512 _(b'PORT'),
6507 _(b'PORT'),
6513 ),
6508 ),
6514 (
6509 (
6515 b'a',
6510 b'a',
6516 b'address',
6511 b'address',
6517 b'',
6512 b'',
6518 _(b'address to listen on (default: all interfaces)'),
6513 _(b'address to listen on (default: all interfaces)'),
6519 _(b'ADDR'),
6514 _(b'ADDR'),
6520 ),
6515 ),
6521 (
6516 (
6522 b'',
6517 b'',
6523 b'prefix',
6518 b'prefix',
6524 b'',
6519 b'',
6525 _(b'prefix path to serve from (default: server root)'),
6520 _(b'prefix path to serve from (default: server root)'),
6526 _(b'PREFIX'),
6521 _(b'PREFIX'),
6527 ),
6522 ),
6528 (
6523 (
6529 b'n',
6524 b'n',
6530 b'name',
6525 b'name',
6531 b'',
6526 b'',
6532 _(b'name to show in web pages (default: working directory)'),
6527 _(b'name to show in web pages (default: working directory)'),
6533 _(b'NAME'),
6528 _(b'NAME'),
6534 ),
6529 ),
6535 (
6530 (
6536 b'',
6531 b'',
6537 b'web-conf',
6532 b'web-conf',
6538 b'',
6533 b'',
6539 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6534 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6540 _(b'FILE'),
6535 _(b'FILE'),
6541 ),
6536 ),
6542 (
6537 (
6543 b'',
6538 b'',
6544 b'webdir-conf',
6539 b'webdir-conf',
6545 b'',
6540 b'',
6546 _(b'name of the hgweb config file (DEPRECATED)'),
6541 _(b'name of the hgweb config file (DEPRECATED)'),
6547 _(b'FILE'),
6542 _(b'FILE'),
6548 ),
6543 ),
6549 (
6544 (
6550 b'',
6545 b'',
6551 b'pid-file',
6546 b'pid-file',
6552 b'',
6547 b'',
6553 _(b'name of file to write process ID to'),
6548 _(b'name of file to write process ID to'),
6554 _(b'FILE'),
6549 _(b'FILE'),
6555 ),
6550 ),
6556 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6551 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6557 (
6552 (
6558 b'',
6553 b'',
6559 b'cmdserver',
6554 b'cmdserver',
6560 b'',
6555 b'',
6561 _(b'for remote clients (ADVANCED)'),
6556 _(b'for remote clients (ADVANCED)'),
6562 _(b'MODE'),
6557 _(b'MODE'),
6563 ),
6558 ),
6564 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6559 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6565 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6560 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6566 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6561 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6567 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6562 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6568 (b'', b'print-url', None, _(b'start and print only the URL')),
6563 (b'', b'print-url', None, _(b'start and print only the URL')),
6569 ]
6564 ]
6570 + subrepoopts,
6565 + subrepoopts,
6571 _(b'[OPTION]...'),
6566 _(b'[OPTION]...'),
6572 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6567 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6573 helpbasic=True,
6568 helpbasic=True,
6574 optionalrepo=True,
6569 optionalrepo=True,
6575 )
6570 )
6576 def serve(ui, repo, **opts):
6571 def serve(ui, repo, **opts):
6577 """start stand-alone webserver
6572 """start stand-alone webserver
6578
6573
6579 Start a local HTTP repository browser and pull server. You can use
6574 Start a local HTTP repository browser and pull server. You can use
6580 this for ad-hoc sharing and browsing of repositories. It is
6575 this for ad-hoc sharing and browsing of repositories. It is
6581 recommended to use a real web server to serve a repository for
6576 recommended to use a real web server to serve a repository for
6582 longer periods of time.
6577 longer periods of time.
6583
6578
6584 Please note that the server does not implement access control.
6579 Please note that the server does not implement access control.
6585 This means that, by default, anybody can read from the server and
6580 This means that, by default, anybody can read from the server and
6586 nobody can write to it by default. Set the ``web.allow-push``
6581 nobody can write to it by default. Set the ``web.allow-push``
6587 option to ``*`` to allow everybody to push to the server. You
6582 option to ``*`` to allow everybody to push to the server. You
6588 should use a real web server if you need to authenticate users.
6583 should use a real web server if you need to authenticate users.
6589
6584
6590 By default, the server logs accesses to stdout and errors to
6585 By default, the server logs accesses to stdout and errors to
6591 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6586 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6592 files.
6587 files.
6593
6588
6594 To have the server choose a free port number to listen on, specify
6589 To have the server choose a free port number to listen on, specify
6595 a port number of 0; in this case, the server will print the port
6590 a port number of 0; in this case, the server will print the port
6596 number it uses.
6591 number it uses.
6597
6592
6598 Returns 0 on success.
6593 Returns 0 on success.
6599 """
6594 """
6600
6595
6601 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6596 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6602 opts = pycompat.byteskwargs(opts)
6597 opts = pycompat.byteskwargs(opts)
6603 if opts[b"print_url"] and ui.verbose:
6598 if opts[b"print_url"] and ui.verbose:
6604 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6599 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6605
6600
6606 if opts[b"stdio"]:
6601 if opts[b"stdio"]:
6607 if repo is None:
6602 if repo is None:
6608 raise error.RepoError(
6603 raise error.RepoError(
6609 _(b"there is no Mercurial repository here (.hg not found)")
6604 _(b"there is no Mercurial repository here (.hg not found)")
6610 )
6605 )
6611 s = wireprotoserver.sshserver(ui, repo)
6606 s = wireprotoserver.sshserver(ui, repo)
6612 s.serve_forever()
6607 s.serve_forever()
6613 return
6608 return
6614
6609
6615 service = server.createservice(ui, repo, opts)
6610 service = server.createservice(ui, repo, opts)
6616 return server.runservice(opts, initfn=service.init, runfn=service.run)
6611 return server.runservice(opts, initfn=service.init, runfn=service.run)
6617
6612
6618
6613
6619 @command(
6614 @command(
6620 b'shelve',
6615 b'shelve',
6621 [
6616 [
6622 (
6617 (
6623 b'A',
6618 b'A',
6624 b'addremove',
6619 b'addremove',
6625 None,
6620 None,
6626 _(b'mark new/missing files as added/removed before shelving'),
6621 _(b'mark new/missing files as added/removed before shelving'),
6627 ),
6622 ),
6628 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6623 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6629 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6624 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6630 (
6625 (
6631 b'',
6626 b'',
6632 b'date',
6627 b'date',
6633 b'',
6628 b'',
6634 _(b'shelve with the specified commit date'),
6629 _(b'shelve with the specified commit date'),
6635 _(b'DATE'),
6630 _(b'DATE'),
6636 ),
6631 ),
6637 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6632 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6638 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6633 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6639 (
6634 (
6640 b'k',
6635 b'k',
6641 b'keep',
6636 b'keep',
6642 False,
6637 False,
6643 _(b'shelve, but keep changes in the working directory'),
6638 _(b'shelve, but keep changes in the working directory'),
6644 ),
6639 ),
6645 (b'l', b'list', None, _(b'list current shelves')),
6640 (b'l', b'list', None, _(b'list current shelves')),
6646 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6641 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6647 (
6642 (
6648 b'n',
6643 b'n',
6649 b'name',
6644 b'name',
6650 b'',
6645 b'',
6651 _(b'use the given name for the shelved commit'),
6646 _(b'use the given name for the shelved commit'),
6652 _(b'NAME'),
6647 _(b'NAME'),
6653 ),
6648 ),
6654 (
6649 (
6655 b'p',
6650 b'p',
6656 b'patch',
6651 b'patch',
6657 None,
6652 None,
6658 _(
6653 _(
6659 b'output patches for changes (provide the names of the shelved '
6654 b'output patches for changes (provide the names of the shelved '
6660 b'changes as positional arguments)'
6655 b'changes as positional arguments)'
6661 ),
6656 ),
6662 ),
6657 ),
6663 (b'i', b'interactive', None, _(b'interactive mode')),
6658 (b'i', b'interactive', None, _(b'interactive mode')),
6664 (
6659 (
6665 b'',
6660 b'',
6666 b'stat',
6661 b'stat',
6667 None,
6662 None,
6668 _(
6663 _(
6669 b'output diffstat-style summary of changes (provide the names of '
6664 b'output diffstat-style summary of changes (provide the names of '
6670 b'the shelved changes as positional arguments)'
6665 b'the shelved changes as positional arguments)'
6671 ),
6666 ),
6672 ),
6667 ),
6673 ]
6668 ]
6674 + cmdutil.walkopts,
6669 + cmdutil.walkopts,
6675 _(b'hg shelve [OPTION]... [FILE]...'),
6670 _(b'hg shelve [OPTION]... [FILE]...'),
6676 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6671 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6677 )
6672 )
6678 def shelve(ui, repo, *pats, **opts):
6673 def shelve(ui, repo, *pats, **opts):
6679 """save and set aside changes from the working directory
6674 """save and set aside changes from the working directory
6680
6675
6681 Shelving takes files that "hg status" reports as not clean, saves
6676 Shelving takes files that "hg status" reports as not clean, saves
6682 the modifications to a bundle (a shelved change), and reverts the
6677 the modifications to a bundle (a shelved change), and reverts the
6683 files so that their state in the working directory becomes clean.
6678 files so that their state in the working directory becomes clean.
6684
6679
6685 To restore these changes to the working directory, using "hg
6680 To restore these changes to the working directory, using "hg
6686 unshelve"; this will work even if you switch to a different
6681 unshelve"; this will work even if you switch to a different
6687 commit.
6682 commit.
6688
6683
6689 When no files are specified, "hg shelve" saves all not-clean
6684 When no files are specified, "hg shelve" saves all not-clean
6690 files. If specific files or directories are named, only changes to
6685 files. If specific files or directories are named, only changes to
6691 those files are shelved.
6686 those files are shelved.
6692
6687
6693 In bare shelve (when no files are specified, without interactive,
6688 In bare shelve (when no files are specified, without interactive,
6694 include and exclude option), shelving remembers information if the
6689 include and exclude option), shelving remembers information if the
6695 working directory was on newly created branch, in other words working
6690 working directory was on newly created branch, in other words working
6696 directory was on different branch than its first parent. In this
6691 directory was on different branch than its first parent. In this
6697 situation unshelving restores branch information to the working directory.
6692 situation unshelving restores branch information to the working directory.
6698
6693
6699 Each shelved change has a name that makes it easier to find later.
6694 Each shelved change has a name that makes it easier to find later.
6700 The name of a shelved change defaults to being based on the active
6695 The name of a shelved change defaults to being based on the active
6701 bookmark, or if there is no active bookmark, the current named
6696 bookmark, or if there is no active bookmark, the current named
6702 branch. To specify a different name, use ``--name``.
6697 branch. To specify a different name, use ``--name``.
6703
6698
6704 To see a list of existing shelved changes, use the ``--list``
6699 To see a list of existing shelved changes, use the ``--list``
6705 option. For each shelved change, this will print its name, age,
6700 option. For each shelved change, this will print its name, age,
6706 and description; use ``--patch`` or ``--stat`` for more details.
6701 and description; use ``--patch`` or ``--stat`` for more details.
6707
6702
6708 To delete specific shelved changes, use ``--delete``. To delete
6703 To delete specific shelved changes, use ``--delete``. To delete
6709 all shelved changes, use ``--cleanup``.
6704 all shelved changes, use ``--cleanup``.
6710 """
6705 """
6711 opts = pycompat.byteskwargs(opts)
6706 opts = pycompat.byteskwargs(opts)
6712 allowables = [
6707 allowables = [
6713 (b'addremove', {b'create'}), # 'create' is pseudo action
6708 (b'addremove', {b'create'}), # 'create' is pseudo action
6714 (b'unknown', {b'create'}),
6709 (b'unknown', {b'create'}),
6715 (b'cleanup', {b'cleanup'}),
6710 (b'cleanup', {b'cleanup'}),
6716 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6711 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6717 (b'delete', {b'delete'}),
6712 (b'delete', {b'delete'}),
6718 (b'edit', {b'create'}),
6713 (b'edit', {b'create'}),
6719 (b'keep', {b'create'}),
6714 (b'keep', {b'create'}),
6720 (b'list', {b'list'}),
6715 (b'list', {b'list'}),
6721 (b'message', {b'create'}),
6716 (b'message', {b'create'}),
6722 (b'name', {b'create'}),
6717 (b'name', {b'create'}),
6723 (b'patch', {b'patch', b'list'}),
6718 (b'patch', {b'patch', b'list'}),
6724 (b'stat', {b'stat', b'list'}),
6719 (b'stat', {b'stat', b'list'}),
6725 ]
6720 ]
6726
6721
6727 def checkopt(opt):
6722 def checkopt(opt):
6728 if opts.get(opt):
6723 if opts.get(opt):
6729 for i, allowable in allowables:
6724 for i, allowable in allowables:
6730 if opts[i] and opt not in allowable:
6725 if opts[i] and opt not in allowable:
6731 raise error.InputError(
6726 raise error.InputError(
6732 _(
6727 _(
6733 b"options '--%s' and '--%s' may not be "
6728 b"options '--%s' and '--%s' may not be "
6734 b"used together"
6729 b"used together"
6735 )
6730 )
6736 % (opt, i)
6731 % (opt, i)
6737 )
6732 )
6738 return True
6733 return True
6739
6734
6740 if checkopt(b'cleanup'):
6735 if checkopt(b'cleanup'):
6741 if pats:
6736 if pats:
6742 raise error.InputError(
6737 raise error.InputError(
6743 _(b"cannot specify names when using '--cleanup'")
6738 _(b"cannot specify names when using '--cleanup'")
6744 )
6739 )
6745 return shelvemod.cleanupcmd(ui, repo)
6740 return shelvemod.cleanupcmd(ui, repo)
6746 elif checkopt(b'delete'):
6741 elif checkopt(b'delete'):
6747 return shelvemod.deletecmd(ui, repo, pats)
6742 return shelvemod.deletecmd(ui, repo, pats)
6748 elif checkopt(b'list'):
6743 elif checkopt(b'list'):
6749 return shelvemod.listcmd(ui, repo, pats, opts)
6744 return shelvemod.listcmd(ui, repo, pats, opts)
6750 elif checkopt(b'patch') or checkopt(b'stat'):
6745 elif checkopt(b'patch') or checkopt(b'stat'):
6751 return shelvemod.patchcmds(ui, repo, pats, opts)
6746 return shelvemod.patchcmds(ui, repo, pats, opts)
6752 else:
6747 else:
6753 return shelvemod.createcmd(ui, repo, pats, opts)
6748 return shelvemod.createcmd(ui, repo, pats, opts)
6754
6749
6755
6750
6756 _NOTTERSE = b'nothing'
6751 _NOTTERSE = b'nothing'
6757
6752
6758
6753
6759 @command(
6754 @command(
6760 b'status|st',
6755 b'status|st',
6761 [
6756 [
6762 (b'A', b'all', None, _(b'show status of all files')),
6757 (b'A', b'all', None, _(b'show status of all files')),
6763 (b'm', b'modified', None, _(b'show only modified files')),
6758 (b'm', b'modified', None, _(b'show only modified files')),
6764 (b'a', b'added', None, _(b'show only added files')),
6759 (b'a', b'added', None, _(b'show only added files')),
6765 (b'r', b'removed', None, _(b'show only removed files')),
6760 (b'r', b'removed', None, _(b'show only removed files')),
6766 (b'd', b'deleted', None, _(b'show only missing files')),
6761 (b'd', b'deleted', None, _(b'show only missing files')),
6767 (b'c', b'clean', None, _(b'show only files without changes')),
6762 (b'c', b'clean', None, _(b'show only files without changes')),
6768 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6763 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6769 (b'i', b'ignored', None, _(b'show only ignored files')),
6764 (b'i', b'ignored', None, _(b'show only ignored files')),
6770 (b'n', b'no-status', None, _(b'hide status prefix')),
6765 (b'n', b'no-status', None, _(b'hide status prefix')),
6771 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6766 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6772 (
6767 (
6773 b'C',
6768 b'C',
6774 b'copies',
6769 b'copies',
6775 None,
6770 None,
6776 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6771 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6777 ),
6772 ),
6778 (
6773 (
6779 b'0',
6774 b'0',
6780 b'print0',
6775 b'print0',
6781 None,
6776 None,
6782 _(b'end filenames with NUL, for use with xargs'),
6777 _(b'end filenames with NUL, for use with xargs'),
6783 ),
6778 ),
6784 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6779 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6785 (
6780 (
6786 b'',
6781 b'',
6787 b'change',
6782 b'change',
6788 b'',
6783 b'',
6789 _(b'list the changed files of a revision'),
6784 _(b'list the changed files of a revision'),
6790 _(b'REV'),
6785 _(b'REV'),
6791 ),
6786 ),
6792 ]
6787 ]
6793 + walkopts
6788 + walkopts
6794 + subrepoopts
6789 + subrepoopts
6795 + formatteropts,
6790 + formatteropts,
6796 _(b'[OPTION]... [FILE]...'),
6791 _(b'[OPTION]... [FILE]...'),
6797 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6792 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6798 helpbasic=True,
6793 helpbasic=True,
6799 inferrepo=True,
6794 inferrepo=True,
6800 intents={INTENT_READONLY},
6795 intents={INTENT_READONLY},
6801 )
6796 )
6802 def status(ui, repo, *pats, **opts):
6797 def status(ui, repo, *pats, **opts):
6803 """show changed files in the working directory
6798 """show changed files in the working directory
6804
6799
6805 Show status of files in the repository. If names are given, only
6800 Show status of files in the repository. If names are given, only
6806 files that match are shown. Files that are clean or ignored or
6801 files that match are shown. Files that are clean or ignored or
6807 the source of a copy/move operation, are not listed unless
6802 the source of a copy/move operation, are not listed unless
6808 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6803 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6809 Unless options described with "show only ..." are given, the
6804 Unless options described with "show only ..." are given, the
6810 options -mardu are used.
6805 options -mardu are used.
6811
6806
6812 Option -q/--quiet hides untracked (unknown and ignored) files
6807 Option -q/--quiet hides untracked (unknown and ignored) files
6813 unless explicitly requested with -u/--unknown or -i/--ignored.
6808 unless explicitly requested with -u/--unknown or -i/--ignored.
6814
6809
6815 .. note::
6810 .. note::
6816
6811
6817 :hg:`status` may appear to disagree with diff if permissions have
6812 :hg:`status` may appear to disagree with diff if permissions have
6818 changed or a merge has occurred. The standard diff format does
6813 changed or a merge has occurred. The standard diff format does
6819 not report permission changes and diff only reports changes
6814 not report permission changes and diff only reports changes
6820 relative to one merge parent.
6815 relative to one merge parent.
6821
6816
6822 If one revision is given, it is used as the base revision.
6817 If one revision is given, it is used as the base revision.
6823 If two revisions are given, the differences between them are
6818 If two revisions are given, the differences between them are
6824 shown. The --change option can also be used as a shortcut to list
6819 shown. The --change option can also be used as a shortcut to list
6825 the changed files of a revision from its first parent.
6820 the changed files of a revision from its first parent.
6826
6821
6827 The codes used to show the status of files are::
6822 The codes used to show the status of files are::
6828
6823
6829 M = modified
6824 M = modified
6830 A = added
6825 A = added
6831 R = removed
6826 R = removed
6832 C = clean
6827 C = clean
6833 ! = missing (deleted by non-hg command, but still tracked)
6828 ! = missing (deleted by non-hg command, but still tracked)
6834 ? = not tracked
6829 ? = not tracked
6835 I = ignored
6830 I = ignored
6836 = origin of the previous file (with --copies)
6831 = origin of the previous file (with --copies)
6837
6832
6838 .. container:: verbose
6833 .. container:: verbose
6839
6834
6840 The -t/--terse option abbreviates the output by showing only the directory
6835 The -t/--terse option abbreviates the output by showing only the directory
6841 name if all the files in it share the same status. The option takes an
6836 name if all the files in it share the same status. The option takes an
6842 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6837 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6843 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6838 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6844 for 'ignored' and 'c' for clean.
6839 for 'ignored' and 'c' for clean.
6845
6840
6846 It abbreviates only those statuses which are passed. Note that clean and
6841 It abbreviates only those statuses which are passed. Note that clean and
6847 ignored files are not displayed with '--terse ic' unless the -c/--clean
6842 ignored files are not displayed with '--terse ic' unless the -c/--clean
6848 and -i/--ignored options are also used.
6843 and -i/--ignored options are also used.
6849
6844
6850 The -v/--verbose option shows information when the repository is in an
6845 The -v/--verbose option shows information when the repository is in an
6851 unfinished merge, shelve, rebase state etc. You can have this behavior
6846 unfinished merge, shelve, rebase state etc. You can have this behavior
6852 turned on by default by enabling the ``commands.status.verbose`` option.
6847 turned on by default by enabling the ``commands.status.verbose`` option.
6853
6848
6854 You can skip displaying some of these states by setting
6849 You can skip displaying some of these states by setting
6855 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6850 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6856 'histedit', 'merge', 'rebase', or 'unshelve'.
6851 'histedit', 'merge', 'rebase', or 'unshelve'.
6857
6852
6858 Template:
6853 Template:
6859
6854
6860 The following keywords are supported in addition to the common template
6855 The following keywords are supported in addition to the common template
6861 keywords and functions. See also :hg:`help templates`.
6856 keywords and functions. See also :hg:`help templates`.
6862
6857
6863 :path: String. Repository-absolute path of the file.
6858 :path: String. Repository-absolute path of the file.
6864 :source: String. Repository-absolute path of the file originated from.
6859 :source: String. Repository-absolute path of the file originated from.
6865 Available if ``--copies`` is specified.
6860 Available if ``--copies`` is specified.
6866 :status: String. Character denoting file's status.
6861 :status: String. Character denoting file's status.
6867
6862
6868 Examples:
6863 Examples:
6869
6864
6870 - show changes in the working directory relative to a
6865 - show changes in the working directory relative to a
6871 changeset::
6866 changeset::
6872
6867
6873 hg status --rev 9353
6868 hg status --rev 9353
6874
6869
6875 - show changes in the working directory relative to the
6870 - show changes in the working directory relative to the
6876 current directory (see :hg:`help patterns` for more information)::
6871 current directory (see :hg:`help patterns` for more information)::
6877
6872
6878 hg status re:
6873 hg status re:
6879
6874
6880 - show all changes including copies in an existing changeset::
6875 - show all changes including copies in an existing changeset::
6881
6876
6882 hg status --copies --change 9353
6877 hg status --copies --change 9353
6883
6878
6884 - get a NUL separated list of added files, suitable for xargs::
6879 - get a NUL separated list of added files, suitable for xargs::
6885
6880
6886 hg status -an0
6881 hg status -an0
6887
6882
6888 - show more information about the repository status, abbreviating
6883 - show more information about the repository status, abbreviating
6889 added, removed, modified, deleted, and untracked paths::
6884 added, removed, modified, deleted, and untracked paths::
6890
6885
6891 hg status -v -t mardu
6886 hg status -v -t mardu
6892
6887
6893 Returns 0 on success.
6888 Returns 0 on success.
6894
6889
6895 """
6890 """
6896
6891
6897 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6892 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6898 opts = pycompat.byteskwargs(opts)
6893 opts = pycompat.byteskwargs(opts)
6899 revs = opts.get(b'rev')
6894 revs = opts.get(b'rev')
6900 change = opts.get(b'change')
6895 change = opts.get(b'change')
6901 terse = opts.get(b'terse')
6896 terse = opts.get(b'terse')
6902 if terse is _NOTTERSE:
6897 if terse is _NOTTERSE:
6903 if revs:
6898 if revs:
6904 terse = b''
6899 terse = b''
6905 else:
6900 else:
6906 terse = ui.config(b'commands', b'status.terse')
6901 terse = ui.config(b'commands', b'status.terse')
6907
6902
6908 if revs and terse:
6903 if revs and terse:
6909 msg = _(b'cannot use --terse with --rev')
6904 msg = _(b'cannot use --terse with --rev')
6910 raise error.InputError(msg)
6905 raise error.InputError(msg)
6911 elif change:
6906 elif change:
6912 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6907 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6913 ctx2 = scmutil.revsingle(repo, change, None)
6908 ctx2 = scmutil.revsingle(repo, change, None)
6914 ctx1 = ctx2.p1()
6909 ctx1 = ctx2.p1()
6915 else:
6910 else:
6916 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6911 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6917 ctx1, ctx2 = scmutil.revpair(repo, revs)
6912 ctx1, ctx2 = scmutil.revpair(repo, revs)
6918
6913
6919 forcerelativevalue = None
6914 forcerelativevalue = None
6920 if ui.hasconfig(b'commands', b'status.relative'):
6915 if ui.hasconfig(b'commands', b'status.relative'):
6921 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6916 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6922 uipathfn = scmutil.getuipathfn(
6917 uipathfn = scmutil.getuipathfn(
6923 repo,
6918 repo,
6924 legacyrelativevalue=bool(pats),
6919 legacyrelativevalue=bool(pats),
6925 forcerelativevalue=forcerelativevalue,
6920 forcerelativevalue=forcerelativevalue,
6926 )
6921 )
6927
6922
6928 if opts.get(b'print0'):
6923 if opts.get(b'print0'):
6929 end = b'\0'
6924 end = b'\0'
6930 else:
6925 else:
6931 end = b'\n'
6926 end = b'\n'
6932 states = b'modified added removed deleted unknown ignored clean'.split()
6927 states = b'modified added removed deleted unknown ignored clean'.split()
6933 show = [k for k in states if opts.get(k)]
6928 show = [k for k in states if opts.get(k)]
6934 if opts.get(b'all'):
6929 if opts.get(b'all'):
6935 show += ui.quiet and (states[:4] + [b'clean']) or states
6930 show += ui.quiet and (states[:4] + [b'clean']) or states
6936
6931
6937 if not show:
6932 if not show:
6938 if ui.quiet:
6933 if ui.quiet:
6939 show = states[:4]
6934 show = states[:4]
6940 else:
6935 else:
6941 show = states[:5]
6936 show = states[:5]
6942
6937
6943 m = scmutil.match(ctx2, pats, opts)
6938 m = scmutil.match(ctx2, pats, opts)
6944 if terse:
6939 if terse:
6945 # we need to compute clean and unknown to terse
6940 # we need to compute clean and unknown to terse
6946 stat = repo.status(
6941 stat = repo.status(
6947 ctx1.node(),
6942 ctx1.node(),
6948 ctx2.node(),
6943 ctx2.node(),
6949 m,
6944 m,
6950 b'ignored' in show or b'i' in terse,
6945 b'ignored' in show or b'i' in terse,
6951 clean=True,
6946 clean=True,
6952 unknown=True,
6947 unknown=True,
6953 listsubrepos=opts.get(b'subrepos'),
6948 listsubrepos=opts.get(b'subrepos'),
6954 )
6949 )
6955
6950
6956 stat = cmdutil.tersedir(stat, terse)
6951 stat = cmdutil.tersedir(stat, terse)
6957 else:
6952 else:
6958 stat = repo.status(
6953 stat = repo.status(
6959 ctx1.node(),
6954 ctx1.node(),
6960 ctx2.node(),
6955 ctx2.node(),
6961 m,
6956 m,
6962 b'ignored' in show,
6957 b'ignored' in show,
6963 b'clean' in show,
6958 b'clean' in show,
6964 b'unknown' in show,
6959 b'unknown' in show,
6965 opts.get(b'subrepos'),
6960 opts.get(b'subrepos'),
6966 )
6961 )
6967
6962
6968 changestates = zip(
6963 changestates = zip(
6969 states,
6964 states,
6970 pycompat.iterbytestr(b'MAR!?IC'),
6965 pycompat.iterbytestr(b'MAR!?IC'),
6971 [getattr(stat, s.decode('utf8')) for s in states],
6966 [getattr(stat, s.decode('utf8')) for s in states],
6972 )
6967 )
6973
6968
6974 copy = {}
6969 copy = {}
6975 if (
6970 if (
6976 opts.get(b'all')
6971 opts.get(b'all')
6977 or opts.get(b'copies')
6972 or opts.get(b'copies')
6978 or ui.configbool(b'ui', b'statuscopies')
6973 or ui.configbool(b'ui', b'statuscopies')
6979 ) and not opts.get(b'no_status'):
6974 ) and not opts.get(b'no_status'):
6980 copy = copies.pathcopies(ctx1, ctx2, m)
6975 copy = copies.pathcopies(ctx1, ctx2, m)
6981
6976
6982 morestatus = None
6977 morestatus = None
6983 if (
6978 if (
6984 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6979 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6985 and not ui.plain()
6980 and not ui.plain()
6986 and not opts.get(b'print0')
6981 and not opts.get(b'print0')
6987 ):
6982 ):
6988 morestatus = cmdutil.readmorestatus(repo)
6983 morestatus = cmdutil.readmorestatus(repo)
6989
6984
6990 ui.pager(b'status')
6985 ui.pager(b'status')
6991 fm = ui.formatter(b'status', opts)
6986 fm = ui.formatter(b'status', opts)
6992 fmt = b'%s' + end
6987 fmt = b'%s' + end
6993 showchar = not opts.get(b'no_status')
6988 showchar = not opts.get(b'no_status')
6994
6989
6995 for state, char, files in changestates:
6990 for state, char, files in changestates:
6996 if state in show:
6991 if state in show:
6997 label = b'status.' + state
6992 label = b'status.' + state
6998 for f in files:
6993 for f in files:
6999 fm.startitem()
6994 fm.startitem()
7000 fm.context(ctx=ctx2)
6995 fm.context(ctx=ctx2)
7001 fm.data(itemtype=b'file', path=f)
6996 fm.data(itemtype=b'file', path=f)
7002 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6997 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7003 fm.plain(fmt % uipathfn(f), label=label)
6998 fm.plain(fmt % uipathfn(f), label=label)
7004 if f in copy:
6999 if f in copy:
7005 fm.data(source=copy[f])
7000 fm.data(source=copy[f])
7006 fm.plain(
7001 fm.plain(
7007 (b' %s' + end) % uipathfn(copy[f]),
7002 (b' %s' + end) % uipathfn(copy[f]),
7008 label=b'status.copied',
7003 label=b'status.copied',
7009 )
7004 )
7010 if morestatus:
7005 if morestatus:
7011 morestatus.formatfile(f, fm)
7006 morestatus.formatfile(f, fm)
7012
7007
7013 if morestatus:
7008 if morestatus:
7014 morestatus.formatfooter(fm)
7009 morestatus.formatfooter(fm)
7015 fm.end()
7010 fm.end()
7016
7011
7017
7012
7018 @command(
7013 @command(
7019 b'summary|sum',
7014 b'summary|sum',
7020 [(b'', b'remote', None, _(b'check for push and pull'))],
7015 [(b'', b'remote', None, _(b'check for push and pull'))],
7021 b'[--remote]',
7016 b'[--remote]',
7022 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7017 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7023 helpbasic=True,
7018 helpbasic=True,
7024 intents={INTENT_READONLY},
7019 intents={INTENT_READONLY},
7025 )
7020 )
7026 def summary(ui, repo, **opts):
7021 def summary(ui, repo, **opts):
7027 """summarize working directory state
7022 """summarize working directory state
7028
7023
7029 This generates a brief summary of the working directory state,
7024 This generates a brief summary of the working directory state,
7030 including parents, branch, commit status, phase and available updates.
7025 including parents, branch, commit status, phase and available updates.
7031
7026
7032 With the --remote option, this will check the default paths for
7027 With the --remote option, this will check the default paths for
7033 incoming and outgoing changes. This can be time-consuming.
7028 incoming and outgoing changes. This can be time-consuming.
7034
7029
7035 Returns 0 on success.
7030 Returns 0 on success.
7036 """
7031 """
7037
7032
7038 opts = pycompat.byteskwargs(opts)
7033 opts = pycompat.byteskwargs(opts)
7039 ui.pager(b'summary')
7034 ui.pager(b'summary')
7040 ctx = repo[None]
7035 ctx = repo[None]
7041 parents = ctx.parents()
7036 parents = ctx.parents()
7042 pnode = parents[0].node()
7037 pnode = parents[0].node()
7043 marks = []
7038 marks = []
7044
7039
7045 try:
7040 try:
7046 ms = mergestatemod.mergestate.read(repo)
7041 ms = mergestatemod.mergestate.read(repo)
7047 except error.UnsupportedMergeRecords as e:
7042 except error.UnsupportedMergeRecords as e:
7048 s = b' '.join(e.recordtypes)
7043 s = b' '.join(e.recordtypes)
7049 ui.warn(
7044 ui.warn(
7050 _(b'warning: merge state has unsupported record types: %s\n') % s
7045 _(b'warning: merge state has unsupported record types: %s\n') % s
7051 )
7046 )
7052 unresolved = []
7047 unresolved = []
7053 else:
7048 else:
7054 unresolved = list(ms.unresolved())
7049 unresolved = list(ms.unresolved())
7055
7050
7056 for p in parents:
7051 for p in parents:
7057 # label with log.changeset (instead of log.parent) since this
7052 # label with log.changeset (instead of log.parent) since this
7058 # shows a working directory parent *changeset*:
7053 # shows a working directory parent *changeset*:
7059 # i18n: column positioning for "hg summary"
7054 # i18n: column positioning for "hg summary"
7060 ui.write(
7055 ui.write(
7061 _(b'parent: %d:%s ') % (p.rev(), p),
7056 _(b'parent: %d:%s ') % (p.rev(), p),
7062 label=logcmdutil.changesetlabels(p),
7057 label=logcmdutil.changesetlabels(p),
7063 )
7058 )
7064 ui.write(b' '.join(p.tags()), label=b'log.tag')
7059 ui.write(b' '.join(p.tags()), label=b'log.tag')
7065 if p.bookmarks():
7060 if p.bookmarks():
7066 marks.extend(p.bookmarks())
7061 marks.extend(p.bookmarks())
7067 if p.rev() == -1:
7062 if p.rev() == -1:
7068 if not len(repo):
7063 if not len(repo):
7069 ui.write(_(b' (empty repository)'))
7064 ui.write(_(b' (empty repository)'))
7070 else:
7065 else:
7071 ui.write(_(b' (no revision checked out)'))
7066 ui.write(_(b' (no revision checked out)'))
7072 if p.obsolete():
7067 if p.obsolete():
7073 ui.write(_(b' (obsolete)'))
7068 ui.write(_(b' (obsolete)'))
7074 if p.isunstable():
7069 if p.isunstable():
7075 instabilities = (
7070 instabilities = (
7076 ui.label(instability, b'trouble.%s' % instability)
7071 ui.label(instability, b'trouble.%s' % instability)
7077 for instability in p.instabilities()
7072 for instability in p.instabilities()
7078 )
7073 )
7079 ui.write(b' (' + b', '.join(instabilities) + b')')
7074 ui.write(b' (' + b', '.join(instabilities) + b')')
7080 ui.write(b'\n')
7075 ui.write(b'\n')
7081 if p.description():
7076 if p.description():
7082 ui.status(
7077 ui.status(
7083 b' ' + p.description().splitlines()[0].strip() + b'\n',
7078 b' ' + p.description().splitlines()[0].strip() + b'\n',
7084 label=b'log.summary',
7079 label=b'log.summary',
7085 )
7080 )
7086
7081
7087 branch = ctx.branch()
7082 branch = ctx.branch()
7088 bheads = repo.branchheads(branch)
7083 bheads = repo.branchheads(branch)
7089 # i18n: column positioning for "hg summary"
7084 # i18n: column positioning for "hg summary"
7090 m = _(b'branch: %s\n') % branch
7085 m = _(b'branch: %s\n') % branch
7091 if branch != b'default':
7086 if branch != b'default':
7092 ui.write(m, label=b'log.branch')
7087 ui.write(m, label=b'log.branch')
7093 else:
7088 else:
7094 ui.status(m, label=b'log.branch')
7089 ui.status(m, label=b'log.branch')
7095
7090
7096 if marks:
7091 if marks:
7097 active = repo._activebookmark
7092 active = repo._activebookmark
7098 # i18n: column positioning for "hg summary"
7093 # i18n: column positioning for "hg summary"
7099 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7094 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7100 if active is not None:
7095 if active is not None:
7101 if active in marks:
7096 if active in marks:
7102 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7097 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7103 marks.remove(active)
7098 marks.remove(active)
7104 else:
7099 else:
7105 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7100 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7106 for m in marks:
7101 for m in marks:
7107 ui.write(b' ' + m, label=b'log.bookmark')
7102 ui.write(b' ' + m, label=b'log.bookmark')
7108 ui.write(b'\n', label=b'log.bookmark')
7103 ui.write(b'\n', label=b'log.bookmark')
7109
7104
7110 status = repo.status(unknown=True)
7105 status = repo.status(unknown=True)
7111
7106
7112 c = repo.dirstate.copies()
7107 c = repo.dirstate.copies()
7113 copied, renamed = [], []
7108 copied, renamed = [], []
7114 for d, s in pycompat.iteritems(c):
7109 for d, s in pycompat.iteritems(c):
7115 if s in status.removed:
7110 if s in status.removed:
7116 status.removed.remove(s)
7111 status.removed.remove(s)
7117 renamed.append(d)
7112 renamed.append(d)
7118 else:
7113 else:
7119 copied.append(d)
7114 copied.append(d)
7120 if d in status.added:
7115 if d in status.added:
7121 status.added.remove(d)
7116 status.added.remove(d)
7122
7117
7123 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7118 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7124
7119
7125 labels = [
7120 labels = [
7126 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7121 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7127 (ui.label(_(b'%d added'), b'status.added'), status.added),
7122 (ui.label(_(b'%d added'), b'status.added'), status.added),
7128 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7123 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7129 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7124 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7130 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7125 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7131 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7126 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7132 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7127 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7133 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7128 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7134 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7129 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7135 ]
7130 ]
7136 t = []
7131 t = []
7137 for l, s in labels:
7132 for l, s in labels:
7138 if s:
7133 if s:
7139 t.append(l % len(s))
7134 t.append(l % len(s))
7140
7135
7141 t = b', '.join(t)
7136 t = b', '.join(t)
7142 cleanworkdir = False
7137 cleanworkdir = False
7143
7138
7144 if repo.vfs.exists(b'graftstate'):
7139 if repo.vfs.exists(b'graftstate'):
7145 t += _(b' (graft in progress)')
7140 t += _(b' (graft in progress)')
7146 if repo.vfs.exists(b'updatestate'):
7141 if repo.vfs.exists(b'updatestate'):
7147 t += _(b' (interrupted update)')
7142 t += _(b' (interrupted update)')
7148 elif len(parents) > 1:
7143 elif len(parents) > 1:
7149 t += _(b' (merge)')
7144 t += _(b' (merge)')
7150 elif branch != parents[0].branch():
7145 elif branch != parents[0].branch():
7151 t += _(b' (new branch)')
7146 t += _(b' (new branch)')
7152 elif parents[0].closesbranch() and pnode in repo.branchheads(
7147 elif parents[0].closesbranch() and pnode in repo.branchheads(
7153 branch, closed=True
7148 branch, closed=True
7154 ):
7149 ):
7155 t += _(b' (head closed)')
7150 t += _(b' (head closed)')
7156 elif not (
7151 elif not (
7157 status.modified
7152 status.modified
7158 or status.added
7153 or status.added
7159 or status.removed
7154 or status.removed
7160 or renamed
7155 or renamed
7161 or copied
7156 or copied
7162 or subs
7157 or subs
7163 ):
7158 ):
7164 t += _(b' (clean)')
7159 t += _(b' (clean)')
7165 cleanworkdir = True
7160 cleanworkdir = True
7166 elif pnode not in bheads:
7161 elif pnode not in bheads:
7167 t += _(b' (new branch head)')
7162 t += _(b' (new branch head)')
7168
7163
7169 if parents:
7164 if parents:
7170 pendingphase = max(p.phase() for p in parents)
7165 pendingphase = max(p.phase() for p in parents)
7171 else:
7166 else:
7172 pendingphase = phases.public
7167 pendingphase = phases.public
7173
7168
7174 if pendingphase > phases.newcommitphase(ui):
7169 if pendingphase > phases.newcommitphase(ui):
7175 t += b' (%s)' % phases.phasenames[pendingphase]
7170 t += b' (%s)' % phases.phasenames[pendingphase]
7176
7171
7177 if cleanworkdir:
7172 if cleanworkdir:
7178 # i18n: column positioning for "hg summary"
7173 # i18n: column positioning for "hg summary"
7179 ui.status(_(b'commit: %s\n') % t.strip())
7174 ui.status(_(b'commit: %s\n') % t.strip())
7180 else:
7175 else:
7181 # i18n: column positioning for "hg summary"
7176 # i18n: column positioning for "hg summary"
7182 ui.write(_(b'commit: %s\n') % t.strip())
7177 ui.write(_(b'commit: %s\n') % t.strip())
7183
7178
7184 # all ancestors of branch heads - all ancestors of parent = new csets
7179 # all ancestors of branch heads - all ancestors of parent = new csets
7185 new = len(
7180 new = len(
7186 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7181 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7187 )
7182 )
7188
7183
7189 if new == 0:
7184 if new == 0:
7190 # i18n: column positioning for "hg summary"
7185 # i18n: column positioning for "hg summary"
7191 ui.status(_(b'update: (current)\n'))
7186 ui.status(_(b'update: (current)\n'))
7192 elif pnode not in bheads:
7187 elif pnode not in bheads:
7193 # i18n: column positioning for "hg summary"
7188 # i18n: column positioning for "hg summary"
7194 ui.write(_(b'update: %d new changesets (update)\n') % new)
7189 ui.write(_(b'update: %d new changesets (update)\n') % new)
7195 else:
7190 else:
7196 # i18n: column positioning for "hg summary"
7191 # i18n: column positioning for "hg summary"
7197 ui.write(
7192 ui.write(
7198 _(b'update: %d new changesets, %d branch heads (merge)\n')
7193 _(b'update: %d new changesets, %d branch heads (merge)\n')
7199 % (new, len(bheads))
7194 % (new, len(bheads))
7200 )
7195 )
7201
7196
7202 t = []
7197 t = []
7203 draft = len(repo.revs(b'draft()'))
7198 draft = len(repo.revs(b'draft()'))
7204 if draft:
7199 if draft:
7205 t.append(_(b'%d draft') % draft)
7200 t.append(_(b'%d draft') % draft)
7206 secret = len(repo.revs(b'secret()'))
7201 secret = len(repo.revs(b'secret()'))
7207 if secret:
7202 if secret:
7208 t.append(_(b'%d secret') % secret)
7203 t.append(_(b'%d secret') % secret)
7209
7204
7210 if draft or secret:
7205 if draft or secret:
7211 ui.status(_(b'phases: %s\n') % b', '.join(t))
7206 ui.status(_(b'phases: %s\n') % b', '.join(t))
7212
7207
7213 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7208 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7214 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7209 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7215 numtrouble = len(repo.revs(trouble + b"()"))
7210 numtrouble = len(repo.revs(trouble + b"()"))
7216 # We write all the possibilities to ease translation
7211 # We write all the possibilities to ease translation
7217 troublemsg = {
7212 troublemsg = {
7218 b"orphan": _(b"orphan: %d changesets"),
7213 b"orphan": _(b"orphan: %d changesets"),
7219 b"contentdivergent": _(b"content-divergent: %d changesets"),
7214 b"contentdivergent": _(b"content-divergent: %d changesets"),
7220 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7215 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7221 }
7216 }
7222 if numtrouble > 0:
7217 if numtrouble > 0:
7223 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7218 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7224
7219
7225 cmdutil.summaryhooks(ui, repo)
7220 cmdutil.summaryhooks(ui, repo)
7226
7221
7227 if opts.get(b'remote'):
7222 if opts.get(b'remote'):
7228 needsincoming, needsoutgoing = True, True
7223 needsincoming, needsoutgoing = True, True
7229 else:
7224 else:
7230 needsincoming, needsoutgoing = False, False
7225 needsincoming, needsoutgoing = False, False
7231 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7226 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7232 if i:
7227 if i:
7233 needsincoming = True
7228 needsincoming = True
7234 if o:
7229 if o:
7235 needsoutgoing = True
7230 needsoutgoing = True
7236 if not needsincoming and not needsoutgoing:
7231 if not needsincoming and not needsoutgoing:
7237 return
7232 return
7238
7233
7239 def getincoming():
7234 def getincoming():
7240 # XXX We should actually skip this if no default is specified, instead
7235 # XXX We should actually skip this if no default is specified, instead
7241 # of passing "default" which will resolve as "./default/" if no default
7236 # of passing "default" which will resolve as "./default/" if no default
7242 # path is defined.
7237 # path is defined.
7243 source, branches = urlutil.get_unique_pull_path(
7238 source, branches = urlutil.get_unique_pull_path(
7244 b'summary', repo, ui, b'default'
7239 b'summary', repo, ui, b'default'
7245 )
7240 )
7246 sbranch = branches[0]
7241 sbranch = branches[0]
7247 try:
7242 try:
7248 other = hg.peer(repo, {}, source)
7243 other = hg.peer(repo, {}, source)
7249 except error.RepoError:
7244 except error.RepoError:
7250 if opts.get(b'remote'):
7245 if opts.get(b'remote'):
7251 raise
7246 raise
7252 return source, sbranch, None, None, None
7247 return source, sbranch, None, None, None
7253 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7248 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7254 if revs:
7249 if revs:
7255 revs = [other.lookup(rev) for rev in revs]
7250 revs = [other.lookup(rev) for rev in revs]
7256 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7251 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7257 with repo.ui.silent():
7252 with repo.ui.silent():
7258 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7253 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7259 return source, sbranch, other, commoninc, commoninc[1]
7254 return source, sbranch, other, commoninc, commoninc[1]
7260
7255
7261 if needsincoming:
7256 if needsincoming:
7262 source, sbranch, sother, commoninc, incoming = getincoming()
7257 source, sbranch, sother, commoninc, incoming = getincoming()
7263 else:
7258 else:
7264 source = sbranch = sother = commoninc = incoming = None
7259 source = sbranch = sother = commoninc = incoming = None
7265
7260
7266 def getoutgoing():
7261 def getoutgoing():
7267 # XXX We should actually skip this if no default is specified, instead
7262 # XXX We should actually skip this if no default is specified, instead
7268 # of passing "default" which will resolve as "./default/" if no default
7263 # of passing "default" which will resolve as "./default/" if no default
7269 # path is defined.
7264 # path is defined.
7270 d = None
7265 d = None
7271 if b'default-push' in ui.paths:
7266 if b'default-push' in ui.paths:
7272 d = b'default-push'
7267 d = b'default-push'
7273 elif b'default' in ui.paths:
7268 elif b'default' in ui.paths:
7274 d = b'default'
7269 d = b'default'
7275 if d is not None:
7270 if d is not None:
7276 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7271 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7277 dest = path.pushloc or path.loc
7272 dest = path.pushloc or path.loc
7278 dbranch = path.branch
7273 dbranch = path.branch
7279 else:
7274 else:
7280 dest = b'default'
7275 dest = b'default'
7281 dbranch = None
7276 dbranch = None
7282 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7277 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7283 if source != dest:
7278 if source != dest:
7284 try:
7279 try:
7285 dother = hg.peer(repo, {}, dest)
7280 dother = hg.peer(repo, {}, dest)
7286 except error.RepoError:
7281 except error.RepoError:
7287 if opts.get(b'remote'):
7282 if opts.get(b'remote'):
7288 raise
7283 raise
7289 return dest, dbranch, None, None
7284 return dest, dbranch, None, None
7290 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7285 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7291 elif sother is None:
7286 elif sother is None:
7292 # there is no explicit destination peer, but source one is invalid
7287 # there is no explicit destination peer, but source one is invalid
7293 return dest, dbranch, None, None
7288 return dest, dbranch, None, None
7294 else:
7289 else:
7295 dother = sother
7290 dother = sother
7296 if source != dest or (sbranch is not None and sbranch != dbranch):
7291 if source != dest or (sbranch is not None and sbranch != dbranch):
7297 common = None
7292 common = None
7298 else:
7293 else:
7299 common = commoninc
7294 common = commoninc
7300 if revs:
7295 if revs:
7301 revs = [repo.lookup(rev) for rev in revs]
7296 revs = [repo.lookup(rev) for rev in revs]
7302 with repo.ui.silent():
7297 with repo.ui.silent():
7303 outgoing = discovery.findcommonoutgoing(
7298 outgoing = discovery.findcommonoutgoing(
7304 repo, dother, onlyheads=revs, commoninc=common
7299 repo, dother, onlyheads=revs, commoninc=common
7305 )
7300 )
7306 return dest, dbranch, dother, outgoing
7301 return dest, dbranch, dother, outgoing
7307
7302
7308 if needsoutgoing:
7303 if needsoutgoing:
7309 dest, dbranch, dother, outgoing = getoutgoing()
7304 dest, dbranch, dother, outgoing = getoutgoing()
7310 else:
7305 else:
7311 dest = dbranch = dother = outgoing = None
7306 dest = dbranch = dother = outgoing = None
7312
7307
7313 if opts.get(b'remote'):
7308 if opts.get(b'remote'):
7314 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7309 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7315 # The former always sets `sother` (or raises an exception if it can't);
7310 # The former always sets `sother` (or raises an exception if it can't);
7316 # the latter always sets `outgoing`.
7311 # the latter always sets `outgoing`.
7317 assert sother is not None
7312 assert sother is not None
7318 assert outgoing is not None
7313 assert outgoing is not None
7319
7314
7320 t = []
7315 t = []
7321 if incoming:
7316 if incoming:
7322 t.append(_(b'1 or more incoming'))
7317 t.append(_(b'1 or more incoming'))
7323 o = outgoing.missing
7318 o = outgoing.missing
7324 if o:
7319 if o:
7325 t.append(_(b'%d outgoing') % len(o))
7320 t.append(_(b'%d outgoing') % len(o))
7326 other = dother or sother
7321 other = dother or sother
7327 if b'bookmarks' in other.listkeys(b'namespaces'):
7322 if b'bookmarks' in other.listkeys(b'namespaces'):
7328 counts = bookmarks.summary(repo, other)
7323 counts = bookmarks.summary(repo, other)
7329 if counts[0] > 0:
7324 if counts[0] > 0:
7330 t.append(_(b'%d incoming bookmarks') % counts[0])
7325 t.append(_(b'%d incoming bookmarks') % counts[0])
7331 if counts[1] > 0:
7326 if counts[1] > 0:
7332 t.append(_(b'%d outgoing bookmarks') % counts[1])
7327 t.append(_(b'%d outgoing bookmarks') % counts[1])
7333
7328
7334 if t:
7329 if t:
7335 # i18n: column positioning for "hg summary"
7330 # i18n: column positioning for "hg summary"
7336 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7331 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7337 else:
7332 else:
7338 # i18n: column positioning for "hg summary"
7333 # i18n: column positioning for "hg summary"
7339 ui.status(_(b'remote: (synced)\n'))
7334 ui.status(_(b'remote: (synced)\n'))
7340
7335
7341 cmdutil.summaryremotehooks(
7336 cmdutil.summaryremotehooks(
7342 ui,
7337 ui,
7343 repo,
7338 repo,
7344 opts,
7339 opts,
7345 (
7340 (
7346 (source, sbranch, sother, commoninc),
7341 (source, sbranch, sother, commoninc),
7347 (dest, dbranch, dother, outgoing),
7342 (dest, dbranch, dother, outgoing),
7348 ),
7343 ),
7349 )
7344 )
7350
7345
7351
7346
7352 @command(
7347 @command(
7353 b'tag',
7348 b'tag',
7354 [
7349 [
7355 (b'f', b'force', None, _(b'force tag')),
7350 (b'f', b'force', None, _(b'force tag')),
7356 (b'l', b'local', None, _(b'make the tag local')),
7351 (b'l', b'local', None, _(b'make the tag local')),
7357 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7352 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7358 (b'', b'remove', None, _(b'remove a tag')),
7353 (b'', b'remove', None, _(b'remove a tag')),
7359 # -l/--local is already there, commitopts cannot be used
7354 # -l/--local is already there, commitopts cannot be used
7360 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7355 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7361 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7356 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7362 ]
7357 ]
7363 + commitopts2,
7358 + commitopts2,
7364 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7359 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7365 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7360 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7366 )
7361 )
7367 def tag(ui, repo, name1, *names, **opts):
7362 def tag(ui, repo, name1, *names, **opts):
7368 """add one or more tags for the current or given revision
7363 """add one or more tags for the current or given revision
7369
7364
7370 Name a particular revision using <name>.
7365 Name a particular revision using <name>.
7371
7366
7372 Tags are used to name particular revisions of the repository and are
7367 Tags are used to name particular revisions of the repository and are
7373 very useful to compare different revisions, to go back to significant
7368 very useful to compare different revisions, to go back to significant
7374 earlier versions or to mark branch points as releases, etc. Changing
7369 earlier versions or to mark branch points as releases, etc. Changing
7375 an existing tag is normally disallowed; use -f/--force to override.
7370 an existing tag is normally disallowed; use -f/--force to override.
7376
7371
7377 If no revision is given, the parent of the working directory is
7372 If no revision is given, the parent of the working directory is
7378 used.
7373 used.
7379
7374
7380 To facilitate version control, distribution, and merging of tags,
7375 To facilitate version control, distribution, and merging of tags,
7381 they are stored as a file named ".hgtags" which is managed similarly
7376 they are stored as a file named ".hgtags" which is managed similarly
7382 to other project files and can be hand-edited if necessary. This
7377 to other project files and can be hand-edited if necessary. This
7383 also means that tagging creates a new commit. The file
7378 also means that tagging creates a new commit. The file
7384 ".hg/localtags" is used for local tags (not shared among
7379 ".hg/localtags" is used for local tags (not shared among
7385 repositories).
7380 repositories).
7386
7381
7387 Tag commits are usually made at the head of a branch. If the parent
7382 Tag commits are usually made at the head of a branch. If the parent
7388 of the working directory is not a branch head, :hg:`tag` aborts; use
7383 of the working directory is not a branch head, :hg:`tag` aborts; use
7389 -f/--force to force the tag commit to be based on a non-head
7384 -f/--force to force the tag commit to be based on a non-head
7390 changeset.
7385 changeset.
7391
7386
7392 See :hg:`help dates` for a list of formats valid for -d/--date.
7387 See :hg:`help dates` for a list of formats valid for -d/--date.
7393
7388
7394 Since tag names have priority over branch names during revision
7389 Since tag names have priority over branch names during revision
7395 lookup, using an existing branch name as a tag name is discouraged.
7390 lookup, using an existing branch name as a tag name is discouraged.
7396
7391
7397 Returns 0 on success.
7392 Returns 0 on success.
7398 """
7393 """
7399 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7394 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7400 opts = pycompat.byteskwargs(opts)
7395 opts = pycompat.byteskwargs(opts)
7401 with repo.wlock(), repo.lock():
7396 with repo.wlock(), repo.lock():
7402 rev_ = b"."
7397 rev_ = b"."
7403 names = [t.strip() for t in (name1,) + names]
7398 names = [t.strip() for t in (name1,) + names]
7404 if len(names) != len(set(names)):
7399 if len(names) != len(set(names)):
7405 raise error.InputError(_(b'tag names must be unique'))
7400 raise error.InputError(_(b'tag names must be unique'))
7406 for n in names:
7401 for n in names:
7407 scmutil.checknewlabel(repo, n, b'tag')
7402 scmutil.checknewlabel(repo, n, b'tag')
7408 if not n:
7403 if not n:
7409 raise error.InputError(
7404 raise error.InputError(
7410 _(b'tag names cannot consist entirely of whitespace')
7405 _(b'tag names cannot consist entirely of whitespace')
7411 )
7406 )
7412 if opts.get(b'rev'):
7407 if opts.get(b'rev'):
7413 rev_ = opts[b'rev']
7408 rev_ = opts[b'rev']
7414 message = opts.get(b'message')
7409 message = opts.get(b'message')
7415 if opts.get(b'remove'):
7410 if opts.get(b'remove'):
7416 if opts.get(b'local'):
7411 if opts.get(b'local'):
7417 expectedtype = b'local'
7412 expectedtype = b'local'
7418 else:
7413 else:
7419 expectedtype = b'global'
7414 expectedtype = b'global'
7420
7415
7421 for n in names:
7416 for n in names:
7422 if repo.tagtype(n) == b'global':
7417 if repo.tagtype(n) == b'global':
7423 alltags = tagsmod.findglobaltags(ui, repo)
7418 alltags = tagsmod.findglobaltags(ui, repo)
7424 if alltags[n][0] == repo.nullid:
7419 if alltags[n][0] == repo.nullid:
7425 raise error.InputError(
7420 raise error.InputError(
7426 _(b"tag '%s' is already removed") % n
7421 _(b"tag '%s' is already removed") % n
7427 )
7422 )
7428 if not repo.tagtype(n):
7423 if not repo.tagtype(n):
7429 raise error.InputError(_(b"tag '%s' does not exist") % n)
7424 raise error.InputError(_(b"tag '%s' does not exist") % n)
7430 if repo.tagtype(n) != expectedtype:
7425 if repo.tagtype(n) != expectedtype:
7431 if expectedtype == b'global':
7426 if expectedtype == b'global':
7432 raise error.InputError(
7427 raise error.InputError(
7433 _(b"tag '%s' is not a global tag") % n
7428 _(b"tag '%s' is not a global tag") % n
7434 )
7429 )
7435 else:
7430 else:
7436 raise error.InputError(
7431 raise error.InputError(
7437 _(b"tag '%s' is not a local tag") % n
7432 _(b"tag '%s' is not a local tag") % n
7438 )
7433 )
7439 rev_ = b'null'
7434 rev_ = b'null'
7440 if not message:
7435 if not message:
7441 # we don't translate commit messages
7436 # we don't translate commit messages
7442 message = b'Removed tag %s' % b', '.join(names)
7437 message = b'Removed tag %s' % b', '.join(names)
7443 elif not opts.get(b'force'):
7438 elif not opts.get(b'force'):
7444 for n in names:
7439 for n in names:
7445 if n in repo.tags():
7440 if n in repo.tags():
7446 raise error.InputError(
7441 raise error.InputError(
7447 _(b"tag '%s' already exists (use -f to force)") % n
7442 _(b"tag '%s' already exists (use -f to force)") % n
7448 )
7443 )
7449 if not opts.get(b'local'):
7444 if not opts.get(b'local'):
7450 p1, p2 = repo.dirstate.parents()
7445 p1, p2 = repo.dirstate.parents()
7451 if p2 != repo.nullid:
7446 if p2 != repo.nullid:
7452 raise error.StateError(_(b'uncommitted merge'))
7447 raise error.StateError(_(b'uncommitted merge'))
7453 bheads = repo.branchheads()
7448 bheads = repo.branchheads()
7454 if not opts.get(b'force') and bheads and p1 not in bheads:
7449 if not opts.get(b'force') and bheads and p1 not in bheads:
7455 raise error.InputError(
7450 raise error.InputError(
7456 _(
7451 _(
7457 b'working directory is not at a branch head '
7452 b'working directory is not at a branch head '
7458 b'(use -f to force)'
7453 b'(use -f to force)'
7459 )
7454 )
7460 )
7455 )
7461 node = scmutil.revsingle(repo, rev_).node()
7456 node = scmutil.revsingle(repo, rev_).node()
7462
7457
7463 if not message:
7458 if not message:
7464 # we don't translate commit messages
7459 # we don't translate commit messages
7465 message = b'Added tag %s for changeset %s' % (
7460 message = b'Added tag %s for changeset %s' % (
7466 b', '.join(names),
7461 b', '.join(names),
7467 short(node),
7462 short(node),
7468 )
7463 )
7469
7464
7470 date = opts.get(b'date')
7465 date = opts.get(b'date')
7471 if date:
7466 if date:
7472 date = dateutil.parsedate(date)
7467 date = dateutil.parsedate(date)
7473
7468
7474 if opts.get(b'remove'):
7469 if opts.get(b'remove'):
7475 editform = b'tag.remove'
7470 editform = b'tag.remove'
7476 else:
7471 else:
7477 editform = b'tag.add'
7472 editform = b'tag.add'
7478 editor = cmdutil.getcommiteditor(
7473 editor = cmdutil.getcommiteditor(
7479 editform=editform, **pycompat.strkwargs(opts)
7474 editform=editform, **pycompat.strkwargs(opts)
7480 )
7475 )
7481
7476
7482 # don't allow tagging the null rev
7477 # don't allow tagging the null rev
7483 if (
7478 if (
7484 not opts.get(b'remove')
7479 not opts.get(b'remove')
7485 and scmutil.revsingle(repo, rev_).rev() == nullrev
7480 and scmutil.revsingle(repo, rev_).rev() == nullrev
7486 ):
7481 ):
7487 raise error.InputError(_(b"cannot tag null revision"))
7482 raise error.InputError(_(b"cannot tag null revision"))
7488
7483
7489 tagsmod.tag(
7484 tagsmod.tag(
7490 repo,
7485 repo,
7491 names,
7486 names,
7492 node,
7487 node,
7493 message,
7488 message,
7494 opts.get(b'local'),
7489 opts.get(b'local'),
7495 opts.get(b'user'),
7490 opts.get(b'user'),
7496 date,
7491 date,
7497 editor=editor,
7492 editor=editor,
7498 )
7493 )
7499
7494
7500
7495
7501 @command(
7496 @command(
7502 b'tags',
7497 b'tags',
7503 formatteropts,
7498 formatteropts,
7504 b'',
7499 b'',
7505 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7500 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7506 intents={INTENT_READONLY},
7501 intents={INTENT_READONLY},
7507 )
7502 )
7508 def tags(ui, repo, **opts):
7503 def tags(ui, repo, **opts):
7509 """list repository tags
7504 """list repository tags
7510
7505
7511 This lists both regular and local tags. When the -v/--verbose
7506 This lists both regular and local tags. When the -v/--verbose
7512 switch is used, a third column "local" is printed for local tags.
7507 switch is used, a third column "local" is printed for local tags.
7513 When the -q/--quiet switch is used, only the tag name is printed.
7508 When the -q/--quiet switch is used, only the tag name is printed.
7514
7509
7515 .. container:: verbose
7510 .. container:: verbose
7516
7511
7517 Template:
7512 Template:
7518
7513
7519 The following keywords are supported in addition to the common template
7514 The following keywords are supported in addition to the common template
7520 keywords and functions such as ``{tag}``. See also
7515 keywords and functions such as ``{tag}``. See also
7521 :hg:`help templates`.
7516 :hg:`help templates`.
7522
7517
7523 :type: String. ``local`` for local tags.
7518 :type: String. ``local`` for local tags.
7524
7519
7525 Returns 0 on success.
7520 Returns 0 on success.
7526 """
7521 """
7527
7522
7528 opts = pycompat.byteskwargs(opts)
7523 opts = pycompat.byteskwargs(opts)
7529 ui.pager(b'tags')
7524 ui.pager(b'tags')
7530 fm = ui.formatter(b'tags', opts)
7525 fm = ui.formatter(b'tags', opts)
7531 hexfunc = fm.hexfunc
7526 hexfunc = fm.hexfunc
7532
7527
7533 for t, n in reversed(repo.tagslist()):
7528 for t, n in reversed(repo.tagslist()):
7534 hn = hexfunc(n)
7529 hn = hexfunc(n)
7535 label = b'tags.normal'
7530 label = b'tags.normal'
7536 tagtype = repo.tagtype(t)
7531 tagtype = repo.tagtype(t)
7537 if not tagtype or tagtype == b'global':
7532 if not tagtype or tagtype == b'global':
7538 tagtype = b''
7533 tagtype = b''
7539 else:
7534 else:
7540 label = b'tags.' + tagtype
7535 label = b'tags.' + tagtype
7541
7536
7542 fm.startitem()
7537 fm.startitem()
7543 fm.context(repo=repo)
7538 fm.context(repo=repo)
7544 fm.write(b'tag', b'%s', t, label=label)
7539 fm.write(b'tag', b'%s', t, label=label)
7545 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7540 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7546 fm.condwrite(
7541 fm.condwrite(
7547 not ui.quiet,
7542 not ui.quiet,
7548 b'rev node',
7543 b'rev node',
7549 fmt,
7544 fmt,
7550 repo.changelog.rev(n),
7545 repo.changelog.rev(n),
7551 hn,
7546 hn,
7552 label=label,
7547 label=label,
7553 )
7548 )
7554 fm.condwrite(
7549 fm.condwrite(
7555 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7550 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7556 )
7551 )
7557 fm.plain(b'\n')
7552 fm.plain(b'\n')
7558 fm.end()
7553 fm.end()
7559
7554
7560
7555
7561 @command(
7556 @command(
7562 b'tip',
7557 b'tip',
7563 [
7558 [
7564 (b'p', b'patch', None, _(b'show patch')),
7559 (b'p', b'patch', None, _(b'show patch')),
7565 (b'g', b'git', None, _(b'use git extended diff format')),
7560 (b'g', b'git', None, _(b'use git extended diff format')),
7566 ]
7561 ]
7567 + templateopts,
7562 + templateopts,
7568 _(b'[-p] [-g]'),
7563 _(b'[-p] [-g]'),
7569 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7564 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7570 )
7565 )
7571 def tip(ui, repo, **opts):
7566 def tip(ui, repo, **opts):
7572 """show the tip revision (DEPRECATED)
7567 """show the tip revision (DEPRECATED)
7573
7568
7574 The tip revision (usually just called the tip) is the changeset
7569 The tip revision (usually just called the tip) is the changeset
7575 most recently added to the repository (and therefore the most
7570 most recently added to the repository (and therefore the most
7576 recently changed head).
7571 recently changed head).
7577
7572
7578 If you have just made a commit, that commit will be the tip. If
7573 If you have just made a commit, that commit will be the tip. If
7579 you have just pulled changes from another repository, the tip of
7574 you have just pulled changes from another repository, the tip of
7580 that repository becomes the current tip. The "tip" tag is special
7575 that repository becomes the current tip. The "tip" tag is special
7581 and cannot be renamed or assigned to a different changeset.
7576 and cannot be renamed or assigned to a different changeset.
7582
7577
7583 This command is deprecated, please use :hg:`heads` instead.
7578 This command is deprecated, please use :hg:`heads` instead.
7584
7579
7585 Returns 0 on success.
7580 Returns 0 on success.
7586 """
7581 """
7587 opts = pycompat.byteskwargs(opts)
7582 opts = pycompat.byteskwargs(opts)
7588 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7583 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7589 displayer.show(repo[b'tip'])
7584 displayer.show(repo[b'tip'])
7590 displayer.close()
7585 displayer.close()
7591
7586
7592
7587
7593 @command(
7588 @command(
7594 b'unbundle',
7589 b'unbundle',
7595 [
7590 [
7596 (
7591 (
7597 b'u',
7592 b'u',
7598 b'update',
7593 b'update',
7599 None,
7594 None,
7600 _(b'update to new branch head if changesets were unbundled'),
7595 _(b'update to new branch head if changesets were unbundled'),
7601 )
7596 )
7602 ],
7597 ],
7603 _(b'[-u] FILE...'),
7598 _(b'[-u] FILE...'),
7604 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7605 )
7600 )
7606 def unbundle(ui, repo, fname1, *fnames, **opts):
7601 def unbundle(ui, repo, fname1, *fnames, **opts):
7607 """apply one or more bundle files
7602 """apply one or more bundle files
7608
7603
7609 Apply one or more bundle files generated by :hg:`bundle`.
7604 Apply one or more bundle files generated by :hg:`bundle`.
7610
7605
7611 Returns 0 on success, 1 if an update has unresolved files.
7606 Returns 0 on success, 1 if an update has unresolved files.
7612 """
7607 """
7613 fnames = (fname1,) + fnames
7608 fnames = (fname1,) + fnames
7614
7609
7615 with repo.lock():
7610 with repo.lock():
7616 for fname in fnames:
7611 for fname in fnames:
7617 f = hg.openpath(ui, fname)
7612 f = hg.openpath(ui, fname)
7618 gen = exchange.readbundle(ui, f, fname)
7613 gen = exchange.readbundle(ui, f, fname)
7619 if isinstance(gen, streamclone.streamcloneapplier):
7614 if isinstance(gen, streamclone.streamcloneapplier):
7620 raise error.InputError(
7615 raise error.InputError(
7621 _(
7616 _(
7622 b'packed bundles cannot be applied with '
7617 b'packed bundles cannot be applied with '
7623 b'"hg unbundle"'
7618 b'"hg unbundle"'
7624 ),
7619 ),
7625 hint=_(b'use "hg debugapplystreamclonebundle"'),
7620 hint=_(b'use "hg debugapplystreamclonebundle"'),
7626 )
7621 )
7627 url = b'bundle:' + fname
7622 url = b'bundle:' + fname
7628 try:
7623 try:
7629 txnname = b'unbundle'
7624 txnname = b'unbundle'
7630 if not isinstance(gen, bundle2.unbundle20):
7625 if not isinstance(gen, bundle2.unbundle20):
7631 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7626 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7632 with repo.transaction(txnname) as tr:
7627 with repo.transaction(txnname) as tr:
7633 op = bundle2.applybundle(
7628 op = bundle2.applybundle(
7634 repo, gen, tr, source=b'unbundle', url=url
7629 repo, gen, tr, source=b'unbundle', url=url
7635 )
7630 )
7636 except error.BundleUnknownFeatureError as exc:
7631 except error.BundleUnknownFeatureError as exc:
7637 raise error.Abort(
7632 raise error.Abort(
7638 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7633 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7639 hint=_(
7634 hint=_(
7640 b"see https://mercurial-scm.org/"
7635 b"see https://mercurial-scm.org/"
7641 b"wiki/BundleFeature for more "
7636 b"wiki/BundleFeature for more "
7642 b"information"
7637 b"information"
7643 ),
7638 ),
7644 )
7639 )
7645 modheads = bundle2.combinechangegroupresults(op)
7640 modheads = bundle2.combinechangegroupresults(op)
7646
7641
7647 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7642 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7648 return 1
7643 return 1
7649 else:
7644 else:
7650 return 0
7645 return 0
7651
7646
7652
7647
7653 @command(
7648 @command(
7654 b'unshelve',
7649 b'unshelve',
7655 [
7650 [
7656 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7651 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7657 (
7652 (
7658 b'c',
7653 b'c',
7659 b'continue',
7654 b'continue',
7660 None,
7655 None,
7661 _(b'continue an incomplete unshelve operation'),
7656 _(b'continue an incomplete unshelve operation'),
7662 ),
7657 ),
7663 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7658 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7664 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7659 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7665 (
7660 (
7666 b'n',
7661 b'n',
7667 b'name',
7662 b'name',
7668 b'',
7663 b'',
7669 _(b'restore shelved change with given name'),
7664 _(b'restore shelved change with given name'),
7670 _(b'NAME'),
7665 _(b'NAME'),
7671 ),
7666 ),
7672 (b't', b'tool', b'', _(b'specify merge tool')),
7667 (b't', b'tool', b'', _(b'specify merge tool')),
7673 (
7668 (
7674 b'',
7669 b'',
7675 b'date',
7670 b'date',
7676 b'',
7671 b'',
7677 _(b'set date for temporary commits (DEPRECATED)'),
7672 _(b'set date for temporary commits (DEPRECATED)'),
7678 _(b'DATE'),
7673 _(b'DATE'),
7679 ),
7674 ),
7680 ],
7675 ],
7681 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7676 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7677 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7683 )
7678 )
7684 def unshelve(ui, repo, *shelved, **opts):
7679 def unshelve(ui, repo, *shelved, **opts):
7685 """restore a shelved change to the working directory
7680 """restore a shelved change to the working directory
7686
7681
7687 This command accepts an optional name of a shelved change to
7682 This command accepts an optional name of a shelved change to
7688 restore. If none is given, the most recent shelved change is used.
7683 restore. If none is given, the most recent shelved change is used.
7689
7684
7690 If a shelved change is applied successfully, the bundle that
7685 If a shelved change is applied successfully, the bundle that
7691 contains the shelved changes is moved to a backup location
7686 contains the shelved changes is moved to a backup location
7692 (.hg/shelve-backup).
7687 (.hg/shelve-backup).
7693
7688
7694 Since you can restore a shelved change on top of an arbitrary
7689 Since you can restore a shelved change on top of an arbitrary
7695 commit, it is possible that unshelving will result in a conflict
7690 commit, it is possible that unshelving will result in a conflict
7696 between your changes and the commits you are unshelving onto. If
7691 between your changes and the commits you are unshelving onto. If
7697 this occurs, you must resolve the conflict, then use
7692 this occurs, you must resolve the conflict, then use
7698 ``--continue`` to complete the unshelve operation. (The bundle
7693 ``--continue`` to complete the unshelve operation. (The bundle
7699 will not be moved until you successfully complete the unshelve.)
7694 will not be moved until you successfully complete the unshelve.)
7700
7695
7701 (Alternatively, you can use ``--abort`` to abandon an unshelve
7696 (Alternatively, you can use ``--abort`` to abandon an unshelve
7702 that causes a conflict. This reverts the unshelved changes, and
7697 that causes a conflict. This reverts the unshelved changes, and
7703 leaves the bundle in place.)
7698 leaves the bundle in place.)
7704
7699
7705 If bare shelved change (without interactive, include and exclude
7700 If bare shelved change (without interactive, include and exclude
7706 option) was done on newly created branch it would restore branch
7701 option) was done on newly created branch it would restore branch
7707 information to the working directory.
7702 information to the working directory.
7708
7703
7709 After a successful unshelve, the shelved changes are stored in a
7704 After a successful unshelve, the shelved changes are stored in a
7710 backup directory. Only the N most recent backups are kept. N
7705 backup directory. Only the N most recent backups are kept. N
7711 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7706 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7712 configuration option.
7707 configuration option.
7713
7708
7714 .. container:: verbose
7709 .. container:: verbose
7715
7710
7716 Timestamp in seconds is used to decide order of backups. More
7711 Timestamp in seconds is used to decide order of backups. More
7717 than ``maxbackups`` backups are kept, if same timestamp
7712 than ``maxbackups`` backups are kept, if same timestamp
7718 prevents from deciding exact order of them, for safety.
7713 prevents from deciding exact order of them, for safety.
7719
7714
7720 Selected changes can be unshelved with ``--interactive`` flag.
7715 Selected changes can be unshelved with ``--interactive`` flag.
7721 The working directory is updated with the selected changes, and
7716 The working directory is updated with the selected changes, and
7722 only the unselected changes remain shelved.
7717 only the unselected changes remain shelved.
7723 Note: The whole shelve is applied to working directory first before
7718 Note: The whole shelve is applied to working directory first before
7724 running interactively. So, this will bring up all the conflicts between
7719 running interactively. So, this will bring up all the conflicts between
7725 working directory and the shelve, irrespective of which changes will be
7720 working directory and the shelve, irrespective of which changes will be
7726 unshelved.
7721 unshelved.
7727 """
7722 """
7728 with repo.wlock():
7723 with repo.wlock():
7729 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7724 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7730
7725
7731
7726
7732 statemod.addunfinished(
7727 statemod.addunfinished(
7733 b'unshelve',
7728 b'unshelve',
7734 fname=b'shelvedstate',
7729 fname=b'shelvedstate',
7735 continueflag=True,
7730 continueflag=True,
7736 abortfunc=shelvemod.hgabortunshelve,
7731 abortfunc=shelvemod.hgabortunshelve,
7737 continuefunc=shelvemod.hgcontinueunshelve,
7732 continuefunc=shelvemod.hgcontinueunshelve,
7738 cmdmsg=_(b'unshelve already in progress'),
7733 cmdmsg=_(b'unshelve already in progress'),
7739 )
7734 )
7740
7735
7741
7736
7742 @command(
7737 @command(
7743 b'update|up|checkout|co',
7738 b'update|up|checkout|co',
7744 [
7739 [
7745 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7740 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7746 (b'c', b'check', None, _(b'require clean working directory')),
7741 (b'c', b'check', None, _(b'require clean working directory')),
7747 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7742 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7748 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7743 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7749 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7744 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7750 ]
7745 ]
7751 + mergetoolopts,
7746 + mergetoolopts,
7752 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7747 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7753 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7748 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7754 helpbasic=True,
7749 helpbasic=True,
7755 )
7750 )
7756 def update(ui, repo, node=None, **opts):
7751 def update(ui, repo, node=None, **opts):
7757 """update working directory (or switch revisions)
7752 """update working directory (or switch revisions)
7758
7753
7759 Update the repository's working directory to the specified
7754 Update the repository's working directory to the specified
7760 changeset. If no changeset is specified, update to the tip of the
7755 changeset. If no changeset is specified, update to the tip of the
7761 current named branch and move the active bookmark (see :hg:`help
7756 current named branch and move the active bookmark (see :hg:`help
7762 bookmarks`).
7757 bookmarks`).
7763
7758
7764 Update sets the working directory's parent revision to the specified
7759 Update sets the working directory's parent revision to the specified
7765 changeset (see :hg:`help parents`).
7760 changeset (see :hg:`help parents`).
7766
7761
7767 If the changeset is not a descendant or ancestor of the working
7762 If the changeset is not a descendant or ancestor of the working
7768 directory's parent and there are uncommitted changes, the update is
7763 directory's parent and there are uncommitted changes, the update is
7769 aborted. With the -c/--check option, the working directory is checked
7764 aborted. With the -c/--check option, the working directory is checked
7770 for uncommitted changes; if none are found, the working directory is
7765 for uncommitted changes; if none are found, the working directory is
7771 updated to the specified changeset.
7766 updated to the specified changeset.
7772
7767
7773 .. container:: verbose
7768 .. container:: verbose
7774
7769
7775 The -C/--clean, -c/--check, and -m/--merge options control what
7770 The -C/--clean, -c/--check, and -m/--merge options control what
7776 happens if the working directory contains uncommitted changes.
7771 happens if the working directory contains uncommitted changes.
7777 At most of one of them can be specified.
7772 At most of one of them can be specified.
7778
7773
7779 1. If no option is specified, and if
7774 1. If no option is specified, and if
7780 the requested changeset is an ancestor or descendant of
7775 the requested changeset is an ancestor or descendant of
7781 the working directory's parent, the uncommitted changes
7776 the working directory's parent, the uncommitted changes
7782 are merged into the requested changeset and the merged
7777 are merged into the requested changeset and the merged
7783 result is left uncommitted. If the requested changeset is
7778 result is left uncommitted. If the requested changeset is
7784 not an ancestor or descendant (that is, it is on another
7779 not an ancestor or descendant (that is, it is on another
7785 branch), the update is aborted and the uncommitted changes
7780 branch), the update is aborted and the uncommitted changes
7786 are preserved.
7781 are preserved.
7787
7782
7788 2. With the -m/--merge option, the update is allowed even if the
7783 2. With the -m/--merge option, the update is allowed even if the
7789 requested changeset is not an ancestor or descendant of
7784 requested changeset is not an ancestor or descendant of
7790 the working directory's parent.
7785 the working directory's parent.
7791
7786
7792 3. With the -c/--check option, the update is aborted and the
7787 3. With the -c/--check option, the update is aborted and the
7793 uncommitted changes are preserved.
7788 uncommitted changes are preserved.
7794
7789
7795 4. With the -C/--clean option, uncommitted changes are discarded and
7790 4. With the -C/--clean option, uncommitted changes are discarded and
7796 the working directory is updated to the requested changeset.
7791 the working directory is updated to the requested changeset.
7797
7792
7798 To cancel an uncommitted merge (and lose your changes), use
7793 To cancel an uncommitted merge (and lose your changes), use
7799 :hg:`merge --abort`.
7794 :hg:`merge --abort`.
7800
7795
7801 Use null as the changeset to remove the working directory (like
7796 Use null as the changeset to remove the working directory (like
7802 :hg:`clone -U`).
7797 :hg:`clone -U`).
7803
7798
7804 If you want to revert just one file to an older revision, use
7799 If you want to revert just one file to an older revision, use
7805 :hg:`revert [-r REV] NAME`.
7800 :hg:`revert [-r REV] NAME`.
7806
7801
7807 See :hg:`help dates` for a list of formats valid for -d/--date.
7802 See :hg:`help dates` for a list of formats valid for -d/--date.
7808
7803
7809 Returns 0 on success, 1 if there are unresolved files.
7804 Returns 0 on success, 1 if there are unresolved files.
7810 """
7805 """
7811 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7806 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7812 rev = opts.get('rev')
7807 rev = opts.get('rev')
7813 date = opts.get('date')
7808 date = opts.get('date')
7814 clean = opts.get('clean')
7809 clean = opts.get('clean')
7815 check = opts.get('check')
7810 check = opts.get('check')
7816 merge = opts.get('merge')
7811 merge = opts.get('merge')
7817 if rev and node:
7812 if rev and node:
7818 raise error.InputError(_(b"please specify just one revision"))
7813 raise error.InputError(_(b"please specify just one revision"))
7819
7814
7820 if ui.configbool(b'commands', b'update.requiredest'):
7815 if ui.configbool(b'commands', b'update.requiredest'):
7821 if not node and not rev and not date:
7816 if not node and not rev and not date:
7822 raise error.InputError(
7817 raise error.InputError(
7823 _(b'you must specify a destination'),
7818 _(b'you must specify a destination'),
7824 hint=_(b'for example: hg update ".::"'),
7819 hint=_(b'for example: hg update ".::"'),
7825 )
7820 )
7826
7821
7827 if rev is None or rev == b'':
7822 if rev is None or rev == b'':
7828 rev = node
7823 rev = node
7829
7824
7830 if date and rev is not None:
7825 if date and rev is not None:
7831 raise error.InputError(_(b"you can't specify a revision and a date"))
7826 raise error.InputError(_(b"you can't specify a revision and a date"))
7832
7827
7833 updatecheck = None
7828 updatecheck = None
7834 if check:
7829 if check:
7835 updatecheck = b'abort'
7830 updatecheck = b'abort'
7836 elif merge:
7831 elif merge:
7837 updatecheck = b'none'
7832 updatecheck = b'none'
7838
7833
7839 with repo.wlock():
7834 with repo.wlock():
7840 cmdutil.clearunfinished(repo)
7835 cmdutil.clearunfinished(repo)
7841 if date:
7836 if date:
7842 rev = cmdutil.finddate(ui, repo, date)
7837 rev = cmdutil.finddate(ui, repo, date)
7843
7838
7844 # if we defined a bookmark, we have to remember the original name
7839 # if we defined a bookmark, we have to remember the original name
7845 brev = rev
7840 brev = rev
7846 if rev:
7841 if rev:
7847 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7842 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7848 ctx = scmutil.revsingle(repo, rev, default=None)
7843 ctx = scmutil.revsingle(repo, rev, default=None)
7849 rev = ctx.rev()
7844 rev = ctx.rev()
7850 hidden = ctx.hidden()
7845 hidden = ctx.hidden()
7851 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7846 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7852 with ui.configoverride(overrides, b'update'):
7847 with ui.configoverride(overrides, b'update'):
7853 ret = hg.updatetotally(
7848 ret = hg.updatetotally(
7854 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7849 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7855 )
7850 )
7856 if hidden:
7851 if hidden:
7857 ctxstr = ctx.hex()[:12]
7852 ctxstr = ctx.hex()[:12]
7858 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7853 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7859
7854
7860 if ctx.obsolete():
7855 if ctx.obsolete():
7861 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7856 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7862 ui.warn(b"(%s)\n" % obsfatemsg)
7857 ui.warn(b"(%s)\n" % obsfatemsg)
7863 return ret
7858 return ret
7864
7859
7865
7860
7866 @command(
7861 @command(
7867 b'verify',
7862 b'verify',
7868 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7863 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7869 helpcategory=command.CATEGORY_MAINTENANCE,
7864 helpcategory=command.CATEGORY_MAINTENANCE,
7870 )
7865 )
7871 def verify(ui, repo, **opts):
7866 def verify(ui, repo, **opts):
7872 """verify the integrity of the repository
7867 """verify the integrity of the repository
7873
7868
7874 Verify the integrity of the current repository.
7869 Verify the integrity of the current repository.
7875
7870
7876 This will perform an extensive check of the repository's
7871 This will perform an extensive check of the repository's
7877 integrity, validating the hashes and checksums of each entry in
7872 integrity, validating the hashes and checksums of each entry in
7878 the changelog, manifest, and tracked files, as well as the
7873 the changelog, manifest, and tracked files, as well as the
7879 integrity of their crosslinks and indices.
7874 integrity of their crosslinks and indices.
7880
7875
7881 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7876 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7882 for more information about recovery from corruption of the
7877 for more information about recovery from corruption of the
7883 repository.
7878 repository.
7884
7879
7885 Returns 0 on success, 1 if errors are encountered.
7880 Returns 0 on success, 1 if errors are encountered.
7886 """
7881 """
7887 opts = pycompat.byteskwargs(opts)
7882 opts = pycompat.byteskwargs(opts)
7888
7883
7889 level = None
7884 level = None
7890 if opts[b'full']:
7885 if opts[b'full']:
7891 level = verifymod.VERIFY_FULL
7886 level = verifymod.VERIFY_FULL
7892 return hg.verify(repo, level)
7887 return hg.verify(repo, level)
7893
7888
7894
7889
7895 @command(
7890 @command(
7896 b'version',
7891 b'version',
7897 [] + formatteropts,
7892 [] + formatteropts,
7898 helpcategory=command.CATEGORY_HELP,
7893 helpcategory=command.CATEGORY_HELP,
7899 norepo=True,
7894 norepo=True,
7900 intents={INTENT_READONLY},
7895 intents={INTENT_READONLY},
7901 )
7896 )
7902 def version_(ui, **opts):
7897 def version_(ui, **opts):
7903 """output version and copyright information
7898 """output version and copyright information
7904
7899
7905 .. container:: verbose
7900 .. container:: verbose
7906
7901
7907 Template:
7902 Template:
7908
7903
7909 The following keywords are supported. See also :hg:`help templates`.
7904 The following keywords are supported. See also :hg:`help templates`.
7910
7905
7911 :extensions: List of extensions.
7906 :extensions: List of extensions.
7912 :ver: String. Version number.
7907 :ver: String. Version number.
7913
7908
7914 And each entry of ``{extensions}`` provides the following sub-keywords
7909 And each entry of ``{extensions}`` provides the following sub-keywords
7915 in addition to ``{ver}``.
7910 in addition to ``{ver}``.
7916
7911
7917 :bundled: Boolean. True if included in the release.
7912 :bundled: Boolean. True if included in the release.
7918 :name: String. Extension name.
7913 :name: String. Extension name.
7919 """
7914 """
7920 opts = pycompat.byteskwargs(opts)
7915 opts = pycompat.byteskwargs(opts)
7921 if ui.verbose:
7916 if ui.verbose:
7922 ui.pager(b'version')
7917 ui.pager(b'version')
7923 fm = ui.formatter(b"version", opts)
7918 fm = ui.formatter(b"version", opts)
7924 fm.startitem()
7919 fm.startitem()
7925 fm.write(
7920 fm.write(
7926 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7921 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7927 )
7922 )
7928 license = _(
7923 license = _(
7929 b"(see https://mercurial-scm.org for more information)\n"
7924 b"(see https://mercurial-scm.org for more information)\n"
7930 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7925 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7931 b"This is free software; see the source for copying conditions. "
7926 b"This is free software; see the source for copying conditions. "
7932 b"There is NO\nwarranty; "
7927 b"There is NO\nwarranty; "
7933 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7928 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7934 )
7929 )
7935 if not ui.quiet:
7930 if not ui.quiet:
7936 fm.plain(license)
7931 fm.plain(license)
7937
7932
7938 if ui.verbose:
7933 if ui.verbose:
7939 fm.plain(_(b"\nEnabled extensions:\n\n"))
7934 fm.plain(_(b"\nEnabled extensions:\n\n"))
7940 # format names and versions into columns
7935 # format names and versions into columns
7941 names = []
7936 names = []
7942 vers = []
7937 vers = []
7943 isinternals = []
7938 isinternals = []
7944 for name, module in sorted(extensions.extensions()):
7939 for name, module in sorted(extensions.extensions()):
7945 names.append(name)
7940 names.append(name)
7946 vers.append(extensions.moduleversion(module) or None)
7941 vers.append(extensions.moduleversion(module) or None)
7947 isinternals.append(extensions.ismoduleinternal(module))
7942 isinternals.append(extensions.ismoduleinternal(module))
7948 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7943 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7949 if names:
7944 if names:
7950 namefmt = b" %%-%ds " % max(len(n) for n in names)
7945 namefmt = b" %%-%ds " % max(len(n) for n in names)
7951 places = [_(b"external"), _(b"internal")]
7946 places = [_(b"external"), _(b"internal")]
7952 for n, v, p in zip(names, vers, isinternals):
7947 for n, v, p in zip(names, vers, isinternals):
7953 fn.startitem()
7948 fn.startitem()
7954 fn.condwrite(ui.verbose, b"name", namefmt, n)
7949 fn.condwrite(ui.verbose, b"name", namefmt, n)
7955 if ui.verbose:
7950 if ui.verbose:
7956 fn.plain(b"%s " % places[p])
7951 fn.plain(b"%s " % places[p])
7957 fn.data(bundled=p)
7952 fn.data(bundled=p)
7958 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7953 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7959 if ui.verbose:
7954 if ui.verbose:
7960 fn.plain(b"\n")
7955 fn.plain(b"\n")
7961 fn.end()
7956 fn.end()
7962 fm.end()
7957 fm.end()
7963
7958
7964
7959
7965 def loadcmdtable(ui, name, cmdtable):
7960 def loadcmdtable(ui, name, cmdtable):
7966 """Load command functions from specified cmdtable"""
7961 """Load command functions from specified cmdtable"""
7967 overrides = [cmd for cmd in cmdtable if cmd in table]
7962 overrides = [cmd for cmd in cmdtable if cmd in table]
7968 if overrides:
7963 if overrides:
7969 ui.warn(
7964 ui.warn(
7970 _(b"extension '%s' overrides commands: %s\n")
7965 _(b"extension '%s' overrides commands: %s\n")
7971 % (name, b" ".join(overrides))
7966 % (name, b" ".join(overrides))
7972 )
7967 )
7973 table.update(cmdtable)
7968 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now