##// END OF EJS Templates
commands: remove pycompat.iteritems()...
Gregory Szorc -
r49774:8b3f3f10 default
parent child Browse files
Show More
@@ -1,7951 +1,7949 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import errno
9 import errno
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullrev,
17 nullrev,
18 short,
18 short,
19 wdirrev,
19 wdirrev,
20 )
20 )
21 from .pycompat import open
21 from .pycompat import open
22 from . import (
22 from . import (
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 bundlecaches,
26 bundlecaches,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 filemerge,
38 filemerge,
39 formatter,
39 formatter,
40 graphmod,
40 graphmod,
41 grep as grepmod,
41 grep as grepmod,
42 hbisect,
42 hbisect,
43 help,
43 help,
44 hg,
44 hg,
45 logcmdutil,
45 logcmdutil,
46 merge as mergemod,
46 merge as mergemod,
47 mergestate as mergestatemod,
47 mergestate as mergestatemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 requirements,
56 requirements,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 vfs as vfsmod,
68 vfs as vfsmod,
69 wireprotoserver,
69 wireprotoserver,
70 )
70 )
71 from .utils import (
71 from .utils import (
72 dateutil,
72 dateutil,
73 stringutil,
73 stringutil,
74 urlutil,
74 urlutil,
75 )
75 )
76
76
77 table = {}
77 table = {}
78 table.update(debugcommandsmod.command._table)
78 table.update(debugcommandsmod.command._table)
79
79
80 command = registrar.command(table)
80 command = registrar.command(table)
81 INTENT_READONLY = registrar.INTENT_READONLY
81 INTENT_READONLY = registrar.INTENT_READONLY
82
82
83 # common command options
83 # common command options
84
84
85 globalopts = [
85 globalopts = [
86 (
86 (
87 b'R',
87 b'R',
88 b'repository',
88 b'repository',
89 b'',
89 b'',
90 _(b'repository root directory or name of overlay bundle file'),
90 _(b'repository root directory or name of overlay bundle file'),
91 _(b'REPO'),
91 _(b'REPO'),
92 ),
92 ),
93 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
93 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (
94 (
95 b'y',
95 b'y',
96 b'noninteractive',
96 b'noninteractive',
97 None,
97 None,
98 _(
98 _(
99 b'do not prompt, automatically pick the first choice for all prompts'
99 b'do not prompt, automatically pick the first choice for all prompts'
100 ),
100 ),
101 ),
101 ),
102 (b'q', b'quiet', None, _(b'suppress output')),
102 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'v', b'verbose', None, _(b'enable additional output')),
103 (b'v', b'verbose', None, _(b'enable additional output')),
104 (
104 (
105 b'',
105 b'',
106 b'color',
106 b'color',
107 b'',
107 b'',
108 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
108 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # and should not be translated
109 # and should not be translated
110 _(b"when to colorize (boolean, always, auto, never, or debug)"),
110 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b'TYPE'),
111 _(b'TYPE'),
112 ),
112 ),
113 (
113 (
114 b'',
114 b'',
115 b'config',
115 b'config',
116 [],
116 [],
117 _(b'set/override config option (use \'section.name=value\')'),
117 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'CONFIG'),
118 _(b'CONFIG'),
119 ),
119 ),
120 (b'', b'debug', None, _(b'enable debugging output')),
120 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debugger', None, _(b'start debugger')),
121 (b'', b'debugger', None, _(b'start debugger')),
122 (
122 (
123 b'',
123 b'',
124 b'encoding',
124 b'encoding',
125 encoding.encoding,
125 encoding.encoding,
126 _(b'set the charset encoding'),
126 _(b'set the charset encoding'),
127 _(b'ENCODE'),
127 _(b'ENCODE'),
128 ),
128 ),
129 (
129 (
130 b'',
130 b'',
131 b'encodingmode',
131 b'encodingmode',
132 encoding.encodingmode,
132 encoding.encodingmode,
133 _(b'set the charset encoding mode'),
133 _(b'set the charset encoding mode'),
134 _(b'MODE'),
134 _(b'MODE'),
135 ),
135 ),
136 (b'', b'traceback', None, _(b'always print a traceback on exception')),
136 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'time', None, _(b'time how long the command takes')),
137 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'profile', None, _(b'print command execution profile')),
138 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'version', None, _(b'output version information and exit')),
139 (b'', b'version', None, _(b'output version information and exit')),
140 (b'h', b'help', None, _(b'display help and exit')),
140 (b'h', b'help', None, _(b'display help and exit')),
141 (b'', b'hidden', False, _(b'consider hidden changesets')),
141 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (
142 (
143 b'',
143 b'',
144 b'pager',
144 b'pager',
145 b'auto',
145 b'auto',
146 _(b"when to paginate (boolean, always, auto, or never)"),
146 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b'TYPE'),
147 _(b'TYPE'),
148 ),
148 ),
149 ]
149 ]
150
150
151 dryrunopts = cmdutil.dryrunopts
151 dryrunopts = cmdutil.dryrunopts
152 remoteopts = cmdutil.remoteopts
152 remoteopts = cmdutil.remoteopts
153 walkopts = cmdutil.walkopts
153 walkopts = cmdutil.walkopts
154 commitopts = cmdutil.commitopts
154 commitopts = cmdutil.commitopts
155 commitopts2 = cmdutil.commitopts2
155 commitopts2 = cmdutil.commitopts2
156 commitopts3 = cmdutil.commitopts3
156 commitopts3 = cmdutil.commitopts3
157 formatteropts = cmdutil.formatteropts
157 formatteropts = cmdutil.formatteropts
158 templateopts = cmdutil.templateopts
158 templateopts = cmdutil.templateopts
159 logopts = cmdutil.logopts
159 logopts = cmdutil.logopts
160 diffopts = cmdutil.diffopts
160 diffopts = cmdutil.diffopts
161 diffwsopts = cmdutil.diffwsopts
161 diffwsopts = cmdutil.diffwsopts
162 diffopts2 = cmdutil.diffopts2
162 diffopts2 = cmdutil.diffopts2
163 mergetoolopts = cmdutil.mergetoolopts
163 mergetoolopts = cmdutil.mergetoolopts
164 similarityopts = cmdutil.similarityopts
164 similarityopts = cmdutil.similarityopts
165 subrepoopts = cmdutil.subrepoopts
165 subrepoopts = cmdutil.subrepoopts
166 debugrevlogopts = cmdutil.debugrevlogopts
166 debugrevlogopts = cmdutil.debugrevlogopts
167
167
168 # Commands start here, listed alphabetically
168 # Commands start here, listed alphabetically
169
169
170
170
171 @command(
171 @command(
172 b'abort',
172 b'abort',
173 dryrunopts,
173 dryrunopts,
174 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
174 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpbasic=True,
175 helpbasic=True,
176 )
176 )
177 def abort(ui, repo, **opts):
177 def abort(ui, repo, **opts):
178 """abort an unfinished operation (EXPERIMENTAL)
178 """abort an unfinished operation (EXPERIMENTAL)
179
179
180 Aborts a multistep operation like graft, histedit, rebase, merge,
180 Aborts a multistep operation like graft, histedit, rebase, merge,
181 and unshelve if they are in an unfinished state.
181 and unshelve if they are in an unfinished state.
182
182
183 use --dry-run/-n to dry run the command.
183 use --dry-run/-n to dry run the command.
184 """
184 """
185 dryrun = opts.get('dry_run')
185 dryrun = opts.get('dry_run')
186 abortstate = cmdutil.getunfinishedstate(repo)
186 abortstate = cmdutil.getunfinishedstate(repo)
187 if not abortstate:
187 if not abortstate:
188 raise error.StateError(_(b'no operation in progress'))
188 raise error.StateError(_(b'no operation in progress'))
189 if not abortstate.abortfunc:
189 if not abortstate.abortfunc:
190 raise error.InputError(
190 raise error.InputError(
191 (
191 (
192 _(b"%s in progress but does not support 'hg abort'")
192 _(b"%s in progress but does not support 'hg abort'")
193 % (abortstate._opname)
193 % (abortstate._opname)
194 ),
194 ),
195 hint=abortstate.hint(),
195 hint=abortstate.hint(),
196 )
196 )
197 if dryrun:
197 if dryrun:
198 ui.status(
198 ui.status(
199 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
199 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 )
200 )
201 return
201 return
202 return abortstate.abortfunc(ui, repo)
202 return abortstate.abortfunc(ui, repo)
203
203
204
204
205 @command(
205 @command(
206 b'add',
206 b'add',
207 walkopts + subrepoopts + dryrunopts,
207 walkopts + subrepoopts + dryrunopts,
208 _(b'[OPTION]... [FILE]...'),
208 _(b'[OPTION]... [FILE]...'),
209 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
209 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpbasic=True,
210 helpbasic=True,
211 inferrepo=True,
211 inferrepo=True,
212 )
212 )
213 def add(ui, repo, *pats, **opts):
213 def add(ui, repo, *pats, **opts):
214 """add the specified files on the next commit
214 """add the specified files on the next commit
215
215
216 Schedule files to be version controlled and added to the
216 Schedule files to be version controlled and added to the
217 repository.
217 repository.
218
218
219 The files will be added to the repository at the next commit. To
219 The files will be added to the repository at the next commit. To
220 undo an add before that, see :hg:`forget`.
220 undo an add before that, see :hg:`forget`.
221
221
222 If no names are given, add all files to the repository (except
222 If no names are given, add all files to the repository (except
223 files matching ``.hgignore``).
223 files matching ``.hgignore``).
224
224
225 .. container:: verbose
225 .. container:: verbose
226
226
227 Examples:
227 Examples:
228
228
229 - New (unknown) files are added
229 - New (unknown) files are added
230 automatically by :hg:`add`::
230 automatically by :hg:`add`::
231
231
232 $ ls
232 $ ls
233 foo.c
233 foo.c
234 $ hg status
234 $ hg status
235 ? foo.c
235 ? foo.c
236 $ hg add
236 $ hg add
237 adding foo.c
237 adding foo.c
238 $ hg status
238 $ hg status
239 A foo.c
239 A foo.c
240
240
241 - Specific files to be added can be specified::
241 - Specific files to be added can be specified::
242
242
243 $ ls
243 $ ls
244 bar.c foo.c
244 bar.c foo.c
245 $ hg status
245 $ hg status
246 ? bar.c
246 ? bar.c
247 ? foo.c
247 ? foo.c
248 $ hg add bar.c
248 $ hg add bar.c
249 $ hg status
249 $ hg status
250 A bar.c
250 A bar.c
251 ? foo.c
251 ? foo.c
252
252
253 Returns 0 if all files are successfully added.
253 Returns 0 if all files are successfully added.
254 """
254 """
255
255
256 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
256 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
257 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
257 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
258 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
258 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
259 return rejected and 1 or 0
259 return rejected and 1 or 0
260
260
261
261
262 @command(
262 @command(
263 b'addremove',
263 b'addremove',
264 similarityopts + subrepoopts + walkopts + dryrunopts,
264 similarityopts + subrepoopts + walkopts + dryrunopts,
265 _(b'[OPTION]... [FILE]...'),
265 _(b'[OPTION]... [FILE]...'),
266 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
266 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
267 inferrepo=True,
267 inferrepo=True,
268 )
268 )
269 def addremove(ui, repo, *pats, **opts):
269 def addremove(ui, repo, *pats, **opts):
270 """add all new files, delete all missing files
270 """add all new files, delete all missing files
271
271
272 Add all new files and remove all missing files from the
272 Add all new files and remove all missing files from the
273 repository.
273 repository.
274
274
275 Unless names are given, new files are ignored if they match any of
275 Unless names are given, new files are ignored if they match any of
276 the patterns in ``.hgignore``. As with add, these changes take
276 the patterns in ``.hgignore``. As with add, these changes take
277 effect at the next commit.
277 effect at the next commit.
278
278
279 Use the -s/--similarity option to detect renamed files. This
279 Use the -s/--similarity option to detect renamed files. This
280 option takes a percentage between 0 (disabled) and 100 (files must
280 option takes a percentage between 0 (disabled) and 100 (files must
281 be identical) as its parameter. With a parameter greater than 0,
281 be identical) as its parameter. With a parameter greater than 0,
282 this compares every removed file with every added file and records
282 this compares every removed file with every added file and records
283 those similar enough as renames. Detecting renamed files this way
283 those similar enough as renames. Detecting renamed files this way
284 can be expensive. After using this option, :hg:`status -C` can be
284 can be expensive. After using this option, :hg:`status -C` can be
285 used to check which files were identified as moved or renamed. If
285 used to check which files were identified as moved or renamed. If
286 not specified, -s/--similarity defaults to 100 and only renames of
286 not specified, -s/--similarity defaults to 100 and only renames of
287 identical files are detected.
287 identical files are detected.
288
288
289 .. container:: verbose
289 .. container:: verbose
290
290
291 Examples:
291 Examples:
292
292
293 - A number of files (bar.c and foo.c) are new,
293 - A number of files (bar.c and foo.c) are new,
294 while foobar.c has been removed (without using :hg:`remove`)
294 while foobar.c has been removed (without using :hg:`remove`)
295 from the repository::
295 from the repository::
296
296
297 $ ls
297 $ ls
298 bar.c foo.c
298 bar.c foo.c
299 $ hg status
299 $ hg status
300 ! foobar.c
300 ! foobar.c
301 ? bar.c
301 ? bar.c
302 ? foo.c
302 ? foo.c
303 $ hg addremove
303 $ hg addremove
304 adding bar.c
304 adding bar.c
305 adding foo.c
305 adding foo.c
306 removing foobar.c
306 removing foobar.c
307 $ hg status
307 $ hg status
308 A bar.c
308 A bar.c
309 A foo.c
309 A foo.c
310 R foobar.c
310 R foobar.c
311
311
312 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 - A file foobar.c was moved to foo.c without using :hg:`rename`.
313 Afterwards, it was edited slightly::
313 Afterwards, it was edited slightly::
314
314
315 $ ls
315 $ ls
316 foo.c
316 foo.c
317 $ hg status
317 $ hg status
318 ! foobar.c
318 ! foobar.c
319 ? foo.c
319 ? foo.c
320 $ hg addremove --similarity 90
320 $ hg addremove --similarity 90
321 removing foobar.c
321 removing foobar.c
322 adding foo.c
322 adding foo.c
323 recording removal of foobar.c as rename to foo.c (94% similar)
323 recording removal of foobar.c as rename to foo.c (94% similar)
324 $ hg status -C
324 $ hg status -C
325 A foo.c
325 A foo.c
326 foobar.c
326 foobar.c
327 R foobar.c
327 R foobar.c
328
328
329 Returns 0 if all files are successfully added.
329 Returns 0 if all files are successfully added.
330 """
330 """
331 opts = pycompat.byteskwargs(opts)
331 opts = pycompat.byteskwargs(opts)
332 if not opts.get(b'similarity'):
332 if not opts.get(b'similarity'):
333 opts[b'similarity'] = b'100'
333 opts[b'similarity'] = b'100'
334 matcher = scmutil.match(repo[None], pats, opts)
334 matcher = scmutil.match(repo[None], pats, opts)
335 relative = scmutil.anypats(pats, opts)
335 relative = scmutil.anypats(pats, opts)
336 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
336 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
337 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
337 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
338
338
339
339
340 @command(
340 @command(
341 b'annotate|blame',
341 b'annotate|blame',
342 [
342 [
343 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
343 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
344 (
344 (
345 b'',
345 b'',
346 b'follow',
346 b'follow',
347 None,
347 None,
348 _(b'follow copies/renames and list the filename (DEPRECATED)'),
348 _(b'follow copies/renames and list the filename (DEPRECATED)'),
349 ),
349 ),
350 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
350 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
351 (b'a', b'text', None, _(b'treat all files as text')),
351 (b'a', b'text', None, _(b'treat all files as text')),
352 (b'u', b'user', None, _(b'list the author (long with -v)')),
352 (b'u', b'user', None, _(b'list the author (long with -v)')),
353 (b'f', b'file', None, _(b'list the filename')),
353 (b'f', b'file', None, _(b'list the filename')),
354 (b'd', b'date', None, _(b'list the date (short with -q)')),
354 (b'd', b'date', None, _(b'list the date (short with -q)')),
355 (b'n', b'number', None, _(b'list the revision number (default)')),
355 (b'n', b'number', None, _(b'list the revision number (default)')),
356 (b'c', b'changeset', None, _(b'list the changeset')),
356 (b'c', b'changeset', None, _(b'list the changeset')),
357 (
357 (
358 b'l',
358 b'l',
359 b'line-number',
359 b'line-number',
360 None,
360 None,
361 _(b'show line number at the first appearance'),
361 _(b'show line number at the first appearance'),
362 ),
362 ),
363 (
363 (
364 b'',
364 b'',
365 b'skip',
365 b'skip',
366 [],
366 [],
367 _(b'revset to not display (EXPERIMENTAL)'),
367 _(b'revset to not display (EXPERIMENTAL)'),
368 _(b'REV'),
368 _(b'REV'),
369 ),
369 ),
370 ]
370 ]
371 + diffwsopts
371 + diffwsopts
372 + walkopts
372 + walkopts
373 + formatteropts,
373 + formatteropts,
374 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
374 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
375 helpcategory=command.CATEGORY_FILE_CONTENTS,
375 helpcategory=command.CATEGORY_FILE_CONTENTS,
376 helpbasic=True,
376 helpbasic=True,
377 inferrepo=True,
377 inferrepo=True,
378 )
378 )
379 def annotate(ui, repo, *pats, **opts):
379 def annotate(ui, repo, *pats, **opts):
380 """show changeset information by line for each file
380 """show changeset information by line for each file
381
381
382 List changes in files, showing the revision id responsible for
382 List changes in files, showing the revision id responsible for
383 each line.
383 each line.
384
384
385 This command is useful for discovering when a change was made and
385 This command is useful for discovering when a change was made and
386 by whom.
386 by whom.
387
387
388 If you include --file, --user, or --date, the revision number is
388 If you include --file, --user, or --date, the revision number is
389 suppressed unless you also include --number.
389 suppressed unless you also include --number.
390
390
391 Without the -a/--text option, annotate will avoid processing files
391 Without the -a/--text option, annotate will avoid processing files
392 it detects as binary. With -a, annotate will annotate the file
392 it detects as binary. With -a, annotate will annotate the file
393 anyway, although the results will probably be neither useful
393 anyway, although the results will probably be neither useful
394 nor desirable.
394 nor desirable.
395
395
396 .. container:: verbose
396 .. container:: verbose
397
397
398 Template:
398 Template:
399
399
400 The following keywords are supported in addition to the common template
400 The following keywords are supported in addition to the common template
401 keywords and functions. See also :hg:`help templates`.
401 keywords and functions. See also :hg:`help templates`.
402
402
403 :lines: List of lines with annotation data.
403 :lines: List of lines with annotation data.
404 :path: String. Repository-absolute path of the specified file.
404 :path: String. Repository-absolute path of the specified file.
405
405
406 And each entry of ``{lines}`` provides the following sub-keywords in
406 And each entry of ``{lines}`` provides the following sub-keywords in
407 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
407 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
408
408
409 :line: String. Line content.
409 :line: String. Line content.
410 :lineno: Integer. Line number at that revision.
410 :lineno: Integer. Line number at that revision.
411 :path: String. Repository-absolute path of the file at that revision.
411 :path: String. Repository-absolute path of the file at that revision.
412
412
413 See :hg:`help templates.operators` for the list expansion syntax.
413 See :hg:`help templates.operators` for the list expansion syntax.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 """
416 """
417 opts = pycompat.byteskwargs(opts)
417 opts = pycompat.byteskwargs(opts)
418 if not pats:
418 if not pats:
419 raise error.InputError(
419 raise error.InputError(
420 _(b'at least one filename or pattern is required')
420 _(b'at least one filename or pattern is required')
421 )
421 )
422
422
423 if opts.get(b'follow'):
423 if opts.get(b'follow'):
424 # --follow is deprecated and now just an alias for -f/--file
424 # --follow is deprecated and now just an alias for -f/--file
425 # to mimic the behavior of Mercurial before version 1.5
425 # to mimic the behavior of Mercurial before version 1.5
426 opts[b'file'] = True
426 opts[b'file'] = True
427
427
428 if (
428 if (
429 not opts.get(b'user')
429 not opts.get(b'user')
430 and not opts.get(b'changeset')
430 and not opts.get(b'changeset')
431 and not opts.get(b'date')
431 and not opts.get(b'date')
432 and not opts.get(b'file')
432 and not opts.get(b'file')
433 ):
433 ):
434 opts[b'number'] = True
434 opts[b'number'] = True
435
435
436 linenumber = opts.get(b'line_number') is not None
436 linenumber = opts.get(b'line_number') is not None
437 if (
437 if (
438 linenumber
438 linenumber
439 and (not opts.get(b'changeset'))
439 and (not opts.get(b'changeset'))
440 and (not opts.get(b'number'))
440 and (not opts.get(b'number'))
441 ):
441 ):
442 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
442 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
443
443
444 rev = opts.get(b'rev')
444 rev = opts.get(b'rev')
445 if rev:
445 if rev:
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 ctx = logcmdutil.revsingle(repo, rev)
447 ctx = logcmdutil.revsingle(repo, rev)
448
448
449 ui.pager(b'annotate')
449 ui.pager(b'annotate')
450 rootfm = ui.formatter(b'annotate', opts)
450 rootfm = ui.formatter(b'annotate', opts)
451 if ui.debugflag:
451 if ui.debugflag:
452 shorthex = pycompat.identity
452 shorthex = pycompat.identity
453 else:
453 else:
454
454
455 def shorthex(h):
455 def shorthex(h):
456 return h[:12]
456 return h[:12]
457
457
458 if ui.quiet:
458 if ui.quiet:
459 datefunc = dateutil.shortdate
459 datefunc = dateutil.shortdate
460 else:
460 else:
461 datefunc = dateutil.datestr
461 datefunc = dateutil.datestr
462 if ctx.rev() is None:
462 if ctx.rev() is None:
463 if opts.get(b'changeset'):
463 if opts.get(b'changeset'):
464 # omit "+" suffix which is appended to node hex
464 # omit "+" suffix which is appended to node hex
465 def formatrev(rev):
465 def formatrev(rev):
466 if rev == wdirrev:
466 if rev == wdirrev:
467 return b'%d' % ctx.p1().rev()
467 return b'%d' % ctx.p1().rev()
468 else:
468 else:
469 return b'%d' % rev
469 return b'%d' % rev
470
470
471 else:
471 else:
472
472
473 def formatrev(rev):
473 def formatrev(rev):
474 if rev == wdirrev:
474 if rev == wdirrev:
475 return b'%d+' % ctx.p1().rev()
475 return b'%d+' % ctx.p1().rev()
476 else:
476 else:
477 return b'%d ' % rev
477 return b'%d ' % rev
478
478
479 def formathex(h):
479 def formathex(h):
480 if h == repo.nodeconstants.wdirhex:
480 if h == repo.nodeconstants.wdirhex:
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 else:
482 else:
483 return b'%s ' % shorthex(h)
483 return b'%s ' % shorthex(h)
484
484
485 else:
485 else:
486 formatrev = b'%d'.__mod__
486 formatrev = b'%d'.__mod__
487 formathex = shorthex
487 formathex = shorthex
488
488
489 opmap = [
489 opmap = [
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 ]
496 ]
497 opnamemap = {
497 opnamemap = {
498 b'rev': b'number',
498 b'rev': b'number',
499 b'node': b'changeset',
499 b'node': b'changeset',
500 b'path': b'file',
500 b'path': b'file',
501 b'lineno': b'line_number',
501 b'lineno': b'line_number',
502 }
502 }
503
503
504 if rootfm.isplain():
504 if rootfm.isplain():
505
505
506 def makefunc(get, fmt):
506 def makefunc(get, fmt):
507 return lambda x: fmt(get(x))
507 return lambda x: fmt(get(x))
508
508
509 else:
509 else:
510
510
511 def makefunc(get, fmt):
511 def makefunc(get, fmt):
512 return get
512 return get
513
513
514 datahint = rootfm.datahint()
514 datahint = rootfm.datahint()
515 funcmap = [
515 funcmap = [
516 (makefunc(get, fmt), sep)
516 (makefunc(get, fmt), sep)
517 for fn, sep, get, fmt in opmap
517 for fn, sep, get, fmt in opmap
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 ]
519 ]
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 fields = b' '.join(
521 fields = b' '.join(
522 fn
522 fn
523 for fn, sep, get, fmt in opmap
523 for fn, sep, get, fmt in opmap
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 )
525 )
526
526
527 def bad(x, y):
527 def bad(x, y):
528 raise error.InputError(b"%s: %s" % (x, y))
528 raise error.InputError(b"%s: %s" % (x, y))
529
529
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
531
531
532 follow = not opts.get(b'no_follow')
532 follow = not opts.get(b'no_follow')
533 diffopts = patch.difffeatureopts(
533 diffopts = patch.difffeatureopts(
534 ui, opts, section=b'annotate', whitespace=True
534 ui, opts, section=b'annotate', whitespace=True
535 )
535 )
536 skiprevs = opts.get(b'skip')
536 skiprevs = opts.get(b'skip')
537 if skiprevs:
537 if skiprevs:
538 skiprevs = logcmdutil.revrange(repo, skiprevs)
538 skiprevs = logcmdutil.revrange(repo, skiprevs)
539
539
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 for abs in ctx.walk(m):
541 for abs in ctx.walk(m):
542 fctx = ctx[abs]
542 fctx = ctx[abs]
543 rootfm.startitem()
543 rootfm.startitem()
544 rootfm.data(path=abs)
544 rootfm.data(path=abs)
545 if not opts.get(b'text') and fctx.isbinary():
545 if not opts.get(b'text') and fctx.isbinary():
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 continue
547 continue
548
548
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 lines = fctx.annotate(
550 lines = fctx.annotate(
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 )
552 )
553 if not lines:
553 if not lines:
554 fm.end()
554 fm.end()
555 continue
555 continue
556 formats = []
556 formats = []
557 pieces = []
557 pieces = []
558
558
559 for f, sep in funcmap:
559 for f, sep in funcmap:
560 l = [f(n) for n in lines]
560 l = [f(n) for n in lines]
561 if fm.isplain():
561 if fm.isplain():
562 sizes = [encoding.colwidth(x) for x in l]
562 sizes = [encoding.colwidth(x) for x in l]
563 ml = max(sizes)
563 ml = max(sizes)
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 else:
565 else:
566 formats.append([b'%s'] * len(l))
566 formats.append([b'%s'] * len(l))
567 pieces.append(l)
567 pieces.append(l)
568
568
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 fm.startitem()
570 fm.startitem()
571 fm.context(fctx=n.fctx)
571 fm.context(fctx=n.fctx)
572 fm.write(fields, b"".join(f), *p)
572 fm.write(fields, b"".join(f), *p)
573 if n.skip:
573 if n.skip:
574 fmt = b"* %s"
574 fmt = b"* %s"
575 else:
575 else:
576 fmt = b": %s"
576 fmt = b": %s"
577 fm.write(b'line', fmt, n.text)
577 fm.write(b'line', fmt, n.text)
578
578
579 if not lines[-1].text.endswith(b'\n'):
579 if not lines[-1].text.endswith(b'\n'):
580 fm.plain(b'\n')
580 fm.plain(b'\n')
581 fm.end()
581 fm.end()
582
582
583 rootfm.end()
583 rootfm.end()
584
584
585
585
586 @command(
586 @command(
587 b'archive',
587 b'archive',
588 [
588 [
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (
590 (
591 b'p',
591 b'p',
592 b'prefix',
592 b'prefix',
593 b'',
593 b'',
594 _(b'directory prefix for files in archive'),
594 _(b'directory prefix for files in archive'),
595 _(b'PREFIX'),
595 _(b'PREFIX'),
596 ),
596 ),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
599 ]
599 ]
600 + subrepoopts
600 + subrepoopts
601 + walkopts,
601 + walkopts,
602 _(b'[OPTION]... DEST'),
602 _(b'[OPTION]... DEST'),
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 )
604 )
605 def archive(ui, repo, dest, **opts):
605 def archive(ui, repo, dest, **opts):
606 """create an unversioned archive of a repository revision
606 """create an unversioned archive of a repository revision
607
607
608 By default, the revision used is the parent of the working
608 By default, the revision used is the parent of the working
609 directory; use -r/--rev to specify a different revision.
609 directory; use -r/--rev to specify a different revision.
610
610
611 The archive type is automatically detected based on file
611 The archive type is automatically detected based on file
612 extension (to override, use -t/--type).
612 extension (to override, use -t/--type).
613
613
614 .. container:: verbose
614 .. container:: verbose
615
615
616 Examples:
616 Examples:
617
617
618 - create a zip file containing the 1.0 release::
618 - create a zip file containing the 1.0 release::
619
619
620 hg archive -r 1.0 project-1.0.zip
620 hg archive -r 1.0 project-1.0.zip
621
621
622 - create a tarball excluding .hg files::
622 - create a tarball excluding .hg files::
623
623
624 hg archive project.tar.gz -X ".hg*"
624 hg archive project.tar.gz -X ".hg*"
625
625
626 Valid types are:
626 Valid types are:
627
627
628 :``files``: a directory full of files (default)
628 :``files``: a directory full of files (default)
629 :``tar``: tar archive, uncompressed
629 :``tar``: tar archive, uncompressed
630 :``tbz2``: tar archive, compressed using bzip2
630 :``tbz2``: tar archive, compressed using bzip2
631 :``tgz``: tar archive, compressed using gzip
631 :``tgz``: tar archive, compressed using gzip
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``uzip``: zip archive, uncompressed
633 :``uzip``: zip archive, uncompressed
634 :``zip``: zip archive, compressed using deflate
634 :``zip``: zip archive, compressed using deflate
635
635
636 The exact name of the destination archive or directory is given
636 The exact name of the destination archive or directory is given
637 using a format string; see :hg:`help export` for details.
637 using a format string; see :hg:`help export` for details.
638
638
639 Each member added to an archive file has a directory prefix
639 Each member added to an archive file has a directory prefix
640 prepended. Use -p/--prefix to specify a format string for the
640 prepended. Use -p/--prefix to specify a format string for the
641 prefix. The default is the basename of the archive, with suffixes
641 prefix. The default is the basename of the archive, with suffixes
642 removed.
642 removed.
643
643
644 Returns 0 on success.
644 Returns 0 on success.
645 """
645 """
646
646
647 opts = pycompat.byteskwargs(opts)
647 opts = pycompat.byteskwargs(opts)
648 rev = opts.get(b'rev')
648 rev = opts.get(b'rev')
649 if rev:
649 if rev:
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 ctx = logcmdutil.revsingle(repo, rev)
651 ctx = logcmdutil.revsingle(repo, rev)
652 if not ctx:
652 if not ctx:
653 raise error.InputError(
653 raise error.InputError(
654 _(b'no working directory: please specify a revision')
654 _(b'no working directory: please specify a revision')
655 )
655 )
656 node = ctx.node()
656 node = ctx.node()
657 dest = cmdutil.makefilename(ctx, dest)
657 dest = cmdutil.makefilename(ctx, dest)
658 if os.path.realpath(dest) == repo.root:
658 if os.path.realpath(dest) == repo.root:
659 raise error.InputError(_(b'repository root cannot be destination'))
659 raise error.InputError(_(b'repository root cannot be destination'))
660
660
661 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
661 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
662 prefix = opts.get(b'prefix')
662 prefix = opts.get(b'prefix')
663
663
664 if dest == b'-':
664 if dest == b'-':
665 if kind == b'files':
665 if kind == b'files':
666 raise error.InputError(_(b'cannot archive plain files to stdout'))
666 raise error.InputError(_(b'cannot archive plain files to stdout'))
667 dest = cmdutil.makefileobj(ctx, dest)
667 dest = cmdutil.makefileobj(ctx, dest)
668 if not prefix:
668 if not prefix:
669 prefix = os.path.basename(repo.root) + b'-%h'
669 prefix = os.path.basename(repo.root) + b'-%h'
670
670
671 prefix = cmdutil.makefilename(ctx, prefix)
671 prefix = cmdutil.makefilename(ctx, prefix)
672 match = scmutil.match(ctx, [], opts)
672 match = scmutil.match(ctx, [], opts)
673 archival.archive(
673 archival.archive(
674 repo,
674 repo,
675 dest,
675 dest,
676 node,
676 node,
677 kind,
677 kind,
678 not opts.get(b'no_decode'),
678 not opts.get(b'no_decode'),
679 match,
679 match,
680 prefix,
680 prefix,
681 subrepos=opts.get(b'subrepos'),
681 subrepos=opts.get(b'subrepos'),
682 )
682 )
683
683
684
684
685 @command(
685 @command(
686 b'backout',
686 b'backout',
687 [
687 [
688 (
688 (
689 b'',
689 b'',
690 b'merge',
690 b'merge',
691 None,
691 None,
692 _(b'merge with old dirstate parent after backout'),
692 _(b'merge with old dirstate parent after backout'),
693 ),
693 ),
694 (
694 (
695 b'',
695 b'',
696 b'commit',
696 b'commit',
697 None,
697 None,
698 _(b'commit if no conflicts were encountered (DEPRECATED)'),
698 _(b'commit if no conflicts were encountered (DEPRECATED)'),
699 ),
699 ),
700 (b'', b'no-commit', None, _(b'do not commit')),
700 (b'', b'no-commit', None, _(b'do not commit')),
701 (
701 (
702 b'',
702 b'',
703 b'parent',
703 b'parent',
704 b'',
704 b'',
705 _(b'parent to choose when backing out merge (DEPRECATED)'),
705 _(b'parent to choose when backing out merge (DEPRECATED)'),
706 _(b'REV'),
706 _(b'REV'),
707 ),
707 ),
708 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
708 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
709 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
709 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
710 ]
710 ]
711 + mergetoolopts
711 + mergetoolopts
712 + walkopts
712 + walkopts
713 + commitopts
713 + commitopts
714 + commitopts2,
714 + commitopts2,
715 _(b'[OPTION]... [-r] REV'),
715 _(b'[OPTION]... [-r] REV'),
716 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
716 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
717 )
717 )
718 def backout(ui, repo, node=None, rev=None, **opts):
718 def backout(ui, repo, node=None, rev=None, **opts):
719 """reverse effect of earlier changeset
719 """reverse effect of earlier changeset
720
720
721 Prepare a new changeset with the effect of REV undone in the
721 Prepare a new changeset with the effect of REV undone in the
722 current working directory. If no conflicts were encountered,
722 current working directory. If no conflicts were encountered,
723 it will be committed immediately.
723 it will be committed immediately.
724
724
725 If REV is the parent of the working directory, then this new changeset
725 If REV is the parent of the working directory, then this new changeset
726 is committed automatically (unless --no-commit is specified).
726 is committed automatically (unless --no-commit is specified).
727
727
728 .. note::
728 .. note::
729
729
730 :hg:`backout` cannot be used to fix either an unwanted or
730 :hg:`backout` cannot be used to fix either an unwanted or
731 incorrect merge.
731 incorrect merge.
732
732
733 .. container:: verbose
733 .. container:: verbose
734
734
735 Examples:
735 Examples:
736
736
737 - Reverse the effect of the parent of the working directory.
737 - Reverse the effect of the parent of the working directory.
738 This backout will be committed immediately::
738 This backout will be committed immediately::
739
739
740 hg backout -r .
740 hg backout -r .
741
741
742 - Reverse the effect of previous bad revision 23::
742 - Reverse the effect of previous bad revision 23::
743
743
744 hg backout -r 23
744 hg backout -r 23
745
745
746 - Reverse the effect of previous bad revision 23 and
746 - Reverse the effect of previous bad revision 23 and
747 leave changes uncommitted::
747 leave changes uncommitted::
748
748
749 hg backout -r 23 --no-commit
749 hg backout -r 23 --no-commit
750 hg commit -m "Backout revision 23"
750 hg commit -m "Backout revision 23"
751
751
752 By default, the pending changeset will have one parent,
752 By default, the pending changeset will have one parent,
753 maintaining a linear history. With --merge, the pending
753 maintaining a linear history. With --merge, the pending
754 changeset will instead have two parents: the old parent of the
754 changeset will instead have two parents: the old parent of the
755 working directory and a new child of REV that simply undoes REV.
755 working directory and a new child of REV that simply undoes REV.
756
756
757 Before version 1.7, the behavior without --merge was equivalent
757 Before version 1.7, the behavior without --merge was equivalent
758 to specifying --merge followed by :hg:`update --clean .` to
758 to specifying --merge followed by :hg:`update --clean .` to
759 cancel the merge and leave the child of REV as a head to be
759 cancel the merge and leave the child of REV as a head to be
760 merged separately.
760 merged separately.
761
761
762 See :hg:`help dates` for a list of formats valid for -d/--date.
762 See :hg:`help dates` for a list of formats valid for -d/--date.
763
763
764 See :hg:`help revert` for a way to restore files to the state
764 See :hg:`help revert` for a way to restore files to the state
765 of another revision.
765 of another revision.
766
766
767 Returns 0 on success, 1 if nothing to backout or there are unresolved
767 Returns 0 on success, 1 if nothing to backout or there are unresolved
768 files.
768 files.
769 """
769 """
770 with repo.wlock(), repo.lock():
770 with repo.wlock(), repo.lock():
771 return _dobackout(ui, repo, node, rev, **opts)
771 return _dobackout(ui, repo, node, rev, **opts)
772
772
773
773
774 def _dobackout(ui, repo, node=None, rev=None, **opts):
774 def _dobackout(ui, repo, node=None, rev=None, **opts):
775 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
775 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
776 opts = pycompat.byteskwargs(opts)
776 opts = pycompat.byteskwargs(opts)
777
777
778 if rev and node:
778 if rev and node:
779 raise error.InputError(_(b"please specify just one revision"))
779 raise error.InputError(_(b"please specify just one revision"))
780
780
781 if not rev:
781 if not rev:
782 rev = node
782 rev = node
783
783
784 if not rev:
784 if not rev:
785 raise error.InputError(_(b"please specify a revision to backout"))
785 raise error.InputError(_(b"please specify a revision to backout"))
786
786
787 date = opts.get(b'date')
787 date = opts.get(b'date')
788 if date:
788 if date:
789 opts[b'date'] = dateutil.parsedate(date)
789 opts[b'date'] = dateutil.parsedate(date)
790
790
791 cmdutil.checkunfinished(repo)
791 cmdutil.checkunfinished(repo)
792 cmdutil.bailifchanged(repo)
792 cmdutil.bailifchanged(repo)
793 ctx = logcmdutil.revsingle(repo, rev)
793 ctx = logcmdutil.revsingle(repo, rev)
794 node = ctx.node()
794 node = ctx.node()
795
795
796 op1, op2 = repo.dirstate.parents()
796 op1, op2 = repo.dirstate.parents()
797 if not repo.changelog.isancestor(node, op1):
797 if not repo.changelog.isancestor(node, op1):
798 raise error.InputError(
798 raise error.InputError(
799 _(b'cannot backout change that is not an ancestor')
799 _(b'cannot backout change that is not an ancestor')
800 )
800 )
801
801
802 p1, p2 = repo.changelog.parents(node)
802 p1, p2 = repo.changelog.parents(node)
803 if p1 == repo.nullid:
803 if p1 == repo.nullid:
804 raise error.InputError(_(b'cannot backout a change with no parents'))
804 raise error.InputError(_(b'cannot backout a change with no parents'))
805 if p2 != repo.nullid:
805 if p2 != repo.nullid:
806 if not opts.get(b'parent'):
806 if not opts.get(b'parent'):
807 raise error.InputError(_(b'cannot backout a merge changeset'))
807 raise error.InputError(_(b'cannot backout a merge changeset'))
808 p = repo.lookup(opts[b'parent'])
808 p = repo.lookup(opts[b'parent'])
809 if p not in (p1, p2):
809 if p not in (p1, p2):
810 raise error.InputError(
810 raise error.InputError(
811 _(b'%s is not a parent of %s') % (short(p), short(node))
811 _(b'%s is not a parent of %s') % (short(p), short(node))
812 )
812 )
813 parent = p
813 parent = p
814 else:
814 else:
815 if opts.get(b'parent'):
815 if opts.get(b'parent'):
816 raise error.InputError(
816 raise error.InputError(
817 _(b'cannot use --parent on non-merge changeset')
817 _(b'cannot use --parent on non-merge changeset')
818 )
818 )
819 parent = p1
819 parent = p1
820
820
821 # the backout should appear on the same branch
821 # the backout should appear on the same branch
822 branch = repo.dirstate.branch()
822 branch = repo.dirstate.branch()
823 bheads = repo.branchheads(branch)
823 bheads = repo.branchheads(branch)
824 rctx = scmutil.revsingle(repo, hex(parent))
824 rctx = scmutil.revsingle(repo, hex(parent))
825 if not opts.get(b'merge') and op1 != node:
825 if not opts.get(b'merge') and op1 != node:
826 with dirstateguard.dirstateguard(repo, b'backout'):
826 with dirstateguard.dirstateguard(repo, b'backout'):
827 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
827 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
828 with ui.configoverride(overrides, b'backout'):
828 with ui.configoverride(overrides, b'backout'):
829 stats = mergemod.back_out(ctx, parent=repo[parent])
829 stats = mergemod.back_out(ctx, parent=repo[parent])
830 repo.setparents(op1, op2)
830 repo.setparents(op1, op2)
831 hg._showstats(repo, stats)
831 hg._showstats(repo, stats)
832 if stats.unresolvedcount:
832 if stats.unresolvedcount:
833 repo.ui.status(
833 repo.ui.status(
834 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 _(b"use 'hg resolve' to retry unresolved file merges\n")
835 )
835 )
836 return 1
836 return 1
837 else:
837 else:
838 hg.clean(repo, node, show_stats=False)
838 hg.clean(repo, node, show_stats=False)
839 repo.dirstate.setbranch(branch)
839 repo.dirstate.setbranch(branch)
840 cmdutil.revert(ui, repo, rctx)
840 cmdutil.revert(ui, repo, rctx)
841
841
842 if opts.get(b'no_commit'):
842 if opts.get(b'no_commit'):
843 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 msg = _(b"changeset %s backed out, don't forget to commit.\n")
844 ui.status(msg % short(node))
844 ui.status(msg % short(node))
845 return 0
845 return 0
846
846
847 def commitfunc(ui, repo, message, match, opts):
847 def commitfunc(ui, repo, message, match, opts):
848 editform = b'backout'
848 editform = b'backout'
849 e = cmdutil.getcommiteditor(
849 e = cmdutil.getcommiteditor(
850 editform=editform, **pycompat.strkwargs(opts)
850 editform=editform, **pycompat.strkwargs(opts)
851 )
851 )
852 if not message:
852 if not message:
853 # we don't translate commit messages
853 # we don't translate commit messages
854 message = b"Backed out changeset %s" % short(node)
854 message = b"Backed out changeset %s" % short(node)
855 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 e = cmdutil.getcommiteditor(edit=True, editform=editform)
856 return repo.commit(
856 return repo.commit(
857 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
858 )
858 )
859
859
860 # save to detect changes
860 # save to detect changes
861 tip = repo.changelog.tip()
861 tip = repo.changelog.tip()
862
862
863 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
863 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
864 if not newnode:
864 if not newnode:
865 ui.status(_(b"nothing changed\n"))
865 ui.status(_(b"nothing changed\n"))
866 return 1
866 return 1
867 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
867 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
868
868
869 def nice(node):
869 def nice(node):
870 return b'%d:%s' % (repo.changelog.rev(node), short(node))
870 return b'%d:%s' % (repo.changelog.rev(node), short(node))
871
871
872 ui.status(
872 ui.status(
873 _(b'changeset %s backs out changeset %s\n')
873 _(b'changeset %s backs out changeset %s\n')
874 % (nice(newnode), nice(node))
874 % (nice(newnode), nice(node))
875 )
875 )
876 if opts.get(b'merge') and op1 != node:
876 if opts.get(b'merge') and op1 != node:
877 hg.clean(repo, op1, show_stats=False)
877 hg.clean(repo, op1, show_stats=False)
878 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
878 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
879 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
879 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
880 with ui.configoverride(overrides, b'backout'):
880 with ui.configoverride(overrides, b'backout'):
881 return hg.merge(repo[b'tip'])
881 return hg.merge(repo[b'tip'])
882 return 0
882 return 0
883
883
884
884
885 @command(
885 @command(
886 b'bisect',
886 b'bisect',
887 [
887 [
888 (b'r', b'reset', False, _(b'reset bisect state')),
888 (b'r', b'reset', False, _(b'reset bisect state')),
889 (b'g', b'good', False, _(b'mark changeset good')),
889 (b'g', b'good', False, _(b'mark changeset good')),
890 (b'b', b'bad', False, _(b'mark changeset bad')),
890 (b'b', b'bad', False, _(b'mark changeset bad')),
891 (b's', b'skip', False, _(b'skip testing changeset')),
891 (b's', b'skip', False, _(b'skip testing changeset')),
892 (b'e', b'extend', False, _(b'extend the bisect range')),
892 (b'e', b'extend', False, _(b'extend the bisect range')),
893 (
893 (
894 b'c',
894 b'c',
895 b'command',
895 b'command',
896 b'',
896 b'',
897 _(b'use command to check changeset state'),
897 _(b'use command to check changeset state'),
898 _(b'CMD'),
898 _(b'CMD'),
899 ),
899 ),
900 (b'U', b'noupdate', False, _(b'do not update to target')),
900 (b'U', b'noupdate', False, _(b'do not update to target')),
901 ],
901 ],
902 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
902 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
903 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
903 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
904 )
904 )
905 def bisect(
905 def bisect(
906 ui,
906 ui,
907 repo,
907 repo,
908 positional_1=None,
908 positional_1=None,
909 positional_2=None,
909 positional_2=None,
910 command=None,
910 command=None,
911 reset=None,
911 reset=None,
912 good=None,
912 good=None,
913 bad=None,
913 bad=None,
914 skip=None,
914 skip=None,
915 extend=None,
915 extend=None,
916 noupdate=None,
916 noupdate=None,
917 ):
917 ):
918 """subdivision search of changesets
918 """subdivision search of changesets
919
919
920 This command helps to find changesets which introduce problems. To
920 This command helps to find changesets which introduce problems. To
921 use, mark the earliest changeset you know exhibits the problem as
921 use, mark the earliest changeset you know exhibits the problem as
922 bad, then mark the latest changeset which is free from the problem
922 bad, then mark the latest changeset which is free from the problem
923 as good. Bisect will update your working directory to a revision
923 as good. Bisect will update your working directory to a revision
924 for testing (unless the -U/--noupdate option is specified). Once
924 for testing (unless the -U/--noupdate option is specified). Once
925 you have performed tests, mark the working directory as good or
925 you have performed tests, mark the working directory as good or
926 bad, and bisect will either update to another candidate changeset
926 bad, and bisect will either update to another candidate changeset
927 or announce that it has found the bad revision.
927 or announce that it has found the bad revision.
928
928
929 As a shortcut, you can also use the revision argument to mark a
929 As a shortcut, you can also use the revision argument to mark a
930 revision as good or bad without checking it out first.
930 revision as good or bad without checking it out first.
931
931
932 If you supply a command, it will be used for automatic bisection.
932 If you supply a command, it will be used for automatic bisection.
933 The environment variable HG_NODE will contain the ID of the
933 The environment variable HG_NODE will contain the ID of the
934 changeset being tested. The exit status of the command will be
934 changeset being tested. The exit status of the command will be
935 used to mark revisions as good or bad: status 0 means good, 125
935 used to mark revisions as good or bad: status 0 means good, 125
936 means to skip the revision, 127 (command not found) will abort the
936 means to skip the revision, 127 (command not found) will abort the
937 bisection, and any other non-zero exit status means the revision
937 bisection, and any other non-zero exit status means the revision
938 is bad.
938 is bad.
939
939
940 .. container:: verbose
940 .. container:: verbose
941
941
942 Some examples:
942 Some examples:
943
943
944 - start a bisection with known bad revision 34, and good revision 12::
944 - start a bisection with known bad revision 34, and good revision 12::
945
945
946 hg bisect --bad 34
946 hg bisect --bad 34
947 hg bisect --good 12
947 hg bisect --good 12
948
948
949 - advance the current bisection by marking current revision as good or
949 - advance the current bisection by marking current revision as good or
950 bad::
950 bad::
951
951
952 hg bisect --good
952 hg bisect --good
953 hg bisect --bad
953 hg bisect --bad
954
954
955 - mark the current revision, or a known revision, to be skipped (e.g. if
955 - mark the current revision, or a known revision, to be skipped (e.g. if
956 that revision is not usable because of another issue)::
956 that revision is not usable because of another issue)::
957
957
958 hg bisect --skip
958 hg bisect --skip
959 hg bisect --skip 23
959 hg bisect --skip 23
960
960
961 - skip all revisions that do not touch directories ``foo`` or ``bar``::
961 - skip all revisions that do not touch directories ``foo`` or ``bar``::
962
962
963 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
963 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
964
964
965 - forget the current bisection::
965 - forget the current bisection::
966
966
967 hg bisect --reset
967 hg bisect --reset
968
968
969 - use 'make && make tests' to automatically find the first broken
969 - use 'make && make tests' to automatically find the first broken
970 revision::
970 revision::
971
971
972 hg bisect --reset
972 hg bisect --reset
973 hg bisect --bad 34
973 hg bisect --bad 34
974 hg bisect --good 12
974 hg bisect --good 12
975 hg bisect --command "make && make tests"
975 hg bisect --command "make && make tests"
976
976
977 - see all changesets whose states are already known in the current
977 - see all changesets whose states are already known in the current
978 bisection::
978 bisection::
979
979
980 hg log -r "bisect(pruned)"
980 hg log -r "bisect(pruned)"
981
981
982 - see the changeset currently being bisected (especially useful
982 - see the changeset currently being bisected (especially useful
983 if running with -U/--noupdate)::
983 if running with -U/--noupdate)::
984
984
985 hg log -r "bisect(current)"
985 hg log -r "bisect(current)"
986
986
987 - see all changesets that took part in the current bisection::
987 - see all changesets that took part in the current bisection::
988
988
989 hg log -r "bisect(range)"
989 hg log -r "bisect(range)"
990
990
991 - you can even get a nice graph::
991 - you can even get a nice graph::
992
992
993 hg log --graph -r "bisect(range)"
993 hg log --graph -r "bisect(range)"
994
994
995 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
995 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
996
996
997 Returns 0 on success.
997 Returns 0 on success.
998 """
998 """
999 rev = []
999 rev = []
1000 # backward compatibility
1000 # backward compatibility
1001 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1001 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1002 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1002 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1003 cmd = positional_1
1003 cmd = positional_1
1004 rev.append(positional_2)
1004 rev.append(positional_2)
1005 if cmd == b"good":
1005 if cmd == b"good":
1006 good = True
1006 good = True
1007 elif cmd == b"bad":
1007 elif cmd == b"bad":
1008 bad = True
1008 bad = True
1009 else:
1009 else:
1010 reset = True
1010 reset = True
1011 elif positional_2:
1011 elif positional_2:
1012 raise error.InputError(_(b'incompatible arguments'))
1012 raise error.InputError(_(b'incompatible arguments'))
1013 elif positional_1 is not None:
1013 elif positional_1 is not None:
1014 rev.append(positional_1)
1014 rev.append(positional_1)
1015
1015
1016 incompatibles = {
1016 incompatibles = {
1017 b'--bad': bad,
1017 b'--bad': bad,
1018 b'--command': bool(command),
1018 b'--command': bool(command),
1019 b'--extend': extend,
1019 b'--extend': extend,
1020 b'--good': good,
1020 b'--good': good,
1021 b'--reset': reset,
1021 b'--reset': reset,
1022 b'--skip': skip,
1022 b'--skip': skip,
1023 }
1023 }
1024
1024
1025 enabled = [x for x in incompatibles if incompatibles[x]]
1025 enabled = [x for x in incompatibles if incompatibles[x]]
1026
1026
1027 if len(enabled) > 1:
1027 if len(enabled) > 1:
1028 raise error.InputError(
1028 raise error.InputError(
1029 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1029 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1030 )
1030 )
1031
1031
1032 if reset:
1032 if reset:
1033 hbisect.resetstate(repo)
1033 hbisect.resetstate(repo)
1034 return
1034 return
1035
1035
1036 state = hbisect.load_state(repo)
1036 state = hbisect.load_state(repo)
1037
1037
1038 if rev:
1038 if rev:
1039 nodes = [repo[i].node() for i in logcmdutil.revrange(repo, rev)]
1039 nodes = [repo[i].node() for i in logcmdutil.revrange(repo, rev)]
1040 else:
1040 else:
1041 nodes = [repo.lookup(b'.')]
1041 nodes = [repo.lookup(b'.')]
1042
1042
1043 # update state
1043 # update state
1044 if good or bad or skip:
1044 if good or bad or skip:
1045 if good:
1045 if good:
1046 state[b'good'] += nodes
1046 state[b'good'] += nodes
1047 elif bad:
1047 elif bad:
1048 state[b'bad'] += nodes
1048 state[b'bad'] += nodes
1049 elif skip:
1049 elif skip:
1050 state[b'skip'] += nodes
1050 state[b'skip'] += nodes
1051 hbisect.save_state(repo, state)
1051 hbisect.save_state(repo, state)
1052 if not (state[b'good'] and state[b'bad']):
1052 if not (state[b'good'] and state[b'bad']):
1053 return
1053 return
1054
1054
1055 def mayupdate(repo, node, show_stats=True):
1055 def mayupdate(repo, node, show_stats=True):
1056 """common used update sequence"""
1056 """common used update sequence"""
1057 if noupdate:
1057 if noupdate:
1058 return
1058 return
1059 cmdutil.checkunfinished(repo)
1059 cmdutil.checkunfinished(repo)
1060 cmdutil.bailifchanged(repo)
1060 cmdutil.bailifchanged(repo)
1061 return hg.clean(repo, node, show_stats=show_stats)
1061 return hg.clean(repo, node, show_stats=show_stats)
1062
1062
1063 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1063 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1064
1064
1065 if command:
1065 if command:
1066 changesets = 1
1066 changesets = 1
1067 if noupdate:
1067 if noupdate:
1068 try:
1068 try:
1069 node = state[b'current'][0]
1069 node = state[b'current'][0]
1070 except LookupError:
1070 except LookupError:
1071 raise error.StateError(
1071 raise error.StateError(
1072 _(
1072 _(
1073 b'current bisect revision is unknown - '
1073 b'current bisect revision is unknown - '
1074 b'start a new bisect to fix'
1074 b'start a new bisect to fix'
1075 )
1075 )
1076 )
1076 )
1077 else:
1077 else:
1078 node, p2 = repo.dirstate.parents()
1078 node, p2 = repo.dirstate.parents()
1079 if p2 != repo.nullid:
1079 if p2 != repo.nullid:
1080 raise error.StateError(_(b'current bisect revision is a merge'))
1080 raise error.StateError(_(b'current bisect revision is a merge'))
1081 if rev:
1081 if rev:
1082 if not nodes:
1082 if not nodes:
1083 raise error.InputError(_(b'empty revision set'))
1083 raise error.InputError(_(b'empty revision set'))
1084 node = repo[nodes[-1]].node()
1084 node = repo[nodes[-1]].node()
1085 with hbisect.restore_state(repo, state, node):
1085 with hbisect.restore_state(repo, state, node):
1086 while changesets:
1086 while changesets:
1087 # update state
1087 # update state
1088 state[b'current'] = [node]
1088 state[b'current'] = [node]
1089 hbisect.save_state(repo, state)
1089 hbisect.save_state(repo, state)
1090 status = ui.system(
1090 status = ui.system(
1091 command,
1091 command,
1092 environ={b'HG_NODE': hex(node)},
1092 environ={b'HG_NODE': hex(node)},
1093 blockedtag=b'bisect_check',
1093 blockedtag=b'bisect_check',
1094 )
1094 )
1095 if status == 125:
1095 if status == 125:
1096 transition = b"skip"
1096 transition = b"skip"
1097 elif status == 0:
1097 elif status == 0:
1098 transition = b"good"
1098 transition = b"good"
1099 # status < 0 means process was killed
1099 # status < 0 means process was killed
1100 elif status == 127:
1100 elif status == 127:
1101 raise error.Abort(_(b"failed to execute %s") % command)
1101 raise error.Abort(_(b"failed to execute %s") % command)
1102 elif status < 0:
1102 elif status < 0:
1103 raise error.Abort(_(b"%s killed") % command)
1103 raise error.Abort(_(b"%s killed") % command)
1104 else:
1104 else:
1105 transition = b"bad"
1105 transition = b"bad"
1106 state[transition].append(node)
1106 state[transition].append(node)
1107 ctx = repo[node]
1107 ctx = repo[node]
1108 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1108 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1109 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1109 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1110 hbisect.checkstate(state)
1110 hbisect.checkstate(state)
1111 # bisect
1111 # bisect
1112 nodes, changesets, bgood = hbisect.bisect(repo, state)
1112 nodes, changesets, bgood = hbisect.bisect(repo, state)
1113 # update to next check
1113 # update to next check
1114 node = nodes[0]
1114 node = nodes[0]
1115 mayupdate(repo, node, show_stats=False)
1115 mayupdate(repo, node, show_stats=False)
1116 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1116 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1117 return
1117 return
1118
1118
1119 hbisect.checkstate(state)
1119 hbisect.checkstate(state)
1120
1120
1121 # actually bisect
1121 # actually bisect
1122 nodes, changesets, good = hbisect.bisect(repo, state)
1122 nodes, changesets, good = hbisect.bisect(repo, state)
1123 if extend:
1123 if extend:
1124 if not changesets:
1124 if not changesets:
1125 extendctx = hbisect.extendrange(repo, state, nodes, good)
1125 extendctx = hbisect.extendrange(repo, state, nodes, good)
1126 if extendctx is not None:
1126 if extendctx is not None:
1127 ui.write(
1127 ui.write(
1128 _(b"Extending search to changeset %s\n")
1128 _(b"Extending search to changeset %s\n")
1129 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1129 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1130 )
1130 )
1131 state[b'current'] = [extendctx.node()]
1131 state[b'current'] = [extendctx.node()]
1132 hbisect.save_state(repo, state)
1132 hbisect.save_state(repo, state)
1133 return mayupdate(repo, extendctx.node())
1133 return mayupdate(repo, extendctx.node())
1134 raise error.StateError(_(b"nothing to extend"))
1134 raise error.StateError(_(b"nothing to extend"))
1135
1135
1136 if changesets == 0:
1136 if changesets == 0:
1137 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1137 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1138 else:
1138 else:
1139 assert len(nodes) == 1 # only a single node can be tested next
1139 assert len(nodes) == 1 # only a single node can be tested next
1140 node = nodes[0]
1140 node = nodes[0]
1141 # compute the approximate number of remaining tests
1141 # compute the approximate number of remaining tests
1142 tests, size = 0, 2
1142 tests, size = 0, 2
1143 while size <= changesets:
1143 while size <= changesets:
1144 tests, size = tests + 1, size * 2
1144 tests, size = tests + 1, size * 2
1145 rev = repo.changelog.rev(node)
1145 rev = repo.changelog.rev(node)
1146 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1146 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1147 ui.write(
1147 ui.write(
1148 _(
1148 _(
1149 b"Testing changeset %s "
1149 b"Testing changeset %s "
1150 b"(%d changesets remaining, ~%d tests)\n"
1150 b"(%d changesets remaining, ~%d tests)\n"
1151 )
1151 )
1152 % (summary, changesets, tests)
1152 % (summary, changesets, tests)
1153 )
1153 )
1154 state[b'current'] = [node]
1154 state[b'current'] = [node]
1155 hbisect.save_state(repo, state)
1155 hbisect.save_state(repo, state)
1156 return mayupdate(repo, node)
1156 return mayupdate(repo, node)
1157
1157
1158
1158
1159 @command(
1159 @command(
1160 b'bookmarks|bookmark',
1160 b'bookmarks|bookmark',
1161 [
1161 [
1162 (b'f', b'force', False, _(b'force')),
1162 (b'f', b'force', False, _(b'force')),
1163 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1163 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1164 (b'd', b'delete', False, _(b'delete a given bookmark')),
1164 (b'd', b'delete', False, _(b'delete a given bookmark')),
1165 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1165 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1166 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1166 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1167 (b'l', b'list', False, _(b'list existing bookmarks')),
1167 (b'l', b'list', False, _(b'list existing bookmarks')),
1168 ]
1168 ]
1169 + formatteropts,
1169 + formatteropts,
1170 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1170 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1171 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1171 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1172 )
1172 )
1173 def bookmark(ui, repo, *names, **opts):
1173 def bookmark(ui, repo, *names, **opts):
1174 """create a new bookmark or list existing bookmarks
1174 """create a new bookmark or list existing bookmarks
1175
1175
1176 Bookmarks are labels on changesets to help track lines of development.
1176 Bookmarks are labels on changesets to help track lines of development.
1177 Bookmarks are unversioned and can be moved, renamed and deleted.
1177 Bookmarks are unversioned and can be moved, renamed and deleted.
1178 Deleting or moving a bookmark has no effect on the associated changesets.
1178 Deleting or moving a bookmark has no effect on the associated changesets.
1179
1179
1180 Creating or updating to a bookmark causes it to be marked as 'active'.
1180 Creating or updating to a bookmark causes it to be marked as 'active'.
1181 The active bookmark is indicated with a '*'.
1181 The active bookmark is indicated with a '*'.
1182 When a commit is made, the active bookmark will advance to the new commit.
1182 When a commit is made, the active bookmark will advance to the new commit.
1183 A plain :hg:`update` will also advance an active bookmark, if possible.
1183 A plain :hg:`update` will also advance an active bookmark, if possible.
1184 Updating away from a bookmark will cause it to be deactivated.
1184 Updating away from a bookmark will cause it to be deactivated.
1185
1185
1186 Bookmarks can be pushed and pulled between repositories (see
1186 Bookmarks can be pushed and pulled between repositories (see
1187 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1187 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1188 diverged, a new 'divergent bookmark' of the form 'name@path' will
1188 diverged, a new 'divergent bookmark' of the form 'name@path' will
1189 be created. Using :hg:`merge` will resolve the divergence.
1189 be created. Using :hg:`merge` will resolve the divergence.
1190
1190
1191 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1191 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1192 the active bookmark's name.
1192 the active bookmark's name.
1193
1193
1194 A bookmark named '@' has the special property that :hg:`clone` will
1194 A bookmark named '@' has the special property that :hg:`clone` will
1195 check it out by default if it exists.
1195 check it out by default if it exists.
1196
1196
1197 .. container:: verbose
1197 .. container:: verbose
1198
1198
1199 Template:
1199 Template:
1200
1200
1201 The following keywords are supported in addition to the common template
1201 The following keywords are supported in addition to the common template
1202 keywords and functions such as ``{bookmark}``. See also
1202 keywords and functions such as ``{bookmark}``. See also
1203 :hg:`help templates`.
1203 :hg:`help templates`.
1204
1204
1205 :active: Boolean. True if the bookmark is active.
1205 :active: Boolean. True if the bookmark is active.
1206
1206
1207 Examples:
1207 Examples:
1208
1208
1209 - create an active bookmark for a new line of development::
1209 - create an active bookmark for a new line of development::
1210
1210
1211 hg book new-feature
1211 hg book new-feature
1212
1212
1213 - create an inactive bookmark as a place marker::
1213 - create an inactive bookmark as a place marker::
1214
1214
1215 hg book -i reviewed
1215 hg book -i reviewed
1216
1216
1217 - create an inactive bookmark on another changeset::
1217 - create an inactive bookmark on another changeset::
1218
1218
1219 hg book -r .^ tested
1219 hg book -r .^ tested
1220
1220
1221 - rename bookmark turkey to dinner::
1221 - rename bookmark turkey to dinner::
1222
1222
1223 hg book -m turkey dinner
1223 hg book -m turkey dinner
1224
1224
1225 - move the '@' bookmark from another branch::
1225 - move the '@' bookmark from another branch::
1226
1226
1227 hg book -f @
1227 hg book -f @
1228
1228
1229 - print only the active bookmark name::
1229 - print only the active bookmark name::
1230
1230
1231 hg book -ql .
1231 hg book -ql .
1232 """
1232 """
1233 opts = pycompat.byteskwargs(opts)
1233 opts = pycompat.byteskwargs(opts)
1234 force = opts.get(b'force')
1234 force = opts.get(b'force')
1235 rev = opts.get(b'rev')
1235 rev = opts.get(b'rev')
1236 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1236 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1237
1237
1238 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1238 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1239 if action:
1239 if action:
1240 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1240 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1241 elif names or rev:
1241 elif names or rev:
1242 action = b'add'
1242 action = b'add'
1243 elif inactive:
1243 elif inactive:
1244 action = b'inactive' # meaning deactivate
1244 action = b'inactive' # meaning deactivate
1245 else:
1245 else:
1246 action = b'list'
1246 action = b'list'
1247
1247
1248 cmdutil.check_incompatible_arguments(
1248 cmdutil.check_incompatible_arguments(
1249 opts, b'inactive', [b'delete', b'list']
1249 opts, b'inactive', [b'delete', b'list']
1250 )
1250 )
1251 if not names and action in {b'add', b'delete'}:
1251 if not names and action in {b'add', b'delete'}:
1252 raise error.InputError(_(b"bookmark name required"))
1252 raise error.InputError(_(b"bookmark name required"))
1253
1253
1254 if action in {b'add', b'delete', b'rename', b'inactive'}:
1254 if action in {b'add', b'delete', b'rename', b'inactive'}:
1255 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1255 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1256 if action == b'delete':
1256 if action == b'delete':
1257 names = pycompat.maplist(repo._bookmarks.expandname, names)
1257 names = pycompat.maplist(repo._bookmarks.expandname, names)
1258 bookmarks.delete(repo, tr, names)
1258 bookmarks.delete(repo, tr, names)
1259 elif action == b'rename':
1259 elif action == b'rename':
1260 if not names:
1260 if not names:
1261 raise error.InputError(_(b"new bookmark name required"))
1261 raise error.InputError(_(b"new bookmark name required"))
1262 elif len(names) > 1:
1262 elif len(names) > 1:
1263 raise error.InputError(
1263 raise error.InputError(
1264 _(b"only one new bookmark name allowed")
1264 _(b"only one new bookmark name allowed")
1265 )
1265 )
1266 oldname = repo._bookmarks.expandname(opts[b'rename'])
1266 oldname = repo._bookmarks.expandname(opts[b'rename'])
1267 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1267 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1268 elif action == b'add':
1268 elif action == b'add':
1269 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1269 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1270 elif action == b'inactive':
1270 elif action == b'inactive':
1271 if len(repo._bookmarks) == 0:
1271 if len(repo._bookmarks) == 0:
1272 ui.status(_(b"no bookmarks set\n"))
1272 ui.status(_(b"no bookmarks set\n"))
1273 elif not repo._activebookmark:
1273 elif not repo._activebookmark:
1274 ui.status(_(b"no active bookmark\n"))
1274 ui.status(_(b"no active bookmark\n"))
1275 else:
1275 else:
1276 bookmarks.deactivate(repo)
1276 bookmarks.deactivate(repo)
1277 elif action == b'list':
1277 elif action == b'list':
1278 names = pycompat.maplist(repo._bookmarks.expandname, names)
1278 names = pycompat.maplist(repo._bookmarks.expandname, names)
1279 with ui.formatter(b'bookmarks', opts) as fm:
1279 with ui.formatter(b'bookmarks', opts) as fm:
1280 bookmarks.printbookmarks(ui, repo, fm, names)
1280 bookmarks.printbookmarks(ui, repo, fm, names)
1281 else:
1281 else:
1282 raise error.ProgrammingError(b'invalid action: %s' % action)
1282 raise error.ProgrammingError(b'invalid action: %s' % action)
1283
1283
1284
1284
1285 @command(
1285 @command(
1286 b'branch',
1286 b'branch',
1287 [
1287 [
1288 (
1288 (
1289 b'f',
1289 b'f',
1290 b'force',
1290 b'force',
1291 None,
1291 None,
1292 _(b'set branch name even if it shadows an existing branch'),
1292 _(b'set branch name even if it shadows an existing branch'),
1293 ),
1293 ),
1294 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1294 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1295 (
1295 (
1296 b'r',
1296 b'r',
1297 b'rev',
1297 b'rev',
1298 [],
1298 [],
1299 _(b'change branches of the given revs (EXPERIMENTAL)'),
1299 _(b'change branches of the given revs (EXPERIMENTAL)'),
1300 ),
1300 ),
1301 ],
1301 ],
1302 _(b'[-fC] [NAME]'),
1302 _(b'[-fC] [NAME]'),
1303 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1303 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1304 )
1304 )
1305 def branch(ui, repo, label=None, **opts):
1305 def branch(ui, repo, label=None, **opts):
1306 """set or show the current branch name
1306 """set or show the current branch name
1307
1307
1308 .. note::
1308 .. note::
1309
1309
1310 Branch names are permanent and global. Use :hg:`bookmark` to create a
1310 Branch names are permanent and global. Use :hg:`bookmark` to create a
1311 light-weight bookmark instead. See :hg:`help glossary` for more
1311 light-weight bookmark instead. See :hg:`help glossary` for more
1312 information about named branches and bookmarks.
1312 information about named branches and bookmarks.
1313
1313
1314 With no argument, show the current branch name. With one argument,
1314 With no argument, show the current branch name. With one argument,
1315 set the working directory branch name (the branch will not exist
1315 set the working directory branch name (the branch will not exist
1316 in the repository until the next commit). Standard practice
1316 in the repository until the next commit). Standard practice
1317 recommends that primary development take place on the 'default'
1317 recommends that primary development take place on the 'default'
1318 branch.
1318 branch.
1319
1319
1320 Unless -f/--force is specified, branch will not let you set a
1320 Unless -f/--force is specified, branch will not let you set a
1321 branch name that already exists.
1321 branch name that already exists.
1322
1322
1323 Use -C/--clean to reset the working directory branch to that of
1323 Use -C/--clean to reset the working directory branch to that of
1324 the parent of the working directory, negating a previous branch
1324 the parent of the working directory, negating a previous branch
1325 change.
1325 change.
1326
1326
1327 Use the command :hg:`update` to switch to an existing branch. Use
1327 Use the command :hg:`update` to switch to an existing branch. Use
1328 :hg:`commit --close-branch` to mark this branch head as closed.
1328 :hg:`commit --close-branch` to mark this branch head as closed.
1329 When all heads of a branch are closed, the branch will be
1329 When all heads of a branch are closed, the branch will be
1330 considered closed.
1330 considered closed.
1331
1331
1332 Returns 0 on success.
1332 Returns 0 on success.
1333 """
1333 """
1334 opts = pycompat.byteskwargs(opts)
1334 opts = pycompat.byteskwargs(opts)
1335 revs = opts.get(b'rev')
1335 revs = opts.get(b'rev')
1336 if label:
1336 if label:
1337 label = label.strip()
1337 label = label.strip()
1338
1338
1339 if not opts.get(b'clean') and not label:
1339 if not opts.get(b'clean') and not label:
1340 if revs:
1340 if revs:
1341 raise error.InputError(
1341 raise error.InputError(
1342 _(b"no branch name specified for the revisions")
1342 _(b"no branch name specified for the revisions")
1343 )
1343 )
1344 ui.write(b"%s\n" % repo.dirstate.branch())
1344 ui.write(b"%s\n" % repo.dirstate.branch())
1345 return
1345 return
1346
1346
1347 with repo.wlock():
1347 with repo.wlock():
1348 if opts.get(b'clean'):
1348 if opts.get(b'clean'):
1349 label = repo[b'.'].branch()
1349 label = repo[b'.'].branch()
1350 repo.dirstate.setbranch(label)
1350 repo.dirstate.setbranch(label)
1351 ui.status(_(b'reset working directory to branch %s\n') % label)
1351 ui.status(_(b'reset working directory to branch %s\n') % label)
1352 elif label:
1352 elif label:
1353
1353
1354 scmutil.checknewlabel(repo, label, b'branch')
1354 scmutil.checknewlabel(repo, label, b'branch')
1355 if revs:
1355 if revs:
1356 return cmdutil.changebranch(ui, repo, revs, label, opts)
1356 return cmdutil.changebranch(ui, repo, revs, label, opts)
1357
1357
1358 if not opts.get(b'force') and label in repo.branchmap():
1358 if not opts.get(b'force') and label in repo.branchmap():
1359 if label not in [p.branch() for p in repo[None].parents()]:
1359 if label not in [p.branch() for p in repo[None].parents()]:
1360 raise error.InputError(
1360 raise error.InputError(
1361 _(b'a branch of the same name already exists'),
1361 _(b'a branch of the same name already exists'),
1362 # i18n: "it" refers to an existing branch
1362 # i18n: "it" refers to an existing branch
1363 hint=_(b"use 'hg update' to switch to it"),
1363 hint=_(b"use 'hg update' to switch to it"),
1364 )
1364 )
1365
1365
1366 repo.dirstate.setbranch(label)
1366 repo.dirstate.setbranch(label)
1367 ui.status(_(b'marked working directory as branch %s\n') % label)
1367 ui.status(_(b'marked working directory as branch %s\n') % label)
1368
1368
1369 # find any open named branches aside from default
1369 # find any open named branches aside from default
1370 for n, h, t, c in repo.branchmap().iterbranches():
1370 for n, h, t, c in repo.branchmap().iterbranches():
1371 if n != b"default" and not c:
1371 if n != b"default" and not c:
1372 return 0
1372 return 0
1373 ui.status(
1373 ui.status(
1374 _(
1374 _(
1375 b'(branches are permanent and global, '
1375 b'(branches are permanent and global, '
1376 b'did you want a bookmark?)\n'
1376 b'did you want a bookmark?)\n'
1377 )
1377 )
1378 )
1378 )
1379
1379
1380
1380
1381 @command(
1381 @command(
1382 b'branches',
1382 b'branches',
1383 [
1383 [
1384 (
1384 (
1385 b'a',
1385 b'a',
1386 b'active',
1386 b'active',
1387 False,
1387 False,
1388 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1388 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1389 ),
1389 ),
1390 (b'c', b'closed', False, _(b'show normal and closed branches')),
1390 (b'c', b'closed', False, _(b'show normal and closed branches')),
1391 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1391 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1392 ]
1392 ]
1393 + formatteropts,
1393 + formatteropts,
1394 _(b'[-c]'),
1394 _(b'[-c]'),
1395 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1395 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1396 intents={INTENT_READONLY},
1396 intents={INTENT_READONLY},
1397 )
1397 )
1398 def branches(ui, repo, active=False, closed=False, **opts):
1398 def branches(ui, repo, active=False, closed=False, **opts):
1399 """list repository named branches
1399 """list repository named branches
1400
1400
1401 List the repository's named branches, indicating which ones are
1401 List the repository's named branches, indicating which ones are
1402 inactive. If -c/--closed is specified, also list branches which have
1402 inactive. If -c/--closed is specified, also list branches which have
1403 been marked closed (see :hg:`commit --close-branch`).
1403 been marked closed (see :hg:`commit --close-branch`).
1404
1404
1405 Use the command :hg:`update` to switch to an existing branch.
1405 Use the command :hg:`update` to switch to an existing branch.
1406
1406
1407 .. container:: verbose
1407 .. container:: verbose
1408
1408
1409 Template:
1409 Template:
1410
1410
1411 The following keywords are supported in addition to the common template
1411 The following keywords are supported in addition to the common template
1412 keywords and functions such as ``{branch}``. See also
1412 keywords and functions such as ``{branch}``. See also
1413 :hg:`help templates`.
1413 :hg:`help templates`.
1414
1414
1415 :active: Boolean. True if the branch is active.
1415 :active: Boolean. True if the branch is active.
1416 :closed: Boolean. True if the branch is closed.
1416 :closed: Boolean. True if the branch is closed.
1417 :current: Boolean. True if it is the current branch.
1417 :current: Boolean. True if it is the current branch.
1418
1418
1419 Returns 0.
1419 Returns 0.
1420 """
1420 """
1421
1421
1422 opts = pycompat.byteskwargs(opts)
1422 opts = pycompat.byteskwargs(opts)
1423 revs = opts.get(b'rev')
1423 revs = opts.get(b'rev')
1424 selectedbranches = None
1424 selectedbranches = None
1425 if revs:
1425 if revs:
1426 revs = logcmdutil.revrange(repo, revs)
1426 revs = logcmdutil.revrange(repo, revs)
1427 getbi = repo.revbranchcache().branchinfo
1427 getbi = repo.revbranchcache().branchinfo
1428 selectedbranches = {getbi(r)[0] for r in revs}
1428 selectedbranches = {getbi(r)[0] for r in revs}
1429
1429
1430 ui.pager(b'branches')
1430 ui.pager(b'branches')
1431 fm = ui.formatter(b'branches', opts)
1431 fm = ui.formatter(b'branches', opts)
1432 hexfunc = fm.hexfunc
1432 hexfunc = fm.hexfunc
1433
1433
1434 allheads = set(repo.heads())
1434 allheads = set(repo.heads())
1435 branches = []
1435 branches = []
1436 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1436 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1437 if selectedbranches is not None and tag not in selectedbranches:
1437 if selectedbranches is not None and tag not in selectedbranches:
1438 continue
1438 continue
1439 isactive = False
1439 isactive = False
1440 if not isclosed:
1440 if not isclosed:
1441 openheads = set(repo.branchmap().iteropen(heads))
1441 openheads = set(repo.branchmap().iteropen(heads))
1442 isactive = bool(openheads & allheads)
1442 isactive = bool(openheads & allheads)
1443 branches.append((tag, repo[tip], isactive, not isclosed))
1443 branches.append((tag, repo[tip], isactive, not isclosed))
1444 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1444 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1445
1445
1446 for tag, ctx, isactive, isopen in branches:
1446 for tag, ctx, isactive, isopen in branches:
1447 if active and not isactive:
1447 if active and not isactive:
1448 continue
1448 continue
1449 if isactive:
1449 if isactive:
1450 label = b'branches.active'
1450 label = b'branches.active'
1451 notice = b''
1451 notice = b''
1452 elif not isopen:
1452 elif not isopen:
1453 if not closed:
1453 if not closed:
1454 continue
1454 continue
1455 label = b'branches.closed'
1455 label = b'branches.closed'
1456 notice = _(b' (closed)')
1456 notice = _(b' (closed)')
1457 else:
1457 else:
1458 label = b'branches.inactive'
1458 label = b'branches.inactive'
1459 notice = _(b' (inactive)')
1459 notice = _(b' (inactive)')
1460 current = tag == repo.dirstate.branch()
1460 current = tag == repo.dirstate.branch()
1461 if current:
1461 if current:
1462 label = b'branches.current'
1462 label = b'branches.current'
1463
1463
1464 fm.startitem()
1464 fm.startitem()
1465 fm.write(b'branch', b'%s', tag, label=label)
1465 fm.write(b'branch', b'%s', tag, label=label)
1466 rev = ctx.rev()
1466 rev = ctx.rev()
1467 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1467 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1468 fmt = b' ' * padsize + b' %d:%s'
1468 fmt = b' ' * padsize + b' %d:%s'
1469 fm.condwrite(
1469 fm.condwrite(
1470 not ui.quiet,
1470 not ui.quiet,
1471 b'rev node',
1471 b'rev node',
1472 fmt,
1472 fmt,
1473 rev,
1473 rev,
1474 hexfunc(ctx.node()),
1474 hexfunc(ctx.node()),
1475 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1475 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1476 )
1476 )
1477 fm.context(ctx=ctx)
1477 fm.context(ctx=ctx)
1478 fm.data(active=isactive, closed=not isopen, current=current)
1478 fm.data(active=isactive, closed=not isopen, current=current)
1479 if not ui.quiet:
1479 if not ui.quiet:
1480 fm.plain(notice)
1480 fm.plain(notice)
1481 fm.plain(b'\n')
1481 fm.plain(b'\n')
1482 fm.end()
1482 fm.end()
1483
1483
1484
1484
1485 @command(
1485 @command(
1486 b'bundle',
1486 b'bundle',
1487 [
1487 [
1488 (
1488 (
1489 b'f',
1489 b'f',
1490 b'force',
1490 b'force',
1491 None,
1491 None,
1492 _(b'run even when the destination is unrelated'),
1492 _(b'run even when the destination is unrelated'),
1493 ),
1493 ),
1494 (
1494 (
1495 b'r',
1495 b'r',
1496 b'rev',
1496 b'rev',
1497 [],
1497 [],
1498 _(b'a changeset intended to be added to the destination'),
1498 _(b'a changeset intended to be added to the destination'),
1499 _(b'REV'),
1499 _(b'REV'),
1500 ),
1500 ),
1501 (
1501 (
1502 b'b',
1502 b'b',
1503 b'branch',
1503 b'branch',
1504 [],
1504 [],
1505 _(b'a specific branch you would like to bundle'),
1505 _(b'a specific branch you would like to bundle'),
1506 _(b'BRANCH'),
1506 _(b'BRANCH'),
1507 ),
1507 ),
1508 (
1508 (
1509 b'',
1509 b'',
1510 b'base',
1510 b'base',
1511 [],
1511 [],
1512 _(b'a base changeset assumed to be available at the destination'),
1512 _(b'a base changeset assumed to be available at the destination'),
1513 _(b'REV'),
1513 _(b'REV'),
1514 ),
1514 ),
1515 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1515 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1516 (
1516 (
1517 b't',
1517 b't',
1518 b'type',
1518 b'type',
1519 b'bzip2',
1519 b'bzip2',
1520 _(b'bundle compression type to use'),
1520 _(b'bundle compression type to use'),
1521 _(b'TYPE'),
1521 _(b'TYPE'),
1522 ),
1522 ),
1523 ]
1523 ]
1524 + remoteopts,
1524 + remoteopts,
1525 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1525 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1526 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1526 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1527 )
1527 )
1528 def bundle(ui, repo, fname, *dests, **opts):
1528 def bundle(ui, repo, fname, *dests, **opts):
1529 """create a bundle file
1529 """create a bundle file
1530
1530
1531 Generate a bundle file containing data to be transferred to another
1531 Generate a bundle file containing data to be transferred to another
1532 repository.
1532 repository.
1533
1533
1534 To create a bundle containing all changesets, use -a/--all
1534 To create a bundle containing all changesets, use -a/--all
1535 (or --base null). Otherwise, hg assumes the destination will have
1535 (or --base null). Otherwise, hg assumes the destination will have
1536 all the nodes you specify with --base parameters. Otherwise, hg
1536 all the nodes you specify with --base parameters. Otherwise, hg
1537 will assume the repository has all the nodes in destination, or
1537 will assume the repository has all the nodes in destination, or
1538 default-push/default if no destination is specified, where destination
1538 default-push/default if no destination is specified, where destination
1539 is the repositories you provide through DEST option.
1539 is the repositories you provide through DEST option.
1540
1540
1541 You can change bundle format with the -t/--type option. See
1541 You can change bundle format with the -t/--type option. See
1542 :hg:`help bundlespec` for documentation on this format. By default,
1542 :hg:`help bundlespec` for documentation on this format. By default,
1543 the most appropriate format is used and compression defaults to
1543 the most appropriate format is used and compression defaults to
1544 bzip2.
1544 bzip2.
1545
1545
1546 The bundle file can then be transferred using conventional means
1546 The bundle file can then be transferred using conventional means
1547 and applied to another repository with the unbundle or pull
1547 and applied to another repository with the unbundle or pull
1548 command. This is useful when direct push and pull are not
1548 command. This is useful when direct push and pull are not
1549 available or when exporting an entire repository is undesirable.
1549 available or when exporting an entire repository is undesirable.
1550
1550
1551 Applying bundles preserves all changeset contents including
1551 Applying bundles preserves all changeset contents including
1552 permissions, copy/rename information, and revision history.
1552 permissions, copy/rename information, and revision history.
1553
1553
1554 Returns 0 on success, 1 if no changes found.
1554 Returns 0 on success, 1 if no changes found.
1555 """
1555 """
1556 opts = pycompat.byteskwargs(opts)
1556 opts = pycompat.byteskwargs(opts)
1557 revs = None
1557 revs = None
1558 if b'rev' in opts:
1558 if b'rev' in opts:
1559 revstrings = opts[b'rev']
1559 revstrings = opts[b'rev']
1560 revs = logcmdutil.revrange(repo, revstrings)
1560 revs = logcmdutil.revrange(repo, revstrings)
1561 if revstrings and not revs:
1561 if revstrings and not revs:
1562 raise error.InputError(_(b'no commits to bundle'))
1562 raise error.InputError(_(b'no commits to bundle'))
1563
1563
1564 bundletype = opts.get(b'type', b'bzip2').lower()
1564 bundletype = opts.get(b'type', b'bzip2').lower()
1565 try:
1565 try:
1566 bundlespec = bundlecaches.parsebundlespec(
1566 bundlespec = bundlecaches.parsebundlespec(
1567 repo, bundletype, strict=False
1567 repo, bundletype, strict=False
1568 )
1568 )
1569 except error.UnsupportedBundleSpecification as e:
1569 except error.UnsupportedBundleSpecification as e:
1570 raise error.InputError(
1570 raise error.InputError(
1571 pycompat.bytestr(e),
1571 pycompat.bytestr(e),
1572 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1572 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1573 )
1573 )
1574 cgversion = bundlespec.contentopts[b"cg.version"]
1574 cgversion = bundlespec.contentopts[b"cg.version"]
1575
1575
1576 # Packed bundles are a pseudo bundle format for now.
1576 # Packed bundles are a pseudo bundle format for now.
1577 if cgversion == b's1':
1577 if cgversion == b's1':
1578 raise error.InputError(
1578 raise error.InputError(
1579 _(b'packed bundles cannot be produced by "hg bundle"'),
1579 _(b'packed bundles cannot be produced by "hg bundle"'),
1580 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1580 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1581 )
1581 )
1582
1582
1583 if opts.get(b'all'):
1583 if opts.get(b'all'):
1584 if dests:
1584 if dests:
1585 raise error.InputError(
1585 raise error.InputError(
1586 _(b"--all is incompatible with specifying destinations")
1586 _(b"--all is incompatible with specifying destinations")
1587 )
1587 )
1588 if opts.get(b'base'):
1588 if opts.get(b'base'):
1589 ui.warn(_(b"ignoring --base because --all was specified\n"))
1589 ui.warn(_(b"ignoring --base because --all was specified\n"))
1590 base = [nullrev]
1590 base = [nullrev]
1591 else:
1591 else:
1592 base = logcmdutil.revrange(repo, opts.get(b'base'))
1592 base = logcmdutil.revrange(repo, opts.get(b'base'))
1593 if cgversion not in changegroup.supportedoutgoingversions(repo):
1593 if cgversion not in changegroup.supportedoutgoingversions(repo):
1594 raise error.Abort(
1594 raise error.Abort(
1595 _(b"repository does not support bundle version %s") % cgversion
1595 _(b"repository does not support bundle version %s") % cgversion
1596 )
1596 )
1597
1597
1598 if base:
1598 if base:
1599 if dests:
1599 if dests:
1600 raise error.InputError(
1600 raise error.InputError(
1601 _(b"--base is incompatible with specifying destinations")
1601 _(b"--base is incompatible with specifying destinations")
1602 )
1602 )
1603 common = [repo[rev].node() for rev in base]
1603 common = [repo[rev].node() for rev in base]
1604 heads = [repo[r].node() for r in revs] if revs else None
1604 heads = [repo[r].node() for r in revs] if revs else None
1605 outgoing = discovery.outgoing(repo, common, heads)
1605 outgoing = discovery.outgoing(repo, common, heads)
1606 missing = outgoing.missing
1606 missing = outgoing.missing
1607 excluded = outgoing.excluded
1607 excluded = outgoing.excluded
1608 else:
1608 else:
1609 missing = set()
1609 missing = set()
1610 excluded = set()
1610 excluded = set()
1611 for path in urlutil.get_push_paths(repo, ui, dests):
1611 for path in urlutil.get_push_paths(repo, ui, dests):
1612 other = hg.peer(repo, opts, path.rawloc)
1612 other = hg.peer(repo, opts, path.rawloc)
1613 if revs is not None:
1613 if revs is not None:
1614 hex_revs = [repo[r].hex() for r in revs]
1614 hex_revs = [repo[r].hex() for r in revs]
1615 else:
1615 else:
1616 hex_revs = None
1616 hex_revs = None
1617 branches = (path.branch, [])
1617 branches = (path.branch, [])
1618 head_revs, checkout = hg.addbranchrevs(
1618 head_revs, checkout = hg.addbranchrevs(
1619 repo, repo, branches, hex_revs
1619 repo, repo, branches, hex_revs
1620 )
1620 )
1621 heads = (
1621 heads = (
1622 head_revs
1622 head_revs
1623 and pycompat.maplist(repo.lookup, head_revs)
1623 and pycompat.maplist(repo.lookup, head_revs)
1624 or head_revs
1624 or head_revs
1625 )
1625 )
1626 outgoing = discovery.findcommonoutgoing(
1626 outgoing = discovery.findcommonoutgoing(
1627 repo,
1627 repo,
1628 other,
1628 other,
1629 onlyheads=heads,
1629 onlyheads=heads,
1630 force=opts.get(b'force'),
1630 force=opts.get(b'force'),
1631 portable=True,
1631 portable=True,
1632 )
1632 )
1633 missing.update(outgoing.missing)
1633 missing.update(outgoing.missing)
1634 excluded.update(outgoing.excluded)
1634 excluded.update(outgoing.excluded)
1635
1635
1636 if not missing:
1636 if not missing:
1637 scmutil.nochangesfound(ui, repo, not base and excluded)
1637 scmutil.nochangesfound(ui, repo, not base and excluded)
1638 return 1
1638 return 1
1639
1639
1640 if heads:
1640 if heads:
1641 outgoing = discovery.outgoing(
1641 outgoing = discovery.outgoing(
1642 repo, missingroots=missing, ancestorsof=heads
1642 repo, missingroots=missing, ancestorsof=heads
1643 )
1643 )
1644 else:
1644 else:
1645 outgoing = discovery.outgoing(repo, missingroots=missing)
1645 outgoing = discovery.outgoing(repo, missingroots=missing)
1646 outgoing.excluded = sorted(excluded)
1646 outgoing.excluded = sorted(excluded)
1647
1647
1648 if cgversion == b'01': # bundle1
1648 if cgversion == b'01': # bundle1
1649 bversion = b'HG10' + bundlespec.wirecompression
1649 bversion = b'HG10' + bundlespec.wirecompression
1650 bcompression = None
1650 bcompression = None
1651 elif cgversion in (b'02', b'03'):
1651 elif cgversion in (b'02', b'03'):
1652 bversion = b'HG20'
1652 bversion = b'HG20'
1653 bcompression = bundlespec.wirecompression
1653 bcompression = bundlespec.wirecompression
1654 else:
1654 else:
1655 raise error.ProgrammingError(
1655 raise error.ProgrammingError(
1656 b'bundle: unexpected changegroup version %s' % cgversion
1656 b'bundle: unexpected changegroup version %s' % cgversion
1657 )
1657 )
1658
1658
1659 # TODO compression options should be derived from bundlespec parsing.
1659 # TODO compression options should be derived from bundlespec parsing.
1660 # This is a temporary hack to allow adjusting bundle compression
1660 # This is a temporary hack to allow adjusting bundle compression
1661 # level without a) formalizing the bundlespec changes to declare it
1661 # level without a) formalizing the bundlespec changes to declare it
1662 # b) introducing a command flag.
1662 # b) introducing a command flag.
1663 compopts = {}
1663 compopts = {}
1664 complevel = ui.configint(
1664 complevel = ui.configint(
1665 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1665 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1666 )
1666 )
1667 if complevel is None:
1667 if complevel is None:
1668 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1668 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1669 if complevel is not None:
1669 if complevel is not None:
1670 compopts[b'level'] = complevel
1670 compopts[b'level'] = complevel
1671
1671
1672 compthreads = ui.configint(
1672 compthreads = ui.configint(
1673 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1673 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1674 )
1674 )
1675 if compthreads is None:
1675 if compthreads is None:
1676 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1676 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1677 if compthreads is not None:
1677 if compthreads is not None:
1678 compopts[b'threads'] = compthreads
1678 compopts[b'threads'] = compthreads
1679
1679
1680 # Bundling of obsmarker and phases is optional as not all clients
1680 # Bundling of obsmarker and phases is optional as not all clients
1681 # support the necessary features.
1681 # support the necessary features.
1682 cfg = ui.configbool
1682 cfg = ui.configbool
1683 contentopts = {
1683 contentopts = {
1684 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1684 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1685 b'obsolescence-mandatory': cfg(
1685 b'obsolescence-mandatory': cfg(
1686 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1686 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1687 ),
1687 ),
1688 b'phases': cfg(b'experimental', b'bundle-phases'),
1688 b'phases': cfg(b'experimental', b'bundle-phases'),
1689 }
1689 }
1690 bundlespec.contentopts.update(contentopts)
1690 bundlespec.contentopts.update(contentopts)
1691
1691
1692 bundle2.writenewbundle(
1692 bundle2.writenewbundle(
1693 ui,
1693 ui,
1694 repo,
1694 repo,
1695 b'bundle',
1695 b'bundle',
1696 fname,
1696 fname,
1697 bversion,
1697 bversion,
1698 outgoing,
1698 outgoing,
1699 bundlespec.contentopts,
1699 bundlespec.contentopts,
1700 compression=bcompression,
1700 compression=bcompression,
1701 compopts=compopts,
1701 compopts=compopts,
1702 )
1702 )
1703
1703
1704
1704
1705 @command(
1705 @command(
1706 b'cat',
1706 b'cat',
1707 [
1707 [
1708 (
1708 (
1709 b'o',
1709 b'o',
1710 b'output',
1710 b'output',
1711 b'',
1711 b'',
1712 _(b'print output to file with formatted name'),
1712 _(b'print output to file with formatted name'),
1713 _(b'FORMAT'),
1713 _(b'FORMAT'),
1714 ),
1714 ),
1715 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1715 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1716 (b'', b'decode', None, _(b'apply any matching decode filter')),
1716 (b'', b'decode', None, _(b'apply any matching decode filter')),
1717 ]
1717 ]
1718 + walkopts
1718 + walkopts
1719 + formatteropts,
1719 + formatteropts,
1720 _(b'[OPTION]... FILE...'),
1720 _(b'[OPTION]... FILE...'),
1721 helpcategory=command.CATEGORY_FILE_CONTENTS,
1721 helpcategory=command.CATEGORY_FILE_CONTENTS,
1722 inferrepo=True,
1722 inferrepo=True,
1723 intents={INTENT_READONLY},
1723 intents={INTENT_READONLY},
1724 )
1724 )
1725 def cat(ui, repo, file1, *pats, **opts):
1725 def cat(ui, repo, file1, *pats, **opts):
1726 """output the current or given revision of files
1726 """output the current or given revision of files
1727
1727
1728 Print the specified files as they were at the given revision. If
1728 Print the specified files as they were at the given revision. If
1729 no revision is given, the parent of the working directory is used.
1729 no revision is given, the parent of the working directory is used.
1730
1730
1731 Output may be to a file, in which case the name of the file is
1731 Output may be to a file, in which case the name of the file is
1732 given using a template string. See :hg:`help templates`. In addition
1732 given using a template string. See :hg:`help templates`. In addition
1733 to the common template keywords, the following formatting rules are
1733 to the common template keywords, the following formatting rules are
1734 supported:
1734 supported:
1735
1735
1736 :``%%``: literal "%" character
1736 :``%%``: literal "%" character
1737 :``%s``: basename of file being printed
1737 :``%s``: basename of file being printed
1738 :``%d``: dirname of file being printed, or '.' if in repository root
1738 :``%d``: dirname of file being printed, or '.' if in repository root
1739 :``%p``: root-relative path name of file being printed
1739 :``%p``: root-relative path name of file being printed
1740 :``%H``: changeset hash (40 hexadecimal digits)
1740 :``%H``: changeset hash (40 hexadecimal digits)
1741 :``%R``: changeset revision number
1741 :``%R``: changeset revision number
1742 :``%h``: short-form changeset hash (12 hexadecimal digits)
1742 :``%h``: short-form changeset hash (12 hexadecimal digits)
1743 :``%r``: zero-padded changeset revision number
1743 :``%r``: zero-padded changeset revision number
1744 :``%b``: basename of the exporting repository
1744 :``%b``: basename of the exporting repository
1745 :``\\``: literal "\\" character
1745 :``\\``: literal "\\" character
1746
1746
1747 .. container:: verbose
1747 .. container:: verbose
1748
1748
1749 Template:
1749 Template:
1750
1750
1751 The following keywords are supported in addition to the common template
1751 The following keywords are supported in addition to the common template
1752 keywords and functions. See also :hg:`help templates`.
1752 keywords and functions. See also :hg:`help templates`.
1753
1753
1754 :data: String. File content.
1754 :data: String. File content.
1755 :path: String. Repository-absolute path of the file.
1755 :path: String. Repository-absolute path of the file.
1756
1756
1757 Returns 0 on success.
1757 Returns 0 on success.
1758 """
1758 """
1759 opts = pycompat.byteskwargs(opts)
1759 opts = pycompat.byteskwargs(opts)
1760 rev = opts.get(b'rev')
1760 rev = opts.get(b'rev')
1761 if rev:
1761 if rev:
1762 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1762 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1763 ctx = logcmdutil.revsingle(repo, rev)
1763 ctx = logcmdutil.revsingle(repo, rev)
1764 m = scmutil.match(ctx, (file1,) + pats, opts)
1764 m = scmutil.match(ctx, (file1,) + pats, opts)
1765 fntemplate = opts.pop(b'output', b'')
1765 fntemplate = opts.pop(b'output', b'')
1766 if cmdutil.isstdiofilename(fntemplate):
1766 if cmdutil.isstdiofilename(fntemplate):
1767 fntemplate = b''
1767 fntemplate = b''
1768
1768
1769 if fntemplate:
1769 if fntemplate:
1770 fm = formatter.nullformatter(ui, b'cat', opts)
1770 fm = formatter.nullformatter(ui, b'cat', opts)
1771 else:
1771 else:
1772 ui.pager(b'cat')
1772 ui.pager(b'cat')
1773 fm = ui.formatter(b'cat', opts)
1773 fm = ui.formatter(b'cat', opts)
1774 with fm:
1774 with fm:
1775 return cmdutil.cat(
1775 return cmdutil.cat(
1776 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1776 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1777 )
1777 )
1778
1778
1779
1779
1780 @command(
1780 @command(
1781 b'clone',
1781 b'clone',
1782 [
1782 [
1783 (
1783 (
1784 b'U',
1784 b'U',
1785 b'noupdate',
1785 b'noupdate',
1786 None,
1786 None,
1787 _(
1787 _(
1788 b'the clone will include an empty working '
1788 b'the clone will include an empty working '
1789 b'directory (only a repository)'
1789 b'directory (only a repository)'
1790 ),
1790 ),
1791 ),
1791 ),
1792 (
1792 (
1793 b'u',
1793 b'u',
1794 b'updaterev',
1794 b'updaterev',
1795 b'',
1795 b'',
1796 _(b'revision, tag, or branch to check out'),
1796 _(b'revision, tag, or branch to check out'),
1797 _(b'REV'),
1797 _(b'REV'),
1798 ),
1798 ),
1799 (
1799 (
1800 b'r',
1800 b'r',
1801 b'rev',
1801 b'rev',
1802 [],
1802 [],
1803 _(
1803 _(
1804 b'do not clone everything, but include this changeset'
1804 b'do not clone everything, but include this changeset'
1805 b' and its ancestors'
1805 b' and its ancestors'
1806 ),
1806 ),
1807 _(b'REV'),
1807 _(b'REV'),
1808 ),
1808 ),
1809 (
1809 (
1810 b'b',
1810 b'b',
1811 b'branch',
1811 b'branch',
1812 [],
1812 [],
1813 _(
1813 _(
1814 b'do not clone everything, but include this branch\'s'
1814 b'do not clone everything, but include this branch\'s'
1815 b' changesets and their ancestors'
1815 b' changesets and their ancestors'
1816 ),
1816 ),
1817 _(b'BRANCH'),
1817 _(b'BRANCH'),
1818 ),
1818 ),
1819 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1819 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1820 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1820 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1821 (b'', b'stream', None, _(b'clone with minimal data processing')),
1821 (b'', b'stream', None, _(b'clone with minimal data processing')),
1822 ]
1822 ]
1823 + remoteopts,
1823 + remoteopts,
1824 _(b'[OPTION]... SOURCE [DEST]'),
1824 _(b'[OPTION]... SOURCE [DEST]'),
1825 helpcategory=command.CATEGORY_REPO_CREATION,
1825 helpcategory=command.CATEGORY_REPO_CREATION,
1826 helpbasic=True,
1826 helpbasic=True,
1827 norepo=True,
1827 norepo=True,
1828 )
1828 )
1829 def clone(ui, source, dest=None, **opts):
1829 def clone(ui, source, dest=None, **opts):
1830 """make a copy of an existing repository
1830 """make a copy of an existing repository
1831
1831
1832 Create a copy of an existing repository in a new directory.
1832 Create a copy of an existing repository in a new directory.
1833
1833
1834 If no destination directory name is specified, it defaults to the
1834 If no destination directory name is specified, it defaults to the
1835 basename of the source.
1835 basename of the source.
1836
1836
1837 The location of the source is added to the new repository's
1837 The location of the source is added to the new repository's
1838 ``.hg/hgrc`` file, as the default to be used for future pulls.
1838 ``.hg/hgrc`` file, as the default to be used for future pulls.
1839
1839
1840 Only local paths and ``ssh://`` URLs are supported as
1840 Only local paths and ``ssh://`` URLs are supported as
1841 destinations. For ``ssh://`` destinations, no working directory or
1841 destinations. For ``ssh://`` destinations, no working directory or
1842 ``.hg/hgrc`` will be created on the remote side.
1842 ``.hg/hgrc`` will be created on the remote side.
1843
1843
1844 If the source repository has a bookmark called '@' set, that
1844 If the source repository has a bookmark called '@' set, that
1845 revision will be checked out in the new repository by default.
1845 revision will be checked out in the new repository by default.
1846
1846
1847 To check out a particular version, use -u/--update, or
1847 To check out a particular version, use -u/--update, or
1848 -U/--noupdate to create a clone with no working directory.
1848 -U/--noupdate to create a clone with no working directory.
1849
1849
1850 To pull only a subset of changesets, specify one or more revisions
1850 To pull only a subset of changesets, specify one or more revisions
1851 identifiers with -r/--rev or branches with -b/--branch. The
1851 identifiers with -r/--rev or branches with -b/--branch. The
1852 resulting clone will contain only the specified changesets and
1852 resulting clone will contain only the specified changesets and
1853 their ancestors. These options (or 'clone src#rev dest') imply
1853 their ancestors. These options (or 'clone src#rev dest') imply
1854 --pull, even for local source repositories.
1854 --pull, even for local source repositories.
1855
1855
1856 In normal clone mode, the remote normalizes repository data into a common
1856 In normal clone mode, the remote normalizes repository data into a common
1857 exchange format and the receiving end translates this data into its local
1857 exchange format and the receiving end translates this data into its local
1858 storage format. --stream activates a different clone mode that essentially
1858 storage format. --stream activates a different clone mode that essentially
1859 copies repository files from the remote with minimal data processing. This
1859 copies repository files from the remote with minimal data processing. This
1860 significantly reduces the CPU cost of a clone both remotely and locally.
1860 significantly reduces the CPU cost of a clone both remotely and locally.
1861 However, it often increases the transferred data size by 30-40%. This can
1861 However, it often increases the transferred data size by 30-40%. This can
1862 result in substantially faster clones where I/O throughput is plentiful,
1862 result in substantially faster clones where I/O throughput is plentiful,
1863 especially for larger repositories. A side-effect of --stream clones is
1863 especially for larger repositories. A side-effect of --stream clones is
1864 that storage settings and requirements on the remote are applied locally:
1864 that storage settings and requirements on the remote are applied locally:
1865 a modern client may inherit legacy or inefficient storage used by the
1865 a modern client may inherit legacy or inefficient storage used by the
1866 remote or a legacy Mercurial client may not be able to clone from a
1866 remote or a legacy Mercurial client may not be able to clone from a
1867 modern Mercurial remote.
1867 modern Mercurial remote.
1868
1868
1869 .. note::
1869 .. note::
1870
1870
1871 Specifying a tag will include the tagged changeset but not the
1871 Specifying a tag will include the tagged changeset but not the
1872 changeset containing the tag.
1872 changeset containing the tag.
1873
1873
1874 .. container:: verbose
1874 .. container:: verbose
1875
1875
1876 For efficiency, hardlinks are used for cloning whenever the
1876 For efficiency, hardlinks are used for cloning whenever the
1877 source and destination are on the same filesystem (note this
1877 source and destination are on the same filesystem (note this
1878 applies only to the repository data, not to the working
1878 applies only to the repository data, not to the working
1879 directory). Some filesystems, such as AFS, implement hardlinking
1879 directory). Some filesystems, such as AFS, implement hardlinking
1880 incorrectly, but do not report errors. In these cases, use the
1880 incorrectly, but do not report errors. In these cases, use the
1881 --pull option to avoid hardlinking.
1881 --pull option to avoid hardlinking.
1882
1882
1883 Mercurial will update the working directory to the first applicable
1883 Mercurial will update the working directory to the first applicable
1884 revision from this list:
1884 revision from this list:
1885
1885
1886 a) null if -U or the source repository has no changesets
1886 a) null if -U or the source repository has no changesets
1887 b) if -u . and the source repository is local, the first parent of
1887 b) if -u . and the source repository is local, the first parent of
1888 the source repository's working directory
1888 the source repository's working directory
1889 c) the changeset specified with -u (if a branch name, this means the
1889 c) the changeset specified with -u (if a branch name, this means the
1890 latest head of that branch)
1890 latest head of that branch)
1891 d) the changeset specified with -r
1891 d) the changeset specified with -r
1892 e) the tipmost head specified with -b
1892 e) the tipmost head specified with -b
1893 f) the tipmost head specified with the url#branch source syntax
1893 f) the tipmost head specified with the url#branch source syntax
1894 g) the revision marked with the '@' bookmark, if present
1894 g) the revision marked with the '@' bookmark, if present
1895 h) the tipmost head of the default branch
1895 h) the tipmost head of the default branch
1896 i) tip
1896 i) tip
1897
1897
1898 When cloning from servers that support it, Mercurial may fetch
1898 When cloning from servers that support it, Mercurial may fetch
1899 pre-generated data from a server-advertised URL or inline from the
1899 pre-generated data from a server-advertised URL or inline from the
1900 same stream. When this is done, hooks operating on incoming changesets
1900 same stream. When this is done, hooks operating on incoming changesets
1901 and changegroups may fire more than once, once for each pre-generated
1901 and changegroups may fire more than once, once for each pre-generated
1902 bundle and as well as for any additional remaining data. In addition,
1902 bundle and as well as for any additional remaining data. In addition,
1903 if an error occurs, the repository may be rolled back to a partial
1903 if an error occurs, the repository may be rolled back to a partial
1904 clone. This behavior may change in future releases.
1904 clone. This behavior may change in future releases.
1905 See :hg:`help -e clonebundles` for more.
1905 See :hg:`help -e clonebundles` for more.
1906
1906
1907 Examples:
1907 Examples:
1908
1908
1909 - clone a remote repository to a new directory named hg/::
1909 - clone a remote repository to a new directory named hg/::
1910
1910
1911 hg clone https://www.mercurial-scm.org/repo/hg/
1911 hg clone https://www.mercurial-scm.org/repo/hg/
1912
1912
1913 - create a lightweight local clone::
1913 - create a lightweight local clone::
1914
1914
1915 hg clone project/ project-feature/
1915 hg clone project/ project-feature/
1916
1916
1917 - clone from an absolute path on an ssh server (note double-slash)::
1917 - clone from an absolute path on an ssh server (note double-slash)::
1918
1918
1919 hg clone ssh://user@server//home/projects/alpha/
1919 hg clone ssh://user@server//home/projects/alpha/
1920
1920
1921 - do a streaming clone while checking out a specified version::
1921 - do a streaming clone while checking out a specified version::
1922
1922
1923 hg clone --stream http://server/repo -u 1.5
1923 hg clone --stream http://server/repo -u 1.5
1924
1924
1925 - create a repository without changesets after a particular revision::
1925 - create a repository without changesets after a particular revision::
1926
1926
1927 hg clone -r 04e544 experimental/ good/
1927 hg clone -r 04e544 experimental/ good/
1928
1928
1929 - clone (and track) a particular named branch::
1929 - clone (and track) a particular named branch::
1930
1930
1931 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1931 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1932
1932
1933 See :hg:`help urls` for details on specifying URLs.
1933 See :hg:`help urls` for details on specifying URLs.
1934
1934
1935 Returns 0 on success.
1935 Returns 0 on success.
1936 """
1936 """
1937 opts = pycompat.byteskwargs(opts)
1937 opts = pycompat.byteskwargs(opts)
1938 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1938 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1939
1939
1940 # --include/--exclude can come from narrow or sparse.
1940 # --include/--exclude can come from narrow or sparse.
1941 includepats, excludepats = None, None
1941 includepats, excludepats = None, None
1942
1942
1943 # hg.clone() differentiates between None and an empty set. So make sure
1943 # hg.clone() differentiates between None and an empty set. So make sure
1944 # patterns are sets if narrow is requested without patterns.
1944 # patterns are sets if narrow is requested without patterns.
1945 if opts.get(b'narrow'):
1945 if opts.get(b'narrow'):
1946 includepats = set()
1946 includepats = set()
1947 excludepats = set()
1947 excludepats = set()
1948
1948
1949 if opts.get(b'include'):
1949 if opts.get(b'include'):
1950 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1950 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1951 if opts.get(b'exclude'):
1951 if opts.get(b'exclude'):
1952 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1952 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1953
1953
1954 r = hg.clone(
1954 r = hg.clone(
1955 ui,
1955 ui,
1956 opts,
1956 opts,
1957 source,
1957 source,
1958 dest,
1958 dest,
1959 pull=opts.get(b'pull'),
1959 pull=opts.get(b'pull'),
1960 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1960 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1961 revs=opts.get(b'rev'),
1961 revs=opts.get(b'rev'),
1962 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1962 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1963 branch=opts.get(b'branch'),
1963 branch=opts.get(b'branch'),
1964 shareopts=opts.get(b'shareopts'),
1964 shareopts=opts.get(b'shareopts'),
1965 storeincludepats=includepats,
1965 storeincludepats=includepats,
1966 storeexcludepats=excludepats,
1966 storeexcludepats=excludepats,
1967 depth=opts.get(b'depth') or None,
1967 depth=opts.get(b'depth') or None,
1968 )
1968 )
1969
1969
1970 return r is None
1970 return r is None
1971
1971
1972
1972
1973 @command(
1973 @command(
1974 b'commit|ci',
1974 b'commit|ci',
1975 [
1975 [
1976 (
1976 (
1977 b'A',
1977 b'A',
1978 b'addremove',
1978 b'addremove',
1979 None,
1979 None,
1980 _(b'mark new/missing files as added/removed before committing'),
1980 _(b'mark new/missing files as added/removed before committing'),
1981 ),
1981 ),
1982 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1982 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1983 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1983 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1984 (b's', b'secret', None, _(b'use the secret phase for committing')),
1984 (b's', b'secret', None, _(b'use the secret phase for committing')),
1985 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1985 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1986 (
1986 (
1987 b'',
1987 b'',
1988 b'force-close-branch',
1988 b'force-close-branch',
1989 None,
1989 None,
1990 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1990 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1991 ),
1991 ),
1992 (b'i', b'interactive', None, _(b'use interactive mode')),
1992 (b'i', b'interactive', None, _(b'use interactive mode')),
1993 ]
1993 ]
1994 + walkopts
1994 + walkopts
1995 + commitopts
1995 + commitopts
1996 + commitopts2
1996 + commitopts2
1997 + subrepoopts,
1997 + subrepoopts,
1998 _(b'[OPTION]... [FILE]...'),
1998 _(b'[OPTION]... [FILE]...'),
1999 helpcategory=command.CATEGORY_COMMITTING,
1999 helpcategory=command.CATEGORY_COMMITTING,
2000 helpbasic=True,
2000 helpbasic=True,
2001 inferrepo=True,
2001 inferrepo=True,
2002 )
2002 )
2003 def commit(ui, repo, *pats, **opts):
2003 def commit(ui, repo, *pats, **opts):
2004 """commit the specified files or all outstanding changes
2004 """commit the specified files or all outstanding changes
2005
2005
2006 Commit changes to the given files into the repository. Unlike a
2006 Commit changes to the given files into the repository. Unlike a
2007 centralized SCM, this operation is a local operation. See
2007 centralized SCM, this operation is a local operation. See
2008 :hg:`push` for a way to actively distribute your changes.
2008 :hg:`push` for a way to actively distribute your changes.
2009
2009
2010 If a list of files is omitted, all changes reported by :hg:`status`
2010 If a list of files is omitted, all changes reported by :hg:`status`
2011 will be committed.
2011 will be committed.
2012
2012
2013 If you are committing the result of a merge, do not provide any
2013 If you are committing the result of a merge, do not provide any
2014 filenames or -I/-X filters.
2014 filenames or -I/-X filters.
2015
2015
2016 If no commit message is specified, Mercurial starts your
2016 If no commit message is specified, Mercurial starts your
2017 configured editor where you can enter a message. In case your
2017 configured editor where you can enter a message. In case your
2018 commit fails, you will find a backup of your message in
2018 commit fails, you will find a backup of your message in
2019 ``.hg/last-message.txt``.
2019 ``.hg/last-message.txt``.
2020
2020
2021 The --close-branch flag can be used to mark the current branch
2021 The --close-branch flag can be used to mark the current branch
2022 head closed. When all heads of a branch are closed, the branch
2022 head closed. When all heads of a branch are closed, the branch
2023 will be considered closed and no longer listed.
2023 will be considered closed and no longer listed.
2024
2024
2025 The --amend flag can be used to amend the parent of the
2025 The --amend flag can be used to amend the parent of the
2026 working directory with a new commit that contains the changes
2026 working directory with a new commit that contains the changes
2027 in the parent in addition to those currently reported by :hg:`status`,
2027 in the parent in addition to those currently reported by :hg:`status`,
2028 if there are any. The old commit is stored in a backup bundle in
2028 if there are any. The old commit is stored in a backup bundle in
2029 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2029 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2030 on how to restore it).
2030 on how to restore it).
2031
2031
2032 Message, user and date are taken from the amended commit unless
2032 Message, user and date are taken from the amended commit unless
2033 specified. When a message isn't specified on the command line,
2033 specified. When a message isn't specified on the command line,
2034 the editor will open with the message of the amended commit.
2034 the editor will open with the message of the amended commit.
2035
2035
2036 It is not possible to amend public changesets (see :hg:`help phases`)
2036 It is not possible to amend public changesets (see :hg:`help phases`)
2037 or changesets that have children.
2037 or changesets that have children.
2038
2038
2039 See :hg:`help dates` for a list of formats valid for -d/--date.
2039 See :hg:`help dates` for a list of formats valid for -d/--date.
2040
2040
2041 Returns 0 on success, 1 if nothing changed.
2041 Returns 0 on success, 1 if nothing changed.
2042
2042
2043 .. container:: verbose
2043 .. container:: verbose
2044
2044
2045 Examples:
2045 Examples:
2046
2046
2047 - commit all files ending in .py::
2047 - commit all files ending in .py::
2048
2048
2049 hg commit --include "set:**.py"
2049 hg commit --include "set:**.py"
2050
2050
2051 - commit all non-binary files::
2051 - commit all non-binary files::
2052
2052
2053 hg commit --exclude "set:binary()"
2053 hg commit --exclude "set:binary()"
2054
2054
2055 - amend the current commit and set the date to now::
2055 - amend the current commit and set the date to now::
2056
2056
2057 hg commit --amend --date now
2057 hg commit --amend --date now
2058 """
2058 """
2059 with repo.wlock(), repo.lock():
2059 with repo.wlock(), repo.lock():
2060 return _docommit(ui, repo, *pats, **opts)
2060 return _docommit(ui, repo, *pats, **opts)
2061
2061
2062
2062
2063 def _docommit(ui, repo, *pats, **opts):
2063 def _docommit(ui, repo, *pats, **opts):
2064 if opts.get('interactive'):
2064 if opts.get('interactive'):
2065 opts.pop('interactive')
2065 opts.pop('interactive')
2066 ret = cmdutil.dorecord(
2066 ret = cmdutil.dorecord(
2067 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2067 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2068 )
2068 )
2069 # ret can be 0 (no changes to record) or the value returned by
2069 # ret can be 0 (no changes to record) or the value returned by
2070 # commit(), 1 if nothing changed or None on success.
2070 # commit(), 1 if nothing changed or None on success.
2071 return 1 if ret == 0 else ret
2071 return 1 if ret == 0 else ret
2072
2072
2073 if opts.get('subrepos'):
2073 if opts.get('subrepos'):
2074 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2074 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2075 # Let --subrepos on the command line override config setting.
2075 # Let --subrepos on the command line override config setting.
2076 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2076 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2077
2077
2078 cmdutil.checkunfinished(repo, commit=True)
2078 cmdutil.checkunfinished(repo, commit=True)
2079
2079
2080 branch = repo[None].branch()
2080 branch = repo[None].branch()
2081 bheads = repo.branchheads(branch)
2081 bheads = repo.branchheads(branch)
2082 tip = repo.changelog.tip()
2082 tip = repo.changelog.tip()
2083
2083
2084 extra = {}
2084 extra = {}
2085 if opts.get('close_branch') or opts.get('force_close_branch'):
2085 if opts.get('close_branch') or opts.get('force_close_branch'):
2086 extra[b'close'] = b'1'
2086 extra[b'close'] = b'1'
2087
2087
2088 if repo[b'.'].closesbranch():
2088 if repo[b'.'].closesbranch():
2089 raise error.InputError(
2089 raise error.InputError(
2090 _(b'current revision is already a branch closing head')
2090 _(b'current revision is already a branch closing head')
2091 )
2091 )
2092 elif not bheads:
2092 elif not bheads:
2093 raise error.InputError(
2093 raise error.InputError(
2094 _(b'branch "%s" has no heads to close') % branch
2094 _(b'branch "%s" has no heads to close') % branch
2095 )
2095 )
2096 elif (
2096 elif (
2097 branch == repo[b'.'].branch()
2097 branch == repo[b'.'].branch()
2098 and repo[b'.'].node() not in bheads
2098 and repo[b'.'].node() not in bheads
2099 and not opts.get('force_close_branch')
2099 and not opts.get('force_close_branch')
2100 ):
2100 ):
2101 hint = _(
2101 hint = _(
2102 b'use --force-close-branch to close branch from a non-head'
2102 b'use --force-close-branch to close branch from a non-head'
2103 b' changeset'
2103 b' changeset'
2104 )
2104 )
2105 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2105 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2106 elif opts.get('amend'):
2106 elif opts.get('amend'):
2107 if (
2107 if (
2108 repo[b'.'].p1().branch() != branch
2108 repo[b'.'].p1().branch() != branch
2109 and repo[b'.'].p2().branch() != branch
2109 and repo[b'.'].p2().branch() != branch
2110 ):
2110 ):
2111 raise error.InputError(_(b'can only close branch heads'))
2111 raise error.InputError(_(b'can only close branch heads'))
2112
2112
2113 if opts.get('amend'):
2113 if opts.get('amend'):
2114 if ui.configbool(b'ui', b'commitsubrepos'):
2114 if ui.configbool(b'ui', b'commitsubrepos'):
2115 raise error.InputError(
2115 raise error.InputError(
2116 _(b'cannot amend with ui.commitsubrepos enabled')
2116 _(b'cannot amend with ui.commitsubrepos enabled')
2117 )
2117 )
2118
2118
2119 old = repo[b'.']
2119 old = repo[b'.']
2120 rewriteutil.precheck(repo, [old.rev()], b'amend')
2120 rewriteutil.precheck(repo, [old.rev()], b'amend')
2121
2121
2122 # Currently histedit gets confused if an amend happens while histedit
2122 # Currently histedit gets confused if an amend happens while histedit
2123 # is in progress. Since we have a checkunfinished command, we are
2123 # is in progress. Since we have a checkunfinished command, we are
2124 # temporarily honoring it.
2124 # temporarily honoring it.
2125 #
2125 #
2126 # Note: eventually this guard will be removed. Please do not expect
2126 # Note: eventually this guard will be removed. Please do not expect
2127 # this behavior to remain.
2127 # this behavior to remain.
2128 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2128 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2129 cmdutil.checkunfinished(repo)
2129 cmdutil.checkunfinished(repo)
2130
2130
2131 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2131 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2132 opts = pycompat.byteskwargs(opts)
2132 opts = pycompat.byteskwargs(opts)
2133 if node == old.node():
2133 if node == old.node():
2134 ui.status(_(b"nothing changed\n"))
2134 ui.status(_(b"nothing changed\n"))
2135 return 1
2135 return 1
2136 else:
2136 else:
2137
2137
2138 def commitfunc(ui, repo, message, match, opts):
2138 def commitfunc(ui, repo, message, match, opts):
2139 overrides = {}
2139 overrides = {}
2140 if opts.get(b'secret'):
2140 if opts.get(b'secret'):
2141 overrides[(b'phases', b'new-commit')] = b'secret'
2141 overrides[(b'phases', b'new-commit')] = b'secret'
2142
2142
2143 baseui = repo.baseui
2143 baseui = repo.baseui
2144 with baseui.configoverride(overrides, b'commit'):
2144 with baseui.configoverride(overrides, b'commit'):
2145 with ui.configoverride(overrides, b'commit'):
2145 with ui.configoverride(overrides, b'commit'):
2146 editform = cmdutil.mergeeditform(
2146 editform = cmdutil.mergeeditform(
2147 repo[None], b'commit.normal'
2147 repo[None], b'commit.normal'
2148 )
2148 )
2149 editor = cmdutil.getcommiteditor(
2149 editor = cmdutil.getcommiteditor(
2150 editform=editform, **pycompat.strkwargs(opts)
2150 editform=editform, **pycompat.strkwargs(opts)
2151 )
2151 )
2152 return repo.commit(
2152 return repo.commit(
2153 message,
2153 message,
2154 opts.get(b'user'),
2154 opts.get(b'user'),
2155 opts.get(b'date'),
2155 opts.get(b'date'),
2156 match,
2156 match,
2157 editor=editor,
2157 editor=editor,
2158 extra=extra,
2158 extra=extra,
2159 )
2159 )
2160
2160
2161 opts = pycompat.byteskwargs(opts)
2161 opts = pycompat.byteskwargs(opts)
2162 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2162 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2163
2163
2164 if not node:
2164 if not node:
2165 stat = cmdutil.postcommitstatus(repo, pats, opts)
2165 stat = cmdutil.postcommitstatus(repo, pats, opts)
2166 if stat.deleted:
2166 if stat.deleted:
2167 ui.status(
2167 ui.status(
2168 _(
2168 _(
2169 b"nothing changed (%d missing files, see "
2169 b"nothing changed (%d missing files, see "
2170 b"'hg status')\n"
2170 b"'hg status')\n"
2171 )
2171 )
2172 % len(stat.deleted)
2172 % len(stat.deleted)
2173 )
2173 )
2174 else:
2174 else:
2175 ui.status(_(b"nothing changed\n"))
2175 ui.status(_(b"nothing changed\n"))
2176 return 1
2176 return 1
2177
2177
2178 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2178 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2179
2179
2180 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2180 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2181 status(
2181 status(
2182 ui,
2182 ui,
2183 repo,
2183 repo,
2184 modified=True,
2184 modified=True,
2185 added=True,
2185 added=True,
2186 removed=True,
2186 removed=True,
2187 deleted=True,
2187 deleted=True,
2188 unknown=True,
2188 unknown=True,
2189 subrepos=opts.get(b'subrepos'),
2189 subrepos=opts.get(b'subrepos'),
2190 )
2190 )
2191
2191
2192
2192
2193 @command(
2193 @command(
2194 b'config|showconfig|debugconfig',
2194 b'config|showconfig|debugconfig',
2195 [
2195 [
2196 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2196 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2197 # This is experimental because we need
2197 # This is experimental because we need
2198 # * reasonable behavior around aliases,
2198 # * reasonable behavior around aliases,
2199 # * decide if we display [debug] [experimental] and [devel] section par
2199 # * decide if we display [debug] [experimental] and [devel] section par
2200 # default
2200 # default
2201 # * some way to display "generic" config entry (the one matching
2201 # * some way to display "generic" config entry (the one matching
2202 # regexp,
2202 # regexp,
2203 # * proper display of the different value type
2203 # * proper display of the different value type
2204 # * a better way to handle <DYNAMIC> values (and variable types),
2204 # * a better way to handle <DYNAMIC> values (and variable types),
2205 # * maybe some type information ?
2205 # * maybe some type information ?
2206 (
2206 (
2207 b'',
2207 b'',
2208 b'exp-all-known',
2208 b'exp-all-known',
2209 None,
2209 None,
2210 _(b'show all known config option (EXPERIMENTAL)'),
2210 _(b'show all known config option (EXPERIMENTAL)'),
2211 ),
2211 ),
2212 (b'e', b'edit', None, _(b'edit user config')),
2212 (b'e', b'edit', None, _(b'edit user config')),
2213 (b'l', b'local', None, _(b'edit repository config')),
2213 (b'l', b'local', None, _(b'edit repository config')),
2214 (b'', b'source', None, _(b'show source of configuration value')),
2214 (b'', b'source', None, _(b'show source of configuration value')),
2215 (
2215 (
2216 b'',
2216 b'',
2217 b'shared',
2217 b'shared',
2218 None,
2218 None,
2219 _(b'edit shared source repository config (EXPERIMENTAL)'),
2219 _(b'edit shared source repository config (EXPERIMENTAL)'),
2220 ),
2220 ),
2221 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2221 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2222 (b'g', b'global', None, _(b'edit global config')),
2222 (b'g', b'global', None, _(b'edit global config')),
2223 ]
2223 ]
2224 + formatteropts,
2224 + formatteropts,
2225 _(b'[-u] [NAME]...'),
2225 _(b'[-u] [NAME]...'),
2226 helpcategory=command.CATEGORY_HELP,
2226 helpcategory=command.CATEGORY_HELP,
2227 optionalrepo=True,
2227 optionalrepo=True,
2228 intents={INTENT_READONLY},
2228 intents={INTENT_READONLY},
2229 )
2229 )
2230 def config(ui, repo, *values, **opts):
2230 def config(ui, repo, *values, **opts):
2231 """show combined config settings from all hgrc files
2231 """show combined config settings from all hgrc files
2232
2232
2233 With no arguments, print names and values of all config items.
2233 With no arguments, print names and values of all config items.
2234
2234
2235 With one argument of the form section.name, print just the value
2235 With one argument of the form section.name, print just the value
2236 of that config item.
2236 of that config item.
2237
2237
2238 With multiple arguments, print names and values of all config
2238 With multiple arguments, print names and values of all config
2239 items with matching section names or section.names.
2239 items with matching section names or section.names.
2240
2240
2241 With --edit, start an editor on the user-level config file. With
2241 With --edit, start an editor on the user-level config file. With
2242 --global, edit the system-wide config file. With --local, edit the
2242 --global, edit the system-wide config file. With --local, edit the
2243 repository-level config file.
2243 repository-level config file.
2244
2244
2245 With --source, the source (filename and line number) is printed
2245 With --source, the source (filename and line number) is printed
2246 for each config item.
2246 for each config item.
2247
2247
2248 See :hg:`help config` for more information about config files.
2248 See :hg:`help config` for more information about config files.
2249
2249
2250 .. container:: verbose
2250 .. container:: verbose
2251
2251
2252 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2252 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2253 This file is not shared across shares when in share-safe mode.
2253 This file is not shared across shares when in share-safe mode.
2254
2254
2255 Template:
2255 Template:
2256
2256
2257 The following keywords are supported. See also :hg:`help templates`.
2257 The following keywords are supported. See also :hg:`help templates`.
2258
2258
2259 :name: String. Config name.
2259 :name: String. Config name.
2260 :source: String. Filename and line number where the item is defined.
2260 :source: String. Filename and line number where the item is defined.
2261 :value: String. Config value.
2261 :value: String. Config value.
2262
2262
2263 The --shared flag can be used to edit the config file of shared source
2263 The --shared flag can be used to edit the config file of shared source
2264 repository. It only works when you have shared using the experimental
2264 repository. It only works when you have shared using the experimental
2265 share safe feature.
2265 share safe feature.
2266
2266
2267 Returns 0 on success, 1 if NAME does not exist.
2267 Returns 0 on success, 1 if NAME does not exist.
2268
2268
2269 """
2269 """
2270
2270
2271 opts = pycompat.byteskwargs(opts)
2271 opts = pycompat.byteskwargs(opts)
2272 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2272 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2273 if any(opts.get(o) for o in editopts):
2273 if any(opts.get(o) for o in editopts):
2274 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2274 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2275 if opts.get(b'local'):
2275 if opts.get(b'local'):
2276 if not repo:
2276 if not repo:
2277 raise error.InputError(
2277 raise error.InputError(
2278 _(b"can't use --local outside a repository")
2278 _(b"can't use --local outside a repository")
2279 )
2279 )
2280 paths = [repo.vfs.join(b'hgrc')]
2280 paths = [repo.vfs.join(b'hgrc')]
2281 elif opts.get(b'global'):
2281 elif opts.get(b'global'):
2282 paths = rcutil.systemrcpath()
2282 paths = rcutil.systemrcpath()
2283 elif opts.get(b'shared'):
2283 elif opts.get(b'shared'):
2284 if not repo.shared():
2284 if not repo.shared():
2285 raise error.InputError(
2285 raise error.InputError(
2286 _(b"repository is not shared; can't use --shared")
2286 _(b"repository is not shared; can't use --shared")
2287 )
2287 )
2288 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2288 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2289 raise error.InputError(
2289 raise error.InputError(
2290 _(
2290 _(
2291 b"share safe feature not enabled; "
2291 b"share safe feature not enabled; "
2292 b"unable to edit shared source repository config"
2292 b"unable to edit shared source repository config"
2293 )
2293 )
2294 )
2294 )
2295 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2295 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2296 elif opts.get(b'non_shared'):
2296 elif opts.get(b'non_shared'):
2297 paths = [repo.vfs.join(b'hgrc-not-shared')]
2297 paths = [repo.vfs.join(b'hgrc-not-shared')]
2298 else:
2298 else:
2299 paths = rcutil.userrcpath()
2299 paths = rcutil.userrcpath()
2300
2300
2301 for f in paths:
2301 for f in paths:
2302 if os.path.exists(f):
2302 if os.path.exists(f):
2303 break
2303 break
2304 else:
2304 else:
2305 if opts.get(b'global'):
2305 if opts.get(b'global'):
2306 samplehgrc = uimod.samplehgrcs[b'global']
2306 samplehgrc = uimod.samplehgrcs[b'global']
2307 elif opts.get(b'local'):
2307 elif opts.get(b'local'):
2308 samplehgrc = uimod.samplehgrcs[b'local']
2308 samplehgrc = uimod.samplehgrcs[b'local']
2309 else:
2309 else:
2310 samplehgrc = uimod.samplehgrcs[b'user']
2310 samplehgrc = uimod.samplehgrcs[b'user']
2311
2311
2312 f = paths[0]
2312 f = paths[0]
2313 fp = open(f, b"wb")
2313 fp = open(f, b"wb")
2314 fp.write(util.tonativeeol(samplehgrc))
2314 fp.write(util.tonativeeol(samplehgrc))
2315 fp.close()
2315 fp.close()
2316
2316
2317 editor = ui.geteditor()
2317 editor = ui.geteditor()
2318 ui.system(
2318 ui.system(
2319 b"%s \"%s\"" % (editor, f),
2319 b"%s \"%s\"" % (editor, f),
2320 onerr=error.InputError,
2320 onerr=error.InputError,
2321 errprefix=_(b"edit failed"),
2321 errprefix=_(b"edit failed"),
2322 blockedtag=b'config_edit',
2322 blockedtag=b'config_edit',
2323 )
2323 )
2324 return
2324 return
2325 ui.pager(b'config')
2325 ui.pager(b'config')
2326 fm = ui.formatter(b'config', opts)
2326 fm = ui.formatter(b'config', opts)
2327 for t, f in rcutil.rccomponents():
2327 for t, f in rcutil.rccomponents():
2328 if t == b'path':
2328 if t == b'path':
2329 ui.debug(b'read config from: %s\n' % f)
2329 ui.debug(b'read config from: %s\n' % f)
2330 elif t == b'resource':
2330 elif t == b'resource':
2331 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2331 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2332 elif t == b'items':
2332 elif t == b'items':
2333 # Don't print anything for 'items'.
2333 # Don't print anything for 'items'.
2334 pass
2334 pass
2335 else:
2335 else:
2336 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2336 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2337 untrusted = bool(opts.get(b'untrusted'))
2337 untrusted = bool(opts.get(b'untrusted'))
2338
2338
2339 selsections = selentries = []
2339 selsections = selentries = []
2340 if values:
2340 if values:
2341 selsections = [v for v in values if b'.' not in v]
2341 selsections = [v for v in values if b'.' not in v]
2342 selentries = [v for v in values if b'.' in v]
2342 selentries = [v for v in values if b'.' in v]
2343 uniquesel = len(selentries) == 1 and not selsections
2343 uniquesel = len(selentries) == 1 and not selsections
2344 selsections = set(selsections)
2344 selsections = set(selsections)
2345 selentries = set(selentries)
2345 selentries = set(selentries)
2346
2346
2347 matched = False
2347 matched = False
2348 all_known = opts[b'exp_all_known']
2348 all_known = opts[b'exp_all_known']
2349 show_source = ui.debugflag or opts.get(b'source')
2349 show_source = ui.debugflag or opts.get(b'source')
2350 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2350 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2351 for section, name, value in entries:
2351 for section, name, value in entries:
2352 source = ui.configsource(section, name, untrusted)
2352 source = ui.configsource(section, name, untrusted)
2353 value = pycompat.bytestr(value)
2353 value = pycompat.bytestr(value)
2354 defaultvalue = ui.configdefault(section, name)
2354 defaultvalue = ui.configdefault(section, name)
2355 if fm.isplain():
2355 if fm.isplain():
2356 source = source or b'none'
2356 source = source or b'none'
2357 value = value.replace(b'\n', b'\\n')
2357 value = value.replace(b'\n', b'\\n')
2358 entryname = section + b'.' + name
2358 entryname = section + b'.' + name
2359 if values and not (section in selsections or entryname in selentries):
2359 if values and not (section in selsections or entryname in selentries):
2360 continue
2360 continue
2361 fm.startitem()
2361 fm.startitem()
2362 fm.condwrite(show_source, b'source', b'%s: ', source)
2362 fm.condwrite(show_source, b'source', b'%s: ', source)
2363 if uniquesel:
2363 if uniquesel:
2364 fm.data(name=entryname)
2364 fm.data(name=entryname)
2365 fm.write(b'value', b'%s\n', value)
2365 fm.write(b'value', b'%s\n', value)
2366 else:
2366 else:
2367 fm.write(b'name value', b'%s=%s\n', entryname, value)
2367 fm.write(b'name value', b'%s=%s\n', entryname, value)
2368 if formatter.isprintable(defaultvalue):
2368 if formatter.isprintable(defaultvalue):
2369 fm.data(defaultvalue=defaultvalue)
2369 fm.data(defaultvalue=defaultvalue)
2370 elif isinstance(defaultvalue, list) and all(
2370 elif isinstance(defaultvalue, list) and all(
2371 formatter.isprintable(e) for e in defaultvalue
2371 formatter.isprintable(e) for e in defaultvalue
2372 ):
2372 ):
2373 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2373 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2374 # TODO: no idea how to process unsupported defaultvalue types
2374 # TODO: no idea how to process unsupported defaultvalue types
2375 matched = True
2375 matched = True
2376 fm.end()
2376 fm.end()
2377 if matched:
2377 if matched:
2378 return 0
2378 return 0
2379 return 1
2379 return 1
2380
2380
2381
2381
2382 @command(
2382 @command(
2383 b'continue',
2383 b'continue',
2384 dryrunopts,
2384 dryrunopts,
2385 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2385 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2386 helpbasic=True,
2386 helpbasic=True,
2387 )
2387 )
2388 def continuecmd(ui, repo, **opts):
2388 def continuecmd(ui, repo, **opts):
2389 """resumes an interrupted operation (EXPERIMENTAL)
2389 """resumes an interrupted operation (EXPERIMENTAL)
2390
2390
2391 Finishes a multistep operation like graft, histedit, rebase, merge,
2391 Finishes a multistep operation like graft, histedit, rebase, merge,
2392 and unshelve if they are in an interrupted state.
2392 and unshelve if they are in an interrupted state.
2393
2393
2394 use --dry-run/-n to dry run the command.
2394 use --dry-run/-n to dry run the command.
2395 """
2395 """
2396 dryrun = opts.get('dry_run')
2396 dryrun = opts.get('dry_run')
2397 contstate = cmdutil.getunfinishedstate(repo)
2397 contstate = cmdutil.getunfinishedstate(repo)
2398 if not contstate:
2398 if not contstate:
2399 raise error.StateError(_(b'no operation in progress'))
2399 raise error.StateError(_(b'no operation in progress'))
2400 if not contstate.continuefunc:
2400 if not contstate.continuefunc:
2401 raise error.StateError(
2401 raise error.StateError(
2402 (
2402 (
2403 _(b"%s in progress but does not support 'hg continue'")
2403 _(b"%s in progress but does not support 'hg continue'")
2404 % (contstate._opname)
2404 % (contstate._opname)
2405 ),
2405 ),
2406 hint=contstate.continuemsg(),
2406 hint=contstate.continuemsg(),
2407 )
2407 )
2408 if dryrun:
2408 if dryrun:
2409 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2409 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2410 return
2410 return
2411 return contstate.continuefunc(ui, repo)
2411 return contstate.continuefunc(ui, repo)
2412
2412
2413
2413
2414 @command(
2414 @command(
2415 b'copy|cp',
2415 b'copy|cp',
2416 [
2416 [
2417 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2417 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2418 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2418 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2419 (
2419 (
2420 b'',
2420 b'',
2421 b'at-rev',
2421 b'at-rev',
2422 b'',
2422 b'',
2423 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2423 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2424 _(b'REV'),
2424 _(b'REV'),
2425 ),
2425 ),
2426 (
2426 (
2427 b'f',
2427 b'f',
2428 b'force',
2428 b'force',
2429 None,
2429 None,
2430 _(b'forcibly copy over an existing managed file'),
2430 _(b'forcibly copy over an existing managed file'),
2431 ),
2431 ),
2432 ]
2432 ]
2433 + walkopts
2433 + walkopts
2434 + dryrunopts,
2434 + dryrunopts,
2435 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2435 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2436 helpcategory=command.CATEGORY_FILE_CONTENTS,
2436 helpcategory=command.CATEGORY_FILE_CONTENTS,
2437 )
2437 )
2438 def copy(ui, repo, *pats, **opts):
2438 def copy(ui, repo, *pats, **opts):
2439 """mark files as copied for the next commit
2439 """mark files as copied for the next commit
2440
2440
2441 Mark dest as having copies of source files. If dest is a
2441 Mark dest as having copies of source files. If dest is a
2442 directory, copies are put in that directory. If dest is a file,
2442 directory, copies are put in that directory. If dest is a file,
2443 the source must be a single file.
2443 the source must be a single file.
2444
2444
2445 By default, this command copies the contents of files as they
2445 By default, this command copies the contents of files as they
2446 exist in the working directory. If invoked with -A/--after, the
2446 exist in the working directory. If invoked with -A/--after, the
2447 operation is recorded, but no copying is performed.
2447 operation is recorded, but no copying is performed.
2448
2448
2449 To undo marking a destination file as copied, use --forget. With that
2449 To undo marking a destination file as copied, use --forget. With that
2450 option, all given (positional) arguments are unmarked as copies. The
2450 option, all given (positional) arguments are unmarked as copies. The
2451 destination file(s) will be left in place (still tracked). Note that
2451 destination file(s) will be left in place (still tracked). Note that
2452 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2452 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2453
2453
2454 This command takes effect with the next commit by default.
2454 This command takes effect with the next commit by default.
2455
2455
2456 Returns 0 on success, 1 if errors are encountered.
2456 Returns 0 on success, 1 if errors are encountered.
2457 """
2457 """
2458 opts = pycompat.byteskwargs(opts)
2458 opts = pycompat.byteskwargs(opts)
2459 with repo.wlock():
2459 with repo.wlock():
2460 return cmdutil.copy(ui, repo, pats, opts)
2460 return cmdutil.copy(ui, repo, pats, opts)
2461
2461
2462
2462
2463 @command(
2463 @command(
2464 b'debugcommands',
2464 b'debugcommands',
2465 [],
2465 [],
2466 _(b'[COMMAND]'),
2466 _(b'[COMMAND]'),
2467 helpcategory=command.CATEGORY_HELP,
2467 helpcategory=command.CATEGORY_HELP,
2468 norepo=True,
2468 norepo=True,
2469 )
2469 )
2470 def debugcommands(ui, cmd=b'', *args):
2470 def debugcommands(ui, cmd=b'', *args):
2471 """list all available commands and options"""
2471 """list all available commands and options"""
2472 for cmd, vals in sorted(table.items()):
2472 for cmd, vals in sorted(table.items()):
2473 cmd = cmd.split(b'|')[0]
2473 cmd = cmd.split(b'|')[0]
2474 opts = b', '.join([i[1] for i in vals[1]])
2474 opts = b', '.join([i[1] for i in vals[1]])
2475 ui.write(b'%s: %s\n' % (cmd, opts))
2475 ui.write(b'%s: %s\n' % (cmd, opts))
2476
2476
2477
2477
2478 @command(
2478 @command(
2479 b'debugcomplete',
2479 b'debugcomplete',
2480 [(b'o', b'options', None, _(b'show the command options'))],
2480 [(b'o', b'options', None, _(b'show the command options'))],
2481 _(b'[-o] CMD'),
2481 _(b'[-o] CMD'),
2482 helpcategory=command.CATEGORY_HELP,
2482 helpcategory=command.CATEGORY_HELP,
2483 norepo=True,
2483 norepo=True,
2484 )
2484 )
2485 def debugcomplete(ui, cmd=b'', **opts):
2485 def debugcomplete(ui, cmd=b'', **opts):
2486 """returns the completion list associated with the given command"""
2486 """returns the completion list associated with the given command"""
2487
2487
2488 if opts.get('options'):
2488 if opts.get('options'):
2489 options = []
2489 options = []
2490 otables = [globalopts]
2490 otables = [globalopts]
2491 if cmd:
2491 if cmd:
2492 aliases, entry = cmdutil.findcmd(cmd, table, False)
2492 aliases, entry = cmdutil.findcmd(cmd, table, False)
2493 otables.append(entry[1])
2493 otables.append(entry[1])
2494 for t in otables:
2494 for t in otables:
2495 for o in t:
2495 for o in t:
2496 if b"(DEPRECATED)" in o[3]:
2496 if b"(DEPRECATED)" in o[3]:
2497 continue
2497 continue
2498 if o[0]:
2498 if o[0]:
2499 options.append(b'-%s' % o[0])
2499 options.append(b'-%s' % o[0])
2500 options.append(b'--%s' % o[1])
2500 options.append(b'--%s' % o[1])
2501 ui.write(b"%s\n" % b"\n".join(options))
2501 ui.write(b"%s\n" % b"\n".join(options))
2502 return
2502 return
2503
2503
2504 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2504 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2505 if ui.verbose:
2505 if ui.verbose:
2506 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2506 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2507 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2507 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2508
2508
2509
2509
2510 @command(
2510 @command(
2511 b'diff',
2511 b'diff',
2512 [
2512 [
2513 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2513 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2514 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2514 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2515 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2515 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2516 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2516 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2517 ]
2517 ]
2518 + diffopts
2518 + diffopts
2519 + diffopts2
2519 + diffopts2
2520 + walkopts
2520 + walkopts
2521 + subrepoopts,
2521 + subrepoopts,
2522 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2522 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2523 helpcategory=command.CATEGORY_FILE_CONTENTS,
2523 helpcategory=command.CATEGORY_FILE_CONTENTS,
2524 helpbasic=True,
2524 helpbasic=True,
2525 inferrepo=True,
2525 inferrepo=True,
2526 intents={INTENT_READONLY},
2526 intents={INTENT_READONLY},
2527 )
2527 )
2528 def diff(ui, repo, *pats, **opts):
2528 def diff(ui, repo, *pats, **opts):
2529 """diff repository (or selected files)
2529 """diff repository (or selected files)
2530
2530
2531 Show differences between revisions for the specified files.
2531 Show differences between revisions for the specified files.
2532
2532
2533 Differences between files are shown using the unified diff format.
2533 Differences between files are shown using the unified diff format.
2534
2534
2535 .. note::
2535 .. note::
2536
2536
2537 :hg:`diff` may generate unexpected results for merges, as it will
2537 :hg:`diff` may generate unexpected results for merges, as it will
2538 default to comparing against the working directory's first
2538 default to comparing against the working directory's first
2539 parent changeset if no revisions are specified.
2539 parent changeset if no revisions are specified.
2540
2540
2541 By default, the working directory files are compared to its first parent. To
2541 By default, the working directory files are compared to its first parent. To
2542 see the differences from another revision, use --from. To see the difference
2542 see the differences from another revision, use --from. To see the difference
2543 to another revision, use --to. For example, :hg:`diff --from .^` will show
2543 to another revision, use --to. For example, :hg:`diff --from .^` will show
2544 the differences from the working copy's grandparent to the working copy,
2544 the differences from the working copy's grandparent to the working copy,
2545 :hg:`diff --to .` will show the diff from the working copy to its parent
2545 :hg:`diff --to .` will show the diff from the working copy to its parent
2546 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2546 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2547 show the diff between those two revisions.
2547 show the diff between those two revisions.
2548
2548
2549 Alternatively you can specify -c/--change with a revision to see the changes
2549 Alternatively you can specify -c/--change with a revision to see the changes
2550 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2550 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2551 equivalent to :hg:`diff --from 42^ --to 42`)
2551 equivalent to :hg:`diff --from 42^ --to 42`)
2552
2552
2553 Without the -a/--text option, diff will avoid generating diffs of
2553 Without the -a/--text option, diff will avoid generating diffs of
2554 files it detects as binary. With -a, diff will generate a diff
2554 files it detects as binary. With -a, diff will generate a diff
2555 anyway, probably with undesirable results.
2555 anyway, probably with undesirable results.
2556
2556
2557 Use the -g/--git option to generate diffs in the git extended diff
2557 Use the -g/--git option to generate diffs in the git extended diff
2558 format. For more information, read :hg:`help diffs`.
2558 format. For more information, read :hg:`help diffs`.
2559
2559
2560 .. container:: verbose
2560 .. container:: verbose
2561
2561
2562 Examples:
2562 Examples:
2563
2563
2564 - compare a file in the current working directory to its parent::
2564 - compare a file in the current working directory to its parent::
2565
2565
2566 hg diff foo.c
2566 hg diff foo.c
2567
2567
2568 - compare two historical versions of a directory, with rename info::
2568 - compare two historical versions of a directory, with rename info::
2569
2569
2570 hg diff --git --from 1.0 --to 1.2 lib/
2570 hg diff --git --from 1.0 --to 1.2 lib/
2571
2571
2572 - get change stats relative to the last change on some date::
2572 - get change stats relative to the last change on some date::
2573
2573
2574 hg diff --stat --from "date('may 2')"
2574 hg diff --stat --from "date('may 2')"
2575
2575
2576 - diff all newly-added files that contain a keyword::
2576 - diff all newly-added files that contain a keyword::
2577
2577
2578 hg diff "set:added() and grep(GNU)"
2578 hg diff "set:added() and grep(GNU)"
2579
2579
2580 - compare a revision and its parents::
2580 - compare a revision and its parents::
2581
2581
2582 hg diff -c 9353 # compare against first parent
2582 hg diff -c 9353 # compare against first parent
2583 hg diff --from 9353^ --to 9353 # same using revset syntax
2583 hg diff --from 9353^ --to 9353 # same using revset syntax
2584 hg diff --from 9353^2 --to 9353 # compare against the second parent
2584 hg diff --from 9353^2 --to 9353 # compare against the second parent
2585
2585
2586 Returns 0 on success.
2586 Returns 0 on success.
2587 """
2587 """
2588
2588
2589 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2589 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2590 opts = pycompat.byteskwargs(opts)
2590 opts = pycompat.byteskwargs(opts)
2591 revs = opts.get(b'rev')
2591 revs = opts.get(b'rev')
2592 change = opts.get(b'change')
2592 change = opts.get(b'change')
2593 from_rev = opts.get(b'from')
2593 from_rev = opts.get(b'from')
2594 to_rev = opts.get(b'to')
2594 to_rev = opts.get(b'to')
2595 stat = opts.get(b'stat')
2595 stat = opts.get(b'stat')
2596 reverse = opts.get(b'reverse')
2596 reverse = opts.get(b'reverse')
2597
2597
2598 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2598 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2599 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2599 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2600 if change:
2600 if change:
2601 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2601 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2602 ctx2 = logcmdutil.revsingle(repo, change, None)
2602 ctx2 = logcmdutil.revsingle(repo, change, None)
2603 ctx1 = logcmdutil.diff_parent(ctx2)
2603 ctx1 = logcmdutil.diff_parent(ctx2)
2604 elif from_rev or to_rev:
2604 elif from_rev or to_rev:
2605 repo = scmutil.unhidehashlikerevs(
2605 repo = scmutil.unhidehashlikerevs(
2606 repo, [from_rev] + [to_rev], b'nowarn'
2606 repo, [from_rev] + [to_rev], b'nowarn'
2607 )
2607 )
2608 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2608 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2609 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2609 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2610 else:
2610 else:
2611 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2611 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2612 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2612 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2613
2613
2614 if reverse:
2614 if reverse:
2615 ctxleft = ctx2
2615 ctxleft = ctx2
2616 ctxright = ctx1
2616 ctxright = ctx1
2617 else:
2617 else:
2618 ctxleft = ctx1
2618 ctxleft = ctx1
2619 ctxright = ctx2
2619 ctxright = ctx2
2620
2620
2621 diffopts = patch.diffallopts(ui, opts)
2621 diffopts = patch.diffallopts(ui, opts)
2622 m = scmutil.match(ctx2, pats, opts)
2622 m = scmutil.match(ctx2, pats, opts)
2623 m = repo.narrowmatch(m)
2623 m = repo.narrowmatch(m)
2624 ui.pager(b'diff')
2624 ui.pager(b'diff')
2625 logcmdutil.diffordiffstat(
2625 logcmdutil.diffordiffstat(
2626 ui,
2626 ui,
2627 repo,
2627 repo,
2628 diffopts,
2628 diffopts,
2629 ctxleft,
2629 ctxleft,
2630 ctxright,
2630 ctxright,
2631 m,
2631 m,
2632 stat=stat,
2632 stat=stat,
2633 listsubrepos=opts.get(b'subrepos'),
2633 listsubrepos=opts.get(b'subrepos'),
2634 root=opts.get(b'root'),
2634 root=opts.get(b'root'),
2635 )
2635 )
2636
2636
2637
2637
2638 @command(
2638 @command(
2639 b'export',
2639 b'export',
2640 [
2640 [
2641 (
2641 (
2642 b'B',
2642 b'B',
2643 b'bookmark',
2643 b'bookmark',
2644 b'',
2644 b'',
2645 _(b'export changes only reachable by given bookmark'),
2645 _(b'export changes only reachable by given bookmark'),
2646 _(b'BOOKMARK'),
2646 _(b'BOOKMARK'),
2647 ),
2647 ),
2648 (
2648 (
2649 b'o',
2649 b'o',
2650 b'output',
2650 b'output',
2651 b'',
2651 b'',
2652 _(b'print output to file with formatted name'),
2652 _(b'print output to file with formatted name'),
2653 _(b'FORMAT'),
2653 _(b'FORMAT'),
2654 ),
2654 ),
2655 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2655 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2656 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2656 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2657 ]
2657 ]
2658 + diffopts
2658 + diffopts
2659 + formatteropts,
2659 + formatteropts,
2660 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2660 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2661 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2661 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2662 helpbasic=True,
2662 helpbasic=True,
2663 intents={INTENT_READONLY},
2663 intents={INTENT_READONLY},
2664 )
2664 )
2665 def export(ui, repo, *changesets, **opts):
2665 def export(ui, repo, *changesets, **opts):
2666 """dump the header and diffs for one or more changesets
2666 """dump the header and diffs for one or more changesets
2667
2667
2668 Print the changeset header and diffs for one or more revisions.
2668 Print the changeset header and diffs for one or more revisions.
2669 If no revision is given, the parent of the working directory is used.
2669 If no revision is given, the parent of the working directory is used.
2670
2670
2671 The information shown in the changeset header is: author, date,
2671 The information shown in the changeset header is: author, date,
2672 branch name (if non-default), changeset hash, parent(s) and commit
2672 branch name (if non-default), changeset hash, parent(s) and commit
2673 comment.
2673 comment.
2674
2674
2675 .. note::
2675 .. note::
2676
2676
2677 :hg:`export` may generate unexpected diff output for merge
2677 :hg:`export` may generate unexpected diff output for merge
2678 changesets, as it will compare the merge changeset against its
2678 changesets, as it will compare the merge changeset against its
2679 first parent only.
2679 first parent only.
2680
2680
2681 Output may be to a file, in which case the name of the file is
2681 Output may be to a file, in which case the name of the file is
2682 given using a template string. See :hg:`help templates`. In addition
2682 given using a template string. See :hg:`help templates`. In addition
2683 to the common template keywords, the following formatting rules are
2683 to the common template keywords, the following formatting rules are
2684 supported:
2684 supported:
2685
2685
2686 :``%%``: literal "%" character
2686 :``%%``: literal "%" character
2687 :``%H``: changeset hash (40 hexadecimal digits)
2687 :``%H``: changeset hash (40 hexadecimal digits)
2688 :``%N``: number of patches being generated
2688 :``%N``: number of patches being generated
2689 :``%R``: changeset revision number
2689 :``%R``: changeset revision number
2690 :``%b``: basename of the exporting repository
2690 :``%b``: basename of the exporting repository
2691 :``%h``: short-form changeset hash (12 hexadecimal digits)
2691 :``%h``: short-form changeset hash (12 hexadecimal digits)
2692 :``%m``: first line of the commit message (only alphanumeric characters)
2692 :``%m``: first line of the commit message (only alphanumeric characters)
2693 :``%n``: zero-padded sequence number, starting at 1
2693 :``%n``: zero-padded sequence number, starting at 1
2694 :``%r``: zero-padded changeset revision number
2694 :``%r``: zero-padded changeset revision number
2695 :``\\``: literal "\\" character
2695 :``\\``: literal "\\" character
2696
2696
2697 Without the -a/--text option, export will avoid generating diffs
2697 Without the -a/--text option, export will avoid generating diffs
2698 of files it detects as binary. With -a, export will generate a
2698 of files it detects as binary. With -a, export will generate a
2699 diff anyway, probably with undesirable results.
2699 diff anyway, probably with undesirable results.
2700
2700
2701 With -B/--bookmark changesets reachable by the given bookmark are
2701 With -B/--bookmark changesets reachable by the given bookmark are
2702 selected.
2702 selected.
2703
2703
2704 Use the -g/--git option to generate diffs in the git extended diff
2704 Use the -g/--git option to generate diffs in the git extended diff
2705 format. See :hg:`help diffs` for more information.
2705 format. See :hg:`help diffs` for more information.
2706
2706
2707 With the --switch-parent option, the diff will be against the
2707 With the --switch-parent option, the diff will be against the
2708 second parent. It can be useful to review a merge.
2708 second parent. It can be useful to review a merge.
2709
2709
2710 .. container:: verbose
2710 .. container:: verbose
2711
2711
2712 Template:
2712 Template:
2713
2713
2714 The following keywords are supported in addition to the common template
2714 The following keywords are supported in addition to the common template
2715 keywords and functions. See also :hg:`help templates`.
2715 keywords and functions. See also :hg:`help templates`.
2716
2716
2717 :diff: String. Diff content.
2717 :diff: String. Diff content.
2718 :parents: List of strings. Parent nodes of the changeset.
2718 :parents: List of strings. Parent nodes of the changeset.
2719
2719
2720 Examples:
2720 Examples:
2721
2721
2722 - use export and import to transplant a bugfix to the current
2722 - use export and import to transplant a bugfix to the current
2723 branch::
2723 branch::
2724
2724
2725 hg export -r 9353 | hg import -
2725 hg export -r 9353 | hg import -
2726
2726
2727 - export all the changesets between two revisions to a file with
2727 - export all the changesets between two revisions to a file with
2728 rename information::
2728 rename information::
2729
2729
2730 hg export --git -r 123:150 > changes.txt
2730 hg export --git -r 123:150 > changes.txt
2731
2731
2732 - split outgoing changes into a series of patches with
2732 - split outgoing changes into a series of patches with
2733 descriptive names::
2733 descriptive names::
2734
2734
2735 hg export -r "outgoing()" -o "%n-%m.patch"
2735 hg export -r "outgoing()" -o "%n-%m.patch"
2736
2736
2737 Returns 0 on success.
2737 Returns 0 on success.
2738 """
2738 """
2739 opts = pycompat.byteskwargs(opts)
2739 opts = pycompat.byteskwargs(opts)
2740 bookmark = opts.get(b'bookmark')
2740 bookmark = opts.get(b'bookmark')
2741 changesets += tuple(opts.get(b'rev', []))
2741 changesets += tuple(opts.get(b'rev', []))
2742
2742
2743 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2743 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2744
2744
2745 if bookmark:
2745 if bookmark:
2746 if bookmark not in repo._bookmarks:
2746 if bookmark not in repo._bookmarks:
2747 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2747 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2748
2748
2749 revs = scmutil.bookmarkrevs(repo, bookmark)
2749 revs = scmutil.bookmarkrevs(repo, bookmark)
2750 else:
2750 else:
2751 if not changesets:
2751 if not changesets:
2752 changesets = [b'.']
2752 changesets = [b'.']
2753
2753
2754 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2754 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2755 revs = logcmdutil.revrange(repo, changesets)
2755 revs = logcmdutil.revrange(repo, changesets)
2756
2756
2757 if not revs:
2757 if not revs:
2758 raise error.InputError(_(b"export requires at least one changeset"))
2758 raise error.InputError(_(b"export requires at least one changeset"))
2759 if len(revs) > 1:
2759 if len(revs) > 1:
2760 ui.note(_(b'exporting patches:\n'))
2760 ui.note(_(b'exporting patches:\n'))
2761 else:
2761 else:
2762 ui.note(_(b'exporting patch:\n'))
2762 ui.note(_(b'exporting patch:\n'))
2763
2763
2764 fntemplate = opts.get(b'output')
2764 fntemplate = opts.get(b'output')
2765 if cmdutil.isstdiofilename(fntemplate):
2765 if cmdutil.isstdiofilename(fntemplate):
2766 fntemplate = b''
2766 fntemplate = b''
2767
2767
2768 if fntemplate:
2768 if fntemplate:
2769 fm = formatter.nullformatter(ui, b'export', opts)
2769 fm = formatter.nullformatter(ui, b'export', opts)
2770 else:
2770 else:
2771 ui.pager(b'export')
2771 ui.pager(b'export')
2772 fm = ui.formatter(b'export', opts)
2772 fm = ui.formatter(b'export', opts)
2773 with fm:
2773 with fm:
2774 cmdutil.export(
2774 cmdutil.export(
2775 repo,
2775 repo,
2776 revs,
2776 revs,
2777 fm,
2777 fm,
2778 fntemplate=fntemplate,
2778 fntemplate=fntemplate,
2779 switch_parent=opts.get(b'switch_parent'),
2779 switch_parent=opts.get(b'switch_parent'),
2780 opts=patch.diffallopts(ui, opts),
2780 opts=patch.diffallopts(ui, opts),
2781 )
2781 )
2782
2782
2783
2783
2784 @command(
2784 @command(
2785 b'files',
2785 b'files',
2786 [
2786 [
2787 (
2787 (
2788 b'r',
2788 b'r',
2789 b'rev',
2789 b'rev',
2790 b'',
2790 b'',
2791 _(b'search the repository as it is in REV'),
2791 _(b'search the repository as it is in REV'),
2792 _(b'REV'),
2792 _(b'REV'),
2793 ),
2793 ),
2794 (
2794 (
2795 b'0',
2795 b'0',
2796 b'print0',
2796 b'print0',
2797 None,
2797 None,
2798 _(b'end filenames with NUL, for use with xargs'),
2798 _(b'end filenames with NUL, for use with xargs'),
2799 ),
2799 ),
2800 ]
2800 ]
2801 + walkopts
2801 + walkopts
2802 + formatteropts
2802 + formatteropts
2803 + subrepoopts,
2803 + subrepoopts,
2804 _(b'[OPTION]... [FILE]...'),
2804 _(b'[OPTION]... [FILE]...'),
2805 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2805 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2806 intents={INTENT_READONLY},
2806 intents={INTENT_READONLY},
2807 )
2807 )
2808 def files(ui, repo, *pats, **opts):
2808 def files(ui, repo, *pats, **opts):
2809 """list tracked files
2809 """list tracked files
2810
2810
2811 Print files under Mercurial control in the working directory or
2811 Print files under Mercurial control in the working directory or
2812 specified revision for given files (excluding removed files).
2812 specified revision for given files (excluding removed files).
2813 Files can be specified as filenames or filesets.
2813 Files can be specified as filenames or filesets.
2814
2814
2815 If no files are given to match, this command prints the names
2815 If no files are given to match, this command prints the names
2816 of all files under Mercurial control.
2816 of all files under Mercurial control.
2817
2817
2818 .. container:: verbose
2818 .. container:: verbose
2819
2819
2820 Template:
2820 Template:
2821
2821
2822 The following keywords are supported in addition to the common template
2822 The following keywords are supported in addition to the common template
2823 keywords and functions. See also :hg:`help templates`.
2823 keywords and functions. See also :hg:`help templates`.
2824
2824
2825 :flags: String. Character denoting file's symlink and executable bits.
2825 :flags: String. Character denoting file's symlink and executable bits.
2826 :path: String. Repository-absolute path of the file.
2826 :path: String. Repository-absolute path of the file.
2827 :size: Integer. Size of the file in bytes.
2827 :size: Integer. Size of the file in bytes.
2828
2828
2829 Examples:
2829 Examples:
2830
2830
2831 - list all files under the current directory::
2831 - list all files under the current directory::
2832
2832
2833 hg files .
2833 hg files .
2834
2834
2835 - shows sizes and flags for current revision::
2835 - shows sizes and flags for current revision::
2836
2836
2837 hg files -vr .
2837 hg files -vr .
2838
2838
2839 - list all files named README::
2839 - list all files named README::
2840
2840
2841 hg files -I "**/README"
2841 hg files -I "**/README"
2842
2842
2843 - list all binary files::
2843 - list all binary files::
2844
2844
2845 hg files "set:binary()"
2845 hg files "set:binary()"
2846
2846
2847 - find files containing a regular expression::
2847 - find files containing a regular expression::
2848
2848
2849 hg files "set:grep('bob')"
2849 hg files "set:grep('bob')"
2850
2850
2851 - search tracked file contents with xargs and grep::
2851 - search tracked file contents with xargs and grep::
2852
2852
2853 hg files -0 | xargs -0 grep foo
2853 hg files -0 | xargs -0 grep foo
2854
2854
2855 See :hg:`help patterns` and :hg:`help filesets` for more information
2855 See :hg:`help patterns` and :hg:`help filesets` for more information
2856 on specifying file patterns.
2856 on specifying file patterns.
2857
2857
2858 Returns 0 if a match is found, 1 otherwise.
2858 Returns 0 if a match is found, 1 otherwise.
2859
2859
2860 """
2860 """
2861
2861
2862 opts = pycompat.byteskwargs(opts)
2862 opts = pycompat.byteskwargs(opts)
2863 rev = opts.get(b'rev')
2863 rev = opts.get(b'rev')
2864 if rev:
2864 if rev:
2865 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2865 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2866 ctx = logcmdutil.revsingle(repo, rev, None)
2866 ctx = logcmdutil.revsingle(repo, rev, None)
2867
2867
2868 end = b'\n'
2868 end = b'\n'
2869 if opts.get(b'print0'):
2869 if opts.get(b'print0'):
2870 end = b'\0'
2870 end = b'\0'
2871 fmt = b'%s' + end
2871 fmt = b'%s' + end
2872
2872
2873 m = scmutil.match(ctx, pats, opts)
2873 m = scmutil.match(ctx, pats, opts)
2874 ui.pager(b'files')
2874 ui.pager(b'files')
2875 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2875 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2876 with ui.formatter(b'files', opts) as fm:
2876 with ui.formatter(b'files', opts) as fm:
2877 return cmdutil.files(
2877 return cmdutil.files(
2878 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2878 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2879 )
2879 )
2880
2880
2881
2881
2882 @command(
2882 @command(
2883 b'forget',
2883 b'forget',
2884 [
2884 [
2885 (b'i', b'interactive', None, _(b'use interactive mode')),
2885 (b'i', b'interactive', None, _(b'use interactive mode')),
2886 ]
2886 ]
2887 + walkopts
2887 + walkopts
2888 + dryrunopts,
2888 + dryrunopts,
2889 _(b'[OPTION]... FILE...'),
2889 _(b'[OPTION]... FILE...'),
2890 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2890 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2891 helpbasic=True,
2891 helpbasic=True,
2892 inferrepo=True,
2892 inferrepo=True,
2893 )
2893 )
2894 def forget(ui, repo, *pats, **opts):
2894 def forget(ui, repo, *pats, **opts):
2895 """forget the specified files on the next commit
2895 """forget the specified files on the next commit
2896
2896
2897 Mark the specified files so they will no longer be tracked
2897 Mark the specified files so they will no longer be tracked
2898 after the next commit.
2898 after the next commit.
2899
2899
2900 This only removes files from the current branch, not from the
2900 This only removes files from the current branch, not from the
2901 entire project history, and it does not delete them from the
2901 entire project history, and it does not delete them from the
2902 working directory.
2902 working directory.
2903
2903
2904 To delete the file from the working directory, see :hg:`remove`.
2904 To delete the file from the working directory, see :hg:`remove`.
2905
2905
2906 To undo a forget before the next commit, see :hg:`add`.
2906 To undo a forget before the next commit, see :hg:`add`.
2907
2907
2908 .. container:: verbose
2908 .. container:: verbose
2909
2909
2910 Examples:
2910 Examples:
2911
2911
2912 - forget newly-added binary files::
2912 - forget newly-added binary files::
2913
2913
2914 hg forget "set:added() and binary()"
2914 hg forget "set:added() and binary()"
2915
2915
2916 - forget files that would be excluded by .hgignore::
2916 - forget files that would be excluded by .hgignore::
2917
2917
2918 hg forget "set:hgignore()"
2918 hg forget "set:hgignore()"
2919
2919
2920 Returns 0 on success.
2920 Returns 0 on success.
2921 """
2921 """
2922
2922
2923 opts = pycompat.byteskwargs(opts)
2923 opts = pycompat.byteskwargs(opts)
2924 if not pats:
2924 if not pats:
2925 raise error.InputError(_(b'no files specified'))
2925 raise error.InputError(_(b'no files specified'))
2926
2926
2927 m = scmutil.match(repo[None], pats, opts)
2927 m = scmutil.match(repo[None], pats, opts)
2928 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2928 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2929 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2929 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2930 rejected = cmdutil.forget(
2930 rejected = cmdutil.forget(
2931 ui,
2931 ui,
2932 repo,
2932 repo,
2933 m,
2933 m,
2934 prefix=b"",
2934 prefix=b"",
2935 uipathfn=uipathfn,
2935 uipathfn=uipathfn,
2936 explicitonly=False,
2936 explicitonly=False,
2937 dryrun=dryrun,
2937 dryrun=dryrun,
2938 interactive=interactive,
2938 interactive=interactive,
2939 )[0]
2939 )[0]
2940 return rejected and 1 or 0
2940 return rejected and 1 or 0
2941
2941
2942
2942
2943 @command(
2943 @command(
2944 b'graft',
2944 b'graft',
2945 [
2945 [
2946 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2946 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2947 (
2947 (
2948 b'',
2948 b'',
2949 b'base',
2949 b'base',
2950 b'',
2950 b'',
2951 _(b'base revision when doing the graft merge (ADVANCED)'),
2951 _(b'base revision when doing the graft merge (ADVANCED)'),
2952 _(b'REV'),
2952 _(b'REV'),
2953 ),
2953 ),
2954 (b'c', b'continue', False, _(b'resume interrupted graft')),
2954 (b'c', b'continue', False, _(b'resume interrupted graft')),
2955 (b'', b'stop', False, _(b'stop interrupted graft')),
2955 (b'', b'stop', False, _(b'stop interrupted graft')),
2956 (b'', b'abort', False, _(b'abort interrupted graft')),
2956 (b'', b'abort', False, _(b'abort interrupted graft')),
2957 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2957 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2958 (b'', b'log', None, _(b'append graft info to log message')),
2958 (b'', b'log', None, _(b'append graft info to log message')),
2959 (
2959 (
2960 b'',
2960 b'',
2961 b'no-commit',
2961 b'no-commit',
2962 None,
2962 None,
2963 _(b"don't commit, just apply the changes in working directory"),
2963 _(b"don't commit, just apply the changes in working directory"),
2964 ),
2964 ),
2965 (b'f', b'force', False, _(b'force graft')),
2965 (b'f', b'force', False, _(b'force graft')),
2966 (
2966 (
2967 b'D',
2967 b'D',
2968 b'currentdate',
2968 b'currentdate',
2969 False,
2969 False,
2970 _(b'record the current date as commit date'),
2970 _(b'record the current date as commit date'),
2971 ),
2971 ),
2972 (
2972 (
2973 b'U',
2973 b'U',
2974 b'currentuser',
2974 b'currentuser',
2975 False,
2975 False,
2976 _(b'record the current user as committer'),
2976 _(b'record the current user as committer'),
2977 ),
2977 ),
2978 ]
2978 ]
2979 + commitopts2
2979 + commitopts2
2980 + mergetoolopts
2980 + mergetoolopts
2981 + dryrunopts,
2981 + dryrunopts,
2982 _(b'[OPTION]... [-r REV]... REV...'),
2982 _(b'[OPTION]... [-r REV]... REV...'),
2983 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2983 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2984 )
2984 )
2985 def graft(ui, repo, *revs, **opts):
2985 def graft(ui, repo, *revs, **opts):
2986 """copy changes from other branches onto the current branch
2986 """copy changes from other branches onto the current branch
2987
2987
2988 This command uses Mercurial's merge logic to copy individual
2988 This command uses Mercurial's merge logic to copy individual
2989 changes from other branches without merging branches in the
2989 changes from other branches without merging branches in the
2990 history graph. This is sometimes known as 'backporting' or
2990 history graph. This is sometimes known as 'backporting' or
2991 'cherry-picking'. By default, graft will copy user, date, and
2991 'cherry-picking'. By default, graft will copy user, date, and
2992 description from the source changesets.
2992 description from the source changesets.
2993
2993
2994 Changesets that are ancestors of the current revision, that have
2994 Changesets that are ancestors of the current revision, that have
2995 already been grafted, or that are merges will be skipped.
2995 already been grafted, or that are merges will be skipped.
2996
2996
2997 If --log is specified, log messages will have a comment appended
2997 If --log is specified, log messages will have a comment appended
2998 of the form::
2998 of the form::
2999
2999
3000 (grafted from CHANGESETHASH)
3000 (grafted from CHANGESETHASH)
3001
3001
3002 If --force is specified, revisions will be grafted even if they
3002 If --force is specified, revisions will be grafted even if they
3003 are already ancestors of, or have been grafted to, the destination.
3003 are already ancestors of, or have been grafted to, the destination.
3004 This is useful when the revisions have since been backed out.
3004 This is useful when the revisions have since been backed out.
3005
3005
3006 If a graft merge results in conflicts, the graft process is
3006 If a graft merge results in conflicts, the graft process is
3007 interrupted so that the current merge can be manually resolved.
3007 interrupted so that the current merge can be manually resolved.
3008 Once all conflicts are addressed, the graft process can be
3008 Once all conflicts are addressed, the graft process can be
3009 continued with the -c/--continue option.
3009 continued with the -c/--continue option.
3010
3010
3011 The -c/--continue option reapplies all the earlier options.
3011 The -c/--continue option reapplies all the earlier options.
3012
3012
3013 .. container:: verbose
3013 .. container:: verbose
3014
3014
3015 The --base option exposes more of how graft internally uses merge with a
3015 The --base option exposes more of how graft internally uses merge with a
3016 custom base revision. --base can be used to specify another ancestor than
3016 custom base revision. --base can be used to specify another ancestor than
3017 the first and only parent.
3017 the first and only parent.
3018
3018
3019 The command::
3019 The command::
3020
3020
3021 hg graft -r 345 --base 234
3021 hg graft -r 345 --base 234
3022
3022
3023 is thus pretty much the same as::
3023 is thus pretty much the same as::
3024
3024
3025 hg diff --from 234 --to 345 | hg import
3025 hg diff --from 234 --to 345 | hg import
3026
3026
3027 but using merge to resolve conflicts and track moved files.
3027 but using merge to resolve conflicts and track moved files.
3028
3028
3029 The result of a merge can thus be backported as a single commit by
3029 The result of a merge can thus be backported as a single commit by
3030 specifying one of the merge parents as base, and thus effectively
3030 specifying one of the merge parents as base, and thus effectively
3031 grafting the changes from the other side.
3031 grafting the changes from the other side.
3032
3032
3033 It is also possible to collapse multiple changesets and clean up history
3033 It is also possible to collapse multiple changesets and clean up history
3034 by specifying another ancestor as base, much like rebase --collapse
3034 by specifying another ancestor as base, much like rebase --collapse
3035 --keep.
3035 --keep.
3036
3036
3037 The commit message can be tweaked after the fact using commit --amend .
3037 The commit message can be tweaked after the fact using commit --amend .
3038
3038
3039 For using non-ancestors as the base to backout changes, see the backout
3039 For using non-ancestors as the base to backout changes, see the backout
3040 command and the hidden --parent option.
3040 command and the hidden --parent option.
3041
3041
3042 .. container:: verbose
3042 .. container:: verbose
3043
3043
3044 Examples:
3044 Examples:
3045
3045
3046 - copy a single change to the stable branch and edit its description::
3046 - copy a single change to the stable branch and edit its description::
3047
3047
3048 hg update stable
3048 hg update stable
3049 hg graft --edit 9393
3049 hg graft --edit 9393
3050
3050
3051 - graft a range of changesets with one exception, updating dates::
3051 - graft a range of changesets with one exception, updating dates::
3052
3052
3053 hg graft -D "2085::2093 and not 2091"
3053 hg graft -D "2085::2093 and not 2091"
3054
3054
3055 - continue a graft after resolving conflicts::
3055 - continue a graft after resolving conflicts::
3056
3056
3057 hg graft -c
3057 hg graft -c
3058
3058
3059 - show the source of a grafted changeset::
3059 - show the source of a grafted changeset::
3060
3060
3061 hg log --debug -r .
3061 hg log --debug -r .
3062
3062
3063 - show revisions sorted by date::
3063 - show revisions sorted by date::
3064
3064
3065 hg log -r "sort(all(), date)"
3065 hg log -r "sort(all(), date)"
3066
3066
3067 - backport the result of a merge as a single commit::
3067 - backport the result of a merge as a single commit::
3068
3068
3069 hg graft -r 123 --base 123^
3069 hg graft -r 123 --base 123^
3070
3070
3071 - land a feature branch as one changeset::
3071 - land a feature branch as one changeset::
3072
3072
3073 hg up -cr default
3073 hg up -cr default
3074 hg graft -r featureX --base "ancestor('featureX', 'default')"
3074 hg graft -r featureX --base "ancestor('featureX', 'default')"
3075
3075
3076 See :hg:`help revisions` for more about specifying revisions.
3076 See :hg:`help revisions` for more about specifying revisions.
3077
3077
3078 Returns 0 on successful completion, 1 if there are unresolved files.
3078 Returns 0 on successful completion, 1 if there are unresolved files.
3079 """
3079 """
3080 with repo.wlock():
3080 with repo.wlock():
3081 return _dograft(ui, repo, *revs, **opts)
3081 return _dograft(ui, repo, *revs, **opts)
3082
3082
3083
3083
3084 def _dograft(ui, repo, *revs, **opts):
3084 def _dograft(ui, repo, *revs, **opts):
3085 if revs and opts.get('rev'):
3085 if revs and opts.get('rev'):
3086 ui.warn(
3086 ui.warn(
3087 _(
3087 _(
3088 b'warning: inconsistent use of --rev might give unexpected '
3088 b'warning: inconsistent use of --rev might give unexpected '
3089 b'revision ordering!\n'
3089 b'revision ordering!\n'
3090 )
3090 )
3091 )
3091 )
3092
3092
3093 revs = list(revs)
3093 revs = list(revs)
3094 revs.extend(opts.get('rev'))
3094 revs.extend(opts.get('rev'))
3095 # a dict of data to be stored in state file
3095 # a dict of data to be stored in state file
3096 statedata = {}
3096 statedata = {}
3097 # list of new nodes created by ongoing graft
3097 # list of new nodes created by ongoing graft
3098 statedata[b'newnodes'] = []
3098 statedata[b'newnodes'] = []
3099
3099
3100 cmdutil.resolve_commit_options(ui, opts)
3100 cmdutil.resolve_commit_options(ui, opts)
3101
3101
3102 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3102 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3103
3103
3104 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3104 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3105
3105
3106 cont = False
3106 cont = False
3107 if opts.get('no_commit'):
3107 if opts.get('no_commit'):
3108 cmdutil.check_incompatible_arguments(
3108 cmdutil.check_incompatible_arguments(
3109 opts,
3109 opts,
3110 'no_commit',
3110 'no_commit',
3111 ['edit', 'currentuser', 'currentdate', 'log'],
3111 ['edit', 'currentuser', 'currentdate', 'log'],
3112 )
3112 )
3113
3113
3114 graftstate = statemod.cmdstate(repo, b'graftstate')
3114 graftstate = statemod.cmdstate(repo, b'graftstate')
3115
3115
3116 if opts.get('stop'):
3116 if opts.get('stop'):
3117 cmdutil.check_incompatible_arguments(
3117 cmdutil.check_incompatible_arguments(
3118 opts,
3118 opts,
3119 'stop',
3119 'stop',
3120 [
3120 [
3121 'edit',
3121 'edit',
3122 'log',
3122 'log',
3123 'user',
3123 'user',
3124 'date',
3124 'date',
3125 'currentdate',
3125 'currentdate',
3126 'currentuser',
3126 'currentuser',
3127 'rev',
3127 'rev',
3128 ],
3128 ],
3129 )
3129 )
3130 return _stopgraft(ui, repo, graftstate)
3130 return _stopgraft(ui, repo, graftstate)
3131 elif opts.get('abort'):
3131 elif opts.get('abort'):
3132 cmdutil.check_incompatible_arguments(
3132 cmdutil.check_incompatible_arguments(
3133 opts,
3133 opts,
3134 'abort',
3134 'abort',
3135 [
3135 [
3136 'edit',
3136 'edit',
3137 'log',
3137 'log',
3138 'user',
3138 'user',
3139 'date',
3139 'date',
3140 'currentdate',
3140 'currentdate',
3141 'currentuser',
3141 'currentuser',
3142 'rev',
3142 'rev',
3143 ],
3143 ],
3144 )
3144 )
3145 return cmdutil.abortgraft(ui, repo, graftstate)
3145 return cmdutil.abortgraft(ui, repo, graftstate)
3146 elif opts.get('continue'):
3146 elif opts.get('continue'):
3147 cont = True
3147 cont = True
3148 if revs:
3148 if revs:
3149 raise error.InputError(_(b"can't specify --continue and revisions"))
3149 raise error.InputError(_(b"can't specify --continue and revisions"))
3150 # read in unfinished revisions
3150 # read in unfinished revisions
3151 if graftstate.exists():
3151 if graftstate.exists():
3152 statedata = cmdutil.readgraftstate(repo, graftstate)
3152 statedata = cmdutil.readgraftstate(repo, graftstate)
3153 if statedata.get(b'date'):
3153 if statedata.get(b'date'):
3154 opts['date'] = statedata[b'date']
3154 opts['date'] = statedata[b'date']
3155 if statedata.get(b'user'):
3155 if statedata.get(b'user'):
3156 opts['user'] = statedata[b'user']
3156 opts['user'] = statedata[b'user']
3157 if statedata.get(b'log'):
3157 if statedata.get(b'log'):
3158 opts['log'] = True
3158 opts['log'] = True
3159 if statedata.get(b'no_commit'):
3159 if statedata.get(b'no_commit'):
3160 opts['no_commit'] = statedata.get(b'no_commit')
3160 opts['no_commit'] = statedata.get(b'no_commit')
3161 if statedata.get(b'base'):
3161 if statedata.get(b'base'):
3162 opts['base'] = statedata.get(b'base')
3162 opts['base'] = statedata.get(b'base')
3163 nodes = statedata[b'nodes']
3163 nodes = statedata[b'nodes']
3164 revs = [repo[node].rev() for node in nodes]
3164 revs = [repo[node].rev() for node in nodes]
3165 else:
3165 else:
3166 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3166 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3167 else:
3167 else:
3168 if not revs:
3168 if not revs:
3169 raise error.InputError(_(b'no revisions specified'))
3169 raise error.InputError(_(b'no revisions specified'))
3170 cmdutil.checkunfinished(repo)
3170 cmdutil.checkunfinished(repo)
3171 cmdutil.bailifchanged(repo)
3171 cmdutil.bailifchanged(repo)
3172 revs = logcmdutil.revrange(repo, revs)
3172 revs = logcmdutil.revrange(repo, revs)
3173
3173
3174 skipped = set()
3174 skipped = set()
3175 basectx = None
3175 basectx = None
3176 if opts.get('base'):
3176 if opts.get('base'):
3177 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3177 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3178 if basectx is None:
3178 if basectx is None:
3179 # check for merges
3179 # check for merges
3180 for rev in repo.revs(b'%ld and merge()', revs):
3180 for rev in repo.revs(b'%ld and merge()', revs):
3181 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3181 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3182 skipped.add(rev)
3182 skipped.add(rev)
3183 revs = [r for r in revs if r not in skipped]
3183 revs = [r for r in revs if r not in skipped]
3184 if not revs:
3184 if not revs:
3185 return -1
3185 return -1
3186 if basectx is not None and len(revs) != 1:
3186 if basectx is not None and len(revs) != 1:
3187 raise error.InputError(_(b'only one revision allowed with --base '))
3187 raise error.InputError(_(b'only one revision allowed with --base '))
3188
3188
3189 # Don't check in the --continue case, in effect retaining --force across
3189 # Don't check in the --continue case, in effect retaining --force across
3190 # --continues. That's because without --force, any revisions we decided to
3190 # --continues. That's because without --force, any revisions we decided to
3191 # skip would have been filtered out here, so they wouldn't have made their
3191 # skip would have been filtered out here, so they wouldn't have made their
3192 # way to the graftstate. With --force, any revisions we would have otherwise
3192 # way to the graftstate. With --force, any revisions we would have otherwise
3193 # skipped would not have been filtered out, and if they hadn't been applied
3193 # skipped would not have been filtered out, and if they hadn't been applied
3194 # already, they'd have been in the graftstate.
3194 # already, they'd have been in the graftstate.
3195 if not (cont or opts.get('force')) and basectx is None:
3195 if not (cont or opts.get('force')) and basectx is None:
3196 # check for ancestors of dest branch
3196 # check for ancestors of dest branch
3197 ancestors = repo.revs(b'%ld & (::.)', revs)
3197 ancestors = repo.revs(b'%ld & (::.)', revs)
3198 for rev in ancestors:
3198 for rev in ancestors:
3199 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3199 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3200
3200
3201 revs = [r for r in revs if r not in ancestors]
3201 revs = [r for r in revs if r not in ancestors]
3202
3202
3203 if not revs:
3203 if not revs:
3204 return -1
3204 return -1
3205
3205
3206 # analyze revs for earlier grafts
3206 # analyze revs for earlier grafts
3207 ids = {}
3207 ids = {}
3208 for ctx in repo.set(b"%ld", revs):
3208 for ctx in repo.set(b"%ld", revs):
3209 ids[ctx.hex()] = ctx.rev()
3209 ids[ctx.hex()] = ctx.rev()
3210 n = ctx.extra().get(b'source')
3210 n = ctx.extra().get(b'source')
3211 if n:
3211 if n:
3212 ids[n] = ctx.rev()
3212 ids[n] = ctx.rev()
3213
3213
3214 # check ancestors for earlier grafts
3214 # check ancestors for earlier grafts
3215 ui.debug(b'scanning for duplicate grafts\n')
3215 ui.debug(b'scanning for duplicate grafts\n')
3216
3216
3217 # The only changesets we can be sure doesn't contain grafts of any
3217 # The only changesets we can be sure doesn't contain grafts of any
3218 # revs, are the ones that are common ancestors of *all* revs:
3218 # revs, are the ones that are common ancestors of *all* revs:
3219 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3219 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3220 ctx = repo[rev]
3220 ctx = repo[rev]
3221 n = ctx.extra().get(b'source')
3221 n = ctx.extra().get(b'source')
3222 if n in ids:
3222 if n in ids:
3223 try:
3223 try:
3224 r = repo[n].rev()
3224 r = repo[n].rev()
3225 except error.RepoLookupError:
3225 except error.RepoLookupError:
3226 r = None
3226 r = None
3227 if r in revs:
3227 if r in revs:
3228 ui.warn(
3228 ui.warn(
3229 _(
3229 _(
3230 b'skipping revision %d:%s '
3230 b'skipping revision %d:%s '
3231 b'(already grafted to %d:%s)\n'
3231 b'(already grafted to %d:%s)\n'
3232 )
3232 )
3233 % (r, repo[r], rev, ctx)
3233 % (r, repo[r], rev, ctx)
3234 )
3234 )
3235 revs.remove(r)
3235 revs.remove(r)
3236 elif ids[n] in revs:
3236 elif ids[n] in revs:
3237 if r is None:
3237 if r is None:
3238 ui.warn(
3238 ui.warn(
3239 _(
3239 _(
3240 b'skipping already grafted revision %d:%s '
3240 b'skipping already grafted revision %d:%s '
3241 b'(%d:%s also has unknown origin %s)\n'
3241 b'(%d:%s also has unknown origin %s)\n'
3242 )
3242 )
3243 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3243 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3244 )
3244 )
3245 else:
3245 else:
3246 ui.warn(
3246 ui.warn(
3247 _(
3247 _(
3248 b'skipping already grafted revision %d:%s '
3248 b'skipping already grafted revision %d:%s '
3249 b'(%d:%s also has origin %d:%s)\n'
3249 b'(%d:%s also has origin %d:%s)\n'
3250 )
3250 )
3251 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3251 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3252 )
3252 )
3253 revs.remove(ids[n])
3253 revs.remove(ids[n])
3254 elif ctx.hex() in ids:
3254 elif ctx.hex() in ids:
3255 r = ids[ctx.hex()]
3255 r = ids[ctx.hex()]
3256 if r in revs:
3256 if r in revs:
3257 ui.warn(
3257 ui.warn(
3258 _(
3258 _(
3259 b'skipping already grafted revision %d:%s '
3259 b'skipping already grafted revision %d:%s '
3260 b'(was grafted from %d:%s)\n'
3260 b'(was grafted from %d:%s)\n'
3261 )
3261 )
3262 % (r, repo[r], rev, ctx)
3262 % (r, repo[r], rev, ctx)
3263 )
3263 )
3264 revs.remove(r)
3264 revs.remove(r)
3265 if not revs:
3265 if not revs:
3266 return -1
3266 return -1
3267
3267
3268 if opts.get('no_commit'):
3268 if opts.get('no_commit'):
3269 statedata[b'no_commit'] = True
3269 statedata[b'no_commit'] = True
3270 if opts.get('base'):
3270 if opts.get('base'):
3271 statedata[b'base'] = opts['base']
3271 statedata[b'base'] = opts['base']
3272 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3272 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3273 desc = b'%d:%s "%s"' % (
3273 desc = b'%d:%s "%s"' % (
3274 ctx.rev(),
3274 ctx.rev(),
3275 ctx,
3275 ctx,
3276 ctx.description().split(b'\n', 1)[0],
3276 ctx.description().split(b'\n', 1)[0],
3277 )
3277 )
3278 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3278 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3279 if names:
3279 if names:
3280 desc += b' (%s)' % b' '.join(names)
3280 desc += b' (%s)' % b' '.join(names)
3281 ui.status(_(b'grafting %s\n') % desc)
3281 ui.status(_(b'grafting %s\n') % desc)
3282 if opts.get('dry_run'):
3282 if opts.get('dry_run'):
3283 continue
3283 continue
3284
3284
3285 source = ctx.extra().get(b'source')
3285 source = ctx.extra().get(b'source')
3286 extra = {}
3286 extra = {}
3287 if source:
3287 if source:
3288 extra[b'source'] = source
3288 extra[b'source'] = source
3289 extra[b'intermediate-source'] = ctx.hex()
3289 extra[b'intermediate-source'] = ctx.hex()
3290 else:
3290 else:
3291 extra[b'source'] = ctx.hex()
3291 extra[b'source'] = ctx.hex()
3292 user = ctx.user()
3292 user = ctx.user()
3293 if opts.get('user'):
3293 if opts.get('user'):
3294 user = opts['user']
3294 user = opts['user']
3295 statedata[b'user'] = user
3295 statedata[b'user'] = user
3296 date = ctx.date()
3296 date = ctx.date()
3297 if opts.get('date'):
3297 if opts.get('date'):
3298 date = opts['date']
3298 date = opts['date']
3299 statedata[b'date'] = date
3299 statedata[b'date'] = date
3300 message = ctx.description()
3300 message = ctx.description()
3301 if opts.get('log'):
3301 if opts.get('log'):
3302 message += b'\n(grafted from %s)' % ctx.hex()
3302 message += b'\n(grafted from %s)' % ctx.hex()
3303 statedata[b'log'] = True
3303 statedata[b'log'] = True
3304
3304
3305 # we don't merge the first commit when continuing
3305 # we don't merge the first commit when continuing
3306 if not cont:
3306 if not cont:
3307 # perform the graft merge with p1(rev) as 'ancestor'
3307 # perform the graft merge with p1(rev) as 'ancestor'
3308 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3308 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3309 base = ctx.p1() if basectx is None else basectx
3309 base = ctx.p1() if basectx is None else basectx
3310 with ui.configoverride(overrides, b'graft'):
3310 with ui.configoverride(overrides, b'graft'):
3311 stats = mergemod.graft(
3311 stats = mergemod.graft(
3312 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3312 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3313 )
3313 )
3314 # report any conflicts
3314 # report any conflicts
3315 if stats.unresolvedcount > 0:
3315 if stats.unresolvedcount > 0:
3316 # write out state for --continue
3316 # write out state for --continue
3317 nodes = [repo[rev].hex() for rev in revs[pos:]]
3317 nodes = [repo[rev].hex() for rev in revs[pos:]]
3318 statedata[b'nodes'] = nodes
3318 statedata[b'nodes'] = nodes
3319 stateversion = 1
3319 stateversion = 1
3320 graftstate.save(stateversion, statedata)
3320 graftstate.save(stateversion, statedata)
3321 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3321 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3322 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3322 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3323 return 1
3323 return 1
3324 else:
3324 else:
3325 cont = False
3325 cont = False
3326
3326
3327 # commit if --no-commit is false
3327 # commit if --no-commit is false
3328 if not opts.get('no_commit'):
3328 if not opts.get('no_commit'):
3329 node = repo.commit(
3329 node = repo.commit(
3330 text=message, user=user, date=date, extra=extra, editor=editor
3330 text=message, user=user, date=date, extra=extra, editor=editor
3331 )
3331 )
3332 if node is None:
3332 if node is None:
3333 ui.warn(
3333 ui.warn(
3334 _(b'note: graft of %d:%s created no changes to commit\n')
3334 _(b'note: graft of %d:%s created no changes to commit\n')
3335 % (ctx.rev(), ctx)
3335 % (ctx.rev(), ctx)
3336 )
3336 )
3337 # checking that newnodes exist because old state files won't have it
3337 # checking that newnodes exist because old state files won't have it
3338 elif statedata.get(b'newnodes') is not None:
3338 elif statedata.get(b'newnodes') is not None:
3339 nn = statedata[b'newnodes']
3339 nn = statedata[b'newnodes']
3340 assert isinstance(nn, list) # list of bytes
3340 assert isinstance(nn, list) # list of bytes
3341 nn.append(node)
3341 nn.append(node)
3342
3342
3343 # remove state when we complete successfully
3343 # remove state when we complete successfully
3344 if not opts.get('dry_run'):
3344 if not opts.get('dry_run'):
3345 graftstate.delete()
3345 graftstate.delete()
3346
3346
3347 return 0
3347 return 0
3348
3348
3349
3349
3350 def _stopgraft(ui, repo, graftstate):
3350 def _stopgraft(ui, repo, graftstate):
3351 """stop the interrupted graft"""
3351 """stop the interrupted graft"""
3352 if not graftstate.exists():
3352 if not graftstate.exists():
3353 raise error.StateError(_(b"no interrupted graft found"))
3353 raise error.StateError(_(b"no interrupted graft found"))
3354 pctx = repo[b'.']
3354 pctx = repo[b'.']
3355 mergemod.clean_update(pctx)
3355 mergemod.clean_update(pctx)
3356 graftstate.delete()
3356 graftstate.delete()
3357 ui.status(_(b"stopped the interrupted graft\n"))
3357 ui.status(_(b"stopped the interrupted graft\n"))
3358 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3358 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3359 return 0
3359 return 0
3360
3360
3361
3361
3362 statemod.addunfinished(
3362 statemod.addunfinished(
3363 b'graft',
3363 b'graft',
3364 fname=b'graftstate',
3364 fname=b'graftstate',
3365 clearable=True,
3365 clearable=True,
3366 stopflag=True,
3366 stopflag=True,
3367 continueflag=True,
3367 continueflag=True,
3368 abortfunc=cmdutil.hgabortgraft,
3368 abortfunc=cmdutil.hgabortgraft,
3369 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3369 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3370 )
3370 )
3371
3371
3372
3372
3373 @command(
3373 @command(
3374 b'grep',
3374 b'grep',
3375 [
3375 [
3376 (b'0', b'print0', None, _(b'end fields with NUL')),
3376 (b'0', b'print0', None, _(b'end fields with NUL')),
3377 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3377 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3378 (
3378 (
3379 b'',
3379 b'',
3380 b'diff',
3380 b'diff',
3381 None,
3381 None,
3382 _(
3382 _(
3383 b'search revision differences for when the pattern was added '
3383 b'search revision differences for when the pattern was added '
3384 b'or removed'
3384 b'or removed'
3385 ),
3385 ),
3386 ),
3386 ),
3387 (b'a', b'text', None, _(b'treat all files as text')),
3387 (b'a', b'text', None, _(b'treat all files as text')),
3388 (
3388 (
3389 b'f',
3389 b'f',
3390 b'follow',
3390 b'follow',
3391 None,
3391 None,
3392 _(
3392 _(
3393 b'follow changeset history,'
3393 b'follow changeset history,'
3394 b' or file history across copies and renames'
3394 b' or file history across copies and renames'
3395 ),
3395 ),
3396 ),
3396 ),
3397 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3397 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3398 (
3398 (
3399 b'l',
3399 b'l',
3400 b'files-with-matches',
3400 b'files-with-matches',
3401 None,
3401 None,
3402 _(b'print only filenames and revisions that match'),
3402 _(b'print only filenames and revisions that match'),
3403 ),
3403 ),
3404 (b'n', b'line-number', None, _(b'print matching line numbers')),
3404 (b'n', b'line-number', None, _(b'print matching line numbers')),
3405 (
3405 (
3406 b'r',
3406 b'r',
3407 b'rev',
3407 b'rev',
3408 [],
3408 [],
3409 _(b'search files changed within revision range'),
3409 _(b'search files changed within revision range'),
3410 _(b'REV'),
3410 _(b'REV'),
3411 ),
3411 ),
3412 (
3412 (
3413 b'',
3413 b'',
3414 b'all-files',
3414 b'all-files',
3415 None,
3415 None,
3416 _(
3416 _(
3417 b'include all files in the changeset while grepping (DEPRECATED)'
3417 b'include all files in the changeset while grepping (DEPRECATED)'
3418 ),
3418 ),
3419 ),
3419 ),
3420 (b'u', b'user', None, _(b'list the author (long with -v)')),
3420 (b'u', b'user', None, _(b'list the author (long with -v)')),
3421 (b'd', b'date', None, _(b'list the date (short with -q)')),
3421 (b'd', b'date', None, _(b'list the date (short with -q)')),
3422 ]
3422 ]
3423 + formatteropts
3423 + formatteropts
3424 + walkopts,
3424 + walkopts,
3425 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3425 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3426 helpcategory=command.CATEGORY_FILE_CONTENTS,
3426 helpcategory=command.CATEGORY_FILE_CONTENTS,
3427 inferrepo=True,
3427 inferrepo=True,
3428 intents={INTENT_READONLY},
3428 intents={INTENT_READONLY},
3429 )
3429 )
3430 def grep(ui, repo, pattern, *pats, **opts):
3430 def grep(ui, repo, pattern, *pats, **opts):
3431 """search for a pattern in specified files
3431 """search for a pattern in specified files
3432
3432
3433 Search the working directory or revision history for a regular
3433 Search the working directory or revision history for a regular
3434 expression in the specified files for the entire repository.
3434 expression in the specified files for the entire repository.
3435
3435
3436 By default, grep searches the repository files in the working
3436 By default, grep searches the repository files in the working
3437 directory and prints the files where it finds a match. To specify
3437 directory and prints the files where it finds a match. To specify
3438 historical revisions instead of the working directory, use the
3438 historical revisions instead of the working directory, use the
3439 --rev flag.
3439 --rev flag.
3440
3440
3441 To search instead historical revision differences that contains a
3441 To search instead historical revision differences that contains a
3442 change in match status ("-" for a match that becomes a non-match,
3442 change in match status ("-" for a match that becomes a non-match,
3443 or "+" for a non-match that becomes a match), use the --diff flag.
3443 or "+" for a non-match that becomes a match), use the --diff flag.
3444
3444
3445 PATTERN can be any Python (roughly Perl-compatible) regular
3445 PATTERN can be any Python (roughly Perl-compatible) regular
3446 expression.
3446 expression.
3447
3447
3448 If no FILEs are specified and the --rev flag isn't supplied, all
3448 If no FILEs are specified and the --rev flag isn't supplied, all
3449 files in the working directory are searched. When using the --rev
3449 files in the working directory are searched. When using the --rev
3450 flag and specifying FILEs, use the --follow argument to also
3450 flag and specifying FILEs, use the --follow argument to also
3451 follow the specified FILEs across renames and copies.
3451 follow the specified FILEs across renames and copies.
3452
3452
3453 .. container:: verbose
3453 .. container:: verbose
3454
3454
3455 Template:
3455 Template:
3456
3456
3457 The following keywords are supported in addition to the common template
3457 The following keywords are supported in addition to the common template
3458 keywords and functions. See also :hg:`help templates`.
3458 keywords and functions. See also :hg:`help templates`.
3459
3459
3460 :change: String. Character denoting insertion ``+`` or removal ``-``.
3460 :change: String. Character denoting insertion ``+`` or removal ``-``.
3461 Available if ``--diff`` is specified.
3461 Available if ``--diff`` is specified.
3462 :lineno: Integer. Line number of the match.
3462 :lineno: Integer. Line number of the match.
3463 :path: String. Repository-absolute path of the file.
3463 :path: String. Repository-absolute path of the file.
3464 :texts: List of text chunks.
3464 :texts: List of text chunks.
3465
3465
3466 And each entry of ``{texts}`` provides the following sub-keywords.
3466 And each entry of ``{texts}`` provides the following sub-keywords.
3467
3467
3468 :matched: Boolean. True if the chunk matches the specified pattern.
3468 :matched: Boolean. True if the chunk matches the specified pattern.
3469 :text: String. Chunk content.
3469 :text: String. Chunk content.
3470
3470
3471 See :hg:`help templates.operators` for the list expansion syntax.
3471 See :hg:`help templates.operators` for the list expansion syntax.
3472
3472
3473 Returns 0 if a match is found, 1 otherwise.
3473 Returns 0 if a match is found, 1 otherwise.
3474
3474
3475 """
3475 """
3476 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3476 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3477 opts = pycompat.byteskwargs(opts)
3477 opts = pycompat.byteskwargs(opts)
3478 diff = opts.get(b'all') or opts.get(b'diff')
3478 diff = opts.get(b'all') or opts.get(b'diff')
3479 follow = opts.get(b'follow')
3479 follow = opts.get(b'follow')
3480 if opts.get(b'all_files') is None and not diff:
3480 if opts.get(b'all_files') is None and not diff:
3481 opts[b'all_files'] = True
3481 opts[b'all_files'] = True
3482 plaingrep = (
3482 plaingrep = (
3483 opts.get(b'all_files')
3483 opts.get(b'all_files')
3484 and not opts.get(b'rev')
3484 and not opts.get(b'rev')
3485 and not opts.get(b'follow')
3485 and not opts.get(b'follow')
3486 )
3486 )
3487 all_files = opts.get(b'all_files')
3487 all_files = opts.get(b'all_files')
3488 if plaingrep:
3488 if plaingrep:
3489 opts[b'rev'] = [b'wdir()']
3489 opts[b'rev'] = [b'wdir()']
3490
3490
3491 reflags = re.M
3491 reflags = re.M
3492 if opts.get(b'ignore_case'):
3492 if opts.get(b'ignore_case'):
3493 reflags |= re.I
3493 reflags |= re.I
3494 try:
3494 try:
3495 regexp = util.re.compile(pattern, reflags)
3495 regexp = util.re.compile(pattern, reflags)
3496 except re.error as inst:
3496 except re.error as inst:
3497 ui.warn(
3497 ui.warn(
3498 _(b"grep: invalid match pattern: %s\n")
3498 _(b"grep: invalid match pattern: %s\n")
3499 % stringutil.forcebytestr(inst)
3499 % stringutil.forcebytestr(inst)
3500 )
3500 )
3501 return 1
3501 return 1
3502 sep, eol = b':', b'\n'
3502 sep, eol = b':', b'\n'
3503 if opts.get(b'print0'):
3503 if opts.get(b'print0'):
3504 sep = eol = b'\0'
3504 sep = eol = b'\0'
3505
3505
3506 searcher = grepmod.grepsearcher(
3506 searcher = grepmod.grepsearcher(
3507 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3507 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3508 )
3508 )
3509
3509
3510 getfile = searcher._getfile
3510 getfile = searcher._getfile
3511
3511
3512 uipathfn = scmutil.getuipathfn(repo)
3512 uipathfn = scmutil.getuipathfn(repo)
3513
3513
3514 def display(fm, fn, ctx, pstates, states):
3514 def display(fm, fn, ctx, pstates, states):
3515 rev = scmutil.intrev(ctx)
3515 rev = scmutil.intrev(ctx)
3516 if fm.isplain():
3516 if fm.isplain():
3517 formatuser = ui.shortuser
3517 formatuser = ui.shortuser
3518 else:
3518 else:
3519 formatuser = pycompat.bytestr
3519 formatuser = pycompat.bytestr
3520 if ui.quiet:
3520 if ui.quiet:
3521 datefmt = b'%Y-%m-%d'
3521 datefmt = b'%Y-%m-%d'
3522 else:
3522 else:
3523 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3523 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3524 found = False
3524 found = False
3525
3525
3526 @util.cachefunc
3526 @util.cachefunc
3527 def binary():
3527 def binary():
3528 flog = getfile(fn)
3528 flog = getfile(fn)
3529 try:
3529 try:
3530 return stringutil.binary(flog.read(ctx.filenode(fn)))
3530 return stringutil.binary(flog.read(ctx.filenode(fn)))
3531 except error.WdirUnsupported:
3531 except error.WdirUnsupported:
3532 return ctx[fn].isbinary()
3532 return ctx[fn].isbinary()
3533
3533
3534 fieldnamemap = {b'linenumber': b'lineno'}
3534 fieldnamemap = {b'linenumber': b'lineno'}
3535 if diff:
3535 if diff:
3536 iter = grepmod.difflinestates(pstates, states)
3536 iter = grepmod.difflinestates(pstates, states)
3537 else:
3537 else:
3538 iter = [(b'', l) for l in states]
3538 iter = [(b'', l) for l in states]
3539 for change, l in iter:
3539 for change, l in iter:
3540 fm.startitem()
3540 fm.startitem()
3541 fm.context(ctx=ctx)
3541 fm.context(ctx=ctx)
3542 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3542 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3543 fm.plain(uipathfn(fn), label=b'grep.filename')
3543 fm.plain(uipathfn(fn), label=b'grep.filename')
3544
3544
3545 cols = [
3545 cols = [
3546 (b'rev', b'%d', rev, not plaingrep, b''),
3546 (b'rev', b'%d', rev, not plaingrep, b''),
3547 (
3547 (
3548 b'linenumber',
3548 b'linenumber',
3549 b'%d',
3549 b'%d',
3550 l.linenum,
3550 l.linenum,
3551 opts.get(b'line_number'),
3551 opts.get(b'line_number'),
3552 b'',
3552 b'',
3553 ),
3553 ),
3554 ]
3554 ]
3555 if diff:
3555 if diff:
3556 cols.append(
3556 cols.append(
3557 (
3557 (
3558 b'change',
3558 b'change',
3559 b'%s',
3559 b'%s',
3560 change,
3560 change,
3561 True,
3561 True,
3562 b'grep.inserted '
3562 b'grep.inserted '
3563 if change == b'+'
3563 if change == b'+'
3564 else b'grep.deleted ',
3564 else b'grep.deleted ',
3565 )
3565 )
3566 )
3566 )
3567 cols.extend(
3567 cols.extend(
3568 [
3568 [
3569 (
3569 (
3570 b'user',
3570 b'user',
3571 b'%s',
3571 b'%s',
3572 formatuser(ctx.user()),
3572 formatuser(ctx.user()),
3573 opts.get(b'user'),
3573 opts.get(b'user'),
3574 b'',
3574 b'',
3575 ),
3575 ),
3576 (
3576 (
3577 b'date',
3577 b'date',
3578 b'%s',
3578 b'%s',
3579 fm.formatdate(ctx.date(), datefmt),
3579 fm.formatdate(ctx.date(), datefmt),
3580 opts.get(b'date'),
3580 opts.get(b'date'),
3581 b'',
3581 b'',
3582 ),
3582 ),
3583 ]
3583 ]
3584 )
3584 )
3585 for name, fmt, data, cond, extra_label in cols:
3585 for name, fmt, data, cond, extra_label in cols:
3586 if cond:
3586 if cond:
3587 fm.plain(sep, label=b'grep.sep')
3587 fm.plain(sep, label=b'grep.sep')
3588 field = fieldnamemap.get(name, name)
3588 field = fieldnamemap.get(name, name)
3589 label = extra_label + (b'grep.%s' % name)
3589 label = extra_label + (b'grep.%s' % name)
3590 fm.condwrite(cond, field, fmt, data, label=label)
3590 fm.condwrite(cond, field, fmt, data, label=label)
3591 if not opts.get(b'files_with_matches'):
3591 if not opts.get(b'files_with_matches'):
3592 fm.plain(sep, label=b'grep.sep')
3592 fm.plain(sep, label=b'grep.sep')
3593 if not opts.get(b'text') and binary():
3593 if not opts.get(b'text') and binary():
3594 fm.plain(_(b" Binary file matches"))
3594 fm.plain(_(b" Binary file matches"))
3595 else:
3595 else:
3596 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3596 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3597 fm.plain(eol)
3597 fm.plain(eol)
3598 found = True
3598 found = True
3599 if opts.get(b'files_with_matches'):
3599 if opts.get(b'files_with_matches'):
3600 break
3600 break
3601 return found
3601 return found
3602
3602
3603 def displaymatches(fm, l):
3603 def displaymatches(fm, l):
3604 p = 0
3604 p = 0
3605 for s, e in l.findpos(regexp):
3605 for s, e in l.findpos(regexp):
3606 if p < s:
3606 if p < s:
3607 fm.startitem()
3607 fm.startitem()
3608 fm.write(b'text', b'%s', l.line[p:s])
3608 fm.write(b'text', b'%s', l.line[p:s])
3609 fm.data(matched=False)
3609 fm.data(matched=False)
3610 fm.startitem()
3610 fm.startitem()
3611 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3611 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3612 fm.data(matched=True)
3612 fm.data(matched=True)
3613 p = e
3613 p = e
3614 if p < len(l.line):
3614 if p < len(l.line):
3615 fm.startitem()
3615 fm.startitem()
3616 fm.write(b'text', b'%s', l.line[p:])
3616 fm.write(b'text', b'%s', l.line[p:])
3617 fm.data(matched=False)
3617 fm.data(matched=False)
3618 fm.end()
3618 fm.end()
3619
3619
3620 found = False
3620 found = False
3621
3621
3622 wopts = logcmdutil.walkopts(
3622 wopts = logcmdutil.walkopts(
3623 pats=pats,
3623 pats=pats,
3624 opts=opts,
3624 opts=opts,
3625 revspec=opts[b'rev'],
3625 revspec=opts[b'rev'],
3626 include_pats=opts[b'include'],
3626 include_pats=opts[b'include'],
3627 exclude_pats=opts[b'exclude'],
3627 exclude_pats=opts[b'exclude'],
3628 follow=follow,
3628 follow=follow,
3629 force_changelog_traversal=all_files,
3629 force_changelog_traversal=all_files,
3630 filter_revisions_by_pats=not all_files,
3630 filter_revisions_by_pats=not all_files,
3631 )
3631 )
3632 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3632 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3633
3633
3634 ui.pager(b'grep')
3634 ui.pager(b'grep')
3635 fm = ui.formatter(b'grep', opts)
3635 fm = ui.formatter(b'grep', opts)
3636 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3636 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3637 r = display(fm, fn, ctx, pstates, states)
3637 r = display(fm, fn, ctx, pstates, states)
3638 found = found or r
3638 found = found or r
3639 if r and not diff and not all_files:
3639 if r and not diff and not all_files:
3640 searcher.skipfile(fn, ctx.rev())
3640 searcher.skipfile(fn, ctx.rev())
3641 fm.end()
3641 fm.end()
3642
3642
3643 return not found
3643 return not found
3644
3644
3645
3645
3646 @command(
3646 @command(
3647 b'heads',
3647 b'heads',
3648 [
3648 [
3649 (
3649 (
3650 b'r',
3650 b'r',
3651 b'rev',
3651 b'rev',
3652 b'',
3652 b'',
3653 _(b'show only heads which are descendants of STARTREV'),
3653 _(b'show only heads which are descendants of STARTREV'),
3654 _(b'STARTREV'),
3654 _(b'STARTREV'),
3655 ),
3655 ),
3656 (b't', b'topo', False, _(b'show topological heads only')),
3656 (b't', b'topo', False, _(b'show topological heads only')),
3657 (
3657 (
3658 b'a',
3658 b'a',
3659 b'active',
3659 b'active',
3660 False,
3660 False,
3661 _(b'show active branchheads only (DEPRECATED)'),
3661 _(b'show active branchheads only (DEPRECATED)'),
3662 ),
3662 ),
3663 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3663 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3664 ]
3664 ]
3665 + templateopts,
3665 + templateopts,
3666 _(b'[-ct] [-r STARTREV] [REV]...'),
3666 _(b'[-ct] [-r STARTREV] [REV]...'),
3667 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3667 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3668 intents={INTENT_READONLY},
3668 intents={INTENT_READONLY},
3669 )
3669 )
3670 def heads(ui, repo, *branchrevs, **opts):
3670 def heads(ui, repo, *branchrevs, **opts):
3671 """show branch heads
3671 """show branch heads
3672
3672
3673 With no arguments, show all open branch heads in the repository.
3673 With no arguments, show all open branch heads in the repository.
3674 Branch heads are changesets that have no descendants on the
3674 Branch heads are changesets that have no descendants on the
3675 same branch. They are where development generally takes place and
3675 same branch. They are where development generally takes place and
3676 are the usual targets for update and merge operations.
3676 are the usual targets for update and merge operations.
3677
3677
3678 If one or more REVs are given, only open branch heads on the
3678 If one or more REVs are given, only open branch heads on the
3679 branches associated with the specified changesets are shown. This
3679 branches associated with the specified changesets are shown. This
3680 means that you can use :hg:`heads .` to see the heads on the
3680 means that you can use :hg:`heads .` to see the heads on the
3681 currently checked-out branch.
3681 currently checked-out branch.
3682
3682
3683 If -c/--closed is specified, also show branch heads marked closed
3683 If -c/--closed is specified, also show branch heads marked closed
3684 (see :hg:`commit --close-branch`).
3684 (see :hg:`commit --close-branch`).
3685
3685
3686 If STARTREV is specified, only those heads that are descendants of
3686 If STARTREV is specified, only those heads that are descendants of
3687 STARTREV will be displayed.
3687 STARTREV will be displayed.
3688
3688
3689 If -t/--topo is specified, named branch mechanics will be ignored and only
3689 If -t/--topo is specified, named branch mechanics will be ignored and only
3690 topological heads (changesets with no children) will be shown.
3690 topological heads (changesets with no children) will be shown.
3691
3691
3692 Returns 0 if matching heads are found, 1 if not.
3692 Returns 0 if matching heads are found, 1 if not.
3693 """
3693 """
3694
3694
3695 opts = pycompat.byteskwargs(opts)
3695 opts = pycompat.byteskwargs(opts)
3696 start = None
3696 start = None
3697 rev = opts.get(b'rev')
3697 rev = opts.get(b'rev')
3698 if rev:
3698 if rev:
3699 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3699 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3700 start = logcmdutil.revsingle(repo, rev, None).node()
3700 start = logcmdutil.revsingle(repo, rev, None).node()
3701
3701
3702 if opts.get(b'topo'):
3702 if opts.get(b'topo'):
3703 heads = [repo[h] for h in repo.heads(start)]
3703 heads = [repo[h] for h in repo.heads(start)]
3704 else:
3704 else:
3705 heads = []
3705 heads = []
3706 for branch in repo.branchmap():
3706 for branch in repo.branchmap():
3707 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3707 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3708 heads = [repo[h] for h in heads]
3708 heads = [repo[h] for h in heads]
3709
3709
3710 if branchrevs:
3710 if branchrevs:
3711 branches = {
3711 branches = {
3712 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3712 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3713 }
3713 }
3714 heads = [h for h in heads if h.branch() in branches]
3714 heads = [h for h in heads if h.branch() in branches]
3715
3715
3716 if opts.get(b'active') and branchrevs:
3716 if opts.get(b'active') and branchrevs:
3717 dagheads = repo.heads(start)
3717 dagheads = repo.heads(start)
3718 heads = [h for h in heads if h.node() in dagheads]
3718 heads = [h for h in heads if h.node() in dagheads]
3719
3719
3720 if branchrevs:
3720 if branchrevs:
3721 haveheads = {h.branch() for h in heads}
3721 haveheads = {h.branch() for h in heads}
3722 if branches - haveheads:
3722 if branches - haveheads:
3723 headless = b', '.join(b for b in branches - haveheads)
3723 headless = b', '.join(b for b in branches - haveheads)
3724 msg = _(b'no open branch heads found on branches %s')
3724 msg = _(b'no open branch heads found on branches %s')
3725 if opts.get(b'rev'):
3725 if opts.get(b'rev'):
3726 msg += _(b' (started at %s)') % opts[b'rev']
3726 msg += _(b' (started at %s)') % opts[b'rev']
3727 ui.warn((msg + b'\n') % headless)
3727 ui.warn((msg + b'\n') % headless)
3728
3728
3729 if not heads:
3729 if not heads:
3730 return 1
3730 return 1
3731
3731
3732 ui.pager(b'heads')
3732 ui.pager(b'heads')
3733 heads = sorted(heads, key=lambda x: -(x.rev()))
3733 heads = sorted(heads, key=lambda x: -(x.rev()))
3734 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3734 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3735 for ctx in heads:
3735 for ctx in heads:
3736 displayer.show(ctx)
3736 displayer.show(ctx)
3737 displayer.close()
3737 displayer.close()
3738
3738
3739
3739
3740 @command(
3740 @command(
3741 b'help',
3741 b'help',
3742 [
3742 [
3743 (b'e', b'extension', None, _(b'show only help for extensions')),
3743 (b'e', b'extension', None, _(b'show only help for extensions')),
3744 (b'c', b'command', None, _(b'show only help for commands')),
3744 (b'c', b'command', None, _(b'show only help for commands')),
3745 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3745 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3746 (
3746 (
3747 b's',
3747 b's',
3748 b'system',
3748 b'system',
3749 [],
3749 [],
3750 _(b'show help for specific platform(s)'),
3750 _(b'show help for specific platform(s)'),
3751 _(b'PLATFORM'),
3751 _(b'PLATFORM'),
3752 ),
3752 ),
3753 ],
3753 ],
3754 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3754 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3755 helpcategory=command.CATEGORY_HELP,
3755 helpcategory=command.CATEGORY_HELP,
3756 norepo=True,
3756 norepo=True,
3757 intents={INTENT_READONLY},
3757 intents={INTENT_READONLY},
3758 )
3758 )
3759 def help_(ui, name=None, **opts):
3759 def help_(ui, name=None, **opts):
3760 """show help for a given topic or a help overview
3760 """show help for a given topic or a help overview
3761
3761
3762 With no arguments, print a list of commands with short help messages.
3762 With no arguments, print a list of commands with short help messages.
3763
3763
3764 Given a topic, extension, or command name, print help for that
3764 Given a topic, extension, or command name, print help for that
3765 topic.
3765 topic.
3766
3766
3767 Returns 0 if successful.
3767 Returns 0 if successful.
3768 """
3768 """
3769
3769
3770 keep = opts.get('system') or []
3770 keep = opts.get('system') or []
3771 if len(keep) == 0:
3771 if len(keep) == 0:
3772 if pycompat.sysplatform.startswith(b'win'):
3772 if pycompat.sysplatform.startswith(b'win'):
3773 keep.append(b'windows')
3773 keep.append(b'windows')
3774 elif pycompat.sysplatform == b'OpenVMS':
3774 elif pycompat.sysplatform == b'OpenVMS':
3775 keep.append(b'vms')
3775 keep.append(b'vms')
3776 elif pycompat.sysplatform == b'plan9':
3776 elif pycompat.sysplatform == b'plan9':
3777 keep.append(b'plan9')
3777 keep.append(b'plan9')
3778 else:
3778 else:
3779 keep.append(b'unix')
3779 keep.append(b'unix')
3780 keep.append(pycompat.sysplatform.lower())
3780 keep.append(pycompat.sysplatform.lower())
3781 if ui.verbose:
3781 if ui.verbose:
3782 keep.append(b'verbose')
3782 keep.append(b'verbose')
3783
3783
3784 commands = sys.modules[__name__]
3784 commands = sys.modules[__name__]
3785 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3785 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3786 ui.pager(b'help')
3786 ui.pager(b'help')
3787 ui.write(formatted)
3787 ui.write(formatted)
3788
3788
3789
3789
3790 @command(
3790 @command(
3791 b'identify|id',
3791 b'identify|id',
3792 [
3792 [
3793 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3793 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3794 (b'n', b'num', None, _(b'show local revision number')),
3794 (b'n', b'num', None, _(b'show local revision number')),
3795 (b'i', b'id', None, _(b'show global revision id')),
3795 (b'i', b'id', None, _(b'show global revision id')),
3796 (b'b', b'branch', None, _(b'show branch')),
3796 (b'b', b'branch', None, _(b'show branch')),
3797 (b't', b'tags', None, _(b'show tags')),
3797 (b't', b'tags', None, _(b'show tags')),
3798 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3798 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3799 ]
3799 ]
3800 + remoteopts
3800 + remoteopts
3801 + formatteropts,
3801 + formatteropts,
3802 _(b'[-nibtB] [-r REV] [SOURCE]'),
3802 _(b'[-nibtB] [-r REV] [SOURCE]'),
3803 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3803 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3804 optionalrepo=True,
3804 optionalrepo=True,
3805 intents={INTENT_READONLY},
3805 intents={INTENT_READONLY},
3806 )
3806 )
3807 def identify(
3807 def identify(
3808 ui,
3808 ui,
3809 repo,
3809 repo,
3810 source=None,
3810 source=None,
3811 rev=None,
3811 rev=None,
3812 num=None,
3812 num=None,
3813 id=None,
3813 id=None,
3814 branch=None,
3814 branch=None,
3815 tags=None,
3815 tags=None,
3816 bookmarks=None,
3816 bookmarks=None,
3817 **opts
3817 **opts
3818 ):
3818 ):
3819 """identify the working directory or specified revision
3819 """identify the working directory or specified revision
3820
3820
3821 Print a summary identifying the repository state at REV using one or
3821 Print a summary identifying the repository state at REV using one or
3822 two parent hash identifiers, followed by a "+" if the working
3822 two parent hash identifiers, followed by a "+" if the working
3823 directory has uncommitted changes, the branch name (if not default),
3823 directory has uncommitted changes, the branch name (if not default),
3824 a list of tags, and a list of bookmarks.
3824 a list of tags, and a list of bookmarks.
3825
3825
3826 When REV is not given, print a summary of the current state of the
3826 When REV is not given, print a summary of the current state of the
3827 repository including the working directory. Specify -r. to get information
3827 repository including the working directory. Specify -r. to get information
3828 of the working directory parent without scanning uncommitted changes.
3828 of the working directory parent without scanning uncommitted changes.
3829
3829
3830 Specifying a path to a repository root or Mercurial bundle will
3830 Specifying a path to a repository root or Mercurial bundle will
3831 cause lookup to operate on that repository/bundle.
3831 cause lookup to operate on that repository/bundle.
3832
3832
3833 .. container:: verbose
3833 .. container:: verbose
3834
3834
3835 Template:
3835 Template:
3836
3836
3837 The following keywords are supported in addition to the common template
3837 The following keywords are supported in addition to the common template
3838 keywords and functions. See also :hg:`help templates`.
3838 keywords and functions. See also :hg:`help templates`.
3839
3839
3840 :dirty: String. Character ``+`` denoting if the working directory has
3840 :dirty: String. Character ``+`` denoting if the working directory has
3841 uncommitted changes.
3841 uncommitted changes.
3842 :id: String. One or two nodes, optionally followed by ``+``.
3842 :id: String. One or two nodes, optionally followed by ``+``.
3843 :parents: List of strings. Parent nodes of the changeset.
3843 :parents: List of strings. Parent nodes of the changeset.
3844
3844
3845 Examples:
3845 Examples:
3846
3846
3847 - generate a build identifier for the working directory::
3847 - generate a build identifier for the working directory::
3848
3848
3849 hg id --id > build-id.dat
3849 hg id --id > build-id.dat
3850
3850
3851 - find the revision corresponding to a tag::
3851 - find the revision corresponding to a tag::
3852
3852
3853 hg id -n -r 1.3
3853 hg id -n -r 1.3
3854
3854
3855 - check the most recent revision of a remote repository::
3855 - check the most recent revision of a remote repository::
3856
3856
3857 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3857 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3858
3858
3859 See :hg:`log` for generating more information about specific revisions,
3859 See :hg:`log` for generating more information about specific revisions,
3860 including full hash identifiers.
3860 including full hash identifiers.
3861
3861
3862 Returns 0 if successful.
3862 Returns 0 if successful.
3863 """
3863 """
3864
3864
3865 opts = pycompat.byteskwargs(opts)
3865 opts = pycompat.byteskwargs(opts)
3866 if not repo and not source:
3866 if not repo and not source:
3867 raise error.InputError(
3867 raise error.InputError(
3868 _(b"there is no Mercurial repository here (.hg not found)")
3868 _(b"there is no Mercurial repository here (.hg not found)")
3869 )
3869 )
3870
3870
3871 default = not (num or id or branch or tags or bookmarks)
3871 default = not (num or id or branch or tags or bookmarks)
3872 output = []
3872 output = []
3873 revs = []
3873 revs = []
3874
3874
3875 peer = None
3875 peer = None
3876 try:
3876 try:
3877 if source:
3877 if source:
3878 source, branches = urlutil.get_unique_pull_path(
3878 source, branches = urlutil.get_unique_pull_path(
3879 b'identify', repo, ui, source
3879 b'identify', repo, ui, source
3880 )
3880 )
3881 # only pass ui when no repo
3881 # only pass ui when no repo
3882 peer = hg.peer(repo or ui, opts, source)
3882 peer = hg.peer(repo or ui, opts, source)
3883 repo = peer.local()
3883 repo = peer.local()
3884 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3884 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3885
3885
3886 fm = ui.formatter(b'identify', opts)
3886 fm = ui.formatter(b'identify', opts)
3887 fm.startitem()
3887 fm.startitem()
3888
3888
3889 if not repo:
3889 if not repo:
3890 if num or branch or tags:
3890 if num or branch or tags:
3891 raise error.InputError(
3891 raise error.InputError(
3892 _(b"can't query remote revision number, branch, or tags")
3892 _(b"can't query remote revision number, branch, or tags")
3893 )
3893 )
3894 if not rev and revs:
3894 if not rev and revs:
3895 rev = revs[0]
3895 rev = revs[0]
3896 if not rev:
3896 if not rev:
3897 rev = b"tip"
3897 rev = b"tip"
3898
3898
3899 remoterev = peer.lookup(rev)
3899 remoterev = peer.lookup(rev)
3900 hexrev = fm.hexfunc(remoterev)
3900 hexrev = fm.hexfunc(remoterev)
3901 if default or id:
3901 if default or id:
3902 output = [hexrev]
3902 output = [hexrev]
3903 fm.data(id=hexrev)
3903 fm.data(id=hexrev)
3904
3904
3905 @util.cachefunc
3905 @util.cachefunc
3906 def getbms():
3906 def getbms():
3907 bms = []
3907 bms = []
3908
3908
3909 if b'bookmarks' in peer.listkeys(b'namespaces'):
3909 if b'bookmarks' in peer.listkeys(b'namespaces'):
3910 hexremoterev = hex(remoterev)
3910 hexremoterev = hex(remoterev)
3911 bms = [
3911 bms = [
3912 bm
3912 bm
3913 for bm, bmr in pycompat.iteritems(
3913 for bm, bmr in peer.listkeys(b'bookmarks').items()
3914 peer.listkeys(b'bookmarks')
3915 )
3916 if bmr == hexremoterev
3914 if bmr == hexremoterev
3917 ]
3915 ]
3918
3916
3919 return sorted(bms)
3917 return sorted(bms)
3920
3918
3921 if fm.isplain():
3919 if fm.isplain():
3922 if bookmarks:
3920 if bookmarks:
3923 output.extend(getbms())
3921 output.extend(getbms())
3924 elif default and not ui.quiet:
3922 elif default and not ui.quiet:
3925 # multiple bookmarks for a single parent separated by '/'
3923 # multiple bookmarks for a single parent separated by '/'
3926 bm = b'/'.join(getbms())
3924 bm = b'/'.join(getbms())
3927 if bm:
3925 if bm:
3928 output.append(bm)
3926 output.append(bm)
3929 else:
3927 else:
3930 fm.data(node=hex(remoterev))
3928 fm.data(node=hex(remoterev))
3931 if bookmarks or b'bookmarks' in fm.datahint():
3929 if bookmarks or b'bookmarks' in fm.datahint():
3932 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3930 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3933 else:
3931 else:
3934 if rev:
3932 if rev:
3935 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3933 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3936 ctx = logcmdutil.revsingle(repo, rev, None)
3934 ctx = logcmdutil.revsingle(repo, rev, None)
3937
3935
3938 if ctx.rev() is None:
3936 if ctx.rev() is None:
3939 ctx = repo[None]
3937 ctx = repo[None]
3940 parents = ctx.parents()
3938 parents = ctx.parents()
3941 taglist = []
3939 taglist = []
3942 for p in parents:
3940 for p in parents:
3943 taglist.extend(p.tags())
3941 taglist.extend(p.tags())
3944
3942
3945 dirty = b""
3943 dirty = b""
3946 if ctx.dirty(missing=True, merge=False, branch=False):
3944 if ctx.dirty(missing=True, merge=False, branch=False):
3947 dirty = b'+'
3945 dirty = b'+'
3948 fm.data(dirty=dirty)
3946 fm.data(dirty=dirty)
3949
3947
3950 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3948 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3951 if default or id:
3949 if default or id:
3952 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3950 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3953 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3951 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3954
3952
3955 if num:
3953 if num:
3956 numoutput = [b"%d" % p.rev() for p in parents]
3954 numoutput = [b"%d" % p.rev() for p in parents]
3957 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3955 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3958
3956
3959 fm.data(
3957 fm.data(
3960 parents=fm.formatlist(
3958 parents=fm.formatlist(
3961 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3959 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3962 )
3960 )
3963 )
3961 )
3964 else:
3962 else:
3965 hexoutput = fm.hexfunc(ctx.node())
3963 hexoutput = fm.hexfunc(ctx.node())
3966 if default or id:
3964 if default or id:
3967 output = [hexoutput]
3965 output = [hexoutput]
3968 fm.data(id=hexoutput)
3966 fm.data(id=hexoutput)
3969
3967
3970 if num:
3968 if num:
3971 output.append(pycompat.bytestr(ctx.rev()))
3969 output.append(pycompat.bytestr(ctx.rev()))
3972 taglist = ctx.tags()
3970 taglist = ctx.tags()
3973
3971
3974 if default and not ui.quiet:
3972 if default and not ui.quiet:
3975 b = ctx.branch()
3973 b = ctx.branch()
3976 if b != b'default':
3974 if b != b'default':
3977 output.append(b"(%s)" % b)
3975 output.append(b"(%s)" % b)
3978
3976
3979 # multiple tags for a single parent separated by '/'
3977 # multiple tags for a single parent separated by '/'
3980 t = b'/'.join(taglist)
3978 t = b'/'.join(taglist)
3981 if t:
3979 if t:
3982 output.append(t)
3980 output.append(t)
3983
3981
3984 # multiple bookmarks for a single parent separated by '/'
3982 # multiple bookmarks for a single parent separated by '/'
3985 bm = b'/'.join(ctx.bookmarks())
3983 bm = b'/'.join(ctx.bookmarks())
3986 if bm:
3984 if bm:
3987 output.append(bm)
3985 output.append(bm)
3988 else:
3986 else:
3989 if branch:
3987 if branch:
3990 output.append(ctx.branch())
3988 output.append(ctx.branch())
3991
3989
3992 if tags:
3990 if tags:
3993 output.extend(taglist)
3991 output.extend(taglist)
3994
3992
3995 if bookmarks:
3993 if bookmarks:
3996 output.extend(ctx.bookmarks())
3994 output.extend(ctx.bookmarks())
3997
3995
3998 fm.data(node=ctx.hex())
3996 fm.data(node=ctx.hex())
3999 fm.data(branch=ctx.branch())
3997 fm.data(branch=ctx.branch())
4000 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3998 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4001 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3999 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4002 fm.context(ctx=ctx)
4000 fm.context(ctx=ctx)
4003
4001
4004 fm.plain(b"%s\n" % b' '.join(output))
4002 fm.plain(b"%s\n" % b' '.join(output))
4005 fm.end()
4003 fm.end()
4006 finally:
4004 finally:
4007 if peer:
4005 if peer:
4008 peer.close()
4006 peer.close()
4009
4007
4010
4008
4011 @command(
4009 @command(
4012 b'import|patch',
4010 b'import|patch',
4013 [
4011 [
4014 (
4012 (
4015 b'p',
4013 b'p',
4016 b'strip',
4014 b'strip',
4017 1,
4015 1,
4018 _(
4016 _(
4019 b'directory strip option for patch. This has the same '
4017 b'directory strip option for patch. This has the same '
4020 b'meaning as the corresponding patch option'
4018 b'meaning as the corresponding patch option'
4021 ),
4019 ),
4022 _(b'NUM'),
4020 _(b'NUM'),
4023 ),
4021 ),
4024 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4022 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4025 (b'', b'secret', None, _(b'use the secret phase for committing')),
4023 (b'', b'secret', None, _(b'use the secret phase for committing')),
4026 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4024 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4027 (
4025 (
4028 b'f',
4026 b'f',
4029 b'force',
4027 b'force',
4030 None,
4028 None,
4031 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4029 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4032 ),
4030 ),
4033 (
4031 (
4034 b'',
4032 b'',
4035 b'no-commit',
4033 b'no-commit',
4036 None,
4034 None,
4037 _(b"don't commit, just update the working directory"),
4035 _(b"don't commit, just update the working directory"),
4038 ),
4036 ),
4039 (
4037 (
4040 b'',
4038 b'',
4041 b'bypass',
4039 b'bypass',
4042 None,
4040 None,
4043 _(b"apply patch without touching the working directory"),
4041 _(b"apply patch without touching the working directory"),
4044 ),
4042 ),
4045 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4043 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4046 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4044 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4047 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4045 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4048 (
4046 (
4049 b'',
4047 b'',
4050 b'import-branch',
4048 b'import-branch',
4051 None,
4049 None,
4052 _(b'use any branch information in patch (implied by --exact)'),
4050 _(b'use any branch information in patch (implied by --exact)'),
4053 ),
4051 ),
4054 ]
4052 ]
4055 + commitopts
4053 + commitopts
4056 + commitopts2
4054 + commitopts2
4057 + similarityopts,
4055 + similarityopts,
4058 _(b'[OPTION]... PATCH...'),
4056 _(b'[OPTION]... PATCH...'),
4059 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4057 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4060 )
4058 )
4061 def import_(ui, repo, patch1=None, *patches, **opts):
4059 def import_(ui, repo, patch1=None, *patches, **opts):
4062 """import an ordered set of patches
4060 """import an ordered set of patches
4063
4061
4064 Import a list of patches and commit them individually (unless
4062 Import a list of patches and commit them individually (unless
4065 --no-commit is specified).
4063 --no-commit is specified).
4066
4064
4067 To read a patch from standard input (stdin), use "-" as the patch
4065 To read a patch from standard input (stdin), use "-" as the patch
4068 name. If a URL is specified, the patch will be downloaded from
4066 name. If a URL is specified, the patch will be downloaded from
4069 there.
4067 there.
4070
4068
4071 Import first applies changes to the working directory (unless
4069 Import first applies changes to the working directory (unless
4072 --bypass is specified), import will abort if there are outstanding
4070 --bypass is specified), import will abort if there are outstanding
4073 changes.
4071 changes.
4074
4072
4075 Use --bypass to apply and commit patches directly to the
4073 Use --bypass to apply and commit patches directly to the
4076 repository, without affecting the working directory. Without
4074 repository, without affecting the working directory. Without
4077 --exact, patches will be applied on top of the working directory
4075 --exact, patches will be applied on top of the working directory
4078 parent revision.
4076 parent revision.
4079
4077
4080 You can import a patch straight from a mail message. Even patches
4078 You can import a patch straight from a mail message. Even patches
4081 as attachments work (to use the body part, it must have type
4079 as attachments work (to use the body part, it must have type
4082 text/plain or text/x-patch). From and Subject headers of email
4080 text/plain or text/x-patch). From and Subject headers of email
4083 message are used as default committer and commit message. All
4081 message are used as default committer and commit message. All
4084 text/plain body parts before first diff are added to the commit
4082 text/plain body parts before first diff are added to the commit
4085 message.
4083 message.
4086
4084
4087 If the imported patch was generated by :hg:`export`, user and
4085 If the imported patch was generated by :hg:`export`, user and
4088 description from patch override values from message headers and
4086 description from patch override values from message headers and
4089 body. Values given on command line with -m/--message and -u/--user
4087 body. Values given on command line with -m/--message and -u/--user
4090 override these.
4088 override these.
4091
4089
4092 If --exact is specified, import will set the working directory to
4090 If --exact is specified, import will set the working directory to
4093 the parent of each patch before applying it, and will abort if the
4091 the parent of each patch before applying it, and will abort if the
4094 resulting changeset has a different ID than the one recorded in
4092 resulting changeset has a different ID than the one recorded in
4095 the patch. This will guard against various ways that portable
4093 the patch. This will guard against various ways that portable
4096 patch formats and mail systems might fail to transfer Mercurial
4094 patch formats and mail systems might fail to transfer Mercurial
4097 data or metadata. See :hg:`bundle` for lossless transmission.
4095 data or metadata. See :hg:`bundle` for lossless transmission.
4098
4096
4099 Use --partial to ensure a changeset will be created from the patch
4097 Use --partial to ensure a changeset will be created from the patch
4100 even if some hunks fail to apply. Hunks that fail to apply will be
4098 even if some hunks fail to apply. Hunks that fail to apply will be
4101 written to a <target-file>.rej file. Conflicts can then be resolved
4099 written to a <target-file>.rej file. Conflicts can then be resolved
4102 by hand before :hg:`commit --amend` is run to update the created
4100 by hand before :hg:`commit --amend` is run to update the created
4103 changeset. This flag exists to let people import patches that
4101 changeset. This flag exists to let people import patches that
4104 partially apply without losing the associated metadata (author,
4102 partially apply without losing the associated metadata (author,
4105 date, description, ...).
4103 date, description, ...).
4106
4104
4107 .. note::
4105 .. note::
4108
4106
4109 When no hunks apply cleanly, :hg:`import --partial` will create
4107 When no hunks apply cleanly, :hg:`import --partial` will create
4110 an empty changeset, importing only the patch metadata.
4108 an empty changeset, importing only the patch metadata.
4111
4109
4112 With -s/--similarity, hg will attempt to discover renames and
4110 With -s/--similarity, hg will attempt to discover renames and
4113 copies in the patch in the same way as :hg:`addremove`.
4111 copies in the patch in the same way as :hg:`addremove`.
4114
4112
4115 It is possible to use external patch programs to perform the patch
4113 It is possible to use external patch programs to perform the patch
4116 by setting the ``ui.patch`` configuration option. For the default
4114 by setting the ``ui.patch`` configuration option. For the default
4117 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4115 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4118 See :hg:`help config` for more information about configuration
4116 See :hg:`help config` for more information about configuration
4119 files and how to use these options.
4117 files and how to use these options.
4120
4118
4121 See :hg:`help dates` for a list of formats valid for -d/--date.
4119 See :hg:`help dates` for a list of formats valid for -d/--date.
4122
4120
4123 .. container:: verbose
4121 .. container:: verbose
4124
4122
4125 Examples:
4123 Examples:
4126
4124
4127 - import a traditional patch from a website and detect renames::
4125 - import a traditional patch from a website and detect renames::
4128
4126
4129 hg import -s 80 http://example.com/bugfix.patch
4127 hg import -s 80 http://example.com/bugfix.patch
4130
4128
4131 - import a changeset from an hgweb server::
4129 - import a changeset from an hgweb server::
4132
4130
4133 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4131 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4134
4132
4135 - import all the patches in an Unix-style mbox::
4133 - import all the patches in an Unix-style mbox::
4136
4134
4137 hg import incoming-patches.mbox
4135 hg import incoming-patches.mbox
4138
4136
4139 - import patches from stdin::
4137 - import patches from stdin::
4140
4138
4141 hg import -
4139 hg import -
4142
4140
4143 - attempt to exactly restore an exported changeset (not always
4141 - attempt to exactly restore an exported changeset (not always
4144 possible)::
4142 possible)::
4145
4143
4146 hg import --exact proposed-fix.patch
4144 hg import --exact proposed-fix.patch
4147
4145
4148 - use an external tool to apply a patch which is too fuzzy for
4146 - use an external tool to apply a patch which is too fuzzy for
4149 the default internal tool.
4147 the default internal tool.
4150
4148
4151 hg import --config ui.patch="patch --merge" fuzzy.patch
4149 hg import --config ui.patch="patch --merge" fuzzy.patch
4152
4150
4153 - change the default fuzzing from 2 to a less strict 7
4151 - change the default fuzzing from 2 to a less strict 7
4154
4152
4155 hg import --config ui.fuzz=7 fuzz.patch
4153 hg import --config ui.fuzz=7 fuzz.patch
4156
4154
4157 Returns 0 on success, 1 on partial success (see --partial).
4155 Returns 0 on success, 1 on partial success (see --partial).
4158 """
4156 """
4159
4157
4160 cmdutil.check_incompatible_arguments(
4158 cmdutil.check_incompatible_arguments(
4161 opts, 'no_commit', ['bypass', 'secret']
4159 opts, 'no_commit', ['bypass', 'secret']
4162 )
4160 )
4163 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4161 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4164 opts = pycompat.byteskwargs(opts)
4162 opts = pycompat.byteskwargs(opts)
4165 if not patch1:
4163 if not patch1:
4166 raise error.InputError(_(b'need at least one patch to import'))
4164 raise error.InputError(_(b'need at least one patch to import'))
4167
4165
4168 patches = (patch1,) + patches
4166 patches = (patch1,) + patches
4169
4167
4170 date = opts.get(b'date')
4168 date = opts.get(b'date')
4171 if date:
4169 if date:
4172 opts[b'date'] = dateutil.parsedate(date)
4170 opts[b'date'] = dateutil.parsedate(date)
4173
4171
4174 exact = opts.get(b'exact')
4172 exact = opts.get(b'exact')
4175 update = not opts.get(b'bypass')
4173 update = not opts.get(b'bypass')
4176 try:
4174 try:
4177 sim = float(opts.get(b'similarity') or 0)
4175 sim = float(opts.get(b'similarity') or 0)
4178 except ValueError:
4176 except ValueError:
4179 raise error.InputError(_(b'similarity must be a number'))
4177 raise error.InputError(_(b'similarity must be a number'))
4180 if sim < 0 or sim > 100:
4178 if sim < 0 or sim > 100:
4181 raise error.InputError(_(b'similarity must be between 0 and 100'))
4179 raise error.InputError(_(b'similarity must be between 0 and 100'))
4182 if sim and not update:
4180 if sim and not update:
4183 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4181 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4184
4182
4185 base = opts[b"base"]
4183 base = opts[b"base"]
4186 msgs = []
4184 msgs = []
4187 ret = 0
4185 ret = 0
4188
4186
4189 with repo.wlock():
4187 with repo.wlock():
4190 if update:
4188 if update:
4191 cmdutil.checkunfinished(repo)
4189 cmdutil.checkunfinished(repo)
4192 if exact or not opts.get(b'force'):
4190 if exact or not opts.get(b'force'):
4193 cmdutil.bailifchanged(repo)
4191 cmdutil.bailifchanged(repo)
4194
4192
4195 if not opts.get(b'no_commit'):
4193 if not opts.get(b'no_commit'):
4196 lock = repo.lock
4194 lock = repo.lock
4197 tr = lambda: repo.transaction(b'import')
4195 tr = lambda: repo.transaction(b'import')
4198 dsguard = util.nullcontextmanager
4196 dsguard = util.nullcontextmanager
4199 else:
4197 else:
4200 lock = util.nullcontextmanager
4198 lock = util.nullcontextmanager
4201 tr = util.nullcontextmanager
4199 tr = util.nullcontextmanager
4202 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4200 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4203 with lock(), tr(), dsguard():
4201 with lock(), tr(), dsguard():
4204 parents = repo[None].parents()
4202 parents = repo[None].parents()
4205 for patchurl in patches:
4203 for patchurl in patches:
4206 if patchurl == b'-':
4204 if patchurl == b'-':
4207 ui.status(_(b'applying patch from stdin\n'))
4205 ui.status(_(b'applying patch from stdin\n'))
4208 patchfile = ui.fin
4206 patchfile = ui.fin
4209 patchurl = b'stdin' # for error message
4207 patchurl = b'stdin' # for error message
4210 else:
4208 else:
4211 patchurl = os.path.join(base, patchurl)
4209 patchurl = os.path.join(base, patchurl)
4212 ui.status(_(b'applying %s\n') % patchurl)
4210 ui.status(_(b'applying %s\n') % patchurl)
4213 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4211 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4214
4212
4215 haspatch = False
4213 haspatch = False
4216 for hunk in patch.split(patchfile):
4214 for hunk in patch.split(patchfile):
4217 with patch.extract(ui, hunk) as patchdata:
4215 with patch.extract(ui, hunk) as patchdata:
4218 msg, node, rej = cmdutil.tryimportone(
4216 msg, node, rej = cmdutil.tryimportone(
4219 ui, repo, patchdata, parents, opts, msgs, hg.clean
4217 ui, repo, patchdata, parents, opts, msgs, hg.clean
4220 )
4218 )
4221 if msg:
4219 if msg:
4222 haspatch = True
4220 haspatch = True
4223 ui.note(msg + b'\n')
4221 ui.note(msg + b'\n')
4224 if update or exact:
4222 if update or exact:
4225 parents = repo[None].parents()
4223 parents = repo[None].parents()
4226 else:
4224 else:
4227 parents = [repo[node]]
4225 parents = [repo[node]]
4228 if rej:
4226 if rej:
4229 ui.write_err(_(b"patch applied partially\n"))
4227 ui.write_err(_(b"patch applied partially\n"))
4230 ui.write_err(
4228 ui.write_err(
4231 _(
4229 _(
4232 b"(fix the .rej files and run "
4230 b"(fix the .rej files and run "
4233 b"`hg commit --amend`)\n"
4231 b"`hg commit --amend`)\n"
4234 )
4232 )
4235 )
4233 )
4236 ret = 1
4234 ret = 1
4237 break
4235 break
4238
4236
4239 if not haspatch:
4237 if not haspatch:
4240 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4238 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4241
4239
4242 if msgs:
4240 if msgs:
4243 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4241 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4244 return ret
4242 return ret
4245
4243
4246
4244
4247 @command(
4245 @command(
4248 b'incoming|in',
4246 b'incoming|in',
4249 [
4247 [
4250 (
4248 (
4251 b'f',
4249 b'f',
4252 b'force',
4250 b'force',
4253 None,
4251 None,
4254 _(b'run even if remote repository is unrelated'),
4252 _(b'run even if remote repository is unrelated'),
4255 ),
4253 ),
4256 (b'n', b'newest-first', None, _(b'show newest record first')),
4254 (b'n', b'newest-first', None, _(b'show newest record first')),
4257 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4255 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4258 (
4256 (
4259 b'r',
4257 b'r',
4260 b'rev',
4258 b'rev',
4261 [],
4259 [],
4262 _(b'a remote changeset intended to be added'),
4260 _(b'a remote changeset intended to be added'),
4263 _(b'REV'),
4261 _(b'REV'),
4264 ),
4262 ),
4265 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4263 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4266 (
4264 (
4267 b'b',
4265 b'b',
4268 b'branch',
4266 b'branch',
4269 [],
4267 [],
4270 _(b'a specific branch you would like to pull'),
4268 _(b'a specific branch you would like to pull'),
4271 _(b'BRANCH'),
4269 _(b'BRANCH'),
4272 ),
4270 ),
4273 ]
4271 ]
4274 + logopts
4272 + logopts
4275 + remoteopts
4273 + remoteopts
4276 + subrepoopts,
4274 + subrepoopts,
4277 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4275 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4278 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4276 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4279 )
4277 )
4280 def incoming(ui, repo, source=b"default", **opts):
4278 def incoming(ui, repo, source=b"default", **opts):
4281 """show new changesets found in source
4279 """show new changesets found in source
4282
4280
4283 Show new changesets found in the specified path/URL or the default
4281 Show new changesets found in the specified path/URL or the default
4284 pull location. These are the changesets that would have been pulled
4282 pull location. These are the changesets that would have been pulled
4285 by :hg:`pull` at the time you issued this command.
4283 by :hg:`pull` at the time you issued this command.
4286
4284
4287 See pull for valid source format details.
4285 See pull for valid source format details.
4288
4286
4289 .. container:: verbose
4287 .. container:: verbose
4290
4288
4291 With -B/--bookmarks, the result of bookmark comparison between
4289 With -B/--bookmarks, the result of bookmark comparison between
4292 local and remote repositories is displayed. With -v/--verbose,
4290 local and remote repositories is displayed. With -v/--verbose,
4293 status is also displayed for each bookmark like below::
4291 status is also displayed for each bookmark like below::
4294
4292
4295 BM1 01234567890a added
4293 BM1 01234567890a added
4296 BM2 1234567890ab advanced
4294 BM2 1234567890ab advanced
4297 BM3 234567890abc diverged
4295 BM3 234567890abc diverged
4298 BM4 34567890abcd changed
4296 BM4 34567890abcd changed
4299
4297
4300 The action taken locally when pulling depends on the
4298 The action taken locally when pulling depends on the
4301 status of each bookmark:
4299 status of each bookmark:
4302
4300
4303 :``added``: pull will create it
4301 :``added``: pull will create it
4304 :``advanced``: pull will update it
4302 :``advanced``: pull will update it
4305 :``diverged``: pull will create a divergent bookmark
4303 :``diverged``: pull will create a divergent bookmark
4306 :``changed``: result depends on remote changesets
4304 :``changed``: result depends on remote changesets
4307
4305
4308 From the point of view of pulling behavior, bookmark
4306 From the point of view of pulling behavior, bookmark
4309 existing only in the remote repository are treated as ``added``,
4307 existing only in the remote repository are treated as ``added``,
4310 even if it is in fact locally deleted.
4308 even if it is in fact locally deleted.
4311
4309
4312 .. container:: verbose
4310 .. container:: verbose
4313
4311
4314 For remote repository, using --bundle avoids downloading the
4312 For remote repository, using --bundle avoids downloading the
4315 changesets twice if the incoming is followed by a pull.
4313 changesets twice if the incoming is followed by a pull.
4316
4314
4317 Examples:
4315 Examples:
4318
4316
4319 - show incoming changes with patches and full description::
4317 - show incoming changes with patches and full description::
4320
4318
4321 hg incoming -vp
4319 hg incoming -vp
4322
4320
4323 - show incoming changes excluding merges, store a bundle::
4321 - show incoming changes excluding merges, store a bundle::
4324
4322
4325 hg in -vpM --bundle incoming.hg
4323 hg in -vpM --bundle incoming.hg
4326 hg pull incoming.hg
4324 hg pull incoming.hg
4327
4325
4328 - briefly list changes inside a bundle::
4326 - briefly list changes inside a bundle::
4329
4327
4330 hg in changes.hg -T "{desc|firstline}\\n"
4328 hg in changes.hg -T "{desc|firstline}\\n"
4331
4329
4332 Returns 0 if there are incoming changes, 1 otherwise.
4330 Returns 0 if there are incoming changes, 1 otherwise.
4333 """
4331 """
4334 opts = pycompat.byteskwargs(opts)
4332 opts = pycompat.byteskwargs(opts)
4335 if opts.get(b'graph'):
4333 if opts.get(b'graph'):
4336 logcmdutil.checkunsupportedgraphflags([], opts)
4334 logcmdutil.checkunsupportedgraphflags([], opts)
4337
4335
4338 def display(other, chlist, displayer):
4336 def display(other, chlist, displayer):
4339 revdag = logcmdutil.graphrevs(other, chlist, opts)
4337 revdag = logcmdutil.graphrevs(other, chlist, opts)
4340 logcmdutil.displaygraph(
4338 logcmdutil.displaygraph(
4341 ui, repo, revdag, displayer, graphmod.asciiedges
4339 ui, repo, revdag, displayer, graphmod.asciiedges
4342 )
4340 )
4343
4341
4344 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4342 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4345 return 0
4343 return 0
4346
4344
4347 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4345 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4348
4346
4349 if opts.get(b'bookmarks'):
4347 if opts.get(b'bookmarks'):
4350 srcs = urlutil.get_pull_paths(repo, ui, [source])
4348 srcs = urlutil.get_pull_paths(repo, ui, [source])
4351 for path in srcs:
4349 for path in srcs:
4352 source, branches = urlutil.parseurl(
4350 source, branches = urlutil.parseurl(
4353 path.rawloc, opts.get(b'branch')
4351 path.rawloc, opts.get(b'branch')
4354 )
4352 )
4355 other = hg.peer(repo, opts, source)
4353 other = hg.peer(repo, opts, source)
4356 try:
4354 try:
4357 if b'bookmarks' not in other.listkeys(b'namespaces'):
4355 if b'bookmarks' not in other.listkeys(b'namespaces'):
4358 ui.warn(_(b"remote doesn't support bookmarks\n"))
4356 ui.warn(_(b"remote doesn't support bookmarks\n"))
4359 return 0
4357 return 0
4360 ui.pager(b'incoming')
4358 ui.pager(b'incoming')
4361 ui.status(
4359 ui.status(
4362 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4360 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4363 )
4361 )
4364 return bookmarks.incoming(
4362 return bookmarks.incoming(
4365 ui, repo, other, mode=path.bookmarks_mode
4363 ui, repo, other, mode=path.bookmarks_mode
4366 )
4364 )
4367 finally:
4365 finally:
4368 other.close()
4366 other.close()
4369
4367
4370 return hg.incoming(ui, repo, source, opts)
4368 return hg.incoming(ui, repo, source, opts)
4371
4369
4372
4370
4373 @command(
4371 @command(
4374 b'init',
4372 b'init',
4375 remoteopts,
4373 remoteopts,
4376 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4374 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4377 helpcategory=command.CATEGORY_REPO_CREATION,
4375 helpcategory=command.CATEGORY_REPO_CREATION,
4378 helpbasic=True,
4376 helpbasic=True,
4379 norepo=True,
4377 norepo=True,
4380 )
4378 )
4381 def init(ui, dest=b".", **opts):
4379 def init(ui, dest=b".", **opts):
4382 """create a new repository in the given directory
4380 """create a new repository in the given directory
4383
4381
4384 Initialize a new repository in the given directory. If the given
4382 Initialize a new repository in the given directory. If the given
4385 directory does not exist, it will be created.
4383 directory does not exist, it will be created.
4386
4384
4387 If no directory is given, the current directory is used.
4385 If no directory is given, the current directory is used.
4388
4386
4389 It is possible to specify an ``ssh://`` URL as the destination.
4387 It is possible to specify an ``ssh://`` URL as the destination.
4390 See :hg:`help urls` for more information.
4388 See :hg:`help urls` for more information.
4391
4389
4392 Returns 0 on success.
4390 Returns 0 on success.
4393 """
4391 """
4394 opts = pycompat.byteskwargs(opts)
4392 opts = pycompat.byteskwargs(opts)
4395 path = urlutil.get_clone_path(ui, dest)[1]
4393 path = urlutil.get_clone_path(ui, dest)[1]
4396 peer = hg.peer(ui, opts, path, create=True)
4394 peer = hg.peer(ui, opts, path, create=True)
4397 peer.close()
4395 peer.close()
4398
4396
4399
4397
4400 @command(
4398 @command(
4401 b'locate',
4399 b'locate',
4402 [
4400 [
4403 (
4401 (
4404 b'r',
4402 b'r',
4405 b'rev',
4403 b'rev',
4406 b'',
4404 b'',
4407 _(b'search the repository as it is in REV'),
4405 _(b'search the repository as it is in REV'),
4408 _(b'REV'),
4406 _(b'REV'),
4409 ),
4407 ),
4410 (
4408 (
4411 b'0',
4409 b'0',
4412 b'print0',
4410 b'print0',
4413 None,
4411 None,
4414 _(b'end filenames with NUL, for use with xargs'),
4412 _(b'end filenames with NUL, for use with xargs'),
4415 ),
4413 ),
4416 (
4414 (
4417 b'f',
4415 b'f',
4418 b'fullpath',
4416 b'fullpath',
4419 None,
4417 None,
4420 _(b'print complete paths from the filesystem root'),
4418 _(b'print complete paths from the filesystem root'),
4421 ),
4419 ),
4422 ]
4420 ]
4423 + walkopts,
4421 + walkopts,
4424 _(b'[OPTION]... [PATTERN]...'),
4422 _(b'[OPTION]... [PATTERN]...'),
4425 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4423 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4426 )
4424 )
4427 def locate(ui, repo, *pats, **opts):
4425 def locate(ui, repo, *pats, **opts):
4428 """locate files matching specific patterns (DEPRECATED)
4426 """locate files matching specific patterns (DEPRECATED)
4429
4427
4430 Print files under Mercurial control in the working directory whose
4428 Print files under Mercurial control in the working directory whose
4431 names match the given patterns.
4429 names match the given patterns.
4432
4430
4433 By default, this command searches all directories in the working
4431 By default, this command searches all directories in the working
4434 directory. To search just the current directory and its
4432 directory. To search just the current directory and its
4435 subdirectories, use "--include .".
4433 subdirectories, use "--include .".
4436
4434
4437 If no patterns are given to match, this command prints the names
4435 If no patterns are given to match, this command prints the names
4438 of all files under Mercurial control in the working directory.
4436 of all files under Mercurial control in the working directory.
4439
4437
4440 If you want to feed the output of this command into the "xargs"
4438 If you want to feed the output of this command into the "xargs"
4441 command, use the -0 option to both this command and "xargs". This
4439 command, use the -0 option to both this command and "xargs". This
4442 will avoid the problem of "xargs" treating single filenames that
4440 will avoid the problem of "xargs" treating single filenames that
4443 contain whitespace as multiple filenames.
4441 contain whitespace as multiple filenames.
4444
4442
4445 See :hg:`help files` for a more versatile command.
4443 See :hg:`help files` for a more versatile command.
4446
4444
4447 Returns 0 if a match is found, 1 otherwise.
4445 Returns 0 if a match is found, 1 otherwise.
4448 """
4446 """
4449 opts = pycompat.byteskwargs(opts)
4447 opts = pycompat.byteskwargs(opts)
4450 if opts.get(b'print0'):
4448 if opts.get(b'print0'):
4451 end = b'\0'
4449 end = b'\0'
4452 else:
4450 else:
4453 end = b'\n'
4451 end = b'\n'
4454 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4452 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4455
4453
4456 ret = 1
4454 ret = 1
4457 m = scmutil.match(
4455 m = scmutil.match(
4458 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4456 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4459 )
4457 )
4460
4458
4461 ui.pager(b'locate')
4459 ui.pager(b'locate')
4462 if ctx.rev() is None:
4460 if ctx.rev() is None:
4463 # When run on the working copy, "locate" includes removed files, so
4461 # When run on the working copy, "locate" includes removed files, so
4464 # we get the list of files from the dirstate.
4462 # we get the list of files from the dirstate.
4465 filesgen = sorted(repo.dirstate.matches(m))
4463 filesgen = sorted(repo.dirstate.matches(m))
4466 else:
4464 else:
4467 filesgen = ctx.matches(m)
4465 filesgen = ctx.matches(m)
4468 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4466 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4469 for abs in filesgen:
4467 for abs in filesgen:
4470 if opts.get(b'fullpath'):
4468 if opts.get(b'fullpath'):
4471 ui.write(repo.wjoin(abs), end)
4469 ui.write(repo.wjoin(abs), end)
4472 else:
4470 else:
4473 ui.write(uipathfn(abs), end)
4471 ui.write(uipathfn(abs), end)
4474 ret = 0
4472 ret = 0
4475
4473
4476 return ret
4474 return ret
4477
4475
4478
4476
4479 @command(
4477 @command(
4480 b'log|history',
4478 b'log|history',
4481 [
4479 [
4482 (
4480 (
4483 b'f',
4481 b'f',
4484 b'follow',
4482 b'follow',
4485 None,
4483 None,
4486 _(
4484 _(
4487 b'follow changeset history, or file history across copies and renames'
4485 b'follow changeset history, or file history across copies and renames'
4488 ),
4486 ),
4489 ),
4487 ),
4490 (
4488 (
4491 b'',
4489 b'',
4492 b'follow-first',
4490 b'follow-first',
4493 None,
4491 None,
4494 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4492 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4495 ),
4493 ),
4496 (
4494 (
4497 b'd',
4495 b'd',
4498 b'date',
4496 b'date',
4499 b'',
4497 b'',
4500 _(b'show revisions matching date spec'),
4498 _(b'show revisions matching date spec'),
4501 _(b'DATE'),
4499 _(b'DATE'),
4502 ),
4500 ),
4503 (b'C', b'copies', None, _(b'show copied files')),
4501 (b'C', b'copies', None, _(b'show copied files')),
4504 (
4502 (
4505 b'k',
4503 b'k',
4506 b'keyword',
4504 b'keyword',
4507 [],
4505 [],
4508 _(b'do case-insensitive search for a given text'),
4506 _(b'do case-insensitive search for a given text'),
4509 _(b'TEXT'),
4507 _(b'TEXT'),
4510 ),
4508 ),
4511 (
4509 (
4512 b'r',
4510 b'r',
4513 b'rev',
4511 b'rev',
4514 [],
4512 [],
4515 _(b'revisions to select or follow from'),
4513 _(b'revisions to select or follow from'),
4516 _(b'REV'),
4514 _(b'REV'),
4517 ),
4515 ),
4518 (
4516 (
4519 b'L',
4517 b'L',
4520 b'line-range',
4518 b'line-range',
4521 [],
4519 [],
4522 _(b'follow line range of specified file (EXPERIMENTAL)'),
4520 _(b'follow line range of specified file (EXPERIMENTAL)'),
4523 _(b'FILE,RANGE'),
4521 _(b'FILE,RANGE'),
4524 ),
4522 ),
4525 (
4523 (
4526 b'',
4524 b'',
4527 b'removed',
4525 b'removed',
4528 None,
4526 None,
4529 _(b'include revisions where files were removed'),
4527 _(b'include revisions where files were removed'),
4530 ),
4528 ),
4531 (
4529 (
4532 b'm',
4530 b'm',
4533 b'only-merges',
4531 b'only-merges',
4534 None,
4532 None,
4535 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4533 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4536 ),
4534 ),
4537 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4535 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4538 (
4536 (
4539 b'',
4537 b'',
4540 b'only-branch',
4538 b'only-branch',
4541 [],
4539 [],
4542 _(
4540 _(
4543 b'show only changesets within the given named branch (DEPRECATED)'
4541 b'show only changesets within the given named branch (DEPRECATED)'
4544 ),
4542 ),
4545 _(b'BRANCH'),
4543 _(b'BRANCH'),
4546 ),
4544 ),
4547 (
4545 (
4548 b'b',
4546 b'b',
4549 b'branch',
4547 b'branch',
4550 [],
4548 [],
4551 _(b'show changesets within the given named branch'),
4549 _(b'show changesets within the given named branch'),
4552 _(b'BRANCH'),
4550 _(b'BRANCH'),
4553 ),
4551 ),
4554 (
4552 (
4555 b'B',
4553 b'B',
4556 b'bookmark',
4554 b'bookmark',
4557 [],
4555 [],
4558 _(b"show changesets within the given bookmark"),
4556 _(b"show changesets within the given bookmark"),
4559 _(b'BOOKMARK'),
4557 _(b'BOOKMARK'),
4560 ),
4558 ),
4561 (
4559 (
4562 b'P',
4560 b'P',
4563 b'prune',
4561 b'prune',
4564 [],
4562 [],
4565 _(b'do not display revision or any of its ancestors'),
4563 _(b'do not display revision or any of its ancestors'),
4566 _(b'REV'),
4564 _(b'REV'),
4567 ),
4565 ),
4568 ]
4566 ]
4569 + logopts
4567 + logopts
4570 + walkopts,
4568 + walkopts,
4571 _(b'[OPTION]... [FILE]'),
4569 _(b'[OPTION]... [FILE]'),
4572 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4570 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4573 helpbasic=True,
4571 helpbasic=True,
4574 inferrepo=True,
4572 inferrepo=True,
4575 intents={INTENT_READONLY},
4573 intents={INTENT_READONLY},
4576 )
4574 )
4577 def log(ui, repo, *pats, **opts):
4575 def log(ui, repo, *pats, **opts):
4578 """show revision history of entire repository or files
4576 """show revision history of entire repository or files
4579
4577
4580 Print the revision history of the specified files or the entire
4578 Print the revision history of the specified files or the entire
4581 project.
4579 project.
4582
4580
4583 If no revision range is specified, the default is ``tip:0`` unless
4581 If no revision range is specified, the default is ``tip:0`` unless
4584 --follow is set.
4582 --follow is set.
4585
4583
4586 File history is shown without following rename or copy history of
4584 File history is shown without following rename or copy history of
4587 files. Use -f/--follow with a filename to follow history across
4585 files. Use -f/--follow with a filename to follow history across
4588 renames and copies. --follow without a filename will only show
4586 renames and copies. --follow without a filename will only show
4589 ancestors of the starting revisions. The starting revisions can be
4587 ancestors of the starting revisions. The starting revisions can be
4590 specified by -r/--rev, which default to the working directory parent.
4588 specified by -r/--rev, which default to the working directory parent.
4591
4589
4592 By default this command prints revision number and changeset id,
4590 By default this command prints revision number and changeset id,
4593 tags, non-trivial parents, user, date and time, and a summary for
4591 tags, non-trivial parents, user, date and time, and a summary for
4594 each commit. When the -v/--verbose switch is used, the list of
4592 each commit. When the -v/--verbose switch is used, the list of
4595 changed files and full commit message are shown.
4593 changed files and full commit message are shown.
4596
4594
4597 With --graph the revisions are shown as an ASCII art DAG with the most
4595 With --graph the revisions are shown as an ASCII art DAG with the most
4598 recent changeset at the top.
4596 recent changeset at the top.
4599 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4597 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4600 involved in an unresolved merge conflict, '_' closes a branch,
4598 involved in an unresolved merge conflict, '_' closes a branch,
4601 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4599 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4602 changeset from the lines below is a parent of the 'o' merge on the same
4600 changeset from the lines below is a parent of the 'o' merge on the same
4603 line.
4601 line.
4604 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4602 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4605 of a '|' indicates one or more revisions in a path are omitted.
4603 of a '|' indicates one or more revisions in a path are omitted.
4606
4604
4607 .. container:: verbose
4605 .. container:: verbose
4608
4606
4609 Use -L/--line-range FILE,M:N options to follow the history of lines
4607 Use -L/--line-range FILE,M:N options to follow the history of lines
4610 from M to N in FILE. With -p/--patch only diff hunks affecting
4608 from M to N in FILE. With -p/--patch only diff hunks affecting
4611 specified line range will be shown. This option requires --follow;
4609 specified line range will be shown. This option requires --follow;
4612 it can be specified multiple times. Currently, this option is not
4610 it can be specified multiple times. Currently, this option is not
4613 compatible with --graph. This option is experimental.
4611 compatible with --graph. This option is experimental.
4614
4612
4615 .. note::
4613 .. note::
4616
4614
4617 :hg:`log --patch` may generate unexpected diff output for merge
4615 :hg:`log --patch` may generate unexpected diff output for merge
4618 changesets, as it will only compare the merge changeset against
4616 changesets, as it will only compare the merge changeset against
4619 its first parent. Also, only files different from BOTH parents
4617 its first parent. Also, only files different from BOTH parents
4620 will appear in files:.
4618 will appear in files:.
4621
4619
4622 .. note::
4620 .. note::
4623
4621
4624 For performance reasons, :hg:`log FILE` may omit duplicate changes
4622 For performance reasons, :hg:`log FILE` may omit duplicate changes
4625 made on branches and will not show removals or mode changes. To
4623 made on branches and will not show removals or mode changes. To
4626 see all such changes, use the --removed switch.
4624 see all such changes, use the --removed switch.
4627
4625
4628 .. container:: verbose
4626 .. container:: verbose
4629
4627
4630 .. note::
4628 .. note::
4631
4629
4632 The history resulting from -L/--line-range options depends on diff
4630 The history resulting from -L/--line-range options depends on diff
4633 options; for instance if white-spaces are ignored, respective changes
4631 options; for instance if white-spaces are ignored, respective changes
4634 with only white-spaces in specified line range will not be listed.
4632 with only white-spaces in specified line range will not be listed.
4635
4633
4636 .. container:: verbose
4634 .. container:: verbose
4637
4635
4638 Some examples:
4636 Some examples:
4639
4637
4640 - changesets with full descriptions and file lists::
4638 - changesets with full descriptions and file lists::
4641
4639
4642 hg log -v
4640 hg log -v
4643
4641
4644 - changesets ancestral to the working directory::
4642 - changesets ancestral to the working directory::
4645
4643
4646 hg log -f
4644 hg log -f
4647
4645
4648 - last 10 commits on the current branch::
4646 - last 10 commits on the current branch::
4649
4647
4650 hg log -l 10 -b .
4648 hg log -l 10 -b .
4651
4649
4652 - changesets showing all modifications of a file, including removals::
4650 - changesets showing all modifications of a file, including removals::
4653
4651
4654 hg log --removed file.c
4652 hg log --removed file.c
4655
4653
4656 - all changesets that touch a directory, with diffs, excluding merges::
4654 - all changesets that touch a directory, with diffs, excluding merges::
4657
4655
4658 hg log -Mp lib/
4656 hg log -Mp lib/
4659
4657
4660 - all revision numbers that match a keyword::
4658 - all revision numbers that match a keyword::
4661
4659
4662 hg log -k bug --template "{rev}\\n"
4660 hg log -k bug --template "{rev}\\n"
4663
4661
4664 - the full hash identifier of the working directory parent::
4662 - the full hash identifier of the working directory parent::
4665
4663
4666 hg log -r . --template "{node}\\n"
4664 hg log -r . --template "{node}\\n"
4667
4665
4668 - list available log templates::
4666 - list available log templates::
4669
4667
4670 hg log -T list
4668 hg log -T list
4671
4669
4672 - check if a given changeset is included in a tagged release::
4670 - check if a given changeset is included in a tagged release::
4673
4671
4674 hg log -r "a21ccf and ancestor(1.9)"
4672 hg log -r "a21ccf and ancestor(1.9)"
4675
4673
4676 - find all changesets by some user in a date range::
4674 - find all changesets by some user in a date range::
4677
4675
4678 hg log -k alice -d "may 2008 to jul 2008"
4676 hg log -k alice -d "may 2008 to jul 2008"
4679
4677
4680 - summary of all changesets after the last tag::
4678 - summary of all changesets after the last tag::
4681
4679
4682 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4680 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4683
4681
4684 - changesets touching lines 13 to 23 for file.c::
4682 - changesets touching lines 13 to 23 for file.c::
4685
4683
4686 hg log -L file.c,13:23
4684 hg log -L file.c,13:23
4687
4685
4688 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4686 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4689 main.c with patch::
4687 main.c with patch::
4690
4688
4691 hg log -L file.c,13:23 -L main.c,2:6 -p
4689 hg log -L file.c,13:23 -L main.c,2:6 -p
4692
4690
4693 See :hg:`help dates` for a list of formats valid for -d/--date.
4691 See :hg:`help dates` for a list of formats valid for -d/--date.
4694
4692
4695 See :hg:`help revisions` for more about specifying and ordering
4693 See :hg:`help revisions` for more about specifying and ordering
4696 revisions.
4694 revisions.
4697
4695
4698 See :hg:`help templates` for more about pre-packaged styles and
4696 See :hg:`help templates` for more about pre-packaged styles and
4699 specifying custom templates. The default template used by the log
4697 specifying custom templates. The default template used by the log
4700 command can be customized via the ``command-templates.log`` configuration
4698 command can be customized via the ``command-templates.log`` configuration
4701 setting.
4699 setting.
4702
4700
4703 Returns 0 on success.
4701 Returns 0 on success.
4704
4702
4705 """
4703 """
4706 opts = pycompat.byteskwargs(opts)
4704 opts = pycompat.byteskwargs(opts)
4707 linerange = opts.get(b'line_range')
4705 linerange = opts.get(b'line_range')
4708
4706
4709 if linerange and not opts.get(b'follow'):
4707 if linerange and not opts.get(b'follow'):
4710 raise error.InputError(_(b'--line-range requires --follow'))
4708 raise error.InputError(_(b'--line-range requires --follow'))
4711
4709
4712 if linerange and pats:
4710 if linerange and pats:
4713 # TODO: take pats as patterns with no line-range filter
4711 # TODO: take pats as patterns with no line-range filter
4714 raise error.InputError(
4712 raise error.InputError(
4715 _(b'FILE arguments are not compatible with --line-range option')
4713 _(b'FILE arguments are not compatible with --line-range option')
4716 )
4714 )
4717
4715
4718 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4716 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4719 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4717 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4720 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4718 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4721 if linerange:
4719 if linerange:
4722 # TODO: should follow file history from logcmdutil._initialrevs(),
4720 # TODO: should follow file history from logcmdutil._initialrevs(),
4723 # then filter the result by logcmdutil._makerevset() and --limit
4721 # then filter the result by logcmdutil._makerevset() and --limit
4724 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4722 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4725
4723
4726 getcopies = None
4724 getcopies = None
4727 if opts.get(b'copies'):
4725 if opts.get(b'copies'):
4728 endrev = None
4726 endrev = None
4729 if revs:
4727 if revs:
4730 endrev = revs.max() + 1
4728 endrev = revs.max() + 1
4731 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4729 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4732
4730
4733 ui.pager(b'log')
4731 ui.pager(b'log')
4734 displayer = logcmdutil.changesetdisplayer(
4732 displayer = logcmdutil.changesetdisplayer(
4735 ui, repo, opts, differ, buffered=True
4733 ui, repo, opts, differ, buffered=True
4736 )
4734 )
4737 if opts.get(b'graph'):
4735 if opts.get(b'graph'):
4738 displayfn = logcmdutil.displaygraphrevs
4736 displayfn = logcmdutil.displaygraphrevs
4739 else:
4737 else:
4740 displayfn = logcmdutil.displayrevs
4738 displayfn = logcmdutil.displayrevs
4741 displayfn(ui, repo, revs, displayer, getcopies)
4739 displayfn(ui, repo, revs, displayer, getcopies)
4742
4740
4743
4741
4744 @command(
4742 @command(
4745 b'manifest',
4743 b'manifest',
4746 [
4744 [
4747 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4745 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4748 (b'', b'all', False, _(b"list files from all revisions")),
4746 (b'', b'all', False, _(b"list files from all revisions")),
4749 ]
4747 ]
4750 + formatteropts,
4748 + formatteropts,
4751 _(b'[-r REV]'),
4749 _(b'[-r REV]'),
4752 helpcategory=command.CATEGORY_MAINTENANCE,
4750 helpcategory=command.CATEGORY_MAINTENANCE,
4753 intents={INTENT_READONLY},
4751 intents={INTENT_READONLY},
4754 )
4752 )
4755 def manifest(ui, repo, node=None, rev=None, **opts):
4753 def manifest(ui, repo, node=None, rev=None, **opts):
4756 """output the current or given revision of the project manifest
4754 """output the current or given revision of the project manifest
4757
4755
4758 Print a list of version controlled files for the given revision.
4756 Print a list of version controlled files for the given revision.
4759 If no revision is given, the first parent of the working directory
4757 If no revision is given, the first parent of the working directory
4760 is used, or the null revision if no revision is checked out.
4758 is used, or the null revision if no revision is checked out.
4761
4759
4762 With -v, print file permissions, symlink and executable bits.
4760 With -v, print file permissions, symlink and executable bits.
4763 With --debug, print file revision hashes.
4761 With --debug, print file revision hashes.
4764
4762
4765 If option --all is specified, the list of all files from all revisions
4763 If option --all is specified, the list of all files from all revisions
4766 is printed. This includes deleted and renamed files.
4764 is printed. This includes deleted and renamed files.
4767
4765
4768 Returns 0 on success.
4766 Returns 0 on success.
4769 """
4767 """
4770 opts = pycompat.byteskwargs(opts)
4768 opts = pycompat.byteskwargs(opts)
4771 fm = ui.formatter(b'manifest', opts)
4769 fm = ui.formatter(b'manifest', opts)
4772
4770
4773 if opts.get(b'all'):
4771 if opts.get(b'all'):
4774 if rev or node:
4772 if rev or node:
4775 raise error.InputError(_(b"can't specify a revision with --all"))
4773 raise error.InputError(_(b"can't specify a revision with --all"))
4776
4774
4777 res = set()
4775 res = set()
4778 for rev in repo:
4776 for rev in repo:
4779 ctx = repo[rev]
4777 ctx = repo[rev]
4780 res |= set(ctx.files())
4778 res |= set(ctx.files())
4781
4779
4782 ui.pager(b'manifest')
4780 ui.pager(b'manifest')
4783 for f in sorted(res):
4781 for f in sorted(res):
4784 fm.startitem()
4782 fm.startitem()
4785 fm.write(b"path", b'%s\n', f)
4783 fm.write(b"path", b'%s\n', f)
4786 fm.end()
4784 fm.end()
4787 return
4785 return
4788
4786
4789 if rev and node:
4787 if rev and node:
4790 raise error.InputError(_(b"please specify just one revision"))
4788 raise error.InputError(_(b"please specify just one revision"))
4791
4789
4792 if not node:
4790 if not node:
4793 node = rev
4791 node = rev
4794
4792
4795 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4793 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4796 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4794 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4797 if node:
4795 if node:
4798 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4796 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4799 ctx = logcmdutil.revsingle(repo, node)
4797 ctx = logcmdutil.revsingle(repo, node)
4800 mf = ctx.manifest()
4798 mf = ctx.manifest()
4801 ui.pager(b'manifest')
4799 ui.pager(b'manifest')
4802 for f in ctx:
4800 for f in ctx:
4803 fm.startitem()
4801 fm.startitem()
4804 fm.context(ctx=ctx)
4802 fm.context(ctx=ctx)
4805 fl = ctx[f].flags()
4803 fl = ctx[f].flags()
4806 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4804 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4807 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4805 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4808 fm.write(b'path', b'%s\n', f)
4806 fm.write(b'path', b'%s\n', f)
4809 fm.end()
4807 fm.end()
4810
4808
4811
4809
4812 @command(
4810 @command(
4813 b'merge',
4811 b'merge',
4814 [
4812 [
4815 (
4813 (
4816 b'f',
4814 b'f',
4817 b'force',
4815 b'force',
4818 None,
4816 None,
4819 _(b'force a merge including outstanding changes (DEPRECATED)'),
4817 _(b'force a merge including outstanding changes (DEPRECATED)'),
4820 ),
4818 ),
4821 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4819 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4822 (
4820 (
4823 b'P',
4821 b'P',
4824 b'preview',
4822 b'preview',
4825 None,
4823 None,
4826 _(b'review revisions to merge (no merge is performed)'),
4824 _(b'review revisions to merge (no merge is performed)'),
4827 ),
4825 ),
4828 (b'', b'abort', None, _(b'abort the ongoing merge')),
4826 (b'', b'abort', None, _(b'abort the ongoing merge')),
4829 ]
4827 ]
4830 + mergetoolopts,
4828 + mergetoolopts,
4831 _(b'[-P] [[-r] REV]'),
4829 _(b'[-P] [[-r] REV]'),
4832 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4830 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4833 helpbasic=True,
4831 helpbasic=True,
4834 )
4832 )
4835 def merge(ui, repo, node=None, **opts):
4833 def merge(ui, repo, node=None, **opts):
4836 """merge another revision into working directory
4834 """merge another revision into working directory
4837
4835
4838 The current working directory is updated with all changes made in
4836 The current working directory is updated with all changes made in
4839 the requested revision since the last common predecessor revision.
4837 the requested revision since the last common predecessor revision.
4840
4838
4841 Files that changed between either parent are marked as changed for
4839 Files that changed between either parent are marked as changed for
4842 the next commit and a commit must be performed before any further
4840 the next commit and a commit must be performed before any further
4843 updates to the repository are allowed. The next commit will have
4841 updates to the repository are allowed. The next commit will have
4844 two parents.
4842 two parents.
4845
4843
4846 ``--tool`` can be used to specify the merge tool used for file
4844 ``--tool`` can be used to specify the merge tool used for file
4847 merges. It overrides the HGMERGE environment variable and your
4845 merges. It overrides the HGMERGE environment variable and your
4848 configuration files. See :hg:`help merge-tools` for options.
4846 configuration files. See :hg:`help merge-tools` for options.
4849
4847
4850 If no revision is specified, the working directory's parent is a
4848 If no revision is specified, the working directory's parent is a
4851 head revision, and the current branch contains exactly one other
4849 head revision, and the current branch contains exactly one other
4852 head, the other head is merged with by default. Otherwise, an
4850 head, the other head is merged with by default. Otherwise, an
4853 explicit revision with which to merge must be provided.
4851 explicit revision with which to merge must be provided.
4854
4852
4855 See :hg:`help resolve` for information on handling file conflicts.
4853 See :hg:`help resolve` for information on handling file conflicts.
4856
4854
4857 To undo an uncommitted merge, use :hg:`merge --abort` which
4855 To undo an uncommitted merge, use :hg:`merge --abort` which
4858 will check out a clean copy of the original merge parent, losing
4856 will check out a clean copy of the original merge parent, losing
4859 all changes.
4857 all changes.
4860
4858
4861 Returns 0 on success, 1 if there are unresolved files.
4859 Returns 0 on success, 1 if there are unresolved files.
4862 """
4860 """
4863
4861
4864 opts = pycompat.byteskwargs(opts)
4862 opts = pycompat.byteskwargs(opts)
4865 abort = opts.get(b'abort')
4863 abort = opts.get(b'abort')
4866 if abort and repo.dirstate.p2() == repo.nullid:
4864 if abort and repo.dirstate.p2() == repo.nullid:
4867 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4865 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4868 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4866 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4869 if abort:
4867 if abort:
4870 state = cmdutil.getunfinishedstate(repo)
4868 state = cmdutil.getunfinishedstate(repo)
4871 if state and state._opname != b'merge':
4869 if state and state._opname != b'merge':
4872 raise error.StateError(
4870 raise error.StateError(
4873 _(b'cannot abort merge with %s in progress') % (state._opname),
4871 _(b'cannot abort merge with %s in progress') % (state._opname),
4874 hint=state.hint(),
4872 hint=state.hint(),
4875 )
4873 )
4876 if node:
4874 if node:
4877 raise error.InputError(_(b"cannot specify a node with --abort"))
4875 raise error.InputError(_(b"cannot specify a node with --abort"))
4878 return hg.abortmerge(repo.ui, repo)
4876 return hg.abortmerge(repo.ui, repo)
4879
4877
4880 if opts.get(b'rev') and node:
4878 if opts.get(b'rev') and node:
4881 raise error.InputError(_(b"please specify just one revision"))
4879 raise error.InputError(_(b"please specify just one revision"))
4882 if not node:
4880 if not node:
4883 node = opts.get(b'rev')
4881 node = opts.get(b'rev')
4884
4882
4885 if node:
4883 if node:
4886 ctx = logcmdutil.revsingle(repo, node)
4884 ctx = logcmdutil.revsingle(repo, node)
4887 else:
4885 else:
4888 if ui.configbool(b'commands', b'merge.require-rev'):
4886 if ui.configbool(b'commands', b'merge.require-rev'):
4889 raise error.InputError(
4887 raise error.InputError(
4890 _(
4888 _(
4891 b'configuration requires specifying revision to merge '
4889 b'configuration requires specifying revision to merge '
4892 b'with'
4890 b'with'
4893 )
4891 )
4894 )
4892 )
4895 ctx = repo[destutil.destmerge(repo)]
4893 ctx = repo[destutil.destmerge(repo)]
4896
4894
4897 if ctx.node() is None:
4895 if ctx.node() is None:
4898 raise error.InputError(
4896 raise error.InputError(
4899 _(b'merging with the working copy has no effect')
4897 _(b'merging with the working copy has no effect')
4900 )
4898 )
4901
4899
4902 if opts.get(b'preview'):
4900 if opts.get(b'preview'):
4903 # find nodes that are ancestors of p2 but not of p1
4901 # find nodes that are ancestors of p2 but not of p1
4904 p1 = repo[b'.'].node()
4902 p1 = repo[b'.'].node()
4905 p2 = ctx.node()
4903 p2 = ctx.node()
4906 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4904 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4907
4905
4908 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4906 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4909 for node in nodes:
4907 for node in nodes:
4910 displayer.show(repo[node])
4908 displayer.show(repo[node])
4911 displayer.close()
4909 displayer.close()
4912 return 0
4910 return 0
4913
4911
4914 # ui.forcemerge is an internal variable, do not document
4912 # ui.forcemerge is an internal variable, do not document
4915 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4913 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4916 with ui.configoverride(overrides, b'merge'):
4914 with ui.configoverride(overrides, b'merge'):
4917 force = opts.get(b'force')
4915 force = opts.get(b'force')
4918 labels = [b'working copy', b'merge rev', b'common ancestor']
4916 labels = [b'working copy', b'merge rev', b'common ancestor']
4919 return hg.merge(ctx, force=force, labels=labels)
4917 return hg.merge(ctx, force=force, labels=labels)
4920
4918
4921
4919
4922 statemod.addunfinished(
4920 statemod.addunfinished(
4923 b'merge',
4921 b'merge',
4924 fname=None,
4922 fname=None,
4925 clearable=True,
4923 clearable=True,
4926 allowcommit=True,
4924 allowcommit=True,
4927 cmdmsg=_(b'outstanding uncommitted merge'),
4925 cmdmsg=_(b'outstanding uncommitted merge'),
4928 abortfunc=hg.abortmerge,
4926 abortfunc=hg.abortmerge,
4929 statushint=_(
4927 statushint=_(
4930 b'To continue: hg commit\nTo abort: hg merge --abort'
4928 b'To continue: hg commit\nTo abort: hg merge --abort'
4931 ),
4929 ),
4932 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4930 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4933 )
4931 )
4934
4932
4935
4933
4936 @command(
4934 @command(
4937 b'outgoing|out',
4935 b'outgoing|out',
4938 [
4936 [
4939 (
4937 (
4940 b'f',
4938 b'f',
4941 b'force',
4939 b'force',
4942 None,
4940 None,
4943 _(b'run even when the destination is unrelated'),
4941 _(b'run even when the destination is unrelated'),
4944 ),
4942 ),
4945 (
4943 (
4946 b'r',
4944 b'r',
4947 b'rev',
4945 b'rev',
4948 [],
4946 [],
4949 _(b'a changeset intended to be included in the destination'),
4947 _(b'a changeset intended to be included in the destination'),
4950 _(b'REV'),
4948 _(b'REV'),
4951 ),
4949 ),
4952 (b'n', b'newest-first', None, _(b'show newest record first')),
4950 (b'n', b'newest-first', None, _(b'show newest record first')),
4953 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4951 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4954 (
4952 (
4955 b'b',
4953 b'b',
4956 b'branch',
4954 b'branch',
4957 [],
4955 [],
4958 _(b'a specific branch you would like to push'),
4956 _(b'a specific branch you would like to push'),
4959 _(b'BRANCH'),
4957 _(b'BRANCH'),
4960 ),
4958 ),
4961 ]
4959 ]
4962 + logopts
4960 + logopts
4963 + remoteopts
4961 + remoteopts
4964 + subrepoopts,
4962 + subrepoopts,
4965 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4963 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4966 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4964 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4967 )
4965 )
4968 def outgoing(ui, repo, *dests, **opts):
4966 def outgoing(ui, repo, *dests, **opts):
4969 """show changesets not found in the destination
4967 """show changesets not found in the destination
4970
4968
4971 Show changesets not found in the specified destination repository
4969 Show changesets not found in the specified destination repository
4972 or the default push location. These are the changesets that would
4970 or the default push location. These are the changesets that would
4973 be pushed if a push was requested.
4971 be pushed if a push was requested.
4974
4972
4975 See pull for details of valid destination formats.
4973 See pull for details of valid destination formats.
4976
4974
4977 .. container:: verbose
4975 .. container:: verbose
4978
4976
4979 With -B/--bookmarks, the result of bookmark comparison between
4977 With -B/--bookmarks, the result of bookmark comparison between
4980 local and remote repositories is displayed. With -v/--verbose,
4978 local and remote repositories is displayed. With -v/--verbose,
4981 status is also displayed for each bookmark like below::
4979 status is also displayed for each bookmark like below::
4982
4980
4983 BM1 01234567890a added
4981 BM1 01234567890a added
4984 BM2 deleted
4982 BM2 deleted
4985 BM3 234567890abc advanced
4983 BM3 234567890abc advanced
4986 BM4 34567890abcd diverged
4984 BM4 34567890abcd diverged
4987 BM5 4567890abcde changed
4985 BM5 4567890abcde changed
4988
4986
4989 The action taken when pushing depends on the
4987 The action taken when pushing depends on the
4990 status of each bookmark:
4988 status of each bookmark:
4991
4989
4992 :``added``: push with ``-B`` will create it
4990 :``added``: push with ``-B`` will create it
4993 :``deleted``: push with ``-B`` will delete it
4991 :``deleted``: push with ``-B`` will delete it
4994 :``advanced``: push will update it
4992 :``advanced``: push will update it
4995 :``diverged``: push with ``-B`` will update it
4993 :``diverged``: push with ``-B`` will update it
4996 :``changed``: push with ``-B`` will update it
4994 :``changed``: push with ``-B`` will update it
4997
4995
4998 From the point of view of pushing behavior, bookmarks
4996 From the point of view of pushing behavior, bookmarks
4999 existing only in the remote repository are treated as
4997 existing only in the remote repository are treated as
5000 ``deleted``, even if it is in fact added remotely.
4998 ``deleted``, even if it is in fact added remotely.
5001
4999
5002 Returns 0 if there are outgoing changes, 1 otherwise.
5000 Returns 0 if there are outgoing changes, 1 otherwise.
5003 """
5001 """
5004 opts = pycompat.byteskwargs(opts)
5002 opts = pycompat.byteskwargs(opts)
5005 if opts.get(b'bookmarks'):
5003 if opts.get(b'bookmarks'):
5006 for path in urlutil.get_push_paths(repo, ui, dests):
5004 for path in urlutil.get_push_paths(repo, ui, dests):
5007 dest = path.pushloc or path.loc
5005 dest = path.pushloc or path.loc
5008 other = hg.peer(repo, opts, dest)
5006 other = hg.peer(repo, opts, dest)
5009 try:
5007 try:
5010 if b'bookmarks' not in other.listkeys(b'namespaces'):
5008 if b'bookmarks' not in other.listkeys(b'namespaces'):
5011 ui.warn(_(b"remote doesn't support bookmarks\n"))
5009 ui.warn(_(b"remote doesn't support bookmarks\n"))
5012 return 0
5010 return 0
5013 ui.status(
5011 ui.status(
5014 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5012 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5015 )
5013 )
5016 ui.pager(b'outgoing')
5014 ui.pager(b'outgoing')
5017 return bookmarks.outgoing(ui, repo, other)
5015 return bookmarks.outgoing(ui, repo, other)
5018 finally:
5016 finally:
5019 other.close()
5017 other.close()
5020
5018
5021 return hg.outgoing(ui, repo, dests, opts)
5019 return hg.outgoing(ui, repo, dests, opts)
5022
5020
5023
5021
5024 @command(
5022 @command(
5025 b'parents',
5023 b'parents',
5026 [
5024 [
5027 (
5025 (
5028 b'r',
5026 b'r',
5029 b'rev',
5027 b'rev',
5030 b'',
5028 b'',
5031 _(b'show parents of the specified revision'),
5029 _(b'show parents of the specified revision'),
5032 _(b'REV'),
5030 _(b'REV'),
5033 ),
5031 ),
5034 ]
5032 ]
5035 + templateopts,
5033 + templateopts,
5036 _(b'[-r REV] [FILE]'),
5034 _(b'[-r REV] [FILE]'),
5037 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5035 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5038 inferrepo=True,
5036 inferrepo=True,
5039 )
5037 )
5040 def parents(ui, repo, file_=None, **opts):
5038 def parents(ui, repo, file_=None, **opts):
5041 """show the parents of the working directory or revision (DEPRECATED)
5039 """show the parents of the working directory or revision (DEPRECATED)
5042
5040
5043 Print the working directory's parent revisions. If a revision is
5041 Print the working directory's parent revisions. If a revision is
5044 given via -r/--rev, the parent of that revision will be printed.
5042 given via -r/--rev, the parent of that revision will be printed.
5045 If a file argument is given, the revision in which the file was
5043 If a file argument is given, the revision in which the file was
5046 last changed (before the working directory revision or the
5044 last changed (before the working directory revision or the
5047 argument to --rev if given) is printed.
5045 argument to --rev if given) is printed.
5048
5046
5049 This command is equivalent to::
5047 This command is equivalent to::
5050
5048
5051 hg log -r "p1()+p2()" or
5049 hg log -r "p1()+p2()" or
5052 hg log -r "p1(REV)+p2(REV)" or
5050 hg log -r "p1(REV)+p2(REV)" or
5053 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5051 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5054 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5052 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5055
5053
5056 See :hg:`summary` and :hg:`help revsets` for related information.
5054 See :hg:`summary` and :hg:`help revsets` for related information.
5057
5055
5058 Returns 0 on success.
5056 Returns 0 on success.
5059 """
5057 """
5060
5058
5061 opts = pycompat.byteskwargs(opts)
5059 opts = pycompat.byteskwargs(opts)
5062 rev = opts.get(b'rev')
5060 rev = opts.get(b'rev')
5063 if rev:
5061 if rev:
5064 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5062 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5065 ctx = logcmdutil.revsingle(repo, rev, None)
5063 ctx = logcmdutil.revsingle(repo, rev, None)
5066
5064
5067 if file_:
5065 if file_:
5068 m = scmutil.match(ctx, (file_,), opts)
5066 m = scmutil.match(ctx, (file_,), opts)
5069 if m.anypats() or len(m.files()) != 1:
5067 if m.anypats() or len(m.files()) != 1:
5070 raise error.InputError(_(b'can only specify an explicit filename'))
5068 raise error.InputError(_(b'can only specify an explicit filename'))
5071 file_ = m.files()[0]
5069 file_ = m.files()[0]
5072 filenodes = []
5070 filenodes = []
5073 for cp in ctx.parents():
5071 for cp in ctx.parents():
5074 if not cp:
5072 if not cp:
5075 continue
5073 continue
5076 try:
5074 try:
5077 filenodes.append(cp.filenode(file_))
5075 filenodes.append(cp.filenode(file_))
5078 except error.LookupError:
5076 except error.LookupError:
5079 pass
5077 pass
5080 if not filenodes:
5078 if not filenodes:
5081 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5079 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5082 p = []
5080 p = []
5083 for fn in filenodes:
5081 for fn in filenodes:
5084 fctx = repo.filectx(file_, fileid=fn)
5082 fctx = repo.filectx(file_, fileid=fn)
5085 p.append(fctx.node())
5083 p.append(fctx.node())
5086 else:
5084 else:
5087 p = [cp.node() for cp in ctx.parents()]
5085 p = [cp.node() for cp in ctx.parents()]
5088
5086
5089 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5087 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5090 for n in p:
5088 for n in p:
5091 if n != repo.nullid:
5089 if n != repo.nullid:
5092 displayer.show(repo[n])
5090 displayer.show(repo[n])
5093 displayer.close()
5091 displayer.close()
5094
5092
5095
5093
5096 @command(
5094 @command(
5097 b'paths',
5095 b'paths',
5098 formatteropts,
5096 formatteropts,
5099 _(b'[NAME]'),
5097 _(b'[NAME]'),
5100 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5098 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5101 optionalrepo=True,
5099 optionalrepo=True,
5102 intents={INTENT_READONLY},
5100 intents={INTENT_READONLY},
5103 )
5101 )
5104 def paths(ui, repo, search=None, **opts):
5102 def paths(ui, repo, search=None, **opts):
5105 """show aliases for remote repositories
5103 """show aliases for remote repositories
5106
5104
5107 Show definition of symbolic path name NAME. If no name is given,
5105 Show definition of symbolic path name NAME. If no name is given,
5108 show definition of all available names.
5106 show definition of all available names.
5109
5107
5110 Option -q/--quiet suppresses all output when searching for NAME
5108 Option -q/--quiet suppresses all output when searching for NAME
5111 and shows only the path names when listing all definitions.
5109 and shows only the path names when listing all definitions.
5112
5110
5113 Path names are defined in the [paths] section of your
5111 Path names are defined in the [paths] section of your
5114 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5112 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5115 repository, ``.hg/hgrc`` is used, too.
5113 repository, ``.hg/hgrc`` is used, too.
5116
5114
5117 The path names ``default`` and ``default-push`` have a special
5115 The path names ``default`` and ``default-push`` have a special
5118 meaning. When performing a push or pull operation, they are used
5116 meaning. When performing a push or pull operation, they are used
5119 as fallbacks if no location is specified on the command-line.
5117 as fallbacks if no location is specified on the command-line.
5120 When ``default-push`` is set, it will be used for push and
5118 When ``default-push`` is set, it will be used for push and
5121 ``default`` will be used for pull; otherwise ``default`` is used
5119 ``default`` will be used for pull; otherwise ``default`` is used
5122 as the fallback for both. When cloning a repository, the clone
5120 as the fallback for both. When cloning a repository, the clone
5123 source is written as ``default`` in ``.hg/hgrc``.
5121 source is written as ``default`` in ``.hg/hgrc``.
5124
5122
5125 .. note::
5123 .. note::
5126
5124
5127 ``default`` and ``default-push`` apply to all inbound (e.g.
5125 ``default`` and ``default-push`` apply to all inbound (e.g.
5128 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5126 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5129 and :hg:`bundle`) operations.
5127 and :hg:`bundle`) operations.
5130
5128
5131 See :hg:`help urls` for more information.
5129 See :hg:`help urls` for more information.
5132
5130
5133 .. container:: verbose
5131 .. container:: verbose
5134
5132
5135 Template:
5133 Template:
5136
5134
5137 The following keywords are supported. See also :hg:`help templates`.
5135 The following keywords are supported. See also :hg:`help templates`.
5138
5136
5139 :name: String. Symbolic name of the path alias.
5137 :name: String. Symbolic name of the path alias.
5140 :pushurl: String. URL for push operations.
5138 :pushurl: String. URL for push operations.
5141 :url: String. URL or directory path for the other operations.
5139 :url: String. URL or directory path for the other operations.
5142
5140
5143 Returns 0 on success.
5141 Returns 0 on success.
5144 """
5142 """
5145
5143
5146 opts = pycompat.byteskwargs(opts)
5144 opts = pycompat.byteskwargs(opts)
5147
5145
5148 pathitems = urlutil.list_paths(ui, search)
5146 pathitems = urlutil.list_paths(ui, search)
5149 ui.pager(b'paths')
5147 ui.pager(b'paths')
5150
5148
5151 fm = ui.formatter(b'paths', opts)
5149 fm = ui.formatter(b'paths', opts)
5152 if fm.isplain():
5150 if fm.isplain():
5153 hidepassword = urlutil.hidepassword
5151 hidepassword = urlutil.hidepassword
5154 else:
5152 else:
5155 hidepassword = bytes
5153 hidepassword = bytes
5156 if ui.quiet:
5154 if ui.quiet:
5157 namefmt = b'%s\n'
5155 namefmt = b'%s\n'
5158 else:
5156 else:
5159 namefmt = b'%s = '
5157 namefmt = b'%s = '
5160 showsubopts = not search and not ui.quiet
5158 showsubopts = not search and not ui.quiet
5161
5159
5162 for name, path in pathitems:
5160 for name, path in pathitems:
5163 fm.startitem()
5161 fm.startitem()
5164 fm.condwrite(not search, b'name', namefmt, name)
5162 fm.condwrite(not search, b'name', namefmt, name)
5165 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5163 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5166 for subopt, value in sorted(path.suboptions.items()):
5164 for subopt, value in sorted(path.suboptions.items()):
5167 assert subopt not in (b'name', b'url')
5165 assert subopt not in (b'name', b'url')
5168 if showsubopts:
5166 if showsubopts:
5169 fm.plain(b'%s:%s = ' % (name, subopt))
5167 fm.plain(b'%s:%s = ' % (name, subopt))
5170 if isinstance(value, bool):
5168 if isinstance(value, bool):
5171 if value:
5169 if value:
5172 value = b'yes'
5170 value = b'yes'
5173 else:
5171 else:
5174 value = b'no'
5172 value = b'no'
5175 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5173 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5176
5174
5177 fm.end()
5175 fm.end()
5178
5176
5179 if search and not pathitems:
5177 if search and not pathitems:
5180 if not ui.quiet:
5178 if not ui.quiet:
5181 ui.warn(_(b"not found!\n"))
5179 ui.warn(_(b"not found!\n"))
5182 return 1
5180 return 1
5183 else:
5181 else:
5184 return 0
5182 return 0
5185
5183
5186
5184
5187 @command(
5185 @command(
5188 b'phase',
5186 b'phase',
5189 [
5187 [
5190 (b'p', b'public', False, _(b'set changeset phase to public')),
5188 (b'p', b'public', False, _(b'set changeset phase to public')),
5191 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5189 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5192 (b's', b'secret', False, _(b'set changeset phase to secret')),
5190 (b's', b'secret', False, _(b'set changeset phase to secret')),
5193 (b'f', b'force', False, _(b'allow to move boundary backward')),
5191 (b'f', b'force', False, _(b'allow to move boundary backward')),
5194 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5192 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5195 ],
5193 ],
5196 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5194 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5197 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5195 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5198 )
5196 )
5199 def phase(ui, repo, *revs, **opts):
5197 def phase(ui, repo, *revs, **opts):
5200 """set or show the current phase name
5198 """set or show the current phase name
5201
5199
5202 With no argument, show the phase name of the current revision(s).
5200 With no argument, show the phase name of the current revision(s).
5203
5201
5204 With one of -p/--public, -d/--draft or -s/--secret, change the
5202 With one of -p/--public, -d/--draft or -s/--secret, change the
5205 phase value of the specified revisions.
5203 phase value of the specified revisions.
5206
5204
5207 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5205 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5208 lower phase to a higher phase. Phases are ordered as follows::
5206 lower phase to a higher phase. Phases are ordered as follows::
5209
5207
5210 public < draft < secret
5208 public < draft < secret
5211
5209
5212 Returns 0 on success, 1 if some phases could not be changed.
5210 Returns 0 on success, 1 if some phases could not be changed.
5213
5211
5214 (For more information about the phases concept, see :hg:`help phases`.)
5212 (For more information about the phases concept, see :hg:`help phases`.)
5215 """
5213 """
5216 opts = pycompat.byteskwargs(opts)
5214 opts = pycompat.byteskwargs(opts)
5217 # search for a unique phase argument
5215 # search for a unique phase argument
5218 targetphase = None
5216 targetphase = None
5219 for idx, name in enumerate(phases.cmdphasenames):
5217 for idx, name in enumerate(phases.cmdphasenames):
5220 if opts[name]:
5218 if opts[name]:
5221 if targetphase is not None:
5219 if targetphase is not None:
5222 raise error.InputError(_(b'only one phase can be specified'))
5220 raise error.InputError(_(b'only one phase can be specified'))
5223 targetphase = idx
5221 targetphase = idx
5224
5222
5225 # look for specified revision
5223 # look for specified revision
5226 revs = list(revs)
5224 revs = list(revs)
5227 revs.extend(opts[b'rev'])
5225 revs.extend(opts[b'rev'])
5228 if revs:
5226 if revs:
5229 revs = logcmdutil.revrange(repo, revs)
5227 revs = logcmdutil.revrange(repo, revs)
5230 else:
5228 else:
5231 # display both parents as the second parent phase can influence
5229 # display both parents as the second parent phase can influence
5232 # the phase of a merge commit
5230 # the phase of a merge commit
5233 revs = [c.rev() for c in repo[None].parents()]
5231 revs = [c.rev() for c in repo[None].parents()]
5234
5232
5235 ret = 0
5233 ret = 0
5236 if targetphase is None:
5234 if targetphase is None:
5237 # display
5235 # display
5238 for r in revs:
5236 for r in revs:
5239 ctx = repo[r]
5237 ctx = repo[r]
5240 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5238 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5241 else:
5239 else:
5242 with repo.lock(), repo.transaction(b"phase") as tr:
5240 with repo.lock(), repo.transaction(b"phase") as tr:
5243 # set phase
5241 # set phase
5244 if not revs:
5242 if not revs:
5245 raise error.InputError(_(b'empty revision set'))
5243 raise error.InputError(_(b'empty revision set'))
5246 nodes = [repo[r].node() for r in revs]
5244 nodes = [repo[r].node() for r in revs]
5247 # moving revision from public to draft may hide them
5245 # moving revision from public to draft may hide them
5248 # We have to check result on an unfiltered repository
5246 # We have to check result on an unfiltered repository
5249 unfi = repo.unfiltered()
5247 unfi = repo.unfiltered()
5250 getphase = unfi._phasecache.phase
5248 getphase = unfi._phasecache.phase
5251 olddata = [getphase(unfi, r) for r in unfi]
5249 olddata = [getphase(unfi, r) for r in unfi]
5252 phases.advanceboundary(repo, tr, targetphase, nodes)
5250 phases.advanceboundary(repo, tr, targetphase, nodes)
5253 if opts[b'force']:
5251 if opts[b'force']:
5254 phases.retractboundary(repo, tr, targetphase, nodes)
5252 phases.retractboundary(repo, tr, targetphase, nodes)
5255 getphase = unfi._phasecache.phase
5253 getphase = unfi._phasecache.phase
5256 newdata = [getphase(unfi, r) for r in unfi]
5254 newdata = [getphase(unfi, r) for r in unfi]
5257 changes = sum(newdata[r] != olddata[r] for r in unfi)
5255 changes = sum(newdata[r] != olddata[r] for r in unfi)
5258 cl = unfi.changelog
5256 cl = unfi.changelog
5259 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5257 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5260 if rejected:
5258 if rejected:
5261 ui.warn(
5259 ui.warn(
5262 _(
5260 _(
5263 b'cannot move %i changesets to a higher '
5261 b'cannot move %i changesets to a higher '
5264 b'phase, use --force\n'
5262 b'phase, use --force\n'
5265 )
5263 )
5266 % len(rejected)
5264 % len(rejected)
5267 )
5265 )
5268 ret = 1
5266 ret = 1
5269 if changes:
5267 if changes:
5270 msg = _(b'phase changed for %i changesets\n') % changes
5268 msg = _(b'phase changed for %i changesets\n') % changes
5271 if ret:
5269 if ret:
5272 ui.status(msg)
5270 ui.status(msg)
5273 else:
5271 else:
5274 ui.note(msg)
5272 ui.note(msg)
5275 else:
5273 else:
5276 ui.warn(_(b'no phases changed\n'))
5274 ui.warn(_(b'no phases changed\n'))
5277 return ret
5275 return ret
5278
5276
5279
5277
5280 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5278 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5281 """Run after a changegroup has been added via pull/unbundle
5279 """Run after a changegroup has been added via pull/unbundle
5282
5280
5283 This takes arguments below:
5281 This takes arguments below:
5284
5282
5285 :modheads: change of heads by pull/unbundle
5283 :modheads: change of heads by pull/unbundle
5286 :optupdate: updating working directory is needed or not
5284 :optupdate: updating working directory is needed or not
5287 :checkout: update destination revision (or None to default destination)
5285 :checkout: update destination revision (or None to default destination)
5288 :brev: a name, which might be a bookmark to be activated after updating
5286 :brev: a name, which might be a bookmark to be activated after updating
5289
5287
5290 return True if update raise any conflict, False otherwise.
5288 return True if update raise any conflict, False otherwise.
5291 """
5289 """
5292 if modheads == 0:
5290 if modheads == 0:
5293 return False
5291 return False
5294 if optupdate:
5292 if optupdate:
5295 try:
5293 try:
5296 return hg.updatetotally(ui, repo, checkout, brev)
5294 return hg.updatetotally(ui, repo, checkout, brev)
5297 except error.UpdateAbort as inst:
5295 except error.UpdateAbort as inst:
5298 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5296 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5299 hint = inst.hint
5297 hint = inst.hint
5300 raise error.UpdateAbort(msg, hint=hint)
5298 raise error.UpdateAbort(msg, hint=hint)
5301 if modheads is not None and modheads > 1:
5299 if modheads is not None and modheads > 1:
5302 currentbranchheads = len(repo.branchheads())
5300 currentbranchheads = len(repo.branchheads())
5303 if currentbranchheads == modheads:
5301 if currentbranchheads == modheads:
5304 ui.status(
5302 ui.status(
5305 _(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")
5306 )
5304 )
5307 elif currentbranchheads > 1:
5305 elif currentbranchheads > 1:
5308 ui.status(
5306 ui.status(
5309 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5307 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5310 )
5308 )
5311 else:
5309 else:
5312 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5310 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5313 elif not ui.configbool(b'commands', b'update.requiredest'):
5311 elif not ui.configbool(b'commands', b'update.requiredest'):
5314 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5312 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5315 return False
5313 return False
5316
5314
5317
5315
5318 @command(
5316 @command(
5319 b'pull',
5317 b'pull',
5320 [
5318 [
5321 (
5319 (
5322 b'u',
5320 b'u',
5323 b'update',
5321 b'update',
5324 None,
5322 None,
5325 _(b'update to new branch head if new descendants were pulled'),
5323 _(b'update to new branch head if new descendants were pulled'),
5326 ),
5324 ),
5327 (
5325 (
5328 b'f',
5326 b'f',
5329 b'force',
5327 b'force',
5330 None,
5328 None,
5331 _(b'run even when remote repository is unrelated'),
5329 _(b'run even when remote repository is unrelated'),
5332 ),
5330 ),
5333 (
5331 (
5334 b'',
5332 b'',
5335 b'confirm',
5333 b'confirm',
5336 None,
5334 None,
5337 _(b'confirm pull before applying changes'),
5335 _(b'confirm pull before applying changes'),
5338 ),
5336 ),
5339 (
5337 (
5340 b'r',
5338 b'r',
5341 b'rev',
5339 b'rev',
5342 [],
5340 [],
5343 _(b'a remote changeset intended to be added'),
5341 _(b'a remote changeset intended to be added'),
5344 _(b'REV'),
5342 _(b'REV'),
5345 ),
5343 ),
5346 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5344 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5347 (
5345 (
5348 b'b',
5346 b'b',
5349 b'branch',
5347 b'branch',
5350 [],
5348 [],
5351 _(b'a specific branch you would like to pull'),
5349 _(b'a specific branch you would like to pull'),
5352 _(b'BRANCH'),
5350 _(b'BRANCH'),
5353 ),
5351 ),
5354 ]
5352 ]
5355 + remoteopts,
5353 + remoteopts,
5356 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5354 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5357 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5355 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5358 helpbasic=True,
5356 helpbasic=True,
5359 )
5357 )
5360 def pull(ui, repo, *sources, **opts):
5358 def pull(ui, repo, *sources, **opts):
5361 """pull changes from the specified source
5359 """pull changes from the specified source
5362
5360
5363 Pull changes from a remote repository to a local one.
5361 Pull changes from a remote repository to a local one.
5364
5362
5365 This finds all changes from the repository at the specified path
5363 This finds all changes from the repository at the specified path
5366 or URL and adds them to a local repository (the current one unless
5364 or URL and adds them to a local repository (the current one unless
5367 -R is specified). By default, this does not update the copy of the
5365 -R is specified). By default, this does not update the copy of the
5368 project in the working directory.
5366 project in the working directory.
5369
5367
5370 When cloning from servers that support it, Mercurial may fetch
5368 When cloning from servers that support it, Mercurial may fetch
5371 pre-generated data. When this is done, hooks operating on incoming
5369 pre-generated data. When this is done, hooks operating on incoming
5372 changesets and changegroups may fire more than once, once for each
5370 changesets and changegroups may fire more than once, once for each
5373 pre-generated bundle and as well as for any additional remaining
5371 pre-generated bundle and as well as for any additional remaining
5374 data. See :hg:`help -e clonebundles` for more.
5372 data. See :hg:`help -e clonebundles` for more.
5375
5373
5376 Use :hg:`incoming` if you want to see what would have been added
5374 Use :hg:`incoming` if you want to see what would have been added
5377 by a pull at the time you issued this command. If you then decide
5375 by a pull at the time you issued this command. If you then decide
5378 to add those changes to the repository, you should use :hg:`pull
5376 to add those changes to the repository, you should use :hg:`pull
5379 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5377 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5380
5378
5381 If SOURCE is omitted, the 'default' path will be used.
5379 If SOURCE is omitted, the 'default' path will be used.
5382 See :hg:`help urls` for more information.
5380 See :hg:`help urls` for more information.
5383
5381
5384 If multiple sources are specified, they will be pulled sequentially as if
5382 If multiple sources are specified, they will be pulled sequentially as if
5385 the command was run multiple time. If --update is specify and the command
5383 the command was run multiple time. If --update is specify and the command
5386 will stop at the first failed --update.
5384 will stop at the first failed --update.
5387
5385
5388 Specifying bookmark as ``.`` is equivalent to specifying the active
5386 Specifying bookmark as ``.`` is equivalent to specifying the active
5389 bookmark's name.
5387 bookmark's name.
5390
5388
5391 Returns 0 on success, 1 if an update had unresolved files.
5389 Returns 0 on success, 1 if an update had unresolved files.
5392 """
5390 """
5393
5391
5394 opts = pycompat.byteskwargs(opts)
5392 opts = pycompat.byteskwargs(opts)
5395 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5393 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5396 b'update'
5394 b'update'
5397 ):
5395 ):
5398 msg = _(b'update destination required by configuration')
5396 msg = _(b'update destination required by configuration')
5399 hint = _(b'use hg pull followed by hg update DEST')
5397 hint = _(b'use hg pull followed by hg update DEST')
5400 raise error.InputError(msg, hint=hint)
5398 raise error.InputError(msg, hint=hint)
5401
5399
5402 for path in urlutil.get_pull_paths(repo, ui, sources):
5400 for path in urlutil.get_pull_paths(repo, ui, sources):
5403 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5401 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5404 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5402 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5405 ui.flush()
5403 ui.flush()
5406 other = hg.peer(repo, opts, source)
5404 other = hg.peer(repo, opts, source)
5407 update_conflict = None
5405 update_conflict = None
5408 try:
5406 try:
5409 revs, checkout = hg.addbranchrevs(
5407 revs, checkout = hg.addbranchrevs(
5410 repo, other, branches, opts.get(b'rev')
5408 repo, other, branches, opts.get(b'rev')
5411 )
5409 )
5412
5410
5413 pullopargs = {}
5411 pullopargs = {}
5414
5412
5415 nodes = None
5413 nodes = None
5416 if opts.get(b'bookmark') or revs:
5414 if opts.get(b'bookmark') or revs:
5417 # The list of bookmark used here is the same used to actually update
5415 # The list of bookmark used here is the same used to actually update
5418 # the bookmark names, to avoid the race from issue 4689 and we do
5416 # the bookmark names, to avoid the race from issue 4689 and we do
5419 # all lookup and bookmark queries in one go so they see the same
5417 # all lookup and bookmark queries in one go so they see the same
5420 # version of the server state (issue 4700).
5418 # version of the server state (issue 4700).
5421 nodes = []
5419 nodes = []
5422 fnodes = []
5420 fnodes = []
5423 revs = revs or []
5421 revs = revs or []
5424 if revs and not other.capable(b'lookup'):
5422 if revs and not other.capable(b'lookup'):
5425 err = _(
5423 err = _(
5426 b"other repository doesn't support revision lookup, "
5424 b"other repository doesn't support revision lookup, "
5427 b"so a rev cannot be specified."
5425 b"so a rev cannot be specified."
5428 )
5426 )
5429 raise error.Abort(err)
5427 raise error.Abort(err)
5430 with other.commandexecutor() as e:
5428 with other.commandexecutor() as e:
5431 fremotebookmarks = e.callcommand(
5429 fremotebookmarks = e.callcommand(
5432 b'listkeys', {b'namespace': b'bookmarks'}
5430 b'listkeys', {b'namespace': b'bookmarks'}
5433 )
5431 )
5434 for r in revs:
5432 for r in revs:
5435 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5433 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5436 remotebookmarks = fremotebookmarks.result()
5434 remotebookmarks = fremotebookmarks.result()
5437 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5435 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5438 pullopargs[b'remotebookmarks'] = remotebookmarks
5436 pullopargs[b'remotebookmarks'] = remotebookmarks
5439 for b in opts.get(b'bookmark', []):
5437 for b in opts.get(b'bookmark', []):
5440 b = repo._bookmarks.expandname(b)
5438 b = repo._bookmarks.expandname(b)
5441 if b not in remotebookmarks:
5439 if b not in remotebookmarks:
5442 raise error.InputError(
5440 raise error.InputError(
5443 _(b'remote bookmark %s not found!') % b
5441 _(b'remote bookmark %s not found!') % b
5444 )
5442 )
5445 nodes.append(remotebookmarks[b])
5443 nodes.append(remotebookmarks[b])
5446 for i, rev in enumerate(revs):
5444 for i, rev in enumerate(revs):
5447 node = fnodes[i].result()
5445 node = fnodes[i].result()
5448 nodes.append(node)
5446 nodes.append(node)
5449 if rev == checkout:
5447 if rev == checkout:
5450 checkout = node
5448 checkout = node
5451
5449
5452 wlock = util.nullcontextmanager()
5450 wlock = util.nullcontextmanager()
5453 if opts.get(b'update'):
5451 if opts.get(b'update'):
5454 wlock = repo.wlock()
5452 wlock = repo.wlock()
5455 with wlock:
5453 with wlock:
5456 pullopargs.update(opts.get(b'opargs', {}))
5454 pullopargs.update(opts.get(b'opargs', {}))
5457 modheads = exchange.pull(
5455 modheads = exchange.pull(
5458 repo,
5456 repo,
5459 other,
5457 other,
5460 path=path,
5458 path=path,
5461 heads=nodes,
5459 heads=nodes,
5462 force=opts.get(b'force'),
5460 force=opts.get(b'force'),
5463 bookmarks=opts.get(b'bookmark', ()),
5461 bookmarks=opts.get(b'bookmark', ()),
5464 opargs=pullopargs,
5462 opargs=pullopargs,
5465 confirm=opts.get(b'confirm'),
5463 confirm=opts.get(b'confirm'),
5466 ).cgresult
5464 ).cgresult
5467
5465
5468 # brev is a name, which might be a bookmark to be activated at
5466 # brev is a name, which might be a bookmark to be activated at
5469 # the end of the update. In other words, it is an explicit
5467 # the end of the update. In other words, it is an explicit
5470 # destination of the update
5468 # destination of the update
5471 brev = None
5469 brev = None
5472
5470
5473 if checkout:
5471 if checkout:
5474 checkout = repo.unfiltered().changelog.rev(checkout)
5472 checkout = repo.unfiltered().changelog.rev(checkout)
5475
5473
5476 # order below depends on implementation of
5474 # order below depends on implementation of
5477 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5475 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5478 # because 'checkout' is determined without it.
5476 # because 'checkout' is determined without it.
5479 if opts.get(b'rev'):
5477 if opts.get(b'rev'):
5480 brev = opts[b'rev'][0]
5478 brev = opts[b'rev'][0]
5481 elif opts.get(b'branch'):
5479 elif opts.get(b'branch'):
5482 brev = opts[b'branch'][0]
5480 brev = opts[b'branch'][0]
5483 else:
5481 else:
5484 brev = branches[0]
5482 brev = branches[0]
5485 repo._subtoppath = source
5483 repo._subtoppath = source
5486 try:
5484 try:
5487 update_conflict = postincoming(
5485 update_conflict = postincoming(
5488 ui, repo, modheads, opts.get(b'update'), checkout, brev
5486 ui, repo, modheads, opts.get(b'update'), checkout, brev
5489 )
5487 )
5490 except error.FilteredRepoLookupError as exc:
5488 except error.FilteredRepoLookupError as exc:
5491 msg = _(b'cannot update to target: %s') % exc.args[0]
5489 msg = _(b'cannot update to target: %s') % exc.args[0]
5492 exc.args = (msg,) + exc.args[1:]
5490 exc.args = (msg,) + exc.args[1:]
5493 raise
5491 raise
5494 finally:
5492 finally:
5495 del repo._subtoppath
5493 del repo._subtoppath
5496
5494
5497 finally:
5495 finally:
5498 other.close()
5496 other.close()
5499 # skip the remaining pull source if they are some conflict.
5497 # skip the remaining pull source if they are some conflict.
5500 if update_conflict:
5498 if update_conflict:
5501 break
5499 break
5502 if update_conflict:
5500 if update_conflict:
5503 return 1
5501 return 1
5504 else:
5502 else:
5505 return 0
5503 return 0
5506
5504
5507
5505
5508 @command(
5506 @command(
5509 b'purge|clean',
5507 b'purge|clean',
5510 [
5508 [
5511 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5509 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5512 (b'', b'all', None, _(b'purge ignored files too')),
5510 (b'', b'all', None, _(b'purge ignored files too')),
5513 (b'i', b'ignored', None, _(b'purge only ignored files')),
5511 (b'i', b'ignored', None, _(b'purge only ignored files')),
5514 (b'', b'dirs', None, _(b'purge empty directories')),
5512 (b'', b'dirs', None, _(b'purge empty directories')),
5515 (b'', b'files', None, _(b'purge files')),
5513 (b'', b'files', None, _(b'purge files')),
5516 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5514 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5517 (
5515 (
5518 b'0',
5516 b'0',
5519 b'print0',
5517 b'print0',
5520 None,
5518 None,
5521 _(
5519 _(
5522 b'end filenames with NUL, for use with xargs'
5520 b'end filenames with NUL, for use with xargs'
5523 b' (implies -p/--print)'
5521 b' (implies -p/--print)'
5524 ),
5522 ),
5525 ),
5523 ),
5526 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5524 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5527 ]
5525 ]
5528 + cmdutil.walkopts,
5526 + cmdutil.walkopts,
5529 _(b'hg purge [OPTION]... [DIR]...'),
5527 _(b'hg purge [OPTION]... [DIR]...'),
5530 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5528 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5531 )
5529 )
5532 def purge(ui, repo, *dirs, **opts):
5530 def purge(ui, repo, *dirs, **opts):
5533 """removes files not tracked by Mercurial
5531 """removes files not tracked by Mercurial
5534
5532
5535 Delete files not known to Mercurial. This is useful to test local
5533 Delete files not known to Mercurial. This is useful to test local
5536 and uncommitted changes in an otherwise-clean source tree.
5534 and uncommitted changes in an otherwise-clean source tree.
5537
5535
5538 This means that purge will delete the following by default:
5536 This means that purge will delete the following by default:
5539
5537
5540 - Unknown files: files marked with "?" by :hg:`status`
5538 - Unknown files: files marked with "?" by :hg:`status`
5541 - Empty directories: in fact Mercurial ignores directories unless
5539 - Empty directories: in fact Mercurial ignores directories unless
5542 they contain files under source control management
5540 they contain files under source control management
5543
5541
5544 But it will leave untouched:
5542 But it will leave untouched:
5545
5543
5546 - Modified and unmodified tracked files
5544 - Modified and unmodified tracked files
5547 - Ignored files (unless -i or --all is specified)
5545 - Ignored files (unless -i or --all is specified)
5548 - New files added to the repository (with :hg:`add`)
5546 - New files added to the repository (with :hg:`add`)
5549
5547
5550 The --files and --dirs options can be used to direct purge to delete
5548 The --files and --dirs options can be used to direct purge to delete
5551 only files, only directories, or both. If neither option is given,
5549 only files, only directories, or both. If neither option is given,
5552 both will be deleted.
5550 both will be deleted.
5553
5551
5554 If directories are given on the command line, only files in these
5552 If directories are given on the command line, only files in these
5555 directories are considered.
5553 directories are considered.
5556
5554
5557 Be careful with purge, as you could irreversibly delete some files
5555 Be careful with purge, as you could irreversibly delete some files
5558 you forgot to add to the repository. If you only want to print the
5556 you forgot to add to the repository. If you only want to print the
5559 list of files that this program would delete, use the --print
5557 list of files that this program would delete, use the --print
5560 option.
5558 option.
5561 """
5559 """
5562 opts = pycompat.byteskwargs(opts)
5560 opts = pycompat.byteskwargs(opts)
5563 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5561 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5564
5562
5565 act = not opts.get(b'print')
5563 act = not opts.get(b'print')
5566 eol = b'\n'
5564 eol = b'\n'
5567 if opts.get(b'print0'):
5565 if opts.get(b'print0'):
5568 eol = b'\0'
5566 eol = b'\0'
5569 act = False # --print0 implies --print
5567 act = False # --print0 implies --print
5570 if opts.get(b'all', False):
5568 if opts.get(b'all', False):
5571 ignored = True
5569 ignored = True
5572 unknown = True
5570 unknown = True
5573 else:
5571 else:
5574 ignored = opts.get(b'ignored', False)
5572 ignored = opts.get(b'ignored', False)
5575 unknown = not ignored
5573 unknown = not ignored
5576
5574
5577 removefiles = opts.get(b'files')
5575 removefiles = opts.get(b'files')
5578 removedirs = opts.get(b'dirs')
5576 removedirs = opts.get(b'dirs')
5579 confirm = opts.get(b'confirm')
5577 confirm = opts.get(b'confirm')
5580 if confirm is None:
5578 if confirm is None:
5581 try:
5579 try:
5582 extensions.find(b'purge')
5580 extensions.find(b'purge')
5583 confirm = False
5581 confirm = False
5584 except KeyError:
5582 except KeyError:
5585 confirm = True
5583 confirm = True
5586
5584
5587 if not removefiles and not removedirs:
5585 if not removefiles and not removedirs:
5588 removefiles = True
5586 removefiles = True
5589 removedirs = True
5587 removedirs = True
5590
5588
5591 match = scmutil.match(repo[None], dirs, opts)
5589 match = scmutil.match(repo[None], dirs, opts)
5592
5590
5593 paths = mergemod.purge(
5591 paths = mergemod.purge(
5594 repo,
5592 repo,
5595 match,
5593 match,
5596 unknown=unknown,
5594 unknown=unknown,
5597 ignored=ignored,
5595 ignored=ignored,
5598 removeemptydirs=removedirs,
5596 removeemptydirs=removedirs,
5599 removefiles=removefiles,
5597 removefiles=removefiles,
5600 abortonerror=opts.get(b'abort_on_err'),
5598 abortonerror=opts.get(b'abort_on_err'),
5601 noop=not act,
5599 noop=not act,
5602 confirm=confirm,
5600 confirm=confirm,
5603 )
5601 )
5604
5602
5605 for path in paths:
5603 for path in paths:
5606 if not act:
5604 if not act:
5607 ui.write(b'%s%s' % (path, eol))
5605 ui.write(b'%s%s' % (path, eol))
5608
5606
5609
5607
5610 @command(
5608 @command(
5611 b'push',
5609 b'push',
5612 [
5610 [
5613 (b'f', b'force', None, _(b'force push')),
5611 (b'f', b'force', None, _(b'force push')),
5614 (
5612 (
5615 b'r',
5613 b'r',
5616 b'rev',
5614 b'rev',
5617 [],
5615 [],
5618 _(b'a changeset intended to be included in the destination'),
5616 _(b'a changeset intended to be included in the destination'),
5619 _(b'REV'),
5617 _(b'REV'),
5620 ),
5618 ),
5621 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5619 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5622 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5620 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5623 (
5621 (
5624 b'b',
5622 b'b',
5625 b'branch',
5623 b'branch',
5626 [],
5624 [],
5627 _(b'a specific branch you would like to push'),
5625 _(b'a specific branch you would like to push'),
5628 _(b'BRANCH'),
5626 _(b'BRANCH'),
5629 ),
5627 ),
5630 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5628 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5631 (
5629 (
5632 b'',
5630 b'',
5633 b'pushvars',
5631 b'pushvars',
5634 [],
5632 [],
5635 _(b'variables that can be sent to server (ADVANCED)'),
5633 _(b'variables that can be sent to server (ADVANCED)'),
5636 ),
5634 ),
5637 (
5635 (
5638 b'',
5636 b'',
5639 b'publish',
5637 b'publish',
5640 False,
5638 False,
5641 _(b'push the changeset as public (EXPERIMENTAL)'),
5639 _(b'push the changeset as public (EXPERIMENTAL)'),
5642 ),
5640 ),
5643 ]
5641 ]
5644 + remoteopts,
5642 + remoteopts,
5645 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5643 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5646 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5644 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5647 helpbasic=True,
5645 helpbasic=True,
5648 )
5646 )
5649 def push(ui, repo, *dests, **opts):
5647 def push(ui, repo, *dests, **opts):
5650 """push changes to the specified destination
5648 """push changes to the specified destination
5651
5649
5652 Push changesets from the local repository to the specified
5650 Push changesets from the local repository to the specified
5653 destination.
5651 destination.
5654
5652
5655 This operation is symmetrical to pull: it is identical to a pull
5653 This operation is symmetrical to pull: it is identical to a pull
5656 in the destination repository from the current one.
5654 in the destination repository from the current one.
5657
5655
5658 By default, push will not allow creation of new heads at the
5656 By default, push will not allow creation of new heads at the
5659 destination, since multiple heads would make it unclear which head
5657 destination, since multiple heads would make it unclear which head
5660 to use. In this situation, it is recommended to pull and merge
5658 to use. In this situation, it is recommended to pull and merge
5661 before pushing.
5659 before pushing.
5662
5660
5663 Use --new-branch if you want to allow push to create a new named
5661 Use --new-branch if you want to allow push to create a new named
5664 branch that is not present at the destination. This allows you to
5662 branch that is not present at the destination. This allows you to
5665 only create a new branch without forcing other changes.
5663 only create a new branch without forcing other changes.
5666
5664
5667 .. note::
5665 .. note::
5668
5666
5669 Extra care should be taken with the -f/--force option,
5667 Extra care should be taken with the -f/--force option,
5670 which will push all new heads on all branches, an action which will
5668 which will push all new heads on all branches, an action which will
5671 almost always cause confusion for collaborators.
5669 almost always cause confusion for collaborators.
5672
5670
5673 If -r/--rev is used, the specified revision and all its ancestors
5671 If -r/--rev is used, the specified revision and all its ancestors
5674 will be pushed to the remote repository.
5672 will be pushed to the remote repository.
5675
5673
5676 If -B/--bookmark is used, the specified bookmarked revision, its
5674 If -B/--bookmark is used, the specified bookmarked revision, its
5677 ancestors, and the bookmark will be pushed to the remote
5675 ancestors, and the bookmark will be pushed to the remote
5678 repository. Specifying ``.`` is equivalent to specifying the active
5676 repository. Specifying ``.`` is equivalent to specifying the active
5679 bookmark's name. Use the --all-bookmarks option for pushing all
5677 bookmark's name. Use the --all-bookmarks option for pushing all
5680 current bookmarks.
5678 current bookmarks.
5681
5679
5682 Please see :hg:`help urls` for important details about ``ssh://``
5680 Please see :hg:`help urls` for important details about ``ssh://``
5683 URLs. If DESTINATION is omitted, a default path will be used.
5681 URLs. If DESTINATION is omitted, a default path will be used.
5684
5682
5685 When passed multiple destinations, push will process them one after the
5683 When passed multiple destinations, push will process them one after the
5686 other, but stop should an error occur.
5684 other, but stop should an error occur.
5687
5685
5688 .. container:: verbose
5686 .. container:: verbose
5689
5687
5690 The --pushvars option sends strings to the server that become
5688 The --pushvars option sends strings to the server that become
5691 environment variables prepended with ``HG_USERVAR_``. For example,
5689 environment variables prepended with ``HG_USERVAR_``. For example,
5692 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5690 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5693 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5691 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5694
5692
5695 pushvars can provide for user-overridable hooks as well as set debug
5693 pushvars can provide for user-overridable hooks as well as set debug
5696 levels. One example is having a hook that blocks commits containing
5694 levels. One example is having a hook that blocks commits containing
5697 conflict markers, but enables the user to override the hook if the file
5695 conflict markers, but enables the user to override the hook if the file
5698 is using conflict markers for testing purposes or the file format has
5696 is using conflict markers for testing purposes or the file format has
5699 strings that look like conflict markers.
5697 strings that look like conflict markers.
5700
5698
5701 By default, servers will ignore `--pushvars`. To enable it add the
5699 By default, servers will ignore `--pushvars`. To enable it add the
5702 following to your configuration file::
5700 following to your configuration file::
5703
5701
5704 [push]
5702 [push]
5705 pushvars.server = true
5703 pushvars.server = true
5706
5704
5707 Returns 0 if push was successful, 1 if nothing to push.
5705 Returns 0 if push was successful, 1 if nothing to push.
5708 """
5706 """
5709
5707
5710 opts = pycompat.byteskwargs(opts)
5708 opts = pycompat.byteskwargs(opts)
5711
5709
5712 if opts.get(b'all_bookmarks'):
5710 if opts.get(b'all_bookmarks'):
5713 cmdutil.check_incompatible_arguments(
5711 cmdutil.check_incompatible_arguments(
5714 opts,
5712 opts,
5715 b'all_bookmarks',
5713 b'all_bookmarks',
5716 [b'bookmark', b'rev'],
5714 [b'bookmark', b'rev'],
5717 )
5715 )
5718 opts[b'bookmark'] = list(repo._bookmarks)
5716 opts[b'bookmark'] = list(repo._bookmarks)
5719
5717
5720 if opts.get(b'bookmark'):
5718 if opts.get(b'bookmark'):
5721 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5719 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5722 for b in opts[b'bookmark']:
5720 for b in opts[b'bookmark']:
5723 # translate -B options to -r so changesets get pushed
5721 # translate -B options to -r so changesets get pushed
5724 b = repo._bookmarks.expandname(b)
5722 b = repo._bookmarks.expandname(b)
5725 if b in repo._bookmarks:
5723 if b in repo._bookmarks:
5726 opts.setdefault(b'rev', []).append(b)
5724 opts.setdefault(b'rev', []).append(b)
5727 else:
5725 else:
5728 # if we try to push a deleted bookmark, translate it to null
5726 # if we try to push a deleted bookmark, translate it to null
5729 # this lets simultaneous -r, -b options continue working
5727 # this lets simultaneous -r, -b options continue working
5730 opts.setdefault(b'rev', []).append(b"null")
5728 opts.setdefault(b'rev', []).append(b"null")
5731
5729
5732 some_pushed = False
5730 some_pushed = False
5733 result = 0
5731 result = 0
5734 for path in urlutil.get_push_paths(repo, ui, dests):
5732 for path in urlutil.get_push_paths(repo, ui, dests):
5735 dest = path.pushloc or path.loc
5733 dest = path.pushloc or path.loc
5736 branches = (path.branch, opts.get(b'branch') or [])
5734 branches = (path.branch, opts.get(b'branch') or [])
5737 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5735 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5738 revs, checkout = hg.addbranchrevs(
5736 revs, checkout = hg.addbranchrevs(
5739 repo, repo, branches, opts.get(b'rev')
5737 repo, repo, branches, opts.get(b'rev')
5740 )
5738 )
5741 other = hg.peer(repo, opts, dest)
5739 other = hg.peer(repo, opts, dest)
5742
5740
5743 try:
5741 try:
5744 if revs:
5742 if revs:
5745 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5743 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5746 if not revs:
5744 if not revs:
5747 raise error.InputError(
5745 raise error.InputError(
5748 _(b"specified revisions evaluate to an empty set"),
5746 _(b"specified revisions evaluate to an empty set"),
5749 hint=_(b"use different revision arguments"),
5747 hint=_(b"use different revision arguments"),
5750 )
5748 )
5751 elif path.pushrev:
5749 elif path.pushrev:
5752 # It doesn't make any sense to specify ancestor revisions. So limit
5750 # It doesn't make any sense to specify ancestor revisions. So limit
5753 # to DAG heads to make discovery simpler.
5751 # to DAG heads to make discovery simpler.
5754 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5752 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5755 revs = scmutil.revrange(repo, [expr])
5753 revs = scmutil.revrange(repo, [expr])
5756 revs = [repo[rev].node() for rev in revs]
5754 revs = [repo[rev].node() for rev in revs]
5757 if not revs:
5755 if not revs:
5758 raise error.InputError(
5756 raise error.InputError(
5759 _(
5757 _(
5760 b'default push revset for path evaluates to an empty set'
5758 b'default push revset for path evaluates to an empty set'
5761 )
5759 )
5762 )
5760 )
5763 elif ui.configbool(b'commands', b'push.require-revs'):
5761 elif ui.configbool(b'commands', b'push.require-revs'):
5764 raise error.InputError(
5762 raise error.InputError(
5765 _(b'no revisions specified to push'),
5763 _(b'no revisions specified to push'),
5766 hint=_(b'did you mean "hg push -r ."?'),
5764 hint=_(b'did you mean "hg push -r ."?'),
5767 )
5765 )
5768
5766
5769 repo._subtoppath = dest
5767 repo._subtoppath = dest
5770 try:
5768 try:
5771 # push subrepos depth-first for coherent ordering
5769 # push subrepos depth-first for coherent ordering
5772 c = repo[b'.']
5770 c = repo[b'.']
5773 subs = c.substate # only repos that are committed
5771 subs = c.substate # only repos that are committed
5774 for s in sorted(subs):
5772 for s in sorted(subs):
5775 sub_result = c.sub(s).push(opts)
5773 sub_result = c.sub(s).push(opts)
5776 if sub_result == 0:
5774 if sub_result == 0:
5777 return 1
5775 return 1
5778 finally:
5776 finally:
5779 del repo._subtoppath
5777 del repo._subtoppath
5780
5778
5781 opargs = dict(
5779 opargs = dict(
5782 opts.get(b'opargs', {})
5780 opts.get(b'opargs', {})
5783 ) # copy opargs since we may mutate it
5781 ) # copy opargs since we may mutate it
5784 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5782 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5785
5783
5786 pushop = exchange.push(
5784 pushop = exchange.push(
5787 repo,
5785 repo,
5788 other,
5786 other,
5789 opts.get(b'force'),
5787 opts.get(b'force'),
5790 revs=revs,
5788 revs=revs,
5791 newbranch=opts.get(b'new_branch'),
5789 newbranch=opts.get(b'new_branch'),
5792 bookmarks=opts.get(b'bookmark', ()),
5790 bookmarks=opts.get(b'bookmark', ()),
5793 publish=opts.get(b'publish'),
5791 publish=opts.get(b'publish'),
5794 opargs=opargs,
5792 opargs=opargs,
5795 )
5793 )
5796
5794
5797 if pushop.cgresult == 0:
5795 if pushop.cgresult == 0:
5798 result = 1
5796 result = 1
5799 elif pushop.cgresult is not None:
5797 elif pushop.cgresult is not None:
5800 some_pushed = True
5798 some_pushed = True
5801
5799
5802 if pushop.bkresult is not None:
5800 if pushop.bkresult is not None:
5803 if pushop.bkresult == 2:
5801 if pushop.bkresult == 2:
5804 result = 2
5802 result = 2
5805 elif not result and pushop.bkresult:
5803 elif not result and pushop.bkresult:
5806 result = 2
5804 result = 2
5807
5805
5808 if result:
5806 if result:
5809 break
5807 break
5810
5808
5811 finally:
5809 finally:
5812 other.close()
5810 other.close()
5813 if result == 0 and not some_pushed:
5811 if result == 0 and not some_pushed:
5814 result = 1
5812 result = 1
5815 return result
5813 return result
5816
5814
5817
5815
5818 @command(
5816 @command(
5819 b'recover',
5817 b'recover',
5820 [
5818 [
5821 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5819 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5822 ],
5820 ],
5823 helpcategory=command.CATEGORY_MAINTENANCE,
5821 helpcategory=command.CATEGORY_MAINTENANCE,
5824 )
5822 )
5825 def recover(ui, repo, **opts):
5823 def recover(ui, repo, **opts):
5826 """roll back an interrupted transaction
5824 """roll back an interrupted transaction
5827
5825
5828 Recover from an interrupted commit or pull.
5826 Recover from an interrupted commit or pull.
5829
5827
5830 This command tries to fix the repository status after an
5828 This command tries to fix the repository status after an
5831 interrupted operation. It should only be necessary when Mercurial
5829 interrupted operation. It should only be necessary when Mercurial
5832 suggests it.
5830 suggests it.
5833
5831
5834 Returns 0 if successful, 1 if nothing to recover or verify fails.
5832 Returns 0 if successful, 1 if nothing to recover or verify fails.
5835 """
5833 """
5836 ret = repo.recover()
5834 ret = repo.recover()
5837 if ret:
5835 if ret:
5838 if opts['verify']:
5836 if opts['verify']:
5839 return hg.verify(repo)
5837 return hg.verify(repo)
5840 else:
5838 else:
5841 msg = _(
5839 msg = _(
5842 b"(verify step skipped, run `hg verify` to check your "
5840 b"(verify step skipped, run `hg verify` to check your "
5843 b"repository content)\n"
5841 b"repository content)\n"
5844 )
5842 )
5845 ui.warn(msg)
5843 ui.warn(msg)
5846 return 0
5844 return 0
5847 return 1
5845 return 1
5848
5846
5849
5847
5850 @command(
5848 @command(
5851 b'remove|rm',
5849 b'remove|rm',
5852 [
5850 [
5853 (b'A', b'after', None, _(b'record delete for missing files')),
5851 (b'A', b'after', None, _(b'record delete for missing files')),
5854 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5852 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5855 ]
5853 ]
5856 + subrepoopts
5854 + subrepoopts
5857 + walkopts
5855 + walkopts
5858 + dryrunopts,
5856 + dryrunopts,
5859 _(b'[OPTION]... FILE...'),
5857 _(b'[OPTION]... FILE...'),
5860 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5858 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5861 helpbasic=True,
5859 helpbasic=True,
5862 inferrepo=True,
5860 inferrepo=True,
5863 )
5861 )
5864 def remove(ui, repo, *pats, **opts):
5862 def remove(ui, repo, *pats, **opts):
5865 """remove the specified files on the next commit
5863 """remove the specified files on the next commit
5866
5864
5867 Schedule the indicated files for removal from the current branch.
5865 Schedule the indicated files for removal from the current branch.
5868
5866
5869 This command schedules the files to be removed at the next commit.
5867 This command schedules the files to be removed at the next commit.
5870 To undo a remove before that, see :hg:`revert`. To undo added
5868 To undo a remove before that, see :hg:`revert`. To undo added
5871 files, see :hg:`forget`.
5869 files, see :hg:`forget`.
5872
5870
5873 .. container:: verbose
5871 .. container:: verbose
5874
5872
5875 -A/--after can be used to remove only files that have already
5873 -A/--after can be used to remove only files that have already
5876 been deleted, -f/--force can be used to force deletion, and -Af
5874 been deleted, -f/--force can be used to force deletion, and -Af
5877 can be used to remove files from the next revision without
5875 can be used to remove files from the next revision without
5878 deleting them from the working directory.
5876 deleting them from the working directory.
5879
5877
5880 The following table details the behavior of remove for different
5878 The following table details the behavior of remove for different
5881 file states (columns) and option combinations (rows). The file
5879 file states (columns) and option combinations (rows). The file
5882 states are Added [A], Clean [C], Modified [M] and Missing [!]
5880 states are Added [A], Clean [C], Modified [M] and Missing [!]
5883 (as reported by :hg:`status`). The actions are Warn, Remove
5881 (as reported by :hg:`status`). The actions are Warn, Remove
5884 (from branch) and Delete (from disk):
5882 (from branch) and Delete (from disk):
5885
5883
5886 ========= == == == ==
5884 ========= == == == ==
5887 opt/state A C M !
5885 opt/state A C M !
5888 ========= == == == ==
5886 ========= == == == ==
5889 none W RD W R
5887 none W RD W R
5890 -f R RD RD R
5888 -f R RD RD R
5891 -A W W W R
5889 -A W W W R
5892 -Af R R R R
5890 -Af R R R R
5893 ========= == == == ==
5891 ========= == == == ==
5894
5892
5895 .. note::
5893 .. note::
5896
5894
5897 :hg:`remove` never deletes files in Added [A] state from the
5895 :hg:`remove` never deletes files in Added [A] state from the
5898 working directory, not even if ``--force`` is specified.
5896 working directory, not even if ``--force`` is specified.
5899
5897
5900 Returns 0 on success, 1 if any warnings encountered.
5898 Returns 0 on success, 1 if any warnings encountered.
5901 """
5899 """
5902
5900
5903 opts = pycompat.byteskwargs(opts)
5901 opts = pycompat.byteskwargs(opts)
5904 after, force = opts.get(b'after'), opts.get(b'force')
5902 after, force = opts.get(b'after'), opts.get(b'force')
5905 dryrun = opts.get(b'dry_run')
5903 dryrun = opts.get(b'dry_run')
5906 if not pats and not after:
5904 if not pats and not after:
5907 raise error.InputError(_(b'no files specified'))
5905 raise error.InputError(_(b'no files specified'))
5908
5906
5909 m = scmutil.match(repo[None], pats, opts)
5907 m = scmutil.match(repo[None], pats, opts)
5910 subrepos = opts.get(b'subrepos')
5908 subrepos = opts.get(b'subrepos')
5911 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5909 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5912 return cmdutil.remove(
5910 return cmdutil.remove(
5913 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5911 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5914 )
5912 )
5915
5913
5916
5914
5917 @command(
5915 @command(
5918 b'rename|move|mv',
5916 b'rename|move|mv',
5919 [
5917 [
5920 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5918 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5921 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5919 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5922 (
5920 (
5923 b'',
5921 b'',
5924 b'at-rev',
5922 b'at-rev',
5925 b'',
5923 b'',
5926 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5924 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5927 _(b'REV'),
5925 _(b'REV'),
5928 ),
5926 ),
5929 (
5927 (
5930 b'f',
5928 b'f',
5931 b'force',
5929 b'force',
5932 None,
5930 None,
5933 _(b'forcibly move over an existing managed file'),
5931 _(b'forcibly move over an existing managed file'),
5934 ),
5932 ),
5935 ]
5933 ]
5936 + walkopts
5934 + walkopts
5937 + dryrunopts,
5935 + dryrunopts,
5938 _(b'[OPTION]... SOURCE... DEST'),
5936 _(b'[OPTION]... SOURCE... DEST'),
5939 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5937 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5940 )
5938 )
5941 def rename(ui, repo, *pats, **opts):
5939 def rename(ui, repo, *pats, **opts):
5942 """rename files; equivalent of copy + remove
5940 """rename files; equivalent of copy + remove
5943
5941
5944 Mark dest as copies of sources; mark sources for deletion. If dest
5942 Mark dest as copies of sources; mark sources for deletion. If dest
5945 is a directory, copies are put in that directory. If dest is a
5943 is a directory, copies are put in that directory. If dest is a
5946 file, there can only be one source.
5944 file, there can only be one source.
5947
5945
5948 By default, this command copies the contents of files as they
5946 By default, this command copies the contents of files as they
5949 exist in the working directory. If invoked with -A/--after, the
5947 exist in the working directory. If invoked with -A/--after, the
5950 operation is recorded, but no copying is performed.
5948 operation is recorded, but no copying is performed.
5951
5949
5952 To undo marking a destination file as renamed, use --forget. With that
5950 To undo marking a destination file as renamed, use --forget. With that
5953 option, all given (positional) arguments are unmarked as renames. The
5951 option, all given (positional) arguments are unmarked as renames. The
5954 destination file(s) will be left in place (still tracked). The source
5952 destination file(s) will be left in place (still tracked). The source
5955 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5953 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5956 the same way as :hg:`copy --forget`.
5954 the same way as :hg:`copy --forget`.
5957
5955
5958 This command takes effect with the next commit by default.
5956 This command takes effect with the next commit by default.
5959
5957
5960 Returns 0 on success, 1 if errors are encountered.
5958 Returns 0 on success, 1 if errors are encountered.
5961 """
5959 """
5962 opts = pycompat.byteskwargs(opts)
5960 opts = pycompat.byteskwargs(opts)
5963 with repo.wlock():
5961 with repo.wlock():
5964 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5962 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5965
5963
5966
5964
5967 @command(
5965 @command(
5968 b'resolve',
5966 b'resolve',
5969 [
5967 [
5970 (b'a', b'all', None, _(b'select all unresolved files')),
5968 (b'a', b'all', None, _(b'select all unresolved files')),
5971 (b'l', b'list', None, _(b'list state of files needing merge')),
5969 (b'l', b'list', None, _(b'list state of files needing merge')),
5972 (b'm', b'mark', None, _(b'mark files as resolved')),
5970 (b'm', b'mark', None, _(b'mark files as resolved')),
5973 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5971 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5974 (b'n', b'no-status', None, _(b'hide status prefix')),
5972 (b'n', b'no-status', None, _(b'hide status prefix')),
5975 (b'', b're-merge', None, _(b're-merge files')),
5973 (b'', b're-merge', None, _(b're-merge files')),
5976 ]
5974 ]
5977 + mergetoolopts
5975 + mergetoolopts
5978 + walkopts
5976 + walkopts
5979 + formatteropts,
5977 + formatteropts,
5980 _(b'[OPTION]... [FILE]...'),
5978 _(b'[OPTION]... [FILE]...'),
5981 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5979 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5982 inferrepo=True,
5980 inferrepo=True,
5983 )
5981 )
5984 def resolve(ui, repo, *pats, **opts):
5982 def resolve(ui, repo, *pats, **opts):
5985 """redo merges or set/view the merge status of files
5983 """redo merges or set/view the merge status of files
5986
5984
5987 Merges with unresolved conflicts are often the result of
5985 Merges with unresolved conflicts are often the result of
5988 non-interactive merging using the ``internal:merge`` configuration
5986 non-interactive merging using the ``internal:merge`` configuration
5989 setting, or a command-line merge tool like ``diff3``. The resolve
5987 setting, or a command-line merge tool like ``diff3``. The resolve
5990 command is used to manage the files involved in a merge, after
5988 command is used to manage the files involved in a merge, after
5991 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5989 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5992 working directory must have two parents). See :hg:`help
5990 working directory must have two parents). See :hg:`help
5993 merge-tools` for information on configuring merge tools.
5991 merge-tools` for information on configuring merge tools.
5994
5992
5995 The resolve command can be used in the following ways:
5993 The resolve command can be used in the following ways:
5996
5994
5997 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5995 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5998 the specified files, discarding any previous merge attempts. Re-merging
5996 the specified files, discarding any previous merge attempts. Re-merging
5999 is not performed for files already marked as resolved. Use ``--all/-a``
5997 is not performed for files already marked as resolved. Use ``--all/-a``
6000 to select all unresolved files. ``--tool`` can be used to specify
5998 to select all unresolved files. ``--tool`` can be used to specify
6001 the merge tool used for the given files. It overrides the HGMERGE
5999 the merge tool used for the given files. It overrides the HGMERGE
6002 environment variable and your configuration files. Previous file
6000 environment variable and your configuration files. Previous file
6003 contents are saved with a ``.orig`` suffix.
6001 contents are saved with a ``.orig`` suffix.
6004
6002
6005 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6003 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6006 (e.g. after having manually fixed-up the files). The default is
6004 (e.g. after having manually fixed-up the files). The default is
6007 to mark all unresolved files.
6005 to mark all unresolved files.
6008
6006
6009 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6007 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6010 default is to mark all resolved files.
6008 default is to mark all resolved files.
6011
6009
6012 - :hg:`resolve -l`: list files which had or still have conflicts.
6010 - :hg:`resolve -l`: list files which had or still have conflicts.
6013 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6011 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6014 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6012 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6015 the list. See :hg:`help filesets` for details.
6013 the list. See :hg:`help filesets` for details.
6016
6014
6017 .. note::
6015 .. note::
6018
6016
6019 Mercurial will not let you commit files with unresolved merge
6017 Mercurial will not let you commit files with unresolved merge
6020 conflicts. You must use :hg:`resolve -m ...` before you can
6018 conflicts. You must use :hg:`resolve -m ...` before you can
6021 commit after a conflicting merge.
6019 commit after a conflicting merge.
6022
6020
6023 .. container:: verbose
6021 .. container:: verbose
6024
6022
6025 Template:
6023 Template:
6026
6024
6027 The following keywords are supported in addition to the common template
6025 The following keywords are supported in addition to the common template
6028 keywords and functions. See also :hg:`help templates`.
6026 keywords and functions. See also :hg:`help templates`.
6029
6027
6030 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6028 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6031 :path: String. Repository-absolute path of the file.
6029 :path: String. Repository-absolute path of the file.
6032
6030
6033 Returns 0 on success, 1 if any files fail a resolve attempt.
6031 Returns 0 on success, 1 if any files fail a resolve attempt.
6034 """
6032 """
6035
6033
6036 opts = pycompat.byteskwargs(opts)
6034 opts = pycompat.byteskwargs(opts)
6037 confirm = ui.configbool(b'commands', b'resolve.confirm')
6035 confirm = ui.configbool(b'commands', b'resolve.confirm')
6038 flaglist = b'all mark unmark list no_status re_merge'.split()
6036 flaglist = b'all mark unmark list no_status re_merge'.split()
6039 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6037 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6040
6038
6041 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6039 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6042 if actioncount > 1:
6040 if actioncount > 1:
6043 raise error.InputError(_(b"too many actions specified"))
6041 raise error.InputError(_(b"too many actions specified"))
6044 elif actioncount == 0 and ui.configbool(
6042 elif actioncount == 0 and ui.configbool(
6045 b'commands', b'resolve.explicit-re-merge'
6043 b'commands', b'resolve.explicit-re-merge'
6046 ):
6044 ):
6047 hint = _(b'use --mark, --unmark, --list or --re-merge')
6045 hint = _(b'use --mark, --unmark, --list or --re-merge')
6048 raise error.InputError(_(b'no action specified'), hint=hint)
6046 raise error.InputError(_(b'no action specified'), hint=hint)
6049 if pats and all:
6047 if pats and all:
6050 raise error.InputError(_(b"can't specify --all and patterns"))
6048 raise error.InputError(_(b"can't specify --all and patterns"))
6051 if not (all or pats or show or mark or unmark):
6049 if not (all or pats or show or mark or unmark):
6052 raise error.InputError(
6050 raise error.InputError(
6053 _(b'no files or directories specified'),
6051 _(b'no files or directories specified'),
6054 hint=b'use --all to re-merge all unresolved files',
6052 hint=b'use --all to re-merge all unresolved files',
6055 )
6053 )
6056
6054
6057 if confirm:
6055 if confirm:
6058 if all:
6056 if all:
6059 if ui.promptchoice(
6057 if ui.promptchoice(
6060 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6058 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6061 ):
6059 ):
6062 raise error.CanceledError(_(b'user quit'))
6060 raise error.CanceledError(_(b'user quit'))
6063 if mark and not pats:
6061 if mark and not pats:
6064 if ui.promptchoice(
6062 if ui.promptchoice(
6065 _(
6063 _(
6066 b'mark all unresolved files as resolved (yn)?'
6064 b'mark all unresolved files as resolved (yn)?'
6067 b'$$ &Yes $$ &No'
6065 b'$$ &Yes $$ &No'
6068 )
6066 )
6069 ):
6067 ):
6070 raise error.CanceledError(_(b'user quit'))
6068 raise error.CanceledError(_(b'user quit'))
6071 if unmark and not pats:
6069 if unmark and not pats:
6072 if ui.promptchoice(
6070 if ui.promptchoice(
6073 _(
6071 _(
6074 b'mark all resolved files as unresolved (yn)?'
6072 b'mark all resolved files as unresolved (yn)?'
6075 b'$$ &Yes $$ &No'
6073 b'$$ &Yes $$ &No'
6076 )
6074 )
6077 ):
6075 ):
6078 raise error.CanceledError(_(b'user quit'))
6076 raise error.CanceledError(_(b'user quit'))
6079
6077
6080 uipathfn = scmutil.getuipathfn(repo)
6078 uipathfn = scmutil.getuipathfn(repo)
6081
6079
6082 if show:
6080 if show:
6083 ui.pager(b'resolve')
6081 ui.pager(b'resolve')
6084 fm = ui.formatter(b'resolve', opts)
6082 fm = ui.formatter(b'resolve', opts)
6085 ms = mergestatemod.mergestate.read(repo)
6083 ms = mergestatemod.mergestate.read(repo)
6086 wctx = repo[None]
6084 wctx = repo[None]
6087 m = scmutil.match(wctx, pats, opts)
6085 m = scmutil.match(wctx, pats, opts)
6088
6086
6089 # Labels and keys based on merge state. Unresolved path conflicts show
6087 # Labels and keys based on merge state. Unresolved path conflicts show
6090 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6088 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6091 # resolved conflicts.
6089 # resolved conflicts.
6092 mergestateinfo = {
6090 mergestateinfo = {
6093 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6091 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6094 b'resolve.unresolved',
6092 b'resolve.unresolved',
6095 b'U',
6093 b'U',
6096 ),
6094 ),
6097 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6095 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6098 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6096 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6099 b'resolve.unresolved',
6097 b'resolve.unresolved',
6100 b'P',
6098 b'P',
6101 ),
6099 ),
6102 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6100 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6103 b'resolve.resolved',
6101 b'resolve.resolved',
6104 b'R',
6102 b'R',
6105 ),
6103 ),
6106 }
6104 }
6107
6105
6108 for f in ms:
6106 for f in ms:
6109 if not m(f):
6107 if not m(f):
6110 continue
6108 continue
6111
6109
6112 label, key = mergestateinfo[ms[f]]
6110 label, key = mergestateinfo[ms[f]]
6113 fm.startitem()
6111 fm.startitem()
6114 fm.context(ctx=wctx)
6112 fm.context(ctx=wctx)
6115 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6113 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6116 fm.data(path=f)
6114 fm.data(path=f)
6117 fm.plain(b'%s\n' % uipathfn(f), label=label)
6115 fm.plain(b'%s\n' % uipathfn(f), label=label)
6118 fm.end()
6116 fm.end()
6119 return 0
6117 return 0
6120
6118
6121 with repo.wlock():
6119 with repo.wlock():
6122 ms = mergestatemod.mergestate.read(repo)
6120 ms = mergestatemod.mergestate.read(repo)
6123
6121
6124 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6122 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6125 raise error.StateError(
6123 raise error.StateError(
6126 _(b'resolve command not applicable when not merging')
6124 _(b'resolve command not applicable when not merging')
6127 )
6125 )
6128
6126
6129 wctx = repo[None]
6127 wctx = repo[None]
6130 m = scmutil.match(wctx, pats, opts)
6128 m = scmutil.match(wctx, pats, opts)
6131 ret = 0
6129 ret = 0
6132 didwork = False
6130 didwork = False
6133
6131
6134 hasconflictmarkers = []
6132 hasconflictmarkers = []
6135 if mark:
6133 if mark:
6136 markcheck = ui.config(b'commands', b'resolve.mark-check')
6134 markcheck = ui.config(b'commands', b'resolve.mark-check')
6137 if markcheck not in [b'warn', b'abort']:
6135 if markcheck not in [b'warn', b'abort']:
6138 # Treat all invalid / unrecognized values as 'none'.
6136 # Treat all invalid / unrecognized values as 'none'.
6139 markcheck = False
6137 markcheck = False
6140 for f in ms:
6138 for f in ms:
6141 if not m(f):
6139 if not m(f):
6142 continue
6140 continue
6143
6141
6144 didwork = True
6142 didwork = True
6145
6143
6146 # path conflicts must be resolved manually
6144 # path conflicts must be resolved manually
6147 if ms[f] in (
6145 if ms[f] in (
6148 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6146 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6149 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6147 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6150 ):
6148 ):
6151 if mark:
6149 if mark:
6152 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6150 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6153 elif unmark:
6151 elif unmark:
6154 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6152 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6155 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6153 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6156 ui.warn(
6154 ui.warn(
6157 _(b'%s: path conflict must be resolved manually\n')
6155 _(b'%s: path conflict must be resolved manually\n')
6158 % uipathfn(f)
6156 % uipathfn(f)
6159 )
6157 )
6160 continue
6158 continue
6161
6159
6162 if mark:
6160 if mark:
6163 if markcheck:
6161 if markcheck:
6164 fdata = repo.wvfs.tryread(f)
6162 fdata = repo.wvfs.tryread(f)
6165 if (
6163 if (
6166 filemerge.hasconflictmarkers(fdata)
6164 filemerge.hasconflictmarkers(fdata)
6167 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6165 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6168 ):
6166 ):
6169 hasconflictmarkers.append(f)
6167 hasconflictmarkers.append(f)
6170 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6168 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6171 elif unmark:
6169 elif unmark:
6172 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6170 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6173 else:
6171 else:
6174 # backup pre-resolve (merge uses .orig for its own purposes)
6172 # backup pre-resolve (merge uses .orig for its own purposes)
6175 a = repo.wjoin(f)
6173 a = repo.wjoin(f)
6176 try:
6174 try:
6177 util.copyfile(a, a + b".resolve")
6175 util.copyfile(a, a + b".resolve")
6178 except (IOError, OSError) as inst:
6176 except (IOError, OSError) as inst:
6179 if inst.errno != errno.ENOENT:
6177 if inst.errno != errno.ENOENT:
6180 raise
6178 raise
6181
6179
6182 try:
6180 try:
6183 # preresolve file
6181 # preresolve file
6184 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6182 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6185 with ui.configoverride(overrides, b'resolve'):
6183 with ui.configoverride(overrides, b'resolve'):
6186 r = ms.resolve(f, wctx)
6184 r = ms.resolve(f, wctx)
6187 if r:
6185 if r:
6188 ret = 1
6186 ret = 1
6189 finally:
6187 finally:
6190 ms.commit()
6188 ms.commit()
6191
6189
6192 # replace filemerge's .orig file with our resolve file
6190 # replace filemerge's .orig file with our resolve file
6193 try:
6191 try:
6194 util.rename(
6192 util.rename(
6195 a + b".resolve", scmutil.backuppath(ui, repo, f)
6193 a + b".resolve", scmutil.backuppath(ui, repo, f)
6196 )
6194 )
6197 except OSError as inst:
6195 except OSError as inst:
6198 if inst.errno != errno.ENOENT:
6196 if inst.errno != errno.ENOENT:
6199 raise
6197 raise
6200
6198
6201 if hasconflictmarkers:
6199 if hasconflictmarkers:
6202 ui.warn(
6200 ui.warn(
6203 _(
6201 _(
6204 b'warning: the following files still have conflict '
6202 b'warning: the following files still have conflict '
6205 b'markers:\n'
6203 b'markers:\n'
6206 )
6204 )
6207 + b''.join(
6205 + b''.join(
6208 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6206 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6209 )
6207 )
6210 )
6208 )
6211 if markcheck == b'abort' and not all and not pats:
6209 if markcheck == b'abort' and not all and not pats:
6212 raise error.StateError(
6210 raise error.StateError(
6213 _(b'conflict markers detected'),
6211 _(b'conflict markers detected'),
6214 hint=_(b'use --all to mark anyway'),
6212 hint=_(b'use --all to mark anyway'),
6215 )
6213 )
6216
6214
6217 ms.commit()
6215 ms.commit()
6218 branchmerge = repo.dirstate.p2() != repo.nullid
6216 branchmerge = repo.dirstate.p2() != repo.nullid
6219 # resolve is not doing a parent change here, however, `record updates`
6217 # resolve is not doing a parent change here, however, `record updates`
6220 # will call some dirstate API that at intended for parent changes call.
6218 # will call some dirstate API that at intended for parent changes call.
6221 # Ideally we would not need this and could implement a lighter version
6219 # Ideally we would not need this and could implement a lighter version
6222 # of the recordupdateslogic that will not have to deal with the part
6220 # of the recordupdateslogic that will not have to deal with the part
6223 # related to parent changes. However this would requires that:
6221 # related to parent changes. However this would requires that:
6224 # - we are sure we passed around enough information at update/merge
6222 # - we are sure we passed around enough information at update/merge
6225 # time to no longer needs it at `hg resolve time`
6223 # time to no longer needs it at `hg resolve time`
6226 # - we are sure we store that information well enough to be able to reuse it
6224 # - we are sure we store that information well enough to be able to reuse it
6227 # - we are the necessary logic to reuse it right.
6225 # - we are the necessary logic to reuse it right.
6228 #
6226 #
6229 # All this should eventually happens, but in the mean time, we use this
6227 # All this should eventually happens, but in the mean time, we use this
6230 # context manager slightly out of the context it should be.
6228 # context manager slightly out of the context it should be.
6231 with repo.dirstate.parentchange():
6229 with repo.dirstate.parentchange():
6232 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6230 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6233
6231
6234 if not didwork and pats:
6232 if not didwork and pats:
6235 hint = None
6233 hint = None
6236 if not any([p for p in pats if p.find(b':') >= 0]):
6234 if not any([p for p in pats if p.find(b':') >= 0]):
6237 pats = [b'path:%s' % p for p in pats]
6235 pats = [b'path:%s' % p for p in pats]
6238 m = scmutil.match(wctx, pats, opts)
6236 m = scmutil.match(wctx, pats, opts)
6239 for f in ms:
6237 for f in ms:
6240 if not m(f):
6238 if not m(f):
6241 continue
6239 continue
6242
6240
6243 def flag(o):
6241 def flag(o):
6244 if o == b're_merge':
6242 if o == b're_merge':
6245 return b'--re-merge '
6243 return b'--re-merge '
6246 return b'-%s ' % o[0:1]
6244 return b'-%s ' % o[0:1]
6247
6245
6248 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6246 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6249 hint = _(b"(try: hg resolve %s%s)\n") % (
6247 hint = _(b"(try: hg resolve %s%s)\n") % (
6250 flags,
6248 flags,
6251 b' '.join(pats),
6249 b' '.join(pats),
6252 )
6250 )
6253 break
6251 break
6254 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6252 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6255 if hint:
6253 if hint:
6256 ui.warn(hint)
6254 ui.warn(hint)
6257
6255
6258 unresolvedf = ms.unresolvedcount()
6256 unresolvedf = ms.unresolvedcount()
6259 if not unresolvedf:
6257 if not unresolvedf:
6260 ui.status(_(b'(no more unresolved files)\n'))
6258 ui.status(_(b'(no more unresolved files)\n'))
6261 cmdutil.checkafterresolved(repo)
6259 cmdutil.checkafterresolved(repo)
6262
6260
6263 return ret
6261 return ret
6264
6262
6265
6263
6266 @command(
6264 @command(
6267 b'revert',
6265 b'revert',
6268 [
6266 [
6269 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6267 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6270 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6268 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6271 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6269 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6272 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6270 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6273 (b'i', b'interactive', None, _(b'interactively select the changes')),
6271 (b'i', b'interactive', None, _(b'interactively select the changes')),
6274 ]
6272 ]
6275 + walkopts
6273 + walkopts
6276 + dryrunopts,
6274 + dryrunopts,
6277 _(b'[OPTION]... [-r REV] [NAME]...'),
6275 _(b'[OPTION]... [-r REV] [NAME]...'),
6278 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6276 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6279 )
6277 )
6280 def revert(ui, repo, *pats, **opts):
6278 def revert(ui, repo, *pats, **opts):
6281 """restore files to their checkout state
6279 """restore files to their checkout state
6282
6280
6283 .. note::
6281 .. note::
6284
6282
6285 To check out earlier revisions, you should use :hg:`update REV`.
6283 To check out earlier revisions, you should use :hg:`update REV`.
6286 To cancel an uncommitted merge (and lose your changes),
6284 To cancel an uncommitted merge (and lose your changes),
6287 use :hg:`merge --abort`.
6285 use :hg:`merge --abort`.
6288
6286
6289 With no revision specified, revert the specified files or directories
6287 With no revision specified, revert the specified files or directories
6290 to the contents they had in the parent of the working directory.
6288 to the contents they had in the parent of the working directory.
6291 This restores the contents of files to an unmodified
6289 This restores the contents of files to an unmodified
6292 state and unschedules adds, removes, copies, and renames. If the
6290 state and unschedules adds, removes, copies, and renames. If the
6293 working directory has two parents, you must explicitly specify a
6291 working directory has two parents, you must explicitly specify a
6294 revision.
6292 revision.
6295
6293
6296 Using the -r/--rev or -d/--date options, revert the given files or
6294 Using the -r/--rev or -d/--date options, revert the given files or
6297 directories to their states as of a specific revision. Because
6295 directories to their states as of a specific revision. Because
6298 revert does not change the working directory parents, this will
6296 revert does not change the working directory parents, this will
6299 cause these files to appear modified. This can be helpful to "back
6297 cause these files to appear modified. This can be helpful to "back
6300 out" some or all of an earlier change. See :hg:`backout` for a
6298 out" some or all of an earlier change. See :hg:`backout` for a
6301 related method.
6299 related method.
6302
6300
6303 Modified files are saved with a .orig suffix before reverting.
6301 Modified files are saved with a .orig suffix before reverting.
6304 To disable these backups, use --no-backup. It is possible to store
6302 To disable these backups, use --no-backup. It is possible to store
6305 the backup files in a custom directory relative to the root of the
6303 the backup files in a custom directory relative to the root of the
6306 repository by setting the ``ui.origbackuppath`` configuration
6304 repository by setting the ``ui.origbackuppath`` configuration
6307 option.
6305 option.
6308
6306
6309 See :hg:`help dates` for a list of formats valid for -d/--date.
6307 See :hg:`help dates` for a list of formats valid for -d/--date.
6310
6308
6311 See :hg:`help backout` for a way to reverse the effect of an
6309 See :hg:`help backout` for a way to reverse the effect of an
6312 earlier changeset.
6310 earlier changeset.
6313
6311
6314 Returns 0 on success.
6312 Returns 0 on success.
6315 """
6313 """
6316
6314
6317 opts = pycompat.byteskwargs(opts)
6315 opts = pycompat.byteskwargs(opts)
6318 if opts.get(b"date"):
6316 if opts.get(b"date"):
6319 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6317 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6320 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6318 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6321
6319
6322 parent, p2 = repo.dirstate.parents()
6320 parent, p2 = repo.dirstate.parents()
6323 if not opts.get(b'rev') and p2 != repo.nullid:
6321 if not opts.get(b'rev') and p2 != repo.nullid:
6324 # revert after merge is a trap for new users (issue2915)
6322 # revert after merge is a trap for new users (issue2915)
6325 raise error.InputError(
6323 raise error.InputError(
6326 _(b'uncommitted merge with no revision specified'),
6324 _(b'uncommitted merge with no revision specified'),
6327 hint=_(b"use 'hg update' or see 'hg help revert'"),
6325 hint=_(b"use 'hg update' or see 'hg help revert'"),
6328 )
6326 )
6329
6327
6330 rev = opts.get(b'rev')
6328 rev = opts.get(b'rev')
6331 if rev:
6329 if rev:
6332 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6330 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6333 ctx = logcmdutil.revsingle(repo, rev)
6331 ctx = logcmdutil.revsingle(repo, rev)
6334
6332
6335 if not (
6333 if not (
6336 pats
6334 pats
6337 or opts.get(b'include')
6335 or opts.get(b'include')
6338 or opts.get(b'exclude')
6336 or opts.get(b'exclude')
6339 or opts.get(b'all')
6337 or opts.get(b'all')
6340 or opts.get(b'interactive')
6338 or opts.get(b'interactive')
6341 ):
6339 ):
6342 msg = _(b"no files or directories specified")
6340 msg = _(b"no files or directories specified")
6343 if p2 != repo.nullid:
6341 if p2 != repo.nullid:
6344 hint = _(
6342 hint = _(
6345 b"uncommitted merge, use --all to discard all changes,"
6343 b"uncommitted merge, use --all to discard all changes,"
6346 b" or 'hg update -C .' to abort the merge"
6344 b" or 'hg update -C .' to abort the merge"
6347 )
6345 )
6348 raise error.InputError(msg, hint=hint)
6346 raise error.InputError(msg, hint=hint)
6349 dirty = any(repo.status())
6347 dirty = any(repo.status())
6350 node = ctx.node()
6348 node = ctx.node()
6351 if node != parent:
6349 if node != parent:
6352 if dirty:
6350 if dirty:
6353 hint = (
6351 hint = (
6354 _(
6352 _(
6355 b"uncommitted changes, use --all to discard all"
6353 b"uncommitted changes, use --all to discard all"
6356 b" changes, or 'hg update %d' to update"
6354 b" changes, or 'hg update %d' to update"
6357 )
6355 )
6358 % ctx.rev()
6356 % ctx.rev()
6359 )
6357 )
6360 else:
6358 else:
6361 hint = (
6359 hint = (
6362 _(
6360 _(
6363 b"use --all to revert all files,"
6361 b"use --all to revert all files,"
6364 b" or 'hg update %d' to update"
6362 b" or 'hg update %d' to update"
6365 )
6363 )
6366 % ctx.rev()
6364 % ctx.rev()
6367 )
6365 )
6368 elif dirty:
6366 elif dirty:
6369 hint = _(b"uncommitted changes, use --all to discard all changes")
6367 hint = _(b"uncommitted changes, use --all to discard all changes")
6370 else:
6368 else:
6371 hint = _(b"use --all to revert all files")
6369 hint = _(b"use --all to revert all files")
6372 raise error.InputError(msg, hint=hint)
6370 raise error.InputError(msg, hint=hint)
6373
6371
6374 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6372 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6375
6373
6376
6374
6377 @command(
6375 @command(
6378 b'rollback',
6376 b'rollback',
6379 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6377 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6380 helpcategory=command.CATEGORY_MAINTENANCE,
6378 helpcategory=command.CATEGORY_MAINTENANCE,
6381 )
6379 )
6382 def rollback(ui, repo, **opts):
6380 def rollback(ui, repo, **opts):
6383 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6381 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6384
6382
6385 Please use :hg:`commit --amend` instead of rollback to correct
6383 Please use :hg:`commit --amend` instead of rollback to correct
6386 mistakes in the last commit.
6384 mistakes in the last commit.
6387
6385
6388 This command should be used with care. There is only one level of
6386 This command should be used with care. There is only one level of
6389 rollback, and there is no way to undo a rollback. It will also
6387 rollback, and there is no way to undo a rollback. It will also
6390 restore the dirstate at the time of the last transaction, losing
6388 restore the dirstate at the time of the last transaction, losing
6391 any dirstate changes since that time. This command does not alter
6389 any dirstate changes since that time. This command does not alter
6392 the working directory.
6390 the working directory.
6393
6391
6394 Transactions are used to encapsulate the effects of all commands
6392 Transactions are used to encapsulate the effects of all commands
6395 that create new changesets or propagate existing changesets into a
6393 that create new changesets or propagate existing changesets into a
6396 repository.
6394 repository.
6397
6395
6398 .. container:: verbose
6396 .. container:: verbose
6399
6397
6400 For example, the following commands are transactional, and their
6398 For example, the following commands are transactional, and their
6401 effects can be rolled back:
6399 effects can be rolled back:
6402
6400
6403 - commit
6401 - commit
6404 - import
6402 - import
6405 - pull
6403 - pull
6406 - push (with this repository as the destination)
6404 - push (with this repository as the destination)
6407 - unbundle
6405 - unbundle
6408
6406
6409 To avoid permanent data loss, rollback will refuse to rollback a
6407 To avoid permanent data loss, rollback will refuse to rollback a
6410 commit transaction if it isn't checked out. Use --force to
6408 commit transaction if it isn't checked out. Use --force to
6411 override this protection.
6409 override this protection.
6412
6410
6413 The rollback command can be entirely disabled by setting the
6411 The rollback command can be entirely disabled by setting the
6414 ``ui.rollback`` configuration setting to false. If you're here
6412 ``ui.rollback`` configuration setting to false. If you're here
6415 because you want to use rollback and it's disabled, you can
6413 because you want to use rollback and it's disabled, you can
6416 re-enable the command by setting ``ui.rollback`` to true.
6414 re-enable the command by setting ``ui.rollback`` to true.
6417
6415
6418 This command is not intended for use on public repositories. Once
6416 This command is not intended for use on public repositories. Once
6419 changes are visible for pull by other users, rolling a transaction
6417 changes are visible for pull by other users, rolling a transaction
6420 back locally is ineffective (someone else may already have pulled
6418 back locally is ineffective (someone else may already have pulled
6421 the changes). Furthermore, a race is possible with readers of the
6419 the changes). Furthermore, a race is possible with readers of the
6422 repository; for example an in-progress pull from the repository
6420 repository; for example an in-progress pull from the repository
6423 may fail if a rollback is performed.
6421 may fail if a rollback is performed.
6424
6422
6425 Returns 0 on success, 1 if no rollback data is available.
6423 Returns 0 on success, 1 if no rollback data is available.
6426 """
6424 """
6427 if not ui.configbool(b'ui', b'rollback'):
6425 if not ui.configbool(b'ui', b'rollback'):
6428 raise error.Abort(
6426 raise error.Abort(
6429 _(b'rollback is disabled because it is unsafe'),
6427 _(b'rollback is disabled because it is unsafe'),
6430 hint=b'see `hg help -v rollback` for information',
6428 hint=b'see `hg help -v rollback` for information',
6431 )
6429 )
6432 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6430 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6433
6431
6434
6432
6435 @command(
6433 @command(
6436 b'root',
6434 b'root',
6437 [] + formatteropts,
6435 [] + formatteropts,
6438 intents={INTENT_READONLY},
6436 intents={INTENT_READONLY},
6439 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6437 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6440 )
6438 )
6441 def root(ui, repo, **opts):
6439 def root(ui, repo, **opts):
6442 """print the root (top) of the current working directory
6440 """print the root (top) of the current working directory
6443
6441
6444 Print the root directory of the current repository.
6442 Print the root directory of the current repository.
6445
6443
6446 .. container:: verbose
6444 .. container:: verbose
6447
6445
6448 Template:
6446 Template:
6449
6447
6450 The following keywords are supported in addition to the common template
6448 The following keywords are supported in addition to the common template
6451 keywords and functions. See also :hg:`help templates`.
6449 keywords and functions. See also :hg:`help templates`.
6452
6450
6453 :hgpath: String. Path to the .hg directory.
6451 :hgpath: String. Path to the .hg directory.
6454 :storepath: String. Path to the directory holding versioned data.
6452 :storepath: String. Path to the directory holding versioned data.
6455
6453
6456 Returns 0 on success.
6454 Returns 0 on success.
6457 """
6455 """
6458 opts = pycompat.byteskwargs(opts)
6456 opts = pycompat.byteskwargs(opts)
6459 with ui.formatter(b'root', opts) as fm:
6457 with ui.formatter(b'root', opts) as fm:
6460 fm.startitem()
6458 fm.startitem()
6461 fm.write(b'reporoot', b'%s\n', repo.root)
6459 fm.write(b'reporoot', b'%s\n', repo.root)
6462 fm.data(hgpath=repo.path, storepath=repo.spath)
6460 fm.data(hgpath=repo.path, storepath=repo.spath)
6463
6461
6464
6462
6465 @command(
6463 @command(
6466 b'serve',
6464 b'serve',
6467 [
6465 [
6468 (
6466 (
6469 b'A',
6467 b'A',
6470 b'accesslog',
6468 b'accesslog',
6471 b'',
6469 b'',
6472 _(b'name of access log file to write to'),
6470 _(b'name of access log file to write to'),
6473 _(b'FILE'),
6471 _(b'FILE'),
6474 ),
6472 ),
6475 (b'd', b'daemon', None, _(b'run server in background')),
6473 (b'd', b'daemon', None, _(b'run server in background')),
6476 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6474 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6477 (
6475 (
6478 b'E',
6476 b'E',
6479 b'errorlog',
6477 b'errorlog',
6480 b'',
6478 b'',
6481 _(b'name of error log file to write to'),
6479 _(b'name of error log file to write to'),
6482 _(b'FILE'),
6480 _(b'FILE'),
6483 ),
6481 ),
6484 # use string type, then we can check if something was passed
6482 # use string type, then we can check if something was passed
6485 (
6483 (
6486 b'p',
6484 b'p',
6487 b'port',
6485 b'port',
6488 b'',
6486 b'',
6489 _(b'port to listen on (default: 8000)'),
6487 _(b'port to listen on (default: 8000)'),
6490 _(b'PORT'),
6488 _(b'PORT'),
6491 ),
6489 ),
6492 (
6490 (
6493 b'a',
6491 b'a',
6494 b'address',
6492 b'address',
6495 b'',
6493 b'',
6496 _(b'address to listen on (default: all interfaces)'),
6494 _(b'address to listen on (default: all interfaces)'),
6497 _(b'ADDR'),
6495 _(b'ADDR'),
6498 ),
6496 ),
6499 (
6497 (
6500 b'',
6498 b'',
6501 b'prefix',
6499 b'prefix',
6502 b'',
6500 b'',
6503 _(b'prefix path to serve from (default: server root)'),
6501 _(b'prefix path to serve from (default: server root)'),
6504 _(b'PREFIX'),
6502 _(b'PREFIX'),
6505 ),
6503 ),
6506 (
6504 (
6507 b'n',
6505 b'n',
6508 b'name',
6506 b'name',
6509 b'',
6507 b'',
6510 _(b'name to show in web pages (default: working directory)'),
6508 _(b'name to show in web pages (default: working directory)'),
6511 _(b'NAME'),
6509 _(b'NAME'),
6512 ),
6510 ),
6513 (
6511 (
6514 b'',
6512 b'',
6515 b'web-conf',
6513 b'web-conf',
6516 b'',
6514 b'',
6517 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6515 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6518 _(b'FILE'),
6516 _(b'FILE'),
6519 ),
6517 ),
6520 (
6518 (
6521 b'',
6519 b'',
6522 b'webdir-conf',
6520 b'webdir-conf',
6523 b'',
6521 b'',
6524 _(b'name of the hgweb config file (DEPRECATED)'),
6522 _(b'name of the hgweb config file (DEPRECATED)'),
6525 _(b'FILE'),
6523 _(b'FILE'),
6526 ),
6524 ),
6527 (
6525 (
6528 b'',
6526 b'',
6529 b'pid-file',
6527 b'pid-file',
6530 b'',
6528 b'',
6531 _(b'name of file to write process ID to'),
6529 _(b'name of file to write process ID to'),
6532 _(b'FILE'),
6530 _(b'FILE'),
6533 ),
6531 ),
6534 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6532 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6535 (
6533 (
6536 b'',
6534 b'',
6537 b'cmdserver',
6535 b'cmdserver',
6538 b'',
6536 b'',
6539 _(b'for remote clients (ADVANCED)'),
6537 _(b'for remote clients (ADVANCED)'),
6540 _(b'MODE'),
6538 _(b'MODE'),
6541 ),
6539 ),
6542 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6540 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6543 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6541 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6544 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6542 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6545 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6543 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6546 (b'', b'print-url', None, _(b'start and print only the URL')),
6544 (b'', b'print-url', None, _(b'start and print only the URL')),
6547 ]
6545 ]
6548 + subrepoopts,
6546 + subrepoopts,
6549 _(b'[OPTION]...'),
6547 _(b'[OPTION]...'),
6550 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6548 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6551 helpbasic=True,
6549 helpbasic=True,
6552 optionalrepo=True,
6550 optionalrepo=True,
6553 )
6551 )
6554 def serve(ui, repo, **opts):
6552 def serve(ui, repo, **opts):
6555 """start stand-alone webserver
6553 """start stand-alone webserver
6556
6554
6557 Start a local HTTP repository browser and pull server. You can use
6555 Start a local HTTP repository browser and pull server. You can use
6558 this for ad-hoc sharing and browsing of repositories. It is
6556 this for ad-hoc sharing and browsing of repositories. It is
6559 recommended to use a real web server to serve a repository for
6557 recommended to use a real web server to serve a repository for
6560 longer periods of time.
6558 longer periods of time.
6561
6559
6562 Please note that the server does not implement access control.
6560 Please note that the server does not implement access control.
6563 This means that, by default, anybody can read from the server and
6561 This means that, by default, anybody can read from the server and
6564 nobody can write to it by default. Set the ``web.allow-push``
6562 nobody can write to it by default. Set the ``web.allow-push``
6565 option to ``*`` to allow everybody to push to the server. You
6563 option to ``*`` to allow everybody to push to the server. You
6566 should use a real web server if you need to authenticate users.
6564 should use a real web server if you need to authenticate users.
6567
6565
6568 By default, the server logs accesses to stdout and errors to
6566 By default, the server logs accesses to stdout and errors to
6569 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6567 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6570 files.
6568 files.
6571
6569
6572 To have the server choose a free port number to listen on, specify
6570 To have the server choose a free port number to listen on, specify
6573 a port number of 0; in this case, the server will print the port
6571 a port number of 0; in this case, the server will print the port
6574 number it uses.
6572 number it uses.
6575
6573
6576 Returns 0 on success.
6574 Returns 0 on success.
6577 """
6575 """
6578
6576
6579 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6577 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6580 opts = pycompat.byteskwargs(opts)
6578 opts = pycompat.byteskwargs(opts)
6581 if opts[b"print_url"] and ui.verbose:
6579 if opts[b"print_url"] and ui.verbose:
6582 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6580 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6583
6581
6584 if opts[b"stdio"]:
6582 if opts[b"stdio"]:
6585 if repo is None:
6583 if repo is None:
6586 raise error.RepoError(
6584 raise error.RepoError(
6587 _(b"there is no Mercurial repository here (.hg not found)")
6585 _(b"there is no Mercurial repository here (.hg not found)")
6588 )
6586 )
6589 s = wireprotoserver.sshserver(ui, repo)
6587 s = wireprotoserver.sshserver(ui, repo)
6590 s.serve_forever()
6588 s.serve_forever()
6591 return
6589 return
6592
6590
6593 service = server.createservice(ui, repo, opts)
6591 service = server.createservice(ui, repo, opts)
6594 return server.runservice(opts, initfn=service.init, runfn=service.run)
6592 return server.runservice(opts, initfn=service.init, runfn=service.run)
6595
6593
6596
6594
6597 @command(
6595 @command(
6598 b'shelve',
6596 b'shelve',
6599 [
6597 [
6600 (
6598 (
6601 b'A',
6599 b'A',
6602 b'addremove',
6600 b'addremove',
6603 None,
6601 None,
6604 _(b'mark new/missing files as added/removed before shelving'),
6602 _(b'mark new/missing files as added/removed before shelving'),
6605 ),
6603 ),
6606 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6604 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6607 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6605 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6608 (
6606 (
6609 b'',
6607 b'',
6610 b'date',
6608 b'date',
6611 b'',
6609 b'',
6612 _(b'shelve with the specified commit date'),
6610 _(b'shelve with the specified commit date'),
6613 _(b'DATE'),
6611 _(b'DATE'),
6614 ),
6612 ),
6615 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6613 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6616 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6614 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6617 (
6615 (
6618 b'k',
6616 b'k',
6619 b'keep',
6617 b'keep',
6620 False,
6618 False,
6621 _(b'shelve, but keep changes in the working directory'),
6619 _(b'shelve, but keep changes in the working directory'),
6622 ),
6620 ),
6623 (b'l', b'list', None, _(b'list current shelves')),
6621 (b'l', b'list', None, _(b'list current shelves')),
6624 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6622 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6625 (
6623 (
6626 b'n',
6624 b'n',
6627 b'name',
6625 b'name',
6628 b'',
6626 b'',
6629 _(b'use the given name for the shelved commit'),
6627 _(b'use the given name for the shelved commit'),
6630 _(b'NAME'),
6628 _(b'NAME'),
6631 ),
6629 ),
6632 (
6630 (
6633 b'p',
6631 b'p',
6634 b'patch',
6632 b'patch',
6635 None,
6633 None,
6636 _(
6634 _(
6637 b'output patches for changes (provide the names of the shelved '
6635 b'output patches for changes (provide the names of the shelved '
6638 b'changes as positional arguments)'
6636 b'changes as positional arguments)'
6639 ),
6637 ),
6640 ),
6638 ),
6641 (b'i', b'interactive', None, _(b'interactive mode')),
6639 (b'i', b'interactive', None, _(b'interactive mode')),
6642 (
6640 (
6643 b'',
6641 b'',
6644 b'stat',
6642 b'stat',
6645 None,
6643 None,
6646 _(
6644 _(
6647 b'output diffstat-style summary of changes (provide the names of '
6645 b'output diffstat-style summary of changes (provide the names of '
6648 b'the shelved changes as positional arguments)'
6646 b'the shelved changes as positional arguments)'
6649 ),
6647 ),
6650 ),
6648 ),
6651 ]
6649 ]
6652 + cmdutil.walkopts,
6650 + cmdutil.walkopts,
6653 _(b'hg shelve [OPTION]... [FILE]...'),
6651 _(b'hg shelve [OPTION]... [FILE]...'),
6654 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6652 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6655 )
6653 )
6656 def shelve(ui, repo, *pats, **opts):
6654 def shelve(ui, repo, *pats, **opts):
6657 """save and set aside changes from the working directory
6655 """save and set aside changes from the working directory
6658
6656
6659 Shelving takes files that "hg status" reports as not clean, saves
6657 Shelving takes files that "hg status" reports as not clean, saves
6660 the modifications to a bundle (a shelved change), and reverts the
6658 the modifications to a bundle (a shelved change), and reverts the
6661 files so that their state in the working directory becomes clean.
6659 files so that their state in the working directory becomes clean.
6662
6660
6663 To restore these changes to the working directory, using "hg
6661 To restore these changes to the working directory, using "hg
6664 unshelve"; this will work even if you switch to a different
6662 unshelve"; this will work even if you switch to a different
6665 commit.
6663 commit.
6666
6664
6667 When no files are specified, "hg shelve" saves all not-clean
6665 When no files are specified, "hg shelve" saves all not-clean
6668 files. If specific files or directories are named, only changes to
6666 files. If specific files or directories are named, only changes to
6669 those files are shelved.
6667 those files are shelved.
6670
6668
6671 In bare shelve (when no files are specified, without interactive,
6669 In bare shelve (when no files are specified, without interactive,
6672 include and exclude option), shelving remembers information if the
6670 include and exclude option), shelving remembers information if the
6673 working directory was on newly created branch, in other words working
6671 working directory was on newly created branch, in other words working
6674 directory was on different branch than its first parent. In this
6672 directory was on different branch than its first parent. In this
6675 situation unshelving restores branch information to the working directory.
6673 situation unshelving restores branch information to the working directory.
6676
6674
6677 Each shelved change has a name that makes it easier to find later.
6675 Each shelved change has a name that makes it easier to find later.
6678 The name of a shelved change defaults to being based on the active
6676 The name of a shelved change defaults to being based on the active
6679 bookmark, or if there is no active bookmark, the current named
6677 bookmark, or if there is no active bookmark, the current named
6680 branch. To specify a different name, use ``--name``.
6678 branch. To specify a different name, use ``--name``.
6681
6679
6682 To see a list of existing shelved changes, use the ``--list``
6680 To see a list of existing shelved changes, use the ``--list``
6683 option. For each shelved change, this will print its name, age,
6681 option. For each shelved change, this will print its name, age,
6684 and description; use ``--patch`` or ``--stat`` for more details.
6682 and description; use ``--patch`` or ``--stat`` for more details.
6685
6683
6686 To delete specific shelved changes, use ``--delete``. To delete
6684 To delete specific shelved changes, use ``--delete``. To delete
6687 all shelved changes, use ``--cleanup``.
6685 all shelved changes, use ``--cleanup``.
6688 """
6686 """
6689 opts = pycompat.byteskwargs(opts)
6687 opts = pycompat.byteskwargs(opts)
6690 allowables = [
6688 allowables = [
6691 (b'addremove', {b'create'}), # 'create' is pseudo action
6689 (b'addremove', {b'create'}), # 'create' is pseudo action
6692 (b'unknown', {b'create'}),
6690 (b'unknown', {b'create'}),
6693 (b'cleanup', {b'cleanup'}),
6691 (b'cleanup', {b'cleanup'}),
6694 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6692 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6695 (b'delete', {b'delete'}),
6693 (b'delete', {b'delete'}),
6696 (b'edit', {b'create'}),
6694 (b'edit', {b'create'}),
6697 (b'keep', {b'create'}),
6695 (b'keep', {b'create'}),
6698 (b'list', {b'list'}),
6696 (b'list', {b'list'}),
6699 (b'message', {b'create'}),
6697 (b'message', {b'create'}),
6700 (b'name', {b'create'}),
6698 (b'name', {b'create'}),
6701 (b'patch', {b'patch', b'list'}),
6699 (b'patch', {b'patch', b'list'}),
6702 (b'stat', {b'stat', b'list'}),
6700 (b'stat', {b'stat', b'list'}),
6703 ]
6701 ]
6704
6702
6705 def checkopt(opt):
6703 def checkopt(opt):
6706 if opts.get(opt):
6704 if opts.get(opt):
6707 for i, allowable in allowables:
6705 for i, allowable in allowables:
6708 if opts[i] and opt not in allowable:
6706 if opts[i] and opt not in allowable:
6709 raise error.InputError(
6707 raise error.InputError(
6710 _(
6708 _(
6711 b"options '--%s' and '--%s' may not be "
6709 b"options '--%s' and '--%s' may not be "
6712 b"used together"
6710 b"used together"
6713 )
6711 )
6714 % (opt, i)
6712 % (opt, i)
6715 )
6713 )
6716 return True
6714 return True
6717
6715
6718 if checkopt(b'cleanup'):
6716 if checkopt(b'cleanup'):
6719 if pats:
6717 if pats:
6720 raise error.InputError(
6718 raise error.InputError(
6721 _(b"cannot specify names when using '--cleanup'")
6719 _(b"cannot specify names when using '--cleanup'")
6722 )
6720 )
6723 return shelvemod.cleanupcmd(ui, repo)
6721 return shelvemod.cleanupcmd(ui, repo)
6724 elif checkopt(b'delete'):
6722 elif checkopt(b'delete'):
6725 return shelvemod.deletecmd(ui, repo, pats)
6723 return shelvemod.deletecmd(ui, repo, pats)
6726 elif checkopt(b'list'):
6724 elif checkopt(b'list'):
6727 return shelvemod.listcmd(ui, repo, pats, opts)
6725 return shelvemod.listcmd(ui, repo, pats, opts)
6728 elif checkopt(b'patch') or checkopt(b'stat'):
6726 elif checkopt(b'patch') or checkopt(b'stat'):
6729 return shelvemod.patchcmds(ui, repo, pats, opts)
6727 return shelvemod.patchcmds(ui, repo, pats, opts)
6730 else:
6728 else:
6731 return shelvemod.createcmd(ui, repo, pats, opts)
6729 return shelvemod.createcmd(ui, repo, pats, opts)
6732
6730
6733
6731
6734 _NOTTERSE = b'nothing'
6732 _NOTTERSE = b'nothing'
6735
6733
6736
6734
6737 @command(
6735 @command(
6738 b'status|st',
6736 b'status|st',
6739 [
6737 [
6740 (b'A', b'all', None, _(b'show status of all files')),
6738 (b'A', b'all', None, _(b'show status of all files')),
6741 (b'm', b'modified', None, _(b'show only modified files')),
6739 (b'm', b'modified', None, _(b'show only modified files')),
6742 (b'a', b'added', None, _(b'show only added files')),
6740 (b'a', b'added', None, _(b'show only added files')),
6743 (b'r', b'removed', None, _(b'show only removed files')),
6741 (b'r', b'removed', None, _(b'show only removed files')),
6744 (b'd', b'deleted', None, _(b'show only missing files')),
6742 (b'd', b'deleted', None, _(b'show only missing files')),
6745 (b'c', b'clean', None, _(b'show only files without changes')),
6743 (b'c', b'clean', None, _(b'show only files without changes')),
6746 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6744 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6747 (b'i', b'ignored', None, _(b'show only ignored files')),
6745 (b'i', b'ignored', None, _(b'show only ignored files')),
6748 (b'n', b'no-status', None, _(b'hide status prefix')),
6746 (b'n', b'no-status', None, _(b'hide status prefix')),
6749 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6747 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6750 (
6748 (
6751 b'C',
6749 b'C',
6752 b'copies',
6750 b'copies',
6753 None,
6751 None,
6754 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6752 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6755 ),
6753 ),
6756 (
6754 (
6757 b'0',
6755 b'0',
6758 b'print0',
6756 b'print0',
6759 None,
6757 None,
6760 _(b'end filenames with NUL, for use with xargs'),
6758 _(b'end filenames with NUL, for use with xargs'),
6761 ),
6759 ),
6762 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6760 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6763 (
6761 (
6764 b'',
6762 b'',
6765 b'change',
6763 b'change',
6766 b'',
6764 b'',
6767 _(b'list the changed files of a revision'),
6765 _(b'list the changed files of a revision'),
6768 _(b'REV'),
6766 _(b'REV'),
6769 ),
6767 ),
6770 ]
6768 ]
6771 + walkopts
6769 + walkopts
6772 + subrepoopts
6770 + subrepoopts
6773 + formatteropts,
6771 + formatteropts,
6774 _(b'[OPTION]... [FILE]...'),
6772 _(b'[OPTION]... [FILE]...'),
6775 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6773 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6776 helpbasic=True,
6774 helpbasic=True,
6777 inferrepo=True,
6775 inferrepo=True,
6778 intents={INTENT_READONLY},
6776 intents={INTENT_READONLY},
6779 )
6777 )
6780 def status(ui, repo, *pats, **opts):
6778 def status(ui, repo, *pats, **opts):
6781 """show changed files in the working directory
6779 """show changed files in the working directory
6782
6780
6783 Show status of files in the repository. If names are given, only
6781 Show status of files in the repository. If names are given, only
6784 files that match are shown. Files that are clean or ignored or
6782 files that match are shown. Files that are clean or ignored or
6785 the source of a copy/move operation, are not listed unless
6783 the source of a copy/move operation, are not listed unless
6786 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6784 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6787 Unless options described with "show only ..." are given, the
6785 Unless options described with "show only ..." are given, the
6788 options -mardu are used.
6786 options -mardu are used.
6789
6787
6790 Option -q/--quiet hides untracked (unknown and ignored) files
6788 Option -q/--quiet hides untracked (unknown and ignored) files
6791 unless explicitly requested with -u/--unknown or -i/--ignored.
6789 unless explicitly requested with -u/--unknown or -i/--ignored.
6792
6790
6793 .. note::
6791 .. note::
6794
6792
6795 :hg:`status` may appear to disagree with diff if permissions have
6793 :hg:`status` may appear to disagree with diff if permissions have
6796 changed or a merge has occurred. The standard diff format does
6794 changed or a merge has occurred. The standard diff format does
6797 not report permission changes and diff only reports changes
6795 not report permission changes and diff only reports changes
6798 relative to one merge parent.
6796 relative to one merge parent.
6799
6797
6800 If one revision is given, it is used as the base revision.
6798 If one revision is given, it is used as the base revision.
6801 If two revisions are given, the differences between them are
6799 If two revisions are given, the differences between them are
6802 shown. The --change option can also be used as a shortcut to list
6800 shown. The --change option can also be used as a shortcut to list
6803 the changed files of a revision from its first parent.
6801 the changed files of a revision from its first parent.
6804
6802
6805 The codes used to show the status of files are::
6803 The codes used to show the status of files are::
6806
6804
6807 M = modified
6805 M = modified
6808 A = added
6806 A = added
6809 R = removed
6807 R = removed
6810 C = clean
6808 C = clean
6811 ! = missing (deleted by non-hg command, but still tracked)
6809 ! = missing (deleted by non-hg command, but still tracked)
6812 ? = not tracked
6810 ? = not tracked
6813 I = ignored
6811 I = ignored
6814 = origin of the previous file (with --copies)
6812 = origin of the previous file (with --copies)
6815
6813
6816 .. container:: verbose
6814 .. container:: verbose
6817
6815
6818 The -t/--terse option abbreviates the output by showing only the directory
6816 The -t/--terse option abbreviates the output by showing only the directory
6819 name if all the files in it share the same status. The option takes an
6817 name if all the files in it share the same status. The option takes an
6820 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6818 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6821 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6819 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6822 for 'ignored' and 'c' for clean.
6820 for 'ignored' and 'c' for clean.
6823
6821
6824 It abbreviates only those statuses which are passed. Note that clean and
6822 It abbreviates only those statuses which are passed. Note that clean and
6825 ignored files are not displayed with '--terse ic' unless the -c/--clean
6823 ignored files are not displayed with '--terse ic' unless the -c/--clean
6826 and -i/--ignored options are also used.
6824 and -i/--ignored options are also used.
6827
6825
6828 The -v/--verbose option shows information when the repository is in an
6826 The -v/--verbose option shows information when the repository is in an
6829 unfinished merge, shelve, rebase state etc. You can have this behavior
6827 unfinished merge, shelve, rebase state etc. You can have this behavior
6830 turned on by default by enabling the ``commands.status.verbose`` option.
6828 turned on by default by enabling the ``commands.status.verbose`` option.
6831
6829
6832 You can skip displaying some of these states by setting
6830 You can skip displaying some of these states by setting
6833 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6831 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6834 'histedit', 'merge', 'rebase', or 'unshelve'.
6832 'histedit', 'merge', 'rebase', or 'unshelve'.
6835
6833
6836 Template:
6834 Template:
6837
6835
6838 The following keywords are supported in addition to the common template
6836 The following keywords are supported in addition to the common template
6839 keywords and functions. See also :hg:`help templates`.
6837 keywords and functions. See also :hg:`help templates`.
6840
6838
6841 :path: String. Repository-absolute path of the file.
6839 :path: String. Repository-absolute path of the file.
6842 :source: String. Repository-absolute path of the file originated from.
6840 :source: String. Repository-absolute path of the file originated from.
6843 Available if ``--copies`` is specified.
6841 Available if ``--copies`` is specified.
6844 :status: String. Character denoting file's status.
6842 :status: String. Character denoting file's status.
6845
6843
6846 Examples:
6844 Examples:
6847
6845
6848 - show changes in the working directory relative to a
6846 - show changes in the working directory relative to a
6849 changeset::
6847 changeset::
6850
6848
6851 hg status --rev 9353
6849 hg status --rev 9353
6852
6850
6853 - show changes in the working directory relative to the
6851 - show changes in the working directory relative to the
6854 current directory (see :hg:`help patterns` for more information)::
6852 current directory (see :hg:`help patterns` for more information)::
6855
6853
6856 hg status re:
6854 hg status re:
6857
6855
6858 - show all changes including copies in an existing changeset::
6856 - show all changes including copies in an existing changeset::
6859
6857
6860 hg status --copies --change 9353
6858 hg status --copies --change 9353
6861
6859
6862 - get a NUL separated list of added files, suitable for xargs::
6860 - get a NUL separated list of added files, suitable for xargs::
6863
6861
6864 hg status -an0
6862 hg status -an0
6865
6863
6866 - show more information about the repository status, abbreviating
6864 - show more information about the repository status, abbreviating
6867 added, removed, modified, deleted, and untracked paths::
6865 added, removed, modified, deleted, and untracked paths::
6868
6866
6869 hg status -v -t mardu
6867 hg status -v -t mardu
6870
6868
6871 Returns 0 on success.
6869 Returns 0 on success.
6872
6870
6873 """
6871 """
6874
6872
6875 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6873 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6876 opts = pycompat.byteskwargs(opts)
6874 opts = pycompat.byteskwargs(opts)
6877 revs = opts.get(b'rev', [])
6875 revs = opts.get(b'rev', [])
6878 change = opts.get(b'change', b'')
6876 change = opts.get(b'change', b'')
6879 terse = opts.get(b'terse', _NOTTERSE)
6877 terse = opts.get(b'terse', _NOTTERSE)
6880 if terse is _NOTTERSE:
6878 if terse is _NOTTERSE:
6881 if revs:
6879 if revs:
6882 terse = b''
6880 terse = b''
6883 else:
6881 else:
6884 terse = ui.config(b'commands', b'status.terse')
6882 terse = ui.config(b'commands', b'status.terse')
6885
6883
6886 if revs and terse:
6884 if revs and terse:
6887 msg = _(b'cannot use --terse with --rev')
6885 msg = _(b'cannot use --terse with --rev')
6888 raise error.InputError(msg)
6886 raise error.InputError(msg)
6889 elif change:
6887 elif change:
6890 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6888 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6891 ctx2 = logcmdutil.revsingle(repo, change, None)
6889 ctx2 = logcmdutil.revsingle(repo, change, None)
6892 ctx1 = ctx2.p1()
6890 ctx1 = ctx2.p1()
6893 else:
6891 else:
6894 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6892 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6895 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6893 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6896
6894
6897 forcerelativevalue = None
6895 forcerelativevalue = None
6898 if ui.hasconfig(b'commands', b'status.relative'):
6896 if ui.hasconfig(b'commands', b'status.relative'):
6899 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6897 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6900 uipathfn = scmutil.getuipathfn(
6898 uipathfn = scmutil.getuipathfn(
6901 repo,
6899 repo,
6902 legacyrelativevalue=bool(pats),
6900 legacyrelativevalue=bool(pats),
6903 forcerelativevalue=forcerelativevalue,
6901 forcerelativevalue=forcerelativevalue,
6904 )
6902 )
6905
6903
6906 if opts.get(b'print0'):
6904 if opts.get(b'print0'):
6907 end = b'\0'
6905 end = b'\0'
6908 else:
6906 else:
6909 end = b'\n'
6907 end = b'\n'
6910 states = b'modified added removed deleted unknown ignored clean'.split()
6908 states = b'modified added removed deleted unknown ignored clean'.split()
6911 show = [k for k in states if opts.get(k)]
6909 show = [k for k in states if opts.get(k)]
6912 if opts.get(b'all'):
6910 if opts.get(b'all'):
6913 show += ui.quiet and (states[:4] + [b'clean']) or states
6911 show += ui.quiet and (states[:4] + [b'clean']) or states
6914
6912
6915 if not show:
6913 if not show:
6916 if ui.quiet:
6914 if ui.quiet:
6917 show = states[:4]
6915 show = states[:4]
6918 else:
6916 else:
6919 show = states[:5]
6917 show = states[:5]
6920
6918
6921 m = scmutil.match(ctx2, pats, opts)
6919 m = scmutil.match(ctx2, pats, opts)
6922 if terse:
6920 if terse:
6923 # we need to compute clean and unknown to terse
6921 # we need to compute clean and unknown to terse
6924 stat = repo.status(
6922 stat = repo.status(
6925 ctx1.node(),
6923 ctx1.node(),
6926 ctx2.node(),
6924 ctx2.node(),
6927 m,
6925 m,
6928 b'ignored' in show or b'i' in terse,
6926 b'ignored' in show or b'i' in terse,
6929 clean=True,
6927 clean=True,
6930 unknown=True,
6928 unknown=True,
6931 listsubrepos=opts.get(b'subrepos'),
6929 listsubrepos=opts.get(b'subrepos'),
6932 )
6930 )
6933
6931
6934 stat = cmdutil.tersedir(stat, terse)
6932 stat = cmdutil.tersedir(stat, terse)
6935 else:
6933 else:
6936 stat = repo.status(
6934 stat = repo.status(
6937 ctx1.node(),
6935 ctx1.node(),
6938 ctx2.node(),
6936 ctx2.node(),
6939 m,
6937 m,
6940 b'ignored' in show,
6938 b'ignored' in show,
6941 b'clean' in show,
6939 b'clean' in show,
6942 b'unknown' in show,
6940 b'unknown' in show,
6943 opts.get(b'subrepos'),
6941 opts.get(b'subrepos'),
6944 )
6942 )
6945
6943
6946 changestates = zip(
6944 changestates = zip(
6947 states,
6945 states,
6948 pycompat.iterbytestr(b'MAR!?IC'),
6946 pycompat.iterbytestr(b'MAR!?IC'),
6949 [getattr(stat, s.decode('utf8')) for s in states],
6947 [getattr(stat, s.decode('utf8')) for s in states],
6950 )
6948 )
6951
6949
6952 copy = {}
6950 copy = {}
6953 if (
6951 if (
6954 opts.get(b'all')
6952 opts.get(b'all')
6955 or opts.get(b'copies')
6953 or opts.get(b'copies')
6956 or ui.configbool(b'ui', b'statuscopies')
6954 or ui.configbool(b'ui', b'statuscopies')
6957 ) and not opts.get(b'no_status'):
6955 ) and not opts.get(b'no_status'):
6958 copy = copies.pathcopies(ctx1, ctx2, m)
6956 copy = copies.pathcopies(ctx1, ctx2, m)
6959
6957
6960 morestatus = None
6958 morestatus = None
6961 if (
6959 if (
6962 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6960 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6963 and not ui.plain()
6961 and not ui.plain()
6964 and not opts.get(b'print0')
6962 and not opts.get(b'print0')
6965 ):
6963 ):
6966 morestatus = cmdutil.readmorestatus(repo)
6964 morestatus = cmdutil.readmorestatus(repo)
6967
6965
6968 ui.pager(b'status')
6966 ui.pager(b'status')
6969 fm = ui.formatter(b'status', opts)
6967 fm = ui.formatter(b'status', opts)
6970 fmt = b'%s' + end
6968 fmt = b'%s' + end
6971 showchar = not opts.get(b'no_status')
6969 showchar = not opts.get(b'no_status')
6972
6970
6973 for state, char, files in changestates:
6971 for state, char, files in changestates:
6974 if state in show:
6972 if state in show:
6975 label = b'status.' + state
6973 label = b'status.' + state
6976 for f in files:
6974 for f in files:
6977 fm.startitem()
6975 fm.startitem()
6978 fm.context(ctx=ctx2)
6976 fm.context(ctx=ctx2)
6979 fm.data(itemtype=b'file', path=f)
6977 fm.data(itemtype=b'file', path=f)
6980 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6978 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6981 fm.plain(fmt % uipathfn(f), label=label)
6979 fm.plain(fmt % uipathfn(f), label=label)
6982 if f in copy:
6980 if f in copy:
6983 fm.data(source=copy[f])
6981 fm.data(source=copy[f])
6984 fm.plain(
6982 fm.plain(
6985 (b' %s' + end) % uipathfn(copy[f]),
6983 (b' %s' + end) % uipathfn(copy[f]),
6986 label=b'status.copied',
6984 label=b'status.copied',
6987 )
6985 )
6988 if morestatus:
6986 if morestatus:
6989 morestatus.formatfile(f, fm)
6987 morestatus.formatfile(f, fm)
6990
6988
6991 if morestatus:
6989 if morestatus:
6992 morestatus.formatfooter(fm)
6990 morestatus.formatfooter(fm)
6993 fm.end()
6991 fm.end()
6994
6992
6995
6993
6996 @command(
6994 @command(
6997 b'summary|sum',
6995 b'summary|sum',
6998 [(b'', b'remote', None, _(b'check for push and pull'))],
6996 [(b'', b'remote', None, _(b'check for push and pull'))],
6999 b'[--remote]',
6997 b'[--remote]',
7000 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6998 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7001 helpbasic=True,
6999 helpbasic=True,
7002 intents={INTENT_READONLY},
7000 intents={INTENT_READONLY},
7003 )
7001 )
7004 def summary(ui, repo, **opts):
7002 def summary(ui, repo, **opts):
7005 """summarize working directory state
7003 """summarize working directory state
7006
7004
7007 This generates a brief summary of the working directory state,
7005 This generates a brief summary of the working directory state,
7008 including parents, branch, commit status, phase and available updates.
7006 including parents, branch, commit status, phase and available updates.
7009
7007
7010 With the --remote option, this will check the default paths for
7008 With the --remote option, this will check the default paths for
7011 incoming and outgoing changes. This can be time-consuming.
7009 incoming and outgoing changes. This can be time-consuming.
7012
7010
7013 Returns 0 on success.
7011 Returns 0 on success.
7014 """
7012 """
7015
7013
7016 opts = pycompat.byteskwargs(opts)
7014 opts = pycompat.byteskwargs(opts)
7017 ui.pager(b'summary')
7015 ui.pager(b'summary')
7018 ctx = repo[None]
7016 ctx = repo[None]
7019 parents = ctx.parents()
7017 parents = ctx.parents()
7020 pnode = parents[0].node()
7018 pnode = parents[0].node()
7021 marks = []
7019 marks = []
7022
7020
7023 try:
7021 try:
7024 ms = mergestatemod.mergestate.read(repo)
7022 ms = mergestatemod.mergestate.read(repo)
7025 except error.UnsupportedMergeRecords as e:
7023 except error.UnsupportedMergeRecords as e:
7026 s = b' '.join(e.recordtypes)
7024 s = b' '.join(e.recordtypes)
7027 ui.warn(
7025 ui.warn(
7028 _(b'warning: merge state has unsupported record types: %s\n') % s
7026 _(b'warning: merge state has unsupported record types: %s\n') % s
7029 )
7027 )
7030 unresolved = []
7028 unresolved = []
7031 else:
7029 else:
7032 unresolved = list(ms.unresolved())
7030 unresolved = list(ms.unresolved())
7033
7031
7034 for p in parents:
7032 for p in parents:
7035 # label with log.changeset (instead of log.parent) since this
7033 # label with log.changeset (instead of log.parent) since this
7036 # shows a working directory parent *changeset*:
7034 # shows a working directory parent *changeset*:
7037 # i18n: column positioning for "hg summary"
7035 # i18n: column positioning for "hg summary"
7038 ui.write(
7036 ui.write(
7039 _(b'parent: %d:%s ') % (p.rev(), p),
7037 _(b'parent: %d:%s ') % (p.rev(), p),
7040 label=logcmdutil.changesetlabels(p),
7038 label=logcmdutil.changesetlabels(p),
7041 )
7039 )
7042 ui.write(b' '.join(p.tags()), label=b'log.tag')
7040 ui.write(b' '.join(p.tags()), label=b'log.tag')
7043 if p.bookmarks():
7041 if p.bookmarks():
7044 marks.extend(p.bookmarks())
7042 marks.extend(p.bookmarks())
7045 if p.rev() == -1:
7043 if p.rev() == -1:
7046 if not len(repo):
7044 if not len(repo):
7047 ui.write(_(b' (empty repository)'))
7045 ui.write(_(b' (empty repository)'))
7048 else:
7046 else:
7049 ui.write(_(b' (no revision checked out)'))
7047 ui.write(_(b' (no revision checked out)'))
7050 if p.obsolete():
7048 if p.obsolete():
7051 ui.write(_(b' (obsolete)'))
7049 ui.write(_(b' (obsolete)'))
7052 if p.isunstable():
7050 if p.isunstable():
7053 instabilities = (
7051 instabilities = (
7054 ui.label(instability, b'trouble.%s' % instability)
7052 ui.label(instability, b'trouble.%s' % instability)
7055 for instability in p.instabilities()
7053 for instability in p.instabilities()
7056 )
7054 )
7057 ui.write(b' (' + b', '.join(instabilities) + b')')
7055 ui.write(b' (' + b', '.join(instabilities) + b')')
7058 ui.write(b'\n')
7056 ui.write(b'\n')
7059 if p.description():
7057 if p.description():
7060 ui.status(
7058 ui.status(
7061 b' ' + p.description().splitlines()[0].strip() + b'\n',
7059 b' ' + p.description().splitlines()[0].strip() + b'\n',
7062 label=b'log.summary',
7060 label=b'log.summary',
7063 )
7061 )
7064
7062
7065 branch = ctx.branch()
7063 branch = ctx.branch()
7066 bheads = repo.branchheads(branch)
7064 bheads = repo.branchheads(branch)
7067 # i18n: column positioning for "hg summary"
7065 # i18n: column positioning for "hg summary"
7068 m = _(b'branch: %s\n') % branch
7066 m = _(b'branch: %s\n') % branch
7069 if branch != b'default':
7067 if branch != b'default':
7070 ui.write(m, label=b'log.branch')
7068 ui.write(m, label=b'log.branch')
7071 else:
7069 else:
7072 ui.status(m, label=b'log.branch')
7070 ui.status(m, label=b'log.branch')
7073
7071
7074 if marks:
7072 if marks:
7075 active = repo._activebookmark
7073 active = repo._activebookmark
7076 # i18n: column positioning for "hg summary"
7074 # i18n: column positioning for "hg summary"
7077 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7075 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7078 if active is not None:
7076 if active is not None:
7079 if active in marks:
7077 if active in marks:
7080 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7078 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7081 marks.remove(active)
7079 marks.remove(active)
7082 else:
7080 else:
7083 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7081 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7084 for m in marks:
7082 for m in marks:
7085 ui.write(b' ' + m, label=b'log.bookmark')
7083 ui.write(b' ' + m, label=b'log.bookmark')
7086 ui.write(b'\n', label=b'log.bookmark')
7084 ui.write(b'\n', label=b'log.bookmark')
7087
7085
7088 status = repo.status(unknown=True)
7086 status = repo.status(unknown=True)
7089
7087
7090 c = repo.dirstate.copies()
7088 c = repo.dirstate.copies()
7091 copied, renamed = [], []
7089 copied, renamed = [], []
7092 for d, s in c.items():
7090 for d, s in c.items():
7093 if s in status.removed:
7091 if s in status.removed:
7094 status.removed.remove(s)
7092 status.removed.remove(s)
7095 renamed.append(d)
7093 renamed.append(d)
7096 else:
7094 else:
7097 copied.append(d)
7095 copied.append(d)
7098 if d in status.added:
7096 if d in status.added:
7099 status.added.remove(d)
7097 status.added.remove(d)
7100
7098
7101 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7099 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7102
7100
7103 labels = [
7101 labels = [
7104 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7102 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7105 (ui.label(_(b'%d added'), b'status.added'), status.added),
7103 (ui.label(_(b'%d added'), b'status.added'), status.added),
7106 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7104 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7107 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7105 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7108 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7106 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7109 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7107 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7110 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7108 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7111 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7109 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7112 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7110 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7113 ]
7111 ]
7114 t = []
7112 t = []
7115 for l, s in labels:
7113 for l, s in labels:
7116 if s:
7114 if s:
7117 t.append(l % len(s))
7115 t.append(l % len(s))
7118
7116
7119 t = b', '.join(t)
7117 t = b', '.join(t)
7120 cleanworkdir = False
7118 cleanworkdir = False
7121
7119
7122 if repo.vfs.exists(b'graftstate'):
7120 if repo.vfs.exists(b'graftstate'):
7123 t += _(b' (graft in progress)')
7121 t += _(b' (graft in progress)')
7124 if repo.vfs.exists(b'updatestate'):
7122 if repo.vfs.exists(b'updatestate'):
7125 t += _(b' (interrupted update)')
7123 t += _(b' (interrupted update)')
7126 elif len(parents) > 1:
7124 elif len(parents) > 1:
7127 t += _(b' (merge)')
7125 t += _(b' (merge)')
7128 elif branch != parents[0].branch():
7126 elif branch != parents[0].branch():
7129 t += _(b' (new branch)')
7127 t += _(b' (new branch)')
7130 elif parents[0].closesbranch() and pnode in repo.branchheads(
7128 elif parents[0].closesbranch() and pnode in repo.branchheads(
7131 branch, closed=True
7129 branch, closed=True
7132 ):
7130 ):
7133 t += _(b' (head closed)')
7131 t += _(b' (head closed)')
7134 elif not (
7132 elif not (
7135 status.modified
7133 status.modified
7136 or status.added
7134 or status.added
7137 or status.removed
7135 or status.removed
7138 or renamed
7136 or renamed
7139 or copied
7137 or copied
7140 or subs
7138 or subs
7141 ):
7139 ):
7142 t += _(b' (clean)')
7140 t += _(b' (clean)')
7143 cleanworkdir = True
7141 cleanworkdir = True
7144 elif pnode not in bheads:
7142 elif pnode not in bheads:
7145 t += _(b' (new branch head)')
7143 t += _(b' (new branch head)')
7146
7144
7147 if parents:
7145 if parents:
7148 pendingphase = max(p.phase() for p in parents)
7146 pendingphase = max(p.phase() for p in parents)
7149 else:
7147 else:
7150 pendingphase = phases.public
7148 pendingphase = phases.public
7151
7149
7152 if pendingphase > phases.newcommitphase(ui):
7150 if pendingphase > phases.newcommitphase(ui):
7153 t += b' (%s)' % phases.phasenames[pendingphase]
7151 t += b' (%s)' % phases.phasenames[pendingphase]
7154
7152
7155 if cleanworkdir:
7153 if cleanworkdir:
7156 # i18n: column positioning for "hg summary"
7154 # i18n: column positioning for "hg summary"
7157 ui.status(_(b'commit: %s\n') % t.strip())
7155 ui.status(_(b'commit: %s\n') % t.strip())
7158 else:
7156 else:
7159 # i18n: column positioning for "hg summary"
7157 # i18n: column positioning for "hg summary"
7160 ui.write(_(b'commit: %s\n') % t.strip())
7158 ui.write(_(b'commit: %s\n') % t.strip())
7161
7159
7162 # all ancestors of branch heads - all ancestors of parent = new csets
7160 # all ancestors of branch heads - all ancestors of parent = new csets
7163 new = len(
7161 new = len(
7164 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7162 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7165 )
7163 )
7166
7164
7167 if new == 0:
7165 if new == 0:
7168 # i18n: column positioning for "hg summary"
7166 # i18n: column positioning for "hg summary"
7169 ui.status(_(b'update: (current)\n'))
7167 ui.status(_(b'update: (current)\n'))
7170 elif pnode not in bheads:
7168 elif pnode not in bheads:
7171 # i18n: column positioning for "hg summary"
7169 # i18n: column positioning for "hg summary"
7172 ui.write(_(b'update: %d new changesets (update)\n') % new)
7170 ui.write(_(b'update: %d new changesets (update)\n') % new)
7173 else:
7171 else:
7174 # i18n: column positioning for "hg summary"
7172 # i18n: column positioning for "hg summary"
7175 ui.write(
7173 ui.write(
7176 _(b'update: %d new changesets, %d branch heads (merge)\n')
7174 _(b'update: %d new changesets, %d branch heads (merge)\n')
7177 % (new, len(bheads))
7175 % (new, len(bheads))
7178 )
7176 )
7179
7177
7180 t = []
7178 t = []
7181 draft = len(repo.revs(b'draft()'))
7179 draft = len(repo.revs(b'draft()'))
7182 if draft:
7180 if draft:
7183 t.append(_(b'%d draft') % draft)
7181 t.append(_(b'%d draft') % draft)
7184 secret = len(repo.revs(b'secret()'))
7182 secret = len(repo.revs(b'secret()'))
7185 if secret:
7183 if secret:
7186 t.append(_(b'%d secret') % secret)
7184 t.append(_(b'%d secret') % secret)
7187
7185
7188 if draft or secret:
7186 if draft or secret:
7189 ui.status(_(b'phases: %s\n') % b', '.join(t))
7187 ui.status(_(b'phases: %s\n') % b', '.join(t))
7190
7188
7191 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7189 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7192 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7190 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7193 numtrouble = len(repo.revs(trouble + b"()"))
7191 numtrouble = len(repo.revs(trouble + b"()"))
7194 # We write all the possibilities to ease translation
7192 # We write all the possibilities to ease translation
7195 troublemsg = {
7193 troublemsg = {
7196 b"orphan": _(b"orphan: %d changesets"),
7194 b"orphan": _(b"orphan: %d changesets"),
7197 b"contentdivergent": _(b"content-divergent: %d changesets"),
7195 b"contentdivergent": _(b"content-divergent: %d changesets"),
7198 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7196 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7199 }
7197 }
7200 if numtrouble > 0:
7198 if numtrouble > 0:
7201 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7199 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7202
7200
7203 cmdutil.summaryhooks(ui, repo)
7201 cmdutil.summaryhooks(ui, repo)
7204
7202
7205 if opts.get(b'remote'):
7203 if opts.get(b'remote'):
7206 needsincoming, needsoutgoing = True, True
7204 needsincoming, needsoutgoing = True, True
7207 else:
7205 else:
7208 needsincoming, needsoutgoing = False, False
7206 needsincoming, needsoutgoing = False, False
7209 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7207 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7210 if i:
7208 if i:
7211 needsincoming = True
7209 needsincoming = True
7212 if o:
7210 if o:
7213 needsoutgoing = True
7211 needsoutgoing = True
7214 if not needsincoming and not needsoutgoing:
7212 if not needsincoming and not needsoutgoing:
7215 return
7213 return
7216
7214
7217 def getincoming():
7215 def getincoming():
7218 # XXX We should actually skip this if no default is specified, instead
7216 # XXX We should actually skip this if no default is specified, instead
7219 # of passing "default" which will resolve as "./default/" if no default
7217 # of passing "default" which will resolve as "./default/" if no default
7220 # path is defined.
7218 # path is defined.
7221 source, branches = urlutil.get_unique_pull_path(
7219 source, branches = urlutil.get_unique_pull_path(
7222 b'summary', repo, ui, b'default'
7220 b'summary', repo, ui, b'default'
7223 )
7221 )
7224 sbranch = branches[0]
7222 sbranch = branches[0]
7225 try:
7223 try:
7226 other = hg.peer(repo, {}, source)
7224 other = hg.peer(repo, {}, source)
7227 except error.RepoError:
7225 except error.RepoError:
7228 if opts.get(b'remote'):
7226 if opts.get(b'remote'):
7229 raise
7227 raise
7230 return source, sbranch, None, None, None
7228 return source, sbranch, None, None, None
7231 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7229 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7232 if revs:
7230 if revs:
7233 revs = [other.lookup(rev) for rev in revs]
7231 revs = [other.lookup(rev) for rev in revs]
7234 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7232 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7235 with repo.ui.silent():
7233 with repo.ui.silent():
7236 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7234 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7237 return source, sbranch, other, commoninc, commoninc[1]
7235 return source, sbranch, other, commoninc, commoninc[1]
7238
7236
7239 if needsincoming:
7237 if needsincoming:
7240 source, sbranch, sother, commoninc, incoming = getincoming()
7238 source, sbranch, sother, commoninc, incoming = getincoming()
7241 else:
7239 else:
7242 source = sbranch = sother = commoninc = incoming = None
7240 source = sbranch = sother = commoninc = incoming = None
7243
7241
7244 def getoutgoing():
7242 def getoutgoing():
7245 # XXX We should actually skip this if no default is specified, instead
7243 # XXX We should actually skip this if no default is specified, instead
7246 # of passing "default" which will resolve as "./default/" if no default
7244 # of passing "default" which will resolve as "./default/" if no default
7247 # path is defined.
7245 # path is defined.
7248 d = None
7246 d = None
7249 if b'default-push' in ui.paths:
7247 if b'default-push' in ui.paths:
7250 d = b'default-push'
7248 d = b'default-push'
7251 elif b'default' in ui.paths:
7249 elif b'default' in ui.paths:
7252 d = b'default'
7250 d = b'default'
7253 if d is not None:
7251 if d is not None:
7254 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7252 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7255 dest = path.pushloc or path.loc
7253 dest = path.pushloc or path.loc
7256 dbranch = path.branch
7254 dbranch = path.branch
7257 else:
7255 else:
7258 dest = b'default'
7256 dest = b'default'
7259 dbranch = None
7257 dbranch = None
7260 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7258 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7261 if source != dest:
7259 if source != dest:
7262 try:
7260 try:
7263 dother = hg.peer(repo, {}, dest)
7261 dother = hg.peer(repo, {}, dest)
7264 except error.RepoError:
7262 except error.RepoError:
7265 if opts.get(b'remote'):
7263 if opts.get(b'remote'):
7266 raise
7264 raise
7267 return dest, dbranch, None, None
7265 return dest, dbranch, None, None
7268 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7266 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7269 elif sother is None:
7267 elif sother is None:
7270 # there is no explicit destination peer, but source one is invalid
7268 # there is no explicit destination peer, but source one is invalid
7271 return dest, dbranch, None, None
7269 return dest, dbranch, None, None
7272 else:
7270 else:
7273 dother = sother
7271 dother = sother
7274 if source != dest or (sbranch is not None and sbranch != dbranch):
7272 if source != dest or (sbranch is not None and sbranch != dbranch):
7275 common = None
7273 common = None
7276 else:
7274 else:
7277 common = commoninc
7275 common = commoninc
7278 if revs:
7276 if revs:
7279 revs = [repo.lookup(rev) for rev in revs]
7277 revs = [repo.lookup(rev) for rev in revs]
7280 with repo.ui.silent():
7278 with repo.ui.silent():
7281 outgoing = discovery.findcommonoutgoing(
7279 outgoing = discovery.findcommonoutgoing(
7282 repo, dother, onlyheads=revs, commoninc=common
7280 repo, dother, onlyheads=revs, commoninc=common
7283 )
7281 )
7284 return dest, dbranch, dother, outgoing
7282 return dest, dbranch, dother, outgoing
7285
7283
7286 if needsoutgoing:
7284 if needsoutgoing:
7287 dest, dbranch, dother, outgoing = getoutgoing()
7285 dest, dbranch, dother, outgoing = getoutgoing()
7288 else:
7286 else:
7289 dest = dbranch = dother = outgoing = None
7287 dest = dbranch = dother = outgoing = None
7290
7288
7291 if opts.get(b'remote'):
7289 if opts.get(b'remote'):
7292 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7290 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7293 # The former always sets `sother` (or raises an exception if it can't);
7291 # The former always sets `sother` (or raises an exception if it can't);
7294 # the latter always sets `outgoing`.
7292 # the latter always sets `outgoing`.
7295 assert sother is not None
7293 assert sother is not None
7296 assert outgoing is not None
7294 assert outgoing is not None
7297
7295
7298 t = []
7296 t = []
7299 if incoming:
7297 if incoming:
7300 t.append(_(b'1 or more incoming'))
7298 t.append(_(b'1 or more incoming'))
7301 o = outgoing.missing
7299 o = outgoing.missing
7302 if o:
7300 if o:
7303 t.append(_(b'%d outgoing') % len(o))
7301 t.append(_(b'%d outgoing') % len(o))
7304 other = dother or sother
7302 other = dother or sother
7305 if b'bookmarks' in other.listkeys(b'namespaces'):
7303 if b'bookmarks' in other.listkeys(b'namespaces'):
7306 counts = bookmarks.summary(repo, other)
7304 counts = bookmarks.summary(repo, other)
7307 if counts[0] > 0:
7305 if counts[0] > 0:
7308 t.append(_(b'%d incoming bookmarks') % counts[0])
7306 t.append(_(b'%d incoming bookmarks') % counts[0])
7309 if counts[1] > 0:
7307 if counts[1] > 0:
7310 t.append(_(b'%d outgoing bookmarks') % counts[1])
7308 t.append(_(b'%d outgoing bookmarks') % counts[1])
7311
7309
7312 if t:
7310 if t:
7313 # i18n: column positioning for "hg summary"
7311 # i18n: column positioning for "hg summary"
7314 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7312 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7315 else:
7313 else:
7316 # i18n: column positioning for "hg summary"
7314 # i18n: column positioning for "hg summary"
7317 ui.status(_(b'remote: (synced)\n'))
7315 ui.status(_(b'remote: (synced)\n'))
7318
7316
7319 cmdutil.summaryremotehooks(
7317 cmdutil.summaryremotehooks(
7320 ui,
7318 ui,
7321 repo,
7319 repo,
7322 opts,
7320 opts,
7323 (
7321 (
7324 (source, sbranch, sother, commoninc),
7322 (source, sbranch, sother, commoninc),
7325 (dest, dbranch, dother, outgoing),
7323 (dest, dbranch, dother, outgoing),
7326 ),
7324 ),
7327 )
7325 )
7328
7326
7329
7327
7330 @command(
7328 @command(
7331 b'tag',
7329 b'tag',
7332 [
7330 [
7333 (b'f', b'force', None, _(b'force tag')),
7331 (b'f', b'force', None, _(b'force tag')),
7334 (b'l', b'local', None, _(b'make the tag local')),
7332 (b'l', b'local', None, _(b'make the tag local')),
7335 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7333 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7336 (b'', b'remove', None, _(b'remove a tag')),
7334 (b'', b'remove', None, _(b'remove a tag')),
7337 # -l/--local is already there, commitopts cannot be used
7335 # -l/--local is already there, commitopts cannot be used
7338 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7336 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7339 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7337 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7340 ]
7338 ]
7341 + commitopts2,
7339 + commitopts2,
7342 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7340 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7343 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7341 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7344 )
7342 )
7345 def tag(ui, repo, name1, *names, **opts):
7343 def tag(ui, repo, name1, *names, **opts):
7346 """add one or more tags for the current or given revision
7344 """add one or more tags for the current or given revision
7347
7345
7348 Name a particular revision using <name>.
7346 Name a particular revision using <name>.
7349
7347
7350 Tags are used to name particular revisions of the repository and are
7348 Tags are used to name particular revisions of the repository and are
7351 very useful to compare different revisions, to go back to significant
7349 very useful to compare different revisions, to go back to significant
7352 earlier versions or to mark branch points as releases, etc. Changing
7350 earlier versions or to mark branch points as releases, etc. Changing
7353 an existing tag is normally disallowed; use -f/--force to override.
7351 an existing tag is normally disallowed; use -f/--force to override.
7354
7352
7355 If no revision is given, the parent of the working directory is
7353 If no revision is given, the parent of the working directory is
7356 used.
7354 used.
7357
7355
7358 To facilitate version control, distribution, and merging of tags,
7356 To facilitate version control, distribution, and merging of tags,
7359 they are stored as a file named ".hgtags" which is managed similarly
7357 they are stored as a file named ".hgtags" which is managed similarly
7360 to other project files and can be hand-edited if necessary. This
7358 to other project files and can be hand-edited if necessary. This
7361 also means that tagging creates a new commit. The file
7359 also means that tagging creates a new commit. The file
7362 ".hg/localtags" is used for local tags (not shared among
7360 ".hg/localtags" is used for local tags (not shared among
7363 repositories).
7361 repositories).
7364
7362
7365 Tag commits are usually made at the head of a branch. If the parent
7363 Tag commits are usually made at the head of a branch. If the parent
7366 of the working directory is not a branch head, :hg:`tag` aborts; use
7364 of the working directory is not a branch head, :hg:`tag` aborts; use
7367 -f/--force to force the tag commit to be based on a non-head
7365 -f/--force to force the tag commit to be based on a non-head
7368 changeset.
7366 changeset.
7369
7367
7370 See :hg:`help dates` for a list of formats valid for -d/--date.
7368 See :hg:`help dates` for a list of formats valid for -d/--date.
7371
7369
7372 Since tag names have priority over branch names during revision
7370 Since tag names have priority over branch names during revision
7373 lookup, using an existing branch name as a tag name is discouraged.
7371 lookup, using an existing branch name as a tag name is discouraged.
7374
7372
7375 Returns 0 on success.
7373 Returns 0 on success.
7376 """
7374 """
7377 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7375 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7378 opts = pycompat.byteskwargs(opts)
7376 opts = pycompat.byteskwargs(opts)
7379 with repo.wlock(), repo.lock():
7377 with repo.wlock(), repo.lock():
7380 rev_ = b"."
7378 rev_ = b"."
7381 names = [t.strip() for t in (name1,) + names]
7379 names = [t.strip() for t in (name1,) + names]
7382 if len(names) != len(set(names)):
7380 if len(names) != len(set(names)):
7383 raise error.InputError(_(b'tag names must be unique'))
7381 raise error.InputError(_(b'tag names must be unique'))
7384 for n in names:
7382 for n in names:
7385 scmutil.checknewlabel(repo, n, b'tag')
7383 scmutil.checknewlabel(repo, n, b'tag')
7386 if not n:
7384 if not n:
7387 raise error.InputError(
7385 raise error.InputError(
7388 _(b'tag names cannot consist entirely of whitespace')
7386 _(b'tag names cannot consist entirely of whitespace')
7389 )
7387 )
7390 if opts.get(b'rev'):
7388 if opts.get(b'rev'):
7391 rev_ = opts[b'rev']
7389 rev_ = opts[b'rev']
7392 message = opts.get(b'message')
7390 message = opts.get(b'message')
7393 if opts.get(b'remove'):
7391 if opts.get(b'remove'):
7394 if opts.get(b'local'):
7392 if opts.get(b'local'):
7395 expectedtype = b'local'
7393 expectedtype = b'local'
7396 else:
7394 else:
7397 expectedtype = b'global'
7395 expectedtype = b'global'
7398
7396
7399 for n in names:
7397 for n in names:
7400 if repo.tagtype(n) == b'global':
7398 if repo.tagtype(n) == b'global':
7401 alltags = tagsmod.findglobaltags(ui, repo)
7399 alltags = tagsmod.findglobaltags(ui, repo)
7402 if alltags[n][0] == repo.nullid:
7400 if alltags[n][0] == repo.nullid:
7403 raise error.InputError(
7401 raise error.InputError(
7404 _(b"tag '%s' is already removed") % n
7402 _(b"tag '%s' is already removed") % n
7405 )
7403 )
7406 if not repo.tagtype(n):
7404 if not repo.tagtype(n):
7407 raise error.InputError(_(b"tag '%s' does not exist") % n)
7405 raise error.InputError(_(b"tag '%s' does not exist") % n)
7408 if repo.tagtype(n) != expectedtype:
7406 if repo.tagtype(n) != expectedtype:
7409 if expectedtype == b'global':
7407 if expectedtype == b'global':
7410 raise error.InputError(
7408 raise error.InputError(
7411 _(b"tag '%s' is not a global tag") % n
7409 _(b"tag '%s' is not a global tag") % n
7412 )
7410 )
7413 else:
7411 else:
7414 raise error.InputError(
7412 raise error.InputError(
7415 _(b"tag '%s' is not a local tag") % n
7413 _(b"tag '%s' is not a local tag") % n
7416 )
7414 )
7417 rev_ = b'null'
7415 rev_ = b'null'
7418 if not message:
7416 if not message:
7419 # we don't translate commit messages
7417 # we don't translate commit messages
7420 message = b'Removed tag %s' % b', '.join(names)
7418 message = b'Removed tag %s' % b', '.join(names)
7421 elif not opts.get(b'force'):
7419 elif not opts.get(b'force'):
7422 for n in names:
7420 for n in names:
7423 if n in repo.tags():
7421 if n in repo.tags():
7424 raise error.InputError(
7422 raise error.InputError(
7425 _(b"tag '%s' already exists (use -f to force)") % n
7423 _(b"tag '%s' already exists (use -f to force)") % n
7426 )
7424 )
7427 if not opts.get(b'local'):
7425 if not opts.get(b'local'):
7428 p1, p2 = repo.dirstate.parents()
7426 p1, p2 = repo.dirstate.parents()
7429 if p2 != repo.nullid:
7427 if p2 != repo.nullid:
7430 raise error.StateError(_(b'uncommitted merge'))
7428 raise error.StateError(_(b'uncommitted merge'))
7431 bheads = repo.branchheads()
7429 bheads = repo.branchheads()
7432 if not opts.get(b'force') and bheads and p1 not in bheads:
7430 if not opts.get(b'force') and bheads and p1 not in bheads:
7433 raise error.InputError(
7431 raise error.InputError(
7434 _(
7432 _(
7435 b'working directory is not at a branch head '
7433 b'working directory is not at a branch head '
7436 b'(use -f to force)'
7434 b'(use -f to force)'
7437 )
7435 )
7438 )
7436 )
7439 node = logcmdutil.revsingle(repo, rev_).node()
7437 node = logcmdutil.revsingle(repo, rev_).node()
7440
7438
7441 if not message:
7439 if not message:
7442 # we don't translate commit messages
7440 # we don't translate commit messages
7443 message = b'Added tag %s for changeset %s' % (
7441 message = b'Added tag %s for changeset %s' % (
7444 b', '.join(names),
7442 b', '.join(names),
7445 short(node),
7443 short(node),
7446 )
7444 )
7447
7445
7448 date = opts.get(b'date')
7446 date = opts.get(b'date')
7449 if date:
7447 if date:
7450 date = dateutil.parsedate(date)
7448 date = dateutil.parsedate(date)
7451
7449
7452 if opts.get(b'remove'):
7450 if opts.get(b'remove'):
7453 editform = b'tag.remove'
7451 editform = b'tag.remove'
7454 else:
7452 else:
7455 editform = b'tag.add'
7453 editform = b'tag.add'
7456 editor = cmdutil.getcommiteditor(
7454 editor = cmdutil.getcommiteditor(
7457 editform=editform, **pycompat.strkwargs(opts)
7455 editform=editform, **pycompat.strkwargs(opts)
7458 )
7456 )
7459
7457
7460 # don't allow tagging the null rev
7458 # don't allow tagging the null rev
7461 if (
7459 if (
7462 not opts.get(b'remove')
7460 not opts.get(b'remove')
7463 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7461 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7464 ):
7462 ):
7465 raise error.InputError(_(b"cannot tag null revision"))
7463 raise error.InputError(_(b"cannot tag null revision"))
7466
7464
7467 tagsmod.tag(
7465 tagsmod.tag(
7468 repo,
7466 repo,
7469 names,
7467 names,
7470 node,
7468 node,
7471 message,
7469 message,
7472 opts.get(b'local'),
7470 opts.get(b'local'),
7473 opts.get(b'user'),
7471 opts.get(b'user'),
7474 date,
7472 date,
7475 editor=editor,
7473 editor=editor,
7476 )
7474 )
7477
7475
7478
7476
7479 @command(
7477 @command(
7480 b'tags',
7478 b'tags',
7481 formatteropts,
7479 formatteropts,
7482 b'',
7480 b'',
7483 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7481 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7484 intents={INTENT_READONLY},
7482 intents={INTENT_READONLY},
7485 )
7483 )
7486 def tags(ui, repo, **opts):
7484 def tags(ui, repo, **opts):
7487 """list repository tags
7485 """list repository tags
7488
7486
7489 This lists both regular and local tags. When the -v/--verbose
7487 This lists both regular and local tags. When the -v/--verbose
7490 switch is used, a third column "local" is printed for local tags.
7488 switch is used, a third column "local" is printed for local tags.
7491 When the -q/--quiet switch is used, only the tag name is printed.
7489 When the -q/--quiet switch is used, only the tag name is printed.
7492
7490
7493 .. container:: verbose
7491 .. container:: verbose
7494
7492
7495 Template:
7493 Template:
7496
7494
7497 The following keywords are supported in addition to the common template
7495 The following keywords are supported in addition to the common template
7498 keywords and functions such as ``{tag}``. See also
7496 keywords and functions such as ``{tag}``. See also
7499 :hg:`help templates`.
7497 :hg:`help templates`.
7500
7498
7501 :type: String. ``local`` for local tags.
7499 :type: String. ``local`` for local tags.
7502
7500
7503 Returns 0 on success.
7501 Returns 0 on success.
7504 """
7502 """
7505
7503
7506 opts = pycompat.byteskwargs(opts)
7504 opts = pycompat.byteskwargs(opts)
7507 ui.pager(b'tags')
7505 ui.pager(b'tags')
7508 fm = ui.formatter(b'tags', opts)
7506 fm = ui.formatter(b'tags', opts)
7509 hexfunc = fm.hexfunc
7507 hexfunc = fm.hexfunc
7510
7508
7511 for t, n in reversed(repo.tagslist()):
7509 for t, n in reversed(repo.tagslist()):
7512 hn = hexfunc(n)
7510 hn = hexfunc(n)
7513 label = b'tags.normal'
7511 label = b'tags.normal'
7514 tagtype = repo.tagtype(t)
7512 tagtype = repo.tagtype(t)
7515 if not tagtype or tagtype == b'global':
7513 if not tagtype or tagtype == b'global':
7516 tagtype = b''
7514 tagtype = b''
7517 else:
7515 else:
7518 label = b'tags.' + tagtype
7516 label = b'tags.' + tagtype
7519
7517
7520 fm.startitem()
7518 fm.startitem()
7521 fm.context(repo=repo)
7519 fm.context(repo=repo)
7522 fm.write(b'tag', b'%s', t, label=label)
7520 fm.write(b'tag', b'%s', t, label=label)
7523 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7521 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7524 fm.condwrite(
7522 fm.condwrite(
7525 not ui.quiet,
7523 not ui.quiet,
7526 b'rev node',
7524 b'rev node',
7527 fmt,
7525 fmt,
7528 repo.changelog.rev(n),
7526 repo.changelog.rev(n),
7529 hn,
7527 hn,
7530 label=label,
7528 label=label,
7531 )
7529 )
7532 fm.condwrite(
7530 fm.condwrite(
7533 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7531 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7534 )
7532 )
7535 fm.plain(b'\n')
7533 fm.plain(b'\n')
7536 fm.end()
7534 fm.end()
7537
7535
7538
7536
7539 @command(
7537 @command(
7540 b'tip',
7538 b'tip',
7541 [
7539 [
7542 (b'p', b'patch', None, _(b'show patch')),
7540 (b'p', b'patch', None, _(b'show patch')),
7543 (b'g', b'git', None, _(b'use git extended diff format')),
7541 (b'g', b'git', None, _(b'use git extended diff format')),
7544 ]
7542 ]
7545 + templateopts,
7543 + templateopts,
7546 _(b'[-p] [-g]'),
7544 _(b'[-p] [-g]'),
7547 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7545 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7548 )
7546 )
7549 def tip(ui, repo, **opts):
7547 def tip(ui, repo, **opts):
7550 """show the tip revision (DEPRECATED)
7548 """show the tip revision (DEPRECATED)
7551
7549
7552 The tip revision (usually just called the tip) is the changeset
7550 The tip revision (usually just called the tip) is the changeset
7553 most recently added to the repository (and therefore the most
7551 most recently added to the repository (and therefore the most
7554 recently changed head).
7552 recently changed head).
7555
7553
7556 If you have just made a commit, that commit will be the tip. If
7554 If you have just made a commit, that commit will be the tip. If
7557 you have just pulled changes from another repository, the tip of
7555 you have just pulled changes from another repository, the tip of
7558 that repository becomes the current tip. The "tip" tag is special
7556 that repository becomes the current tip. The "tip" tag is special
7559 and cannot be renamed or assigned to a different changeset.
7557 and cannot be renamed or assigned to a different changeset.
7560
7558
7561 This command is deprecated, please use :hg:`heads` instead.
7559 This command is deprecated, please use :hg:`heads` instead.
7562
7560
7563 Returns 0 on success.
7561 Returns 0 on success.
7564 """
7562 """
7565 opts = pycompat.byteskwargs(opts)
7563 opts = pycompat.byteskwargs(opts)
7566 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7564 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7567 displayer.show(repo[b'tip'])
7565 displayer.show(repo[b'tip'])
7568 displayer.close()
7566 displayer.close()
7569
7567
7570
7568
7571 @command(
7569 @command(
7572 b'unbundle',
7570 b'unbundle',
7573 [
7571 [
7574 (
7572 (
7575 b'u',
7573 b'u',
7576 b'update',
7574 b'update',
7577 None,
7575 None,
7578 _(b'update to new branch head if changesets were unbundled'),
7576 _(b'update to new branch head if changesets were unbundled'),
7579 )
7577 )
7580 ],
7578 ],
7581 _(b'[-u] FILE...'),
7579 _(b'[-u] FILE...'),
7582 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7580 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7583 )
7581 )
7584 def unbundle(ui, repo, fname1, *fnames, **opts):
7582 def unbundle(ui, repo, fname1, *fnames, **opts):
7585 """apply one or more bundle files
7583 """apply one or more bundle files
7586
7584
7587 Apply one or more bundle files generated by :hg:`bundle`.
7585 Apply one or more bundle files generated by :hg:`bundle`.
7588
7586
7589 Returns 0 on success, 1 if an update has unresolved files.
7587 Returns 0 on success, 1 if an update has unresolved files.
7590 """
7588 """
7591 fnames = (fname1,) + fnames
7589 fnames = (fname1,) + fnames
7592
7590
7593 with repo.lock():
7591 with repo.lock():
7594 for fname in fnames:
7592 for fname in fnames:
7595 f = hg.openpath(ui, fname)
7593 f = hg.openpath(ui, fname)
7596 gen = exchange.readbundle(ui, f, fname)
7594 gen = exchange.readbundle(ui, f, fname)
7597 if isinstance(gen, streamclone.streamcloneapplier):
7595 if isinstance(gen, streamclone.streamcloneapplier):
7598 raise error.InputError(
7596 raise error.InputError(
7599 _(
7597 _(
7600 b'packed bundles cannot be applied with '
7598 b'packed bundles cannot be applied with '
7601 b'"hg unbundle"'
7599 b'"hg unbundle"'
7602 ),
7600 ),
7603 hint=_(b'use "hg debugapplystreamclonebundle"'),
7601 hint=_(b'use "hg debugapplystreamclonebundle"'),
7604 )
7602 )
7605 url = b'bundle:' + fname
7603 url = b'bundle:' + fname
7606 try:
7604 try:
7607 txnname = b'unbundle'
7605 txnname = b'unbundle'
7608 if not isinstance(gen, bundle2.unbundle20):
7606 if not isinstance(gen, bundle2.unbundle20):
7609 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7607 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7610 with repo.transaction(txnname) as tr:
7608 with repo.transaction(txnname) as tr:
7611 op = bundle2.applybundle(
7609 op = bundle2.applybundle(
7612 repo, gen, tr, source=b'unbundle', url=url
7610 repo, gen, tr, source=b'unbundle', url=url
7613 )
7611 )
7614 except error.BundleUnknownFeatureError as exc:
7612 except error.BundleUnknownFeatureError as exc:
7615 raise error.Abort(
7613 raise error.Abort(
7616 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7614 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7617 hint=_(
7615 hint=_(
7618 b"see https://mercurial-scm.org/"
7616 b"see https://mercurial-scm.org/"
7619 b"wiki/BundleFeature for more "
7617 b"wiki/BundleFeature for more "
7620 b"information"
7618 b"information"
7621 ),
7619 ),
7622 )
7620 )
7623 modheads = bundle2.combinechangegroupresults(op)
7621 modheads = bundle2.combinechangegroupresults(op)
7624
7622
7625 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7623 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7626 return 1
7624 return 1
7627 else:
7625 else:
7628 return 0
7626 return 0
7629
7627
7630
7628
7631 @command(
7629 @command(
7632 b'unshelve',
7630 b'unshelve',
7633 [
7631 [
7634 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7632 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7635 (
7633 (
7636 b'c',
7634 b'c',
7637 b'continue',
7635 b'continue',
7638 None,
7636 None,
7639 _(b'continue an incomplete unshelve operation'),
7637 _(b'continue an incomplete unshelve operation'),
7640 ),
7638 ),
7641 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7639 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7642 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7640 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7643 (
7641 (
7644 b'n',
7642 b'n',
7645 b'name',
7643 b'name',
7646 b'',
7644 b'',
7647 _(b'restore shelved change with given name'),
7645 _(b'restore shelved change with given name'),
7648 _(b'NAME'),
7646 _(b'NAME'),
7649 ),
7647 ),
7650 (b't', b'tool', b'', _(b'specify merge tool')),
7648 (b't', b'tool', b'', _(b'specify merge tool')),
7651 (
7649 (
7652 b'',
7650 b'',
7653 b'date',
7651 b'date',
7654 b'',
7652 b'',
7655 _(b'set date for temporary commits (DEPRECATED)'),
7653 _(b'set date for temporary commits (DEPRECATED)'),
7656 _(b'DATE'),
7654 _(b'DATE'),
7657 ),
7655 ),
7658 ],
7656 ],
7659 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7657 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7660 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7658 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7661 )
7659 )
7662 def unshelve(ui, repo, *shelved, **opts):
7660 def unshelve(ui, repo, *shelved, **opts):
7663 """restore a shelved change to the working directory
7661 """restore a shelved change to the working directory
7664
7662
7665 This command accepts an optional name of a shelved change to
7663 This command accepts an optional name of a shelved change to
7666 restore. If none is given, the most recent shelved change is used.
7664 restore. If none is given, the most recent shelved change is used.
7667
7665
7668 If a shelved change is applied successfully, the bundle that
7666 If a shelved change is applied successfully, the bundle that
7669 contains the shelved changes is moved to a backup location
7667 contains the shelved changes is moved to a backup location
7670 (.hg/shelve-backup).
7668 (.hg/shelve-backup).
7671
7669
7672 Since you can restore a shelved change on top of an arbitrary
7670 Since you can restore a shelved change on top of an arbitrary
7673 commit, it is possible that unshelving will result in a conflict
7671 commit, it is possible that unshelving will result in a conflict
7674 between your changes and the commits you are unshelving onto. If
7672 between your changes and the commits you are unshelving onto. If
7675 this occurs, you must resolve the conflict, then use
7673 this occurs, you must resolve the conflict, then use
7676 ``--continue`` to complete the unshelve operation. (The bundle
7674 ``--continue`` to complete the unshelve operation. (The bundle
7677 will not be moved until you successfully complete the unshelve.)
7675 will not be moved until you successfully complete the unshelve.)
7678
7676
7679 (Alternatively, you can use ``--abort`` to abandon an unshelve
7677 (Alternatively, you can use ``--abort`` to abandon an unshelve
7680 that causes a conflict. This reverts the unshelved changes, and
7678 that causes a conflict. This reverts the unshelved changes, and
7681 leaves the bundle in place.)
7679 leaves the bundle in place.)
7682
7680
7683 If bare shelved change (without interactive, include and exclude
7681 If bare shelved change (without interactive, include and exclude
7684 option) was done on newly created branch it would restore branch
7682 option) was done on newly created branch it would restore branch
7685 information to the working directory.
7683 information to the working directory.
7686
7684
7687 After a successful unshelve, the shelved changes are stored in a
7685 After a successful unshelve, the shelved changes are stored in a
7688 backup directory. Only the N most recent backups are kept. N
7686 backup directory. Only the N most recent backups are kept. N
7689 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7687 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7690 configuration option.
7688 configuration option.
7691
7689
7692 .. container:: verbose
7690 .. container:: verbose
7693
7691
7694 Timestamp in seconds is used to decide order of backups. More
7692 Timestamp in seconds is used to decide order of backups. More
7695 than ``maxbackups`` backups are kept, if same timestamp
7693 than ``maxbackups`` backups are kept, if same timestamp
7696 prevents from deciding exact order of them, for safety.
7694 prevents from deciding exact order of them, for safety.
7697
7695
7698 Selected changes can be unshelved with ``--interactive`` flag.
7696 Selected changes can be unshelved with ``--interactive`` flag.
7699 The working directory is updated with the selected changes, and
7697 The working directory is updated with the selected changes, and
7700 only the unselected changes remain shelved.
7698 only the unselected changes remain shelved.
7701 Note: The whole shelve is applied to working directory first before
7699 Note: The whole shelve is applied to working directory first before
7702 running interactively. So, this will bring up all the conflicts between
7700 running interactively. So, this will bring up all the conflicts between
7703 working directory and the shelve, irrespective of which changes will be
7701 working directory and the shelve, irrespective of which changes will be
7704 unshelved.
7702 unshelved.
7705 """
7703 """
7706 with repo.wlock():
7704 with repo.wlock():
7707 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7705 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7708
7706
7709
7707
7710 statemod.addunfinished(
7708 statemod.addunfinished(
7711 b'unshelve',
7709 b'unshelve',
7712 fname=b'shelvedstate',
7710 fname=b'shelvedstate',
7713 continueflag=True,
7711 continueflag=True,
7714 abortfunc=shelvemod.hgabortunshelve,
7712 abortfunc=shelvemod.hgabortunshelve,
7715 continuefunc=shelvemod.hgcontinueunshelve,
7713 continuefunc=shelvemod.hgcontinueunshelve,
7716 cmdmsg=_(b'unshelve already in progress'),
7714 cmdmsg=_(b'unshelve already in progress'),
7717 )
7715 )
7718
7716
7719
7717
7720 @command(
7718 @command(
7721 b'update|up|checkout|co',
7719 b'update|up|checkout|co',
7722 [
7720 [
7723 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7721 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7724 (b'c', b'check', None, _(b'require clean working directory')),
7722 (b'c', b'check', None, _(b'require clean working directory')),
7725 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7723 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7726 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7724 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7727 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7725 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7728 ]
7726 ]
7729 + mergetoolopts,
7727 + mergetoolopts,
7730 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7728 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7731 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7729 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7732 helpbasic=True,
7730 helpbasic=True,
7733 )
7731 )
7734 def update(ui, repo, node=None, **opts):
7732 def update(ui, repo, node=None, **opts):
7735 """update working directory (or switch revisions)
7733 """update working directory (or switch revisions)
7736
7734
7737 Update the repository's working directory to the specified
7735 Update the repository's working directory to the specified
7738 changeset. If no changeset is specified, update to the tip of the
7736 changeset. If no changeset is specified, update to the tip of the
7739 current named branch and move the active bookmark (see :hg:`help
7737 current named branch and move the active bookmark (see :hg:`help
7740 bookmarks`).
7738 bookmarks`).
7741
7739
7742 Update sets the working directory's parent revision to the specified
7740 Update sets the working directory's parent revision to the specified
7743 changeset (see :hg:`help parents`).
7741 changeset (see :hg:`help parents`).
7744
7742
7745 If the changeset is not a descendant or ancestor of the working
7743 If the changeset is not a descendant or ancestor of the working
7746 directory's parent and there are uncommitted changes, the update is
7744 directory's parent and there are uncommitted changes, the update is
7747 aborted. With the -c/--check option, the working directory is checked
7745 aborted. With the -c/--check option, the working directory is checked
7748 for uncommitted changes; if none are found, the working directory is
7746 for uncommitted changes; if none are found, the working directory is
7749 updated to the specified changeset.
7747 updated to the specified changeset.
7750
7748
7751 .. container:: verbose
7749 .. container:: verbose
7752
7750
7753 The -C/--clean, -c/--check, and -m/--merge options control what
7751 The -C/--clean, -c/--check, and -m/--merge options control what
7754 happens if the working directory contains uncommitted changes.
7752 happens if the working directory contains uncommitted changes.
7755 At most of one of them can be specified.
7753 At most of one of them can be specified.
7756
7754
7757 1. If no option is specified, and if
7755 1. If no option is specified, and if
7758 the requested changeset is an ancestor or descendant of
7756 the requested changeset is an ancestor or descendant of
7759 the working directory's parent, the uncommitted changes
7757 the working directory's parent, the uncommitted changes
7760 are merged into the requested changeset and the merged
7758 are merged into the requested changeset and the merged
7761 result is left uncommitted. If the requested changeset is
7759 result is left uncommitted. If the requested changeset is
7762 not an ancestor or descendant (that is, it is on another
7760 not an ancestor or descendant (that is, it is on another
7763 branch), the update is aborted and the uncommitted changes
7761 branch), the update is aborted and the uncommitted changes
7764 are preserved.
7762 are preserved.
7765
7763
7766 2. With the -m/--merge option, the update is allowed even if the
7764 2. With the -m/--merge option, the update is allowed even if the
7767 requested changeset is not an ancestor or descendant of
7765 requested changeset is not an ancestor or descendant of
7768 the working directory's parent.
7766 the working directory's parent.
7769
7767
7770 3. With the -c/--check option, the update is aborted and the
7768 3. With the -c/--check option, the update is aborted and the
7771 uncommitted changes are preserved.
7769 uncommitted changes are preserved.
7772
7770
7773 4. With the -C/--clean option, uncommitted changes are discarded and
7771 4. With the -C/--clean option, uncommitted changes are discarded and
7774 the working directory is updated to the requested changeset.
7772 the working directory is updated to the requested changeset.
7775
7773
7776 To cancel an uncommitted merge (and lose your changes), use
7774 To cancel an uncommitted merge (and lose your changes), use
7777 :hg:`merge --abort`.
7775 :hg:`merge --abort`.
7778
7776
7779 Use null as the changeset to remove the working directory (like
7777 Use null as the changeset to remove the working directory (like
7780 :hg:`clone -U`).
7778 :hg:`clone -U`).
7781
7779
7782 If you want to revert just one file to an older revision, use
7780 If you want to revert just one file to an older revision, use
7783 :hg:`revert [-r REV] NAME`.
7781 :hg:`revert [-r REV] NAME`.
7784
7782
7785 See :hg:`help dates` for a list of formats valid for -d/--date.
7783 See :hg:`help dates` for a list of formats valid for -d/--date.
7786
7784
7787 Returns 0 on success, 1 if there are unresolved files.
7785 Returns 0 on success, 1 if there are unresolved files.
7788 """
7786 """
7789 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7787 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7790 rev = opts.get('rev')
7788 rev = opts.get('rev')
7791 date = opts.get('date')
7789 date = opts.get('date')
7792 clean = opts.get('clean')
7790 clean = opts.get('clean')
7793 check = opts.get('check')
7791 check = opts.get('check')
7794 merge = opts.get('merge')
7792 merge = opts.get('merge')
7795 if rev and node:
7793 if rev and node:
7796 raise error.InputError(_(b"please specify just one revision"))
7794 raise error.InputError(_(b"please specify just one revision"))
7797
7795
7798 if ui.configbool(b'commands', b'update.requiredest'):
7796 if ui.configbool(b'commands', b'update.requiredest'):
7799 if not node and not rev and not date:
7797 if not node and not rev and not date:
7800 raise error.InputError(
7798 raise error.InputError(
7801 _(b'you must specify a destination'),
7799 _(b'you must specify a destination'),
7802 hint=_(b'for example: hg update ".::"'),
7800 hint=_(b'for example: hg update ".::"'),
7803 )
7801 )
7804
7802
7805 if rev is None or rev == b'':
7803 if rev is None or rev == b'':
7806 rev = node
7804 rev = node
7807
7805
7808 if date and rev is not None:
7806 if date and rev is not None:
7809 raise error.InputError(_(b"you can't specify a revision and a date"))
7807 raise error.InputError(_(b"you can't specify a revision and a date"))
7810
7808
7811 updatecheck = None
7809 updatecheck = None
7812 if check or merge is not None and not merge:
7810 if check or merge is not None and not merge:
7813 updatecheck = b'abort'
7811 updatecheck = b'abort'
7814 elif merge or check is not None and not check:
7812 elif merge or check is not None and not check:
7815 updatecheck = b'none'
7813 updatecheck = b'none'
7816
7814
7817 with repo.wlock():
7815 with repo.wlock():
7818 cmdutil.clearunfinished(repo)
7816 cmdutil.clearunfinished(repo)
7819 if date:
7817 if date:
7820 rev = cmdutil.finddate(ui, repo, date)
7818 rev = cmdutil.finddate(ui, repo, date)
7821
7819
7822 # if we defined a bookmark, we have to remember the original name
7820 # if we defined a bookmark, we have to remember the original name
7823 brev = rev
7821 brev = rev
7824 if rev:
7822 if rev:
7825 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7823 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7826 ctx = logcmdutil.revsingle(repo, rev, default=None)
7824 ctx = logcmdutil.revsingle(repo, rev, default=None)
7827 rev = ctx.rev()
7825 rev = ctx.rev()
7828 hidden = ctx.hidden()
7826 hidden = ctx.hidden()
7829 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7827 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7830 with ui.configoverride(overrides, b'update'):
7828 with ui.configoverride(overrides, b'update'):
7831 ret = hg.updatetotally(
7829 ret = hg.updatetotally(
7832 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7830 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7833 )
7831 )
7834 if hidden:
7832 if hidden:
7835 ctxstr = ctx.hex()[:12]
7833 ctxstr = ctx.hex()[:12]
7836 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7834 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7837
7835
7838 if ctx.obsolete():
7836 if ctx.obsolete():
7839 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7837 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7840 ui.warn(b"(%s)\n" % obsfatemsg)
7838 ui.warn(b"(%s)\n" % obsfatemsg)
7841 return ret
7839 return ret
7842
7840
7843
7841
7844 @command(
7842 @command(
7845 b'verify',
7843 b'verify',
7846 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7844 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7847 helpcategory=command.CATEGORY_MAINTENANCE,
7845 helpcategory=command.CATEGORY_MAINTENANCE,
7848 )
7846 )
7849 def verify(ui, repo, **opts):
7847 def verify(ui, repo, **opts):
7850 """verify the integrity of the repository
7848 """verify the integrity of the repository
7851
7849
7852 Verify the integrity of the current repository.
7850 Verify the integrity of the current repository.
7853
7851
7854 This will perform an extensive check of the repository's
7852 This will perform an extensive check of the repository's
7855 integrity, validating the hashes and checksums of each entry in
7853 integrity, validating the hashes and checksums of each entry in
7856 the changelog, manifest, and tracked files, as well as the
7854 the changelog, manifest, and tracked files, as well as the
7857 integrity of their crosslinks and indices.
7855 integrity of their crosslinks and indices.
7858
7856
7859 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7857 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7860 for more information about recovery from corruption of the
7858 for more information about recovery from corruption of the
7861 repository.
7859 repository.
7862
7860
7863 Returns 0 on success, 1 if errors are encountered.
7861 Returns 0 on success, 1 if errors are encountered.
7864 """
7862 """
7865 opts = pycompat.byteskwargs(opts)
7863 opts = pycompat.byteskwargs(opts)
7866
7864
7867 level = None
7865 level = None
7868 if opts[b'full']:
7866 if opts[b'full']:
7869 level = verifymod.VERIFY_FULL
7867 level = verifymod.VERIFY_FULL
7870 return hg.verify(repo, level)
7868 return hg.verify(repo, level)
7871
7869
7872
7870
7873 @command(
7871 @command(
7874 b'version',
7872 b'version',
7875 [] + formatteropts,
7873 [] + formatteropts,
7876 helpcategory=command.CATEGORY_HELP,
7874 helpcategory=command.CATEGORY_HELP,
7877 norepo=True,
7875 norepo=True,
7878 intents={INTENT_READONLY},
7876 intents={INTENT_READONLY},
7879 )
7877 )
7880 def version_(ui, **opts):
7878 def version_(ui, **opts):
7881 """output version and copyright information
7879 """output version and copyright information
7882
7880
7883 .. container:: verbose
7881 .. container:: verbose
7884
7882
7885 Template:
7883 Template:
7886
7884
7887 The following keywords are supported. See also :hg:`help templates`.
7885 The following keywords are supported. See also :hg:`help templates`.
7888
7886
7889 :extensions: List of extensions.
7887 :extensions: List of extensions.
7890 :ver: String. Version number.
7888 :ver: String. Version number.
7891
7889
7892 And each entry of ``{extensions}`` provides the following sub-keywords
7890 And each entry of ``{extensions}`` provides the following sub-keywords
7893 in addition to ``{ver}``.
7891 in addition to ``{ver}``.
7894
7892
7895 :bundled: Boolean. True if included in the release.
7893 :bundled: Boolean. True if included in the release.
7896 :name: String. Extension name.
7894 :name: String. Extension name.
7897 """
7895 """
7898 opts = pycompat.byteskwargs(opts)
7896 opts = pycompat.byteskwargs(opts)
7899 if ui.verbose:
7897 if ui.verbose:
7900 ui.pager(b'version')
7898 ui.pager(b'version')
7901 fm = ui.formatter(b"version", opts)
7899 fm = ui.formatter(b"version", opts)
7902 fm.startitem()
7900 fm.startitem()
7903 fm.write(
7901 fm.write(
7904 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7902 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7905 )
7903 )
7906 license = _(
7904 license = _(
7907 b"(see https://mercurial-scm.org for more information)\n"
7905 b"(see https://mercurial-scm.org for more information)\n"
7908 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7906 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7909 b"This is free software; see the source for copying conditions. "
7907 b"This is free software; see the source for copying conditions. "
7910 b"There is NO\nwarranty; "
7908 b"There is NO\nwarranty; "
7911 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7909 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7912 )
7910 )
7913 if not ui.quiet:
7911 if not ui.quiet:
7914 fm.plain(license)
7912 fm.plain(license)
7915
7913
7916 if ui.verbose:
7914 if ui.verbose:
7917 fm.plain(_(b"\nEnabled extensions:\n\n"))
7915 fm.plain(_(b"\nEnabled extensions:\n\n"))
7918 # format names and versions into columns
7916 # format names and versions into columns
7919 names = []
7917 names = []
7920 vers = []
7918 vers = []
7921 isinternals = []
7919 isinternals = []
7922 for name, module in sorted(extensions.extensions()):
7920 for name, module in sorted(extensions.extensions()):
7923 names.append(name)
7921 names.append(name)
7924 vers.append(extensions.moduleversion(module) or None)
7922 vers.append(extensions.moduleversion(module) or None)
7925 isinternals.append(extensions.ismoduleinternal(module))
7923 isinternals.append(extensions.ismoduleinternal(module))
7926 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7924 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7927 if names:
7925 if names:
7928 namefmt = b" %%-%ds " % max(len(n) for n in names)
7926 namefmt = b" %%-%ds " % max(len(n) for n in names)
7929 places = [_(b"external"), _(b"internal")]
7927 places = [_(b"external"), _(b"internal")]
7930 for n, v, p in zip(names, vers, isinternals):
7928 for n, v, p in zip(names, vers, isinternals):
7931 fn.startitem()
7929 fn.startitem()
7932 fn.condwrite(ui.verbose, b"name", namefmt, n)
7930 fn.condwrite(ui.verbose, b"name", namefmt, n)
7933 if ui.verbose:
7931 if ui.verbose:
7934 fn.plain(b"%s " % places[p])
7932 fn.plain(b"%s " % places[p])
7935 fn.data(bundled=p)
7933 fn.data(bundled=p)
7936 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7934 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7937 if ui.verbose:
7935 if ui.verbose:
7938 fn.plain(b"\n")
7936 fn.plain(b"\n")
7939 fn.end()
7937 fn.end()
7940 fm.end()
7938 fm.end()
7941
7939
7942
7940
7943 def loadcmdtable(ui, name, cmdtable):
7941 def loadcmdtable(ui, name, cmdtable):
7944 """Load command functions from specified cmdtable"""
7942 """Load command functions from specified cmdtable"""
7945 overrides = [cmd for cmd in cmdtable if cmd in table]
7943 overrides = [cmd for cmd in cmdtable if cmd in table]
7946 if overrides:
7944 if overrides:
7947 ui.warn(
7945 ui.warn(
7948 _(b"extension '%s' overrides commands: %s\n")
7946 _(b"extension '%s' overrides commands: %s\n")
7949 % (name, b" ".join(overrides))
7947 % (name, b" ".join(overrides))
7950 )
7948 )
7951 table.update(cmdtable)
7949 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now