##// END OF EJS Templates
config: move "component display" in the new module...
marmoute -
r53315:e98cea8f default
parent child Browse files
Show More
@@ -1,7710 +1,7701
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import annotations
8 from __future__ import annotations
9
9
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullid,
17 nullid,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 wdirrev,
20 wdirrev,
21 )
21 )
22 from . import (
22 from . import (
23 admin_commands as admin_commands_mod,
23 admin_commands as admin_commands_mod,
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 bundlecaches,
27 bundlecaches,
28 changegroup,
28 changegroup,
29 cmdutil,
29 cmdutil,
30 copies,
30 copies,
31 debugcommands as debugcommandsmod,
31 debugcommands as debugcommandsmod,
32 destutil,
32 destutil,
33 diffutil,
33 diffutil,
34 discovery,
34 discovery,
35 encoding,
35 encoding,
36 error,
36 error,
37 exchange,
37 exchange,
38 extensions,
38 extensions,
39 filemerge,
39 filemerge,
40 formatter,
40 formatter,
41 graphmod,
41 graphmod,
42 grep as grepmod,
42 grep as grepmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 mergestate as mergestatemod,
48 mergestate as mergestatemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 registrar,
55 registrar,
56 revsetlang,
56 revsetlang,
57 rewriteutil,
57 rewriteutil,
58 scmutil,
58 scmutil,
59 server,
59 server,
60 shelve as shelvemod,
60 shelve as shelvemod,
61 state as statemod,
61 state as statemod,
62 tags as tagsmod,
62 tags as tagsmod,
63 util,
63 util,
64 verify as verifymod,
64 verify as verifymod,
65 wireprotoserver,
65 wireprotoserver,
66 )
66 )
67
67
68 from .cmd_impls import graft as graft_impl
68 from .cmd_impls import graft as graft_impl
69 from .configuration import (
69 from .configuration import (
70 command as config_command,
70 command as config_command,
71 rcutil,
72 )
71 )
73 from .utils import (
72 from .utils import (
74 dateutil,
73 dateutil,
75 procutil,
74 procutil,
76 stringutil,
75 stringutil,
77 urlutil,
76 urlutil,
78 )
77 )
79
78
80 table = {}
79 table = {}
81 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
82 table.update(admin_commands_mod.command._table)
81 table.update(admin_commands_mod.command._table)
83
82
84 command = registrar.command(table)
83 command = registrar.command(table)
85 INTENT_READONLY = registrar.INTENT_READONLY
84 INTENT_READONLY = registrar.INTENT_READONLY
86
85
87 # common command options
86 # common command options
88
87
89 globalopts = [
88 globalopts = [
90 (
89 (
91 b'R',
90 b'R',
92 b'repository',
91 b'repository',
93 b'',
92 b'',
94 _(b'repository root directory or name of overlay bundle file'),
93 _(b'repository root directory or name of overlay bundle file'),
95 _(b'REPO'),
94 _(b'REPO'),
96 ),
95 ),
97 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
98 (
97 (
99 b'y',
98 b'y',
100 b'noninteractive',
99 b'noninteractive',
101 None,
100 None,
102 _(
101 _(
103 b'do not prompt, automatically pick the first choice for all prompts'
102 b'do not prompt, automatically pick the first choice for all prompts'
104 ),
103 ),
105 ),
104 ),
106 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'q', b'quiet', None, _(b'suppress output')),
107 (b'v', b'verbose', None, _(b'enable additional output')),
106 (b'v', b'verbose', None, _(b'enable additional output')),
108 (
107 (
109 b'',
108 b'',
110 b'color',
109 b'color',
111 b'',
110 b'',
112 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
113 # and should not be translated
112 # and should not be translated
114 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b"when to colorize (boolean, always, auto, never, or debug)"),
115 _(b'TYPE'),
114 _(b'TYPE'),
116 ),
115 ),
117 (
116 (
118 b'',
117 b'',
119 b'config',
118 b'config',
120 [],
119 [],
121 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'set/override config option (use \'section.name=value\')'),
122 _(b'CONFIG'),
121 _(b'CONFIG'),
123 ),
122 ),
124 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debug', None, _(b'enable debugging output')),
125 (b'', b'debugger', None, _(b'start debugger')),
124 (b'', b'debugger', None, _(b'start debugger')),
126 (
125 (
127 b'',
126 b'',
128 b'encoding',
127 b'encoding',
129 encoding.encoding,
128 encoding.encoding,
130 _(b'set the charset encoding'),
129 _(b'set the charset encoding'),
131 _(b'ENCODE'),
130 _(b'ENCODE'),
132 ),
131 ),
133 (
132 (
134 b'',
133 b'',
135 b'encodingmode',
134 b'encodingmode',
136 encoding.encodingmode,
135 encoding.encodingmode,
137 _(b'set the charset encoding mode'),
136 _(b'set the charset encoding mode'),
138 _(b'MODE'),
137 _(b'MODE'),
139 ),
138 ),
140 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'traceback', None, _(b'always print a traceback on exception')),
141 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'time', None, _(b'time how long the command takes')),
142 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'profile', None, _(b'print command execution profile')),
143 (b'', b'version', None, _(b'output version information and exit')),
142 (b'', b'version', None, _(b'output version information and exit')),
144 (b'h', b'help', None, _(b'display help and exit')),
143 (b'h', b'help', None, _(b'display help and exit')),
145 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (b'', b'hidden', False, _(b'consider hidden changesets')),
146 (
145 (
147 b'',
146 b'',
148 b'pager',
147 b'pager',
149 b'auto',
148 b'auto',
150 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b"when to paginate (boolean, always, auto, or never)"),
151 _(b'TYPE'),
150 _(b'TYPE'),
152 ),
151 ),
153 ]
152 ]
154
153
155 dryrunopts = cmdutil.dryrunopts
154 dryrunopts = cmdutil.dryrunopts
156 remoteopts = cmdutil.remoteopts
155 remoteopts = cmdutil.remoteopts
157 walkopts = cmdutil.walkopts
156 walkopts = cmdutil.walkopts
158 commitopts = cmdutil.commitopts
157 commitopts = cmdutil.commitopts
159 commitopts2 = cmdutil.commitopts2
158 commitopts2 = cmdutil.commitopts2
160 commitopts3 = cmdutil.commitopts3
159 commitopts3 = cmdutil.commitopts3
161 formatteropts = cmdutil.formatteropts
160 formatteropts = cmdutil.formatteropts
162 templateopts = cmdutil.templateopts
161 templateopts = cmdutil.templateopts
163 logopts = cmdutil.logopts
162 logopts = cmdutil.logopts
164 diffopts = cmdutil.diffopts
163 diffopts = cmdutil.diffopts
165 diffwsopts = cmdutil.diffwsopts
164 diffwsopts = cmdutil.diffwsopts
166 diffopts2 = cmdutil.diffopts2
165 diffopts2 = cmdutil.diffopts2
167 mergetoolopts = cmdutil.mergetoolopts
166 mergetoolopts = cmdutil.mergetoolopts
168 similarityopts = cmdutil.similarityopts
167 similarityopts = cmdutil.similarityopts
169 subrepoopts = cmdutil.subrepoopts
168 subrepoopts = cmdutil.subrepoopts
170 debugrevlogopts = cmdutil.debugrevlogopts
169 debugrevlogopts = cmdutil.debugrevlogopts
171
170
172 # Commands start here, listed alphabetically
171 # Commands start here, listed alphabetically
173
172
174
173
175 @command(
174 @command(
176 b'abort',
175 b'abort',
177 dryrunopts,
176 dryrunopts,
178 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
179 helpbasic=True,
178 helpbasic=True,
180 )
179 )
181 def abort(ui, repo, **opts):
180 def abort(ui, repo, **opts):
182 """abort an unfinished operation (EXPERIMENTAL)
181 """abort an unfinished operation (EXPERIMENTAL)
183
182
184 Aborts a multistep operation like graft, histedit, rebase, merge,
183 Aborts a multistep operation like graft, histedit, rebase, merge,
185 and unshelve if they are in an unfinished state.
184 and unshelve if they are in an unfinished state.
186
185
187 use --dry-run/-n to dry run the command.
186 use --dry-run/-n to dry run the command.
188 """
187 """
189 dryrun = opts.get('dry_run')
188 dryrun = opts.get('dry_run')
190 abortstate = cmdutil.getunfinishedstate(repo)
189 abortstate = cmdutil.getunfinishedstate(repo)
191 if not abortstate:
190 if not abortstate:
192 raise error.StateError(_(b'no operation in progress'))
191 raise error.StateError(_(b'no operation in progress'))
193 if not abortstate.abortfunc:
192 if not abortstate.abortfunc:
194 raise error.InputError(
193 raise error.InputError(
195 (
194 (
196 _(b"%s in progress but does not support 'hg abort'")
195 _(b"%s in progress but does not support 'hg abort'")
197 % (abortstate._opname)
196 % (abortstate._opname)
198 ),
197 ),
199 hint=abortstate.hint(),
198 hint=abortstate.hint(),
200 )
199 )
201 if dryrun:
200 if dryrun:
202 ui.status(
201 ui.status(
203 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
204 )
203 )
205 return
204 return
206 return abortstate.abortfunc(ui, repo)
205 return abortstate.abortfunc(ui, repo)
207
206
208
207
209 @command(
208 @command(
210 b'add',
209 b'add',
211 walkopts + subrepoopts + dryrunopts,
210 walkopts + subrepoopts + dryrunopts,
212 _(b'[OPTION]... [FILE]...'),
211 _(b'[OPTION]... [FILE]...'),
213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
214 helpbasic=True,
213 helpbasic=True,
215 inferrepo=True,
214 inferrepo=True,
216 )
215 )
217 def add(ui, repo, *pats, **opts):
216 def add(ui, repo, *pats, **opts):
218 """add the specified files on the next commit
217 """add the specified files on the next commit
219
218
220 Schedule files to be version controlled and added to the
219 Schedule files to be version controlled and added to the
221 repository.
220 repository.
222
221
223 The files will be added to the repository at the next commit. To
222 The files will be added to the repository at the next commit. To
224 undo an add before that, see :hg:`forget`.
223 undo an add before that, see :hg:`forget`.
225
224
226 If no names are given, add all files to the repository (except
225 If no names are given, add all files to the repository (except
227 files matching ``.hgignore``).
226 files matching ``.hgignore``).
228
227
229 .. container:: verbose
228 .. container:: verbose
230
229
231 Examples:
230 Examples:
232
231
233 - New (unknown) files are added
232 - New (unknown) files are added
234 automatically by :hg:`add`::
233 automatically by :hg:`add`::
235
234
236 $ ls
235 $ ls
237 foo.c
236 foo.c
238 $ hg status
237 $ hg status
239 ? foo.c
238 ? foo.c
240 $ hg add
239 $ hg add
241 adding foo.c
240 adding foo.c
242 $ hg status
241 $ hg status
243 A foo.c
242 A foo.c
244
243
245 - Specific files to be added can be specified::
244 - Specific files to be added can be specified::
246
245
247 $ ls
246 $ ls
248 bar.c foo.c
247 bar.c foo.c
249 $ hg status
248 $ hg status
250 ? bar.c
249 ? bar.c
251 ? foo.c
250 ? foo.c
252 $ hg add bar.c
251 $ hg add bar.c
253 $ hg status
252 $ hg status
254 A bar.c
253 A bar.c
255 ? foo.c
254 ? foo.c
256
255
257 Returns 0 if all files are successfully added.
256 Returns 0 if all files are successfully added.
258 """
257 """
259
258
260 with repo.wlock(), repo.dirstate.changing_files(repo):
259 with repo.wlock(), repo.dirstate.changing_files(repo):
261 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
260 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
262 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
261 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
263 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
262 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
264 return rejected and 1 or 0
263 return rejected and 1 or 0
265
264
266
265
267 @command(
266 @command(
268 b'addremove',
267 b'addremove',
269 similarityopts + subrepoopts + walkopts + dryrunopts,
268 similarityopts + subrepoopts + walkopts + dryrunopts,
270 _(b'[OPTION]... [FILE]...'),
269 _(b'[OPTION]... [FILE]...'),
271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
270 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
272 inferrepo=True,
271 inferrepo=True,
273 )
272 )
274 def addremove(ui, repo, *pats, **opts):
273 def addremove(ui, repo, *pats, **opts):
275 """add all new files, delete all missing files
274 """add all new files, delete all missing files
276
275
277 Add all new files and remove all missing files from the
276 Add all new files and remove all missing files from the
278 repository.
277 repository.
279
278
280 Unless names are given, new files are ignored if they match any of
279 Unless names are given, new files are ignored if they match any of
281 the patterns in ``.hgignore``. As with add, these changes take
280 the patterns in ``.hgignore``. As with add, these changes take
282 effect at the next commit.
281 effect at the next commit.
283
282
284 Use the -s/--similarity option to detect renamed files. This
283 Use the -s/--similarity option to detect renamed files. This
285 option takes a percentage between 0 (disabled) and 100 (files must
284 option takes a percentage between 0 (disabled) and 100 (files must
286 be identical) as its parameter. With a parameter greater than 0,
285 be identical) as its parameter. With a parameter greater than 0,
287 this compares every removed file with every added file and records
286 this compares every removed file with every added file and records
288 those similar enough as renames. Detecting renamed files this way
287 those similar enough as renames. Detecting renamed files this way
289 can be expensive. After using this option, :hg:`status -C` can be
288 can be expensive. After using this option, :hg:`status -C` can be
290 used to check which files were identified as moved or renamed. If
289 used to check which files were identified as moved or renamed. If
291 not specified, -s/--similarity defaults to 100 and only renames of
290 not specified, -s/--similarity defaults to 100 and only renames of
292 identical files are detected.
291 identical files are detected.
293
292
294 .. container:: verbose
293 .. container:: verbose
295
294
296 Examples:
295 Examples:
297
296
298 - A number of files (bar.c and foo.c) are new,
297 - A number of files (bar.c and foo.c) are new,
299 while foobar.c has been removed (without using :hg:`remove`)
298 while foobar.c has been removed (without using :hg:`remove`)
300 from the repository::
299 from the repository::
301
300
302 $ ls
301 $ ls
303 bar.c foo.c
302 bar.c foo.c
304 $ hg status
303 $ hg status
305 ! foobar.c
304 ! foobar.c
306 ? bar.c
305 ? bar.c
307 ? foo.c
306 ? foo.c
308 $ hg addremove
307 $ hg addremove
309 adding bar.c
308 adding bar.c
310 adding foo.c
309 adding foo.c
311 removing foobar.c
310 removing foobar.c
312 $ hg status
311 $ hg status
313 A bar.c
312 A bar.c
314 A foo.c
313 A foo.c
315 R foobar.c
314 R foobar.c
316
315
317 - A file foobar.c was moved to foo.c without using :hg:`rename`.
316 - A file foobar.c was moved to foo.c without using :hg:`rename`.
318 Afterwards, it was edited slightly::
317 Afterwards, it was edited slightly::
319
318
320 $ ls
319 $ ls
321 foo.c
320 foo.c
322 $ hg status
321 $ hg status
323 ! foobar.c
322 ! foobar.c
324 ? foo.c
323 ? foo.c
325 $ hg addremove --similarity 90
324 $ hg addremove --similarity 90
326 removing foobar.c
325 removing foobar.c
327 adding foo.c
326 adding foo.c
328 recording removal of foobar.c as rename to foo.c (94% similar)
327 recording removal of foobar.c as rename to foo.c (94% similar)
329 $ hg status -C
328 $ hg status -C
330 A foo.c
329 A foo.c
331 foobar.c
330 foobar.c
332 R foobar.c
331 R foobar.c
333
332
334 Returns 0 if all files are successfully added.
333 Returns 0 if all files are successfully added.
335 """
334 """
336 opts = pycompat.byteskwargs(opts)
335 opts = pycompat.byteskwargs(opts)
337 if not opts.get(b'similarity'):
336 if not opts.get(b'similarity'):
338 opts[b'similarity'] = b'100'
337 opts[b'similarity'] = b'100'
339 with repo.wlock(), repo.dirstate.changing_files(repo):
338 with repo.wlock(), repo.dirstate.changing_files(repo):
340 matcher = scmutil.match(repo[None], pats, opts)
339 matcher = scmutil.match(repo[None], pats, opts)
341 relative = scmutil.anypats(pats, opts)
340 relative = scmutil.anypats(pats, opts)
342 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
341 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
343 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
342 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
344
343
345
344
346 @command(
345 @command(
347 b'annotate|blame',
346 b'annotate|blame',
348 [
347 [
349 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
348 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
350 (
349 (
351 b'',
350 b'',
352 b'follow',
351 b'follow',
353 None,
352 None,
354 _(b'follow copies/renames and list the filename (DEPRECATED)'),
353 _(b'follow copies/renames and list the filename (DEPRECATED)'),
355 ),
354 ),
356 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
355 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
357 (b'a', b'text', None, _(b'treat all files as text')),
356 (b'a', b'text', None, _(b'treat all files as text')),
358 (b'u', b'user', None, _(b'list the author (long with -v)')),
357 (b'u', b'user', None, _(b'list the author (long with -v)')),
359 (b'f', b'file', None, _(b'list the filename')),
358 (b'f', b'file', None, _(b'list the filename')),
360 (b'd', b'date', None, _(b'list the date (short with -q)')),
359 (b'd', b'date', None, _(b'list the date (short with -q)')),
361 (b'n', b'number', None, _(b'list the revision number (default)')),
360 (b'n', b'number', None, _(b'list the revision number (default)')),
362 (b'c', b'changeset', None, _(b'list the changeset')),
361 (b'c', b'changeset', None, _(b'list the changeset')),
363 (
362 (
364 b'l',
363 b'l',
365 b'line-number',
364 b'line-number',
366 None,
365 None,
367 _(b'show line number at the first appearance'),
366 _(b'show line number at the first appearance'),
368 ),
367 ),
369 (
368 (
370 b'',
369 b'',
371 b'skip',
370 b'skip',
372 [],
371 [],
373 _(b'revset to not display (EXPERIMENTAL)'),
372 _(b'revset to not display (EXPERIMENTAL)'),
374 _(b'REV'),
373 _(b'REV'),
375 ),
374 ),
376 (
375 (
377 b'L',
376 b'L',
378 b'line-range',
377 b'line-range',
379 [],
378 [],
380 _(b'follow line range of specified file (EXPERIMENTAL)'),
379 _(b'follow line range of specified file (EXPERIMENTAL)'),
381 _(b'FILE,RANGE'),
380 _(b'FILE,RANGE'),
382 ),
381 ),
383 ]
382 ]
384 + diffwsopts
383 + diffwsopts
385 + walkopts
384 + walkopts
386 + formatteropts,
385 + formatteropts,
387 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
386 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
388 helpcategory=command.CATEGORY_FILE_CONTENTS,
387 helpcategory=command.CATEGORY_FILE_CONTENTS,
389 helpbasic=True,
388 helpbasic=True,
390 inferrepo=True,
389 inferrepo=True,
391 )
390 )
392 def annotate(ui, repo, *pats, **opts):
391 def annotate(ui, repo, *pats, **opts):
393 """show changeset information by line for each file
392 """show changeset information by line for each file
394
393
395 List changes in files, showing the revision id responsible for
394 List changes in files, showing the revision id responsible for
396 each line.
395 each line.
397
396
398 This command is useful for discovering when a change was made and
397 This command is useful for discovering when a change was made and
399 by whom.
398 by whom.
400
399
401 If you include --file, --user, or --date, the revision number is
400 If you include --file, --user, or --date, the revision number is
402 suppressed unless you also include --number.
401 suppressed unless you also include --number.
403
402
404 Without the -a/--text option, annotate will avoid processing files
403 Without the -a/--text option, annotate will avoid processing files
405 it detects as binary. With -a, annotate will annotate the file
404 it detects as binary. With -a, annotate will annotate the file
406 anyway, although the results will probably be neither useful
405 anyway, although the results will probably be neither useful
407 nor desirable.
406 nor desirable.
408
407
409 .. container:: verbose
408 .. container:: verbose
410
409
411 Use -L/--line-range FILE,M:N options to filter the output to the lines
410 Use -L/--line-range FILE,M:N options to filter the output to the lines
412 from M to N in FILE. This option is incompatible with --no-follow and
411 from M to N in FILE. This option is incompatible with --no-follow and
413 cannot be combined with file pattern arguments. When combined with --rev
412 cannot be combined with file pattern arguments. When combined with --rev
414 the line ranges refer to the state of the file at the requested revision.
413 the line ranges refer to the state of the file at the requested revision.
415
414
416 .. container:: verbose
415 .. container:: verbose
417
416
418 Template:
417 Template:
419
418
420 The following keywords are supported in addition to the common template
419 The following keywords are supported in addition to the common template
421 keywords and functions. See also :hg:`help templates`.
420 keywords and functions. See also :hg:`help templates`.
422
421
423 :lines: List of lines with annotation data.
422 :lines: List of lines with annotation data.
424 :path: String. Repository-absolute path of the specified file.
423 :path: String. Repository-absolute path of the specified file.
425
424
426 And each entry of ``{lines}`` provides the following sub-keywords in
425 And each entry of ``{lines}`` provides the following sub-keywords in
427 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
426 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
428
427
429 :line: String. Line content.
428 :line: String. Line content.
430 :lineno: Integer. Line number at that revision.
429 :lineno: Integer. Line number at that revision.
431 :path: String. Repository-absolute path of the file at that revision.
430 :path: String. Repository-absolute path of the file at that revision.
432
431
433 See :hg:`help templates.operators` for the list expansion syntax.
432 See :hg:`help templates.operators` for the list expansion syntax.
434
433
435 Returns 0 on success.
434 Returns 0 on success.
436 """
435 """
437 opts = pycompat.byteskwargs(opts)
436 opts = pycompat.byteskwargs(opts)
438
437
439 linerange = opts.get(b'line_range')
438 linerange = opts.get(b'line_range')
440
439
441 if linerange and opts.get(b'no_follow'):
440 if linerange and opts.get(b'no_follow'):
442 raise error.InputError(
441 raise error.InputError(
443 _(b'--line-range is incompatible with --no-follow')
442 _(b'--line-range is incompatible with --no-follow')
444 )
443 )
445
444
446 if pats and linerange:
445 if pats and linerange:
447 raise error.InputError(
446 raise error.InputError(
448 _(b'cannot combine filename or pattern and --line-range')
447 _(b'cannot combine filename or pattern and --line-range')
449 )
448 )
450
449
451 if not pats and not linerange:
450 if not pats and not linerange:
452 raise error.InputError(
451 raise error.InputError(
453 _(b'at least one filename or pattern is required')
452 _(b'at least one filename or pattern is required')
454 )
453 )
455
454
456 if opts.get(b'follow'):
455 if opts.get(b'follow'):
457 # --follow is deprecated and now just an alias for -f/--file
456 # --follow is deprecated and now just an alias for -f/--file
458 # to mimic the behavior of Mercurial before version 1.5
457 # to mimic the behavior of Mercurial before version 1.5
459 opts[b'file'] = True
458 opts[b'file'] = True
460
459
461 if (
460 if (
462 not opts.get(b'user')
461 not opts.get(b'user')
463 and not opts.get(b'changeset')
462 and not opts.get(b'changeset')
464 and not opts.get(b'date')
463 and not opts.get(b'date')
465 and not opts.get(b'file')
464 and not opts.get(b'file')
466 ):
465 ):
467 opts[b'number'] = True
466 opts[b'number'] = True
468
467
469 linenumber = opts.get(b'line_number') is not None
468 linenumber = opts.get(b'line_number') is not None
470 if (
469 if (
471 linenumber
470 linenumber
472 and (not opts.get(b'changeset'))
471 and (not opts.get(b'changeset'))
473 and (not opts.get(b'number'))
472 and (not opts.get(b'number'))
474 ):
473 ):
475 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
474 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
476
475
477 rev = opts.get(b'rev')
476 rev = opts.get(b'rev')
478 if rev:
477 if rev:
479 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
478 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
480 ctx = logcmdutil.revsingle(repo, rev)
479 ctx = logcmdutil.revsingle(repo, rev)
481
480
482 if not pats:
481 if not pats:
483 pats = [
482 pats = [
484 fname
483 fname
485 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
484 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
486 ]
485 ]
487
486
488 ui.pager(b'annotate')
487 ui.pager(b'annotate')
489 rootfm = ui.formatter(b'annotate', opts)
488 rootfm = ui.formatter(b'annotate', opts)
490 if ui.debugflag:
489 if ui.debugflag:
491 shorthex = pycompat.identity
490 shorthex = pycompat.identity
492 else:
491 else:
493
492
494 def shorthex(h):
493 def shorthex(h):
495 return h[:12]
494 return h[:12]
496
495
497 if ui.quiet:
496 if ui.quiet:
498 datefunc = dateutil.shortdate
497 datefunc = dateutil.shortdate
499 else:
498 else:
500 datefunc = dateutil.datestr
499 datefunc = dateutil.datestr
501 if ctx.rev() is None:
500 if ctx.rev() is None:
502 if opts.get(b'changeset'):
501 if opts.get(b'changeset'):
503 # omit "+" suffix which is appended to node hex
502 # omit "+" suffix which is appended to node hex
504 def formatrev(rev):
503 def formatrev(rev):
505 if rev == wdirrev:
504 if rev == wdirrev:
506 return b'%d' % ctx.p1().rev()
505 return b'%d' % ctx.p1().rev()
507 else:
506 else:
508 return b'%d' % rev
507 return b'%d' % rev
509
508
510 else:
509 else:
511
510
512 def formatrev(rev):
511 def formatrev(rev):
513 if rev == wdirrev:
512 if rev == wdirrev:
514 return b'%d+' % ctx.p1().rev()
513 return b'%d+' % ctx.p1().rev()
515 else:
514 else:
516 return b'%d ' % rev
515 return b'%d ' % rev
517
516
518 def formathex(h):
517 def formathex(h):
519 if h == repo.nodeconstants.wdirhex:
518 if h == repo.nodeconstants.wdirhex:
520 return b'%s+' % shorthex(hex(ctx.p1().node()))
519 return b'%s+' % shorthex(hex(ctx.p1().node()))
521 else:
520 else:
522 return b'%s ' % shorthex(h)
521 return b'%s ' % shorthex(h)
523
522
524 else:
523 else:
525 formatrev = b'%d'.__mod__
524 formatrev = b'%d'.__mod__
526 formathex = shorthex
525 formathex = shorthex
527
526
528 opmap = [
527 opmap = [
529 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
528 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
530 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
529 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
531 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
530 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
532 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
531 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
533 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
532 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
534 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
533 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
535 ]
534 ]
536 opnamemap = {
535 opnamemap = {
537 b'rev': b'number',
536 b'rev': b'number',
538 b'node': b'changeset',
537 b'node': b'changeset',
539 b'path': b'file',
538 b'path': b'file',
540 b'lineno': b'line_number',
539 b'lineno': b'line_number',
541 }
540 }
542
541
543 if rootfm.isplain():
542 if rootfm.isplain():
544
543
545 def makefunc(get, fmt):
544 def makefunc(get, fmt):
546 return lambda x: fmt(get(x))
545 return lambda x: fmt(get(x))
547
546
548 else:
547 else:
549
548
550 def makefunc(get, fmt):
549 def makefunc(get, fmt):
551 return get
550 return get
552
551
553 datahint = rootfm.datahint()
552 datahint = rootfm.datahint()
554 funcmap = [
553 funcmap = [
555 (makefunc(get, fmt), sep)
554 (makefunc(get, fmt), sep)
556 for fn, sep, get, fmt in opmap
555 for fn, sep, get, fmt in opmap
557 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
556 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
558 ]
557 ]
559 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
558 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
560 fields = b' '.join(
559 fields = b' '.join(
561 fn
560 fn
562 for fn, sep, get, fmt in opmap
561 for fn, sep, get, fmt in opmap
563 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
562 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
564 )
563 )
565
564
566 def bad(x, y):
565 def bad(x, y):
567 raise error.InputError(b"%s: %s" % (x, y))
566 raise error.InputError(b"%s: %s" % (x, y))
568
567
569 m = scmutil.match(ctx, pats, opts, badfn=bad)
568 m = scmutil.match(ctx, pats, opts, badfn=bad)
570
569
571 follow = not opts.get(b'no_follow')
570 follow = not opts.get(b'no_follow')
572 diffopts = patch.difffeatureopts(
571 diffopts = patch.difffeatureopts(
573 ui, opts, section=b'annotate', whitespace=True
572 ui, opts, section=b'annotate', whitespace=True
574 )
573 )
575 skiprevs = opts.get(b'skip')
574 skiprevs = opts.get(b'skip')
576 if skiprevs:
575 if skiprevs:
577 skiprevs = logcmdutil.revrange(repo, skiprevs)
576 skiprevs = logcmdutil.revrange(repo, skiprevs)
578
577
579 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
578 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
580 for abs in ctx.walk(m):
579 for abs in ctx.walk(m):
581 fctx = ctx[abs]
580 fctx = ctx[abs]
582 rootfm.startitem()
581 rootfm.startitem()
583 rootfm.data(path=abs)
582 rootfm.data(path=abs)
584 if not opts.get(b'text') and fctx.isbinary():
583 if not opts.get(b'text') and fctx.isbinary():
585 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
584 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
586 continue
585 continue
587
586
588 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
587 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
589 lines = fctx.annotate(
588 lines = fctx.annotate(
590 follow=follow, skiprevs=skiprevs, diffopts=diffopts
589 follow=follow, skiprevs=skiprevs, diffopts=diffopts
591 )
590 )
592 if linerange:
591 if linerange:
593 _fname, (line_start, line_end) = list(
592 _fname, (line_start, line_end) = list(
594 logcmdutil._parselinerangeopt(repo, opts)
593 logcmdutil._parselinerangeopt(repo, opts)
595 )[0]
594 )[0]
596 lines = [
595 lines = [
597 line
596 line
598 for no, line in enumerate(lines)
597 for no, line in enumerate(lines)
599 if line_start <= no < line_end
598 if line_start <= no < line_end
600 ]
599 ]
601
600
602 if not lines:
601 if not lines:
603 fm.end()
602 fm.end()
604 continue
603 continue
605 formats = []
604 formats = []
606 pieces = []
605 pieces = []
607
606
608 for f, sep in funcmap:
607 for f, sep in funcmap:
609 l = [f(n) for n in lines]
608 l = [f(n) for n in lines]
610 if fm.isplain():
609 if fm.isplain():
611 sizes = [encoding.colwidth(x) for x in l]
610 sizes = [encoding.colwidth(x) for x in l]
612 ml = max(sizes)
611 ml = max(sizes)
613 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
612 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
614 else:
613 else:
615 formats.append([b'%s'] * len(l))
614 formats.append([b'%s'] * len(l))
616 pieces.append(l)
615 pieces.append(l)
617
616
618 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
617 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
619 fm.startitem()
618 fm.startitem()
620 fm.context(fctx=n.fctx)
619 fm.context(fctx=n.fctx)
621 fm.write(fields, b"".join(f), *p)
620 fm.write(fields, b"".join(f), *p)
622 if n.skip:
621 if n.skip:
623 fmt = b"* %s"
622 fmt = b"* %s"
624 else:
623 else:
625 fmt = b": %s"
624 fmt = b": %s"
626 fm.write(b'line', fmt, n.text)
625 fm.write(b'line', fmt, n.text)
627
626
628 if not lines[-1].text.endswith(b'\n'):
627 if not lines[-1].text.endswith(b'\n'):
629 fm.plain(b'\n')
628 fm.plain(b'\n')
630 fm.end()
629 fm.end()
631
630
632 rootfm.end()
631 rootfm.end()
633
632
634
633
635 @command(
634 @command(
636 b'archive',
635 b'archive',
637 [
636 [
638 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
637 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
639 (
638 (
640 b'p',
639 b'p',
641 b'prefix',
640 b'prefix',
642 b'',
641 b'',
643 _(b'directory prefix for files in archive'),
642 _(b'directory prefix for files in archive'),
644 _(b'PREFIX'),
643 _(b'PREFIX'),
645 ),
644 ),
646 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
645 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
647 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
646 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
648 ]
647 ]
649 + subrepoopts
648 + subrepoopts
650 + walkopts,
649 + walkopts,
651 _(b'[OPTION]... DEST'),
650 _(b'[OPTION]... DEST'),
652 helpcategory=command.CATEGORY_IMPORT_EXPORT,
651 helpcategory=command.CATEGORY_IMPORT_EXPORT,
653 )
652 )
654 def archive(ui, repo, dest, **opts):
653 def archive(ui, repo, dest, **opts):
655 """create an unversioned archive of a repository revision
654 """create an unversioned archive of a repository revision
656
655
657 By default, the revision used is the parent of the working
656 By default, the revision used is the parent of the working
658 directory; use -r/--rev to specify a different revision.
657 directory; use -r/--rev to specify a different revision.
659
658
660 The archive type is automatically detected based on file
659 The archive type is automatically detected based on file
661 extension (to override, use -t/--type).
660 extension (to override, use -t/--type).
662
661
663 .. container:: verbose
662 .. container:: verbose
664
663
665 Examples:
664 Examples:
666
665
667 - create a zip file containing the 1.0 release::
666 - create a zip file containing the 1.0 release::
668
667
669 hg archive -r 1.0 project-1.0.zip
668 hg archive -r 1.0 project-1.0.zip
670
669
671 - create a tarball excluding .hg files::
670 - create a tarball excluding .hg files::
672
671
673 hg archive project.tar.gz -X ".hg*"
672 hg archive project.tar.gz -X ".hg*"
674
673
675 Valid types are:
674 Valid types are:
676
675
677 :``files``: a directory full of files (default)
676 :``files``: a directory full of files (default)
678 :``tar``: tar archive, uncompressed
677 :``tar``: tar archive, uncompressed
679 :``tbz2``: tar archive, compressed using bzip2
678 :``tbz2``: tar archive, compressed using bzip2
680 :``tgz``: tar archive, compressed using gzip
679 :``tgz``: tar archive, compressed using gzip
681 :``txz``: tar archive, compressed using lzma (only in Python 3)
680 :``txz``: tar archive, compressed using lzma (only in Python 3)
682 :``uzip``: zip archive, uncompressed
681 :``uzip``: zip archive, uncompressed
683 :``zip``: zip archive, compressed using deflate
682 :``zip``: zip archive, compressed using deflate
684
683
685 The exact name of the destination archive or directory is given
684 The exact name of the destination archive or directory is given
686 using a format string; see :hg:`help export` for details.
685 using a format string; see :hg:`help export` for details.
687
686
688 Each member added to an archive file has a directory prefix
687 Each member added to an archive file has a directory prefix
689 prepended. Use -p/--prefix to specify a format string for the
688 prepended. Use -p/--prefix to specify a format string for the
690 prefix. The default is the basename of the archive, with suffixes
689 prefix. The default is the basename of the archive, with suffixes
691 removed.
690 removed.
692
691
693 Returns 0 on success.
692 Returns 0 on success.
694 """
693 """
695
694
696 rev = opts.get('rev')
695 rev = opts.get('rev')
697 if rev:
696 if rev:
698 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
697 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
699 ctx = logcmdutil.revsingle(repo, rev)
698 ctx = logcmdutil.revsingle(repo, rev)
700 if not ctx:
699 if not ctx:
701 raise error.InputError(
700 raise error.InputError(
702 _(b'no working directory: please specify a revision')
701 _(b'no working directory: please specify a revision')
703 )
702 )
704 node = ctx.node()
703 node = ctx.node()
705 dest = cmdutil.makefilename(ctx, dest)
704 dest = cmdutil.makefilename(ctx, dest)
706 if os.path.realpath(dest) == repo.root:
705 if os.path.realpath(dest) == repo.root:
707 raise error.InputError(_(b'repository root cannot be destination'))
706 raise error.InputError(_(b'repository root cannot be destination'))
708
707
709 kind = opts.get('type') or archival.guesskind(dest) or b'files'
708 kind = opts.get('type') or archival.guesskind(dest) or b'files'
710 prefix = opts.get('prefix')
709 prefix = opts.get('prefix')
711
710
712 if dest == b'-':
711 if dest == b'-':
713 if kind == b'files':
712 if kind == b'files':
714 raise error.InputError(_(b'cannot archive plain files to stdout'))
713 raise error.InputError(_(b'cannot archive plain files to stdout'))
715 realdest = dest
714 realdest = dest
716 dest = lambda: cmdutil.makefileobj(ctx, realdest)
715 dest = lambda: cmdutil.makefileobj(ctx, realdest)
717 if not prefix:
716 if not prefix:
718 prefix = os.path.basename(repo.root) + b'-%h'
717 prefix = os.path.basename(repo.root) + b'-%h'
719
718
720 prefix = cmdutil.makefilename(ctx, prefix)
719 prefix = cmdutil.makefilename(ctx, prefix)
721 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
720 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
722 archival.archive(
721 archival.archive(
723 repo,
722 repo,
724 dest,
723 dest,
725 node,
724 node,
726 kind,
725 kind,
727 not opts.get('no_decode'),
726 not opts.get('no_decode'),
728 match,
727 match,
729 prefix,
728 prefix,
730 subrepos=opts.get('subrepos'),
729 subrepos=opts.get('subrepos'),
731 )
730 )
732
731
733
732
734 @command(
733 @command(
735 b'backout',
734 b'backout',
736 [
735 [
737 (
736 (
738 b'',
737 b'',
739 b'merge',
738 b'merge',
740 None,
739 None,
741 _(b'merge with old dirstate parent after backout'),
740 _(b'merge with old dirstate parent after backout'),
742 ),
741 ),
743 (
742 (
744 b'',
743 b'',
745 b'commit',
744 b'commit',
746 None,
745 None,
747 _(b'commit if no conflicts were encountered (DEPRECATED)'),
746 _(b'commit if no conflicts were encountered (DEPRECATED)'),
748 ),
747 ),
749 (b'', b'no-commit', None, _(b'do not commit')),
748 (b'', b'no-commit', None, _(b'do not commit')),
750 (
749 (
751 b'',
750 b'',
752 b'parent',
751 b'parent',
753 b'',
752 b'',
754 _(b'parent to choose when backing out merge (DEPRECATED)'),
753 _(b'parent to choose when backing out merge (DEPRECATED)'),
755 _(b'REV'),
754 _(b'REV'),
756 ),
755 ),
757 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
756 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
758 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
757 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
759 ]
758 ]
760 + mergetoolopts
759 + mergetoolopts
761 + walkopts
760 + walkopts
762 + commitopts
761 + commitopts
763 + commitopts2,
762 + commitopts2,
764 _(b'[OPTION]... [-r] REV'),
763 _(b'[OPTION]... [-r] REV'),
765 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
764 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
766 )
765 )
767 def backout(ui, repo, node=None, rev=None, **opts):
766 def backout(ui, repo, node=None, rev=None, **opts):
768 """reverse effect of earlier changeset
767 """reverse effect of earlier changeset
769
768
770 Prepare a new changeset with the effect of REV undone in the
769 Prepare a new changeset with the effect of REV undone in the
771 current working directory. If no conflicts were encountered,
770 current working directory. If no conflicts were encountered,
772 it will be committed immediately.
771 it will be committed immediately.
773
772
774 If REV is the parent of the working directory, then this new changeset
773 If REV is the parent of the working directory, then this new changeset
775 is committed automatically (unless --no-commit is specified).
774 is committed automatically (unless --no-commit is specified).
776
775
777 .. note::
776 .. note::
778
777
779 :hg:`backout` cannot be used to fix either an unwanted or
778 :hg:`backout` cannot be used to fix either an unwanted or
780 incorrect merge.
779 incorrect merge.
781
780
782 .. container:: verbose
781 .. container:: verbose
783
782
784 Examples:
783 Examples:
785
784
786 - Reverse the effect of the parent of the working directory.
785 - Reverse the effect of the parent of the working directory.
787 This backout will be committed immediately::
786 This backout will be committed immediately::
788
787
789 hg backout -r .
788 hg backout -r .
790
789
791 - Reverse the effect of previous bad revision 23::
790 - Reverse the effect of previous bad revision 23::
792
791
793 hg backout -r 23
792 hg backout -r 23
794
793
795 - Reverse the effect of previous bad revision 23 and
794 - Reverse the effect of previous bad revision 23 and
796 leave changes uncommitted::
795 leave changes uncommitted::
797
796
798 hg backout -r 23 --no-commit
797 hg backout -r 23 --no-commit
799 hg commit -m "Backout revision 23"
798 hg commit -m "Backout revision 23"
800
799
801 By default, the pending changeset will have one parent,
800 By default, the pending changeset will have one parent,
802 maintaining a linear history. With --merge, the pending
801 maintaining a linear history. With --merge, the pending
803 changeset will instead have two parents: the old parent of the
802 changeset will instead have two parents: the old parent of the
804 working directory and a new child of REV that simply undoes REV.
803 working directory and a new child of REV that simply undoes REV.
805
804
806 Before version 1.7, the behavior without --merge was equivalent
805 Before version 1.7, the behavior without --merge was equivalent
807 to specifying --merge followed by :hg:`update --clean .` to
806 to specifying --merge followed by :hg:`update --clean .` to
808 cancel the merge and leave the child of REV as a head to be
807 cancel the merge and leave the child of REV as a head to be
809 merged separately.
808 merged separately.
810
809
811 See :hg:`help dates` for a list of formats valid for -d/--date.
810 See :hg:`help dates` for a list of formats valid for -d/--date.
812
811
813 See :hg:`help revert` for a way to restore files to the state
812 See :hg:`help revert` for a way to restore files to the state
814 of another revision.
813 of another revision.
815
814
816 Returns 0 on success, 1 if nothing to backout or there are unresolved
815 Returns 0 on success, 1 if nothing to backout or there are unresolved
817 files.
816 files.
818 """
817 """
819 with repo.wlock(), repo.lock():
818 with repo.wlock(), repo.lock():
820 return _dobackout(ui, repo, node, rev, **opts)
819 return _dobackout(ui, repo, node, rev, **opts)
821
820
822
821
823 def _dobackout(ui, repo, node=None, rev=None, **opts):
822 def _dobackout(ui, repo, node=None, rev=None, **opts):
824 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
823 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
825
824
826 if rev and node:
825 if rev and node:
827 raise error.InputError(_(b"please specify just one revision"))
826 raise error.InputError(_(b"please specify just one revision"))
828
827
829 if not rev:
828 if not rev:
830 rev = node
829 rev = node
831
830
832 if not rev:
831 if not rev:
833 raise error.InputError(_(b"please specify a revision to backout"))
832 raise error.InputError(_(b"please specify a revision to backout"))
834
833
835 date = opts.get('date')
834 date = opts.get('date')
836 if date:
835 if date:
837 opts['date'] = dateutil.parsedate(date)
836 opts['date'] = dateutil.parsedate(date)
838
837
839 cmdutil.checkunfinished(repo)
838 cmdutil.checkunfinished(repo)
840 cmdutil.bailifchanged(repo)
839 cmdutil.bailifchanged(repo)
841 ctx = logcmdutil.revsingle(repo, rev)
840 ctx = logcmdutil.revsingle(repo, rev)
842 node = ctx.node()
841 node = ctx.node()
843
842
844 op1, op2 = repo.dirstate.parents()
843 op1, op2 = repo.dirstate.parents()
845 if not repo.changelog.isancestor(node, op1):
844 if not repo.changelog.isancestor(node, op1):
846 raise error.InputError(
845 raise error.InputError(
847 _(b'cannot backout change that is not an ancestor')
846 _(b'cannot backout change that is not an ancestor')
848 )
847 )
849
848
850 p1, p2 = repo.changelog.parents(node)
849 p1, p2 = repo.changelog.parents(node)
851 if p1 == repo.nullid:
850 if p1 == repo.nullid:
852 raise error.InputError(_(b'cannot backout a change with no parents'))
851 raise error.InputError(_(b'cannot backout a change with no parents'))
853 if p2 != repo.nullid:
852 if p2 != repo.nullid:
854 if not opts.get('parent'):
853 if not opts.get('parent'):
855 raise error.InputError(_(b'cannot backout a merge changeset'))
854 raise error.InputError(_(b'cannot backout a merge changeset'))
856 p = repo.lookup(opts['parent'])
855 p = repo.lookup(opts['parent'])
857 if p not in (p1, p2):
856 if p not in (p1, p2):
858 raise error.InputError(
857 raise error.InputError(
859 _(b'%s is not a parent of %s') % (short(p), short(node))
858 _(b'%s is not a parent of %s') % (short(p), short(node))
860 )
859 )
861 parent = p
860 parent = p
862 else:
861 else:
863 if opts.get('parent'):
862 if opts.get('parent'):
864 raise error.InputError(
863 raise error.InputError(
865 _(b'cannot use --parent on non-merge changeset')
864 _(b'cannot use --parent on non-merge changeset')
866 )
865 )
867 parent = p1
866 parent = p1
868
867
869 # the backout should appear on the same branch
868 # the backout should appear on the same branch
870 branch = repo.dirstate.branch()
869 branch = repo.dirstate.branch()
871 bheads = repo.branchheads(branch)
870 bheads = repo.branchheads(branch)
872 rctx = scmutil.revsingle(repo, hex(parent))
871 rctx = scmutil.revsingle(repo, hex(parent))
873 if not opts.get('merge') and op1 != node:
872 if not opts.get('merge') and op1 != node:
874 with repo.transaction(b"backout"):
873 with repo.transaction(b"backout"):
875 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
874 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
876 with ui.configoverride(overrides, b'backout'):
875 with ui.configoverride(overrides, b'backout'):
877 stats = mergemod.back_out(ctx, parent=repo[parent])
876 stats = mergemod.back_out(ctx, parent=repo[parent])
878 repo.setparents(op1, op2)
877 repo.setparents(op1, op2)
879 hg._showstats(repo, stats)
878 hg._showstats(repo, stats)
880 if stats.unresolvedcount:
879 if stats.unresolvedcount:
881 repo.ui.status(
880 repo.ui.status(
882 _(b"use 'hg resolve' to retry unresolved file merges\n")
881 _(b"use 'hg resolve' to retry unresolved file merges\n")
883 )
882 )
884 return 1
883 return 1
885 else:
884 else:
886 hg.clean(repo, node, show_stats=False)
885 hg.clean(repo, node, show_stats=False)
887 repo.dirstate.setbranch(branch, repo.currenttransaction())
886 repo.dirstate.setbranch(branch, repo.currenttransaction())
888 cmdutil.revert(ui, repo, rctx)
887 cmdutil.revert(ui, repo, rctx)
889
888
890 if opts.get('no_commit'):
889 if opts.get('no_commit'):
891 msg = _(b"changeset %s backed out, don't forget to commit.\n")
890 msg = _(b"changeset %s backed out, don't forget to commit.\n")
892 ui.status(msg % short(node))
891 ui.status(msg % short(node))
893 return 0
892 return 0
894
893
895 def commitfunc(ui, repo, message, match, opts):
894 def commitfunc(ui, repo, message, match, opts):
896 editform = b'backout'
895 editform = b'backout'
897 e = cmdutil.getcommiteditor(
896 e = cmdutil.getcommiteditor(
898 editform=editform, **pycompat.strkwargs(opts)
897 editform=editform, **pycompat.strkwargs(opts)
899 )
898 )
900 if not message:
899 if not message:
901 # we don't translate commit messages
900 # we don't translate commit messages
902 message = b"Backed out changeset %s" % short(node)
901 message = b"Backed out changeset %s" % short(node)
903 e = cmdutil.getcommiteditor(edit=True, editform=editform)
902 e = cmdutil.getcommiteditor(edit=True, editform=editform)
904 return repo.commit(
903 return repo.commit(
905 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
904 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
906 )
905 )
907
906
908 # save to detect changes
907 # save to detect changes
909 tip = repo.changelog.tip()
908 tip = repo.changelog.tip()
910
909
911 newnode = cmdutil.commit(
910 newnode = cmdutil.commit(
912 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
911 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
913 )
912 )
914 if not newnode:
913 if not newnode:
915 ui.status(_(b"nothing changed\n"))
914 ui.status(_(b"nothing changed\n"))
916 return 1
915 return 1
917 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
916 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
918
917
919 def nice(node):
918 def nice(node):
920 return b'%d:%s' % (repo.changelog.rev(node), short(node))
919 return b'%d:%s' % (repo.changelog.rev(node), short(node))
921
920
922 ui.status(
921 ui.status(
923 _(b'changeset %s backs out changeset %s\n')
922 _(b'changeset %s backs out changeset %s\n')
924 % (nice(newnode), nice(node))
923 % (nice(newnode), nice(node))
925 )
924 )
926 if opts.get('merge') and op1 != node:
925 if opts.get('merge') and op1 != node:
927 hg.clean(repo, op1, show_stats=False)
926 hg.clean(repo, op1, show_stats=False)
928 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
927 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
929 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
928 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
930 with ui.configoverride(overrides, b'backout'):
929 with ui.configoverride(overrides, b'backout'):
931 return hg.merge(repo[b'tip'])
930 return hg.merge(repo[b'tip'])
932 return 0
931 return 0
933
932
934
933
935 @command(
934 @command(
936 b'bisect',
935 b'bisect',
937 [
936 [
938 (b'r', b'reset', False, _(b'reset bisect state')),
937 (b'r', b'reset', False, _(b'reset bisect state')),
939 (b'g', b'good', False, _(b'mark changeset good')),
938 (b'g', b'good', False, _(b'mark changeset good')),
940 (b'b', b'bad', False, _(b'mark changeset bad')),
939 (b'b', b'bad', False, _(b'mark changeset bad')),
941 (b's', b'skip', False, _(b'skip testing changeset')),
940 (b's', b'skip', False, _(b'skip testing changeset')),
942 (b'e', b'extend', False, _(b'extend the bisect range')),
941 (b'e', b'extend', False, _(b'extend the bisect range')),
943 (
942 (
944 b'c',
943 b'c',
945 b'command',
944 b'command',
946 b'',
945 b'',
947 _(b'use command to check changeset state'),
946 _(b'use command to check changeset state'),
948 _(b'CMD'),
947 _(b'CMD'),
949 ),
948 ),
950 (b'U', b'noupdate', False, _(b'do not update to target')),
949 (b'U', b'noupdate', False, _(b'do not update to target')),
951 ],
950 ],
952 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
951 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
953 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
952 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
954 )
953 )
955 def bisect(
954 def bisect(
956 ui,
955 ui,
957 repo,
956 repo,
958 positional_1=None,
957 positional_1=None,
959 positional_2=None,
958 positional_2=None,
960 command=None,
959 command=None,
961 reset=None,
960 reset=None,
962 good=None,
961 good=None,
963 bad=None,
962 bad=None,
964 skip=None,
963 skip=None,
965 extend=None,
964 extend=None,
966 noupdate=None,
965 noupdate=None,
967 ):
966 ):
968 """subdivision search of changesets
967 """subdivision search of changesets
969
968
970 This command helps to find changesets which introduce problems. To
969 This command helps to find changesets which introduce problems. To
971 use, mark the earliest changeset you know exhibits the problem as
970 use, mark the earliest changeset you know exhibits the problem as
972 bad, then mark the latest changeset which is free from the problem
971 bad, then mark the latest changeset which is free from the problem
973 as good. Bisect will update your working directory to a revision
972 as good. Bisect will update your working directory to a revision
974 for testing (unless the -U/--noupdate option is specified). Once
973 for testing (unless the -U/--noupdate option is specified). Once
975 you have performed tests, mark the working directory as good or
974 you have performed tests, mark the working directory as good or
976 bad, and bisect will either update to another candidate changeset
975 bad, and bisect will either update to another candidate changeset
977 or announce that it has found the bad revision.
976 or announce that it has found the bad revision.
978
977
979 As a shortcut, you can also use the revision argument to mark a
978 As a shortcut, you can also use the revision argument to mark a
980 revision as good or bad without checking it out first.
979 revision as good or bad without checking it out first.
981
980
982 If you supply a command, it will be used for automatic bisection.
981 If you supply a command, it will be used for automatic bisection.
983 The environment variable HG_NODE will contain the ID of the
982 The environment variable HG_NODE will contain the ID of the
984 changeset being tested. The exit status of the command will be
983 changeset being tested. The exit status of the command will be
985 used to mark revisions as good or bad: status 0 means good, 125
984 used to mark revisions as good or bad: status 0 means good, 125
986 means to skip the revision, 127 (command not found) will abort the
985 means to skip the revision, 127 (command not found) will abort the
987 bisection, and any other non-zero exit status means the revision
986 bisection, and any other non-zero exit status means the revision
988 is bad.
987 is bad.
989
988
990 .. container:: verbose
989 .. container:: verbose
991
990
992 Some examples:
991 Some examples:
993
992
994 - start a bisection with known bad revision 34, and good revision 12::
993 - start a bisection with known bad revision 34, and good revision 12::
995
994
996 hg bisect --bad 34
995 hg bisect --bad 34
997 hg bisect --good 12
996 hg bisect --good 12
998
997
999 - advance the current bisection by marking current revision as good or
998 - advance the current bisection by marking current revision as good or
1000 bad::
999 bad::
1001
1000
1002 hg bisect --good
1001 hg bisect --good
1003 hg bisect --bad
1002 hg bisect --bad
1004
1003
1005 - mark the current revision, or a known revision, to be skipped (e.g. if
1004 - mark the current revision, or a known revision, to be skipped (e.g. if
1006 that revision is not usable because of another issue)::
1005 that revision is not usable because of another issue)::
1007
1006
1008 hg bisect --skip
1007 hg bisect --skip
1009 hg bisect --skip 23
1008 hg bisect --skip 23
1010
1009
1011 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1010 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1012
1011
1013 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1012 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1014
1013
1015 - forget the current bisection::
1014 - forget the current bisection::
1016
1015
1017 hg bisect --reset
1016 hg bisect --reset
1018
1017
1019 - use 'make && make tests' to automatically find the first broken
1018 - use 'make && make tests' to automatically find the first broken
1020 revision::
1019 revision::
1021
1020
1022 hg bisect --reset
1021 hg bisect --reset
1023 hg bisect --bad 34
1022 hg bisect --bad 34
1024 hg bisect --good 12
1023 hg bisect --good 12
1025 hg bisect --command "make && make tests"
1024 hg bisect --command "make && make tests"
1026
1025
1027 - see all changesets whose states are already known in the current
1026 - see all changesets whose states are already known in the current
1028 bisection::
1027 bisection::
1029
1028
1030 hg log -r "bisect(pruned)"
1029 hg log -r "bisect(pruned)"
1031
1030
1032 - see the changeset currently being bisected (especially useful
1031 - see the changeset currently being bisected (especially useful
1033 if running with -U/--noupdate)::
1032 if running with -U/--noupdate)::
1034
1033
1035 hg log -r "bisect(current)"
1034 hg log -r "bisect(current)"
1036
1035
1037 - see all changesets that took part in the current bisection::
1036 - see all changesets that took part in the current bisection::
1038
1037
1039 hg log -r "bisect(range)"
1038 hg log -r "bisect(range)"
1040
1039
1041 - you can even get a nice graph::
1040 - you can even get a nice graph::
1042
1041
1043 hg log --graph -r "bisect(range)"
1042 hg log --graph -r "bisect(range)"
1044
1043
1045 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1044 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1046
1045
1047 Returns 0 on success.
1046 Returns 0 on success.
1048 """
1047 """
1049 rev = []
1048 rev = []
1050 # backward compatibility
1049 # backward compatibility
1051 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1050 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1052 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1051 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1053 cmd = positional_1
1052 cmd = positional_1
1054 rev.append(positional_2)
1053 rev.append(positional_2)
1055 if cmd == b"good":
1054 if cmd == b"good":
1056 good = True
1055 good = True
1057 elif cmd == b"bad":
1056 elif cmd == b"bad":
1058 bad = True
1057 bad = True
1059 else:
1058 else:
1060 reset = True
1059 reset = True
1061 elif positional_2:
1060 elif positional_2:
1062 raise error.InputError(_(b'incompatible arguments'))
1061 raise error.InputError(_(b'incompatible arguments'))
1063 elif positional_1 is not None:
1062 elif positional_1 is not None:
1064 rev.append(positional_1)
1063 rev.append(positional_1)
1065
1064
1066 incompatibles = {
1065 incompatibles = {
1067 b'--bad': bad,
1066 b'--bad': bad,
1068 b'--command': bool(command),
1067 b'--command': bool(command),
1069 b'--extend': extend,
1068 b'--extend': extend,
1070 b'--good': good,
1069 b'--good': good,
1071 b'--reset': reset,
1070 b'--reset': reset,
1072 b'--skip': skip,
1071 b'--skip': skip,
1073 }
1072 }
1074
1073
1075 enabled = [x for x in incompatibles if incompatibles[x]]
1074 enabled = [x for x in incompatibles if incompatibles[x]]
1076
1075
1077 if len(enabled) > 1:
1076 if len(enabled) > 1:
1078 raise error.InputError(
1077 raise error.InputError(
1079 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1078 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1080 )
1079 )
1081
1080
1082 if reset:
1081 if reset:
1083 hbisect.resetstate(repo)
1082 hbisect.resetstate(repo)
1084 return
1083 return
1085
1084
1086 state = hbisect.load_state(repo)
1085 state = hbisect.load_state(repo)
1087
1086
1088 if rev:
1087 if rev:
1089 revs = logcmdutil.revrange(repo, rev)
1088 revs = logcmdutil.revrange(repo, rev)
1090 goodnodes = state[b'good']
1089 goodnodes = state[b'good']
1091 badnodes = state[b'bad']
1090 badnodes = state[b'bad']
1092 if goodnodes and badnodes:
1091 if goodnodes and badnodes:
1093 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1092 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1094 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1093 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1095 revs = candidates & revs
1094 revs = candidates & revs
1096 nodes = [repo.changelog.node(i) for i in revs]
1095 nodes = [repo.changelog.node(i) for i in revs]
1097 else:
1096 else:
1098 nodes = [repo.lookup(b'.')]
1097 nodes = [repo.lookup(b'.')]
1099
1098
1100 # update state
1099 # update state
1101 if good or bad or skip:
1100 if good or bad or skip:
1102 if good:
1101 if good:
1103 state[b'good'] += nodes
1102 state[b'good'] += nodes
1104 elif bad:
1103 elif bad:
1105 state[b'bad'] += nodes
1104 state[b'bad'] += nodes
1106 elif skip:
1105 elif skip:
1107 state[b'skip'] += nodes
1106 state[b'skip'] += nodes
1108 hbisect.save_state(repo, state)
1107 hbisect.save_state(repo, state)
1109 if not (state[b'good'] and state[b'bad']):
1108 if not (state[b'good'] and state[b'bad']):
1110 return
1109 return
1111
1110
1112 def mayupdate(repo, node, show_stats=True):
1111 def mayupdate(repo, node, show_stats=True):
1113 """common used update sequence"""
1112 """common used update sequence"""
1114 if noupdate:
1113 if noupdate:
1115 return
1114 return
1116 cmdutil.checkunfinished(repo)
1115 cmdutil.checkunfinished(repo)
1117 cmdutil.bailifchanged(repo)
1116 cmdutil.bailifchanged(repo)
1118 return hg.clean(repo, node, show_stats=show_stats)
1117 return hg.clean(repo, node, show_stats=show_stats)
1119
1118
1120 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1119 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1121
1120
1122 if command:
1121 if command:
1123 changesets = 1
1122 changesets = 1
1124 if noupdate:
1123 if noupdate:
1125 try:
1124 try:
1126 node = state[b'current'][0]
1125 node = state[b'current'][0]
1127 except LookupError:
1126 except LookupError:
1128 raise error.StateError(
1127 raise error.StateError(
1129 _(
1128 _(
1130 b'current bisect revision is unknown - '
1129 b'current bisect revision is unknown - '
1131 b'start a new bisect to fix'
1130 b'start a new bisect to fix'
1132 )
1131 )
1133 )
1132 )
1134 else:
1133 else:
1135 node, p2 = repo.dirstate.parents()
1134 node, p2 = repo.dirstate.parents()
1136 if p2 != repo.nullid:
1135 if p2 != repo.nullid:
1137 raise error.StateError(_(b'current bisect revision is a merge'))
1136 raise error.StateError(_(b'current bisect revision is a merge'))
1138 if rev:
1137 if rev:
1139 if not nodes:
1138 if not nodes:
1140 raise error.InputError(_(b'empty revision set'))
1139 raise error.InputError(_(b'empty revision set'))
1141 node = repo[nodes[-1]].node()
1140 node = repo[nodes[-1]].node()
1142 with hbisect.restore_state(repo, state, node):
1141 with hbisect.restore_state(repo, state, node):
1143 while changesets:
1142 while changesets:
1144 # update state
1143 # update state
1145 state[b'current'] = [node]
1144 state[b'current'] = [node]
1146 hbisect.save_state(repo, state)
1145 hbisect.save_state(repo, state)
1147 status = ui.system(
1146 status = ui.system(
1148 command,
1147 command,
1149 environ={b'HG_NODE': hex(node)},
1148 environ={b'HG_NODE': hex(node)},
1150 blockedtag=b'bisect_check',
1149 blockedtag=b'bisect_check',
1151 )
1150 )
1152 if status == 125:
1151 if status == 125:
1153 transition = b"skip"
1152 transition = b"skip"
1154 elif status == 0:
1153 elif status == 0:
1155 transition = b"good"
1154 transition = b"good"
1156 # status < 0 means process was killed
1155 # status < 0 means process was killed
1157 elif status == 127:
1156 elif status == 127:
1158 raise error.Abort(_(b"failed to execute %s") % command)
1157 raise error.Abort(_(b"failed to execute %s") % command)
1159 elif status < 0:
1158 elif status < 0:
1160 raise error.Abort(_(b"%s killed") % command)
1159 raise error.Abort(_(b"%s killed") % command)
1161 else:
1160 else:
1162 transition = b"bad"
1161 transition = b"bad"
1163 state[transition].append(node)
1162 state[transition].append(node)
1164 ctx = repo[node]
1163 ctx = repo[node]
1165 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1164 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1166 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1165 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1167 hbisect.checkstate(state)
1166 hbisect.checkstate(state)
1168 # bisect
1167 # bisect
1169 nodes, changesets, bgood = hbisect.bisect(repo, state)
1168 nodes, changesets, bgood = hbisect.bisect(repo, state)
1170 # update to next check
1169 # update to next check
1171 node = nodes[0]
1170 node = nodes[0]
1172 mayupdate(repo, node, show_stats=False)
1171 mayupdate(repo, node, show_stats=False)
1173 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1172 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1174 return
1173 return
1175
1174
1176 hbisect.checkstate(state)
1175 hbisect.checkstate(state)
1177
1176
1178 # actually bisect
1177 # actually bisect
1179 nodes, changesets, good = hbisect.bisect(repo, state)
1178 nodes, changesets, good = hbisect.bisect(repo, state)
1180 if extend:
1179 if extend:
1181 if not changesets:
1180 if not changesets:
1182 extendctx = hbisect.extendrange(repo, state, nodes, good)
1181 extendctx = hbisect.extendrange(repo, state, nodes, good)
1183 if extendctx is not None:
1182 if extendctx is not None:
1184 ui.write(
1183 ui.write(
1185 _(b"Extending search to changeset %s\n")
1184 _(b"Extending search to changeset %s\n")
1186 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1185 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1187 )
1186 )
1188 state[b'current'] = [extendctx.node()]
1187 state[b'current'] = [extendctx.node()]
1189 hbisect.save_state(repo, state)
1188 hbisect.save_state(repo, state)
1190 return mayupdate(repo, extendctx.node())
1189 return mayupdate(repo, extendctx.node())
1191 raise error.StateError(_(b"nothing to extend"))
1190 raise error.StateError(_(b"nothing to extend"))
1192
1191
1193 if changesets == 0:
1192 if changesets == 0:
1194 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1193 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1195 else:
1194 else:
1196 assert len(nodes) == 1 # only a single node can be tested next
1195 assert len(nodes) == 1 # only a single node can be tested next
1197 node = nodes[0]
1196 node = nodes[0]
1198 # compute the approximate number of remaining tests
1197 # compute the approximate number of remaining tests
1199 tests, size = 0, 2
1198 tests, size = 0, 2
1200 while size <= changesets:
1199 while size <= changesets:
1201 tests, size = tests + 1, size * 2
1200 tests, size = tests + 1, size * 2
1202 rev = repo.changelog.rev(node)
1201 rev = repo.changelog.rev(node)
1203 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1202 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1204 ui.write(
1203 ui.write(
1205 _(
1204 _(
1206 b"Testing changeset %s "
1205 b"Testing changeset %s "
1207 b"(%d changesets remaining, ~%d tests)\n"
1206 b"(%d changesets remaining, ~%d tests)\n"
1208 )
1207 )
1209 % (summary, changesets, tests)
1208 % (summary, changesets, tests)
1210 )
1209 )
1211 state[b'current'] = [node]
1210 state[b'current'] = [node]
1212 hbisect.save_state(repo, state)
1211 hbisect.save_state(repo, state)
1213 return mayupdate(repo, node)
1212 return mayupdate(repo, node)
1214
1213
1215
1214
1216 @command(
1215 @command(
1217 b'bookmarks|bookmark',
1216 b'bookmarks|bookmark',
1218 [
1217 [
1219 (b'f', b'force', False, _(b'force')),
1218 (b'f', b'force', False, _(b'force')),
1220 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1219 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1221 (b'd', b'delete', False, _(b'delete a given bookmark')),
1220 (b'd', b'delete', False, _(b'delete a given bookmark')),
1222 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1221 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1223 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1222 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1224 (b'l', b'list', False, _(b'list existing bookmarks')),
1223 (b'l', b'list', False, _(b'list existing bookmarks')),
1225 ]
1224 ]
1226 + formatteropts,
1225 + formatteropts,
1227 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1226 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1228 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1227 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1229 )
1228 )
1230 def bookmark(ui, repo, *names, **opts):
1229 def bookmark(ui, repo, *names, **opts):
1231 """create a new bookmark or list existing bookmarks
1230 """create a new bookmark or list existing bookmarks
1232
1231
1233 Bookmarks are labels on changesets to help track lines of development.
1232 Bookmarks are labels on changesets to help track lines of development.
1234 Bookmarks are unversioned and can be moved, renamed and deleted.
1233 Bookmarks are unversioned and can be moved, renamed and deleted.
1235 Deleting or moving a bookmark has no effect on the associated changesets.
1234 Deleting or moving a bookmark has no effect on the associated changesets.
1236
1235
1237 Creating or updating to a bookmark causes it to be marked as 'active'.
1236 Creating or updating to a bookmark causes it to be marked as 'active'.
1238 The active bookmark is indicated with a '*'.
1237 The active bookmark is indicated with a '*'.
1239 When a commit is made, the active bookmark will advance to the new commit.
1238 When a commit is made, the active bookmark will advance to the new commit.
1240 A plain :hg:`update` will also advance an active bookmark, if possible.
1239 A plain :hg:`update` will also advance an active bookmark, if possible.
1241 Updating away from a bookmark will cause it to be deactivated.
1240 Updating away from a bookmark will cause it to be deactivated.
1242
1241
1243 Bookmarks can be pushed and pulled between repositories (see
1242 Bookmarks can be pushed and pulled between repositories (see
1244 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1243 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1245 diverged, a new 'divergent bookmark' of the form 'name@path' will
1244 diverged, a new 'divergent bookmark' of the form 'name@path' will
1246 be created. Using :hg:`merge` will resolve the divergence.
1245 be created. Using :hg:`merge` will resolve the divergence.
1247
1246
1248 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1247 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1249 the active bookmark's name.
1248 the active bookmark's name.
1250
1249
1251 A bookmark named '@' has the special property that :hg:`clone` will
1250 A bookmark named '@' has the special property that :hg:`clone` will
1252 check it out by default if it exists.
1251 check it out by default if it exists.
1253
1252
1254 .. container:: verbose
1253 .. container:: verbose
1255
1254
1256 Template:
1255 Template:
1257
1256
1258 The following keywords are supported in addition to the common template
1257 The following keywords are supported in addition to the common template
1259 keywords and functions such as ``{bookmark}``. See also
1258 keywords and functions such as ``{bookmark}``. See also
1260 :hg:`help templates`.
1259 :hg:`help templates`.
1261
1260
1262 :active: Boolean. True if the bookmark is active.
1261 :active: Boolean. True if the bookmark is active.
1263
1262
1264 Examples:
1263 Examples:
1265
1264
1266 - create an active bookmark for a new line of development::
1265 - create an active bookmark for a new line of development::
1267
1266
1268 hg book new-feature
1267 hg book new-feature
1269
1268
1270 - create an inactive bookmark as a place marker::
1269 - create an inactive bookmark as a place marker::
1271
1270
1272 hg book -i reviewed
1271 hg book -i reviewed
1273
1272
1274 - create an inactive bookmark on another changeset::
1273 - create an inactive bookmark on another changeset::
1275
1274
1276 hg book -r .^ tested
1275 hg book -r .^ tested
1277
1276
1278 - rename bookmark turkey to dinner::
1277 - rename bookmark turkey to dinner::
1279
1278
1280 hg book -m turkey dinner
1279 hg book -m turkey dinner
1281
1280
1282 - move the '@' bookmark from another branch::
1281 - move the '@' bookmark from another branch::
1283
1282
1284 hg book -f @
1283 hg book -f @
1285
1284
1286 - print only the active bookmark name::
1285 - print only the active bookmark name::
1287
1286
1288 hg book -ql .
1287 hg book -ql .
1289 """
1288 """
1290 force = opts.get('force')
1289 force = opts.get('force')
1291 rev = opts.get('rev')
1290 rev = opts.get('rev')
1292 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1291 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1293
1292
1294 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1293 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1295 if action:
1294 if action:
1296 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1295 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1297 elif names or rev:
1296 elif names or rev:
1298 action = 'add'
1297 action = 'add'
1299 elif inactive:
1298 elif inactive:
1300 action = 'inactive' # meaning deactivate
1299 action = 'inactive' # meaning deactivate
1301 else:
1300 else:
1302 action = 'list'
1301 action = 'list'
1303
1302
1304 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1303 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1305 if not names and action in {'add', 'delete'}:
1304 if not names and action in {'add', 'delete'}:
1306 raise error.InputError(_(b"bookmark name required"))
1305 raise error.InputError(_(b"bookmark name required"))
1307
1306
1308 if action in {'add', 'delete', 'rename', 'inactive'}:
1307 if action in {'add', 'delete', 'rename', 'inactive'}:
1309 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1308 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1310 if action == 'delete':
1309 if action == 'delete':
1311 names = pycompat.maplist(repo._bookmarks.expandname, names)
1310 names = pycompat.maplist(repo._bookmarks.expandname, names)
1312 bookmarks.delete(repo, tr, names)
1311 bookmarks.delete(repo, tr, names)
1313 elif action == 'rename':
1312 elif action == 'rename':
1314 if not names:
1313 if not names:
1315 raise error.InputError(_(b"new bookmark name required"))
1314 raise error.InputError(_(b"new bookmark name required"))
1316 elif len(names) > 1:
1315 elif len(names) > 1:
1317 raise error.InputError(
1316 raise error.InputError(
1318 _(b"only one new bookmark name allowed")
1317 _(b"only one new bookmark name allowed")
1319 )
1318 )
1320 oldname = repo._bookmarks.expandname(opts['rename'])
1319 oldname = repo._bookmarks.expandname(opts['rename'])
1321 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1320 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1322 elif action == 'add':
1321 elif action == 'add':
1323 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1322 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1324 elif action == 'inactive':
1323 elif action == 'inactive':
1325 if len(repo._bookmarks) == 0:
1324 if len(repo._bookmarks) == 0:
1326 ui.status(_(b"no bookmarks set\n"))
1325 ui.status(_(b"no bookmarks set\n"))
1327 elif not repo._activebookmark:
1326 elif not repo._activebookmark:
1328 ui.status(_(b"no active bookmark\n"))
1327 ui.status(_(b"no active bookmark\n"))
1329 else:
1328 else:
1330 bookmarks.deactivate(repo)
1329 bookmarks.deactivate(repo)
1331 elif action == 'list':
1330 elif action == 'list':
1332 names = pycompat.maplist(repo._bookmarks.expandname, names)
1331 names = pycompat.maplist(repo._bookmarks.expandname, names)
1333 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1332 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1334 bookmarks.printbookmarks(ui, repo, fm, names)
1333 bookmarks.printbookmarks(ui, repo, fm, names)
1335 else:
1334 else:
1336 raise error.ProgrammingError(
1335 raise error.ProgrammingError(
1337 b'invalid action: %s' % pycompat.sysbytes(action)
1336 b'invalid action: %s' % pycompat.sysbytes(action)
1338 )
1337 )
1339
1338
1340
1339
1341 @command(
1340 @command(
1342 b'branch',
1341 b'branch',
1343 [
1342 [
1344 (
1343 (
1345 b'f',
1344 b'f',
1346 b'force',
1345 b'force',
1347 None,
1346 None,
1348 _(b'set branch name even if it shadows an existing branch'),
1347 _(b'set branch name even if it shadows an existing branch'),
1349 ),
1348 ),
1350 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1349 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1351 (
1350 (
1352 b'r',
1351 b'r',
1353 b'rev',
1352 b'rev',
1354 [],
1353 [],
1355 _(b'change branches of the given revs (EXPERIMENTAL)'),
1354 _(b'change branches of the given revs (EXPERIMENTAL)'),
1356 ),
1355 ),
1357 ],
1356 ],
1358 _(b'[-fC] [NAME]'),
1357 _(b'[-fC] [NAME]'),
1359 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1358 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1360 )
1359 )
1361 def branch(ui, repo, label=None, **opts):
1360 def branch(ui, repo, label=None, **opts):
1362 """set or show the current branch name
1361 """set or show the current branch name
1363
1362
1364 .. note::
1363 .. note::
1365
1364
1366 Branch names are permanent and global. Use :hg:`bookmark` to create a
1365 Branch names are permanent and global. Use :hg:`bookmark` to create a
1367 light-weight bookmark instead. See :hg:`help glossary` for more
1366 light-weight bookmark instead. See :hg:`help glossary` for more
1368 information about named branches and bookmarks.
1367 information about named branches and bookmarks.
1369
1368
1370 With no argument, show the current branch name. With one argument,
1369 With no argument, show the current branch name. With one argument,
1371 set the working directory branch name (the branch will not exist
1370 set the working directory branch name (the branch will not exist
1372 in the repository until the next commit). Standard practice
1371 in the repository until the next commit). Standard practice
1373 recommends that primary development take place on the 'default'
1372 recommends that primary development take place on the 'default'
1374 branch.
1373 branch.
1375
1374
1376 Unless -f/--force is specified, branch will not let you set a
1375 Unless -f/--force is specified, branch will not let you set a
1377 branch name that already exists.
1376 branch name that already exists.
1378
1377
1379 Use -C/--clean to reset the working directory branch to that of
1378 Use -C/--clean to reset the working directory branch to that of
1380 the parent of the working directory, negating a previous branch
1379 the parent of the working directory, negating a previous branch
1381 change.
1380 change.
1382
1381
1383 Use the command :hg:`update` to switch to an existing branch. Use
1382 Use the command :hg:`update` to switch to an existing branch. Use
1384 :hg:`commit --close-branch` to mark this branch head as closed.
1383 :hg:`commit --close-branch` to mark this branch head as closed.
1385 When all heads of a branch are closed, the branch will be
1384 When all heads of a branch are closed, the branch will be
1386 considered closed.
1385 considered closed.
1387
1386
1388 Returns 0 on success.
1387 Returns 0 on success.
1389 """
1388 """
1390 revs = opts.get('rev')
1389 revs = opts.get('rev')
1391 if label:
1390 if label:
1392 label = label.strip()
1391 label = label.strip()
1393
1392
1394 if not opts.get('clean') and not label:
1393 if not opts.get('clean') and not label:
1395 if revs:
1394 if revs:
1396 raise error.InputError(
1395 raise error.InputError(
1397 _(b"no branch name specified for the revisions")
1396 _(b"no branch name specified for the revisions")
1398 )
1397 )
1399 ui.write(b"%s\n" % repo.dirstate.branch())
1398 ui.write(b"%s\n" % repo.dirstate.branch())
1400 return
1399 return
1401
1400
1402 with repo.wlock():
1401 with repo.wlock():
1403 if opts.get('clean'):
1402 if opts.get('clean'):
1404 label = repo[b'.'].branch()
1403 label = repo[b'.'].branch()
1405 repo.dirstate.setbranch(label, repo.currenttransaction())
1404 repo.dirstate.setbranch(label, repo.currenttransaction())
1406 ui.status(_(b'reset working directory to branch %s\n') % label)
1405 ui.status(_(b'reset working directory to branch %s\n') % label)
1407 elif label:
1406 elif label:
1408 scmutil.checknewlabel(repo, label, b'branch')
1407 scmutil.checknewlabel(repo, label, b'branch')
1409 if revs:
1408 if revs:
1410 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1409 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1411
1410
1412 if not opts.get('force') and label in repo.branchmap():
1411 if not opts.get('force') and label in repo.branchmap():
1413 if label not in [p.branch() for p in repo[None].parents()]:
1412 if label not in [p.branch() for p in repo[None].parents()]:
1414 raise error.InputError(
1413 raise error.InputError(
1415 _(b'a branch of the same name already exists'),
1414 _(b'a branch of the same name already exists'),
1416 # i18n: "it" refers to an existing branch
1415 # i18n: "it" refers to an existing branch
1417 hint=_(b"use 'hg update' to switch to it"),
1416 hint=_(b"use 'hg update' to switch to it"),
1418 )
1417 )
1419
1418
1420 repo.dirstate.setbranch(label, repo.currenttransaction())
1419 repo.dirstate.setbranch(label, repo.currenttransaction())
1421 ui.status(_(b'marked working directory as branch %s\n') % label)
1420 ui.status(_(b'marked working directory as branch %s\n') % label)
1422
1421
1423 # find any open named branches aside from default
1422 # find any open named branches aside from default
1424 for n, h, t, c in repo.branchmap().iterbranches():
1423 for n, h, t, c in repo.branchmap().iterbranches():
1425 if n != b"default" and not c:
1424 if n != b"default" and not c:
1426 return 0
1425 return 0
1427 ui.status(
1426 ui.status(
1428 _(
1427 _(
1429 b'(branches are permanent and global, '
1428 b'(branches are permanent and global, '
1430 b'did you want a bookmark?)\n'
1429 b'did you want a bookmark?)\n'
1431 )
1430 )
1432 )
1431 )
1433
1432
1434
1433
1435 @command(
1434 @command(
1436 b'branches',
1435 b'branches',
1437 [
1436 [
1438 (
1437 (
1439 b'a',
1438 b'a',
1440 b'active',
1439 b'active',
1441 False,
1440 False,
1442 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1441 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1443 ),
1442 ),
1444 (b'c', b'closed', False, _(b'show normal and closed branches')),
1443 (b'c', b'closed', False, _(b'show normal and closed branches')),
1445 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1444 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1446 ]
1445 ]
1447 + formatteropts,
1446 + formatteropts,
1448 _(b'[-c]'),
1447 _(b'[-c]'),
1449 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1448 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1450 intents={INTENT_READONLY},
1449 intents={INTENT_READONLY},
1451 )
1450 )
1452 def branches(ui, repo, active=False, closed=False, **opts):
1451 def branches(ui, repo, active=False, closed=False, **opts):
1453 """list repository named branches
1452 """list repository named branches
1454
1453
1455 List the repository's named branches, indicating which ones are
1454 List the repository's named branches, indicating which ones are
1456 inactive. If -c/--closed is specified, also list branches which have
1455 inactive. If -c/--closed is specified, also list branches which have
1457 been marked closed (see :hg:`commit --close-branch`).
1456 been marked closed (see :hg:`commit --close-branch`).
1458
1457
1459 Use the command :hg:`update` to switch to an existing branch.
1458 Use the command :hg:`update` to switch to an existing branch.
1460
1459
1461 .. container:: verbose
1460 .. container:: verbose
1462
1461
1463 Template:
1462 Template:
1464
1463
1465 The following keywords are supported in addition to the common template
1464 The following keywords are supported in addition to the common template
1466 keywords and functions such as ``{branch}``. See also
1465 keywords and functions such as ``{branch}``. See also
1467 :hg:`help templates`.
1466 :hg:`help templates`.
1468
1467
1469 :active: Boolean. True if the branch is active.
1468 :active: Boolean. True if the branch is active.
1470 :closed: Boolean. True if the branch is closed.
1469 :closed: Boolean. True if the branch is closed.
1471 :current: Boolean. True if it is the current branch.
1470 :current: Boolean. True if it is the current branch.
1472
1471
1473 Returns 0.
1472 Returns 0.
1474 """
1473 """
1475
1474
1476 revs = opts.get('rev')
1475 revs = opts.get('rev')
1477 selectedbranches = None
1476 selectedbranches = None
1478 if revs:
1477 if revs:
1479 revs = logcmdutil.revrange(repo, revs)
1478 revs = logcmdutil.revrange(repo, revs)
1480 getbi = repo.revbranchcache().branchinfo
1479 getbi = repo.revbranchcache().branchinfo
1481 selectedbranches = {getbi(r)[0] for r in revs}
1480 selectedbranches = {getbi(r)[0] for r in revs}
1482
1481
1483 ui.pager(b'branches')
1482 ui.pager(b'branches')
1484 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1483 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1485 hexfunc = fm.hexfunc
1484 hexfunc = fm.hexfunc
1486
1485
1487 allheads = set(repo.heads())
1486 allheads = set(repo.heads())
1488 branches = []
1487 branches = []
1489 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1488 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1490 if selectedbranches is not None and tag not in selectedbranches:
1489 if selectedbranches is not None and tag not in selectedbranches:
1491 continue
1490 continue
1492 isactive = False
1491 isactive = False
1493 if not isclosed:
1492 if not isclosed:
1494 openheads = set(repo.branchmap().iteropen(heads))
1493 openheads = set(repo.branchmap().iteropen(heads))
1495 isactive = bool(openheads & allheads)
1494 isactive = bool(openheads & allheads)
1496 branches.append((tag, repo[tip], isactive, not isclosed))
1495 branches.append((tag, repo[tip], isactive, not isclosed))
1497 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1496 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1498
1497
1499 for tag, ctx, isactive, isopen in branches:
1498 for tag, ctx, isactive, isopen in branches:
1500 if active and not isactive:
1499 if active and not isactive:
1501 continue
1500 continue
1502 if isactive:
1501 if isactive:
1503 label = b'branches.active'
1502 label = b'branches.active'
1504 notice = b''
1503 notice = b''
1505 elif not isopen:
1504 elif not isopen:
1506 if not closed:
1505 if not closed:
1507 continue
1506 continue
1508 label = b'branches.closed'
1507 label = b'branches.closed'
1509 notice = _(b' (closed)')
1508 notice = _(b' (closed)')
1510 else:
1509 else:
1511 label = b'branches.inactive'
1510 label = b'branches.inactive'
1512 notice = _(b' (inactive)')
1511 notice = _(b' (inactive)')
1513 current = tag == repo.dirstate.branch()
1512 current = tag == repo.dirstate.branch()
1514 if current:
1513 if current:
1515 label = b'branches.current'
1514 label = b'branches.current'
1516
1515
1517 fm.startitem()
1516 fm.startitem()
1518 fm.write(b'branch', b'%s', tag, label=label)
1517 fm.write(b'branch', b'%s', tag, label=label)
1519 rev = ctx.rev()
1518 rev = ctx.rev()
1520 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1519 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1521 fmt = b' ' * padsize + b' %d:%s'
1520 fmt = b' ' * padsize + b' %d:%s'
1522 fm.condwrite(
1521 fm.condwrite(
1523 not ui.quiet,
1522 not ui.quiet,
1524 b'rev node',
1523 b'rev node',
1525 fmt,
1524 fmt,
1526 rev,
1525 rev,
1527 hexfunc(ctx.node()),
1526 hexfunc(ctx.node()),
1528 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1527 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1529 )
1528 )
1530 fm.context(ctx=ctx)
1529 fm.context(ctx=ctx)
1531 fm.data(active=isactive, closed=not isopen, current=current)
1530 fm.data(active=isactive, closed=not isopen, current=current)
1532 if not ui.quiet:
1531 if not ui.quiet:
1533 fm.plain(notice)
1532 fm.plain(notice)
1534 fm.plain(b'\n')
1533 fm.plain(b'\n')
1535 fm.end()
1534 fm.end()
1536
1535
1537
1536
1538 @command(
1537 @command(
1539 b'bundle',
1538 b'bundle',
1540 [
1539 [
1541 (
1540 (
1542 b'',
1541 b'',
1543 b'exact',
1542 b'exact',
1544 None,
1543 None,
1545 _(b'compute the base from the revision specified'),
1544 _(b'compute the base from the revision specified'),
1546 ),
1545 ),
1547 (
1546 (
1548 b'f',
1547 b'f',
1549 b'force',
1548 b'force',
1550 None,
1549 None,
1551 _(b'run even when the destination is unrelated'),
1550 _(b'run even when the destination is unrelated'),
1552 ),
1551 ),
1553 (
1552 (
1554 b'r',
1553 b'r',
1555 b'rev',
1554 b'rev',
1556 [],
1555 [],
1557 _(b'a changeset intended to be added to the destination'),
1556 _(b'a changeset intended to be added to the destination'),
1558 _(b'REV'),
1557 _(b'REV'),
1559 ),
1558 ),
1560 (
1559 (
1561 b'b',
1560 b'b',
1562 b'branch',
1561 b'branch',
1563 [],
1562 [],
1564 _(b'a specific branch you would like to bundle'),
1563 _(b'a specific branch you would like to bundle'),
1565 _(b'BRANCH'),
1564 _(b'BRANCH'),
1566 ),
1565 ),
1567 (
1566 (
1568 b'',
1567 b'',
1569 b'base',
1568 b'base',
1570 [],
1569 [],
1571 _(b'a base changeset assumed to be available at the destination'),
1570 _(b'a base changeset assumed to be available at the destination'),
1572 _(b'REV'),
1571 _(b'REV'),
1573 ),
1572 ),
1574 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1573 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1575 (
1574 (
1576 b't',
1575 b't',
1577 b'type',
1576 b'type',
1578 b'bzip2',
1577 b'bzip2',
1579 _(b'bundle compression type to use'),
1578 _(b'bundle compression type to use'),
1580 _(b'TYPE'),
1579 _(b'TYPE'),
1581 ),
1580 ),
1582 ]
1581 ]
1583 + remoteopts,
1582 + remoteopts,
1584 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1583 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1585 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1584 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1586 )
1585 )
1587 def bundle(ui, repo, fname, *dests, **opts):
1586 def bundle(ui, repo, fname, *dests, **opts):
1588 """create a bundle file
1587 """create a bundle file
1589
1588
1590 Generate a bundle file containing data to be transferred to another
1589 Generate a bundle file containing data to be transferred to another
1591 repository.
1590 repository.
1592
1591
1593 To create a bundle containing all changesets, use -a/--all
1592 To create a bundle containing all changesets, use -a/--all
1594 (or --base null). Otherwise, hg assumes the destination will have
1593 (or --base null). Otherwise, hg assumes the destination will have
1595 all the nodes you specify with --base parameters. Otherwise, hg
1594 all the nodes you specify with --base parameters. Otherwise, hg
1596 will assume the repository has all the nodes in destination, or
1595 will assume the repository has all the nodes in destination, or
1597 default-push/default if no destination is specified, where destination
1596 default-push/default if no destination is specified, where destination
1598 is the repositories you provide through DEST option.
1597 is the repositories you provide through DEST option.
1599
1598
1600 You can change bundle format with the -t/--type option. See
1599 You can change bundle format with the -t/--type option. See
1601 :hg:`help bundlespec` for documentation on this format. By default,
1600 :hg:`help bundlespec` for documentation on this format. By default,
1602 the most appropriate format is used and compression defaults to
1601 the most appropriate format is used and compression defaults to
1603 bzip2.
1602 bzip2.
1604
1603
1605 The bundle file can then be transferred using conventional means
1604 The bundle file can then be transferred using conventional means
1606 and applied to another repository with the unbundle or pull
1605 and applied to another repository with the unbundle or pull
1607 command. This is useful when direct push and pull are not
1606 command. This is useful when direct push and pull are not
1608 available or when exporting an entire repository is undesirable.
1607 available or when exporting an entire repository is undesirable.
1609
1608
1610 Applying bundles preserves all changeset contents including
1609 Applying bundles preserves all changeset contents including
1611 permissions, copy/rename information, and revision history.
1610 permissions, copy/rename information, and revision history.
1612
1611
1613 Returns 0 on success, 1 if no changes found.
1612 Returns 0 on success, 1 if no changes found.
1614 """
1613 """
1615
1614
1616 revs = None
1615 revs = None
1617 if 'rev' in opts:
1616 if 'rev' in opts:
1618 revstrings = opts['rev']
1617 revstrings = opts['rev']
1619 revs = logcmdutil.revrange(repo, revstrings)
1618 revs = logcmdutil.revrange(repo, revstrings)
1620 if revstrings and not revs:
1619 if revstrings and not revs:
1621 raise error.InputError(_(b'no commits to bundle'))
1620 raise error.InputError(_(b'no commits to bundle'))
1622
1621
1623 bundletype = opts.get('type', b'bzip2').lower()
1622 bundletype = opts.get('type', b'bzip2').lower()
1624 try:
1623 try:
1625 bundlespec = bundlecaches.parsebundlespec(
1624 bundlespec = bundlecaches.parsebundlespec(
1626 repo, bundletype, strict=False
1625 repo, bundletype, strict=False
1627 )
1626 )
1628 except error.UnsupportedBundleSpecification as e:
1627 except error.UnsupportedBundleSpecification as e:
1629 raise error.InputError(
1628 raise error.InputError(
1630 pycompat.bytestr(e),
1629 pycompat.bytestr(e),
1631 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1630 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1632 )
1631 )
1633
1632
1634 has_changegroup = bundlespec.params.get(b"changegroup", False)
1633 has_changegroup = bundlespec.params.get(b"changegroup", False)
1635 cgversion = bundlespec.params[b"cg.version"]
1634 cgversion = bundlespec.params[b"cg.version"]
1636
1635
1637 # Packed bundles are a pseudo bundle format for now.
1636 # Packed bundles are a pseudo bundle format for now.
1638 if cgversion == b's1':
1637 if cgversion == b's1':
1639 raise error.InputError(
1638 raise error.InputError(
1640 _(b'packed bundles cannot be produced by "hg bundle"'),
1639 _(b'packed bundles cannot be produced by "hg bundle"'),
1641 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1640 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1642 )
1641 )
1643 base_opt = opts.get('base')
1642 base_opt = opts.get('base')
1644 if opts.get('all'):
1643 if opts.get('all'):
1645 if dests:
1644 if dests:
1646 raise error.InputError(
1645 raise error.InputError(
1647 _(b"--all is incompatible with specifying destinations")
1646 _(b"--all is incompatible with specifying destinations")
1648 )
1647 )
1649 if base_opt:
1648 if base_opt:
1650 ui.warn(_(b"ignoring --base because --all was specified\n"))
1649 ui.warn(_(b"ignoring --base because --all was specified\n"))
1651 if opts.get('exact'):
1650 if opts.get('exact'):
1652 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1651 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1653 base = [nullrev]
1652 base = [nullrev]
1654 elif opts.get('exact'):
1653 elif opts.get('exact'):
1655 if dests:
1654 if dests:
1656 raise error.InputError(
1655 raise error.InputError(
1657 _(b"--exact is incompatible with specifying destinations")
1656 _(b"--exact is incompatible with specifying destinations")
1658 )
1657 )
1659 if base_opt:
1658 if base_opt:
1660 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1659 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1661 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1660 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1662 if not base:
1661 if not base:
1663 base = [nullrev]
1662 base = [nullrev]
1664 elif base_opt:
1663 elif base_opt:
1665 base = logcmdutil.revrange(repo, base_opt)
1664 base = logcmdutil.revrange(repo, base_opt)
1666 if not base:
1665 if not base:
1667 # base specified, but nothing was selected
1666 # base specified, but nothing was selected
1668 base = [nullrev]
1667 base = [nullrev]
1669 else:
1668 else:
1670 base = None
1669 base = None
1671 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1670 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1672 if has_changegroup and cgversion not in supported_cg_versions:
1671 if has_changegroup and cgversion not in supported_cg_versions:
1673 raise error.Abort(
1672 raise error.Abort(
1674 _(b"repository does not support bundle version %s") % cgversion
1673 _(b"repository does not support bundle version %s") % cgversion
1675 )
1674 )
1676
1675
1677 if base is not None:
1676 if base is not None:
1678 if dests:
1677 if dests:
1679 raise error.InputError(
1678 raise error.InputError(
1680 _(b"--base is incompatible with specifying destinations")
1679 _(b"--base is incompatible with specifying destinations")
1681 )
1680 )
1682 cl = repo.changelog
1681 cl = repo.changelog
1683 common = [cl.node(rev) for rev in base]
1682 common = [cl.node(rev) for rev in base]
1684 heads = [cl.node(r) for r in revs] if revs else None
1683 heads = [cl.node(r) for r in revs] if revs else None
1685 outgoing = discovery.outgoing(repo, common, heads)
1684 outgoing = discovery.outgoing(repo, common, heads)
1686 missing = outgoing.missing
1685 missing = outgoing.missing
1687 excluded = outgoing.excluded
1686 excluded = outgoing.excluded
1688 else:
1687 else:
1689 missing = set()
1688 missing = set()
1690 excluded = set()
1689 excluded = set()
1691 for path in urlutil.get_push_paths(repo, ui, dests):
1690 for path in urlutil.get_push_paths(repo, ui, dests):
1692 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1691 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1693 if revs is not None:
1692 if revs is not None:
1694 hex_revs = [repo[r].hex() for r in revs]
1693 hex_revs = [repo[r].hex() for r in revs]
1695 else:
1694 else:
1696 hex_revs = None
1695 hex_revs = None
1697 branches = (path.branch, [])
1696 branches = (path.branch, [])
1698 head_revs, checkout = hg.addbranchrevs(
1697 head_revs, checkout = hg.addbranchrevs(
1699 repo, repo, branches, hex_revs
1698 repo, repo, branches, hex_revs
1700 )
1699 )
1701 heads = (
1700 heads = (
1702 head_revs
1701 head_revs
1703 and pycompat.maplist(repo.lookup, head_revs)
1702 and pycompat.maplist(repo.lookup, head_revs)
1704 or head_revs
1703 or head_revs
1705 )
1704 )
1706 outgoing = discovery.findcommonoutgoing(
1705 outgoing = discovery.findcommonoutgoing(
1707 repo,
1706 repo,
1708 other,
1707 other,
1709 onlyheads=heads,
1708 onlyheads=heads,
1710 force=opts.get('force'),
1709 force=opts.get('force'),
1711 portable=True,
1710 portable=True,
1712 )
1711 )
1713 missing.update(outgoing.missing)
1712 missing.update(outgoing.missing)
1714 excluded.update(outgoing.excluded)
1713 excluded.update(outgoing.excluded)
1715
1714
1716 if not missing:
1715 if not missing:
1717 scmutil.nochangesfound(ui, repo, not base and excluded)
1716 scmutil.nochangesfound(ui, repo, not base and excluded)
1718 return 1
1717 return 1
1719
1718
1720 # internal changeset are internal implementation details that should not
1719 # internal changeset are internal implementation details that should not
1721 # leave the repository. Bundling with `hg bundle` create such risk.
1720 # leave the repository. Bundling with `hg bundle` create such risk.
1722 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1721 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1723 if bundled_internal:
1722 if bundled_internal:
1724 msg = _(b"cannot bundle internal changesets")
1723 msg = _(b"cannot bundle internal changesets")
1725 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1724 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1726 raise error.Abort(msg, hint=hint)
1725 raise error.Abort(msg, hint=hint)
1727
1726
1728 if heads:
1727 if heads:
1729 outgoing = discovery.outgoing(
1728 outgoing = discovery.outgoing(
1730 repo, missingroots=missing, ancestorsof=heads
1729 repo, missingroots=missing, ancestorsof=heads
1731 )
1730 )
1732 else:
1731 else:
1733 outgoing = discovery.outgoing(repo, missingroots=missing)
1732 outgoing = discovery.outgoing(repo, missingroots=missing)
1734 outgoing.excluded = sorted(excluded)
1733 outgoing.excluded = sorted(excluded)
1735
1734
1736 if cgversion == b'01': # bundle1
1735 if cgversion == b'01': # bundle1
1737 bversion = b'HG10' + bundlespec.wirecompression
1736 bversion = b'HG10' + bundlespec.wirecompression
1738 bcompression = None
1737 bcompression = None
1739 elif cgversion in (b'02', b'03'):
1738 elif cgversion in (b'02', b'03'):
1740 bversion = b'HG20'
1739 bversion = b'HG20'
1741 bcompression = bundlespec.wirecompression
1740 bcompression = bundlespec.wirecompression
1742 else:
1741 else:
1743 raise error.ProgrammingError(
1742 raise error.ProgrammingError(
1744 b'bundle: unexpected changegroup version %s' % cgversion
1743 b'bundle: unexpected changegroup version %s' % cgversion
1745 )
1744 )
1746
1745
1747 # TODO compression options should be derived from bundlespec parsing.
1746 # TODO compression options should be derived from bundlespec parsing.
1748 # This is a temporary hack to allow adjusting bundle compression
1747 # This is a temporary hack to allow adjusting bundle compression
1749 # level without a) formalizing the bundlespec changes to declare it
1748 # level without a) formalizing the bundlespec changes to declare it
1750 # b) introducing a command flag.
1749 # b) introducing a command flag.
1751 compopts = {}
1750 compopts = {}
1752 complevel = ui.configint(
1751 complevel = ui.configint(
1753 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1752 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1754 )
1753 )
1755 if complevel is None:
1754 if complevel is None:
1756 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1755 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1757 if complevel is not None:
1756 if complevel is not None:
1758 compopts[b'level'] = complevel
1757 compopts[b'level'] = complevel
1759
1758
1760 compthreads = ui.configint(
1759 compthreads = ui.configint(
1761 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1760 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1762 )
1761 )
1763 if compthreads is None:
1762 if compthreads is None:
1764 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1763 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1765 if compthreads is not None:
1764 if compthreads is not None:
1766 compopts[b'threads'] = compthreads
1765 compopts[b'threads'] = compthreads
1767
1766
1768 # Bundling of obsmarker and phases is optional as not all clients
1767 # Bundling of obsmarker and phases is optional as not all clients
1769 # support the necessary features.
1768 # support the necessary features.
1770 cfg = ui.configbool
1769 cfg = ui.configbool
1771 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1770 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1772 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1771 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1773 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1772 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1774 bundlespec.set_param(
1773 bundlespec.set_param(
1775 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1774 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1776 )
1775 )
1777 if not bundlespec.params.get(b'phases', False):
1776 if not bundlespec.params.get(b'phases', False):
1778 phases_cfg = cfg(b'experimental', b'bundle-phases')
1777 phases_cfg = cfg(b'experimental', b'bundle-phases')
1779 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1778 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1780
1779
1781 bundle2.writenewbundle(
1780 bundle2.writenewbundle(
1782 ui,
1781 ui,
1783 repo,
1782 repo,
1784 b'bundle',
1783 b'bundle',
1785 fname,
1784 fname,
1786 bversion,
1785 bversion,
1787 outgoing,
1786 outgoing,
1788 bundlespec.params,
1787 bundlespec.params,
1789 compression=bcompression,
1788 compression=bcompression,
1790 compopts=compopts,
1789 compopts=compopts,
1791 )
1790 )
1792
1791
1793
1792
1794 @command(
1793 @command(
1795 b'cat',
1794 b'cat',
1796 [
1795 [
1797 (
1796 (
1798 b'o',
1797 b'o',
1799 b'output',
1798 b'output',
1800 b'',
1799 b'',
1801 _(b'print output to file with formatted name'),
1800 _(b'print output to file with formatted name'),
1802 _(b'FORMAT'),
1801 _(b'FORMAT'),
1803 ),
1802 ),
1804 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1803 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1805 (b'', b'decode', None, _(b'apply any matching decode filter')),
1804 (b'', b'decode', None, _(b'apply any matching decode filter')),
1806 ]
1805 ]
1807 + walkopts
1806 + walkopts
1808 + formatteropts,
1807 + formatteropts,
1809 _(b'[OPTION]... FILE...'),
1808 _(b'[OPTION]... FILE...'),
1810 helpcategory=command.CATEGORY_FILE_CONTENTS,
1809 helpcategory=command.CATEGORY_FILE_CONTENTS,
1811 inferrepo=True,
1810 inferrepo=True,
1812 intents={INTENT_READONLY},
1811 intents={INTENT_READONLY},
1813 )
1812 )
1814 def cat(ui, repo, file1, *pats, **opts):
1813 def cat(ui, repo, file1, *pats, **opts):
1815 """output the current or given revision of files
1814 """output the current or given revision of files
1816
1815
1817 Print the specified files as they were at the given revision. If
1816 Print the specified files as they were at the given revision. If
1818 no revision is given, the parent of the working directory is used.
1817 no revision is given, the parent of the working directory is used.
1819
1818
1820 Output may be to a file, in which case the name of the file is
1819 Output may be to a file, in which case the name of the file is
1821 given using a template string. See :hg:`help templates`. In addition
1820 given using a template string. See :hg:`help templates`. In addition
1822 to the common template keywords, the following formatting rules are
1821 to the common template keywords, the following formatting rules are
1823 supported:
1822 supported:
1824
1823
1825 :``%%``: literal "%" character
1824 :``%%``: literal "%" character
1826 :``%s``: basename of file being printed
1825 :``%s``: basename of file being printed
1827 :``%d``: dirname of file being printed, or '.' if in repository root
1826 :``%d``: dirname of file being printed, or '.' if in repository root
1828 :``%p``: root-relative path name of file being printed
1827 :``%p``: root-relative path name of file being printed
1829 :``%H``: changeset hash (40 hexadecimal digits)
1828 :``%H``: changeset hash (40 hexadecimal digits)
1830 :``%R``: changeset revision number
1829 :``%R``: changeset revision number
1831 :``%h``: short-form changeset hash (12 hexadecimal digits)
1830 :``%h``: short-form changeset hash (12 hexadecimal digits)
1832 :``%r``: zero-padded changeset revision number
1831 :``%r``: zero-padded changeset revision number
1833 :``%b``: basename of the exporting repository
1832 :``%b``: basename of the exporting repository
1834 :``\\``: literal "\\" character
1833 :``\\``: literal "\\" character
1835
1834
1836 .. container:: verbose
1835 .. container:: verbose
1837
1836
1838 Template:
1837 Template:
1839
1838
1840 The following keywords are supported in addition to the common template
1839 The following keywords are supported in addition to the common template
1841 keywords and functions. See also :hg:`help templates`.
1840 keywords and functions. See also :hg:`help templates`.
1842
1841
1843 :data: String. File content.
1842 :data: String. File content.
1844 :path: String. Repository-absolute path of the file.
1843 :path: String. Repository-absolute path of the file.
1845
1844
1846 Returns 0 on success.
1845 Returns 0 on success.
1847 """
1846 """
1848 rev = opts.get('rev')
1847 rev = opts.get('rev')
1849 if rev:
1848 if rev:
1850 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1849 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1851 ctx = logcmdutil.revsingle(repo, rev)
1850 ctx = logcmdutil.revsingle(repo, rev)
1852 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1851 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1853 fntemplate = opts.pop('output', b'')
1852 fntemplate = opts.pop('output', b'')
1854 if cmdutil.isstdiofilename(fntemplate):
1853 if cmdutil.isstdiofilename(fntemplate):
1855 fntemplate = b''
1854 fntemplate = b''
1856
1855
1857 if fntemplate:
1856 if fntemplate:
1858 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1857 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1859 else:
1858 else:
1860 ui.pager(b'cat')
1859 ui.pager(b'cat')
1861 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1860 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1862 with fm:
1861 with fm:
1863 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1862 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1864
1863
1865
1864
1866 @command(
1865 @command(
1867 b'clone',
1866 b'clone',
1868 [
1867 [
1869 (
1868 (
1870 b'U',
1869 b'U',
1871 b'noupdate',
1870 b'noupdate',
1872 None,
1871 None,
1873 _(
1872 _(
1874 b'the clone will include an empty working '
1873 b'the clone will include an empty working '
1875 b'directory (only a repository)'
1874 b'directory (only a repository)'
1876 ),
1875 ),
1877 ),
1876 ),
1878 (
1877 (
1879 b'u',
1878 b'u',
1880 b'updaterev',
1879 b'updaterev',
1881 b'',
1880 b'',
1882 _(b'revision, tag, or branch to check out'),
1881 _(b'revision, tag, or branch to check out'),
1883 _(b'REV'),
1882 _(b'REV'),
1884 ),
1883 ),
1885 (
1884 (
1886 b'r',
1885 b'r',
1887 b'rev',
1886 b'rev',
1888 [],
1887 [],
1889 _(
1888 _(
1890 b'do not clone everything, but include this changeset'
1889 b'do not clone everything, but include this changeset'
1891 b' and its ancestors'
1890 b' and its ancestors'
1892 ),
1891 ),
1893 _(b'REV'),
1892 _(b'REV'),
1894 ),
1893 ),
1895 (
1894 (
1896 b'b',
1895 b'b',
1897 b'branch',
1896 b'branch',
1898 [],
1897 [],
1899 _(
1898 _(
1900 b'do not clone everything, but include this branch\'s'
1899 b'do not clone everything, but include this branch\'s'
1901 b' changesets and their ancestors'
1900 b' changesets and their ancestors'
1902 ),
1901 ),
1903 _(b'BRANCH'),
1902 _(b'BRANCH'),
1904 ),
1903 ),
1905 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1904 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1906 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1905 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1907 (b'', b'stream', None, _(b'clone with minimal data processing')),
1906 (b'', b'stream', None, _(b'clone with minimal data processing')),
1908 ]
1907 ]
1909 + remoteopts,
1908 + remoteopts,
1910 _(b'[OPTION]... SOURCE [DEST]'),
1909 _(b'[OPTION]... SOURCE [DEST]'),
1911 helpcategory=command.CATEGORY_REPO_CREATION,
1910 helpcategory=command.CATEGORY_REPO_CREATION,
1912 helpbasic=True,
1911 helpbasic=True,
1913 norepo=True,
1912 norepo=True,
1914 )
1913 )
1915 def clone(ui, source, dest=None, **opts):
1914 def clone(ui, source, dest=None, **opts):
1916 """make a copy of an existing repository
1915 """make a copy of an existing repository
1917
1916
1918 Create a copy of an existing repository in a new directory.
1917 Create a copy of an existing repository in a new directory.
1919
1918
1920 If no destination directory name is specified, it defaults to the
1919 If no destination directory name is specified, it defaults to the
1921 basename of the source.
1920 basename of the source.
1922
1921
1923 The location of the source is added to the new repository's
1922 The location of the source is added to the new repository's
1924 ``.hg/hgrc`` file, as the default to be used for future pulls.
1923 ``.hg/hgrc`` file, as the default to be used for future pulls.
1925
1924
1926 Only local paths and ``ssh://`` URLs are supported as
1925 Only local paths and ``ssh://`` URLs are supported as
1927 destinations. For ``ssh://`` destinations, no working directory or
1926 destinations. For ``ssh://`` destinations, no working directory or
1928 ``.hg/hgrc`` will be created on the remote side.
1927 ``.hg/hgrc`` will be created on the remote side.
1929
1928
1930 If the source repository has a bookmark called '@' set, that
1929 If the source repository has a bookmark called '@' set, that
1931 revision will be checked out in the new repository by default.
1930 revision will be checked out in the new repository by default.
1932
1931
1933 To check out a particular version, use -u/--update, or
1932 To check out a particular version, use -u/--update, or
1934 -U/--noupdate to create a clone with no working directory.
1933 -U/--noupdate to create a clone with no working directory.
1935
1934
1936 To pull only a subset of changesets, specify one or more revisions
1935 To pull only a subset of changesets, specify one or more revisions
1937 identifiers with -r/--rev or branches with -b/--branch. The
1936 identifiers with -r/--rev or branches with -b/--branch. The
1938 resulting clone will contain only the specified changesets and
1937 resulting clone will contain only the specified changesets and
1939 their ancestors. These options (or 'clone src#rev dest') imply
1938 their ancestors. These options (or 'clone src#rev dest') imply
1940 --pull, even for local source repositories.
1939 --pull, even for local source repositories.
1941
1940
1942 In normal clone mode, the remote normalizes repository data into a common
1941 In normal clone mode, the remote normalizes repository data into a common
1943 exchange format and the receiving end translates this data into its local
1942 exchange format and the receiving end translates this data into its local
1944 storage format. --stream activates a different clone mode that essentially
1943 storage format. --stream activates a different clone mode that essentially
1945 copies repository files from the remote with minimal data processing. This
1944 copies repository files from the remote with minimal data processing. This
1946 significantly reduces the CPU cost of a clone both remotely and locally.
1945 significantly reduces the CPU cost of a clone both remotely and locally.
1947 However, it often increases the transferred data size by 30-40%. This can
1946 However, it often increases the transferred data size by 30-40%. This can
1948 result in substantially faster clones where I/O throughput is plentiful,
1947 result in substantially faster clones where I/O throughput is plentiful,
1949 especially for larger repositories. A side-effect of --stream clones is
1948 especially for larger repositories. A side-effect of --stream clones is
1950 that storage settings and requirements on the remote are applied locally:
1949 that storage settings and requirements on the remote are applied locally:
1951 a modern client may inherit legacy or inefficient storage used by the
1950 a modern client may inherit legacy or inefficient storage used by the
1952 remote or a legacy Mercurial client may not be able to clone from a
1951 remote or a legacy Mercurial client may not be able to clone from a
1953 modern Mercurial remote.
1952 modern Mercurial remote.
1954
1953
1955 .. note::
1954 .. note::
1956
1955
1957 Specifying a tag will include the tagged changeset but not the
1956 Specifying a tag will include the tagged changeset but not the
1958 changeset containing the tag.
1957 changeset containing the tag.
1959
1958
1960 .. container:: verbose
1959 .. container:: verbose
1961
1960
1962 For efficiency, hardlinks are used for cloning whenever the
1961 For efficiency, hardlinks are used for cloning whenever the
1963 source and destination are on the same filesystem (note this
1962 source and destination are on the same filesystem (note this
1964 applies only to the repository data, not to the working
1963 applies only to the repository data, not to the working
1965 directory). Some filesystems, such as AFS, implement hardlinking
1964 directory). Some filesystems, such as AFS, implement hardlinking
1966 incorrectly, but do not report errors. In these cases, use the
1965 incorrectly, but do not report errors. In these cases, use the
1967 --pull option to avoid hardlinking.
1966 --pull option to avoid hardlinking.
1968
1967
1969 Mercurial will update the working directory to the first applicable
1968 Mercurial will update the working directory to the first applicable
1970 revision from this list:
1969 revision from this list:
1971
1970
1972 a) null if -U or the source repository has no changesets
1971 a) null if -U or the source repository has no changesets
1973 b) if -u . and the source repository is local, the first parent of
1972 b) if -u . and the source repository is local, the first parent of
1974 the source repository's working directory
1973 the source repository's working directory
1975 c) the changeset specified with -u (if a branch name, this means the
1974 c) the changeset specified with -u (if a branch name, this means the
1976 latest head of that branch)
1975 latest head of that branch)
1977 d) the changeset specified with -r
1976 d) the changeset specified with -r
1978 e) the tipmost head specified with -b
1977 e) the tipmost head specified with -b
1979 f) the tipmost head specified with the url#branch source syntax
1978 f) the tipmost head specified with the url#branch source syntax
1980 g) the revision marked with the '@' bookmark, if present
1979 g) the revision marked with the '@' bookmark, if present
1981 h) the tipmost head of the default branch
1980 h) the tipmost head of the default branch
1982 i) tip
1981 i) tip
1983
1982
1984 When cloning from servers that support it, Mercurial may fetch
1983 When cloning from servers that support it, Mercurial may fetch
1985 pre-generated data from a server-advertised URL or inline from the
1984 pre-generated data from a server-advertised URL or inline from the
1986 same stream. When this is done, hooks operating on incoming changesets
1985 same stream. When this is done, hooks operating on incoming changesets
1987 and changegroups may fire more than once, once for each pre-generated
1986 and changegroups may fire more than once, once for each pre-generated
1988 bundle and as well as for any additional remaining data. In addition,
1987 bundle and as well as for any additional remaining data. In addition,
1989 if an error occurs, the repository may be rolled back to a partial
1988 if an error occurs, the repository may be rolled back to a partial
1990 clone. This behavior may change in future releases.
1989 clone. This behavior may change in future releases.
1991 See :hg:`help -e clonebundles` for more.
1990 See :hg:`help -e clonebundles` for more.
1992
1991
1993 Examples:
1992 Examples:
1994
1993
1995 - clone a remote repository to a new directory named hg/::
1994 - clone a remote repository to a new directory named hg/::
1996
1995
1997 hg clone https://www.mercurial-scm.org/repo/hg/
1996 hg clone https://www.mercurial-scm.org/repo/hg/
1998
1997
1999 - create a lightweight local clone::
1998 - create a lightweight local clone::
2000
1999
2001 hg clone project/ project-feature/
2000 hg clone project/ project-feature/
2002
2001
2003 - clone from an absolute path on an ssh server (note double-slash)::
2002 - clone from an absolute path on an ssh server (note double-slash)::
2004
2003
2005 hg clone ssh://user@server//home/projects/alpha/
2004 hg clone ssh://user@server//home/projects/alpha/
2006
2005
2007 - do a streaming clone while checking out a specified version::
2006 - do a streaming clone while checking out a specified version::
2008
2007
2009 hg clone --stream http://server/repo -u 1.5
2008 hg clone --stream http://server/repo -u 1.5
2010
2009
2011 - create a repository without changesets after a particular revision::
2010 - create a repository without changesets after a particular revision::
2012
2011
2013 hg clone -r 04e544 experimental/ good/
2012 hg clone -r 04e544 experimental/ good/
2014
2013
2015 - clone (and track) a particular named branch::
2014 - clone (and track) a particular named branch::
2016
2015
2017 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2016 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2018
2017
2019 See :hg:`help urls` for details on specifying URLs.
2018 See :hg:`help urls` for details on specifying URLs.
2020
2019
2021 Returns 0 on success.
2020 Returns 0 on success.
2022 """
2021 """
2023 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2022 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2024
2023
2025 # --include/--exclude can come from narrow or sparse.
2024 # --include/--exclude can come from narrow or sparse.
2026 includepats, excludepats = None, None
2025 includepats, excludepats = None, None
2027
2026
2028 # hg.clone() differentiates between None and an empty set. So make sure
2027 # hg.clone() differentiates between None and an empty set. So make sure
2029 # patterns are sets if narrow is requested without patterns.
2028 # patterns are sets if narrow is requested without patterns.
2030 if opts.get('narrow'):
2029 if opts.get('narrow'):
2031 includepats = set()
2030 includepats = set()
2032 excludepats = set()
2031 excludepats = set()
2033
2032
2034 if opts.get('include'):
2033 if opts.get('include'):
2035 includepats = narrowspec.parsepatterns(opts.get('include'))
2034 includepats = narrowspec.parsepatterns(opts.get('include'))
2036 if opts.get('exclude'):
2035 if opts.get('exclude'):
2037 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2036 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2038
2037
2039 r = hg.clone(
2038 r = hg.clone(
2040 ui,
2039 ui,
2041 pycompat.byteskwargs(opts),
2040 pycompat.byteskwargs(opts),
2042 source,
2041 source,
2043 dest,
2042 dest,
2044 pull=opts.get('pull'),
2043 pull=opts.get('pull'),
2045 stream=opts.get('stream') or opts.get('uncompressed'),
2044 stream=opts.get('stream') or opts.get('uncompressed'),
2046 revs=opts.get('rev'),
2045 revs=opts.get('rev'),
2047 update=opts.get('updaterev') or not opts.get('noupdate'),
2046 update=opts.get('updaterev') or not opts.get('noupdate'),
2048 branch=opts.get('branch'),
2047 branch=opts.get('branch'),
2049 shareopts=opts.get('shareopts'),
2048 shareopts=opts.get('shareopts'),
2050 storeincludepats=includepats,
2049 storeincludepats=includepats,
2051 storeexcludepats=excludepats,
2050 storeexcludepats=excludepats,
2052 depth=opts.get('depth') or None,
2051 depth=opts.get('depth') or None,
2053 )
2052 )
2054
2053
2055 return r is None
2054 return r is None
2056
2055
2057
2056
2058 @command(
2057 @command(
2059 b'commit|ci',
2058 b'commit|ci',
2060 [
2059 [
2061 (
2060 (
2062 b'A',
2061 b'A',
2063 b'addremove',
2062 b'addremove',
2064 None,
2063 None,
2065 _(b'mark new/missing files as added/removed before committing'),
2064 _(b'mark new/missing files as added/removed before committing'),
2066 ),
2065 ),
2067 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2066 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2068 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2067 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2069 (b's', b'secret', None, _(b'use the secret phase for committing')),
2068 (b's', b'secret', None, _(b'use the secret phase for committing')),
2070 (b'', b'draft', None, _(b'use the draft phase for committing')),
2069 (b'', b'draft', None, _(b'use the draft phase for committing')),
2071 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2070 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2072 (
2071 (
2073 b'',
2072 b'',
2074 b'force-close-branch',
2073 b'force-close-branch',
2075 None,
2074 None,
2076 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2075 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2077 ),
2076 ),
2078 (b'i', b'interactive', None, _(b'use interactive mode')),
2077 (b'i', b'interactive', None, _(b'use interactive mode')),
2079 ]
2078 ]
2080 + walkopts
2079 + walkopts
2081 + commitopts
2080 + commitopts
2082 + commitopts2
2081 + commitopts2
2083 + subrepoopts,
2082 + subrepoopts,
2084 _(b'[OPTION]... [FILE]...'),
2083 _(b'[OPTION]... [FILE]...'),
2085 helpcategory=command.CATEGORY_COMMITTING,
2084 helpcategory=command.CATEGORY_COMMITTING,
2086 helpbasic=True,
2085 helpbasic=True,
2087 inferrepo=True,
2086 inferrepo=True,
2088 )
2087 )
2089 def commit(ui, repo, *pats, **opts):
2088 def commit(ui, repo, *pats, **opts):
2090 """commit the specified files or all outstanding changes
2089 """commit the specified files or all outstanding changes
2091
2090
2092 Commit changes to the given files into the repository. Unlike a
2091 Commit changes to the given files into the repository. Unlike a
2093 centralized SCM, this operation is a local operation. See
2092 centralized SCM, this operation is a local operation. See
2094 :hg:`push` for a way to actively distribute your changes.
2093 :hg:`push` for a way to actively distribute your changes.
2095
2094
2096 If a list of files is omitted, all changes reported by :hg:`status`
2095 If a list of files is omitted, all changes reported by :hg:`status`
2097 will be committed.
2096 will be committed.
2098
2097
2099 If you are committing the result of a merge, do not provide any
2098 If you are committing the result of a merge, do not provide any
2100 filenames or -I/-X filters.
2099 filenames or -I/-X filters.
2101
2100
2102 If no commit message is specified, Mercurial starts your
2101 If no commit message is specified, Mercurial starts your
2103 configured editor where you can enter a message. In case your
2102 configured editor where you can enter a message. In case your
2104 commit fails, you will find a backup of your message in
2103 commit fails, you will find a backup of your message in
2105 ``.hg/last-message.txt``.
2104 ``.hg/last-message.txt``.
2106
2105
2107 The --close-branch flag can be used to mark the current branch
2106 The --close-branch flag can be used to mark the current branch
2108 head closed. When all heads of a branch are closed, the branch
2107 head closed. When all heads of a branch are closed, the branch
2109 will be considered closed and no longer listed.
2108 will be considered closed and no longer listed.
2110
2109
2111 The --amend flag can be used to amend the parent of the
2110 The --amend flag can be used to amend the parent of the
2112 working directory with a new commit that contains the changes
2111 working directory with a new commit that contains the changes
2113 in the parent in addition to those currently reported by :hg:`status`,
2112 in the parent in addition to those currently reported by :hg:`status`,
2114 if there are any. The old commit is stored in a backup bundle in
2113 if there are any. The old commit is stored in a backup bundle in
2115 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2114 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2116 on how to restore it).
2115 on how to restore it).
2117
2116
2118 Message, user and date are taken from the amended commit unless
2117 Message, user and date are taken from the amended commit unless
2119 specified. When a message isn't specified on the command line,
2118 specified. When a message isn't specified on the command line,
2120 the editor will open with the message of the amended commit.
2119 the editor will open with the message of the amended commit.
2121
2120
2122 It is not possible to amend public changesets (see :hg:`help phases`)
2121 It is not possible to amend public changesets (see :hg:`help phases`)
2123 or changesets that have children.
2122 or changesets that have children.
2124
2123
2125 See :hg:`help dates` for a list of formats valid for -d/--date.
2124 See :hg:`help dates` for a list of formats valid for -d/--date.
2126
2125
2127 Returns 0 on success, 1 if nothing changed.
2126 Returns 0 on success, 1 if nothing changed.
2128
2127
2129 .. container:: verbose
2128 .. container:: verbose
2130
2129
2131 Examples:
2130 Examples:
2132
2131
2133 - commit all files ending in .py::
2132 - commit all files ending in .py::
2134
2133
2135 hg commit --include "set:**.py"
2134 hg commit --include "set:**.py"
2136
2135
2137 - commit all non-binary files::
2136 - commit all non-binary files::
2138
2137
2139 hg commit --exclude "set:binary()"
2138 hg commit --exclude "set:binary()"
2140
2139
2141 - amend the current commit and set the date to now::
2140 - amend the current commit and set the date to now::
2142
2141
2143 hg commit --amend --date now
2142 hg commit --amend --date now
2144 """
2143 """
2145 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2144 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2146 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2145 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2147 with repo.wlock(), repo.lock():
2146 with repo.wlock(), repo.lock():
2148 return _docommit(ui, repo, *pats, **opts)
2147 return _docommit(ui, repo, *pats, **opts)
2149
2148
2150
2149
2151 def _docommit(ui, repo, *pats, **opts):
2150 def _docommit(ui, repo, *pats, **opts):
2152 if opts.get('interactive'):
2151 if opts.get('interactive'):
2153 opts.pop('interactive')
2152 opts.pop('interactive')
2154 ret = cmdutil.dorecord(
2153 ret = cmdutil.dorecord(
2155 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2154 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2156 )
2155 )
2157 # ret can be 0 (no changes to record) or the value returned by
2156 # ret can be 0 (no changes to record) or the value returned by
2158 # commit(), 1 if nothing changed or None on success.
2157 # commit(), 1 if nothing changed or None on success.
2159 return 1 if ret == 0 else ret
2158 return 1 if ret == 0 else ret
2160
2159
2161 if opts.get('subrepos'):
2160 if opts.get('subrepos'):
2162 # Let --subrepos on the command line override config setting.
2161 # Let --subrepos on the command line override config setting.
2163 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2162 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2164
2163
2165 cmdutil.checkunfinished(repo, commit=True)
2164 cmdutil.checkunfinished(repo, commit=True)
2166
2165
2167 branch = repo[None].branch()
2166 branch = repo[None].branch()
2168 bheads = repo.branchheads(branch)
2167 bheads = repo.branchheads(branch)
2169 tip = repo.changelog.tip()
2168 tip = repo.changelog.tip()
2170
2169
2171 extra = {}
2170 extra = {}
2172 if opts.get('close_branch') or opts.get('force_close_branch'):
2171 if opts.get('close_branch') or opts.get('force_close_branch'):
2173 extra[b'close'] = b'1'
2172 extra[b'close'] = b'1'
2174
2173
2175 if repo[b'.'].closesbranch():
2174 if repo[b'.'].closesbranch():
2176 # Not ideal, but let us do an extra status early to prevent early
2175 # Not ideal, but let us do an extra status early to prevent early
2177 # bail out.
2176 # bail out.
2178 matcher = scmutil.match(
2177 matcher = scmutil.match(
2179 repo[None], pats, pycompat.byteskwargs(opts)
2178 repo[None], pats, pycompat.byteskwargs(opts)
2180 )
2179 )
2181 s = repo.status(match=matcher)
2180 s = repo.status(match=matcher)
2182 if s.modified or s.added or s.removed:
2181 if s.modified or s.added or s.removed:
2183 bheads = repo.branchheads(branch, closed=True)
2182 bheads = repo.branchheads(branch, closed=True)
2184 else:
2183 else:
2185 msg = _(b'current revision is already a branch closing head')
2184 msg = _(b'current revision is already a branch closing head')
2186 raise error.InputError(msg)
2185 raise error.InputError(msg)
2187
2186
2188 if not bheads:
2187 if not bheads:
2189 raise error.InputError(
2188 raise error.InputError(
2190 _(b'branch "%s" has no heads to close') % branch
2189 _(b'branch "%s" has no heads to close') % branch
2191 )
2190 )
2192 elif (
2191 elif (
2193 branch == repo[b'.'].branch()
2192 branch == repo[b'.'].branch()
2194 and repo[b'.'].node() not in bheads
2193 and repo[b'.'].node() not in bheads
2195 and not opts.get('force_close_branch')
2194 and not opts.get('force_close_branch')
2196 ):
2195 ):
2197 hint = _(
2196 hint = _(
2198 b'use --force-close-branch to close branch from a non-head'
2197 b'use --force-close-branch to close branch from a non-head'
2199 b' changeset'
2198 b' changeset'
2200 )
2199 )
2201 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2200 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2202 elif opts.get('amend'):
2201 elif opts.get('amend'):
2203 if (
2202 if (
2204 repo[b'.'].p1().branch() != branch
2203 repo[b'.'].p1().branch() != branch
2205 and repo[b'.'].p2().branch() != branch
2204 and repo[b'.'].p2().branch() != branch
2206 ):
2205 ):
2207 raise error.InputError(_(b'can only close branch heads'))
2206 raise error.InputError(_(b'can only close branch heads'))
2208
2207
2209 if opts.get('amend'):
2208 if opts.get('amend'):
2210 if ui.configbool(b'ui', b'commitsubrepos'):
2209 if ui.configbool(b'ui', b'commitsubrepos'):
2211 raise error.InputError(
2210 raise error.InputError(
2212 _(b'cannot amend with ui.commitsubrepos enabled')
2211 _(b'cannot amend with ui.commitsubrepos enabled')
2213 )
2212 )
2214
2213
2215 old = repo[b'.']
2214 old = repo[b'.']
2216 rewriteutil.precheck(repo, [old.rev()], b'amend')
2215 rewriteutil.precheck(repo, [old.rev()], b'amend')
2217
2216
2218 # Currently histedit gets confused if an amend happens while histedit
2217 # Currently histedit gets confused if an amend happens while histedit
2219 # is in progress. Since we have a checkunfinished command, we are
2218 # is in progress. Since we have a checkunfinished command, we are
2220 # temporarily honoring it.
2219 # temporarily honoring it.
2221 #
2220 #
2222 # Note: eventually this guard will be removed. Please do not expect
2221 # Note: eventually this guard will be removed. Please do not expect
2223 # this behavior to remain.
2222 # this behavior to remain.
2224 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2223 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2225 cmdutil.checkunfinished(repo)
2224 cmdutil.checkunfinished(repo)
2226
2225
2227 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2226 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2228 if node == old.node():
2227 if node == old.node():
2229 ui.status(_(b"nothing changed\n"))
2228 ui.status(_(b"nothing changed\n"))
2230 return 1
2229 return 1
2231 else:
2230 else:
2232
2231
2233 def commitfunc(ui, repo, message, match, opts):
2232 def commitfunc(ui, repo, message, match, opts):
2234 overrides = {}
2233 overrides = {}
2235 if opts.get(b'secret'):
2234 if opts.get(b'secret'):
2236 overrides[(b'phases', b'new-commit')] = b'secret'
2235 overrides[(b'phases', b'new-commit')] = b'secret'
2237 elif opts.get(b'draft'):
2236 elif opts.get(b'draft'):
2238 overrides[(b'phases', b'new-commit')] = b'draft'
2237 overrides[(b'phases', b'new-commit')] = b'draft'
2239
2238
2240 baseui = repo.baseui
2239 baseui = repo.baseui
2241 with baseui.configoverride(overrides, b'commit'):
2240 with baseui.configoverride(overrides, b'commit'):
2242 with ui.configoverride(overrides, b'commit'):
2241 with ui.configoverride(overrides, b'commit'):
2243 editform = cmdutil.mergeeditform(
2242 editform = cmdutil.mergeeditform(
2244 repo[None], b'commit.normal'
2243 repo[None], b'commit.normal'
2245 )
2244 )
2246 editor = cmdutil.getcommiteditor(
2245 editor = cmdutil.getcommiteditor(
2247 editform=editform, **pycompat.strkwargs(opts)
2246 editform=editform, **pycompat.strkwargs(opts)
2248 )
2247 )
2249 return repo.commit(
2248 return repo.commit(
2250 message,
2249 message,
2251 opts.get(b'user'),
2250 opts.get(b'user'),
2252 opts.get(b'date'),
2251 opts.get(b'date'),
2253 match,
2252 match,
2254 editor=editor,
2253 editor=editor,
2255 extra=extra,
2254 extra=extra,
2256 )
2255 )
2257
2256
2258 node = cmdutil.commit(
2257 node = cmdutil.commit(
2259 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2258 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2260 )
2259 )
2261
2260
2262 if not node:
2261 if not node:
2263 stat = cmdutil.postcommitstatus(
2262 stat = cmdutil.postcommitstatus(
2264 repo, pats, pycompat.byteskwargs(opts)
2263 repo, pats, pycompat.byteskwargs(opts)
2265 )
2264 )
2266 if stat.deleted:
2265 if stat.deleted:
2267 ui.status(
2266 ui.status(
2268 _(
2267 _(
2269 b"nothing changed (%d missing files, see "
2268 b"nothing changed (%d missing files, see "
2270 b"'hg status')\n"
2269 b"'hg status')\n"
2271 )
2270 )
2272 % len(stat.deleted)
2271 % len(stat.deleted)
2273 )
2272 )
2274 else:
2273 else:
2275 ui.status(_(b"nothing changed\n"))
2274 ui.status(_(b"nothing changed\n"))
2276 return 1
2275 return 1
2277
2276
2278 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2277 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2279
2278
2280 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2279 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2281 status(
2280 status(
2282 ui,
2281 ui,
2283 repo,
2282 repo,
2284 modified=True,
2283 modified=True,
2285 added=True,
2284 added=True,
2286 removed=True,
2285 removed=True,
2287 deleted=True,
2286 deleted=True,
2288 unknown=True,
2287 unknown=True,
2289 subrepos=opts.get('subrepos'),
2288 subrepos=opts.get('subrepos'),
2290 )
2289 )
2291
2290
2292
2291
2293 @command(
2292 @command(
2294 b'config|showconfig|debugconfig',
2293 b'config|showconfig|debugconfig',
2295 [
2294 [
2296 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2295 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2297 # This is experimental because we need
2296 # This is experimental because we need
2298 # * reasonable behavior around aliases,
2297 # * reasonable behavior around aliases,
2299 # * decide if we display [debug] [experimental] and [devel] section par
2298 # * decide if we display [debug] [experimental] and [devel] section par
2300 # default
2299 # default
2301 # * some way to display "generic" config entry (the one matching
2300 # * some way to display "generic" config entry (the one matching
2302 # regexp,
2301 # regexp,
2303 # * proper display of the different value type
2302 # * proper display of the different value type
2304 # * a better way to handle <DYNAMIC> values (and variable types),
2303 # * a better way to handle <DYNAMIC> values (and variable types),
2305 # * maybe some type information ?
2304 # * maybe some type information ?
2306 (
2305 (
2307 b'',
2306 b'',
2308 b'exp-all-known',
2307 b'exp-all-known',
2309 None,
2308 None,
2310 _(b'show all known config option (EXPERIMENTAL)'),
2309 _(b'show all known config option (EXPERIMENTAL)'),
2311 ),
2310 ),
2312 (b'e', b'edit', None, _(b'edit user config')),
2311 (b'e', b'edit', None, _(b'edit user config')),
2313 (b'l', b'local', None, _(b'edit repository config')),
2312 (b'l', b'local', None, _(b'edit repository config')),
2314 (b'', b'source', None, _(b'show source of configuration value')),
2313 (b'', b'source', None, _(b'show source of configuration value')),
2315 (
2314 (
2316 b'',
2315 b'',
2317 b'shared',
2316 b'shared',
2318 None,
2317 None,
2319 _(b'edit shared source repository config (EXPERIMENTAL)'),
2318 _(b'edit shared source repository config (EXPERIMENTAL)'),
2320 ),
2319 ),
2321 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2320 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2322 (b'g', b'global', None, _(b'edit global config')),
2321 (b'g', b'global', None, _(b'edit global config')),
2323 ]
2322 ]
2324 + formatteropts,
2323 + formatteropts,
2325 _(b'[-u] [NAME]...'),
2324 _(b'[-u] [NAME]...'),
2326 helpcategory=command.CATEGORY_HELP,
2325 helpcategory=command.CATEGORY_HELP,
2327 optionalrepo=True,
2326 optionalrepo=True,
2328 intents={INTENT_READONLY},
2327 intents={INTENT_READONLY},
2329 )
2328 )
2330 def config(ui, repo, *values, **opts):
2329 def config(ui, repo, *values, **opts):
2331 """show combined config settings from all hgrc files
2330 """show combined config settings from all hgrc files
2332
2331
2333 With no arguments, print names and values of all config items.
2332 With no arguments, print names and values of all config items.
2334
2333
2335 With one argument of the form section.name, print just the value
2334 With one argument of the form section.name, print just the value
2336 of that config item.
2335 of that config item.
2337
2336
2338 With multiple arguments, print names and values of all config
2337 With multiple arguments, print names and values of all config
2339 items with matching section names or section.names.
2338 items with matching section names or section.names.
2340
2339
2341 With --edit, start an editor on the user-level config file. With
2340 With --edit, start an editor on the user-level config file. With
2342 --global, edit the system-wide config file. With --local, edit the
2341 --global, edit the system-wide config file. With --local, edit the
2343 repository-level config file.
2342 repository-level config file.
2344
2343
2345 With --source, the source (filename and line number) is printed
2344 With --source, the source (filename and line number) is printed
2346 for each config item.
2345 for each config item.
2347
2346
2348 See :hg:`help config` for more information about config files.
2347 See :hg:`help config` for more information about config files.
2349
2348
2350 .. container:: verbose
2349 .. container:: verbose
2351
2350
2352 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2351 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2353 This file is not shared across shares when in share-safe mode.
2352 This file is not shared across shares when in share-safe mode.
2354
2353
2355 Template:
2354 Template:
2356
2355
2357 The following keywords are supported. See also :hg:`help templates`.
2356 The following keywords are supported. See also :hg:`help templates`.
2358
2357
2359 :name: String. Config name.
2358 :name: String. Config name.
2360 :source: String. Filename and line number where the item is defined.
2359 :source: String. Filename and line number where the item is defined.
2361 :value: String. Config value.
2360 :value: String. Config value.
2362
2361
2363 The --shared flag can be used to edit the config file of shared source
2362 The --shared flag can be used to edit the config file of shared source
2364 repository. It only works when you have shared using the experimental
2363 repository. It only works when you have shared using the experimental
2365 share safe feature.
2364 share safe feature.
2366
2365
2367 Returns 0 on success, 1 if NAME does not exist.
2366 Returns 0 on success, 1 if NAME does not exist.
2368
2367
2369 """
2368 """
2370 edit_level = config_command.find_edit_level(ui, repo, opts)
2369 edit_level = config_command.find_edit_level(ui, repo, opts)
2371 if edit_level is not None:
2370 if edit_level is not None:
2372 return config_command.edit_config(ui, repo, edit_level)
2371 return config_command.edit_config(ui, repo, edit_level)
2372
2373 ui.pager(b'config')
2373 ui.pager(b'config')
2374 config_command.show_component(ui, repo)
2374 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2375 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2375 for t, f in rcutil.rccomponents():
2376 if t == b'path':
2377 ui.debug(b'read config from: %s\n' % f)
2378 elif t == b'resource':
2379 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2380 elif t == b'items':
2381 # Don't print anything for 'items'.
2382 pass
2383 else:
2384 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2385 untrusted = bool(opts.get('untrusted'))
2376 untrusted = bool(opts.get('untrusted'))
2386
2377
2387 selsections = selentries = []
2378 selsections = selentries = []
2388 if values:
2379 if values:
2389 selsections = [v for v in values if b'.' not in v]
2380 selsections = [v for v in values if b'.' not in v]
2390 selentries = [v for v in values if b'.' in v]
2381 selentries = [v for v in values if b'.' in v]
2391 uniquesel = len(selentries) == 1 and not selsections
2382 uniquesel = len(selentries) == 1 and not selsections
2392 selsections = set(selsections)
2383 selsections = set(selsections)
2393 selentries = set(selentries)
2384 selentries = set(selentries)
2394
2385
2395 matched = False
2386 matched = False
2396 all_known = opts['exp_all_known']
2387 all_known = opts['exp_all_known']
2397 show_source = ui.debugflag or opts.get('source')
2388 show_source = ui.debugflag or opts.get('source')
2398 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2389 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2399 for section, name, value in entries:
2390 for section, name, value in entries:
2400 source = ui.configsource(section, name, untrusted)
2391 source = ui.configsource(section, name, untrusted)
2401 value = pycompat.bytestr(value)
2392 value = pycompat.bytestr(value)
2402 defaultvalue = ui.configdefault(section, name)
2393 defaultvalue = ui.configdefault(section, name)
2403 if fm.isplain():
2394 if fm.isplain():
2404 source = source or b'none'
2395 source = source or b'none'
2405 value = value.replace(b'\n', b'\\n')
2396 value = value.replace(b'\n', b'\\n')
2406 entryname = section + b'.' + name
2397 entryname = section + b'.' + name
2407 if values and not (section in selsections or entryname in selentries):
2398 if values and not (section in selsections or entryname in selentries):
2408 continue
2399 continue
2409 fm.startitem()
2400 fm.startitem()
2410 fm.condwrite(show_source, b'source', b'%s: ', source)
2401 fm.condwrite(show_source, b'source', b'%s: ', source)
2411 if uniquesel:
2402 if uniquesel:
2412 fm.data(name=entryname)
2403 fm.data(name=entryname)
2413 fm.write(b'value', b'%s\n', value)
2404 fm.write(b'value', b'%s\n', value)
2414 else:
2405 else:
2415 fm.write(b'name value', b'%s=%s\n', entryname, value)
2406 fm.write(b'name value', b'%s=%s\n', entryname, value)
2416 if formatter.isprintable(defaultvalue):
2407 if formatter.isprintable(defaultvalue):
2417 fm.data(defaultvalue=defaultvalue)
2408 fm.data(defaultvalue=defaultvalue)
2418 elif isinstance(defaultvalue, list) and all(
2409 elif isinstance(defaultvalue, list) and all(
2419 formatter.isprintable(e) for e in defaultvalue
2410 formatter.isprintable(e) for e in defaultvalue
2420 ):
2411 ):
2421 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2412 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2422 # TODO: no idea how to process unsupported defaultvalue types
2413 # TODO: no idea how to process unsupported defaultvalue types
2423 matched = True
2414 matched = True
2424 fm.end()
2415 fm.end()
2425 if matched:
2416 if matched:
2426 return 0
2417 return 0
2427 return 1
2418 return 1
2428
2419
2429
2420
2430 @command(
2421 @command(
2431 b'continue',
2422 b'continue',
2432 dryrunopts,
2423 dryrunopts,
2433 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2424 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2434 helpbasic=True,
2425 helpbasic=True,
2435 )
2426 )
2436 def continuecmd(ui, repo, **opts):
2427 def continuecmd(ui, repo, **opts):
2437 """resumes an interrupted operation (EXPERIMENTAL)
2428 """resumes an interrupted operation (EXPERIMENTAL)
2438
2429
2439 Finishes a multistep operation like graft, histedit, rebase, merge,
2430 Finishes a multistep operation like graft, histedit, rebase, merge,
2440 and unshelve if they are in an interrupted state.
2431 and unshelve if they are in an interrupted state.
2441
2432
2442 use --dry-run/-n to dry run the command.
2433 use --dry-run/-n to dry run the command.
2443 """
2434 """
2444 dryrun = opts.get('dry_run')
2435 dryrun = opts.get('dry_run')
2445 contstate = cmdutil.getunfinishedstate(repo)
2436 contstate = cmdutil.getunfinishedstate(repo)
2446 if not contstate:
2437 if not contstate:
2447 raise error.StateError(_(b'no operation in progress'))
2438 raise error.StateError(_(b'no operation in progress'))
2448 if not contstate.continuefunc:
2439 if not contstate.continuefunc:
2449 raise error.StateError(
2440 raise error.StateError(
2450 (
2441 (
2451 _(b"%s in progress but does not support 'hg continue'")
2442 _(b"%s in progress but does not support 'hg continue'")
2452 % (contstate._opname)
2443 % (contstate._opname)
2453 ),
2444 ),
2454 hint=contstate.continuemsg(),
2445 hint=contstate.continuemsg(),
2455 )
2446 )
2456 if dryrun:
2447 if dryrun:
2457 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2448 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2458 return
2449 return
2459 return contstate.continuefunc(ui, repo)
2450 return contstate.continuefunc(ui, repo)
2460
2451
2461
2452
2462 @command(
2453 @command(
2463 b'copy|cp',
2454 b'copy|cp',
2464 [
2455 [
2465 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2456 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2466 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2457 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2467 (
2458 (
2468 b'',
2459 b'',
2469 b'at-rev',
2460 b'at-rev',
2470 b'',
2461 b'',
2471 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2462 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2472 _(b'REV'),
2463 _(b'REV'),
2473 ),
2464 ),
2474 (
2465 (
2475 b'f',
2466 b'f',
2476 b'force',
2467 b'force',
2477 None,
2468 None,
2478 _(b'forcibly copy over an existing managed file'),
2469 _(b'forcibly copy over an existing managed file'),
2479 ),
2470 ),
2480 ]
2471 ]
2481 + walkopts
2472 + walkopts
2482 + dryrunopts,
2473 + dryrunopts,
2483 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2474 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2484 helpcategory=command.CATEGORY_FILE_CONTENTS,
2475 helpcategory=command.CATEGORY_FILE_CONTENTS,
2485 )
2476 )
2486 def copy(ui, repo, *pats, **opts):
2477 def copy(ui, repo, *pats, **opts):
2487 """mark files as copied for the next commit
2478 """mark files as copied for the next commit
2488
2479
2489 Mark dest as having copies of source files. If dest is a
2480 Mark dest as having copies of source files. If dest is a
2490 directory, copies are put in that directory. If dest is a file,
2481 directory, copies are put in that directory. If dest is a file,
2491 the source must be a single file.
2482 the source must be a single file.
2492
2483
2493 By default, this command copies the contents of files as they
2484 By default, this command copies the contents of files as they
2494 exist in the working directory. If invoked with -A/--after, the
2485 exist in the working directory. If invoked with -A/--after, the
2495 operation is recorded, but no copying is performed.
2486 operation is recorded, but no copying is performed.
2496
2487
2497 To undo marking a destination file as copied, use --forget. With that
2488 To undo marking a destination file as copied, use --forget. With that
2498 option, all given (positional) arguments are unmarked as copies. The
2489 option, all given (positional) arguments are unmarked as copies. The
2499 destination file(s) will be left in place (still tracked). Note that
2490 destination file(s) will be left in place (still tracked). Note that
2500 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2491 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2501
2492
2502 This command takes effect with the next commit by default.
2493 This command takes effect with the next commit by default.
2503
2494
2504 Returns 0 on success, 1 if errors are encountered.
2495 Returns 0 on success, 1 if errors are encountered.
2505 """
2496 """
2506
2497
2507 context = lambda repo: repo.dirstate.changing_files(repo)
2498 context = lambda repo: repo.dirstate.changing_files(repo)
2508 rev = opts.get('at_rev')
2499 rev = opts.get('at_rev')
2509
2500
2510 if rev:
2501 if rev:
2511 ctx = logcmdutil.revsingle(repo, rev)
2502 ctx = logcmdutil.revsingle(repo, rev)
2512 if ctx.rev() is not None:
2503 if ctx.rev() is not None:
2513
2504
2514 def context(repo):
2505 def context(repo):
2515 return util.nullcontextmanager()
2506 return util.nullcontextmanager()
2516
2507
2517 opts['at_rev'] = ctx.rev()
2508 opts['at_rev'] = ctx.rev()
2518 with repo.wlock(), context(repo):
2509 with repo.wlock(), context(repo):
2519 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2510 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2520
2511
2521
2512
2522 @command(
2513 @command(
2523 b'debugcommands',
2514 b'debugcommands',
2524 [],
2515 [],
2525 _(b'[COMMAND]'),
2516 _(b'[COMMAND]'),
2526 helpcategory=command.CATEGORY_HELP,
2517 helpcategory=command.CATEGORY_HELP,
2527 norepo=True,
2518 norepo=True,
2528 )
2519 )
2529 def debugcommands(ui, cmd=b'', *args):
2520 def debugcommands(ui, cmd=b'', *args):
2530 """list all available commands and options"""
2521 """list all available commands and options"""
2531 for cmd, vals in sorted(table.items()):
2522 for cmd, vals in sorted(table.items()):
2532 cmd = cmd.split(b'|')[0]
2523 cmd = cmd.split(b'|')[0]
2533 opts = b', '.join([i[1] for i in vals[1]])
2524 opts = b', '.join([i[1] for i in vals[1]])
2534 ui.write(b'%s: %s\n' % (cmd, opts))
2525 ui.write(b'%s: %s\n' % (cmd, opts))
2535
2526
2536
2527
2537 @command(
2528 @command(
2538 b'debugcomplete',
2529 b'debugcomplete',
2539 [(b'o', b'options', None, _(b'show the command options'))],
2530 [(b'o', b'options', None, _(b'show the command options'))],
2540 _(b'[-o] CMD'),
2531 _(b'[-o] CMD'),
2541 helpcategory=command.CATEGORY_HELP,
2532 helpcategory=command.CATEGORY_HELP,
2542 norepo=True,
2533 norepo=True,
2543 )
2534 )
2544 def debugcomplete(ui, cmd=b'', **opts):
2535 def debugcomplete(ui, cmd=b'', **opts):
2545 """returns the completion list associated with the given command"""
2536 """returns the completion list associated with the given command"""
2546
2537
2547 if opts.get('options'):
2538 if opts.get('options'):
2548 options = []
2539 options = []
2549 otables = [globalopts]
2540 otables = [globalopts]
2550 if cmd:
2541 if cmd:
2551 aliases, entry = cmdutil.findcmd(cmd, table, False)
2542 aliases, entry = cmdutil.findcmd(cmd, table, False)
2552 otables.append(entry[1])
2543 otables.append(entry[1])
2553 for t in otables:
2544 for t in otables:
2554 for o in t:
2545 for o in t:
2555 if b"(DEPRECATED)" in o[3]:
2546 if b"(DEPRECATED)" in o[3]:
2556 continue
2547 continue
2557 if o[0]:
2548 if o[0]:
2558 options.append(b'-%s' % o[0])
2549 options.append(b'-%s' % o[0])
2559 options.append(b'--%s' % o[1])
2550 options.append(b'--%s' % o[1])
2560 ui.write(b"%s\n" % b"\n".join(options))
2551 ui.write(b"%s\n" % b"\n".join(options))
2561 return
2552 return
2562
2553
2563 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2554 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2564 if ui.verbose:
2555 if ui.verbose:
2565 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2556 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2566 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2557 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2567
2558
2568
2559
2569 @command(
2560 @command(
2570 b'diff',
2561 b'diff',
2571 [
2562 [
2572 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2563 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2573 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2564 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2574 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2565 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2575 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2566 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2576 ]
2567 ]
2577 + diffopts
2568 + diffopts
2578 + diffopts2
2569 + diffopts2
2579 + walkopts
2570 + walkopts
2580 + subrepoopts,
2571 + subrepoopts,
2581 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2572 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2582 helpcategory=command.CATEGORY_FILE_CONTENTS,
2573 helpcategory=command.CATEGORY_FILE_CONTENTS,
2583 helpbasic=True,
2574 helpbasic=True,
2584 inferrepo=True,
2575 inferrepo=True,
2585 intents={INTENT_READONLY},
2576 intents={INTENT_READONLY},
2586 )
2577 )
2587 def diff(ui, repo, *pats, **opts):
2578 def diff(ui, repo, *pats, **opts):
2588 """diff repository (or selected files)
2579 """diff repository (or selected files)
2589
2580
2590 Show differences between revisions for the specified files.
2581 Show differences between revisions for the specified files.
2591
2582
2592 Differences between files are shown using the unified diff format.
2583 Differences between files are shown using the unified diff format.
2593
2584
2594 .. note::
2585 .. note::
2595
2586
2596 :hg:`diff` may generate unexpected results for merges, as it will
2587 :hg:`diff` may generate unexpected results for merges, as it will
2597 default to comparing against the working directory's first
2588 default to comparing against the working directory's first
2598 parent changeset if no revisions are specified. To diff against the
2589 parent changeset if no revisions are specified. To diff against the
2599 conflict regions, you can use `--config diff.merge=yes`.
2590 conflict regions, you can use `--config diff.merge=yes`.
2600
2591
2601 By default, the working directory files are compared to its first parent. To
2592 By default, the working directory files are compared to its first parent. To
2602 see the differences from another revision, use --from. To see the difference
2593 see the differences from another revision, use --from. To see the difference
2603 to another revision, use --to. For example, :hg:`diff --from .^` will show
2594 to another revision, use --to. For example, :hg:`diff --from .^` will show
2604 the differences from the working copy's grandparent to the working copy,
2595 the differences from the working copy's grandparent to the working copy,
2605 :hg:`diff --to .` will show the diff from the working copy to its parent
2596 :hg:`diff --to .` will show the diff from the working copy to its parent
2606 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2597 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2607 show the diff between those two revisions.
2598 show the diff between those two revisions.
2608
2599
2609 Alternatively you can specify -c/--change with a revision to see the changes
2600 Alternatively you can specify -c/--change with a revision to see the changes
2610 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2601 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2611 equivalent to :hg:`diff --from 42^ --to 42`)
2602 equivalent to :hg:`diff --from 42^ --to 42`)
2612
2603
2613 Without the -a/--text option, diff will avoid generating diffs of
2604 Without the -a/--text option, diff will avoid generating diffs of
2614 files it detects as binary. With -a, diff will generate a diff
2605 files it detects as binary. With -a, diff will generate a diff
2615 anyway, probably with undesirable results.
2606 anyway, probably with undesirable results.
2616
2607
2617 Use the -g/--git option to generate diffs in the git extended diff
2608 Use the -g/--git option to generate diffs in the git extended diff
2618 format. For more information, read :hg:`help diffs`.
2609 format. For more information, read :hg:`help diffs`.
2619
2610
2620 .. container:: verbose
2611 .. container:: verbose
2621
2612
2622 Examples:
2613 Examples:
2623
2614
2624 - compare a file in the current working directory to its parent::
2615 - compare a file in the current working directory to its parent::
2625
2616
2626 hg diff foo.c
2617 hg diff foo.c
2627
2618
2628 - compare two historical versions of a directory, with rename info::
2619 - compare two historical versions of a directory, with rename info::
2629
2620
2630 hg diff --git --from 1.0 --to 1.2 lib/
2621 hg diff --git --from 1.0 --to 1.2 lib/
2631
2622
2632 - get change stats relative to the last change on some date::
2623 - get change stats relative to the last change on some date::
2633
2624
2634 hg diff --stat --from "date('may 2')"
2625 hg diff --stat --from "date('may 2')"
2635
2626
2636 - diff all newly-added files that contain a keyword::
2627 - diff all newly-added files that contain a keyword::
2637
2628
2638 hg diff "set:added() and grep(GNU)"
2629 hg diff "set:added() and grep(GNU)"
2639
2630
2640 - compare a revision and its parents::
2631 - compare a revision and its parents::
2641
2632
2642 hg diff -c 9353 # compare against first parent
2633 hg diff -c 9353 # compare against first parent
2643 hg diff --from 9353^ --to 9353 # same using revset syntax
2634 hg diff --from 9353^ --to 9353 # same using revset syntax
2644 hg diff --from 9353^2 --to 9353 # compare against the second parent
2635 hg diff --from 9353^2 --to 9353 # compare against the second parent
2645
2636
2646 Returns 0 on success.
2637 Returns 0 on success.
2647 """
2638 """
2648
2639
2649 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2640 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2650 opts = pycompat.byteskwargs(opts)
2641 opts = pycompat.byteskwargs(opts)
2651 revs = opts.get(b'rev')
2642 revs = opts.get(b'rev')
2652 change = opts.get(b'change')
2643 change = opts.get(b'change')
2653 from_rev = opts.get(b'from')
2644 from_rev = opts.get(b'from')
2654 to_rev = opts.get(b'to')
2645 to_rev = opts.get(b'to')
2655 stat = opts.get(b'stat')
2646 stat = opts.get(b'stat')
2656 reverse = opts.get(b'reverse')
2647 reverse = opts.get(b'reverse')
2657
2648
2658 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2649 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2659 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2650 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2660 if change:
2651 if change:
2661 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2652 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2662 ctx2 = logcmdutil.revsingle(repo, change, None)
2653 ctx2 = logcmdutil.revsingle(repo, change, None)
2663 ctx1 = diffutil.diff_parent(ctx2)
2654 ctx1 = diffutil.diff_parent(ctx2)
2664 elif from_rev or to_rev:
2655 elif from_rev or to_rev:
2665 repo = scmutil.unhidehashlikerevs(
2656 repo = scmutil.unhidehashlikerevs(
2666 repo, [from_rev] + [to_rev], b'nowarn'
2657 repo, [from_rev] + [to_rev], b'nowarn'
2667 )
2658 )
2668 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2659 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2669 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2660 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2670 else:
2661 else:
2671 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2662 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2672 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2663 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2673
2664
2674 if reverse:
2665 if reverse:
2675 ctxleft = ctx2
2666 ctxleft = ctx2
2676 ctxright = ctx1
2667 ctxright = ctx1
2677 else:
2668 else:
2678 ctxleft = ctx1
2669 ctxleft = ctx1
2679 ctxright = ctx2
2670 ctxright = ctx2
2680
2671
2681 diffopts = patch.diffallopts(ui, opts)
2672 diffopts = patch.diffallopts(ui, opts)
2682 m = scmutil.match(ctx2, pats, opts)
2673 m = scmutil.match(ctx2, pats, opts)
2683 m = repo.narrowmatch(m)
2674 m = repo.narrowmatch(m)
2684 ui.pager(b'diff')
2675 ui.pager(b'diff')
2685 logcmdutil.diffordiffstat(
2676 logcmdutil.diffordiffstat(
2686 ui,
2677 ui,
2687 repo,
2678 repo,
2688 diffopts,
2679 diffopts,
2689 ctxleft,
2680 ctxleft,
2690 ctxright,
2681 ctxright,
2691 m,
2682 m,
2692 stat=stat,
2683 stat=stat,
2693 listsubrepos=opts.get(b'subrepos'),
2684 listsubrepos=opts.get(b'subrepos'),
2694 root=opts.get(b'root'),
2685 root=opts.get(b'root'),
2695 )
2686 )
2696
2687
2697
2688
2698 @command(
2689 @command(
2699 b'export',
2690 b'export',
2700 [
2691 [
2701 (
2692 (
2702 b'B',
2693 b'B',
2703 b'bookmark',
2694 b'bookmark',
2704 b'',
2695 b'',
2705 _(b'export changes only reachable by given bookmark'),
2696 _(b'export changes only reachable by given bookmark'),
2706 _(b'BOOKMARK'),
2697 _(b'BOOKMARK'),
2707 ),
2698 ),
2708 (
2699 (
2709 b'o',
2700 b'o',
2710 b'output',
2701 b'output',
2711 b'',
2702 b'',
2712 _(b'print output to file with formatted name'),
2703 _(b'print output to file with formatted name'),
2713 _(b'FORMAT'),
2704 _(b'FORMAT'),
2714 ),
2705 ),
2715 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2706 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2716 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2707 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2717 ]
2708 ]
2718 + diffopts
2709 + diffopts
2719 + formatteropts,
2710 + formatteropts,
2720 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2711 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2721 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2712 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2722 helpbasic=True,
2713 helpbasic=True,
2723 intents={INTENT_READONLY},
2714 intents={INTENT_READONLY},
2724 )
2715 )
2725 def export(ui, repo, *changesets, **opts):
2716 def export(ui, repo, *changesets, **opts):
2726 """dump the header and diffs for one or more changesets
2717 """dump the header and diffs for one or more changesets
2727
2718
2728 Print the changeset header and diffs for one or more revisions.
2719 Print the changeset header and diffs for one or more revisions.
2729 If no revision is given, the parent of the working directory is used.
2720 If no revision is given, the parent of the working directory is used.
2730
2721
2731 The information shown in the changeset header is: author, date,
2722 The information shown in the changeset header is: author, date,
2732 branch name (if non-default), changeset hash, parent(s) and commit
2723 branch name (if non-default), changeset hash, parent(s) and commit
2733 comment.
2724 comment.
2734
2725
2735 .. note::
2726 .. note::
2736
2727
2737 :hg:`export` may generate unexpected diff output for merge
2728 :hg:`export` may generate unexpected diff output for merge
2738 changesets, as it will compare the merge changeset against its
2729 changesets, as it will compare the merge changeset against its
2739 first parent only.
2730 first parent only.
2740
2731
2741 Output may be to a file, in which case the name of the file is
2732 Output may be to a file, in which case the name of the file is
2742 given using a template string. See :hg:`help templates`. In addition
2733 given using a template string. See :hg:`help templates`. In addition
2743 to the common template keywords, the following formatting rules are
2734 to the common template keywords, the following formatting rules are
2744 supported:
2735 supported:
2745
2736
2746 :``%%``: literal "%" character
2737 :``%%``: literal "%" character
2747 :``%H``: changeset hash (40 hexadecimal digits)
2738 :``%H``: changeset hash (40 hexadecimal digits)
2748 :``%N``: number of patches being generated
2739 :``%N``: number of patches being generated
2749 :``%R``: changeset revision number
2740 :``%R``: changeset revision number
2750 :``%b``: basename of the exporting repository
2741 :``%b``: basename of the exporting repository
2751 :``%h``: short-form changeset hash (12 hexadecimal digits)
2742 :``%h``: short-form changeset hash (12 hexadecimal digits)
2752 :``%m``: first line of the commit message (only alphanumeric characters)
2743 :``%m``: first line of the commit message (only alphanumeric characters)
2753 :``%n``: zero-padded sequence number, starting at 1
2744 :``%n``: zero-padded sequence number, starting at 1
2754 :``%r``: zero-padded changeset revision number
2745 :``%r``: zero-padded changeset revision number
2755 :``\\``: literal "\\" character
2746 :``\\``: literal "\\" character
2756
2747
2757 Without the -a/--text option, export will avoid generating diffs
2748 Without the -a/--text option, export will avoid generating diffs
2758 of files it detects as binary. With -a, export will generate a
2749 of files it detects as binary. With -a, export will generate a
2759 diff anyway, probably with undesirable results.
2750 diff anyway, probably with undesirable results.
2760
2751
2761 With -B/--bookmark changesets reachable by the given bookmark are
2752 With -B/--bookmark changesets reachable by the given bookmark are
2762 selected.
2753 selected.
2763
2754
2764 Use the -g/--git option to generate diffs in the git extended diff
2755 Use the -g/--git option to generate diffs in the git extended diff
2765 format. See :hg:`help diffs` for more information.
2756 format. See :hg:`help diffs` for more information.
2766
2757
2767 With the --switch-parent option, the diff will be against the
2758 With the --switch-parent option, the diff will be against the
2768 second parent. It can be useful to review a merge.
2759 second parent. It can be useful to review a merge.
2769
2760
2770 .. container:: verbose
2761 .. container:: verbose
2771
2762
2772 Template:
2763 Template:
2773
2764
2774 The following keywords are supported in addition to the common template
2765 The following keywords are supported in addition to the common template
2775 keywords and functions. See also :hg:`help templates`.
2766 keywords and functions. See also :hg:`help templates`.
2776
2767
2777 :diff: String. Diff content.
2768 :diff: String. Diff content.
2778 :parents: List of strings. Parent nodes of the changeset.
2769 :parents: List of strings. Parent nodes of the changeset.
2779
2770
2780 Examples:
2771 Examples:
2781
2772
2782 - use export and import to transplant a bugfix to the current
2773 - use export and import to transplant a bugfix to the current
2783 branch::
2774 branch::
2784
2775
2785 hg export -r 9353 | hg import -
2776 hg export -r 9353 | hg import -
2786
2777
2787 - export all the changesets between two revisions to a file with
2778 - export all the changesets between two revisions to a file with
2788 rename information::
2779 rename information::
2789
2780
2790 hg export --git -r 123:150 > changes.txt
2781 hg export --git -r 123:150 > changes.txt
2791
2782
2792 - split outgoing changes into a series of patches with
2783 - split outgoing changes into a series of patches with
2793 descriptive names::
2784 descriptive names::
2794
2785
2795 hg export -r "outgoing()" -o "%n-%m.patch"
2786 hg export -r "outgoing()" -o "%n-%m.patch"
2796
2787
2797 Returns 0 on success.
2788 Returns 0 on success.
2798 """
2789 """
2799 opts = pycompat.byteskwargs(opts)
2790 opts = pycompat.byteskwargs(opts)
2800 bookmark = opts.get(b'bookmark')
2791 bookmark = opts.get(b'bookmark')
2801 changesets += tuple(opts.get(b'rev', []))
2792 changesets += tuple(opts.get(b'rev', []))
2802
2793
2803 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2794 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2804
2795
2805 if bookmark:
2796 if bookmark:
2806 if bookmark not in repo._bookmarks:
2797 if bookmark not in repo._bookmarks:
2807 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2798 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2808
2799
2809 revs = scmutil.bookmarkrevs(repo, bookmark)
2800 revs = scmutil.bookmarkrevs(repo, bookmark)
2810 else:
2801 else:
2811 if not changesets:
2802 if not changesets:
2812 changesets = [b'.']
2803 changesets = [b'.']
2813
2804
2814 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2805 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2815 revs = logcmdutil.revrange(repo, changesets)
2806 revs = logcmdutil.revrange(repo, changesets)
2816
2807
2817 if not revs:
2808 if not revs:
2818 raise error.InputError(_(b"export requires at least one changeset"))
2809 raise error.InputError(_(b"export requires at least one changeset"))
2819 if len(revs) > 1:
2810 if len(revs) > 1:
2820 ui.note(_(b'exporting patches:\n'))
2811 ui.note(_(b'exporting patches:\n'))
2821 else:
2812 else:
2822 ui.note(_(b'exporting patch:\n'))
2813 ui.note(_(b'exporting patch:\n'))
2823
2814
2824 fntemplate = opts.get(b'output')
2815 fntemplate = opts.get(b'output')
2825 if cmdutil.isstdiofilename(fntemplate):
2816 if cmdutil.isstdiofilename(fntemplate):
2826 fntemplate = b''
2817 fntemplate = b''
2827
2818
2828 if fntemplate:
2819 if fntemplate:
2829 fm = formatter.nullformatter(ui, b'export', opts)
2820 fm = formatter.nullformatter(ui, b'export', opts)
2830 else:
2821 else:
2831 ui.pager(b'export')
2822 ui.pager(b'export')
2832 fm = ui.formatter(b'export', opts)
2823 fm = ui.formatter(b'export', opts)
2833 with fm:
2824 with fm:
2834 cmdutil.export(
2825 cmdutil.export(
2835 repo,
2826 repo,
2836 revs,
2827 revs,
2837 fm,
2828 fm,
2838 fntemplate=fntemplate,
2829 fntemplate=fntemplate,
2839 switch_parent=opts.get(b'switch_parent'),
2830 switch_parent=opts.get(b'switch_parent'),
2840 opts=patch.diffallopts(ui, opts),
2831 opts=patch.diffallopts(ui, opts),
2841 )
2832 )
2842
2833
2843
2834
2844 @command(
2835 @command(
2845 b'files',
2836 b'files',
2846 [
2837 [
2847 (
2838 (
2848 b'r',
2839 b'r',
2849 b'rev',
2840 b'rev',
2850 b'',
2841 b'',
2851 _(b'search the repository as it is in REV'),
2842 _(b'search the repository as it is in REV'),
2852 _(b'REV'),
2843 _(b'REV'),
2853 ),
2844 ),
2854 (
2845 (
2855 b'0',
2846 b'0',
2856 b'print0',
2847 b'print0',
2857 None,
2848 None,
2858 _(b'end filenames with NUL, for use with xargs'),
2849 _(b'end filenames with NUL, for use with xargs'),
2859 ),
2850 ),
2860 ]
2851 ]
2861 + walkopts
2852 + walkopts
2862 + formatteropts
2853 + formatteropts
2863 + subrepoopts,
2854 + subrepoopts,
2864 _(b'[OPTION]... [FILE]...'),
2855 _(b'[OPTION]... [FILE]...'),
2865 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2856 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2866 intents={INTENT_READONLY},
2857 intents={INTENT_READONLY},
2867 )
2858 )
2868 def files(ui, repo, *pats, **opts):
2859 def files(ui, repo, *pats, **opts):
2869 """list tracked files
2860 """list tracked files
2870
2861
2871 Print files under Mercurial control in the working directory or
2862 Print files under Mercurial control in the working directory or
2872 specified revision for given files (excluding removed files).
2863 specified revision for given files (excluding removed files).
2873 Files can be specified as filenames or filesets.
2864 Files can be specified as filenames or filesets.
2874
2865
2875 If no files are given to match, this command prints the names
2866 If no files are given to match, this command prints the names
2876 of all files under Mercurial control.
2867 of all files under Mercurial control.
2877
2868
2878 .. container:: verbose
2869 .. container:: verbose
2879
2870
2880 Template:
2871 Template:
2881
2872
2882 The following keywords are supported in addition to the common template
2873 The following keywords are supported in addition to the common template
2883 keywords and functions. See also :hg:`help templates`.
2874 keywords and functions. See also :hg:`help templates`.
2884
2875
2885 :flags: String. Character denoting file's symlink and executable bits.
2876 :flags: String. Character denoting file's symlink and executable bits.
2886 :path: String. Repository-absolute path of the file.
2877 :path: String. Repository-absolute path of the file.
2887 :size: Integer. Size of the file in bytes.
2878 :size: Integer. Size of the file in bytes.
2888
2879
2889 Examples:
2880 Examples:
2890
2881
2891 - list all files under the current directory::
2882 - list all files under the current directory::
2892
2883
2893 hg files .
2884 hg files .
2894
2885
2895 - shows sizes and flags for current revision::
2886 - shows sizes and flags for current revision::
2896
2887
2897 hg files -vr .
2888 hg files -vr .
2898
2889
2899 - list all files named README::
2890 - list all files named README::
2900
2891
2901 hg files -I "**/README"
2892 hg files -I "**/README"
2902
2893
2903 - list all binary files::
2894 - list all binary files::
2904
2895
2905 hg files "set:binary()"
2896 hg files "set:binary()"
2906
2897
2907 - find files containing a regular expression::
2898 - find files containing a regular expression::
2908
2899
2909 hg files "set:grep('bob')"
2900 hg files "set:grep('bob')"
2910
2901
2911 - search tracked file contents with xargs and grep::
2902 - search tracked file contents with xargs and grep::
2912
2903
2913 hg files -0 | xargs -0 grep foo
2904 hg files -0 | xargs -0 grep foo
2914
2905
2915 See :hg:`help patterns` and :hg:`help filesets` for more information
2906 See :hg:`help patterns` and :hg:`help filesets` for more information
2916 on specifying file patterns.
2907 on specifying file patterns.
2917
2908
2918 Returns 0 if a match is found, 1 otherwise.
2909 Returns 0 if a match is found, 1 otherwise.
2919
2910
2920 """
2911 """
2921
2912
2922 opts = pycompat.byteskwargs(opts)
2913 opts = pycompat.byteskwargs(opts)
2923 rev = opts.get(b'rev')
2914 rev = opts.get(b'rev')
2924 if rev:
2915 if rev:
2925 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2916 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2926 ctx = logcmdutil.revsingle(repo, rev, None)
2917 ctx = logcmdutil.revsingle(repo, rev, None)
2927
2918
2928 end = b'\n'
2919 end = b'\n'
2929 if opts.get(b'print0'):
2920 if opts.get(b'print0'):
2930 end = b'\0'
2921 end = b'\0'
2931 fmt = b'%s' + end
2922 fmt = b'%s' + end
2932
2923
2933 m = scmutil.match(ctx, pats, opts)
2924 m = scmutil.match(ctx, pats, opts)
2934 ui.pager(b'files')
2925 ui.pager(b'files')
2935 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2926 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2936 with ui.formatter(b'files', opts) as fm:
2927 with ui.formatter(b'files', opts) as fm:
2937 return cmdutil.files(
2928 return cmdutil.files(
2938 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2929 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2939 )
2930 )
2940
2931
2941
2932
2942 @command(
2933 @command(
2943 b'forget',
2934 b'forget',
2944 [
2935 [
2945 (b'i', b'interactive', None, _(b'use interactive mode')),
2936 (b'i', b'interactive', None, _(b'use interactive mode')),
2946 ]
2937 ]
2947 + walkopts
2938 + walkopts
2948 + dryrunopts,
2939 + dryrunopts,
2949 _(b'[OPTION]... FILE...'),
2940 _(b'[OPTION]... FILE...'),
2950 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2941 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2951 helpbasic=True,
2942 helpbasic=True,
2952 inferrepo=True,
2943 inferrepo=True,
2953 )
2944 )
2954 def forget(ui, repo, *pats, **opts):
2945 def forget(ui, repo, *pats, **opts):
2955 """forget the specified files on the next commit
2946 """forget the specified files on the next commit
2956
2947
2957 Mark the specified files so they will no longer be tracked
2948 Mark the specified files so they will no longer be tracked
2958 after the next commit.
2949 after the next commit.
2959
2950
2960 This only removes files from the current branch, not from the
2951 This only removes files from the current branch, not from the
2961 entire project history, and it does not delete them from the
2952 entire project history, and it does not delete them from the
2962 working directory.
2953 working directory.
2963
2954
2964 To delete the file from the working directory, see :hg:`remove`.
2955 To delete the file from the working directory, see :hg:`remove`.
2965
2956
2966 To undo a forget before the next commit, see :hg:`add`.
2957 To undo a forget before the next commit, see :hg:`add`.
2967
2958
2968 .. container:: verbose
2959 .. container:: verbose
2969
2960
2970 Examples:
2961 Examples:
2971
2962
2972 - forget newly-added binary files::
2963 - forget newly-added binary files::
2973
2964
2974 hg forget "set:added() and binary()"
2965 hg forget "set:added() and binary()"
2975
2966
2976 - forget files that would be excluded by .hgignore::
2967 - forget files that would be excluded by .hgignore::
2977
2968
2978 hg forget "set:hgignore()"
2969 hg forget "set:hgignore()"
2979
2970
2980 Returns 0 on success.
2971 Returns 0 on success.
2981 """
2972 """
2982
2973
2983 if not pats:
2974 if not pats:
2984 raise error.InputError(_(b'no files specified'))
2975 raise error.InputError(_(b'no files specified'))
2985
2976
2986 with repo.wlock(), repo.dirstate.changing_files(repo):
2977 with repo.wlock(), repo.dirstate.changing_files(repo):
2987 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2978 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2988 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2979 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2989 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2980 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2990 rejected = cmdutil.forget(
2981 rejected = cmdutil.forget(
2991 ui,
2982 ui,
2992 repo,
2983 repo,
2993 m,
2984 m,
2994 prefix=b"",
2985 prefix=b"",
2995 uipathfn=uipathfn,
2986 uipathfn=uipathfn,
2996 explicitonly=False,
2987 explicitonly=False,
2997 dryrun=dryrun,
2988 dryrun=dryrun,
2998 interactive=interactive,
2989 interactive=interactive,
2999 )[0]
2990 )[0]
3000 return rejected and 1 or 0
2991 return rejected and 1 or 0
3001
2992
3002
2993
3003 @command(
2994 @command(
3004 b'graft',
2995 b'graft',
3005 [
2996 [
3006 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2997 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3007 (
2998 (
3008 b'',
2999 b'',
3009 b'base',
3000 b'base',
3010 b'',
3001 b'',
3011 _(b'base revision when doing the graft merge (ADVANCED)'),
3002 _(b'base revision when doing the graft merge (ADVANCED)'),
3012 _(b'REV'),
3003 _(b'REV'),
3013 ),
3004 ),
3014 (b'c', b'continue', False, _(b'resume interrupted graft')),
3005 (b'c', b'continue', False, _(b'resume interrupted graft')),
3015 (b'', b'stop', False, _(b'stop interrupted graft')),
3006 (b'', b'stop', False, _(b'stop interrupted graft')),
3016 (b'', b'abort', False, _(b'abort interrupted graft')),
3007 (b'', b'abort', False, _(b'abort interrupted graft')),
3017 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3008 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3018 (b'', b'log', None, _(b'append graft info to log message')),
3009 (b'', b'log', None, _(b'append graft info to log message')),
3019 (
3010 (
3020 b'',
3011 b'',
3021 b'no-commit',
3012 b'no-commit',
3022 None,
3013 None,
3023 _(b"don't commit, just apply the changes in working directory"),
3014 _(b"don't commit, just apply the changes in working directory"),
3024 ),
3015 ),
3025 (b'f', b'force', False, _(b'force graft')),
3016 (b'f', b'force', False, _(b'force graft')),
3026 (
3017 (
3027 b'D',
3018 b'D',
3028 b'currentdate',
3019 b'currentdate',
3029 False,
3020 False,
3030 _(b'record the current date as commit date'),
3021 _(b'record the current date as commit date'),
3031 ),
3022 ),
3032 (
3023 (
3033 b'U',
3024 b'U',
3034 b'currentuser',
3025 b'currentuser',
3035 False,
3026 False,
3036 _(b'record the current user as committer'),
3027 _(b'record the current user as committer'),
3037 ),
3028 ),
3038 ]
3029 ]
3039 + commitopts2
3030 + commitopts2
3040 + mergetoolopts
3031 + mergetoolopts
3041 + dryrunopts,
3032 + dryrunopts,
3042 _(b'[OPTION]... [-r REV]... REV...'),
3033 _(b'[OPTION]... [-r REV]... REV...'),
3043 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3034 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3044 )
3035 )
3045 def graft(ui, repo, *revs, **opts):
3036 def graft(ui, repo, *revs, **opts):
3046 """copy changes from other branches onto the current branch
3037 """copy changes from other branches onto the current branch
3047
3038
3048 This command uses Mercurial's merge logic to copy individual
3039 This command uses Mercurial's merge logic to copy individual
3049 changes from other branches without merging branches in the
3040 changes from other branches without merging branches in the
3050 history graph. This is sometimes known as 'backporting' or
3041 history graph. This is sometimes known as 'backporting' or
3051 'cherry-picking'. By default, graft will copy user, date, and
3042 'cherry-picking'. By default, graft will copy user, date, and
3052 description from the source changesets.
3043 description from the source changesets.
3053
3044
3054 Changesets that are ancestors of the current revision, that have
3045 Changesets that are ancestors of the current revision, that have
3055 already been grafted, or that are merges will be skipped.
3046 already been grafted, or that are merges will be skipped.
3056
3047
3057 If --log is specified, log messages will have a comment appended
3048 If --log is specified, log messages will have a comment appended
3058 of the form::
3049 of the form::
3059
3050
3060 (grafted from CHANGESETHASH)
3051 (grafted from CHANGESETHASH)
3061
3052
3062 If --force is specified, revisions will be grafted even if they
3053 If --force is specified, revisions will be grafted even if they
3063 are already ancestors of, or have been grafted to, the destination.
3054 are already ancestors of, or have been grafted to, the destination.
3064 This is useful when the revisions have since been backed out.
3055 This is useful when the revisions have since been backed out.
3065
3056
3066 If a graft merge results in conflicts, the graft process is
3057 If a graft merge results in conflicts, the graft process is
3067 interrupted so that the current merge can be manually resolved.
3058 interrupted so that the current merge can be manually resolved.
3068 Once all conflicts are addressed, the graft process can be
3059 Once all conflicts are addressed, the graft process can be
3069 continued with the -c/--continue option.
3060 continued with the -c/--continue option.
3070
3061
3071 The -c/--continue option reapplies all the earlier options.
3062 The -c/--continue option reapplies all the earlier options.
3072
3063
3073 .. container:: verbose
3064 .. container:: verbose
3074
3065
3075 The --base option exposes more of how graft internally uses merge with a
3066 The --base option exposes more of how graft internally uses merge with a
3076 custom base revision. --base can be used to specify another ancestor than
3067 custom base revision. --base can be used to specify another ancestor than
3077 the first and only parent.
3068 the first and only parent.
3078
3069
3079 The command::
3070 The command::
3080
3071
3081 hg graft -r 345 --base 234
3072 hg graft -r 345 --base 234
3082
3073
3083 is thus pretty much the same as::
3074 is thus pretty much the same as::
3084
3075
3085 hg diff --from 234 --to 345 | hg import
3076 hg diff --from 234 --to 345 | hg import
3086
3077
3087 but using merge to resolve conflicts and track moved files.
3078 but using merge to resolve conflicts and track moved files.
3088
3079
3089 The result of a merge can thus be backported as a single commit by
3080 The result of a merge can thus be backported as a single commit by
3090 specifying one of the merge parents as base, and thus effectively
3081 specifying one of the merge parents as base, and thus effectively
3091 grafting the changes from the other side.
3082 grafting the changes from the other side.
3092
3083
3093 It is also possible to collapse multiple changesets and clean up history
3084 It is also possible to collapse multiple changesets and clean up history
3094 by specifying another ancestor as base, much like rebase --collapse
3085 by specifying another ancestor as base, much like rebase --collapse
3095 --keep.
3086 --keep.
3096
3087
3097 The commit message can be tweaked after the fact using commit --amend .
3088 The commit message can be tweaked after the fact using commit --amend .
3098
3089
3099 For using non-ancestors as the base to backout changes, see the backout
3090 For using non-ancestors as the base to backout changes, see the backout
3100 command and the hidden --parent option.
3091 command and the hidden --parent option.
3101
3092
3102 .. container:: verbose
3093 .. container:: verbose
3103
3094
3104 Examples:
3095 Examples:
3105
3096
3106 - copy a single change to the stable branch and edit its description::
3097 - copy a single change to the stable branch and edit its description::
3107
3098
3108 hg update stable
3099 hg update stable
3109 hg graft --edit 9393
3100 hg graft --edit 9393
3110
3101
3111 - graft a range of changesets with one exception, updating dates::
3102 - graft a range of changesets with one exception, updating dates::
3112
3103
3113 hg graft -D "2085::2093 and not 2091"
3104 hg graft -D "2085::2093 and not 2091"
3114
3105
3115 - continue a graft after resolving conflicts::
3106 - continue a graft after resolving conflicts::
3116
3107
3117 hg graft -c
3108 hg graft -c
3118
3109
3119 - show the source of a grafted changeset::
3110 - show the source of a grafted changeset::
3120
3111
3121 hg log --debug -r .
3112 hg log --debug -r .
3122
3113
3123 - show revisions sorted by date::
3114 - show revisions sorted by date::
3124
3115
3125 hg log -r "sort(all(), date)"
3116 hg log -r "sort(all(), date)"
3126
3117
3127 - backport the result of a merge as a single commit::
3118 - backport the result of a merge as a single commit::
3128
3119
3129 hg graft -r 123 --base 123^
3120 hg graft -r 123 --base 123^
3130
3121
3131 - land a feature branch as one changeset::
3122 - land a feature branch as one changeset::
3132
3123
3133 hg up -cr default
3124 hg up -cr default
3134 hg graft -r featureX --base "ancestor('featureX', 'default')"
3125 hg graft -r featureX --base "ancestor('featureX', 'default')"
3135
3126
3136 See :hg:`help revisions` for more about specifying revisions.
3127 See :hg:`help revisions` for more about specifying revisions.
3137
3128
3138 Returns 0 on successful completion, 1 if there are unresolved files.
3129 Returns 0 on successful completion, 1 if there are unresolved files.
3139 """
3130 """
3140 with repo.wlock():
3131 with repo.wlock():
3141 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3132 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3142
3133
3143
3134
3144 statemod.addunfinished(
3135 statemod.addunfinished(
3145 b'graft',
3136 b'graft',
3146 fname=b'graftstate',
3137 fname=b'graftstate',
3147 clearable=True,
3138 clearable=True,
3148 stopflag=True,
3139 stopflag=True,
3149 continueflag=True,
3140 continueflag=True,
3150 abortfunc=cmdutil.hgabortgraft,
3141 abortfunc=cmdutil.hgabortgraft,
3151 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3142 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3152 )
3143 )
3153
3144
3154
3145
3155 @command(
3146 @command(
3156 b'grep',
3147 b'grep',
3157 [
3148 [
3158 (b'0', b'print0', None, _(b'end fields with NUL')),
3149 (b'0', b'print0', None, _(b'end fields with NUL')),
3159 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3150 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3160 (
3151 (
3161 b'',
3152 b'',
3162 b'diff',
3153 b'diff',
3163 None,
3154 None,
3164 _(
3155 _(
3165 b'search revision differences for when the pattern was added '
3156 b'search revision differences for when the pattern was added '
3166 b'or removed'
3157 b'or removed'
3167 ),
3158 ),
3168 ),
3159 ),
3169 (b'a', b'text', None, _(b'treat all files as text')),
3160 (b'a', b'text', None, _(b'treat all files as text')),
3170 (
3161 (
3171 b'f',
3162 b'f',
3172 b'follow',
3163 b'follow',
3173 None,
3164 None,
3174 _(
3165 _(
3175 b'follow changeset history,'
3166 b'follow changeset history,'
3176 b' or file history across copies and renames'
3167 b' or file history across copies and renames'
3177 ),
3168 ),
3178 ),
3169 ),
3179 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3170 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3180 (
3171 (
3181 b'l',
3172 b'l',
3182 b'files-with-matches',
3173 b'files-with-matches',
3183 None,
3174 None,
3184 _(b'print only filenames and revisions that match'),
3175 _(b'print only filenames and revisions that match'),
3185 ),
3176 ),
3186 (b'n', b'line-number', None, _(b'print matching line numbers')),
3177 (b'n', b'line-number', None, _(b'print matching line numbers')),
3187 (
3178 (
3188 b'r',
3179 b'r',
3189 b'rev',
3180 b'rev',
3190 [],
3181 [],
3191 _(b'search files changed within revision range'),
3182 _(b'search files changed within revision range'),
3192 _(b'REV'),
3183 _(b'REV'),
3193 ),
3184 ),
3194 (
3185 (
3195 b'',
3186 b'',
3196 b'all-files',
3187 b'all-files',
3197 None,
3188 None,
3198 _(
3189 _(
3199 b'include all files in the changeset while grepping (DEPRECATED)'
3190 b'include all files in the changeset while grepping (DEPRECATED)'
3200 ),
3191 ),
3201 ),
3192 ),
3202 (b'u', b'user', None, _(b'list the author (long with -v)')),
3193 (b'u', b'user', None, _(b'list the author (long with -v)')),
3203 (b'd', b'date', None, _(b'list the date (short with -q)')),
3194 (b'd', b'date', None, _(b'list the date (short with -q)')),
3204 ]
3195 ]
3205 + formatteropts
3196 + formatteropts
3206 + walkopts,
3197 + walkopts,
3207 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3198 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3208 helpcategory=command.CATEGORY_FILE_CONTENTS,
3199 helpcategory=command.CATEGORY_FILE_CONTENTS,
3209 inferrepo=True,
3200 inferrepo=True,
3210 intents={INTENT_READONLY},
3201 intents={INTENT_READONLY},
3211 )
3202 )
3212 def grep(ui, repo, pattern, *pats, **opts):
3203 def grep(ui, repo, pattern, *pats, **opts):
3213 """search for a pattern in specified files
3204 """search for a pattern in specified files
3214
3205
3215 Search the working directory or revision history for a regular
3206 Search the working directory or revision history for a regular
3216 expression in the specified files for the entire repository.
3207 expression in the specified files for the entire repository.
3217
3208
3218 By default, grep searches the repository files in the working
3209 By default, grep searches the repository files in the working
3219 directory and prints the files where it finds a match. To specify
3210 directory and prints the files where it finds a match. To specify
3220 historical revisions instead of the working directory, use the
3211 historical revisions instead of the working directory, use the
3221 --rev flag.
3212 --rev flag.
3222
3213
3223 To search instead historical revision differences that contains a
3214 To search instead historical revision differences that contains a
3224 change in match status ("-" for a match that becomes a non-match,
3215 change in match status ("-" for a match that becomes a non-match,
3225 or "+" for a non-match that becomes a match), use the --diff flag.
3216 or "+" for a non-match that becomes a match), use the --diff flag.
3226
3217
3227 PATTERN can be any Python (roughly Perl-compatible) regular
3218 PATTERN can be any Python (roughly Perl-compatible) regular
3228 expression.
3219 expression.
3229
3220
3230 If no FILEs are specified and the --rev flag isn't supplied, all
3221 If no FILEs are specified and the --rev flag isn't supplied, all
3231 files in the working directory are searched. When using the --rev
3222 files in the working directory are searched. When using the --rev
3232 flag and specifying FILEs, use the --follow argument to also
3223 flag and specifying FILEs, use the --follow argument to also
3233 follow the specified FILEs across renames and copies.
3224 follow the specified FILEs across renames and copies.
3234
3225
3235 .. container:: verbose
3226 .. container:: verbose
3236
3227
3237 Template:
3228 Template:
3238
3229
3239 The following keywords are supported in addition to the common template
3230 The following keywords are supported in addition to the common template
3240 keywords and functions. See also :hg:`help templates`.
3231 keywords and functions. See also :hg:`help templates`.
3241
3232
3242 :change: String. Character denoting insertion ``+`` or removal ``-``.
3233 :change: String. Character denoting insertion ``+`` or removal ``-``.
3243 Available if ``--diff`` is specified.
3234 Available if ``--diff`` is specified.
3244 :lineno: Integer. Line number of the match.
3235 :lineno: Integer. Line number of the match.
3245 :path: String. Repository-absolute path of the file.
3236 :path: String. Repository-absolute path of the file.
3246 :texts: List of text chunks.
3237 :texts: List of text chunks.
3247
3238
3248 And each entry of ``{texts}`` provides the following sub-keywords.
3239 And each entry of ``{texts}`` provides the following sub-keywords.
3249
3240
3250 :matched: Boolean. True if the chunk matches the specified pattern.
3241 :matched: Boolean. True if the chunk matches the specified pattern.
3251 :text: String. Chunk content.
3242 :text: String. Chunk content.
3252
3243
3253 See :hg:`help templates.operators` for the list expansion syntax.
3244 See :hg:`help templates.operators` for the list expansion syntax.
3254
3245
3255 Returns 0 if a match is found, 1 otherwise.
3246 Returns 0 if a match is found, 1 otherwise.
3256
3247
3257 """
3248 """
3258 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3249 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3259
3250
3260 diff = opts.get('all') or opts.get('diff')
3251 diff = opts.get('all') or opts.get('diff')
3261 follow = opts.get('follow')
3252 follow = opts.get('follow')
3262 if opts.get('all_files') is None and not diff:
3253 if opts.get('all_files') is None and not diff:
3263 opts['all_files'] = True
3254 opts['all_files'] = True
3264 plaingrep = (
3255 plaingrep = (
3265 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3256 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3266 )
3257 )
3267 all_files = opts.get('all_files')
3258 all_files = opts.get('all_files')
3268 if plaingrep:
3259 if plaingrep:
3269 opts['rev'] = [b'wdir()']
3260 opts['rev'] = [b'wdir()']
3270
3261
3271 reflags = re.M
3262 reflags = re.M
3272 if opts.get('ignore_case'):
3263 if opts.get('ignore_case'):
3273 reflags |= re.I
3264 reflags |= re.I
3274 try:
3265 try:
3275 regexp = util.re.compile(pattern, reflags)
3266 regexp = util.re.compile(pattern, reflags)
3276 except re.error as inst:
3267 except re.error as inst:
3277 ui.warn(
3268 ui.warn(
3278 _(b"grep: invalid match pattern: %s\n")
3269 _(b"grep: invalid match pattern: %s\n")
3279 % stringutil.forcebytestr(inst)
3270 % stringutil.forcebytestr(inst)
3280 )
3271 )
3281 return 1
3272 return 1
3282 sep, eol = b':', b'\n'
3273 sep, eol = b':', b'\n'
3283 if opts.get('print0'):
3274 if opts.get('print0'):
3284 sep = eol = b'\0'
3275 sep = eol = b'\0'
3285
3276
3286 searcher = grepmod.grepsearcher(
3277 searcher = grepmod.grepsearcher(
3287 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3278 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3288 )
3279 )
3289
3280
3290 getfile = searcher._getfile
3281 getfile = searcher._getfile
3291
3282
3292 uipathfn = scmutil.getuipathfn(repo)
3283 uipathfn = scmutil.getuipathfn(repo)
3293
3284
3294 def display(fm, fn, ctx, pstates, states):
3285 def display(fm, fn, ctx, pstates, states):
3295 rev = scmutil.intrev(ctx)
3286 rev = scmutil.intrev(ctx)
3296 if fm.isplain():
3287 if fm.isplain():
3297 formatuser = ui.shortuser
3288 formatuser = ui.shortuser
3298 else:
3289 else:
3299 formatuser = pycompat.bytestr
3290 formatuser = pycompat.bytestr
3300 if ui.quiet:
3291 if ui.quiet:
3301 datefmt = b'%Y-%m-%d'
3292 datefmt = b'%Y-%m-%d'
3302 else:
3293 else:
3303 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3294 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3304 found = False
3295 found = False
3305
3296
3306 @util.cachefunc
3297 @util.cachefunc
3307 def binary():
3298 def binary():
3308 flog = getfile(fn)
3299 flog = getfile(fn)
3309 try:
3300 try:
3310 return stringutil.binary(flog.read(ctx.filenode(fn)))
3301 return stringutil.binary(flog.read(ctx.filenode(fn)))
3311 except error.WdirUnsupported:
3302 except error.WdirUnsupported:
3312 return ctx[fn].isbinary()
3303 return ctx[fn].isbinary()
3313
3304
3314 fieldnamemap = {b'linenumber': b'lineno'}
3305 fieldnamemap = {b'linenumber': b'lineno'}
3315 if diff:
3306 if diff:
3316 iter = grepmod.difflinestates(pstates, states)
3307 iter = grepmod.difflinestates(pstates, states)
3317 else:
3308 else:
3318 iter = [(b'', l) for l in states]
3309 iter = [(b'', l) for l in states]
3319 for change, l in iter:
3310 for change, l in iter:
3320 fm.startitem()
3311 fm.startitem()
3321 fm.context(ctx=ctx)
3312 fm.context(ctx=ctx)
3322 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3313 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3323 fm.plain(uipathfn(fn), label=b'grep.filename')
3314 fm.plain(uipathfn(fn), label=b'grep.filename')
3324
3315
3325 cols = [
3316 cols = [
3326 (b'rev', b'%d', rev, not plaingrep, b''),
3317 (b'rev', b'%d', rev, not plaingrep, b''),
3327 (
3318 (
3328 b'linenumber',
3319 b'linenumber',
3329 b'%d',
3320 b'%d',
3330 l.linenum,
3321 l.linenum,
3331 opts.get('line_number'),
3322 opts.get('line_number'),
3332 b'',
3323 b'',
3333 ),
3324 ),
3334 ]
3325 ]
3335 if diff:
3326 if diff:
3336 cols.append(
3327 cols.append(
3337 (
3328 (
3338 b'change',
3329 b'change',
3339 b'%s',
3330 b'%s',
3340 change,
3331 change,
3341 True,
3332 True,
3342 b'grep.inserted '
3333 b'grep.inserted '
3343 if change == b'+'
3334 if change == b'+'
3344 else b'grep.deleted ',
3335 else b'grep.deleted ',
3345 )
3336 )
3346 )
3337 )
3347 cols.extend(
3338 cols.extend(
3348 [
3339 [
3349 (
3340 (
3350 b'user',
3341 b'user',
3351 b'%s',
3342 b'%s',
3352 formatuser(ctx.user()),
3343 formatuser(ctx.user()),
3353 opts.get('user'),
3344 opts.get('user'),
3354 b'',
3345 b'',
3355 ),
3346 ),
3356 (
3347 (
3357 b'date',
3348 b'date',
3358 b'%s',
3349 b'%s',
3359 fm.formatdate(ctx.date(), datefmt),
3350 fm.formatdate(ctx.date(), datefmt),
3360 opts.get('date'),
3351 opts.get('date'),
3361 b'',
3352 b'',
3362 ),
3353 ),
3363 ]
3354 ]
3364 )
3355 )
3365 for name, fmt, data, cond, extra_label in cols:
3356 for name, fmt, data, cond, extra_label in cols:
3366 if cond:
3357 if cond:
3367 fm.plain(sep, label=b'grep.sep')
3358 fm.plain(sep, label=b'grep.sep')
3368 field = fieldnamemap.get(name, name)
3359 field = fieldnamemap.get(name, name)
3369 label = extra_label + (b'grep.%s' % name)
3360 label = extra_label + (b'grep.%s' % name)
3370 fm.condwrite(cond, field, fmt, data, label=label)
3361 fm.condwrite(cond, field, fmt, data, label=label)
3371 if not opts.get('files_with_matches'):
3362 if not opts.get('files_with_matches'):
3372 fm.plain(sep, label=b'grep.sep')
3363 fm.plain(sep, label=b'grep.sep')
3373 if not opts.get('text') and binary():
3364 if not opts.get('text') and binary():
3374 fm.plain(_(b" Binary file matches"))
3365 fm.plain(_(b" Binary file matches"))
3375 else:
3366 else:
3376 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3367 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3377 fm.plain(eol)
3368 fm.plain(eol)
3378 found = True
3369 found = True
3379 if opts.get('files_with_matches'):
3370 if opts.get('files_with_matches'):
3380 break
3371 break
3381 return found
3372 return found
3382
3373
3383 def displaymatches(fm, l):
3374 def displaymatches(fm, l):
3384 p = 0
3375 p = 0
3385 for s, e in l.findpos(regexp):
3376 for s, e in l.findpos(regexp):
3386 if p < s:
3377 if p < s:
3387 fm.startitem()
3378 fm.startitem()
3388 fm.write(b'text', b'%s', l.line[p:s])
3379 fm.write(b'text', b'%s', l.line[p:s])
3389 fm.data(matched=False)
3380 fm.data(matched=False)
3390 fm.startitem()
3381 fm.startitem()
3391 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3382 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3392 fm.data(matched=True)
3383 fm.data(matched=True)
3393 p = e
3384 p = e
3394 if p < len(l.line):
3385 if p < len(l.line):
3395 fm.startitem()
3386 fm.startitem()
3396 fm.write(b'text', b'%s', l.line[p:])
3387 fm.write(b'text', b'%s', l.line[p:])
3397 fm.data(matched=False)
3388 fm.data(matched=False)
3398 fm.end()
3389 fm.end()
3399
3390
3400 found = False
3391 found = False
3401
3392
3402 wopts = logcmdutil.walkopts(
3393 wopts = logcmdutil.walkopts(
3403 pats=pats,
3394 pats=pats,
3404 opts=pycompat.byteskwargs(opts),
3395 opts=pycompat.byteskwargs(opts),
3405 revspec=opts['rev'],
3396 revspec=opts['rev'],
3406 include_pats=opts['include'],
3397 include_pats=opts['include'],
3407 exclude_pats=opts['exclude'],
3398 exclude_pats=opts['exclude'],
3408 follow=follow,
3399 follow=follow,
3409 force_changelog_traversal=all_files,
3400 force_changelog_traversal=all_files,
3410 filter_revisions_by_pats=not all_files,
3401 filter_revisions_by_pats=not all_files,
3411 )
3402 )
3412 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3403 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3413
3404
3414 ui.pager(b'grep')
3405 ui.pager(b'grep')
3415 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3406 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3416 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3407 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3417 r = display(fm, fn, ctx, pstates, states)
3408 r = display(fm, fn, ctx, pstates, states)
3418 found = found or r
3409 found = found or r
3419 if r and not diff and not all_files:
3410 if r and not diff and not all_files:
3420 searcher.skipfile(fn, ctx.rev())
3411 searcher.skipfile(fn, ctx.rev())
3421 fm.end()
3412 fm.end()
3422
3413
3423 return not found
3414 return not found
3424
3415
3425
3416
3426 @command(
3417 @command(
3427 b'heads',
3418 b'heads',
3428 [
3419 [
3429 (
3420 (
3430 b'r',
3421 b'r',
3431 b'rev',
3422 b'rev',
3432 b'',
3423 b'',
3433 _(b'show only heads which are descendants of STARTREV'),
3424 _(b'show only heads which are descendants of STARTREV'),
3434 _(b'STARTREV'),
3425 _(b'STARTREV'),
3435 ),
3426 ),
3436 (b't', b'topo', False, _(b'show topological heads only')),
3427 (b't', b'topo', False, _(b'show topological heads only')),
3437 (
3428 (
3438 b'a',
3429 b'a',
3439 b'active',
3430 b'active',
3440 False,
3431 False,
3441 _(b'show active branchheads only (DEPRECATED)'),
3432 _(b'show active branchheads only (DEPRECATED)'),
3442 ),
3433 ),
3443 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3434 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3444 ]
3435 ]
3445 + templateopts,
3436 + templateopts,
3446 _(b'[-ct] [-r STARTREV] [REV]...'),
3437 _(b'[-ct] [-r STARTREV] [REV]...'),
3447 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3438 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3448 intents={INTENT_READONLY},
3439 intents={INTENT_READONLY},
3449 )
3440 )
3450 def heads(ui, repo, *branchrevs, **opts):
3441 def heads(ui, repo, *branchrevs, **opts):
3451 """show branch heads
3442 """show branch heads
3452
3443
3453 With no arguments, show all open branch heads in the repository.
3444 With no arguments, show all open branch heads in the repository.
3454 Branch heads are changesets that have no descendants on the
3445 Branch heads are changesets that have no descendants on the
3455 same branch. They are where development generally takes place and
3446 same branch. They are where development generally takes place and
3456 are the usual targets for update and merge operations.
3447 are the usual targets for update and merge operations.
3457
3448
3458 If one or more REVs are given, only open branch heads on the
3449 If one or more REVs are given, only open branch heads on the
3459 branches associated with the specified changesets are shown. This
3450 branches associated with the specified changesets are shown. This
3460 means that you can use :hg:`heads .` to see the heads on the
3451 means that you can use :hg:`heads .` to see the heads on the
3461 currently checked-out branch.
3452 currently checked-out branch.
3462
3453
3463 If -c/--closed is specified, also show branch heads marked closed
3454 If -c/--closed is specified, also show branch heads marked closed
3464 (see :hg:`commit --close-branch`).
3455 (see :hg:`commit --close-branch`).
3465
3456
3466 If STARTREV is specified, only those heads that are descendants of
3457 If STARTREV is specified, only those heads that are descendants of
3467 STARTREV will be displayed.
3458 STARTREV will be displayed.
3468
3459
3469 If -t/--topo is specified, named branch mechanics will be ignored and only
3460 If -t/--topo is specified, named branch mechanics will be ignored and only
3470 topological heads (changesets with no children) will be shown.
3461 topological heads (changesets with no children) will be shown.
3471
3462
3472 Returns 0 if matching heads are found, 1 if not.
3463 Returns 0 if matching heads are found, 1 if not.
3473 """
3464 """
3474
3465
3475 start = None
3466 start = None
3476 rev = opts.get('rev')
3467 rev = opts.get('rev')
3477 if rev:
3468 if rev:
3478 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3469 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3479 start = logcmdutil.revsingle(repo, rev, None).node()
3470 start = logcmdutil.revsingle(repo, rev, None).node()
3480
3471
3481 if opts.get('topo'):
3472 if opts.get('topo'):
3482 heads = [repo[h] for h in repo.heads(start)]
3473 heads = [repo[h] for h in repo.heads(start)]
3483 else:
3474 else:
3484 heads = []
3475 heads = []
3485 for branch in repo.branchmap():
3476 for branch in repo.branchmap():
3486 heads += repo.branchheads(branch, start, opts.get('closed'))
3477 heads += repo.branchheads(branch, start, opts.get('closed'))
3487 heads = [repo[h] for h in heads]
3478 heads = [repo[h] for h in heads]
3488
3479
3489 if branchrevs:
3480 if branchrevs:
3490 branches = {
3481 branches = {
3491 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3482 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3492 }
3483 }
3493 heads = [h for h in heads if h.branch() in branches]
3484 heads = [h for h in heads if h.branch() in branches]
3494
3485
3495 if opts.get('active') and branchrevs:
3486 if opts.get('active') and branchrevs:
3496 dagheads = repo.heads(start)
3487 dagheads = repo.heads(start)
3497 heads = [h for h in heads if h.node() in dagheads]
3488 heads = [h for h in heads if h.node() in dagheads]
3498
3489
3499 if branchrevs:
3490 if branchrevs:
3500 haveheads = {h.branch() for h in heads}
3491 haveheads = {h.branch() for h in heads}
3501 if branches - haveheads:
3492 if branches - haveheads:
3502 headless = b', '.join(b for b in branches - haveheads)
3493 headless = b', '.join(b for b in branches - haveheads)
3503 msg = _(b'no open branch heads found on branches %s')
3494 msg = _(b'no open branch heads found on branches %s')
3504 if opts.get('rev'):
3495 if opts.get('rev'):
3505 msg += _(b' (started at %s)') % opts['rev']
3496 msg += _(b' (started at %s)') % opts['rev']
3506 ui.warn((msg + b'\n') % headless)
3497 ui.warn((msg + b'\n') % headless)
3507
3498
3508 if not heads:
3499 if not heads:
3509 return 1
3500 return 1
3510
3501
3511 ui.pager(b'heads')
3502 ui.pager(b'heads')
3512 heads = sorted(heads, key=lambda x: -(x.rev()))
3503 heads = sorted(heads, key=lambda x: -(x.rev()))
3513 displayer = logcmdutil.changesetdisplayer(
3504 displayer = logcmdutil.changesetdisplayer(
3514 ui, repo, pycompat.byteskwargs(opts)
3505 ui, repo, pycompat.byteskwargs(opts)
3515 )
3506 )
3516 for ctx in heads:
3507 for ctx in heads:
3517 displayer.show(ctx)
3508 displayer.show(ctx)
3518 displayer.close()
3509 displayer.close()
3519
3510
3520
3511
3521 @command(
3512 @command(
3522 b'help',
3513 b'help',
3523 [
3514 [
3524 (b'e', b'extension', None, _(b'show only help for extensions')),
3515 (b'e', b'extension', None, _(b'show only help for extensions')),
3525 (b'c', b'command', None, _(b'show only help for commands')),
3516 (b'c', b'command', None, _(b'show only help for commands')),
3526 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3517 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3527 (
3518 (
3528 b's',
3519 b's',
3529 b'system',
3520 b'system',
3530 [],
3521 [],
3531 _(b'show help for specific platform(s)'),
3522 _(b'show help for specific platform(s)'),
3532 _(b'PLATFORM'),
3523 _(b'PLATFORM'),
3533 ),
3524 ),
3534 ],
3525 ],
3535 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3526 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3536 helpcategory=command.CATEGORY_HELP,
3527 helpcategory=command.CATEGORY_HELP,
3537 norepo=True,
3528 norepo=True,
3538 intents={INTENT_READONLY},
3529 intents={INTENT_READONLY},
3539 )
3530 )
3540 def help_(ui, name=None, **opts):
3531 def help_(ui, name=None, **opts):
3541 """show help for a given topic or a help overview
3532 """show help for a given topic or a help overview
3542
3533
3543 With no arguments, print a list of commands with short help messages.
3534 With no arguments, print a list of commands with short help messages.
3544
3535
3545 Given a topic, extension, or command name, print help for that
3536 Given a topic, extension, or command name, print help for that
3546 topic.
3537 topic.
3547
3538
3548 Returns 0 if successful.
3539 Returns 0 if successful.
3549 """
3540 """
3550
3541
3551 keep = opts.get('system') or []
3542 keep = opts.get('system') or []
3552 if len(keep) == 0:
3543 if len(keep) == 0:
3553 if pycompat.sysplatform.startswith(b'win'):
3544 if pycompat.sysplatform.startswith(b'win'):
3554 keep.append(b'windows')
3545 keep.append(b'windows')
3555 elif pycompat.sysplatform == b'OpenVMS':
3546 elif pycompat.sysplatform == b'OpenVMS':
3556 keep.append(b'vms')
3547 keep.append(b'vms')
3557 elif pycompat.sysplatform == b'plan9':
3548 elif pycompat.sysplatform == b'plan9':
3558 keep.append(b'plan9')
3549 keep.append(b'plan9')
3559 else:
3550 else:
3560 keep.append(b'unix')
3551 keep.append(b'unix')
3561 keep.append(pycompat.sysplatform.lower())
3552 keep.append(pycompat.sysplatform.lower())
3562 if ui.verbose:
3553 if ui.verbose:
3563 keep.append(b'verbose')
3554 keep.append(b'verbose')
3564
3555
3565 commands = sys.modules[__name__]
3556 commands = sys.modules[__name__]
3566 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3557 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3567 ui.pager(b'help')
3558 ui.pager(b'help')
3568 ui.write(formatted)
3559 ui.write(formatted)
3569
3560
3570
3561
3571 @command(
3562 @command(
3572 b'identify|id',
3563 b'identify|id',
3573 [
3564 [
3574 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3565 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3575 (b'n', b'num', None, _(b'show local revision number')),
3566 (b'n', b'num', None, _(b'show local revision number')),
3576 (b'i', b'id', None, _(b'show global revision id')),
3567 (b'i', b'id', None, _(b'show global revision id')),
3577 (b'b', b'branch', None, _(b'show branch')),
3568 (b'b', b'branch', None, _(b'show branch')),
3578 (b't', b'tags', None, _(b'show tags')),
3569 (b't', b'tags', None, _(b'show tags')),
3579 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3570 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3580 ]
3571 ]
3581 + remoteopts
3572 + remoteopts
3582 + formatteropts,
3573 + formatteropts,
3583 _(b'[-nibtB] [-r REV] [SOURCE]'),
3574 _(b'[-nibtB] [-r REV] [SOURCE]'),
3584 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3575 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3585 optionalrepo=True,
3576 optionalrepo=True,
3586 intents={INTENT_READONLY},
3577 intents={INTENT_READONLY},
3587 )
3578 )
3588 def identify(
3579 def identify(
3589 ui,
3580 ui,
3590 repo,
3581 repo,
3591 source=None,
3582 source=None,
3592 rev=None,
3583 rev=None,
3593 num=None,
3584 num=None,
3594 id=None,
3585 id=None,
3595 branch=None,
3586 branch=None,
3596 tags=None,
3587 tags=None,
3597 bookmarks=None,
3588 bookmarks=None,
3598 **opts,
3589 **opts,
3599 ):
3590 ):
3600 """identify the working directory or specified revision
3591 """identify the working directory or specified revision
3601
3592
3602 Print a summary identifying the repository state at REV using one or
3593 Print a summary identifying the repository state at REV using one or
3603 two parent hash identifiers, followed by a "+" if the working
3594 two parent hash identifiers, followed by a "+" if the working
3604 directory has uncommitted changes, the branch name (if not default),
3595 directory has uncommitted changes, the branch name (if not default),
3605 a list of tags, and a list of bookmarks.
3596 a list of tags, and a list of bookmarks.
3606
3597
3607 When REV is not given, print a summary of the current state of the
3598 When REV is not given, print a summary of the current state of the
3608 repository including the working directory. Specify -r. to get information
3599 repository including the working directory. Specify -r. to get information
3609 of the working directory parent without scanning uncommitted changes.
3600 of the working directory parent without scanning uncommitted changes.
3610
3601
3611 Specifying a path to a repository root or Mercurial bundle will
3602 Specifying a path to a repository root or Mercurial bundle will
3612 cause lookup to operate on that repository/bundle.
3603 cause lookup to operate on that repository/bundle.
3613
3604
3614 .. container:: verbose
3605 .. container:: verbose
3615
3606
3616 Template:
3607 Template:
3617
3608
3618 The following keywords are supported in addition to the common template
3609 The following keywords are supported in addition to the common template
3619 keywords and functions. See also :hg:`help templates`.
3610 keywords and functions. See also :hg:`help templates`.
3620
3611
3621 :dirty: String. Character ``+`` denoting if the working directory has
3612 :dirty: String. Character ``+`` denoting if the working directory has
3622 uncommitted changes.
3613 uncommitted changes.
3623 :id: String. One or two nodes, optionally followed by ``+``.
3614 :id: String. One or two nodes, optionally followed by ``+``.
3624 :parents: List of strings. Parent nodes of the changeset.
3615 :parents: List of strings. Parent nodes of the changeset.
3625
3616
3626 Examples:
3617 Examples:
3627
3618
3628 - generate a build identifier for the working directory::
3619 - generate a build identifier for the working directory::
3629
3620
3630 hg id --id > build-id.dat
3621 hg id --id > build-id.dat
3631
3622
3632 - find the revision corresponding to a tag::
3623 - find the revision corresponding to a tag::
3633
3624
3634 hg id -n -r 1.3
3625 hg id -n -r 1.3
3635
3626
3636 - check the most recent revision of a remote repository::
3627 - check the most recent revision of a remote repository::
3637
3628
3638 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3629 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3639
3630
3640 See :hg:`log` for generating more information about specific revisions,
3631 See :hg:`log` for generating more information about specific revisions,
3641 including full hash identifiers.
3632 including full hash identifiers.
3642
3633
3643 Returns 0 if successful.
3634 Returns 0 if successful.
3644 """
3635 """
3645
3636
3646 opts = pycompat.byteskwargs(opts)
3637 opts = pycompat.byteskwargs(opts)
3647 if not repo and not source:
3638 if not repo and not source:
3648 raise error.InputError(
3639 raise error.InputError(
3649 _(b"there is no Mercurial repository here (.hg not found)")
3640 _(b"there is no Mercurial repository here (.hg not found)")
3650 )
3641 )
3651
3642
3652 default = not (num or id or branch or tags or bookmarks)
3643 default = not (num or id or branch or tags or bookmarks)
3653 output = []
3644 output = []
3654 revs = []
3645 revs = []
3655
3646
3656 peer = None
3647 peer = None
3657 try:
3648 try:
3658 if source:
3649 if source:
3659 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3650 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3660 # only pass ui when no repo
3651 # only pass ui when no repo
3661 peer = hg.peer(repo or ui, opts, path)
3652 peer = hg.peer(repo or ui, opts, path)
3662 repo = peer.local()
3653 repo = peer.local()
3663 branches = (path.branch, [])
3654 branches = (path.branch, [])
3664 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3655 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3665
3656
3666 fm = ui.formatter(b'identify', opts)
3657 fm = ui.formatter(b'identify', opts)
3667 fm.startitem()
3658 fm.startitem()
3668
3659
3669 if not repo:
3660 if not repo:
3670 if num or branch or tags:
3661 if num or branch or tags:
3671 raise error.InputError(
3662 raise error.InputError(
3672 _(b"can't query remote revision number, branch, or tags")
3663 _(b"can't query remote revision number, branch, or tags")
3673 )
3664 )
3674 if not rev and revs:
3665 if not rev and revs:
3675 rev = revs[0]
3666 rev = revs[0]
3676 if not rev:
3667 if not rev:
3677 rev = b"tip"
3668 rev = b"tip"
3678
3669
3679 remoterev = peer.lookup(rev)
3670 remoterev = peer.lookup(rev)
3680 hexrev = fm.hexfunc(remoterev)
3671 hexrev = fm.hexfunc(remoterev)
3681 if default or id:
3672 if default or id:
3682 output = [hexrev]
3673 output = [hexrev]
3683 fm.data(id=hexrev)
3674 fm.data(id=hexrev)
3684
3675
3685 @util.cachefunc
3676 @util.cachefunc
3686 def getbms():
3677 def getbms():
3687 bms = []
3678 bms = []
3688
3679
3689 if b'bookmarks' in peer.listkeys(b'namespaces'):
3680 if b'bookmarks' in peer.listkeys(b'namespaces'):
3690 hexremoterev = hex(remoterev)
3681 hexremoterev = hex(remoterev)
3691 bms = [
3682 bms = [
3692 bm
3683 bm
3693 for bm, bmr in peer.listkeys(b'bookmarks').items()
3684 for bm, bmr in peer.listkeys(b'bookmarks').items()
3694 if bmr == hexremoterev
3685 if bmr == hexremoterev
3695 ]
3686 ]
3696
3687
3697 return sorted(bms)
3688 return sorted(bms)
3698
3689
3699 if fm.isplain():
3690 if fm.isplain():
3700 if bookmarks:
3691 if bookmarks:
3701 output.extend(getbms())
3692 output.extend(getbms())
3702 elif default and not ui.quiet:
3693 elif default and not ui.quiet:
3703 # multiple bookmarks for a single parent separated by '/'
3694 # multiple bookmarks for a single parent separated by '/'
3704 bm = b'/'.join(getbms())
3695 bm = b'/'.join(getbms())
3705 if bm:
3696 if bm:
3706 output.append(bm)
3697 output.append(bm)
3707 else:
3698 else:
3708 fm.data(node=hex(remoterev))
3699 fm.data(node=hex(remoterev))
3709 if bookmarks or b'bookmarks' in fm.datahint():
3700 if bookmarks or b'bookmarks' in fm.datahint():
3710 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3701 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3711 else:
3702 else:
3712 if rev:
3703 if rev:
3713 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3704 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3714 ctx = logcmdutil.revsingle(repo, rev, None)
3705 ctx = logcmdutil.revsingle(repo, rev, None)
3715
3706
3716 if ctx.rev() is None:
3707 if ctx.rev() is None:
3717 ctx = repo[None]
3708 ctx = repo[None]
3718 parents = ctx.parents()
3709 parents = ctx.parents()
3719 taglist = []
3710 taglist = []
3720 for p in parents:
3711 for p in parents:
3721 taglist.extend(p.tags())
3712 taglist.extend(p.tags())
3722
3713
3723 dirty = b""
3714 dirty = b""
3724 if ctx.dirty(missing=True, merge=False, branch=False):
3715 if ctx.dirty(missing=True, merge=False, branch=False):
3725 dirty = b'+'
3716 dirty = b'+'
3726 fm.data(dirty=dirty)
3717 fm.data(dirty=dirty)
3727
3718
3728 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3719 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3729 if default or id:
3720 if default or id:
3730 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3721 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3731 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3722 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3732
3723
3733 if num:
3724 if num:
3734 numoutput = [b"%d" % p.rev() for p in parents]
3725 numoutput = [b"%d" % p.rev() for p in parents]
3735 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3726 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3736
3727
3737 fm.data(
3728 fm.data(
3738 parents=fm.formatlist(
3729 parents=fm.formatlist(
3739 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3730 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3740 )
3731 )
3741 )
3732 )
3742 else:
3733 else:
3743 hexoutput = fm.hexfunc(ctx.node())
3734 hexoutput = fm.hexfunc(ctx.node())
3744 if default or id:
3735 if default or id:
3745 output = [hexoutput]
3736 output = [hexoutput]
3746 fm.data(id=hexoutput)
3737 fm.data(id=hexoutput)
3747
3738
3748 if num:
3739 if num:
3749 output.append(pycompat.bytestr(ctx.rev()))
3740 output.append(pycompat.bytestr(ctx.rev()))
3750 taglist = ctx.tags()
3741 taglist = ctx.tags()
3751
3742
3752 if default and not ui.quiet:
3743 if default and not ui.quiet:
3753 b = ctx.branch()
3744 b = ctx.branch()
3754 if b != b'default':
3745 if b != b'default':
3755 output.append(b"(%s)" % b)
3746 output.append(b"(%s)" % b)
3756
3747
3757 # multiple tags for a single parent separated by '/'
3748 # multiple tags for a single parent separated by '/'
3758 t = b'/'.join(taglist)
3749 t = b'/'.join(taglist)
3759 if t:
3750 if t:
3760 output.append(t)
3751 output.append(t)
3761
3752
3762 # multiple bookmarks for a single parent separated by '/'
3753 # multiple bookmarks for a single parent separated by '/'
3763 bm = b'/'.join(ctx.bookmarks())
3754 bm = b'/'.join(ctx.bookmarks())
3764 if bm:
3755 if bm:
3765 output.append(bm)
3756 output.append(bm)
3766 else:
3757 else:
3767 if branch:
3758 if branch:
3768 output.append(ctx.branch())
3759 output.append(ctx.branch())
3769
3760
3770 if tags:
3761 if tags:
3771 output.extend(taglist)
3762 output.extend(taglist)
3772
3763
3773 if bookmarks:
3764 if bookmarks:
3774 output.extend(ctx.bookmarks())
3765 output.extend(ctx.bookmarks())
3775
3766
3776 fm.data(node=ctx.hex())
3767 fm.data(node=ctx.hex())
3777 fm.data(branch=ctx.branch())
3768 fm.data(branch=ctx.branch())
3778 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3769 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3779 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3770 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3780 fm.context(ctx=ctx)
3771 fm.context(ctx=ctx)
3781
3772
3782 fm.plain(b"%s\n" % b' '.join(output))
3773 fm.plain(b"%s\n" % b' '.join(output))
3783 fm.end()
3774 fm.end()
3784 finally:
3775 finally:
3785 if peer:
3776 if peer:
3786 peer.close()
3777 peer.close()
3787
3778
3788
3779
3789 @command(
3780 @command(
3790 b'import|patch',
3781 b'import|patch',
3791 [
3782 [
3792 (
3783 (
3793 b'p',
3784 b'p',
3794 b'strip',
3785 b'strip',
3795 1,
3786 1,
3796 _(
3787 _(
3797 b'directory strip option for patch. This has the same '
3788 b'directory strip option for patch. This has the same '
3798 b'meaning as the corresponding patch option'
3789 b'meaning as the corresponding patch option'
3799 ),
3790 ),
3800 _(b'NUM'),
3791 _(b'NUM'),
3801 ),
3792 ),
3802 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3793 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3803 (b'', b'secret', None, _(b'use the secret phase for committing')),
3794 (b'', b'secret', None, _(b'use the secret phase for committing')),
3804 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3795 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3805 (
3796 (
3806 b'f',
3797 b'f',
3807 b'force',
3798 b'force',
3808 None,
3799 None,
3809 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3800 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3810 ),
3801 ),
3811 (
3802 (
3812 b'',
3803 b'',
3813 b'no-commit',
3804 b'no-commit',
3814 None,
3805 None,
3815 _(b"don't commit, just update the working directory"),
3806 _(b"don't commit, just update the working directory"),
3816 ),
3807 ),
3817 (
3808 (
3818 b'',
3809 b'',
3819 b'bypass',
3810 b'bypass',
3820 None,
3811 None,
3821 _(b"apply patch without touching the working directory"),
3812 _(b"apply patch without touching the working directory"),
3822 ),
3813 ),
3823 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3814 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3824 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3815 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3825 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3816 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3826 (
3817 (
3827 b'',
3818 b'',
3828 b'import-branch',
3819 b'import-branch',
3829 None,
3820 None,
3830 _(b'use any branch information in patch (implied by --exact)'),
3821 _(b'use any branch information in patch (implied by --exact)'),
3831 ),
3822 ),
3832 ]
3823 ]
3833 + commitopts
3824 + commitopts
3834 + commitopts2
3825 + commitopts2
3835 + similarityopts,
3826 + similarityopts,
3836 _(b'[OPTION]... PATCH...'),
3827 _(b'[OPTION]... PATCH...'),
3837 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3828 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3838 )
3829 )
3839 def import_(ui, repo, patch1=None, *patches, **opts):
3830 def import_(ui, repo, patch1=None, *patches, **opts):
3840 """import an ordered set of patches
3831 """import an ordered set of patches
3841
3832
3842 Import a list of patches and commit them individually (unless
3833 Import a list of patches and commit them individually (unless
3843 --no-commit is specified).
3834 --no-commit is specified).
3844
3835
3845 To read a patch from standard input (stdin), use "-" as the patch
3836 To read a patch from standard input (stdin), use "-" as the patch
3846 name. If a URL is specified, the patch will be downloaded from
3837 name. If a URL is specified, the patch will be downloaded from
3847 there.
3838 there.
3848
3839
3849 Import first applies changes to the working directory (unless
3840 Import first applies changes to the working directory (unless
3850 --bypass is specified), import will abort if there are outstanding
3841 --bypass is specified), import will abort if there are outstanding
3851 changes.
3842 changes.
3852
3843
3853 Use --bypass to apply and commit patches directly to the
3844 Use --bypass to apply and commit patches directly to the
3854 repository, without affecting the working directory. Without
3845 repository, without affecting the working directory. Without
3855 --exact, patches will be applied on top of the working directory
3846 --exact, patches will be applied on top of the working directory
3856 parent revision.
3847 parent revision.
3857
3848
3858 You can import a patch straight from a mail message. Even patches
3849 You can import a patch straight from a mail message. Even patches
3859 as attachments work (to use the body part, it must have type
3850 as attachments work (to use the body part, it must have type
3860 text/plain or text/x-patch). From and Subject headers of email
3851 text/plain or text/x-patch). From and Subject headers of email
3861 message are used as default committer and commit message. All
3852 message are used as default committer and commit message. All
3862 text/plain body parts before first diff are added to the commit
3853 text/plain body parts before first diff are added to the commit
3863 message.
3854 message.
3864
3855
3865 If the imported patch was generated by :hg:`export`, user and
3856 If the imported patch was generated by :hg:`export`, user and
3866 description from patch override values from message headers and
3857 description from patch override values from message headers and
3867 body. Values given on command line with -m/--message and -u/--user
3858 body. Values given on command line with -m/--message and -u/--user
3868 override these.
3859 override these.
3869
3860
3870 If --exact is specified, import will set the working directory to
3861 If --exact is specified, import will set the working directory to
3871 the parent of each patch before applying it, and will abort if the
3862 the parent of each patch before applying it, and will abort if the
3872 resulting changeset has a different ID than the one recorded in
3863 resulting changeset has a different ID than the one recorded in
3873 the patch. This will guard against various ways that portable
3864 the patch. This will guard against various ways that portable
3874 patch formats and mail systems might fail to transfer Mercurial
3865 patch formats and mail systems might fail to transfer Mercurial
3875 data or metadata. See :hg:`bundle` for lossless transmission.
3866 data or metadata. See :hg:`bundle` for lossless transmission.
3876
3867
3877 Use --partial to ensure a changeset will be created from the patch
3868 Use --partial to ensure a changeset will be created from the patch
3878 even if some hunks fail to apply. Hunks that fail to apply will be
3869 even if some hunks fail to apply. Hunks that fail to apply will be
3879 written to a <target-file>.rej file. Conflicts can then be resolved
3870 written to a <target-file>.rej file. Conflicts can then be resolved
3880 by hand before :hg:`commit --amend` is run to update the created
3871 by hand before :hg:`commit --amend` is run to update the created
3881 changeset. This flag exists to let people import patches that
3872 changeset. This flag exists to let people import patches that
3882 partially apply without losing the associated metadata (author,
3873 partially apply without losing the associated metadata (author,
3883 date, description, ...).
3874 date, description, ...).
3884
3875
3885 .. note::
3876 .. note::
3886
3877
3887 When no hunks apply cleanly, :hg:`import --partial` will create
3878 When no hunks apply cleanly, :hg:`import --partial` will create
3888 an empty changeset, importing only the patch metadata.
3879 an empty changeset, importing only the patch metadata.
3889
3880
3890 With -s/--similarity, hg will attempt to discover renames and
3881 With -s/--similarity, hg will attempt to discover renames and
3891 copies in the patch in the same way as :hg:`addremove`.
3882 copies in the patch in the same way as :hg:`addremove`.
3892
3883
3893 It is possible to use external patch programs to perform the patch
3884 It is possible to use external patch programs to perform the patch
3894 by setting the ``ui.patch`` configuration option. For the default
3885 by setting the ``ui.patch`` configuration option. For the default
3895 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3886 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3896 See :hg:`help config` for more information about configuration
3887 See :hg:`help config` for more information about configuration
3897 files and how to use these options.
3888 files and how to use these options.
3898
3889
3899 See :hg:`help dates` for a list of formats valid for -d/--date.
3890 See :hg:`help dates` for a list of formats valid for -d/--date.
3900
3891
3901 .. container:: verbose
3892 .. container:: verbose
3902
3893
3903 Examples:
3894 Examples:
3904
3895
3905 - import a traditional patch from a website and detect renames::
3896 - import a traditional patch from a website and detect renames::
3906
3897
3907 hg import -s 80 http://example.com/bugfix.patch
3898 hg import -s 80 http://example.com/bugfix.patch
3908
3899
3909 - import a changeset from an hgweb server::
3900 - import a changeset from an hgweb server::
3910
3901
3911 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3902 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3912
3903
3913 - import all the patches in an Unix-style mbox::
3904 - import all the patches in an Unix-style mbox::
3914
3905
3915 hg import incoming-patches.mbox
3906 hg import incoming-patches.mbox
3916
3907
3917 - import patches from stdin::
3908 - import patches from stdin::
3918
3909
3919 hg import -
3910 hg import -
3920
3911
3921 - attempt to exactly restore an exported changeset (not always
3912 - attempt to exactly restore an exported changeset (not always
3922 possible)::
3913 possible)::
3923
3914
3924 hg import --exact proposed-fix.patch
3915 hg import --exact proposed-fix.patch
3925
3916
3926 - use an external tool to apply a patch which is too fuzzy for
3917 - use an external tool to apply a patch which is too fuzzy for
3927 the default internal tool.
3918 the default internal tool.
3928
3919
3929 hg import --config ui.patch="patch --merge" fuzzy.patch
3920 hg import --config ui.patch="patch --merge" fuzzy.patch
3930
3921
3931 - change the default fuzzing from 2 to a less strict 7
3922 - change the default fuzzing from 2 to a less strict 7
3932
3923
3933 hg import --config ui.fuzz=7 fuzz.patch
3924 hg import --config ui.fuzz=7 fuzz.patch
3934
3925
3935 Returns 0 on success, 1 on partial success (see --partial).
3926 Returns 0 on success, 1 on partial success (see --partial).
3936 """
3927 """
3937
3928
3938 cmdutil.check_incompatible_arguments(
3929 cmdutil.check_incompatible_arguments(
3939 opts, 'no_commit', ['bypass', 'secret']
3930 opts, 'no_commit', ['bypass', 'secret']
3940 )
3931 )
3941 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3932 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3942
3933
3943 if not patch1:
3934 if not patch1:
3944 raise error.InputError(_(b'need at least one patch to import'))
3935 raise error.InputError(_(b'need at least one patch to import'))
3945
3936
3946 patches = (patch1,) + patches
3937 patches = (patch1,) + patches
3947
3938
3948 date = opts.get('date')
3939 date = opts.get('date')
3949 if date:
3940 if date:
3950 opts['date'] = dateutil.parsedate(date)
3941 opts['date'] = dateutil.parsedate(date)
3951
3942
3952 exact = opts.get('exact')
3943 exact = opts.get('exact')
3953 update = not opts.get('bypass')
3944 update = not opts.get('bypass')
3954 try:
3945 try:
3955 sim = float(opts.get('similarity') or 0)
3946 sim = float(opts.get('similarity') or 0)
3956 except ValueError:
3947 except ValueError:
3957 raise error.InputError(_(b'similarity must be a number'))
3948 raise error.InputError(_(b'similarity must be a number'))
3958 if sim < 0 or sim > 100:
3949 if sim < 0 or sim > 100:
3959 raise error.InputError(_(b'similarity must be between 0 and 100'))
3950 raise error.InputError(_(b'similarity must be between 0 and 100'))
3960 if sim and not update:
3951 if sim and not update:
3961 raise error.InputError(_(b'cannot use --similarity with --bypass'))
3952 raise error.InputError(_(b'cannot use --similarity with --bypass'))
3962
3953
3963 base = opts["base"]
3954 base = opts["base"]
3964 msgs = []
3955 msgs = []
3965 ret = 0
3956 ret = 0
3966
3957
3967 with repo.wlock():
3958 with repo.wlock():
3968 if update:
3959 if update:
3969 cmdutil.checkunfinished(repo)
3960 cmdutil.checkunfinished(repo)
3970 if exact or not opts.get('force'):
3961 if exact or not opts.get('force'):
3971 cmdutil.bailifchanged(repo)
3962 cmdutil.bailifchanged(repo)
3972
3963
3973 if not opts.get('no_commit'):
3964 if not opts.get('no_commit'):
3974 lock = repo.lock
3965 lock = repo.lock
3975 tr = lambda: repo.transaction(b'import')
3966 tr = lambda: repo.transaction(b'import')
3976 else:
3967 else:
3977 lock = util.nullcontextmanager
3968 lock = util.nullcontextmanager
3978 tr = util.nullcontextmanager
3969 tr = util.nullcontextmanager
3979 with lock(), tr():
3970 with lock(), tr():
3980 parents = repo[None].parents()
3971 parents = repo[None].parents()
3981 for patchurl in patches:
3972 for patchurl in patches:
3982 if patchurl == b'-':
3973 if patchurl == b'-':
3983 ui.status(_(b'applying patch from stdin\n'))
3974 ui.status(_(b'applying patch from stdin\n'))
3984 patchfile = ui.fin
3975 patchfile = ui.fin
3985 patchurl = b'stdin' # for error message
3976 patchurl = b'stdin' # for error message
3986 else:
3977 else:
3987 patchurl = os.path.join(base, patchurl)
3978 patchurl = os.path.join(base, patchurl)
3988 ui.status(_(b'applying %s\n') % patchurl)
3979 ui.status(_(b'applying %s\n') % patchurl)
3989 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3980 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3990
3981
3991 haspatch = False
3982 haspatch = False
3992 for hunk in patch.split(patchfile):
3983 for hunk in patch.split(patchfile):
3993 with patch.extract(ui, hunk) as patchdata:
3984 with patch.extract(ui, hunk) as patchdata:
3994 msg, node, rej = cmdutil.tryimportone(
3985 msg, node, rej = cmdutil.tryimportone(
3995 ui,
3986 ui,
3996 repo,
3987 repo,
3997 patchdata,
3988 patchdata,
3998 parents,
3989 parents,
3999 pycompat.byteskwargs(opts),
3990 pycompat.byteskwargs(opts),
4000 msgs,
3991 msgs,
4001 hg.clean,
3992 hg.clean,
4002 )
3993 )
4003 if msg:
3994 if msg:
4004 haspatch = True
3995 haspatch = True
4005 ui.note(msg + b'\n')
3996 ui.note(msg + b'\n')
4006 if update or exact:
3997 if update or exact:
4007 parents = repo[None].parents()
3998 parents = repo[None].parents()
4008 else:
3999 else:
4009 parents = [repo[node]]
4000 parents = [repo[node]]
4010 if rej:
4001 if rej:
4011 ui.write_err(_(b"patch applied partially\n"))
4002 ui.write_err(_(b"patch applied partially\n"))
4012 ui.write_err(
4003 ui.write_err(
4013 _(
4004 _(
4014 b"(fix the .rej files and run "
4005 b"(fix the .rej files and run "
4015 b"`hg commit --amend`)\n"
4006 b"`hg commit --amend`)\n"
4016 )
4007 )
4017 )
4008 )
4018 ret = 1
4009 ret = 1
4019 break
4010 break
4020
4011
4021 if not haspatch:
4012 if not haspatch:
4022 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4013 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4023
4014
4024 if msgs:
4015 if msgs:
4025 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4016 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4026 return ret
4017 return ret
4027
4018
4028
4019
4029 @command(
4020 @command(
4030 b'incoming|in',
4021 b'incoming|in',
4031 [
4022 [
4032 (
4023 (
4033 b'f',
4024 b'f',
4034 b'force',
4025 b'force',
4035 None,
4026 None,
4036 _(b'run even if remote repository is unrelated'),
4027 _(b'run even if remote repository is unrelated'),
4037 ),
4028 ),
4038 (b'n', b'newest-first', None, _(b'show newest record first')),
4029 (b'n', b'newest-first', None, _(b'show newest record first')),
4039 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4030 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4040 (
4031 (
4041 b'r',
4032 b'r',
4042 b'rev',
4033 b'rev',
4043 [],
4034 [],
4044 _(b'a remote changeset intended to be added'),
4035 _(b'a remote changeset intended to be added'),
4045 _(b'REV'),
4036 _(b'REV'),
4046 ),
4037 ),
4047 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4038 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4048 (
4039 (
4049 b'b',
4040 b'b',
4050 b'branch',
4041 b'branch',
4051 [],
4042 [],
4052 _(b'a specific branch you would like to pull'),
4043 _(b'a specific branch you would like to pull'),
4053 _(b'BRANCH'),
4044 _(b'BRANCH'),
4054 ),
4045 ),
4055 ]
4046 ]
4056 + logopts
4047 + logopts
4057 + remoteopts
4048 + remoteopts
4058 + subrepoopts,
4049 + subrepoopts,
4059 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4050 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4060 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4051 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4061 )
4052 )
4062 def incoming(ui, repo, source=b"default", **opts):
4053 def incoming(ui, repo, source=b"default", **opts):
4063 """show new changesets found in source
4054 """show new changesets found in source
4064
4055
4065 Show new changesets found in the specified path/URL or the default
4056 Show new changesets found in the specified path/URL or the default
4066 pull location. These are the changesets that would have been pulled
4057 pull location. These are the changesets that would have been pulled
4067 by :hg:`pull` at the time you issued this command.
4058 by :hg:`pull` at the time you issued this command.
4068
4059
4069 See pull for valid source format details.
4060 See pull for valid source format details.
4070
4061
4071 .. container:: verbose
4062 .. container:: verbose
4072
4063
4073 With -B/--bookmarks, the result of bookmark comparison between
4064 With -B/--bookmarks, the result of bookmark comparison between
4074 local and remote repositories is displayed. With -v/--verbose,
4065 local and remote repositories is displayed. With -v/--verbose,
4075 status is also displayed for each bookmark like below::
4066 status is also displayed for each bookmark like below::
4076
4067
4077 BM1 01234567890a added
4068 BM1 01234567890a added
4078 BM2 1234567890ab advanced
4069 BM2 1234567890ab advanced
4079 BM3 234567890abc diverged
4070 BM3 234567890abc diverged
4080 BM4 34567890abcd changed
4071 BM4 34567890abcd changed
4081
4072
4082 The action taken locally when pulling depends on the
4073 The action taken locally when pulling depends on the
4083 status of each bookmark:
4074 status of each bookmark:
4084
4075
4085 :``added``: pull will create it
4076 :``added``: pull will create it
4086 :``advanced``: pull will update it
4077 :``advanced``: pull will update it
4087 :``diverged``: pull will create a divergent bookmark
4078 :``diverged``: pull will create a divergent bookmark
4088 :``changed``: result depends on remote changesets
4079 :``changed``: result depends on remote changesets
4089
4080
4090 From the point of view of pulling behavior, bookmark
4081 From the point of view of pulling behavior, bookmark
4091 existing only in the remote repository are treated as ``added``,
4082 existing only in the remote repository are treated as ``added``,
4092 even if it is in fact locally deleted.
4083 even if it is in fact locally deleted.
4093
4084
4094 .. container:: verbose
4085 .. container:: verbose
4095
4086
4096 For remote repository, using --bundle avoids downloading the
4087 For remote repository, using --bundle avoids downloading the
4097 changesets twice if the incoming is followed by a pull.
4088 changesets twice if the incoming is followed by a pull.
4098
4089
4099 Examples:
4090 Examples:
4100
4091
4101 - show incoming changes with patches and full description::
4092 - show incoming changes with patches and full description::
4102
4093
4103 hg incoming -vp
4094 hg incoming -vp
4104
4095
4105 - show incoming changes excluding merges, store a bundle::
4096 - show incoming changes excluding merges, store a bundle::
4106
4097
4107 hg in -vpM --bundle incoming.hg
4098 hg in -vpM --bundle incoming.hg
4108 hg pull incoming.hg
4099 hg pull incoming.hg
4109
4100
4110 - briefly list changes inside a bundle::
4101 - briefly list changes inside a bundle::
4111
4102
4112 hg in changes.hg -T "{desc|firstline}\\n"
4103 hg in changes.hg -T "{desc|firstline}\\n"
4113
4104
4114 Returns 0 if there are incoming changes, 1 otherwise.
4105 Returns 0 if there are incoming changes, 1 otherwise.
4115 """
4106 """
4116 opts = pycompat.byteskwargs(opts)
4107 opts = pycompat.byteskwargs(opts)
4117 if opts.get(b'graph'):
4108 if opts.get(b'graph'):
4118 logcmdutil.checkunsupportedgraphflags([], opts)
4109 logcmdutil.checkunsupportedgraphflags([], opts)
4119
4110
4120 def display(other, chlist, displayer):
4111 def display(other, chlist, displayer):
4121 revdag = logcmdutil.graphrevs(other, chlist, opts)
4112 revdag = logcmdutil.graphrevs(other, chlist, opts)
4122 logcmdutil.displaygraph(
4113 logcmdutil.displaygraph(
4123 ui, repo, revdag, displayer, graphmod.asciiedges
4114 ui, repo, revdag, displayer, graphmod.asciiedges
4124 )
4115 )
4125
4116
4126 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4117 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4127 return 0
4118 return 0
4128
4119
4129 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4120 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4130
4121
4131 if opts.get(b'bookmarks'):
4122 if opts.get(b'bookmarks'):
4132 srcs = urlutil.get_pull_paths(repo, ui, [source])
4123 srcs = urlutil.get_pull_paths(repo, ui, [source])
4133 for path in srcs:
4124 for path in srcs:
4134 # XXX the "branches" options are not used. Should it be used?
4125 # XXX the "branches" options are not used. Should it be used?
4135 other = hg.peer(repo, opts, path)
4126 other = hg.peer(repo, opts, path)
4136 try:
4127 try:
4137 if b'bookmarks' not in other.listkeys(b'namespaces'):
4128 if b'bookmarks' not in other.listkeys(b'namespaces'):
4138 ui.warn(_(b"remote doesn't support bookmarks\n"))
4129 ui.warn(_(b"remote doesn't support bookmarks\n"))
4139 return 0
4130 return 0
4140 ui.pager(b'incoming')
4131 ui.pager(b'incoming')
4141 ui.status(
4132 ui.status(
4142 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4133 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4143 )
4134 )
4144 return bookmarks.incoming(
4135 return bookmarks.incoming(
4145 ui, repo, other, mode=path.bookmarks_mode
4136 ui, repo, other, mode=path.bookmarks_mode
4146 )
4137 )
4147 finally:
4138 finally:
4148 other.close()
4139 other.close()
4149
4140
4150 return hg.incoming(ui, repo, source, opts)
4141 return hg.incoming(ui, repo, source, opts)
4151
4142
4152
4143
4153 @command(
4144 @command(
4154 b'init',
4145 b'init',
4155 remoteopts,
4146 remoteopts,
4156 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4147 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4157 helpcategory=command.CATEGORY_REPO_CREATION,
4148 helpcategory=command.CATEGORY_REPO_CREATION,
4158 helpbasic=True,
4149 helpbasic=True,
4159 norepo=True,
4150 norepo=True,
4160 )
4151 )
4161 def init(ui, dest=b".", **opts):
4152 def init(ui, dest=b".", **opts):
4162 """create a new repository in the given directory
4153 """create a new repository in the given directory
4163
4154
4164 Initialize a new repository in the given directory. If the given
4155 Initialize a new repository in the given directory. If the given
4165 directory does not exist, it will be created.
4156 directory does not exist, it will be created.
4166
4157
4167 If no directory is given, the current directory is used.
4158 If no directory is given, the current directory is used.
4168
4159
4169 It is possible to specify an ``ssh://`` URL as the destination.
4160 It is possible to specify an ``ssh://`` URL as the destination.
4170 See :hg:`help urls` for more information.
4161 See :hg:`help urls` for more information.
4171
4162
4172 Returns 0 on success.
4163 Returns 0 on success.
4173 """
4164 """
4174 opts = pycompat.byteskwargs(opts)
4165 opts = pycompat.byteskwargs(opts)
4175 path = urlutil.get_clone_path_obj(ui, dest)
4166 path = urlutil.get_clone_path_obj(ui, dest)
4176 peer = hg.peer(ui, opts, path, create=True)
4167 peer = hg.peer(ui, opts, path, create=True)
4177 peer.close()
4168 peer.close()
4178
4169
4179
4170
4180 @command(
4171 @command(
4181 b'locate',
4172 b'locate',
4182 [
4173 [
4183 (
4174 (
4184 b'r',
4175 b'r',
4185 b'rev',
4176 b'rev',
4186 b'',
4177 b'',
4187 _(b'search the repository as it is in REV'),
4178 _(b'search the repository as it is in REV'),
4188 _(b'REV'),
4179 _(b'REV'),
4189 ),
4180 ),
4190 (
4181 (
4191 b'0',
4182 b'0',
4192 b'print0',
4183 b'print0',
4193 None,
4184 None,
4194 _(b'end filenames with NUL, for use with xargs'),
4185 _(b'end filenames with NUL, for use with xargs'),
4195 ),
4186 ),
4196 (
4187 (
4197 b'f',
4188 b'f',
4198 b'fullpath',
4189 b'fullpath',
4199 None,
4190 None,
4200 _(b'print complete paths from the filesystem root'),
4191 _(b'print complete paths from the filesystem root'),
4201 ),
4192 ),
4202 ]
4193 ]
4203 + walkopts,
4194 + walkopts,
4204 _(b'[OPTION]... [PATTERN]...'),
4195 _(b'[OPTION]... [PATTERN]...'),
4205 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4196 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4206 )
4197 )
4207 def locate(ui, repo, *pats, **opts):
4198 def locate(ui, repo, *pats, **opts):
4208 """locate files matching specific patterns (DEPRECATED)
4199 """locate files matching specific patterns (DEPRECATED)
4209
4200
4210 Print files under Mercurial control in the working directory whose
4201 Print files under Mercurial control in the working directory whose
4211 names match the given patterns.
4202 names match the given patterns.
4212
4203
4213 By default, this command searches all directories in the working
4204 By default, this command searches all directories in the working
4214 directory. To search just the current directory and its
4205 directory. To search just the current directory and its
4215 subdirectories, use "--include .".
4206 subdirectories, use "--include .".
4216
4207
4217 If no patterns are given to match, this command prints the names
4208 If no patterns are given to match, this command prints the names
4218 of all files under Mercurial control in the working directory.
4209 of all files under Mercurial control in the working directory.
4219
4210
4220 If you want to feed the output of this command into the "xargs"
4211 If you want to feed the output of this command into the "xargs"
4221 command, use the -0 option to both this command and "xargs". This
4212 command, use the -0 option to both this command and "xargs". This
4222 will avoid the problem of "xargs" treating single filenames that
4213 will avoid the problem of "xargs" treating single filenames that
4223 contain whitespace as multiple filenames.
4214 contain whitespace as multiple filenames.
4224
4215
4225 See :hg:`help files` for a more versatile command.
4216 See :hg:`help files` for a more versatile command.
4226
4217
4227 Returns 0 if a match is found, 1 otherwise.
4218 Returns 0 if a match is found, 1 otherwise.
4228 """
4219 """
4229 if opts.get('print0'):
4220 if opts.get('print0'):
4230 end = b'\0'
4221 end = b'\0'
4231 else:
4222 else:
4232 end = b'\n'
4223 end = b'\n'
4233 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4224 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4234
4225
4235 ret = 1
4226 ret = 1
4236 m = scmutil.match(
4227 m = scmutil.match(
4237 ctx,
4228 ctx,
4238 pats,
4229 pats,
4239 pycompat.byteskwargs(opts),
4230 pycompat.byteskwargs(opts),
4240 default=b'relglob',
4231 default=b'relglob',
4241 badfn=lambda x, y: False,
4232 badfn=lambda x, y: False,
4242 )
4233 )
4243
4234
4244 ui.pager(b'locate')
4235 ui.pager(b'locate')
4245 if ctx.rev() is None:
4236 if ctx.rev() is None:
4246 # When run on the working copy, "locate" includes removed files, so
4237 # When run on the working copy, "locate" includes removed files, so
4247 # we get the list of files from the dirstate.
4238 # we get the list of files from the dirstate.
4248 filesgen = sorted(repo.dirstate.matches(m))
4239 filesgen = sorted(repo.dirstate.matches(m))
4249 else:
4240 else:
4250 filesgen = ctx.matches(m)
4241 filesgen = ctx.matches(m)
4251 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4242 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4252 for abs in filesgen:
4243 for abs in filesgen:
4253 if opts.get('fullpath'):
4244 if opts.get('fullpath'):
4254 ui.write(repo.wjoin(abs), end)
4245 ui.write(repo.wjoin(abs), end)
4255 else:
4246 else:
4256 ui.write(uipathfn(abs), end)
4247 ui.write(uipathfn(abs), end)
4257 ret = 0
4248 ret = 0
4258
4249
4259 return ret
4250 return ret
4260
4251
4261
4252
4262 @command(
4253 @command(
4263 b'log|history',
4254 b'log|history',
4264 [
4255 [
4265 (
4256 (
4266 b'f',
4257 b'f',
4267 b'follow',
4258 b'follow',
4268 None,
4259 None,
4269 _(
4260 _(
4270 b'follow changeset history, or file history across copies and renames'
4261 b'follow changeset history, or file history across copies and renames'
4271 ),
4262 ),
4272 ),
4263 ),
4273 (
4264 (
4274 b'',
4265 b'',
4275 b'follow-first',
4266 b'follow-first',
4276 None,
4267 None,
4277 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4268 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4278 ),
4269 ),
4279 (
4270 (
4280 b'd',
4271 b'd',
4281 b'date',
4272 b'date',
4282 b'',
4273 b'',
4283 _(b'show revisions matching date spec'),
4274 _(b'show revisions matching date spec'),
4284 _(b'DATE'),
4275 _(b'DATE'),
4285 ),
4276 ),
4286 (b'C', b'copies', None, _(b'show copied files')),
4277 (b'C', b'copies', None, _(b'show copied files')),
4287 (
4278 (
4288 b'k',
4279 b'k',
4289 b'keyword',
4280 b'keyword',
4290 [],
4281 [],
4291 _(b'do case-insensitive search for a given text'),
4282 _(b'do case-insensitive search for a given text'),
4292 _(b'TEXT'),
4283 _(b'TEXT'),
4293 ),
4284 ),
4294 (
4285 (
4295 b'r',
4286 b'r',
4296 b'rev',
4287 b'rev',
4297 [],
4288 [],
4298 _(b'revisions to select or follow from'),
4289 _(b'revisions to select or follow from'),
4299 _(b'REV'),
4290 _(b'REV'),
4300 ),
4291 ),
4301 (
4292 (
4302 b'L',
4293 b'L',
4303 b'line-range',
4294 b'line-range',
4304 [],
4295 [],
4305 _(b'follow line range of specified file (EXPERIMENTAL)'),
4296 _(b'follow line range of specified file (EXPERIMENTAL)'),
4306 _(b'FILE,RANGE'),
4297 _(b'FILE,RANGE'),
4307 ),
4298 ),
4308 (
4299 (
4309 b'',
4300 b'',
4310 b'removed',
4301 b'removed',
4311 None,
4302 None,
4312 _(b'include revisions where files were removed'),
4303 _(b'include revisions where files were removed'),
4313 ),
4304 ),
4314 (
4305 (
4315 b'm',
4306 b'm',
4316 b'only-merges',
4307 b'only-merges',
4317 None,
4308 None,
4318 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4309 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4319 ),
4310 ),
4320 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4311 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4321 (
4312 (
4322 b'',
4313 b'',
4323 b'only-branch',
4314 b'only-branch',
4324 [],
4315 [],
4325 _(
4316 _(
4326 b'show only changesets within the given named branch (DEPRECATED)'
4317 b'show only changesets within the given named branch (DEPRECATED)'
4327 ),
4318 ),
4328 _(b'BRANCH'),
4319 _(b'BRANCH'),
4329 ),
4320 ),
4330 (
4321 (
4331 b'b',
4322 b'b',
4332 b'branch',
4323 b'branch',
4333 [],
4324 [],
4334 _(b'show changesets within the given named branch'),
4325 _(b'show changesets within the given named branch'),
4335 _(b'BRANCH'),
4326 _(b'BRANCH'),
4336 ),
4327 ),
4337 (
4328 (
4338 b'B',
4329 b'B',
4339 b'bookmark',
4330 b'bookmark',
4340 [],
4331 [],
4341 _(b"show changesets within the given bookmark"),
4332 _(b"show changesets within the given bookmark"),
4342 _(b'BOOKMARK'),
4333 _(b'BOOKMARK'),
4343 ),
4334 ),
4344 (
4335 (
4345 b'P',
4336 b'P',
4346 b'prune',
4337 b'prune',
4347 [],
4338 [],
4348 _(b'do not display revision or any of its ancestors'),
4339 _(b'do not display revision or any of its ancestors'),
4349 _(b'REV'),
4340 _(b'REV'),
4350 ),
4341 ),
4351 ]
4342 ]
4352 + logopts
4343 + logopts
4353 + walkopts,
4344 + walkopts,
4354 _(b'[OPTION]... [FILE]'),
4345 _(b'[OPTION]... [FILE]'),
4355 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4346 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4356 helpbasic=True,
4347 helpbasic=True,
4357 inferrepo=True,
4348 inferrepo=True,
4358 intents={INTENT_READONLY},
4349 intents={INTENT_READONLY},
4359 )
4350 )
4360 def log(ui, repo, *pats, **opts):
4351 def log(ui, repo, *pats, **opts):
4361 """show revision history of entire repository or files
4352 """show revision history of entire repository or files
4362
4353
4363 Print the revision history of the specified files or the entire
4354 Print the revision history of the specified files or the entire
4364 project.
4355 project.
4365
4356
4366 If no revision range is specified, the default is ``tip:0`` unless
4357 If no revision range is specified, the default is ``tip:0`` unless
4367 --follow is set.
4358 --follow is set.
4368
4359
4369 File history is shown without following rename or copy history of
4360 File history is shown without following rename or copy history of
4370 files. Use -f/--follow with a filename to follow history across
4361 files. Use -f/--follow with a filename to follow history across
4371 renames and copies. --follow without a filename will only show
4362 renames and copies. --follow without a filename will only show
4372 ancestors of the starting revisions. The starting revisions can be
4363 ancestors of the starting revisions. The starting revisions can be
4373 specified by -r/--rev, which default to the working directory parent.
4364 specified by -r/--rev, which default to the working directory parent.
4374
4365
4375 By default this command prints revision number and changeset id,
4366 By default this command prints revision number and changeset id,
4376 tags, non-trivial parents, user, date and time, and a summary for
4367 tags, non-trivial parents, user, date and time, and a summary for
4377 each commit. When the -v/--verbose switch is used, the list of
4368 each commit. When the -v/--verbose switch is used, the list of
4378 changed files and full commit message are shown.
4369 changed files and full commit message are shown.
4379
4370
4380 With --graph the revisions are shown as an ASCII art DAG with the most
4371 With --graph the revisions are shown as an ASCII art DAG with the most
4381 recent changeset at the top.
4372 recent changeset at the top.
4382 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4373 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4383 involved in an unresolved merge conflict, '_' closes a branch,
4374 involved in an unresolved merge conflict, '_' closes a branch,
4384 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4375 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4385 changeset from the lines below is a parent of the 'o' merge on the same
4376 changeset from the lines below is a parent of the 'o' merge on the same
4386 line.
4377 line.
4387 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4378 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4388 of a '|' indicates one or more revisions in a path are omitted.
4379 of a '|' indicates one or more revisions in a path are omitted.
4389
4380
4390 .. container:: verbose
4381 .. container:: verbose
4391
4382
4392 Use -L/--line-range FILE,M:N options to follow the history of lines
4383 Use -L/--line-range FILE,M:N options to follow the history of lines
4393 from M to N in FILE. With -p/--patch only diff hunks affecting
4384 from M to N in FILE. With -p/--patch only diff hunks affecting
4394 specified line range will be shown. This option requires --follow;
4385 specified line range will be shown. This option requires --follow;
4395 it can be specified multiple times. Currently, this option is not
4386 it can be specified multiple times. Currently, this option is not
4396 compatible with --graph. This option is experimental.
4387 compatible with --graph. This option is experimental.
4397
4388
4398 .. note::
4389 .. note::
4399
4390
4400 :hg:`log --patch` may generate unexpected diff output for merge
4391 :hg:`log --patch` may generate unexpected diff output for merge
4401 changesets, as it will only compare the merge changeset against
4392 changesets, as it will only compare the merge changeset against
4402 its first parent. Also, only files different from BOTH parents
4393 its first parent. Also, only files different from BOTH parents
4403 will appear in files:.
4394 will appear in files:.
4404
4395
4405 .. note::
4396 .. note::
4406
4397
4407 For performance reasons, :hg:`log FILE` may omit duplicate changes
4398 For performance reasons, :hg:`log FILE` may omit duplicate changes
4408 made on branches and will not show removals or mode changes. To
4399 made on branches and will not show removals or mode changes. To
4409 see all such changes, use the --removed switch.
4400 see all such changes, use the --removed switch.
4410
4401
4411 .. container:: verbose
4402 .. container:: verbose
4412
4403
4413 .. note::
4404 .. note::
4414
4405
4415 The history resulting from -L/--line-range options depends on diff
4406 The history resulting from -L/--line-range options depends on diff
4416 options; for instance if white-spaces are ignored, respective changes
4407 options; for instance if white-spaces are ignored, respective changes
4417 with only white-spaces in specified line range will not be listed.
4408 with only white-spaces in specified line range will not be listed.
4418
4409
4419 .. container:: verbose
4410 .. container:: verbose
4420
4411
4421 Some examples:
4412 Some examples:
4422
4413
4423 - changesets with full descriptions and file lists::
4414 - changesets with full descriptions and file lists::
4424
4415
4425 hg log -v
4416 hg log -v
4426
4417
4427 - changesets ancestral to the working directory::
4418 - changesets ancestral to the working directory::
4428
4419
4429 hg log -f
4420 hg log -f
4430
4421
4431 - last 10 commits on the current branch::
4422 - last 10 commits on the current branch::
4432
4423
4433 hg log -l 10 -b .
4424 hg log -l 10 -b .
4434
4425
4435 - changesets showing all modifications of a file, including removals::
4426 - changesets showing all modifications of a file, including removals::
4436
4427
4437 hg log --removed file.c
4428 hg log --removed file.c
4438
4429
4439 - all changesets that touch a directory, with diffs, excluding merges::
4430 - all changesets that touch a directory, with diffs, excluding merges::
4440
4431
4441 hg log -Mp lib/
4432 hg log -Mp lib/
4442
4433
4443 - all revision numbers that match a keyword::
4434 - all revision numbers that match a keyword::
4444
4435
4445 hg log -k bug --template "{rev}\\n"
4436 hg log -k bug --template "{rev}\\n"
4446
4437
4447 - the full hash identifier of the working directory parent::
4438 - the full hash identifier of the working directory parent::
4448
4439
4449 hg log -r . --template "{node}\\n"
4440 hg log -r . --template "{node}\\n"
4450
4441
4451 - list available log templates::
4442 - list available log templates::
4452
4443
4453 hg log -T list
4444 hg log -T list
4454
4445
4455 - check if a given changeset is included in a tagged release::
4446 - check if a given changeset is included in a tagged release::
4456
4447
4457 hg log -r "a21ccf and ancestor(1.9)"
4448 hg log -r "a21ccf and ancestor(1.9)"
4458
4449
4459 - find all changesets by some user in a date range::
4450 - find all changesets by some user in a date range::
4460
4451
4461 hg log -k alice -d "may 2008 to jul 2008"
4452 hg log -k alice -d "may 2008 to jul 2008"
4462
4453
4463 - summary of all changesets after the last tag::
4454 - summary of all changesets after the last tag::
4464
4455
4465 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4456 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4466
4457
4467 - changesets touching lines 13 to 23 for file.c::
4458 - changesets touching lines 13 to 23 for file.c::
4468
4459
4469 hg log -L file.c,13:23
4460 hg log -L file.c,13:23
4470
4461
4471 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4462 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4472 main.c with patch::
4463 main.c with patch::
4473
4464
4474 hg log -L file.c,13:23 -L main.c,2:6 -p
4465 hg log -L file.c,13:23 -L main.c,2:6 -p
4475
4466
4476 See :hg:`help dates` for a list of formats valid for -d/--date.
4467 See :hg:`help dates` for a list of formats valid for -d/--date.
4477
4468
4478 See :hg:`help revisions` for more about specifying and ordering
4469 See :hg:`help revisions` for more about specifying and ordering
4479 revisions.
4470 revisions.
4480
4471
4481 See :hg:`help templates` for more about pre-packaged styles and
4472 See :hg:`help templates` for more about pre-packaged styles and
4482 specifying custom templates. The default template used by the log
4473 specifying custom templates. The default template used by the log
4483 command can be customized via the ``command-templates.log`` configuration
4474 command can be customized via the ``command-templates.log`` configuration
4484 setting.
4475 setting.
4485
4476
4486 Returns 0 on success.
4477 Returns 0 on success.
4487
4478
4488 """
4479 """
4489 opts = pycompat.byteskwargs(opts)
4480 opts = pycompat.byteskwargs(opts)
4490 linerange = opts.get(b'line_range')
4481 linerange = opts.get(b'line_range')
4491
4482
4492 if linerange and not opts.get(b'follow'):
4483 if linerange and not opts.get(b'follow'):
4493 raise error.InputError(_(b'--line-range requires --follow'))
4484 raise error.InputError(_(b'--line-range requires --follow'))
4494
4485
4495 if linerange and pats:
4486 if linerange and pats:
4496 # TODO: take pats as patterns with no line-range filter
4487 # TODO: take pats as patterns with no line-range filter
4497 raise error.InputError(
4488 raise error.InputError(
4498 _(b'FILE arguments are not compatible with --line-range option')
4489 _(b'FILE arguments are not compatible with --line-range option')
4499 )
4490 )
4500
4491
4501 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4492 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4502 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4493 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4503 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4494 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4504 if linerange:
4495 if linerange:
4505 # TODO: should follow file history from logcmdutil._initialrevs(),
4496 # TODO: should follow file history from logcmdutil._initialrevs(),
4506 # then filter the result by logcmdutil._makerevset() and --limit
4497 # then filter the result by logcmdutil._makerevset() and --limit
4507 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4498 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4508
4499
4509 getcopies = None
4500 getcopies = None
4510 if opts.get(b'copies'):
4501 if opts.get(b'copies'):
4511 endrev = None
4502 endrev = None
4512 if revs:
4503 if revs:
4513 endrev = revs.max() + 1
4504 endrev = revs.max() + 1
4514 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4505 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4515
4506
4516 ui.pager(b'log')
4507 ui.pager(b'log')
4517 displayer = logcmdutil.changesetdisplayer(
4508 displayer = logcmdutil.changesetdisplayer(
4518 ui, repo, opts, differ, buffered=True
4509 ui, repo, opts, differ, buffered=True
4519 )
4510 )
4520 if opts.get(b'graph'):
4511 if opts.get(b'graph'):
4521 displayfn = logcmdutil.displaygraphrevs
4512 displayfn = logcmdutil.displaygraphrevs
4522 else:
4513 else:
4523 displayfn = logcmdutil.displayrevs
4514 displayfn = logcmdutil.displayrevs
4524 displayfn(ui, repo, revs, displayer, getcopies)
4515 displayfn(ui, repo, revs, displayer, getcopies)
4525
4516
4526
4517
4527 @command(
4518 @command(
4528 b'manifest',
4519 b'manifest',
4529 [
4520 [
4530 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4521 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4531 (b'', b'all', False, _(b"list files from all revisions")),
4522 (b'', b'all', False, _(b"list files from all revisions")),
4532 ]
4523 ]
4533 + formatteropts,
4524 + formatteropts,
4534 _(b'[-r REV]'),
4525 _(b'[-r REV]'),
4535 helpcategory=command.CATEGORY_MAINTENANCE,
4526 helpcategory=command.CATEGORY_MAINTENANCE,
4536 intents={INTENT_READONLY},
4527 intents={INTENT_READONLY},
4537 )
4528 )
4538 def manifest(ui, repo, node=None, rev=None, **opts):
4529 def manifest(ui, repo, node=None, rev=None, **opts):
4539 """output the current or given revision of the project manifest
4530 """output the current or given revision of the project manifest
4540
4531
4541 Print a list of version controlled files for the given revision.
4532 Print a list of version controlled files for the given revision.
4542 If no revision is given, the first parent of the working directory
4533 If no revision is given, the first parent of the working directory
4543 is used, or the null revision if no revision is checked out.
4534 is used, or the null revision if no revision is checked out.
4544
4535
4545 With -v, print file permissions, symlink and executable bits.
4536 With -v, print file permissions, symlink and executable bits.
4546 With --debug, print file revision hashes.
4537 With --debug, print file revision hashes.
4547
4538
4548 If option --all is specified, the list of all files from all revisions
4539 If option --all is specified, the list of all files from all revisions
4549 is printed. This includes deleted and renamed files.
4540 is printed. This includes deleted and renamed files.
4550
4541
4551 Returns 0 on success.
4542 Returns 0 on success.
4552 """
4543 """
4553 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4544 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4554
4545
4555 if opts.get('all'):
4546 if opts.get('all'):
4556 if rev or node:
4547 if rev or node:
4557 raise error.InputError(_(b"can't specify a revision with --all"))
4548 raise error.InputError(_(b"can't specify a revision with --all"))
4558
4549
4559 res = set()
4550 res = set()
4560 for rev in repo:
4551 for rev in repo:
4561 ctx = repo[rev]
4552 ctx = repo[rev]
4562 res |= set(ctx.files())
4553 res |= set(ctx.files())
4563
4554
4564 ui.pager(b'manifest')
4555 ui.pager(b'manifest')
4565 for f in sorted(res):
4556 for f in sorted(res):
4566 fm.startitem()
4557 fm.startitem()
4567 fm.write(b"path", b'%s\n', f)
4558 fm.write(b"path", b'%s\n', f)
4568 fm.end()
4559 fm.end()
4569 return
4560 return
4570
4561
4571 if rev and node:
4562 if rev and node:
4572 raise error.InputError(_(b"please specify just one revision"))
4563 raise error.InputError(_(b"please specify just one revision"))
4573
4564
4574 if not node:
4565 if not node:
4575 node = rev
4566 node = rev
4576
4567
4577 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4568 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4578 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4569 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4579 if node:
4570 if node:
4580 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4571 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4581 ctx = logcmdutil.revsingle(repo, node)
4572 ctx = logcmdutil.revsingle(repo, node)
4582 mf = ctx.manifest()
4573 mf = ctx.manifest()
4583 ui.pager(b'manifest')
4574 ui.pager(b'manifest')
4584 for f in ctx:
4575 for f in ctx:
4585 fm.startitem()
4576 fm.startitem()
4586 fm.context(ctx=ctx)
4577 fm.context(ctx=ctx)
4587 fl = ctx[f].flags()
4578 fl = ctx[f].flags()
4588 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4579 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4589 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4580 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4590 fm.write(b'path', b'%s\n', f)
4581 fm.write(b'path', b'%s\n', f)
4591 fm.end()
4582 fm.end()
4592
4583
4593
4584
4594 @command(
4585 @command(
4595 b'merge',
4586 b'merge',
4596 [
4587 [
4597 (
4588 (
4598 b'f',
4589 b'f',
4599 b'force',
4590 b'force',
4600 None,
4591 None,
4601 _(b'force a merge including outstanding changes (DEPRECATED)'),
4592 _(b'force a merge including outstanding changes (DEPRECATED)'),
4602 ),
4593 ),
4603 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4594 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4604 (
4595 (
4605 b'P',
4596 b'P',
4606 b'preview',
4597 b'preview',
4607 None,
4598 None,
4608 _(b'review revisions to merge (no merge is performed)'),
4599 _(b'review revisions to merge (no merge is performed)'),
4609 ),
4600 ),
4610 (b'', b'abort', None, _(b'abort the ongoing merge')),
4601 (b'', b'abort', None, _(b'abort the ongoing merge')),
4611 ]
4602 ]
4612 + mergetoolopts,
4603 + mergetoolopts,
4613 _(b'[-P] [[-r] REV]'),
4604 _(b'[-P] [[-r] REV]'),
4614 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4605 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4615 helpbasic=True,
4606 helpbasic=True,
4616 )
4607 )
4617 def merge(ui, repo, node=None, **opts):
4608 def merge(ui, repo, node=None, **opts):
4618 """merge another revision into working directory
4609 """merge another revision into working directory
4619
4610
4620 The current working directory is updated with all changes made in
4611 The current working directory is updated with all changes made in
4621 the requested revision since the last common predecessor revision.
4612 the requested revision since the last common predecessor revision.
4622
4613
4623 Files that changed between either parent are marked as changed for
4614 Files that changed between either parent are marked as changed for
4624 the next commit and a commit must be performed before any further
4615 the next commit and a commit must be performed before any further
4625 updates to the repository are allowed. The next commit will have
4616 updates to the repository are allowed. The next commit will have
4626 two parents.
4617 two parents.
4627
4618
4628 ``--tool`` can be used to specify the merge tool used for file
4619 ``--tool`` can be used to specify the merge tool used for file
4629 merges. It overrides the HGMERGE environment variable and your
4620 merges. It overrides the HGMERGE environment variable and your
4630 configuration files. See :hg:`help merge-tools` for options.
4621 configuration files. See :hg:`help merge-tools` for options.
4631
4622
4632 If no revision is specified, the working directory's parent is a
4623 If no revision is specified, the working directory's parent is a
4633 head revision, and the current branch contains exactly one other
4624 head revision, and the current branch contains exactly one other
4634 head, the other head is merged with by default. Otherwise, an
4625 head, the other head is merged with by default. Otherwise, an
4635 explicit revision with which to merge must be provided.
4626 explicit revision with which to merge must be provided.
4636
4627
4637 See :hg:`help resolve` for information on handling file conflicts.
4628 See :hg:`help resolve` for information on handling file conflicts.
4638
4629
4639 To undo an uncommitted merge, use :hg:`merge --abort` which
4630 To undo an uncommitted merge, use :hg:`merge --abort` which
4640 will check out a clean copy of the original merge parent, losing
4631 will check out a clean copy of the original merge parent, losing
4641 all changes.
4632 all changes.
4642
4633
4643 Returns 0 on success, 1 if there are unresolved files.
4634 Returns 0 on success, 1 if there are unresolved files.
4644 """
4635 """
4645
4636
4646 abort = opts.get('abort')
4637 abort = opts.get('abort')
4647 if abort and repo.dirstate.p2() == repo.nullid:
4638 if abort and repo.dirstate.p2() == repo.nullid:
4648 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4639 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4649 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4640 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4650 if abort:
4641 if abort:
4651 state = cmdutil.getunfinishedstate(repo)
4642 state = cmdutil.getunfinishedstate(repo)
4652 if state and state._opname != b'merge':
4643 if state and state._opname != b'merge':
4653 raise error.StateError(
4644 raise error.StateError(
4654 _(b'cannot abort merge with %s in progress') % (state._opname),
4645 _(b'cannot abort merge with %s in progress') % (state._opname),
4655 hint=state.hint(),
4646 hint=state.hint(),
4656 )
4647 )
4657 if node:
4648 if node:
4658 raise error.InputError(_(b"cannot specify a node with --abort"))
4649 raise error.InputError(_(b"cannot specify a node with --abort"))
4659 return hg.abortmerge(repo.ui, repo)
4650 return hg.abortmerge(repo.ui, repo)
4660
4651
4661 if opts.get('rev') and node:
4652 if opts.get('rev') and node:
4662 raise error.InputError(_(b"please specify just one revision"))
4653 raise error.InputError(_(b"please specify just one revision"))
4663 if not node:
4654 if not node:
4664 node = opts.get('rev')
4655 node = opts.get('rev')
4665
4656
4666 if node:
4657 if node:
4667 ctx = logcmdutil.revsingle(repo, node)
4658 ctx = logcmdutil.revsingle(repo, node)
4668 else:
4659 else:
4669 if ui.configbool(b'commands', b'merge.require-rev'):
4660 if ui.configbool(b'commands', b'merge.require-rev'):
4670 raise error.InputError(
4661 raise error.InputError(
4671 _(
4662 _(
4672 b'configuration requires specifying revision to merge '
4663 b'configuration requires specifying revision to merge '
4673 b'with'
4664 b'with'
4674 )
4665 )
4675 )
4666 )
4676 ctx = repo[destutil.destmerge(repo)]
4667 ctx = repo[destutil.destmerge(repo)]
4677
4668
4678 if ctx.node() is None:
4669 if ctx.node() is None:
4679 raise error.InputError(
4670 raise error.InputError(
4680 _(b'merging with the working copy has no effect')
4671 _(b'merging with the working copy has no effect')
4681 )
4672 )
4682
4673
4683 if opts.get('preview'):
4674 if opts.get('preview'):
4684 # find nodes that are ancestors of p2 but not of p1
4675 # find nodes that are ancestors of p2 but not of p1
4685 p1 = repo[b'.'].node()
4676 p1 = repo[b'.'].node()
4686 p2 = ctx.node()
4677 p2 = ctx.node()
4687 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4678 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4688
4679
4689 displayer = logcmdutil.changesetdisplayer(
4680 displayer = logcmdutil.changesetdisplayer(
4690 ui, repo, pycompat.byteskwargs(opts)
4681 ui, repo, pycompat.byteskwargs(opts)
4691 )
4682 )
4692 for node in nodes:
4683 for node in nodes:
4693 displayer.show(repo[node])
4684 displayer.show(repo[node])
4694 displayer.close()
4685 displayer.close()
4695 return 0
4686 return 0
4696
4687
4697 # ui.forcemerge is an internal variable, do not document
4688 # ui.forcemerge is an internal variable, do not document
4698 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4689 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4699 with ui.configoverride(overrides, b'merge'):
4690 with ui.configoverride(overrides, b'merge'):
4700 force = opts.get('force')
4691 force = opts.get('force')
4701 labels = [b'working copy', b'merge rev', b'common ancestor']
4692 labels = [b'working copy', b'merge rev', b'common ancestor']
4702 return hg.merge(ctx, force=force, labels=labels)
4693 return hg.merge(ctx, force=force, labels=labels)
4703
4694
4704
4695
4705 statemod.addunfinished(
4696 statemod.addunfinished(
4706 b'merge',
4697 b'merge',
4707 fname=None,
4698 fname=None,
4708 clearable=True,
4699 clearable=True,
4709 allowcommit=True,
4700 allowcommit=True,
4710 cmdmsg=_(b'outstanding uncommitted merge'),
4701 cmdmsg=_(b'outstanding uncommitted merge'),
4711 abortfunc=hg.abortmerge,
4702 abortfunc=hg.abortmerge,
4712 statushint=_(
4703 statushint=_(
4713 b'To continue: hg commit\nTo abort: hg merge --abort'
4704 b'To continue: hg commit\nTo abort: hg merge --abort'
4714 ),
4705 ),
4715 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4706 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4716 )
4707 )
4717
4708
4718
4709
4719 @command(
4710 @command(
4720 b'outgoing|out',
4711 b'outgoing|out',
4721 [
4712 [
4722 (
4713 (
4723 b'f',
4714 b'f',
4724 b'force',
4715 b'force',
4725 None,
4716 None,
4726 _(b'run even when the destination is unrelated'),
4717 _(b'run even when the destination is unrelated'),
4727 ),
4718 ),
4728 (
4719 (
4729 b'r',
4720 b'r',
4730 b'rev',
4721 b'rev',
4731 [],
4722 [],
4732 _(b'a changeset intended to be included in the destination'),
4723 _(b'a changeset intended to be included in the destination'),
4733 _(b'REV'),
4724 _(b'REV'),
4734 ),
4725 ),
4735 (b'n', b'newest-first', None, _(b'show newest record first')),
4726 (b'n', b'newest-first', None, _(b'show newest record first')),
4736 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4727 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4737 (
4728 (
4738 b'b',
4729 b'b',
4739 b'branch',
4730 b'branch',
4740 [],
4731 [],
4741 _(b'a specific branch you would like to push'),
4732 _(b'a specific branch you would like to push'),
4742 _(b'BRANCH'),
4733 _(b'BRANCH'),
4743 ),
4734 ),
4744 ]
4735 ]
4745 + logopts
4736 + logopts
4746 + remoteopts
4737 + remoteopts
4747 + subrepoopts,
4738 + subrepoopts,
4748 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4739 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4749 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4740 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4750 )
4741 )
4751 def outgoing(ui, repo, *dests, **opts):
4742 def outgoing(ui, repo, *dests, **opts):
4752 """show changesets not found in the destination
4743 """show changesets not found in the destination
4753
4744
4754 Show changesets not found in the specified destination repository
4745 Show changesets not found in the specified destination repository
4755 or the default push location. These are the changesets that would
4746 or the default push location. These are the changesets that would
4756 be pushed if a push was requested.
4747 be pushed if a push was requested.
4757
4748
4758 See pull for details of valid destination formats.
4749 See pull for details of valid destination formats.
4759
4750
4760 .. container:: verbose
4751 .. container:: verbose
4761
4752
4762 With -B/--bookmarks, the result of bookmark comparison between
4753 With -B/--bookmarks, the result of bookmark comparison between
4763 local and remote repositories is displayed. With -v/--verbose,
4754 local and remote repositories is displayed. With -v/--verbose,
4764 status is also displayed for each bookmark like below::
4755 status is also displayed for each bookmark like below::
4765
4756
4766 BM1 01234567890a added
4757 BM1 01234567890a added
4767 BM2 deleted
4758 BM2 deleted
4768 BM3 234567890abc advanced
4759 BM3 234567890abc advanced
4769 BM4 34567890abcd diverged
4760 BM4 34567890abcd diverged
4770 BM5 4567890abcde changed
4761 BM5 4567890abcde changed
4771
4762
4772 The action taken when pushing depends on the
4763 The action taken when pushing depends on the
4773 status of each bookmark:
4764 status of each bookmark:
4774
4765
4775 :``added``: push with ``-B`` will create it
4766 :``added``: push with ``-B`` will create it
4776 :``deleted``: push with ``-B`` will delete it
4767 :``deleted``: push with ``-B`` will delete it
4777 :``advanced``: push will update it
4768 :``advanced``: push will update it
4778 :``diverged``: push with ``-B`` will update it
4769 :``diverged``: push with ``-B`` will update it
4779 :``changed``: push with ``-B`` will update it
4770 :``changed``: push with ``-B`` will update it
4780
4771
4781 From the point of view of pushing behavior, bookmarks
4772 From the point of view of pushing behavior, bookmarks
4782 existing only in the remote repository are treated as
4773 existing only in the remote repository are treated as
4783 ``deleted``, even if it is in fact added remotely.
4774 ``deleted``, even if it is in fact added remotely.
4784
4775
4785 Returns 0 if there are outgoing changes, 1 otherwise.
4776 Returns 0 if there are outgoing changes, 1 otherwise.
4786 """
4777 """
4787 opts = pycompat.byteskwargs(opts)
4778 opts = pycompat.byteskwargs(opts)
4788 if opts.get(b'bookmarks'):
4779 if opts.get(b'bookmarks'):
4789 for path in urlutil.get_push_paths(repo, ui, dests):
4780 for path in urlutil.get_push_paths(repo, ui, dests):
4790 other = hg.peer(repo, opts, path)
4781 other = hg.peer(repo, opts, path)
4791 try:
4782 try:
4792 if b'bookmarks' not in other.listkeys(b'namespaces'):
4783 if b'bookmarks' not in other.listkeys(b'namespaces'):
4793 ui.warn(_(b"remote doesn't support bookmarks\n"))
4784 ui.warn(_(b"remote doesn't support bookmarks\n"))
4794 return 0
4785 return 0
4795 ui.status(
4786 ui.status(
4796 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4787 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4797 )
4788 )
4798 ui.pager(b'outgoing')
4789 ui.pager(b'outgoing')
4799 return bookmarks.outgoing(ui, repo, other)
4790 return bookmarks.outgoing(ui, repo, other)
4800 finally:
4791 finally:
4801 other.close()
4792 other.close()
4802
4793
4803 return hg.outgoing(ui, repo, dests, opts)
4794 return hg.outgoing(ui, repo, dests, opts)
4804
4795
4805
4796
4806 @command(
4797 @command(
4807 b'parents',
4798 b'parents',
4808 [
4799 [
4809 (
4800 (
4810 b'r',
4801 b'r',
4811 b'rev',
4802 b'rev',
4812 b'',
4803 b'',
4813 _(b'show parents of the specified revision'),
4804 _(b'show parents of the specified revision'),
4814 _(b'REV'),
4805 _(b'REV'),
4815 ),
4806 ),
4816 ]
4807 ]
4817 + templateopts,
4808 + templateopts,
4818 _(b'[-r REV] [FILE]'),
4809 _(b'[-r REV] [FILE]'),
4819 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4810 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4820 inferrepo=True,
4811 inferrepo=True,
4821 )
4812 )
4822 def parents(ui, repo, file_=None, **opts):
4813 def parents(ui, repo, file_=None, **opts):
4823 """show the parents of the working directory or revision (DEPRECATED)
4814 """show the parents of the working directory or revision (DEPRECATED)
4824
4815
4825 Print the working directory's parent revisions. If a revision is
4816 Print the working directory's parent revisions. If a revision is
4826 given via -r/--rev, the parent of that revision will be printed.
4817 given via -r/--rev, the parent of that revision will be printed.
4827 If a file argument is given, the revision in which the file was
4818 If a file argument is given, the revision in which the file was
4828 last changed (before the working directory revision or the
4819 last changed (before the working directory revision or the
4829 argument to --rev if given) is printed.
4820 argument to --rev if given) is printed.
4830
4821
4831 This command is equivalent to::
4822 This command is equivalent to::
4832
4823
4833 hg log -r "p1()+p2()" or
4824 hg log -r "p1()+p2()" or
4834 hg log -r "p1(REV)+p2(REV)" or
4825 hg log -r "p1(REV)+p2(REV)" or
4835 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4826 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4836 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4827 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4837
4828
4838 See :hg:`summary` and :hg:`help revsets` for related information.
4829 See :hg:`summary` and :hg:`help revsets` for related information.
4839
4830
4840 Returns 0 on success.
4831 Returns 0 on success.
4841 """
4832 """
4842
4833
4843 opts = pycompat.byteskwargs(opts)
4834 opts = pycompat.byteskwargs(opts)
4844 rev = opts.get(b'rev')
4835 rev = opts.get(b'rev')
4845 if rev:
4836 if rev:
4846 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4837 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4847 ctx = logcmdutil.revsingle(repo, rev, None)
4838 ctx = logcmdutil.revsingle(repo, rev, None)
4848
4839
4849 if file_:
4840 if file_:
4850 m = scmutil.match(ctx, (file_,), opts)
4841 m = scmutil.match(ctx, (file_,), opts)
4851 if m.anypats() or len(m.files()) != 1:
4842 if m.anypats() or len(m.files()) != 1:
4852 raise error.InputError(_(b'can only specify an explicit filename'))
4843 raise error.InputError(_(b'can only specify an explicit filename'))
4853 file_ = m.files()[0]
4844 file_ = m.files()[0]
4854 filenodes = []
4845 filenodes = []
4855 for cp in ctx.parents():
4846 for cp in ctx.parents():
4856 if not cp:
4847 if not cp:
4857 continue
4848 continue
4858 try:
4849 try:
4859 filenodes.append(cp.filenode(file_))
4850 filenodes.append(cp.filenode(file_))
4860 except error.LookupError:
4851 except error.LookupError:
4861 pass
4852 pass
4862 if not filenodes:
4853 if not filenodes:
4863 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4854 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4864 p = []
4855 p = []
4865 for fn in filenodes:
4856 for fn in filenodes:
4866 fctx = repo.filectx(file_, fileid=fn)
4857 fctx = repo.filectx(file_, fileid=fn)
4867 p.append(fctx.node())
4858 p.append(fctx.node())
4868 else:
4859 else:
4869 p = [cp.node() for cp in ctx.parents()]
4860 p = [cp.node() for cp in ctx.parents()]
4870
4861
4871 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4862 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4872 for n in p:
4863 for n in p:
4873 if n != repo.nullid:
4864 if n != repo.nullid:
4874 displayer.show(repo[n])
4865 displayer.show(repo[n])
4875 displayer.close()
4866 displayer.close()
4876
4867
4877
4868
4878 @command(
4869 @command(
4879 b'paths',
4870 b'paths',
4880 formatteropts,
4871 formatteropts,
4881 _(b'[NAME]'),
4872 _(b'[NAME]'),
4882 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4873 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4883 optionalrepo=True,
4874 optionalrepo=True,
4884 intents={INTENT_READONLY},
4875 intents={INTENT_READONLY},
4885 )
4876 )
4886 def paths(ui, repo, search=None, **opts):
4877 def paths(ui, repo, search=None, **opts):
4887 """show aliases for remote repositories
4878 """show aliases for remote repositories
4888
4879
4889 Show definition of symbolic path name NAME. If no name is given,
4880 Show definition of symbolic path name NAME. If no name is given,
4890 show definition of all available names.
4881 show definition of all available names.
4891
4882
4892 Option -q/--quiet suppresses all output when searching for NAME
4883 Option -q/--quiet suppresses all output when searching for NAME
4893 and shows only the path names when listing all definitions.
4884 and shows only the path names when listing all definitions.
4894
4885
4895 Path names are defined in the [paths] section of your
4886 Path names are defined in the [paths] section of your
4896 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4887 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4897 repository, ``.hg/hgrc`` is used, too.
4888 repository, ``.hg/hgrc`` is used, too.
4898
4889
4899 The path names ``default`` and ``default-push`` have a special
4890 The path names ``default`` and ``default-push`` have a special
4900 meaning. When performing a push or pull operation, they are used
4891 meaning. When performing a push or pull operation, they are used
4901 as fallbacks if no location is specified on the command-line.
4892 as fallbacks if no location is specified on the command-line.
4902 When ``default-push`` is set, it will be used for push and
4893 When ``default-push`` is set, it will be used for push and
4903 ``default`` will be used for pull; otherwise ``default`` is used
4894 ``default`` will be used for pull; otherwise ``default`` is used
4904 as the fallback for both. When cloning a repository, the clone
4895 as the fallback for both. When cloning a repository, the clone
4905 source is written as ``default`` in ``.hg/hgrc``.
4896 source is written as ``default`` in ``.hg/hgrc``.
4906
4897
4907 .. note::
4898 .. note::
4908
4899
4909 ``default`` and ``default-push`` apply to all inbound (e.g.
4900 ``default`` and ``default-push`` apply to all inbound (e.g.
4910 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4901 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4911 and :hg:`bundle`) operations.
4902 and :hg:`bundle`) operations.
4912
4903
4913 See :hg:`help urls` for more information.
4904 See :hg:`help urls` for more information.
4914
4905
4915 .. container:: verbose
4906 .. container:: verbose
4916
4907
4917 Template:
4908 Template:
4918
4909
4919 The following keywords are supported. See also :hg:`help templates`.
4910 The following keywords are supported. See also :hg:`help templates`.
4920
4911
4921 :name: String. Symbolic name of the path alias.
4912 :name: String. Symbolic name of the path alias.
4922 :pushurl: String. URL for push operations.
4913 :pushurl: String. URL for push operations.
4923 :url: String. URL or directory path for the other operations.
4914 :url: String. URL or directory path for the other operations.
4924
4915
4925 Returns 0 on success.
4916 Returns 0 on success.
4926 """
4917 """
4927
4918
4928 pathitems = urlutil.list_paths(ui, search)
4919 pathitems = urlutil.list_paths(ui, search)
4929 ui.pager(b'paths')
4920 ui.pager(b'paths')
4930
4921
4931 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4922 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4932 if fm.isplain():
4923 if fm.isplain():
4933 hidepassword = urlutil.hidepassword
4924 hidepassword = urlutil.hidepassword
4934 else:
4925 else:
4935 hidepassword = bytes
4926 hidepassword = bytes
4936 if ui.quiet:
4927 if ui.quiet:
4937 namefmt = b'%s\n'
4928 namefmt = b'%s\n'
4938 else:
4929 else:
4939 namefmt = b'%s = '
4930 namefmt = b'%s = '
4940 showsubopts = not search and not ui.quiet
4931 showsubopts = not search and not ui.quiet
4941
4932
4942 for name, path in pathitems:
4933 for name, path in pathitems:
4943 fm.startitem()
4934 fm.startitem()
4944 fm.condwrite(not search, b'name', namefmt, name)
4935 fm.condwrite(not search, b'name', namefmt, name)
4945 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4936 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4946 for subopt, value in sorted(path.suboptions.items()):
4937 for subopt, value in sorted(path.suboptions.items()):
4947 assert subopt not in (b'name', b'url')
4938 assert subopt not in (b'name', b'url')
4948 if showsubopts:
4939 if showsubopts:
4949 fm.plain(b'%s:%s = ' % (name, subopt))
4940 fm.plain(b'%s:%s = ' % (name, subopt))
4950 display = urlutil.path_suboptions_display[subopt]
4941 display = urlutil.path_suboptions_display[subopt]
4951 value = display(value)
4942 value = display(value)
4952 fm.condwrite(showsubopts, subopt, b'%s\n', value)
4943 fm.condwrite(showsubopts, subopt, b'%s\n', value)
4953
4944
4954 fm.end()
4945 fm.end()
4955
4946
4956 if search and not pathitems:
4947 if search and not pathitems:
4957 if not ui.quiet:
4948 if not ui.quiet:
4958 ui.warn(_(b"not found!\n"))
4949 ui.warn(_(b"not found!\n"))
4959 return 1
4950 return 1
4960 else:
4951 else:
4961 return 0
4952 return 0
4962
4953
4963
4954
4964 @command(
4955 @command(
4965 b'phase',
4956 b'phase',
4966 [
4957 [
4967 (b'p', b'public', False, _(b'set changeset phase to public')),
4958 (b'p', b'public', False, _(b'set changeset phase to public')),
4968 (b'd', b'draft', False, _(b'set changeset phase to draft')),
4959 (b'd', b'draft', False, _(b'set changeset phase to draft')),
4969 (b's', b'secret', False, _(b'set changeset phase to secret')),
4960 (b's', b'secret', False, _(b'set changeset phase to secret')),
4970 (b'f', b'force', False, _(b'allow to move boundary backward')),
4961 (b'f', b'force', False, _(b'allow to move boundary backward')),
4971 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
4962 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
4972 ],
4963 ],
4973 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
4964 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
4974 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
4965 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
4975 )
4966 )
4976 def phase(ui, repo, *revs, **opts):
4967 def phase(ui, repo, *revs, **opts):
4977 """set or show the current phase name
4968 """set or show the current phase name
4978
4969
4979 With no argument, show the phase name of the current revision(s).
4970 With no argument, show the phase name of the current revision(s).
4980
4971
4981 With one of -p/--public, -d/--draft or -s/--secret, change the
4972 With one of -p/--public, -d/--draft or -s/--secret, change the
4982 phase value of the specified revisions.
4973 phase value of the specified revisions.
4983
4974
4984 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4975 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4985 lower phase to a higher phase. Phases are ordered as follows::
4976 lower phase to a higher phase. Phases are ordered as follows::
4986
4977
4987 public < draft < secret
4978 public < draft < secret
4988
4979
4989 Returns 0 on success, 1 if some phases could not be changed.
4980 Returns 0 on success, 1 if some phases could not be changed.
4990
4981
4991 (For more information about the phases concept, see :hg:`help phases`.)
4982 (For more information about the phases concept, see :hg:`help phases`.)
4992 """
4983 """
4993 opts = pycompat.byteskwargs(opts)
4984 opts = pycompat.byteskwargs(opts)
4994 # search for a unique phase argument
4985 # search for a unique phase argument
4995 targetphase = None
4986 targetphase = None
4996 for idx, name in enumerate(phases.cmdphasenames):
4987 for idx, name in enumerate(phases.cmdphasenames):
4997 if opts[name]:
4988 if opts[name]:
4998 if targetphase is not None:
4989 if targetphase is not None:
4999 raise error.InputError(_(b'only one phase can be specified'))
4990 raise error.InputError(_(b'only one phase can be specified'))
5000 targetphase = idx
4991 targetphase = idx
5001
4992
5002 # look for specified revision
4993 # look for specified revision
5003 revs = list(revs)
4994 revs = list(revs)
5004 revs.extend(opts[b'rev'])
4995 revs.extend(opts[b'rev'])
5005 if revs:
4996 if revs:
5006 revs = logcmdutil.revrange(repo, revs)
4997 revs = logcmdutil.revrange(repo, revs)
5007 else:
4998 else:
5008 # display both parents as the second parent phase can influence
4999 # display both parents as the second parent phase can influence
5009 # the phase of a merge commit
5000 # the phase of a merge commit
5010 revs = [c.rev() for c in repo[None].parents()]
5001 revs = [c.rev() for c in repo[None].parents()]
5011
5002
5012 ret = 0
5003 ret = 0
5013 if targetphase is None:
5004 if targetphase is None:
5014 # display
5005 # display
5015 for r in revs:
5006 for r in revs:
5016 ctx = repo[r]
5007 ctx = repo[r]
5017 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5008 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5018 else:
5009 else:
5019 with repo.lock(), repo.transaction(b"phase") as tr:
5010 with repo.lock(), repo.transaction(b"phase") as tr:
5020 # set phase
5011 # set phase
5021 if not revs:
5012 if not revs:
5022 raise error.InputError(_(b'empty revision set'))
5013 raise error.InputError(_(b'empty revision set'))
5023 nodes = [repo[r].node() for r in revs]
5014 nodes = [repo[r].node() for r in revs]
5024 # moving revision from public to draft may hide them
5015 # moving revision from public to draft may hide them
5025 # We have to check result on an unfiltered repository
5016 # We have to check result on an unfiltered repository
5026 unfi = repo.unfiltered()
5017 unfi = repo.unfiltered()
5027 getphase = unfi._phasecache.phase
5018 getphase = unfi._phasecache.phase
5028 olddata = [getphase(unfi, r) for r in unfi]
5019 olddata = [getphase(unfi, r) for r in unfi]
5029 phases.advanceboundary(repo, tr, targetphase, nodes)
5020 phases.advanceboundary(repo, tr, targetphase, nodes)
5030 if opts[b'force']:
5021 if opts[b'force']:
5031 phases.retractboundary(repo, tr, targetphase, nodes)
5022 phases.retractboundary(repo, tr, targetphase, nodes)
5032 getphase = unfi._phasecache.phase
5023 getphase = unfi._phasecache.phase
5033 newdata = [getphase(unfi, r) for r in unfi]
5024 newdata = [getphase(unfi, r) for r in unfi]
5034 changes = sum(newdata[r] != olddata[r] for r in unfi)
5025 changes = sum(newdata[r] != olddata[r] for r in unfi)
5035 cl = unfi.changelog
5026 cl = unfi.changelog
5036 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5027 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5037 if rejected:
5028 if rejected:
5038 ui.warn(
5029 ui.warn(
5039 _(
5030 _(
5040 b'cannot move %i changesets to a higher '
5031 b'cannot move %i changesets to a higher '
5041 b'phase, use --force\n'
5032 b'phase, use --force\n'
5042 )
5033 )
5043 % len(rejected)
5034 % len(rejected)
5044 )
5035 )
5045 ret = 1
5036 ret = 1
5046 if changes:
5037 if changes:
5047 msg = _(b'phase changed for %i changesets\n') % changes
5038 msg = _(b'phase changed for %i changesets\n') % changes
5048 if ret:
5039 if ret:
5049 ui.status(msg)
5040 ui.status(msg)
5050 else:
5041 else:
5051 ui.note(msg)
5042 ui.note(msg)
5052 else:
5043 else:
5053 ui.warn(_(b'no phases changed\n'))
5044 ui.warn(_(b'no phases changed\n'))
5054 return ret
5045 return ret
5055
5046
5056
5047
5057 @command(
5048 @command(
5058 b'pull',
5049 b'pull',
5059 [
5050 [
5060 (
5051 (
5061 b'u',
5052 b'u',
5062 b'update',
5053 b'update',
5063 None,
5054 None,
5064 _(b'update to new branch head if new descendants were pulled'),
5055 _(b'update to new branch head if new descendants were pulled'),
5065 ),
5056 ),
5066 (
5057 (
5067 b'f',
5058 b'f',
5068 b'force',
5059 b'force',
5069 None,
5060 None,
5070 _(b'run even when remote repository is unrelated'),
5061 _(b'run even when remote repository is unrelated'),
5071 ),
5062 ),
5072 (
5063 (
5073 b'',
5064 b'',
5074 b'confirm',
5065 b'confirm',
5075 None,
5066 None,
5076 _(b'confirm pull before applying changes'),
5067 _(b'confirm pull before applying changes'),
5077 ),
5068 ),
5078 (
5069 (
5079 b'r',
5070 b'r',
5080 b'rev',
5071 b'rev',
5081 [],
5072 [],
5082 _(b'a remote changeset intended to be added'),
5073 _(b'a remote changeset intended to be added'),
5083 _(b'REV'),
5074 _(b'REV'),
5084 ),
5075 ),
5085 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5076 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5086 (
5077 (
5087 b'b',
5078 b'b',
5088 b'branch',
5079 b'branch',
5089 [],
5080 [],
5090 _(b'a specific branch you would like to pull'),
5081 _(b'a specific branch you would like to pull'),
5091 _(b'BRANCH'),
5082 _(b'BRANCH'),
5092 ),
5083 ),
5093 (
5084 (
5094 b'',
5085 b'',
5095 b'remote-hidden',
5086 b'remote-hidden',
5096 False,
5087 False,
5097 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5088 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5098 ),
5089 ),
5099 ]
5090 ]
5100 + remoteopts,
5091 + remoteopts,
5101 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5092 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5102 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5093 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5103 helpbasic=True,
5094 helpbasic=True,
5104 )
5095 )
5105 def pull(ui, repo, *sources, **opts):
5096 def pull(ui, repo, *sources, **opts):
5106 """pull changes from the specified source
5097 """pull changes from the specified source
5107
5098
5108 Pull changes from a remote repository to a local one.
5099 Pull changes from a remote repository to a local one.
5109
5100
5110 This finds all changes from the repository at the specified path
5101 This finds all changes from the repository at the specified path
5111 or URL and adds them to a local repository (the current one unless
5102 or URL and adds them to a local repository (the current one unless
5112 -R is specified). By default, this does not update the copy of the
5103 -R is specified). By default, this does not update the copy of the
5113 project in the working directory.
5104 project in the working directory.
5114
5105
5115 When cloning from servers that support it, Mercurial may fetch
5106 When cloning from servers that support it, Mercurial may fetch
5116 pre-generated data. When this is done, hooks operating on incoming
5107 pre-generated data. When this is done, hooks operating on incoming
5117 changesets and changegroups may fire more than once, once for each
5108 changesets and changegroups may fire more than once, once for each
5118 pre-generated bundle and as well as for any additional remaining
5109 pre-generated bundle and as well as for any additional remaining
5119 data. See :hg:`help -e clonebundles` for more.
5110 data. See :hg:`help -e clonebundles` for more.
5120
5111
5121 Use :hg:`incoming` if you want to see what would have been added
5112 Use :hg:`incoming` if you want to see what would have been added
5122 by a pull at the time you issued this command. If you then decide
5113 by a pull at the time you issued this command. If you then decide
5123 to add those changes to the repository, you should use :hg:`pull
5114 to add those changes to the repository, you should use :hg:`pull
5124 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5115 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5125
5116
5126 If SOURCE is omitted, the 'default' path will be used.
5117 If SOURCE is omitted, the 'default' path will be used.
5127 See :hg:`help urls` for more information.
5118 See :hg:`help urls` for more information.
5128
5119
5129 If multiple sources are specified, they will be pulled sequentially as if
5120 If multiple sources are specified, they will be pulled sequentially as if
5130 the command was run multiple time. If --update is specify and the command
5121 the command was run multiple time. If --update is specify and the command
5131 will stop at the first failed --update.
5122 will stop at the first failed --update.
5132
5123
5133 Specifying bookmark as ``.`` is equivalent to specifying the active
5124 Specifying bookmark as ``.`` is equivalent to specifying the active
5134 bookmark's name.
5125 bookmark's name.
5135
5126
5136 .. container:: verbose
5127 .. container:: verbose
5137
5128
5138 One can use the `--remote-hidden` flag to pull changesets
5129 One can use the `--remote-hidden` flag to pull changesets
5139 hidden on the remote. This flag is "best effort", and will only
5130 hidden on the remote. This flag is "best effort", and will only
5140 work if the server supports the feature and is configured to
5131 work if the server supports the feature and is configured to
5141 allow the user to access hidden changesets. This option is
5132 allow the user to access hidden changesets. This option is
5142 experimental and backwards compatibility is not garanteed.
5133 experimental and backwards compatibility is not garanteed.
5143
5134
5144 Returns 0 on success, 1 if an update had unresolved files.
5135 Returns 0 on success, 1 if an update had unresolved files.
5145 """
5136 """
5146
5137
5147 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5138 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5148 msg = _(b'update destination required by configuration')
5139 msg = _(b'update destination required by configuration')
5149 hint = _(b'use hg pull followed by hg update DEST')
5140 hint = _(b'use hg pull followed by hg update DEST')
5150 raise error.InputError(msg, hint=hint)
5141 raise error.InputError(msg, hint=hint)
5151
5142
5152 update_conflict = None
5143 update_conflict = None
5153
5144
5154 for path in urlutil.get_pull_paths(repo, ui, sources):
5145 for path in urlutil.get_pull_paths(repo, ui, sources):
5155 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5146 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5156 ui.flush()
5147 ui.flush()
5157 other = hg.peer(
5148 other = hg.peer(
5158 repo,
5149 repo,
5159 pycompat.byteskwargs(opts),
5150 pycompat.byteskwargs(opts),
5160 path,
5151 path,
5161 remotehidden=opts['remote_hidden'],
5152 remotehidden=opts['remote_hidden'],
5162 )
5153 )
5163 update_conflict = None
5154 update_conflict = None
5164 try:
5155 try:
5165 branches = (path.branch, opts.get('branch', []))
5156 branches = (path.branch, opts.get('branch', []))
5166 revs, checkout = hg.addbranchrevs(
5157 revs, checkout = hg.addbranchrevs(
5167 repo,
5158 repo,
5168 other,
5159 other,
5169 branches,
5160 branches,
5170 opts.get('rev'),
5161 opts.get('rev'),
5171 remotehidden=opts['remote_hidden'],
5162 remotehidden=opts['remote_hidden'],
5172 )
5163 )
5173
5164
5174 pullopargs = {}
5165 pullopargs = {}
5175
5166
5176 nodes = None
5167 nodes = None
5177 if opts.get('bookmark') or revs:
5168 if opts.get('bookmark') or revs:
5178 # The list of bookmark used here is the same used to actually update
5169 # The list of bookmark used here is the same used to actually update
5179 # the bookmark names, to avoid the race from issue 4689 and we do
5170 # the bookmark names, to avoid the race from issue 4689 and we do
5180 # all lookup and bookmark queries in one go so they see the same
5171 # all lookup and bookmark queries in one go so they see the same
5181 # version of the server state (issue 4700).
5172 # version of the server state (issue 4700).
5182 nodes = []
5173 nodes = []
5183 fnodes = []
5174 fnodes = []
5184 revs = revs or []
5175 revs = revs or []
5185 if revs and not other.capable(b'lookup'):
5176 if revs and not other.capable(b'lookup'):
5186 err = _(
5177 err = _(
5187 b"other repository doesn't support revision lookup, "
5178 b"other repository doesn't support revision lookup, "
5188 b"so a rev cannot be specified."
5179 b"so a rev cannot be specified."
5189 )
5180 )
5190 raise error.Abort(err)
5181 raise error.Abort(err)
5191 with other.commandexecutor() as e:
5182 with other.commandexecutor() as e:
5192 fremotebookmarks = e.callcommand(
5183 fremotebookmarks = e.callcommand(
5193 b'listkeys', {b'namespace': b'bookmarks'}
5184 b'listkeys', {b'namespace': b'bookmarks'}
5194 )
5185 )
5195 for r in revs:
5186 for r in revs:
5196 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5187 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5197 remotebookmarks = fremotebookmarks.result()
5188 remotebookmarks = fremotebookmarks.result()
5198 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5189 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5199 pullopargs[b'remotebookmarks'] = remotebookmarks
5190 pullopargs[b'remotebookmarks'] = remotebookmarks
5200 for b in opts.get('bookmark', []):
5191 for b in opts.get('bookmark', []):
5201 b = repo._bookmarks.expandname(b)
5192 b = repo._bookmarks.expandname(b)
5202 if b not in remotebookmarks:
5193 if b not in remotebookmarks:
5203 raise error.InputError(
5194 raise error.InputError(
5204 _(b'remote bookmark %s not found!') % b
5195 _(b'remote bookmark %s not found!') % b
5205 )
5196 )
5206 nodes.append(remotebookmarks[b])
5197 nodes.append(remotebookmarks[b])
5207 for i, rev in enumerate(revs):
5198 for i, rev in enumerate(revs):
5208 node = fnodes[i].result()
5199 node = fnodes[i].result()
5209 nodes.append(node)
5200 nodes.append(node)
5210 if rev == checkout:
5201 if rev == checkout:
5211 checkout = node
5202 checkout = node
5212
5203
5213 wlock = util.nullcontextmanager()
5204 wlock = util.nullcontextmanager()
5214 if opts.get('update'):
5205 if opts.get('update'):
5215 wlock = repo.wlock()
5206 wlock = repo.wlock()
5216 with wlock:
5207 with wlock:
5217 pullopargs.update(opts.get('opargs', {}))
5208 pullopargs.update(opts.get('opargs', {}))
5218 modheads = exchange.pull(
5209 modheads = exchange.pull(
5219 repo,
5210 repo,
5220 other,
5211 other,
5221 path=path,
5212 path=path,
5222 heads=nodes,
5213 heads=nodes,
5223 force=opts.get('force'),
5214 force=opts.get('force'),
5224 bookmarks=opts.get('bookmark', ()),
5215 bookmarks=opts.get('bookmark', ()),
5225 opargs=pullopargs,
5216 opargs=pullopargs,
5226 confirm=opts.get('confirm'),
5217 confirm=opts.get('confirm'),
5227 ).cgresult
5218 ).cgresult
5228
5219
5229 # brev is a name, which might be a bookmark to be activated at
5220 # brev is a name, which might be a bookmark to be activated at
5230 # the end of the update. In other words, it is an explicit
5221 # the end of the update. In other words, it is an explicit
5231 # destination of the update
5222 # destination of the update
5232 brev = None
5223 brev = None
5233
5224
5234 if checkout:
5225 if checkout:
5235 checkout = repo.unfiltered().changelog.rev(checkout)
5226 checkout = repo.unfiltered().changelog.rev(checkout)
5236
5227
5237 # order below depends on implementation of
5228 # order below depends on implementation of
5238 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5229 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5239 # because 'checkout' is determined without it.
5230 # because 'checkout' is determined without it.
5240 if opts.get('rev'):
5231 if opts.get('rev'):
5241 brev = opts['rev'][0]
5232 brev = opts['rev'][0]
5242 elif opts.get('branch'):
5233 elif opts.get('branch'):
5243 brev = opts['branch'][0]
5234 brev = opts['branch'][0]
5244 else:
5235 else:
5245 brev = path.branch
5236 brev = path.branch
5246
5237
5247 # XXX path: we are losing the `path` object here. Keeping it
5238 # XXX path: we are losing the `path` object here. Keeping it
5248 # would be valuable. For example as a "variant" as we do
5239 # would be valuable. For example as a "variant" as we do
5249 # for pushes.
5240 # for pushes.
5250 repo._subtoppath = path.loc
5241 repo._subtoppath = path.loc
5251 try:
5242 try:
5252 update_conflict = cmdutil.postincoming(
5243 update_conflict = cmdutil.postincoming(
5253 ui, repo, modheads, opts.get('update'), checkout, brev
5244 ui, repo, modheads, opts.get('update'), checkout, brev
5254 )
5245 )
5255 except error.FilteredRepoLookupError as exc:
5246 except error.FilteredRepoLookupError as exc:
5256 msg = _(b'cannot update to target: %s') % exc.args[0]
5247 msg = _(b'cannot update to target: %s') % exc.args[0]
5257 exc.args = (msg,) + exc.args[1:]
5248 exc.args = (msg,) + exc.args[1:]
5258 raise
5249 raise
5259 finally:
5250 finally:
5260 del repo._subtoppath
5251 del repo._subtoppath
5261
5252
5262 finally:
5253 finally:
5263 other.close()
5254 other.close()
5264 # skip the remaining pull source if they are some conflict.
5255 # skip the remaining pull source if they are some conflict.
5265 if update_conflict:
5256 if update_conflict:
5266 break
5257 break
5267 if update_conflict:
5258 if update_conflict:
5268 return 1
5259 return 1
5269 else:
5260 else:
5270 return 0
5261 return 0
5271
5262
5272
5263
5273 @command(
5264 @command(
5274 b'purge|clean',
5265 b'purge|clean',
5275 [
5266 [
5276 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5267 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5277 (b'', b'all', None, _(b'purge ignored files too')),
5268 (b'', b'all', None, _(b'purge ignored files too')),
5278 (b'i', b'ignored', None, _(b'purge only ignored files')),
5269 (b'i', b'ignored', None, _(b'purge only ignored files')),
5279 (b'', b'dirs', None, _(b'purge empty directories')),
5270 (b'', b'dirs', None, _(b'purge empty directories')),
5280 (b'', b'files', None, _(b'purge files')),
5271 (b'', b'files', None, _(b'purge files')),
5281 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5272 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5282 (
5273 (
5283 b'0',
5274 b'0',
5284 b'print0',
5275 b'print0',
5285 None,
5276 None,
5286 _(
5277 _(
5287 b'end filenames with NUL, for use with xargs'
5278 b'end filenames with NUL, for use with xargs'
5288 b' (implies -p/--print)'
5279 b' (implies -p/--print)'
5289 ),
5280 ),
5290 ),
5281 ),
5291 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5282 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5292 ]
5283 ]
5293 + cmdutil.walkopts,
5284 + cmdutil.walkopts,
5294 _(b'hg purge [OPTION]... [DIR]...'),
5285 _(b'hg purge [OPTION]... [DIR]...'),
5295 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5286 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5296 )
5287 )
5297 def purge(ui, repo, *dirs, **opts):
5288 def purge(ui, repo, *dirs, **opts):
5298 """removes files not tracked by Mercurial
5289 """removes files not tracked by Mercurial
5299
5290
5300 Delete files not known to Mercurial. This is useful to test local
5291 Delete files not known to Mercurial. This is useful to test local
5301 and uncommitted changes in an otherwise-clean source tree.
5292 and uncommitted changes in an otherwise-clean source tree.
5302
5293
5303 This means that purge will delete the following by default:
5294 This means that purge will delete the following by default:
5304
5295
5305 - Unknown files: files marked with "?" by :hg:`status`
5296 - Unknown files: files marked with "?" by :hg:`status`
5306 - Empty directories: in fact Mercurial ignores directories unless
5297 - Empty directories: in fact Mercurial ignores directories unless
5307 they contain files under source control management
5298 they contain files under source control management
5308
5299
5309 But it will leave untouched:
5300 But it will leave untouched:
5310
5301
5311 - Modified and unmodified tracked files
5302 - Modified and unmodified tracked files
5312 - Ignored files (unless -i or --all is specified)
5303 - Ignored files (unless -i or --all is specified)
5313 - New files added to the repository (with :hg:`add`)
5304 - New files added to the repository (with :hg:`add`)
5314
5305
5315 The --files and --dirs options can be used to direct purge to delete
5306 The --files and --dirs options can be used to direct purge to delete
5316 only files, only directories, or both. If neither option is given,
5307 only files, only directories, or both. If neither option is given,
5317 both will be deleted.
5308 both will be deleted.
5318
5309
5319 If directories are given on the command line, only files in these
5310 If directories are given on the command line, only files in these
5320 directories are considered.
5311 directories are considered.
5321
5312
5322 Be careful with purge, as you could irreversibly delete some files
5313 Be careful with purge, as you could irreversibly delete some files
5323 you forgot to add to the repository. If you only want to print the
5314 you forgot to add to the repository. If you only want to print the
5324 list of files that this program would delete, use the --print
5315 list of files that this program would delete, use the --print
5325 option.
5316 option.
5326 """
5317 """
5327 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5318 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5328
5319
5329 act = not opts.get('print')
5320 act = not opts.get('print')
5330 eol = b'\n'
5321 eol = b'\n'
5331 if opts.get('print0'):
5322 if opts.get('print0'):
5332 eol = b'\0'
5323 eol = b'\0'
5333 act = False # --print0 implies --print
5324 act = False # --print0 implies --print
5334 if opts.get('all', False):
5325 if opts.get('all', False):
5335 ignored = True
5326 ignored = True
5336 unknown = True
5327 unknown = True
5337 else:
5328 else:
5338 ignored = opts.get('ignored', False)
5329 ignored = opts.get('ignored', False)
5339 unknown = not ignored
5330 unknown = not ignored
5340
5331
5341 removefiles = opts.get('files')
5332 removefiles = opts.get('files')
5342 removedirs = opts.get('dirs')
5333 removedirs = opts.get('dirs')
5343 confirm = opts.get('confirm')
5334 confirm = opts.get('confirm')
5344 if confirm is None:
5335 if confirm is None:
5345 try:
5336 try:
5346 extensions.find(b'purge')
5337 extensions.find(b'purge')
5347 confirm = False
5338 confirm = False
5348 except KeyError:
5339 except KeyError:
5349 confirm = True
5340 confirm = True
5350
5341
5351 if not removefiles and not removedirs:
5342 if not removefiles and not removedirs:
5352 removefiles = True
5343 removefiles = True
5353 removedirs = True
5344 removedirs = True
5354
5345
5355 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5346 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5356
5347
5357 paths = mergemod.purge(
5348 paths = mergemod.purge(
5358 repo,
5349 repo,
5359 match,
5350 match,
5360 unknown=unknown,
5351 unknown=unknown,
5361 ignored=ignored,
5352 ignored=ignored,
5362 removeemptydirs=removedirs,
5353 removeemptydirs=removedirs,
5363 removefiles=removefiles,
5354 removefiles=removefiles,
5364 abortonerror=opts.get('abort_on_err'),
5355 abortonerror=opts.get('abort_on_err'),
5365 noop=not act,
5356 noop=not act,
5366 confirm=confirm,
5357 confirm=confirm,
5367 )
5358 )
5368
5359
5369 for path in paths:
5360 for path in paths:
5370 if not act:
5361 if not act:
5371 ui.write(b'%s%s' % (path, eol))
5362 ui.write(b'%s%s' % (path, eol))
5372
5363
5373
5364
5374 @command(
5365 @command(
5375 b'push',
5366 b'push',
5376 [
5367 [
5377 (b'f', b'force', None, _(b'force push')),
5368 (b'f', b'force', None, _(b'force push')),
5378 (
5369 (
5379 b'r',
5370 b'r',
5380 b'rev',
5371 b'rev',
5381 [],
5372 [],
5382 _(b'a changeset intended to be included in the destination'),
5373 _(b'a changeset intended to be included in the destination'),
5383 _(b'REV'),
5374 _(b'REV'),
5384 ),
5375 ),
5385 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5376 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5386 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5377 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5387 (
5378 (
5388 b'b',
5379 b'b',
5389 b'branch',
5380 b'branch',
5390 [],
5381 [],
5391 _(b'a specific branch you would like to push'),
5382 _(b'a specific branch you would like to push'),
5392 _(b'BRANCH'),
5383 _(b'BRANCH'),
5393 ),
5384 ),
5394 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5385 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5395 (
5386 (
5396 b'',
5387 b'',
5397 b'pushvars',
5388 b'pushvars',
5398 [],
5389 [],
5399 _(b'variables that can be sent to server (ADVANCED)'),
5390 _(b'variables that can be sent to server (ADVANCED)'),
5400 ),
5391 ),
5401 (
5392 (
5402 b'',
5393 b'',
5403 b'publish',
5394 b'publish',
5404 False,
5395 False,
5405 _(b'push the changeset as public (EXPERIMENTAL)'),
5396 _(b'push the changeset as public (EXPERIMENTAL)'),
5406 ),
5397 ),
5407 ]
5398 ]
5408 + remoteopts,
5399 + remoteopts,
5409 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5400 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5410 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5401 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5411 helpbasic=True,
5402 helpbasic=True,
5412 )
5403 )
5413 def push(ui, repo, *dests, **opts):
5404 def push(ui, repo, *dests, **opts):
5414 """push changes to the specified destination
5405 """push changes to the specified destination
5415
5406
5416 Push changesets from the local repository to the specified
5407 Push changesets from the local repository to the specified
5417 destination.
5408 destination.
5418
5409
5419 This operation is symmetrical to pull: it is identical to a pull
5410 This operation is symmetrical to pull: it is identical to a pull
5420 in the destination repository from the current one.
5411 in the destination repository from the current one.
5421
5412
5422 By default, push will not allow creation of new heads at the
5413 By default, push will not allow creation of new heads at the
5423 destination, since multiple heads would make it unclear which head
5414 destination, since multiple heads would make it unclear which head
5424 to use. In this situation, it is recommended to pull and merge
5415 to use. In this situation, it is recommended to pull and merge
5425 before pushing.
5416 before pushing.
5426
5417
5427 Use --new-branch if you want to allow push to create a new named
5418 Use --new-branch if you want to allow push to create a new named
5428 branch that is not present at the destination. This allows you to
5419 branch that is not present at the destination. This allows you to
5429 only create a new branch without forcing other changes.
5420 only create a new branch without forcing other changes.
5430
5421
5431 .. note::
5422 .. note::
5432
5423
5433 Extra care should be taken with the -f/--force option,
5424 Extra care should be taken with the -f/--force option,
5434 which will push all new heads on all branches, an action which will
5425 which will push all new heads on all branches, an action which will
5435 almost always cause confusion for collaborators.
5426 almost always cause confusion for collaborators.
5436
5427
5437 If -r/--rev is used, the specified revision and all its ancestors
5428 If -r/--rev is used, the specified revision and all its ancestors
5438 will be pushed to the remote repository.
5429 will be pushed to the remote repository.
5439
5430
5440 If -B/--bookmark is used, the specified bookmarked revision, its
5431 If -B/--bookmark is used, the specified bookmarked revision, its
5441 ancestors, and the bookmark will be pushed to the remote
5432 ancestors, and the bookmark will be pushed to the remote
5442 repository. Specifying ``.`` is equivalent to specifying the active
5433 repository. Specifying ``.`` is equivalent to specifying the active
5443 bookmark's name. Use the --all-bookmarks option for pushing all
5434 bookmark's name. Use the --all-bookmarks option for pushing all
5444 current bookmarks.
5435 current bookmarks.
5445
5436
5446 Please see :hg:`help urls` for important details about ``ssh://``
5437 Please see :hg:`help urls` for important details about ``ssh://``
5447 URLs. If DESTINATION is omitted, a default path will be used.
5438 URLs. If DESTINATION is omitted, a default path will be used.
5448
5439
5449 When passed multiple destinations, push will process them one after the
5440 When passed multiple destinations, push will process them one after the
5450 other, but stop should an error occur.
5441 other, but stop should an error occur.
5451
5442
5452 .. container:: verbose
5443 .. container:: verbose
5453
5444
5454 The --pushvars option sends strings to the server that become
5445 The --pushvars option sends strings to the server that become
5455 environment variables prepended with ``HG_USERVAR_``. For example,
5446 environment variables prepended with ``HG_USERVAR_``. For example,
5456 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5447 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5457 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5448 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5458
5449
5459 pushvars can provide for user-overridable hooks as well as set debug
5450 pushvars can provide for user-overridable hooks as well as set debug
5460 levels. One example is having a hook that blocks commits containing
5451 levels. One example is having a hook that blocks commits containing
5461 conflict markers, but enables the user to override the hook if the file
5452 conflict markers, but enables the user to override the hook if the file
5462 is using conflict markers for testing purposes or the file format has
5453 is using conflict markers for testing purposes or the file format has
5463 strings that look like conflict markers.
5454 strings that look like conflict markers.
5464
5455
5465 By default, servers will ignore `--pushvars`. To enable it add the
5456 By default, servers will ignore `--pushvars`. To enable it add the
5466 following to your configuration file::
5457 following to your configuration file::
5467
5458
5468 [push]
5459 [push]
5469 pushvars.server = true
5460 pushvars.server = true
5470
5461
5471 Returns 0 if push was successful, 1 if nothing to push.
5462 Returns 0 if push was successful, 1 if nothing to push.
5472 """
5463 """
5473
5464
5474 opts = pycompat.byteskwargs(opts)
5465 opts = pycompat.byteskwargs(opts)
5475
5466
5476 if opts.get(b'all_bookmarks'):
5467 if opts.get(b'all_bookmarks'):
5477 cmdutil.check_incompatible_arguments(
5468 cmdutil.check_incompatible_arguments(
5478 opts,
5469 opts,
5479 b'all_bookmarks',
5470 b'all_bookmarks',
5480 [b'bookmark', b'rev'],
5471 [b'bookmark', b'rev'],
5481 )
5472 )
5482 opts[b'bookmark'] = list(repo._bookmarks)
5473 opts[b'bookmark'] = list(repo._bookmarks)
5483
5474
5484 if opts.get(b'bookmark'):
5475 if opts.get(b'bookmark'):
5485 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5476 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5486 for b in opts[b'bookmark']:
5477 for b in opts[b'bookmark']:
5487 # translate -B options to -r so changesets get pushed
5478 # translate -B options to -r so changesets get pushed
5488 b = repo._bookmarks.expandname(b)
5479 b = repo._bookmarks.expandname(b)
5489 if b in repo._bookmarks:
5480 if b in repo._bookmarks:
5490 opts.setdefault(b'rev', []).append(b)
5481 opts.setdefault(b'rev', []).append(b)
5491 else:
5482 else:
5492 # if we try to push a deleted bookmark, translate it to null
5483 # if we try to push a deleted bookmark, translate it to null
5493 # this lets simultaneous -r, -b options continue working
5484 # this lets simultaneous -r, -b options continue working
5494 opts.setdefault(b'rev', []).append(b"null")
5485 opts.setdefault(b'rev', []).append(b"null")
5495
5486
5496 some_pushed = False
5487 some_pushed = False
5497 result = 0
5488 result = 0
5498 for path in urlutil.get_push_paths(repo, ui, dests):
5489 for path in urlutil.get_push_paths(repo, ui, dests):
5499 dest = path.loc
5490 dest = path.loc
5500 branches = (path.branch, opts.get(b'branch') or [])
5491 branches = (path.branch, opts.get(b'branch') or [])
5501 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5492 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5502 revs, checkout = hg.addbranchrevs(
5493 revs, checkout = hg.addbranchrevs(
5503 repo, repo, branches, opts.get(b'rev')
5494 repo, repo, branches, opts.get(b'rev')
5504 )
5495 )
5505 other = hg.peer(repo, opts, dest)
5496 other = hg.peer(repo, opts, dest)
5506
5497
5507 try:
5498 try:
5508 if revs:
5499 if revs:
5509 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5500 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5510 if not revs:
5501 if not revs:
5511 raise error.InputError(
5502 raise error.InputError(
5512 _(b"specified revisions evaluate to an empty set"),
5503 _(b"specified revisions evaluate to an empty set"),
5513 hint=_(b"use different revision arguments"),
5504 hint=_(b"use different revision arguments"),
5514 )
5505 )
5515 elif path.pushrev:
5506 elif path.pushrev:
5516 # It doesn't make any sense to specify ancestor revisions. So limit
5507 # It doesn't make any sense to specify ancestor revisions. So limit
5517 # to DAG heads to make discovery simpler.
5508 # to DAG heads to make discovery simpler.
5518 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5509 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5519 revs = scmutil.revrange(repo, [expr])
5510 revs = scmutil.revrange(repo, [expr])
5520 revs = [repo[rev].node() for rev in revs]
5511 revs = [repo[rev].node() for rev in revs]
5521 if not revs:
5512 if not revs:
5522 raise error.InputError(
5513 raise error.InputError(
5523 _(
5514 _(
5524 b'default push revset for path evaluates to an empty set'
5515 b'default push revset for path evaluates to an empty set'
5525 )
5516 )
5526 )
5517 )
5527 elif ui.configbool(b'commands', b'push.require-revs'):
5518 elif ui.configbool(b'commands', b'push.require-revs'):
5528 raise error.InputError(
5519 raise error.InputError(
5529 _(b'no revisions specified to push'),
5520 _(b'no revisions specified to push'),
5530 hint=_(b'did you mean "hg push -r ."?'),
5521 hint=_(b'did you mean "hg push -r ."?'),
5531 )
5522 )
5532
5523
5533 repo._subtoppath = dest
5524 repo._subtoppath = dest
5534 try:
5525 try:
5535 # push subrepos depth-first for coherent ordering
5526 # push subrepos depth-first for coherent ordering
5536 c = repo[b'.']
5527 c = repo[b'.']
5537 subs = c.substate # only repos that are committed
5528 subs = c.substate # only repos that are committed
5538 for s in sorted(subs):
5529 for s in sorted(subs):
5539 sub_result = c.sub(s).push(opts)
5530 sub_result = c.sub(s).push(opts)
5540 if sub_result == 0:
5531 if sub_result == 0:
5541 return 1
5532 return 1
5542 finally:
5533 finally:
5543 del repo._subtoppath
5534 del repo._subtoppath
5544
5535
5545 opargs = dict(
5536 opargs = dict(
5546 opts.get(b'opargs', {})
5537 opts.get(b'opargs', {})
5547 ) # copy opargs since we may mutate it
5538 ) # copy opargs since we may mutate it
5548 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5539 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5549
5540
5550 pushop = exchange.push(
5541 pushop = exchange.push(
5551 repo,
5542 repo,
5552 other,
5543 other,
5553 opts.get(b'force'),
5544 opts.get(b'force'),
5554 revs=revs,
5545 revs=revs,
5555 newbranch=opts.get(b'new_branch'),
5546 newbranch=opts.get(b'new_branch'),
5556 bookmarks=opts.get(b'bookmark', ()),
5547 bookmarks=opts.get(b'bookmark', ()),
5557 publish=opts.get(b'publish'),
5548 publish=opts.get(b'publish'),
5558 opargs=opargs,
5549 opargs=opargs,
5559 )
5550 )
5560
5551
5561 if pushop.cgresult == 0:
5552 if pushop.cgresult == 0:
5562 result = 1
5553 result = 1
5563 elif pushop.cgresult is not None:
5554 elif pushop.cgresult is not None:
5564 some_pushed = True
5555 some_pushed = True
5565
5556
5566 if pushop.bkresult is not None:
5557 if pushop.bkresult is not None:
5567 if pushop.bkresult == 2:
5558 if pushop.bkresult == 2:
5568 result = 2
5559 result = 2
5569 elif not result and pushop.bkresult:
5560 elif not result and pushop.bkresult:
5570 result = 2
5561 result = 2
5571
5562
5572 if result:
5563 if result:
5573 break
5564 break
5574
5565
5575 finally:
5566 finally:
5576 other.close()
5567 other.close()
5577 if result == 0 and not some_pushed:
5568 if result == 0 and not some_pushed:
5578 result = 1
5569 result = 1
5579 return result
5570 return result
5580
5571
5581
5572
5582 @command(
5573 @command(
5583 b'recover',
5574 b'recover',
5584 [
5575 [
5585 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5576 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5586 ],
5577 ],
5587 helpcategory=command.CATEGORY_MAINTENANCE,
5578 helpcategory=command.CATEGORY_MAINTENANCE,
5588 )
5579 )
5589 def recover(ui, repo, **opts):
5580 def recover(ui, repo, **opts):
5590 """roll back an interrupted transaction
5581 """roll back an interrupted transaction
5591
5582
5592 Recover from an interrupted commit or pull.
5583 Recover from an interrupted commit or pull.
5593
5584
5594 This command tries to fix the repository status after an
5585 This command tries to fix the repository status after an
5595 interrupted operation. It should only be necessary when Mercurial
5586 interrupted operation. It should only be necessary when Mercurial
5596 suggests it.
5587 suggests it.
5597
5588
5598 Returns 0 if successful, 1 if nothing to recover or verify fails.
5589 Returns 0 if successful, 1 if nothing to recover or verify fails.
5599 """
5590 """
5600 ret = repo.recover()
5591 ret = repo.recover()
5601 if ret:
5592 if ret:
5602 if opts['verify']:
5593 if opts['verify']:
5603 return hg.verify(repo)
5594 return hg.verify(repo)
5604 else:
5595 else:
5605 msg = _(
5596 msg = _(
5606 b"(verify step skipped, run `hg verify` to check your "
5597 b"(verify step skipped, run `hg verify` to check your "
5607 b"repository content)\n"
5598 b"repository content)\n"
5608 )
5599 )
5609 ui.warn(msg)
5600 ui.warn(msg)
5610 return 0
5601 return 0
5611 return 1
5602 return 1
5612
5603
5613
5604
5614 @command(
5605 @command(
5615 b'remove|rm',
5606 b'remove|rm',
5616 [
5607 [
5617 (b'A', b'after', None, _(b'record delete for missing files')),
5608 (b'A', b'after', None, _(b'record delete for missing files')),
5618 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5609 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5619 ]
5610 ]
5620 + subrepoopts
5611 + subrepoopts
5621 + walkopts
5612 + walkopts
5622 + dryrunopts,
5613 + dryrunopts,
5623 _(b'[OPTION]... FILE...'),
5614 _(b'[OPTION]... FILE...'),
5624 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5615 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5625 helpbasic=True,
5616 helpbasic=True,
5626 inferrepo=True,
5617 inferrepo=True,
5627 )
5618 )
5628 def remove(ui, repo, *pats, **opts):
5619 def remove(ui, repo, *pats, **opts):
5629 """remove the specified files on the next commit
5620 """remove the specified files on the next commit
5630
5621
5631 Schedule the indicated files for removal from the current branch.
5622 Schedule the indicated files for removal from the current branch.
5632
5623
5633 This command schedules the files to be removed at the next commit.
5624 This command schedules the files to be removed at the next commit.
5634 To undo a remove before that, see :hg:`revert`. To undo added
5625 To undo a remove before that, see :hg:`revert`. To undo added
5635 files, see :hg:`forget`.
5626 files, see :hg:`forget`.
5636
5627
5637 .. container:: verbose
5628 .. container:: verbose
5638
5629
5639 -A/--after can be used to remove only files that have already
5630 -A/--after can be used to remove only files that have already
5640 been deleted, -f/--force can be used to force deletion, and -Af
5631 been deleted, -f/--force can be used to force deletion, and -Af
5641 can be used to remove files from the next revision without
5632 can be used to remove files from the next revision without
5642 deleting them from the working directory.
5633 deleting them from the working directory.
5643
5634
5644 The following table details the behavior of remove for different
5635 The following table details the behavior of remove for different
5645 file states (columns) and option combinations (rows). The file
5636 file states (columns) and option combinations (rows). The file
5646 states are Added [A], Clean [C], Modified [M] and Missing [!]
5637 states are Added [A], Clean [C], Modified [M] and Missing [!]
5647 (as reported by :hg:`status`). The actions are Warn, Remove
5638 (as reported by :hg:`status`). The actions are Warn, Remove
5648 (from branch) and Delete (from disk):
5639 (from branch) and Delete (from disk):
5649
5640
5650 ========= == == == ==
5641 ========= == == == ==
5651 opt/state A C M !
5642 opt/state A C M !
5652 ========= == == == ==
5643 ========= == == == ==
5653 none W RD W R
5644 none W RD W R
5654 -f R RD RD R
5645 -f R RD RD R
5655 -A W W W R
5646 -A W W W R
5656 -Af R R R R
5647 -Af R R R R
5657 ========= == == == ==
5648 ========= == == == ==
5658
5649
5659 .. note::
5650 .. note::
5660
5651
5661 :hg:`remove` never deletes files in Added [A] state from the
5652 :hg:`remove` never deletes files in Added [A] state from the
5662 working directory, not even if ``--force`` is specified.
5653 working directory, not even if ``--force`` is specified.
5663
5654
5664 Returns 0 on success, 1 if any warnings encountered.
5655 Returns 0 on success, 1 if any warnings encountered.
5665 """
5656 """
5666
5657
5667 after, force = opts.get('after'), opts.get('force')
5658 after, force = opts.get('after'), opts.get('force')
5668 dryrun = opts.get('dry_run')
5659 dryrun = opts.get('dry_run')
5669 if not pats and not after:
5660 if not pats and not after:
5670 raise error.InputError(_(b'no files specified'))
5661 raise error.InputError(_(b'no files specified'))
5671
5662
5672 with repo.wlock(), repo.dirstate.changing_files(repo):
5663 with repo.wlock(), repo.dirstate.changing_files(repo):
5673 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5664 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5674 subrepos = opts.get('subrepos')
5665 subrepos = opts.get('subrepos')
5675 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5666 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5676 return cmdutil.remove(
5667 return cmdutil.remove(
5677 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5668 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5678 )
5669 )
5679
5670
5680
5671
5681 @command(
5672 @command(
5682 b'rename|move|mv',
5673 b'rename|move|mv',
5683 [
5674 [
5684 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5675 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5685 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5676 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5686 (
5677 (
5687 b'',
5678 b'',
5688 b'at-rev',
5679 b'at-rev',
5689 b'',
5680 b'',
5690 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5681 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5691 _(b'REV'),
5682 _(b'REV'),
5692 ),
5683 ),
5693 (
5684 (
5694 b'f',
5685 b'f',
5695 b'force',
5686 b'force',
5696 None,
5687 None,
5697 _(b'forcibly move over an existing managed file'),
5688 _(b'forcibly move over an existing managed file'),
5698 ),
5689 ),
5699 ]
5690 ]
5700 + walkopts
5691 + walkopts
5701 + dryrunopts,
5692 + dryrunopts,
5702 _(b'[OPTION]... SOURCE... DEST'),
5693 _(b'[OPTION]... SOURCE... DEST'),
5703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5694 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5704 )
5695 )
5705 def rename(ui, repo, *pats, **opts):
5696 def rename(ui, repo, *pats, **opts):
5706 """rename files; equivalent of copy + remove
5697 """rename files; equivalent of copy + remove
5707
5698
5708 Mark dest as copies of sources; mark sources for deletion. If dest
5699 Mark dest as copies of sources; mark sources for deletion. If dest
5709 is a directory, copies are put in that directory. If dest is a
5700 is a directory, copies are put in that directory. If dest is a
5710 file, there can only be one source.
5701 file, there can only be one source.
5711
5702
5712 By default, this command copies the contents of files as they
5703 By default, this command copies the contents of files as they
5713 exist in the working directory. If invoked with -A/--after, the
5704 exist in the working directory. If invoked with -A/--after, the
5714 operation is recorded, but no copying is performed.
5705 operation is recorded, but no copying is performed.
5715
5706
5716 To undo marking a destination file as renamed, use --forget. With that
5707 To undo marking a destination file as renamed, use --forget. With that
5717 option, all given (positional) arguments are unmarked as renames. The
5708 option, all given (positional) arguments are unmarked as renames. The
5718 destination file(s) will be left in place (still tracked). The source
5709 destination file(s) will be left in place (still tracked). The source
5719 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5710 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5720 the same way as :hg:`copy --forget`.
5711 the same way as :hg:`copy --forget`.
5721
5712
5722 This command takes effect with the next commit by default.
5713 This command takes effect with the next commit by default.
5723
5714
5724 Returns 0 on success, 1 if errors are encountered.
5715 Returns 0 on success, 1 if errors are encountered.
5725 """
5716 """
5726 context = lambda repo: repo.dirstate.changing_files(repo)
5717 context = lambda repo: repo.dirstate.changing_files(repo)
5727 rev = opts.get('at_rev')
5718 rev = opts.get('at_rev')
5728
5719
5729 if rev:
5720 if rev:
5730 ctx = logcmdutil.revsingle(repo, rev)
5721 ctx = logcmdutil.revsingle(repo, rev)
5731 if ctx.rev() is not None:
5722 if ctx.rev() is not None:
5732
5723
5733 def context(repo):
5724 def context(repo):
5734 return util.nullcontextmanager()
5725 return util.nullcontextmanager()
5735
5726
5736 opts['at_rev'] = ctx.rev()
5727 opts['at_rev'] = ctx.rev()
5737 with repo.wlock(), context(repo):
5728 with repo.wlock(), context(repo):
5738 return cmdutil.copy(
5729 return cmdutil.copy(
5739 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5730 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5740 )
5731 )
5741
5732
5742
5733
5743 @command(
5734 @command(
5744 b'resolve',
5735 b'resolve',
5745 [
5736 [
5746 (b'a', b'all', None, _(b'select all unresolved files')),
5737 (b'a', b'all', None, _(b'select all unresolved files')),
5747 (b'l', b'list', None, _(b'list state of files needing merge')),
5738 (b'l', b'list', None, _(b'list state of files needing merge')),
5748 (b'm', b'mark', None, _(b'mark files as resolved')),
5739 (b'm', b'mark', None, _(b'mark files as resolved')),
5749 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5740 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5750 (b'n', b'no-status', None, _(b'hide status prefix')),
5741 (b'n', b'no-status', None, _(b'hide status prefix')),
5751 (b'', b're-merge', None, _(b're-merge files')),
5742 (b'', b're-merge', None, _(b're-merge files')),
5752 ]
5743 ]
5753 + mergetoolopts
5744 + mergetoolopts
5754 + walkopts
5745 + walkopts
5755 + formatteropts,
5746 + formatteropts,
5756 _(b'[OPTION]... [FILE]...'),
5747 _(b'[OPTION]... [FILE]...'),
5757 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5748 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5758 inferrepo=True,
5749 inferrepo=True,
5759 )
5750 )
5760 def resolve(ui, repo, *pats, **opts):
5751 def resolve(ui, repo, *pats, **opts):
5761 """redo merges or set/view the merge status of files
5752 """redo merges or set/view the merge status of files
5762
5753
5763 Merges with unresolved conflicts are often the result of
5754 Merges with unresolved conflicts are often the result of
5764 non-interactive merging using the ``internal:merge`` configuration
5755 non-interactive merging using the ``internal:merge`` configuration
5765 setting, or a command-line merge tool like ``diff3``. The resolve
5756 setting, or a command-line merge tool like ``diff3``. The resolve
5766 command is used to manage the files involved in a merge, after
5757 command is used to manage the files involved in a merge, after
5767 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5758 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5768 working directory must have two parents). See :hg:`help
5759 working directory must have two parents). See :hg:`help
5769 merge-tools` for information on configuring merge tools.
5760 merge-tools` for information on configuring merge tools.
5770
5761
5771 The resolve command can be used in the following ways:
5762 The resolve command can be used in the following ways:
5772
5763
5773 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5764 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5774 the specified files, discarding any previous merge attempts. Re-merging
5765 the specified files, discarding any previous merge attempts. Re-merging
5775 is not performed for files already marked as resolved. Use ``--all/-a``
5766 is not performed for files already marked as resolved. Use ``--all/-a``
5776 to select all unresolved files. ``--tool`` can be used to specify
5767 to select all unresolved files. ``--tool`` can be used to specify
5777 the merge tool used for the given files. It overrides the HGMERGE
5768 the merge tool used for the given files. It overrides the HGMERGE
5778 environment variable and your configuration files. Previous file
5769 environment variable and your configuration files. Previous file
5779 contents are saved with a ``.orig`` suffix.
5770 contents are saved with a ``.orig`` suffix.
5780
5771
5781 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5772 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5782 (e.g. after having manually fixed-up the files). The default is
5773 (e.g. after having manually fixed-up the files). The default is
5783 to mark all unresolved files.
5774 to mark all unresolved files.
5784
5775
5785 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5776 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5786 default is to mark all resolved files.
5777 default is to mark all resolved files.
5787
5778
5788 - :hg:`resolve -l`: list files which had or still have conflicts.
5779 - :hg:`resolve -l`: list files which had or still have conflicts.
5789 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5780 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5790 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5781 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5791 the list. See :hg:`help filesets` for details.
5782 the list. See :hg:`help filesets` for details.
5792
5783
5793 .. note::
5784 .. note::
5794
5785
5795 Mercurial will not let you commit files with unresolved merge
5786 Mercurial will not let you commit files with unresolved merge
5796 conflicts. You must use :hg:`resolve -m ...` before you can
5787 conflicts. You must use :hg:`resolve -m ...` before you can
5797 commit after a conflicting merge.
5788 commit after a conflicting merge.
5798
5789
5799 .. container:: verbose
5790 .. container:: verbose
5800
5791
5801 Template:
5792 Template:
5802
5793
5803 The following keywords are supported in addition to the common template
5794 The following keywords are supported in addition to the common template
5804 keywords and functions. See also :hg:`help templates`.
5795 keywords and functions. See also :hg:`help templates`.
5805
5796
5806 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5797 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5807 :path: String. Repository-absolute path of the file.
5798 :path: String. Repository-absolute path of the file.
5808
5799
5809 Returns 0 on success, 1 if any files fail a resolve attempt.
5800 Returns 0 on success, 1 if any files fail a resolve attempt.
5810 """
5801 """
5811
5802
5812 opts = pycompat.byteskwargs(opts)
5803 opts = pycompat.byteskwargs(opts)
5813 confirm = ui.configbool(b'commands', b'resolve.confirm')
5804 confirm = ui.configbool(b'commands', b'resolve.confirm')
5814 flaglist = b'all mark unmark list no_status re_merge'.split()
5805 flaglist = b'all mark unmark list no_status re_merge'.split()
5815 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5806 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5816
5807
5817 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5808 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5818 if actioncount > 1:
5809 if actioncount > 1:
5819 raise error.InputError(_(b"too many actions specified"))
5810 raise error.InputError(_(b"too many actions specified"))
5820 elif actioncount == 0 and ui.configbool(
5811 elif actioncount == 0 and ui.configbool(
5821 b'commands', b'resolve.explicit-re-merge'
5812 b'commands', b'resolve.explicit-re-merge'
5822 ):
5813 ):
5823 hint = _(b'use --mark, --unmark, --list or --re-merge')
5814 hint = _(b'use --mark, --unmark, --list or --re-merge')
5824 raise error.InputError(_(b'no action specified'), hint=hint)
5815 raise error.InputError(_(b'no action specified'), hint=hint)
5825 if pats and all:
5816 if pats and all:
5826 raise error.InputError(_(b"can't specify --all and patterns"))
5817 raise error.InputError(_(b"can't specify --all and patterns"))
5827 if not (all or pats or show or mark or unmark):
5818 if not (all or pats or show or mark or unmark):
5828 raise error.InputError(
5819 raise error.InputError(
5829 _(b'no files or directories specified'),
5820 _(b'no files or directories specified'),
5830 hint=b'use --all to re-merge all unresolved files',
5821 hint=b'use --all to re-merge all unresolved files',
5831 )
5822 )
5832
5823
5833 if confirm:
5824 if confirm:
5834 if all:
5825 if all:
5835 if ui.promptchoice(
5826 if ui.promptchoice(
5836 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5827 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5837 ):
5828 ):
5838 raise error.CanceledError(_(b'user quit'))
5829 raise error.CanceledError(_(b'user quit'))
5839 if mark and not pats:
5830 if mark and not pats:
5840 if ui.promptchoice(
5831 if ui.promptchoice(
5841 _(
5832 _(
5842 b'mark all unresolved files as resolved (yn)?'
5833 b'mark all unresolved files as resolved (yn)?'
5843 b'$$ &Yes $$ &No'
5834 b'$$ &Yes $$ &No'
5844 )
5835 )
5845 ):
5836 ):
5846 raise error.CanceledError(_(b'user quit'))
5837 raise error.CanceledError(_(b'user quit'))
5847 if unmark and not pats:
5838 if unmark and not pats:
5848 if ui.promptchoice(
5839 if ui.promptchoice(
5849 _(
5840 _(
5850 b'mark all resolved files as unresolved (yn)?'
5841 b'mark all resolved files as unresolved (yn)?'
5851 b'$$ &Yes $$ &No'
5842 b'$$ &Yes $$ &No'
5852 )
5843 )
5853 ):
5844 ):
5854 raise error.CanceledError(_(b'user quit'))
5845 raise error.CanceledError(_(b'user quit'))
5855
5846
5856 uipathfn = scmutil.getuipathfn(repo)
5847 uipathfn = scmutil.getuipathfn(repo)
5857
5848
5858 if show:
5849 if show:
5859 ui.pager(b'resolve')
5850 ui.pager(b'resolve')
5860 fm = ui.formatter(b'resolve', opts)
5851 fm = ui.formatter(b'resolve', opts)
5861 ms = mergestatemod.mergestate.read(repo)
5852 ms = mergestatemod.mergestate.read(repo)
5862 wctx = repo[None]
5853 wctx = repo[None]
5863 m = scmutil.match(wctx, pats, opts)
5854 m = scmutil.match(wctx, pats, opts)
5864
5855
5865 # Labels and keys based on merge state. Unresolved path conflicts show
5856 # Labels and keys based on merge state. Unresolved path conflicts show
5866 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5857 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5867 # resolved conflicts.
5858 # resolved conflicts.
5868 mergestateinfo = {
5859 mergestateinfo = {
5869 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5860 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5870 b'resolve.unresolved',
5861 b'resolve.unresolved',
5871 b'U',
5862 b'U',
5872 ),
5863 ),
5873 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5864 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5874 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5865 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5875 b'resolve.unresolved',
5866 b'resolve.unresolved',
5876 b'P',
5867 b'P',
5877 ),
5868 ),
5878 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5869 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5879 b'resolve.resolved',
5870 b'resolve.resolved',
5880 b'R',
5871 b'R',
5881 ),
5872 ),
5882 }
5873 }
5883
5874
5884 for f in ms:
5875 for f in ms:
5885 if not m(f):
5876 if not m(f):
5886 continue
5877 continue
5887
5878
5888 label, key = mergestateinfo[ms[f]]
5879 label, key = mergestateinfo[ms[f]]
5889 fm.startitem()
5880 fm.startitem()
5890 fm.context(ctx=wctx)
5881 fm.context(ctx=wctx)
5891 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5882 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5892 fm.data(path=f)
5883 fm.data(path=f)
5893 fm.plain(b'%s\n' % uipathfn(f), label=label)
5884 fm.plain(b'%s\n' % uipathfn(f), label=label)
5894 fm.end()
5885 fm.end()
5895 return 0
5886 return 0
5896
5887
5897 with repo.wlock():
5888 with repo.wlock():
5898 ms = mergestatemod.mergestate.read(repo)
5889 ms = mergestatemod.mergestate.read(repo)
5899
5890
5900 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5891 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5901 raise error.StateError(
5892 raise error.StateError(
5902 _(b'resolve command not applicable when not merging')
5893 _(b'resolve command not applicable when not merging')
5903 )
5894 )
5904
5895
5905 wctx = repo[None]
5896 wctx = repo[None]
5906 m = scmutil.match(wctx, pats, opts)
5897 m = scmutil.match(wctx, pats, opts)
5907 ret = 0
5898 ret = 0
5908 didwork = False
5899 didwork = False
5909
5900
5910 hasconflictmarkers = []
5901 hasconflictmarkers = []
5911 if mark:
5902 if mark:
5912 markcheck = ui.config(b'commands', b'resolve.mark-check')
5903 markcheck = ui.config(b'commands', b'resolve.mark-check')
5913 if markcheck not in [b'warn', b'abort']:
5904 if markcheck not in [b'warn', b'abort']:
5914 # Treat all invalid / unrecognized values as 'none'.
5905 # Treat all invalid / unrecognized values as 'none'.
5915 markcheck = False
5906 markcheck = False
5916 for f in ms:
5907 for f in ms:
5917 if not m(f):
5908 if not m(f):
5918 continue
5909 continue
5919
5910
5920 didwork = True
5911 didwork = True
5921
5912
5922 # path conflicts must be resolved manually
5913 # path conflicts must be resolved manually
5923 if ms[f] in (
5914 if ms[f] in (
5924 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5915 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5925 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5916 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5926 ):
5917 ):
5927 if mark:
5918 if mark:
5928 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5919 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5929 elif unmark:
5920 elif unmark:
5930 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5921 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5931 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5922 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5932 ui.warn(
5923 ui.warn(
5933 _(b'%s: path conflict must be resolved manually\n')
5924 _(b'%s: path conflict must be resolved manually\n')
5934 % uipathfn(f)
5925 % uipathfn(f)
5935 )
5926 )
5936 continue
5927 continue
5937
5928
5938 if mark:
5929 if mark:
5939 if markcheck:
5930 if markcheck:
5940 fdata = repo.wvfs.tryread(f)
5931 fdata = repo.wvfs.tryread(f)
5941 if (
5932 if (
5942 filemerge.hasconflictmarkers(fdata)
5933 filemerge.hasconflictmarkers(fdata)
5943 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5934 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5944 ):
5935 ):
5945 hasconflictmarkers.append(f)
5936 hasconflictmarkers.append(f)
5946 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5937 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5947 elif unmark:
5938 elif unmark:
5948 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5939 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5949 else:
5940 else:
5950 # backup pre-resolve (merge uses .orig for its own purposes)
5941 # backup pre-resolve (merge uses .orig for its own purposes)
5951 a = repo.wjoin(f)
5942 a = repo.wjoin(f)
5952 try:
5943 try:
5953 util.copyfile(a, a + b".resolve")
5944 util.copyfile(a, a + b".resolve")
5954 except FileNotFoundError:
5945 except FileNotFoundError:
5955 pass
5946 pass
5956
5947
5957 try:
5948 try:
5958 # preresolve file
5949 # preresolve file
5959 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5950 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5960 with ui.configoverride(overrides, b'resolve'):
5951 with ui.configoverride(overrides, b'resolve'):
5961 r = ms.resolve(f, wctx)
5952 r = ms.resolve(f, wctx)
5962 if r:
5953 if r:
5963 ret = 1
5954 ret = 1
5964 finally:
5955 finally:
5965 ms.commit()
5956 ms.commit()
5966
5957
5967 # replace filemerge's .orig file with our resolve file
5958 # replace filemerge's .orig file with our resolve file
5968 try:
5959 try:
5969 util.rename(
5960 util.rename(
5970 a + b".resolve", scmutil.backuppath(ui, repo, f)
5961 a + b".resolve", scmutil.backuppath(ui, repo, f)
5971 )
5962 )
5972 except FileNotFoundError:
5963 except FileNotFoundError:
5973 pass
5964 pass
5974
5965
5975 if hasconflictmarkers:
5966 if hasconflictmarkers:
5976 ui.warn(
5967 ui.warn(
5977 _(
5968 _(
5978 b'warning: the following files still have conflict '
5969 b'warning: the following files still have conflict '
5979 b'markers:\n'
5970 b'markers:\n'
5980 )
5971 )
5981 + b''.join(
5972 + b''.join(
5982 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5973 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5983 )
5974 )
5984 )
5975 )
5985 if markcheck == b'abort' and not all and not pats:
5976 if markcheck == b'abort' and not all and not pats:
5986 raise error.StateError(
5977 raise error.StateError(
5987 _(b'conflict markers detected'),
5978 _(b'conflict markers detected'),
5988 hint=_(b'use --all to mark anyway'),
5979 hint=_(b'use --all to mark anyway'),
5989 )
5980 )
5990
5981
5991 ms.commit()
5982 ms.commit()
5992 branchmerge = repo.dirstate.p2() != repo.nullid
5983 branchmerge = repo.dirstate.p2() != repo.nullid
5993 # resolve is not doing a parent change here, however, `record updates`
5984 # resolve is not doing a parent change here, however, `record updates`
5994 # will call some dirstate API that at intended for parent changes call.
5985 # will call some dirstate API that at intended for parent changes call.
5995 # Ideally we would not need this and could implement a lighter version
5986 # Ideally we would not need this and could implement a lighter version
5996 # of the recordupdateslogic that will not have to deal with the part
5987 # of the recordupdateslogic that will not have to deal with the part
5997 # related to parent changes. However this would requires that:
5988 # related to parent changes. However this would requires that:
5998 # - we are sure we passed around enough information at update/merge
5989 # - we are sure we passed around enough information at update/merge
5999 # time to no longer needs it at `hg resolve time`
5990 # time to no longer needs it at `hg resolve time`
6000 # - we are sure we store that information well enough to be able to reuse it
5991 # - we are sure we store that information well enough to be able to reuse it
6001 # - we are the necessary logic to reuse it right.
5992 # - we are the necessary logic to reuse it right.
6002 #
5993 #
6003 # All this should eventually happens, but in the mean time, we use this
5994 # All this should eventually happens, but in the mean time, we use this
6004 # context manager slightly out of the context it should be.
5995 # context manager slightly out of the context it should be.
6005 with repo.dirstate.changing_parents(repo):
5996 with repo.dirstate.changing_parents(repo):
6006 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5997 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6007
5998
6008 if not didwork and pats:
5999 if not didwork and pats:
6009 hint = None
6000 hint = None
6010 if not any([p for p in pats if p.find(b':') >= 0]):
6001 if not any([p for p in pats if p.find(b':') >= 0]):
6011 pats = [b'path:%s' % p for p in pats]
6002 pats = [b'path:%s' % p for p in pats]
6012 m = scmutil.match(wctx, pats, opts)
6003 m = scmutil.match(wctx, pats, opts)
6013 for f in ms:
6004 for f in ms:
6014 if not m(f):
6005 if not m(f):
6015 continue
6006 continue
6016
6007
6017 def flag(o):
6008 def flag(o):
6018 if o == b're_merge':
6009 if o == b're_merge':
6019 return b'--re-merge '
6010 return b'--re-merge '
6020 return b'-%s ' % o[0:1]
6011 return b'-%s ' % o[0:1]
6021
6012
6022 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6013 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6023 hint = _(b"(try: hg resolve %s%s)\n") % (
6014 hint = _(b"(try: hg resolve %s%s)\n") % (
6024 flags,
6015 flags,
6025 b' '.join(pats),
6016 b' '.join(pats),
6026 )
6017 )
6027 break
6018 break
6028 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6019 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6029 if hint:
6020 if hint:
6030 ui.warn(hint)
6021 ui.warn(hint)
6031
6022
6032 unresolvedf = ms.unresolvedcount()
6023 unresolvedf = ms.unresolvedcount()
6033 if not unresolvedf:
6024 if not unresolvedf:
6034 ui.status(_(b'(no more unresolved files)\n'))
6025 ui.status(_(b'(no more unresolved files)\n'))
6035 cmdutil.checkafterresolved(repo)
6026 cmdutil.checkafterresolved(repo)
6036
6027
6037 return ret
6028 return ret
6038
6029
6039
6030
6040 @command(
6031 @command(
6041 b'revert',
6032 b'revert',
6042 [
6033 [
6043 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6034 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6044 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6035 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6045 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6036 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6046 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6037 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6047 (b'i', b'interactive', None, _(b'interactively select the changes')),
6038 (b'i', b'interactive', None, _(b'interactively select the changes')),
6048 ]
6039 ]
6049 + walkopts
6040 + walkopts
6050 + dryrunopts,
6041 + dryrunopts,
6051 _(b'[OPTION]... [-r REV] [NAME]...'),
6042 _(b'[OPTION]... [-r REV] [NAME]...'),
6052 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6043 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6053 )
6044 )
6054 def revert(ui, repo, *pats, **opts):
6045 def revert(ui, repo, *pats, **opts):
6055 """restore files to their checkout state
6046 """restore files to their checkout state
6056
6047
6057 .. note::
6048 .. note::
6058
6049
6059 To check out earlier revisions, you should use :hg:`update REV`.
6050 To check out earlier revisions, you should use :hg:`update REV`.
6060 To cancel an uncommitted merge (and lose your changes),
6051 To cancel an uncommitted merge (and lose your changes),
6061 use :hg:`merge --abort`.
6052 use :hg:`merge --abort`.
6062
6053
6063 With no revision specified, revert the specified files or directories
6054 With no revision specified, revert the specified files or directories
6064 to the contents they had in the parent of the working directory.
6055 to the contents they had in the parent of the working directory.
6065 This restores the contents of files to an unmodified
6056 This restores the contents of files to an unmodified
6066 state and unschedules adds, removes, copies, and renames. If the
6057 state and unschedules adds, removes, copies, and renames. If the
6067 working directory has two parents, you must explicitly specify a
6058 working directory has two parents, you must explicitly specify a
6068 revision.
6059 revision.
6069
6060
6070 Using the -r/--rev or -d/--date options, revert the given files or
6061 Using the -r/--rev or -d/--date options, revert the given files or
6071 directories to their states as of a specific revision. Because
6062 directories to their states as of a specific revision. Because
6072 revert does not change the working directory parents, this will
6063 revert does not change the working directory parents, this will
6073 cause these files to appear modified. This can be helpful to "back
6064 cause these files to appear modified. This can be helpful to "back
6074 out" some or all of an earlier change. See :hg:`backout` for a
6065 out" some or all of an earlier change. See :hg:`backout` for a
6075 related method.
6066 related method.
6076
6067
6077 Modified files are saved with a .orig suffix before reverting.
6068 Modified files are saved with a .orig suffix before reverting.
6078 To disable these backups, use --no-backup. It is possible to store
6069 To disable these backups, use --no-backup. It is possible to store
6079 the backup files in a custom directory relative to the root of the
6070 the backup files in a custom directory relative to the root of the
6080 repository by setting the ``ui.origbackuppath`` configuration
6071 repository by setting the ``ui.origbackuppath`` configuration
6081 option.
6072 option.
6082
6073
6083 See :hg:`help dates` for a list of formats valid for -d/--date.
6074 See :hg:`help dates` for a list of formats valid for -d/--date.
6084
6075
6085 See :hg:`help backout` for a way to reverse the effect of an
6076 See :hg:`help backout` for a way to reverse the effect of an
6086 earlier changeset.
6077 earlier changeset.
6087
6078
6088 Returns 0 on success.
6079 Returns 0 on success.
6089 """
6080 """
6090
6081
6091 if opts.get("date"):
6082 if opts.get("date"):
6092 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6083 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6093 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6084 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6094
6085
6095 parent, p2 = repo.dirstate.parents()
6086 parent, p2 = repo.dirstate.parents()
6096 if not opts.get('rev') and p2 != repo.nullid:
6087 if not opts.get('rev') and p2 != repo.nullid:
6097 # revert after merge is a trap for new users (issue2915)
6088 # revert after merge is a trap for new users (issue2915)
6098 raise error.InputError(
6089 raise error.InputError(
6099 _(b'uncommitted merge with no revision specified'),
6090 _(b'uncommitted merge with no revision specified'),
6100 hint=_(b"use 'hg update' or see 'hg help revert'"),
6091 hint=_(b"use 'hg update' or see 'hg help revert'"),
6101 )
6092 )
6102
6093
6103 rev = opts.get('rev')
6094 rev = opts.get('rev')
6104 if rev:
6095 if rev:
6105 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6096 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6106 ctx = logcmdutil.revsingle(repo, rev)
6097 ctx = logcmdutil.revsingle(repo, rev)
6107
6098
6108 if not (
6099 if not (
6109 pats
6100 pats
6110 or opts.get('include')
6101 or opts.get('include')
6111 or opts.get('exclude')
6102 or opts.get('exclude')
6112 or opts.get('all')
6103 or opts.get('all')
6113 or opts.get('interactive')
6104 or opts.get('interactive')
6114 ):
6105 ):
6115 msg = _(b"no files or directories specified")
6106 msg = _(b"no files or directories specified")
6116 if p2 != repo.nullid:
6107 if p2 != repo.nullid:
6117 hint = _(
6108 hint = _(
6118 b"uncommitted merge, use --all to discard all changes,"
6109 b"uncommitted merge, use --all to discard all changes,"
6119 b" or 'hg update -C .' to abort the merge"
6110 b" or 'hg update -C .' to abort the merge"
6120 )
6111 )
6121 raise error.InputError(msg, hint=hint)
6112 raise error.InputError(msg, hint=hint)
6122 dirty = any(repo.status())
6113 dirty = any(repo.status())
6123 node = ctx.node()
6114 node = ctx.node()
6124 if node != parent:
6115 if node != parent:
6125 if dirty:
6116 if dirty:
6126 hint = (
6117 hint = (
6127 _(
6118 _(
6128 b"uncommitted changes, use --all to discard all"
6119 b"uncommitted changes, use --all to discard all"
6129 b" changes, or 'hg update %d' to update"
6120 b" changes, or 'hg update %d' to update"
6130 )
6121 )
6131 % ctx.rev()
6122 % ctx.rev()
6132 )
6123 )
6133 else:
6124 else:
6134 hint = (
6125 hint = (
6135 _(
6126 _(
6136 b"use --all to revert all files,"
6127 b"use --all to revert all files,"
6137 b" or 'hg update %d' to update"
6128 b" or 'hg update %d' to update"
6138 )
6129 )
6139 % ctx.rev()
6130 % ctx.rev()
6140 )
6131 )
6141 elif dirty:
6132 elif dirty:
6142 hint = _(b"uncommitted changes, use --all to discard all changes")
6133 hint = _(b"uncommitted changes, use --all to discard all changes")
6143 else:
6134 else:
6144 hint = _(b"use --all to revert all files")
6135 hint = _(b"use --all to revert all files")
6145 raise error.InputError(msg, hint=hint)
6136 raise error.InputError(msg, hint=hint)
6146
6137
6147 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6138 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6148
6139
6149
6140
6150 @command(
6141 @command(
6151 b'rollback',
6142 b'rollback',
6152 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6143 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6153 helpcategory=command.CATEGORY_MAINTENANCE,
6144 helpcategory=command.CATEGORY_MAINTENANCE,
6154 )
6145 )
6155 def rollback(ui, repo, **opts):
6146 def rollback(ui, repo, **opts):
6156 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6147 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6157
6148
6158 Please use :hg:`commit --amend` instead of rollback to correct
6149 Please use :hg:`commit --amend` instead of rollback to correct
6159 mistakes in the last commit.
6150 mistakes in the last commit.
6160
6151
6161 This command should be used with care. There is only one level of
6152 This command should be used with care. There is only one level of
6162 rollback, and there is no way to undo a rollback. It will also
6153 rollback, and there is no way to undo a rollback. It will also
6163 restore the dirstate at the time of the last transaction, losing
6154 restore the dirstate at the time of the last transaction, losing
6164 any dirstate changes since that time. This command does not alter
6155 any dirstate changes since that time. This command does not alter
6165 the working directory.
6156 the working directory.
6166
6157
6167 Transactions are used to encapsulate the effects of all commands
6158 Transactions are used to encapsulate the effects of all commands
6168 that create new changesets or propagate existing changesets into a
6159 that create new changesets or propagate existing changesets into a
6169 repository.
6160 repository.
6170
6161
6171 .. container:: verbose
6162 .. container:: verbose
6172
6163
6173 For example, the following commands are transactional, and their
6164 For example, the following commands are transactional, and their
6174 effects can be rolled back:
6165 effects can be rolled back:
6175
6166
6176 - commit
6167 - commit
6177 - import
6168 - import
6178 - pull
6169 - pull
6179 - push (with this repository as the destination)
6170 - push (with this repository as the destination)
6180 - unbundle
6171 - unbundle
6181
6172
6182 To avoid permanent data loss, rollback will refuse to rollback a
6173 To avoid permanent data loss, rollback will refuse to rollback a
6183 commit transaction if it isn't checked out. Use --force to
6174 commit transaction if it isn't checked out. Use --force to
6184 override this protection.
6175 override this protection.
6185
6176
6186 The rollback command can be entirely disabled by setting the
6177 The rollback command can be entirely disabled by setting the
6187 ``ui.rollback`` configuration setting to false. If you're here
6178 ``ui.rollback`` configuration setting to false. If you're here
6188 because you want to use rollback and it's disabled, you can
6179 because you want to use rollback and it's disabled, you can
6189 re-enable the command by setting ``ui.rollback`` to true.
6180 re-enable the command by setting ``ui.rollback`` to true.
6190
6181
6191 This command is not intended for use on public repositories. Once
6182 This command is not intended for use on public repositories. Once
6192 changes are visible for pull by other users, rolling a transaction
6183 changes are visible for pull by other users, rolling a transaction
6193 back locally is ineffective (someone else may already have pulled
6184 back locally is ineffective (someone else may already have pulled
6194 the changes). Furthermore, a race is possible with readers of the
6185 the changes). Furthermore, a race is possible with readers of the
6195 repository; for example an in-progress pull from the repository
6186 repository; for example an in-progress pull from the repository
6196 may fail if a rollback is performed.
6187 may fail if a rollback is performed.
6197
6188
6198 Returns 0 on success, 1 if no rollback data is available.
6189 Returns 0 on success, 1 if no rollback data is available.
6199 """
6190 """
6200 if not ui.configbool(b'ui', b'rollback'):
6191 if not ui.configbool(b'ui', b'rollback'):
6201 raise error.Abort(
6192 raise error.Abort(
6202 _(b'rollback is disabled because it is unsafe'),
6193 _(b'rollback is disabled because it is unsafe'),
6203 hint=b'see `hg help -v rollback` for information',
6194 hint=b'see `hg help -v rollback` for information',
6204 )
6195 )
6205 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6196 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6206
6197
6207
6198
6208 @command(
6199 @command(
6209 b'root',
6200 b'root',
6210 [] + formatteropts,
6201 [] + formatteropts,
6211 intents={INTENT_READONLY},
6202 intents={INTENT_READONLY},
6212 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6203 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6213 )
6204 )
6214 def root(ui, repo, **opts):
6205 def root(ui, repo, **opts):
6215 """print the root (top) of the current working directory
6206 """print the root (top) of the current working directory
6216
6207
6217 Print the root directory of the current repository.
6208 Print the root directory of the current repository.
6218
6209
6219 .. container:: verbose
6210 .. container:: verbose
6220
6211
6221 Template:
6212 Template:
6222
6213
6223 The following keywords are supported in addition to the common template
6214 The following keywords are supported in addition to the common template
6224 keywords and functions. See also :hg:`help templates`.
6215 keywords and functions. See also :hg:`help templates`.
6225
6216
6226 :hgpath: String. Path to the .hg directory.
6217 :hgpath: String. Path to the .hg directory.
6227 :storepath: String. Path to the directory holding versioned data.
6218 :storepath: String. Path to the directory holding versioned data.
6228
6219
6229 Returns 0 on success.
6220 Returns 0 on success.
6230 """
6221 """
6231 opts = pycompat.byteskwargs(opts)
6222 opts = pycompat.byteskwargs(opts)
6232 with ui.formatter(b'root', opts) as fm:
6223 with ui.formatter(b'root', opts) as fm:
6233 fm.startitem()
6224 fm.startitem()
6234 fm.write(b'reporoot', b'%s\n', repo.root)
6225 fm.write(b'reporoot', b'%s\n', repo.root)
6235 fm.data(hgpath=repo.path, storepath=repo.spath)
6226 fm.data(hgpath=repo.path, storepath=repo.spath)
6236
6227
6237
6228
6238 @command(
6229 @command(
6239 b'serve',
6230 b'serve',
6240 [
6231 [
6241 (
6232 (
6242 b'A',
6233 b'A',
6243 b'accesslog',
6234 b'accesslog',
6244 b'',
6235 b'',
6245 _(b'name of access log file to write to'),
6236 _(b'name of access log file to write to'),
6246 _(b'FILE'),
6237 _(b'FILE'),
6247 ),
6238 ),
6248 (b'd', b'daemon', None, _(b'run server in background')),
6239 (b'd', b'daemon', None, _(b'run server in background')),
6249 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6240 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6250 (
6241 (
6251 b'E',
6242 b'E',
6252 b'errorlog',
6243 b'errorlog',
6253 b'',
6244 b'',
6254 _(b'name of error log file to write to'),
6245 _(b'name of error log file to write to'),
6255 _(b'FILE'),
6246 _(b'FILE'),
6256 ),
6247 ),
6257 # use string type, then we can check if something was passed
6248 # use string type, then we can check if something was passed
6258 (
6249 (
6259 b'p',
6250 b'p',
6260 b'port',
6251 b'port',
6261 b'',
6252 b'',
6262 _(b'port to listen on (default: 8000)'),
6253 _(b'port to listen on (default: 8000)'),
6263 _(b'PORT'),
6254 _(b'PORT'),
6264 ),
6255 ),
6265 (
6256 (
6266 b'a',
6257 b'a',
6267 b'address',
6258 b'address',
6268 b'',
6259 b'',
6269 _(b'address to listen on (default: all interfaces)'),
6260 _(b'address to listen on (default: all interfaces)'),
6270 _(b'ADDR'),
6261 _(b'ADDR'),
6271 ),
6262 ),
6272 (
6263 (
6273 b'',
6264 b'',
6274 b'prefix',
6265 b'prefix',
6275 b'',
6266 b'',
6276 _(b'prefix path to serve from (default: server root)'),
6267 _(b'prefix path to serve from (default: server root)'),
6277 _(b'PREFIX'),
6268 _(b'PREFIX'),
6278 ),
6269 ),
6279 (
6270 (
6280 b'n',
6271 b'n',
6281 b'name',
6272 b'name',
6282 b'',
6273 b'',
6283 _(b'name to show in web pages (default: working directory)'),
6274 _(b'name to show in web pages (default: working directory)'),
6284 _(b'NAME'),
6275 _(b'NAME'),
6285 ),
6276 ),
6286 (
6277 (
6287 b'',
6278 b'',
6288 b'web-conf',
6279 b'web-conf',
6289 b'',
6280 b'',
6290 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6281 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6291 _(b'FILE'),
6282 _(b'FILE'),
6292 ),
6283 ),
6293 (
6284 (
6294 b'',
6285 b'',
6295 b'webdir-conf',
6286 b'webdir-conf',
6296 b'',
6287 b'',
6297 _(b'name of the hgweb config file (DEPRECATED)'),
6288 _(b'name of the hgweb config file (DEPRECATED)'),
6298 _(b'FILE'),
6289 _(b'FILE'),
6299 ),
6290 ),
6300 (
6291 (
6301 b'',
6292 b'',
6302 b'pid-file',
6293 b'pid-file',
6303 b'',
6294 b'',
6304 _(b'name of file to write process ID to'),
6295 _(b'name of file to write process ID to'),
6305 _(b'FILE'),
6296 _(b'FILE'),
6306 ),
6297 ),
6307 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6298 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6308 (
6299 (
6309 b'',
6300 b'',
6310 b'cmdserver',
6301 b'cmdserver',
6311 b'',
6302 b'',
6312 _(b'for remote clients (ADVANCED)'),
6303 _(b'for remote clients (ADVANCED)'),
6313 _(b'MODE'),
6304 _(b'MODE'),
6314 ),
6305 ),
6315 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6306 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6316 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6307 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6317 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6308 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6318 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6309 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6319 (b'', b'print-url', None, _(b'start and print only the URL')),
6310 (b'', b'print-url', None, _(b'start and print only the URL')),
6320 ]
6311 ]
6321 + subrepoopts,
6312 + subrepoopts,
6322 _(b'[OPTION]...'),
6313 _(b'[OPTION]...'),
6323 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6314 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6324 helpbasic=True,
6315 helpbasic=True,
6325 optionalrepo=True,
6316 optionalrepo=True,
6326 )
6317 )
6327 def serve(ui, repo, **opts):
6318 def serve(ui, repo, **opts):
6328 """start stand-alone webserver
6319 """start stand-alone webserver
6329
6320
6330 Start a local HTTP repository browser and pull server. You can use
6321 Start a local HTTP repository browser and pull server. You can use
6331 this for ad-hoc sharing and browsing of repositories. It is
6322 this for ad-hoc sharing and browsing of repositories. It is
6332 recommended to use a real web server to serve a repository for
6323 recommended to use a real web server to serve a repository for
6333 longer periods of time.
6324 longer periods of time.
6334
6325
6335 Please note that the server does not implement access control.
6326 Please note that the server does not implement access control.
6336 This means that, by default, anybody can read from the server and
6327 This means that, by default, anybody can read from the server and
6337 nobody can write to it by default. Set the ``web.allow-push``
6328 nobody can write to it by default. Set the ``web.allow-push``
6338 option to ``*`` to allow everybody to push to the server. You
6329 option to ``*`` to allow everybody to push to the server. You
6339 should use a real web server if you need to authenticate users.
6330 should use a real web server if you need to authenticate users.
6340
6331
6341 By default, the server logs accesses to stdout and errors to
6332 By default, the server logs accesses to stdout and errors to
6342 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6333 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6343 files.
6334 files.
6344
6335
6345 To have the server choose a free port number to listen on, specify
6336 To have the server choose a free port number to listen on, specify
6346 a port number of 0; in this case, the server will print the port
6337 a port number of 0; in this case, the server will print the port
6347 number it uses.
6338 number it uses.
6348
6339
6349 Returns 0 on success.
6340 Returns 0 on success.
6350 """
6341 """
6351
6342
6352 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6343 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6353 opts = pycompat.byteskwargs(opts)
6344 opts = pycompat.byteskwargs(opts)
6354 if opts[b"print_url"] and ui.verbose:
6345 if opts[b"print_url"] and ui.verbose:
6355 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6346 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6356
6347
6357 if opts[b"stdio"]:
6348 if opts[b"stdio"]:
6358 if repo is None:
6349 if repo is None:
6359 raise error.RepoError(
6350 raise error.RepoError(
6360 _(b"there is no Mercurial repository here (.hg not found)")
6351 _(b"there is no Mercurial repository here (.hg not found)")
6361 )
6352 )
6362 accesshidden = False
6353 accesshidden = False
6363 if repo.filtername is None:
6354 if repo.filtername is None:
6364 allow = ui.configlist(
6355 allow = ui.configlist(
6365 b'experimental', b'server.allow-hidden-access'
6356 b'experimental', b'server.allow-hidden-access'
6366 )
6357 )
6367 user = procutil.getuser()
6358 user = procutil.getuser()
6368 if allow and scmutil.ismember(ui, user, allow):
6359 if allow and scmutil.ismember(ui, user, allow):
6369 accesshidden = True
6360 accesshidden = True
6370 else:
6361 else:
6371 msg = (
6362 msg = (
6372 _(
6363 _(
6373 b'ignoring request to access hidden changeset by '
6364 b'ignoring request to access hidden changeset by '
6374 b'unauthorized user: %s\n'
6365 b'unauthorized user: %s\n'
6375 )
6366 )
6376 % user
6367 % user
6377 )
6368 )
6378 ui.warn(msg)
6369 ui.warn(msg)
6379
6370
6380 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6371 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6381 s.serve_forever()
6372 s.serve_forever()
6382 return
6373 return
6383
6374
6384 service = server.createservice(ui, repo, opts)
6375 service = server.createservice(ui, repo, opts)
6385 return server.runservice(opts, initfn=service.init, runfn=service.run)
6376 return server.runservice(opts, initfn=service.init, runfn=service.run)
6386
6377
6387
6378
6388 @command(
6379 @command(
6389 b'shelve',
6380 b'shelve',
6390 [
6381 [
6391 (
6382 (
6392 b'A',
6383 b'A',
6393 b'addremove',
6384 b'addremove',
6394 None,
6385 None,
6395 _(b'mark new/missing files as added/removed before shelving'),
6386 _(b'mark new/missing files as added/removed before shelving'),
6396 ),
6387 ),
6397 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6388 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6398 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6389 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6399 (
6390 (
6400 b'',
6391 b'',
6401 b'date',
6392 b'date',
6402 b'',
6393 b'',
6403 _(b'shelve with the specified commit date'),
6394 _(b'shelve with the specified commit date'),
6404 _(b'DATE'),
6395 _(b'DATE'),
6405 ),
6396 ),
6406 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6397 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6407 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6398 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6408 (
6399 (
6409 b'k',
6400 b'k',
6410 b'keep',
6401 b'keep',
6411 False,
6402 False,
6412 _(b'shelve, but keep changes in the working directory'),
6403 _(b'shelve, but keep changes in the working directory'),
6413 ),
6404 ),
6414 (b'l', b'list', None, _(b'list current shelves')),
6405 (b'l', b'list', None, _(b'list current shelves')),
6415 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6406 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6416 (
6407 (
6417 b'n',
6408 b'n',
6418 b'name',
6409 b'name',
6419 b'',
6410 b'',
6420 _(b'use the given name for the shelved commit'),
6411 _(b'use the given name for the shelved commit'),
6421 _(b'NAME'),
6412 _(b'NAME'),
6422 ),
6413 ),
6423 (
6414 (
6424 b'p',
6415 b'p',
6425 b'patch',
6416 b'patch',
6426 None,
6417 None,
6427 _(
6418 _(
6428 b'output patches for changes (provide the names of the shelved '
6419 b'output patches for changes (provide the names of the shelved '
6429 b'changes as positional arguments)'
6420 b'changes as positional arguments)'
6430 ),
6421 ),
6431 ),
6422 ),
6432 (b'i', b'interactive', None, _(b'interactive mode')),
6423 (b'i', b'interactive', None, _(b'interactive mode')),
6433 (
6424 (
6434 b'',
6425 b'',
6435 b'stat',
6426 b'stat',
6436 None,
6427 None,
6437 _(
6428 _(
6438 b'output diffstat-style summary of changes (provide the names of '
6429 b'output diffstat-style summary of changes (provide the names of '
6439 b'the shelved changes as positional arguments)'
6430 b'the shelved changes as positional arguments)'
6440 ),
6431 ),
6441 ),
6432 ),
6442 ]
6433 ]
6443 + cmdutil.walkopts,
6434 + cmdutil.walkopts,
6444 _(b'hg shelve [OPTION]... [FILE]...'),
6435 _(b'hg shelve [OPTION]... [FILE]...'),
6445 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6436 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6446 )
6437 )
6447 def shelve(ui, repo, *pats, **opts):
6438 def shelve(ui, repo, *pats, **opts):
6448 """save and set aside changes from the working directory
6439 """save and set aside changes from the working directory
6449
6440
6450 Shelving takes files that "hg status" reports as not clean, saves
6441 Shelving takes files that "hg status" reports as not clean, saves
6451 the modifications to a bundle (a shelved change), and reverts the
6442 the modifications to a bundle (a shelved change), and reverts the
6452 files so that their state in the working directory becomes clean.
6443 files so that their state in the working directory becomes clean.
6453
6444
6454 To restore these changes to the working directory, using "hg
6445 To restore these changes to the working directory, using "hg
6455 unshelve"; this will work even if you switch to a different
6446 unshelve"; this will work even if you switch to a different
6456 commit.
6447 commit.
6457
6448
6458 When no files are specified, "hg shelve" saves all not-clean
6449 When no files are specified, "hg shelve" saves all not-clean
6459 files. If specific files or directories are named, only changes to
6450 files. If specific files or directories are named, only changes to
6460 those files are shelved.
6451 those files are shelved.
6461
6452
6462 In bare shelve (when no files are specified, without interactive,
6453 In bare shelve (when no files are specified, without interactive,
6463 include and exclude option), shelving remembers information if the
6454 include and exclude option), shelving remembers information if the
6464 working directory was on newly created branch, in other words working
6455 working directory was on newly created branch, in other words working
6465 directory was on different branch than its first parent. In this
6456 directory was on different branch than its first parent. In this
6466 situation unshelving restores branch information to the working directory.
6457 situation unshelving restores branch information to the working directory.
6467
6458
6468 Each shelved change has a name that makes it easier to find later.
6459 Each shelved change has a name that makes it easier to find later.
6469 The name of a shelved change defaults to being based on the active
6460 The name of a shelved change defaults to being based on the active
6470 bookmark, or if there is no active bookmark, the current named
6461 bookmark, or if there is no active bookmark, the current named
6471 branch. To specify a different name, use ``--name``.
6462 branch. To specify a different name, use ``--name``.
6472
6463
6473 To see a list of existing shelved changes, use the ``--list``
6464 To see a list of existing shelved changes, use the ``--list``
6474 option. For each shelved change, this will print its name, age,
6465 option. For each shelved change, this will print its name, age,
6475 and description; use ``--patch`` or ``--stat`` for more details.
6466 and description; use ``--patch`` or ``--stat`` for more details.
6476
6467
6477 To delete specific shelved changes, use ``--delete``. To delete
6468 To delete specific shelved changes, use ``--delete``. To delete
6478 all shelved changes, use ``--cleanup``.
6469 all shelved changes, use ``--cleanup``.
6479 """
6470 """
6480 opts = pycompat.byteskwargs(opts)
6471 opts = pycompat.byteskwargs(opts)
6481 allowables = [
6472 allowables = [
6482 (b'addremove', {b'create'}), # 'create' is pseudo action
6473 (b'addremove', {b'create'}), # 'create' is pseudo action
6483 (b'unknown', {b'create'}),
6474 (b'unknown', {b'create'}),
6484 (b'cleanup', {b'cleanup'}),
6475 (b'cleanup', {b'cleanup'}),
6485 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6476 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6486 (b'delete', {b'delete'}),
6477 (b'delete', {b'delete'}),
6487 (b'edit', {b'create'}),
6478 (b'edit', {b'create'}),
6488 (b'keep', {b'create'}),
6479 (b'keep', {b'create'}),
6489 (b'list', {b'list'}),
6480 (b'list', {b'list'}),
6490 (b'message', {b'create'}),
6481 (b'message', {b'create'}),
6491 (b'name', {b'create'}),
6482 (b'name', {b'create'}),
6492 (b'patch', {b'patch', b'list'}),
6483 (b'patch', {b'patch', b'list'}),
6493 (b'stat', {b'stat', b'list'}),
6484 (b'stat', {b'stat', b'list'}),
6494 ]
6485 ]
6495
6486
6496 def checkopt(opt):
6487 def checkopt(opt):
6497 if opts.get(opt):
6488 if opts.get(opt):
6498 for i, allowable in allowables:
6489 for i, allowable in allowables:
6499 if opts[i] and opt not in allowable:
6490 if opts[i] and opt not in allowable:
6500 raise error.InputError(
6491 raise error.InputError(
6501 _(
6492 _(
6502 b"options '--%s' and '--%s' may not be "
6493 b"options '--%s' and '--%s' may not be "
6503 b"used together"
6494 b"used together"
6504 )
6495 )
6505 % (opt, i)
6496 % (opt, i)
6506 )
6497 )
6507 return True
6498 return True
6508
6499
6509 if checkopt(b'cleanup'):
6500 if checkopt(b'cleanup'):
6510 if pats:
6501 if pats:
6511 raise error.InputError(
6502 raise error.InputError(
6512 _(b"cannot specify names when using '--cleanup'")
6503 _(b"cannot specify names when using '--cleanup'")
6513 )
6504 )
6514 return shelvemod.cleanupcmd(ui, repo)
6505 return shelvemod.cleanupcmd(ui, repo)
6515 elif checkopt(b'delete'):
6506 elif checkopt(b'delete'):
6516 return shelvemod.deletecmd(ui, repo, pats)
6507 return shelvemod.deletecmd(ui, repo, pats)
6517 elif checkopt(b'list'):
6508 elif checkopt(b'list'):
6518 return shelvemod.listcmd(ui, repo, pats, opts)
6509 return shelvemod.listcmd(ui, repo, pats, opts)
6519 elif checkopt(b'patch') or checkopt(b'stat'):
6510 elif checkopt(b'patch') or checkopt(b'stat'):
6520 return shelvemod.patchcmds(ui, repo, pats, opts)
6511 return shelvemod.patchcmds(ui, repo, pats, opts)
6521 else:
6512 else:
6522 return shelvemod.createcmd(ui, repo, pats, opts)
6513 return shelvemod.createcmd(ui, repo, pats, opts)
6523
6514
6524
6515
6525 _NOTTERSE = b'nothing'
6516 _NOTTERSE = b'nothing'
6526
6517
6527
6518
6528 @command(
6519 @command(
6529 b'status|st',
6520 b'status|st',
6530 [
6521 [
6531 (b'A', b'all', None, _(b'show status of all files')),
6522 (b'A', b'all', None, _(b'show status of all files')),
6532 (b'm', b'modified', None, _(b'show only modified files')),
6523 (b'm', b'modified', None, _(b'show only modified files')),
6533 (b'a', b'added', None, _(b'show only added files')),
6524 (b'a', b'added', None, _(b'show only added files')),
6534 (b'r', b'removed', None, _(b'show only removed files')),
6525 (b'r', b'removed', None, _(b'show only removed files')),
6535 (b'd', b'deleted', None, _(b'show only missing files')),
6526 (b'd', b'deleted', None, _(b'show only missing files')),
6536 (b'c', b'clean', None, _(b'show only files without changes')),
6527 (b'c', b'clean', None, _(b'show only files without changes')),
6537 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6528 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6538 (b'i', b'ignored', None, _(b'show only ignored files')),
6529 (b'i', b'ignored', None, _(b'show only ignored files')),
6539 (b'n', b'no-status', None, _(b'hide status prefix')),
6530 (b'n', b'no-status', None, _(b'hide status prefix')),
6540 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6531 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6541 (
6532 (
6542 b'C',
6533 b'C',
6543 b'copies',
6534 b'copies',
6544 None,
6535 None,
6545 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6536 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6546 ),
6537 ),
6547 (
6538 (
6548 b'0',
6539 b'0',
6549 b'print0',
6540 b'print0',
6550 None,
6541 None,
6551 _(b'end filenames with NUL, for use with xargs'),
6542 _(b'end filenames with NUL, for use with xargs'),
6552 ),
6543 ),
6553 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6544 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6554 (
6545 (
6555 b'',
6546 b'',
6556 b'change',
6547 b'change',
6557 b'',
6548 b'',
6558 _(b'list the changed files of a revision'),
6549 _(b'list the changed files of a revision'),
6559 _(b'REV'),
6550 _(b'REV'),
6560 ),
6551 ),
6561 ]
6552 ]
6562 + walkopts
6553 + walkopts
6563 + subrepoopts
6554 + subrepoopts
6564 + formatteropts,
6555 + formatteropts,
6565 _(b'[OPTION]... [FILE]...'),
6556 _(b'[OPTION]... [FILE]...'),
6566 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6557 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6567 helpbasic=True,
6558 helpbasic=True,
6568 inferrepo=True,
6559 inferrepo=True,
6569 intents={INTENT_READONLY},
6560 intents={INTENT_READONLY},
6570 )
6561 )
6571 def status(ui, repo, *pats, **opts):
6562 def status(ui, repo, *pats, **opts):
6572 """show changed files in the working directory
6563 """show changed files in the working directory
6573
6564
6574 Show status of files in the repository. If names are given, only
6565 Show status of files in the repository. If names are given, only
6575 files that match are shown. Files that are clean or ignored or
6566 files that match are shown. Files that are clean or ignored or
6576 the source of a copy/move operation, are not listed unless
6567 the source of a copy/move operation, are not listed unless
6577 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6568 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6578 Unless options described with "show only ..." are given, the
6569 Unless options described with "show only ..." are given, the
6579 options -mardu are used.
6570 options -mardu are used.
6580
6571
6581 Option -q/--quiet hides untracked (unknown and ignored) files
6572 Option -q/--quiet hides untracked (unknown and ignored) files
6582 unless explicitly requested with -u/--unknown or -i/--ignored.
6573 unless explicitly requested with -u/--unknown or -i/--ignored.
6583
6574
6584 .. note::
6575 .. note::
6585
6576
6586 :hg:`status` may appear to disagree with diff if permissions have
6577 :hg:`status` may appear to disagree with diff if permissions have
6587 changed or a merge has occurred. The standard diff format does
6578 changed or a merge has occurred. The standard diff format does
6588 not report permission changes and diff only reports changes
6579 not report permission changes and diff only reports changes
6589 relative to one merge parent.
6580 relative to one merge parent.
6590
6581
6591 If one revision is given, it is used as the base revision.
6582 If one revision is given, it is used as the base revision.
6592 If two revisions are given, the differences between them are
6583 If two revisions are given, the differences between them are
6593 shown. The --change option can also be used as a shortcut to list
6584 shown. The --change option can also be used as a shortcut to list
6594 the changed files of a revision from its first parent.
6585 the changed files of a revision from its first parent.
6595
6586
6596 The codes used to show the status of files are::
6587 The codes used to show the status of files are::
6597
6588
6598 M = modified
6589 M = modified
6599 A = added
6590 A = added
6600 R = removed
6591 R = removed
6601 C = clean
6592 C = clean
6602 ! = missing (deleted by non-hg command, but still tracked)
6593 ! = missing (deleted by non-hg command, but still tracked)
6603 ? = not tracked
6594 ? = not tracked
6604 I = ignored
6595 I = ignored
6605 = origin of the previous file (with --copies)
6596 = origin of the previous file (with --copies)
6606
6597
6607 .. container:: verbose
6598 .. container:: verbose
6608
6599
6609 The -t/--terse option abbreviates the output by showing only the directory
6600 The -t/--terse option abbreviates the output by showing only the directory
6610 name if all the files in it share the same status. The option takes an
6601 name if all the files in it share the same status. The option takes an
6611 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6602 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6612 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6603 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6613 for 'ignored' and 'c' for clean.
6604 for 'ignored' and 'c' for clean.
6614
6605
6615 It abbreviates only those statuses which are passed. Note that clean and
6606 It abbreviates only those statuses which are passed. Note that clean and
6616 ignored files are not displayed with '--terse ic' unless the -c/--clean
6607 ignored files are not displayed with '--terse ic' unless the -c/--clean
6617 and -i/--ignored options are also used.
6608 and -i/--ignored options are also used.
6618
6609
6619 The -v/--verbose option shows information when the repository is in an
6610 The -v/--verbose option shows information when the repository is in an
6620 unfinished merge, shelve, rebase state etc. You can have this behavior
6611 unfinished merge, shelve, rebase state etc. You can have this behavior
6621 turned on by default by enabling the ``commands.status.verbose`` option.
6612 turned on by default by enabling the ``commands.status.verbose`` option.
6622
6613
6623 You can skip displaying some of these states by setting
6614 You can skip displaying some of these states by setting
6624 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6615 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6625 'histedit', 'merge', 'rebase', or 'unshelve'.
6616 'histedit', 'merge', 'rebase', or 'unshelve'.
6626
6617
6627 Template:
6618 Template:
6628
6619
6629 The following keywords are supported in addition to the common template
6620 The following keywords are supported in addition to the common template
6630 keywords and functions. See also :hg:`help templates`.
6621 keywords and functions. See also :hg:`help templates`.
6631
6622
6632 :path: String. Repository-absolute path of the file.
6623 :path: String. Repository-absolute path of the file.
6633 :source: String. Repository-absolute path of the file originated from.
6624 :source: String. Repository-absolute path of the file originated from.
6634 Available if ``--copies`` is specified.
6625 Available if ``--copies`` is specified.
6635 :status: String. Character denoting file's status.
6626 :status: String. Character denoting file's status.
6636
6627
6637 Examples:
6628 Examples:
6638
6629
6639 - show changes in the working directory relative to a
6630 - show changes in the working directory relative to a
6640 changeset::
6631 changeset::
6641
6632
6642 hg status --rev 9353
6633 hg status --rev 9353
6643
6634
6644 - show changes in the working directory relative to the
6635 - show changes in the working directory relative to the
6645 current directory (see :hg:`help patterns` for more information)::
6636 current directory (see :hg:`help patterns` for more information)::
6646
6637
6647 hg status re:
6638 hg status re:
6648
6639
6649 - show all changes including copies in an existing changeset::
6640 - show all changes including copies in an existing changeset::
6650
6641
6651 hg status --copies --change 9353
6642 hg status --copies --change 9353
6652
6643
6653 - get a NUL separated list of added files, suitable for xargs::
6644 - get a NUL separated list of added files, suitable for xargs::
6654
6645
6655 hg status -an0
6646 hg status -an0
6656
6647
6657 - show more information about the repository status, abbreviating
6648 - show more information about the repository status, abbreviating
6658 added, removed, modified, deleted, and untracked paths::
6649 added, removed, modified, deleted, and untracked paths::
6659
6650
6660 hg status -v -t mardu
6651 hg status -v -t mardu
6661
6652
6662 Returns 0 on success.
6653 Returns 0 on success.
6663
6654
6664 """
6655 """
6665
6656
6666 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6657 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6667 opts = pycompat.byteskwargs(opts)
6658 opts = pycompat.byteskwargs(opts)
6668 revs = opts.get(b'rev', [])
6659 revs = opts.get(b'rev', [])
6669 change = opts.get(b'change', b'')
6660 change = opts.get(b'change', b'')
6670 terse = opts.get(b'terse', _NOTTERSE)
6661 terse = opts.get(b'terse', _NOTTERSE)
6671 if terse is _NOTTERSE:
6662 if terse is _NOTTERSE:
6672 if revs:
6663 if revs:
6673 terse = b''
6664 terse = b''
6674 else:
6665 else:
6675 terse = ui.config(b'commands', b'status.terse')
6666 terse = ui.config(b'commands', b'status.terse')
6676
6667
6677 if revs and terse:
6668 if revs and terse:
6678 msg = _(b'cannot use --terse with --rev')
6669 msg = _(b'cannot use --terse with --rev')
6679 raise error.InputError(msg)
6670 raise error.InputError(msg)
6680 elif change:
6671 elif change:
6681 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6672 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6682 ctx2 = logcmdutil.revsingle(repo, change, None)
6673 ctx2 = logcmdutil.revsingle(repo, change, None)
6683 ctx1 = ctx2.p1()
6674 ctx1 = ctx2.p1()
6684 else:
6675 else:
6685 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6676 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6686 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6677 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6687
6678
6688 forcerelativevalue = None
6679 forcerelativevalue = None
6689 if ui.hasconfig(b'commands', b'status.relative'):
6680 if ui.hasconfig(b'commands', b'status.relative'):
6690 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6681 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6691 uipathfn = scmutil.getuipathfn(
6682 uipathfn = scmutil.getuipathfn(
6692 repo,
6683 repo,
6693 legacyrelativevalue=bool(pats),
6684 legacyrelativevalue=bool(pats),
6694 forcerelativevalue=forcerelativevalue,
6685 forcerelativevalue=forcerelativevalue,
6695 )
6686 )
6696
6687
6697 if opts.get(b'print0'):
6688 if opts.get(b'print0'):
6698 end = b'\0'
6689 end = b'\0'
6699 else:
6690 else:
6700 end = b'\n'
6691 end = b'\n'
6701 states = b'modified added removed deleted unknown ignored clean'.split()
6692 states = b'modified added removed deleted unknown ignored clean'.split()
6702 show = [k for k in states if opts.get(k)]
6693 show = [k for k in states if opts.get(k)]
6703 if opts.get(b'all'):
6694 if opts.get(b'all'):
6704 show += ui.quiet and (states[:4] + [b'clean']) or states
6695 show += ui.quiet and (states[:4] + [b'clean']) or states
6705
6696
6706 if not show:
6697 if not show:
6707 if ui.quiet:
6698 if ui.quiet:
6708 show = states[:4]
6699 show = states[:4]
6709 else:
6700 else:
6710 show = states[:5]
6701 show = states[:5]
6711
6702
6712 m = scmutil.match(ctx2, pats, opts)
6703 m = scmutil.match(ctx2, pats, opts)
6713 if terse:
6704 if terse:
6714 # we need to compute clean and unknown to terse
6705 # we need to compute clean and unknown to terse
6715 stat = repo.status(
6706 stat = repo.status(
6716 ctx1.node(),
6707 ctx1.node(),
6717 ctx2.node(),
6708 ctx2.node(),
6718 m,
6709 m,
6719 b'ignored' in show or b'i' in terse,
6710 b'ignored' in show or b'i' in terse,
6720 clean=True,
6711 clean=True,
6721 unknown=True,
6712 unknown=True,
6722 listsubrepos=opts.get(b'subrepos'),
6713 listsubrepos=opts.get(b'subrepos'),
6723 )
6714 )
6724
6715
6725 stat = cmdutil.tersedir(stat, terse)
6716 stat = cmdutil.tersedir(stat, terse)
6726 else:
6717 else:
6727 stat = repo.status(
6718 stat = repo.status(
6728 ctx1.node(),
6719 ctx1.node(),
6729 ctx2.node(),
6720 ctx2.node(),
6730 m,
6721 m,
6731 b'ignored' in show,
6722 b'ignored' in show,
6732 b'clean' in show,
6723 b'clean' in show,
6733 b'unknown' in show,
6724 b'unknown' in show,
6734 opts.get(b'subrepos'),
6725 opts.get(b'subrepos'),
6735 )
6726 )
6736
6727
6737 changestates = zip(
6728 changestates = zip(
6738 states,
6729 states,
6739 pycompat.iterbytestr(b'MAR!?IC'),
6730 pycompat.iterbytestr(b'MAR!?IC'),
6740 [getattr(stat, s.decode('utf8')) for s in states],
6731 [getattr(stat, s.decode('utf8')) for s in states],
6741 )
6732 )
6742
6733
6743 copy = {}
6734 copy = {}
6744 show_copies = ui.configbool(b'ui', b'statuscopies')
6735 show_copies = ui.configbool(b'ui', b'statuscopies')
6745 if opts.get(b'copies') is not None:
6736 if opts.get(b'copies') is not None:
6746 show_copies = opts.get(b'copies')
6737 show_copies = opts.get(b'copies')
6747 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6738 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6748 b'no_status'
6739 b'no_status'
6749 )
6740 )
6750 if show_copies:
6741 if show_copies:
6751 copy = copies.pathcopies(ctx1, ctx2, m)
6742 copy = copies.pathcopies(ctx1, ctx2, m)
6752
6743
6753 morestatus = None
6744 morestatus = None
6754 if (
6745 if (
6755 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6746 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6756 and not ui.plain()
6747 and not ui.plain()
6757 and not opts.get(b'print0')
6748 and not opts.get(b'print0')
6758 ):
6749 ):
6759 morestatus = cmdutil.readmorestatus(repo)
6750 morestatus = cmdutil.readmorestatus(repo)
6760
6751
6761 ui.pager(b'status')
6752 ui.pager(b'status')
6762 fm = ui.formatter(b'status', opts)
6753 fm = ui.formatter(b'status', opts)
6763 fmt = b'%s' + end
6754 fmt = b'%s' + end
6764 showchar = not opts.get(b'no_status')
6755 showchar = not opts.get(b'no_status')
6765
6756
6766 for state, char, files in changestates:
6757 for state, char, files in changestates:
6767 if state in show:
6758 if state in show:
6768 label = b'status.' + state
6759 label = b'status.' + state
6769 for f in files:
6760 for f in files:
6770 fm.startitem()
6761 fm.startitem()
6771 fm.context(ctx=ctx2)
6762 fm.context(ctx=ctx2)
6772 fm.data(itemtype=b'file', path=f)
6763 fm.data(itemtype=b'file', path=f)
6773 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6764 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6774 fm.plain(fmt % uipathfn(f), label=label)
6765 fm.plain(fmt % uipathfn(f), label=label)
6775 if f in copy:
6766 if f in copy:
6776 fm.data(source=copy[f])
6767 fm.data(source=copy[f])
6777 fm.plain(
6768 fm.plain(
6778 (b' %s' + end) % uipathfn(copy[f]),
6769 (b' %s' + end) % uipathfn(copy[f]),
6779 label=b'status.copied',
6770 label=b'status.copied',
6780 )
6771 )
6781 if morestatus:
6772 if morestatus:
6782 morestatus.formatfile(f, fm)
6773 morestatus.formatfile(f, fm)
6783
6774
6784 if morestatus:
6775 if morestatus:
6785 morestatus.formatfooter(fm)
6776 morestatus.formatfooter(fm)
6786 fm.end()
6777 fm.end()
6787
6778
6788
6779
6789 @command(
6780 @command(
6790 b'summary|sum',
6781 b'summary|sum',
6791 [(b'', b'remote', None, _(b'check for push and pull'))],
6782 [(b'', b'remote', None, _(b'check for push and pull'))],
6792 b'[--remote]',
6783 b'[--remote]',
6793 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6784 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6794 helpbasic=True,
6785 helpbasic=True,
6795 intents={INTENT_READONLY},
6786 intents={INTENT_READONLY},
6796 )
6787 )
6797 def summary(ui, repo, **opts):
6788 def summary(ui, repo, **opts):
6798 """summarize working directory state
6789 """summarize working directory state
6799
6790
6800 This generates a brief summary of the working directory state,
6791 This generates a brief summary of the working directory state,
6801 including parents, branch, commit status, phase and available updates.
6792 including parents, branch, commit status, phase and available updates.
6802
6793
6803 With the --remote option, this will check the default paths for
6794 With the --remote option, this will check the default paths for
6804 incoming and outgoing changes. This can be time-consuming.
6795 incoming and outgoing changes. This can be time-consuming.
6805
6796
6806 Returns 0 on success.
6797 Returns 0 on success.
6807 """
6798 """
6808
6799
6809 ui.pager(b'summary')
6800 ui.pager(b'summary')
6810 ctx = repo[None]
6801 ctx = repo[None]
6811 parents = ctx.parents()
6802 parents = ctx.parents()
6812 pnode = parents[0].node()
6803 pnode = parents[0].node()
6813 marks = []
6804 marks = []
6814
6805
6815 try:
6806 try:
6816 ms = mergestatemod.mergestate.read(repo)
6807 ms = mergestatemod.mergestate.read(repo)
6817 except error.UnsupportedMergeRecords as e:
6808 except error.UnsupportedMergeRecords as e:
6818 s = b' '.join(e.recordtypes)
6809 s = b' '.join(e.recordtypes)
6819 ui.warn(
6810 ui.warn(
6820 _(b'warning: merge state has unsupported record types: %s\n') % s
6811 _(b'warning: merge state has unsupported record types: %s\n') % s
6821 )
6812 )
6822 unresolved = []
6813 unresolved = []
6823 else:
6814 else:
6824 unresolved = list(ms.unresolved())
6815 unresolved = list(ms.unresolved())
6825
6816
6826 for p in parents:
6817 for p in parents:
6827 # label with log.changeset (instead of log.parent) since this
6818 # label with log.changeset (instead of log.parent) since this
6828 # shows a working directory parent *changeset*:
6819 # shows a working directory parent *changeset*:
6829 # i18n: column positioning for "hg summary"
6820 # i18n: column positioning for "hg summary"
6830 ui.write(
6821 ui.write(
6831 _(b'parent: %d:%s ') % (p.rev(), p),
6822 _(b'parent: %d:%s ') % (p.rev(), p),
6832 label=logcmdutil.changesetlabels(p),
6823 label=logcmdutil.changesetlabels(p),
6833 )
6824 )
6834 ui.write(b' '.join(p.tags()), label=b'log.tag')
6825 ui.write(b' '.join(p.tags()), label=b'log.tag')
6835 if p.bookmarks():
6826 if p.bookmarks():
6836 marks.extend(p.bookmarks())
6827 marks.extend(p.bookmarks())
6837 if p.rev() == -1:
6828 if p.rev() == -1:
6838 if not len(repo):
6829 if not len(repo):
6839 ui.write(_(b' (empty repository)'))
6830 ui.write(_(b' (empty repository)'))
6840 else:
6831 else:
6841 ui.write(_(b' (no revision checked out)'))
6832 ui.write(_(b' (no revision checked out)'))
6842 if p.obsolete():
6833 if p.obsolete():
6843 ui.write(_(b' (obsolete)'))
6834 ui.write(_(b' (obsolete)'))
6844 if p.isunstable():
6835 if p.isunstable():
6845 instabilities = (
6836 instabilities = (
6846 ui.label(instability, b'trouble.%s' % instability)
6837 ui.label(instability, b'trouble.%s' % instability)
6847 for instability in p.instabilities()
6838 for instability in p.instabilities()
6848 )
6839 )
6849 ui.write(b' (' + b', '.join(instabilities) + b')')
6840 ui.write(b' (' + b', '.join(instabilities) + b')')
6850 ui.write(b'\n')
6841 ui.write(b'\n')
6851 if p.description():
6842 if p.description():
6852 ui.status(
6843 ui.status(
6853 b' ' + p.description().splitlines()[0].strip() + b'\n',
6844 b' ' + p.description().splitlines()[0].strip() + b'\n',
6854 label=b'log.summary',
6845 label=b'log.summary',
6855 )
6846 )
6856
6847
6857 branch = ctx.branch()
6848 branch = ctx.branch()
6858 bheads = repo.branchheads(branch)
6849 bheads = repo.branchheads(branch)
6859 # i18n: column positioning for "hg summary"
6850 # i18n: column positioning for "hg summary"
6860 m = _(b'branch: %s\n') % branch
6851 m = _(b'branch: %s\n') % branch
6861 if branch != b'default':
6852 if branch != b'default':
6862 ui.write(m, label=b'log.branch')
6853 ui.write(m, label=b'log.branch')
6863 else:
6854 else:
6864 ui.status(m, label=b'log.branch')
6855 ui.status(m, label=b'log.branch')
6865
6856
6866 if marks:
6857 if marks:
6867 active = repo._activebookmark
6858 active = repo._activebookmark
6868 # i18n: column positioning for "hg summary"
6859 # i18n: column positioning for "hg summary"
6869 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6860 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6870 if active is not None:
6861 if active is not None:
6871 if active in marks:
6862 if active in marks:
6872 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6863 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6873 marks.remove(active)
6864 marks.remove(active)
6874 else:
6865 else:
6875 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6866 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6876 for m in marks:
6867 for m in marks:
6877 ui.write(b' ' + m, label=b'log.bookmark')
6868 ui.write(b' ' + m, label=b'log.bookmark')
6878 ui.write(b'\n', label=b'log.bookmark')
6869 ui.write(b'\n', label=b'log.bookmark')
6879
6870
6880 status = repo.status(unknown=True)
6871 status = repo.status(unknown=True)
6881
6872
6882 c = repo.dirstate.copies()
6873 c = repo.dirstate.copies()
6883 copied, renamed = [], []
6874 copied, renamed = [], []
6884 for d, s in c.items():
6875 for d, s in c.items():
6885 if s in status.removed:
6876 if s in status.removed:
6886 status.removed.remove(s)
6877 status.removed.remove(s)
6887 renamed.append(d)
6878 renamed.append(d)
6888 else:
6879 else:
6889 copied.append(d)
6880 copied.append(d)
6890 if d in status.added:
6881 if d in status.added:
6891 status.added.remove(d)
6882 status.added.remove(d)
6892
6883
6893 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6884 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6894
6885
6895 labels = [
6886 labels = [
6896 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6887 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6897 (ui.label(_(b'%d added'), b'status.added'), status.added),
6888 (ui.label(_(b'%d added'), b'status.added'), status.added),
6898 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6889 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6899 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6890 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6900 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6891 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6901 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6892 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6902 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6893 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6903 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6894 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6904 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6895 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6905 ]
6896 ]
6906 t = []
6897 t = []
6907 for l, s in labels:
6898 for l, s in labels:
6908 if s:
6899 if s:
6909 t.append(l % len(s))
6900 t.append(l % len(s))
6910
6901
6911 t = b', '.join(t)
6902 t = b', '.join(t)
6912 cleanworkdir = False
6903 cleanworkdir = False
6913
6904
6914 if repo.vfs.exists(b'graftstate'):
6905 if repo.vfs.exists(b'graftstate'):
6915 t += _(b' (graft in progress)')
6906 t += _(b' (graft in progress)')
6916 if repo.vfs.exists(b'updatestate'):
6907 if repo.vfs.exists(b'updatestate'):
6917 t += _(b' (interrupted update)')
6908 t += _(b' (interrupted update)')
6918 elif len(parents) > 1:
6909 elif len(parents) > 1:
6919 t += _(b' (merge)')
6910 t += _(b' (merge)')
6920 elif branch != parents[0].branch():
6911 elif branch != parents[0].branch():
6921 t += _(b' (new branch)')
6912 t += _(b' (new branch)')
6922 elif parents[0].closesbranch() and pnode in repo.branchheads(
6913 elif parents[0].closesbranch() and pnode in repo.branchheads(
6923 branch, closed=True
6914 branch, closed=True
6924 ):
6915 ):
6925 t += _(b' (head closed)')
6916 t += _(b' (head closed)')
6926 elif not (
6917 elif not (
6927 status.modified
6918 status.modified
6928 or status.added
6919 or status.added
6929 or status.removed
6920 or status.removed
6930 or renamed
6921 or renamed
6931 or copied
6922 or copied
6932 or subs
6923 or subs
6933 ):
6924 ):
6934 t += _(b' (clean)')
6925 t += _(b' (clean)')
6935 cleanworkdir = True
6926 cleanworkdir = True
6936 elif pnode not in bheads:
6927 elif pnode not in bheads:
6937 t += _(b' (new branch head)')
6928 t += _(b' (new branch head)')
6938
6929
6939 if parents:
6930 if parents:
6940 pendingphase = max(p.phase() for p in parents)
6931 pendingphase = max(p.phase() for p in parents)
6941 else:
6932 else:
6942 pendingphase = phases.public
6933 pendingphase = phases.public
6943
6934
6944 if pendingphase > phases.newcommitphase(ui):
6935 if pendingphase > phases.newcommitphase(ui):
6945 t += b' (%s)' % phases.phasenames[pendingphase]
6936 t += b' (%s)' % phases.phasenames[pendingphase]
6946
6937
6947 if cleanworkdir:
6938 if cleanworkdir:
6948 # i18n: column positioning for "hg summary"
6939 # i18n: column positioning for "hg summary"
6949 ui.status(_(b'commit: %s\n') % t.strip())
6940 ui.status(_(b'commit: %s\n') % t.strip())
6950 else:
6941 else:
6951 # i18n: column positioning for "hg summary"
6942 # i18n: column positioning for "hg summary"
6952 ui.write(_(b'commit: %s\n') % t.strip())
6943 ui.write(_(b'commit: %s\n') % t.strip())
6953
6944
6954 # all ancestors of branch heads - all ancestors of parent = new csets
6945 # all ancestors of branch heads - all ancestors of parent = new csets
6955 new = len(
6946 new = len(
6956 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6947 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6957 )
6948 )
6958
6949
6959 if new == 0:
6950 if new == 0:
6960 # i18n: column positioning for "hg summary"
6951 # i18n: column positioning for "hg summary"
6961 ui.status(_(b'update: (current)\n'))
6952 ui.status(_(b'update: (current)\n'))
6962 elif pnode not in bheads:
6953 elif pnode not in bheads:
6963 # i18n: column positioning for "hg summary"
6954 # i18n: column positioning for "hg summary"
6964 ui.write(_(b'update: %d new changesets (update)\n') % new)
6955 ui.write(_(b'update: %d new changesets (update)\n') % new)
6965 else:
6956 else:
6966 # i18n: column positioning for "hg summary"
6957 # i18n: column positioning for "hg summary"
6967 ui.write(
6958 ui.write(
6968 _(b'update: %d new changesets, %d branch heads (merge)\n')
6959 _(b'update: %d new changesets, %d branch heads (merge)\n')
6969 % (new, len(bheads))
6960 % (new, len(bheads))
6970 )
6961 )
6971
6962
6972 t = []
6963 t = []
6973 draft = len(repo.revs(b'draft()'))
6964 draft = len(repo.revs(b'draft()'))
6974 if draft:
6965 if draft:
6975 t.append(_(b'%d draft') % draft)
6966 t.append(_(b'%d draft') % draft)
6976 secret = len(repo.revs(b'secret()'))
6967 secret = len(repo.revs(b'secret()'))
6977 if secret:
6968 if secret:
6978 t.append(_(b'%d secret') % secret)
6969 t.append(_(b'%d secret') % secret)
6979
6970
6980 if draft or secret:
6971 if draft or secret:
6981 ui.status(_(b'phases: %s\n') % b', '.join(t))
6972 ui.status(_(b'phases: %s\n') % b', '.join(t))
6982
6973
6983 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6974 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6984 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6975 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6985 numtrouble = len(repo.revs(trouble + b"()"))
6976 numtrouble = len(repo.revs(trouble + b"()"))
6986 # We write all the possibilities to ease translation
6977 # We write all the possibilities to ease translation
6987 troublemsg = {
6978 troublemsg = {
6988 b"orphan": _(b"orphan: %d changesets"),
6979 b"orphan": _(b"orphan: %d changesets"),
6989 b"contentdivergent": _(b"content-divergent: %d changesets"),
6980 b"contentdivergent": _(b"content-divergent: %d changesets"),
6990 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6981 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6991 }
6982 }
6992 if numtrouble > 0:
6983 if numtrouble > 0:
6993 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6984 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6994
6985
6995 cmdutil.summaryhooks(ui, repo)
6986 cmdutil.summaryhooks(ui, repo)
6996
6987
6997 if opts.get('remote'):
6988 if opts.get('remote'):
6998 needsincoming, needsoutgoing = True, True
6989 needsincoming, needsoutgoing = True, True
6999 else:
6990 else:
7000 needsincoming, needsoutgoing = False, False
6991 needsincoming, needsoutgoing = False, False
7001 for i, o in cmdutil.summaryremotehooks(
6992 for i, o in cmdutil.summaryremotehooks(
7002 ui, repo, pycompat.byteskwargs(opts), None
6993 ui, repo, pycompat.byteskwargs(opts), None
7003 ):
6994 ):
7004 if i:
6995 if i:
7005 needsincoming = True
6996 needsincoming = True
7006 if o:
6997 if o:
7007 needsoutgoing = True
6998 needsoutgoing = True
7008 if not needsincoming and not needsoutgoing:
6999 if not needsincoming and not needsoutgoing:
7009 return
7000 return
7010
7001
7011 def getincoming():
7002 def getincoming():
7012 # XXX We should actually skip this if no default is specified, instead
7003 # XXX We should actually skip this if no default is specified, instead
7013 # of passing "default" which will resolve as "./default/" if no default
7004 # of passing "default" which will resolve as "./default/" if no default
7014 # path is defined.
7005 # path is defined.
7015 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7006 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7016 sbranch = path.branch
7007 sbranch = path.branch
7017 try:
7008 try:
7018 other = hg.peer(repo, {}, path)
7009 other = hg.peer(repo, {}, path)
7019 except error.RepoError:
7010 except error.RepoError:
7020 if opts.get('remote'):
7011 if opts.get('remote'):
7021 raise
7012 raise
7022 return path.loc, sbranch, None, None, None
7013 return path.loc, sbranch, None, None, None
7023 branches = (path.branch, [])
7014 branches = (path.branch, [])
7024 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7015 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7025 if revs:
7016 if revs:
7026 revs = [other.lookup(rev) for rev in revs]
7017 revs = [other.lookup(rev) for rev in revs]
7027 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7018 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7028 with repo.ui.silent():
7019 with repo.ui.silent():
7029 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7020 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7030 return path.loc, sbranch, other, commoninc, commoninc[1]
7021 return path.loc, sbranch, other, commoninc, commoninc[1]
7031
7022
7032 if needsincoming:
7023 if needsincoming:
7033 source, sbranch, sother, commoninc, incoming = getincoming()
7024 source, sbranch, sother, commoninc, incoming = getincoming()
7034 else:
7025 else:
7035 source = sbranch = sother = commoninc = incoming = None
7026 source = sbranch = sother = commoninc = incoming = None
7036
7027
7037 def getoutgoing():
7028 def getoutgoing():
7038 # XXX We should actually skip this if no default is specified, instead
7029 # XXX We should actually skip this if no default is specified, instead
7039 # of passing "default" which will resolve as "./default/" if no default
7030 # of passing "default" which will resolve as "./default/" if no default
7040 # path is defined.
7031 # path is defined.
7041 d = None
7032 d = None
7042 if b'default-push' in ui.paths:
7033 if b'default-push' in ui.paths:
7043 d = b'default-push'
7034 d = b'default-push'
7044 elif b'default' in ui.paths:
7035 elif b'default' in ui.paths:
7045 d = b'default'
7036 d = b'default'
7046 path = None
7037 path = None
7047 if d is not None:
7038 if d is not None:
7048 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7039 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7049 dest = path.loc
7040 dest = path.loc
7050 dbranch = path.branch
7041 dbranch = path.branch
7051 else:
7042 else:
7052 dest = b'default'
7043 dest = b'default'
7053 dbranch = None
7044 dbranch = None
7054 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7045 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7055 if source != dest:
7046 if source != dest:
7056 try:
7047 try:
7057 dother = hg.peer(repo, {}, path if path is not None else dest)
7048 dother = hg.peer(repo, {}, path if path is not None else dest)
7058 except error.RepoError:
7049 except error.RepoError:
7059 if opts.get('remote'):
7050 if opts.get('remote'):
7060 raise
7051 raise
7061 return dest, dbranch, None, None
7052 return dest, dbranch, None, None
7062 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7053 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7063 elif sother is None:
7054 elif sother is None:
7064 # there is no explicit destination peer, but source one is invalid
7055 # there is no explicit destination peer, but source one is invalid
7065 return dest, dbranch, None, None
7056 return dest, dbranch, None, None
7066 else:
7057 else:
7067 dother = sother
7058 dother = sother
7068 if source != dest or (sbranch is not None and sbranch != dbranch):
7059 if source != dest or (sbranch is not None and sbranch != dbranch):
7069 common = None
7060 common = None
7070 else:
7061 else:
7071 common = commoninc
7062 common = commoninc
7072 if revs:
7063 if revs:
7073 revs = [repo.lookup(rev) for rev in revs]
7064 revs = [repo.lookup(rev) for rev in revs]
7074 with repo.ui.silent():
7065 with repo.ui.silent():
7075 outgoing = discovery.findcommonoutgoing(
7066 outgoing = discovery.findcommonoutgoing(
7076 repo, dother, onlyheads=revs, commoninc=common
7067 repo, dother, onlyheads=revs, commoninc=common
7077 )
7068 )
7078 return dest, dbranch, dother, outgoing
7069 return dest, dbranch, dother, outgoing
7079
7070
7080 if needsoutgoing:
7071 if needsoutgoing:
7081 dest, dbranch, dother, outgoing = getoutgoing()
7072 dest, dbranch, dother, outgoing = getoutgoing()
7082 else:
7073 else:
7083 dest = dbranch = dother = outgoing = None
7074 dest = dbranch = dother = outgoing = None
7084
7075
7085 if opts.get('remote'):
7076 if opts.get('remote'):
7086 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7077 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7087 # The former always sets `sother` (or raises an exception if it can't);
7078 # The former always sets `sother` (or raises an exception if it can't);
7088 # the latter always sets `outgoing`.
7079 # the latter always sets `outgoing`.
7089 assert sother is not None
7080 assert sother is not None
7090 assert outgoing is not None
7081 assert outgoing is not None
7091
7082
7092 t = []
7083 t = []
7093 if incoming:
7084 if incoming:
7094 t.append(_(b'1 or more incoming'))
7085 t.append(_(b'1 or more incoming'))
7095 o = outgoing.missing
7086 o = outgoing.missing
7096 if o:
7087 if o:
7097 t.append(_(b'%d outgoing') % len(o))
7088 t.append(_(b'%d outgoing') % len(o))
7098 other = dother or sother
7089 other = dother or sother
7099 if b'bookmarks' in other.listkeys(b'namespaces'):
7090 if b'bookmarks' in other.listkeys(b'namespaces'):
7100 counts = bookmarks.summary(repo, other)
7091 counts = bookmarks.summary(repo, other)
7101 if counts[0] > 0:
7092 if counts[0] > 0:
7102 t.append(_(b'%d incoming bookmarks') % counts[0])
7093 t.append(_(b'%d incoming bookmarks') % counts[0])
7103 if counts[1] > 0:
7094 if counts[1] > 0:
7104 t.append(_(b'%d outgoing bookmarks') % counts[1])
7095 t.append(_(b'%d outgoing bookmarks') % counts[1])
7105
7096
7106 if t:
7097 if t:
7107 # i18n: column positioning for "hg summary"
7098 # i18n: column positioning for "hg summary"
7108 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7099 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7109 else:
7100 else:
7110 # i18n: column positioning for "hg summary"
7101 # i18n: column positioning for "hg summary"
7111 ui.status(_(b'remote: (synced)\n'))
7102 ui.status(_(b'remote: (synced)\n'))
7112
7103
7113 cmdutil.summaryremotehooks(
7104 cmdutil.summaryremotehooks(
7114 ui,
7105 ui,
7115 repo,
7106 repo,
7116 pycompat.byteskwargs(opts),
7107 pycompat.byteskwargs(opts),
7117 (
7108 (
7118 (source, sbranch, sother, commoninc),
7109 (source, sbranch, sother, commoninc),
7119 (dest, dbranch, dother, outgoing),
7110 (dest, dbranch, dother, outgoing),
7120 ),
7111 ),
7121 )
7112 )
7122
7113
7123
7114
7124 @command(
7115 @command(
7125 b'tag',
7116 b'tag',
7126 [
7117 [
7127 (b'f', b'force', None, _(b'force tag')),
7118 (b'f', b'force', None, _(b'force tag')),
7128 (b'l', b'local', None, _(b'make the tag local')),
7119 (b'l', b'local', None, _(b'make the tag local')),
7129 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7120 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7130 (b'', b'remove', None, _(b'remove a tag')),
7121 (b'', b'remove', None, _(b'remove a tag')),
7131 # -l/--local is already there, commitopts cannot be used
7122 # -l/--local is already there, commitopts cannot be used
7132 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7123 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7133 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7124 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7134 ]
7125 ]
7135 + commitopts2,
7126 + commitopts2,
7136 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7127 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7137 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7128 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7138 )
7129 )
7139 def tag(ui, repo, name1, *names, **opts):
7130 def tag(ui, repo, name1, *names, **opts):
7140 """add one or more tags for the current or given revision
7131 """add one or more tags for the current or given revision
7141
7132
7142 Name a particular revision using <name>.
7133 Name a particular revision using <name>.
7143
7134
7144 Tags are used to name particular revisions of the repository and are
7135 Tags are used to name particular revisions of the repository and are
7145 very useful to compare different revisions, to go back to significant
7136 very useful to compare different revisions, to go back to significant
7146 earlier versions or to mark branch points as releases, etc. Changing
7137 earlier versions or to mark branch points as releases, etc. Changing
7147 an existing tag is normally disallowed; use -f/--force to override.
7138 an existing tag is normally disallowed; use -f/--force to override.
7148
7139
7149 If no revision is given, the parent of the working directory is
7140 If no revision is given, the parent of the working directory is
7150 used.
7141 used.
7151
7142
7152 To facilitate version control, distribution, and merging of tags,
7143 To facilitate version control, distribution, and merging of tags,
7153 they are stored as a file named ".hgtags" which is managed similarly
7144 they are stored as a file named ".hgtags" which is managed similarly
7154 to other project files and can be hand-edited if necessary. This
7145 to other project files and can be hand-edited if necessary. This
7155 also means that tagging creates a new commit. The file
7146 also means that tagging creates a new commit. The file
7156 ".hg/localtags" is used for local tags (not shared among
7147 ".hg/localtags" is used for local tags (not shared among
7157 repositories).
7148 repositories).
7158
7149
7159 Tag commits are usually made at the head of a branch. If the parent
7150 Tag commits are usually made at the head of a branch. If the parent
7160 of the working directory is not a branch head, :hg:`tag` aborts; use
7151 of the working directory is not a branch head, :hg:`tag` aborts; use
7161 -f/--force to force the tag commit to be based on a non-head
7152 -f/--force to force the tag commit to be based on a non-head
7162 changeset.
7153 changeset.
7163
7154
7164 See :hg:`help dates` for a list of formats valid for -d/--date.
7155 See :hg:`help dates` for a list of formats valid for -d/--date.
7165
7156
7166 Since tag names have priority over branch names during revision
7157 Since tag names have priority over branch names during revision
7167 lookup, using an existing branch name as a tag name is discouraged.
7158 lookup, using an existing branch name as a tag name is discouraged.
7168
7159
7169 Returns 0 on success.
7160 Returns 0 on success.
7170 """
7161 """
7171 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7162 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7172
7163
7173 with repo.wlock(), repo.lock():
7164 with repo.wlock(), repo.lock():
7174 rev_ = b"."
7165 rev_ = b"."
7175 names = [t.strip() for t in (name1,) + names]
7166 names = [t.strip() for t in (name1,) + names]
7176 if len(names) != len(set(names)):
7167 if len(names) != len(set(names)):
7177 raise error.InputError(_(b'tag names must be unique'))
7168 raise error.InputError(_(b'tag names must be unique'))
7178 for n in names:
7169 for n in names:
7179 scmutil.checknewlabel(repo, n, b'tag')
7170 scmutil.checknewlabel(repo, n, b'tag')
7180 if not n:
7171 if not n:
7181 raise error.InputError(
7172 raise error.InputError(
7182 _(b'tag names cannot consist entirely of whitespace')
7173 _(b'tag names cannot consist entirely of whitespace')
7183 )
7174 )
7184 if opts.get('rev'):
7175 if opts.get('rev'):
7185 rev_ = opts['rev']
7176 rev_ = opts['rev']
7186 message = opts.get('message')
7177 message = opts.get('message')
7187 if opts.get('remove'):
7178 if opts.get('remove'):
7188 if opts.get('local'):
7179 if opts.get('local'):
7189 expectedtype = b'local'
7180 expectedtype = b'local'
7190 else:
7181 else:
7191 expectedtype = b'global'
7182 expectedtype = b'global'
7192
7183
7193 for n in names:
7184 for n in names:
7194 if repo.tagtype(n) == b'global':
7185 if repo.tagtype(n) == b'global':
7195 alltags = tagsmod.findglobaltags(ui, repo)
7186 alltags = tagsmod.findglobaltags(ui, repo)
7196 if alltags[n][0] == repo.nullid:
7187 if alltags[n][0] == repo.nullid:
7197 raise error.InputError(
7188 raise error.InputError(
7198 _(b"tag '%s' is already removed") % n
7189 _(b"tag '%s' is already removed") % n
7199 )
7190 )
7200 if not repo.tagtype(n):
7191 if not repo.tagtype(n):
7201 raise error.InputError(_(b"tag '%s' does not exist") % n)
7192 raise error.InputError(_(b"tag '%s' does not exist") % n)
7202 if repo.tagtype(n) != expectedtype:
7193 if repo.tagtype(n) != expectedtype:
7203 if expectedtype == b'global':
7194 if expectedtype == b'global':
7204 raise error.InputError(
7195 raise error.InputError(
7205 _(b"tag '%s' is not a global tag") % n
7196 _(b"tag '%s' is not a global tag") % n
7206 )
7197 )
7207 else:
7198 else:
7208 raise error.InputError(
7199 raise error.InputError(
7209 _(b"tag '%s' is not a local tag") % n
7200 _(b"tag '%s' is not a local tag") % n
7210 )
7201 )
7211 rev_ = b'null'
7202 rev_ = b'null'
7212 if not message:
7203 if not message:
7213 # we don't translate commit messages
7204 # we don't translate commit messages
7214 message = b'Removed tag %s' % b', '.join(names)
7205 message = b'Removed tag %s' % b', '.join(names)
7215 elif not opts.get('force'):
7206 elif not opts.get('force'):
7216 for n in names:
7207 for n in names:
7217 if n in repo.tags():
7208 if n in repo.tags():
7218 raise error.InputError(
7209 raise error.InputError(
7219 _(b"tag '%s' already exists (use -f to force)") % n
7210 _(b"tag '%s' already exists (use -f to force)") % n
7220 )
7211 )
7221 if not opts.get('local'):
7212 if not opts.get('local'):
7222 p1, p2 = repo.dirstate.parents()
7213 p1, p2 = repo.dirstate.parents()
7223 if p2 != repo.nullid:
7214 if p2 != repo.nullid:
7224 raise error.StateError(_(b'uncommitted merge'))
7215 raise error.StateError(_(b'uncommitted merge'))
7225 bheads = repo.branchheads()
7216 bheads = repo.branchheads()
7226 if not opts.get('force') and bheads and p1 not in bheads:
7217 if not opts.get('force') and bheads and p1 not in bheads:
7227 raise error.InputError(
7218 raise error.InputError(
7228 _(
7219 _(
7229 b'working directory is not at a branch head '
7220 b'working directory is not at a branch head '
7230 b'(use -f to force)'
7221 b'(use -f to force)'
7231 )
7222 )
7232 )
7223 )
7233 node = logcmdutil.revsingle(repo, rev_).node()
7224 node = logcmdutil.revsingle(repo, rev_).node()
7234
7225
7235 # don't allow tagging the null rev or the working directory
7226 # don't allow tagging the null rev or the working directory
7236 if node is None:
7227 if node is None:
7237 raise error.InputError(_(b"cannot tag working directory"))
7228 raise error.InputError(_(b"cannot tag working directory"))
7238 elif not opts.get('remove') and node == nullid:
7229 elif not opts.get('remove') and node == nullid:
7239 raise error.InputError(_(b"cannot tag null revision"))
7230 raise error.InputError(_(b"cannot tag null revision"))
7240
7231
7241 if not message:
7232 if not message:
7242 # we don't translate commit messages
7233 # we don't translate commit messages
7243 message = b'Added tag %s for changeset %s' % (
7234 message = b'Added tag %s for changeset %s' % (
7244 b', '.join(names),
7235 b', '.join(names),
7245 short(node),
7236 short(node),
7246 )
7237 )
7247
7238
7248 date = opts.get('date')
7239 date = opts.get('date')
7249 if date:
7240 if date:
7250 date = dateutil.parsedate(date)
7241 date = dateutil.parsedate(date)
7251
7242
7252 if opts.get('remove'):
7243 if opts.get('remove'):
7253 editform = b'tag.remove'
7244 editform = b'tag.remove'
7254 else:
7245 else:
7255 editform = b'tag.add'
7246 editform = b'tag.add'
7256 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7247 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7257
7248
7258 tagsmod.tag(
7249 tagsmod.tag(
7259 repo,
7250 repo,
7260 names,
7251 names,
7261 node,
7252 node,
7262 message,
7253 message,
7263 opts.get('local'),
7254 opts.get('local'),
7264 opts.get('user'),
7255 opts.get('user'),
7265 date,
7256 date,
7266 editor=editor,
7257 editor=editor,
7267 )
7258 )
7268
7259
7269
7260
7270 @command(
7261 @command(
7271 b'tags',
7262 b'tags',
7272 formatteropts,
7263 formatteropts,
7273 b'',
7264 b'',
7274 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7265 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7275 intents={INTENT_READONLY},
7266 intents={INTENT_READONLY},
7276 )
7267 )
7277 def tags(ui, repo, **opts):
7268 def tags(ui, repo, **opts):
7278 """list repository tags
7269 """list repository tags
7279
7270
7280 This lists both regular and local tags. When the -v/--verbose
7271 This lists both regular and local tags. When the -v/--verbose
7281 switch is used, a third column "local" is printed for local tags.
7272 switch is used, a third column "local" is printed for local tags.
7282 When the -q/--quiet switch is used, only the tag name is printed.
7273 When the -q/--quiet switch is used, only the tag name is printed.
7283
7274
7284 .. container:: verbose
7275 .. container:: verbose
7285
7276
7286 Template:
7277 Template:
7287
7278
7288 The following keywords are supported in addition to the common template
7279 The following keywords are supported in addition to the common template
7289 keywords and functions such as ``{tag}``. See also
7280 keywords and functions such as ``{tag}``. See also
7290 :hg:`help templates`.
7281 :hg:`help templates`.
7291
7282
7292 :type: String. ``local`` for local tags.
7283 :type: String. ``local`` for local tags.
7293
7284
7294 Returns 0 on success.
7285 Returns 0 on success.
7295 """
7286 """
7296
7287
7297 ui.pager(b'tags')
7288 ui.pager(b'tags')
7298 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7289 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7299 hexfunc = fm.hexfunc
7290 hexfunc = fm.hexfunc
7300
7291
7301 for t, n in reversed(repo.tagslist()):
7292 for t, n in reversed(repo.tagslist()):
7302 hn = hexfunc(n)
7293 hn = hexfunc(n)
7303 label = b'tags.normal'
7294 label = b'tags.normal'
7304 tagtype = repo.tagtype(t)
7295 tagtype = repo.tagtype(t)
7305 if not tagtype or tagtype == b'global':
7296 if not tagtype or tagtype == b'global':
7306 tagtype = b''
7297 tagtype = b''
7307 else:
7298 else:
7308 label = b'tags.' + tagtype
7299 label = b'tags.' + tagtype
7309
7300
7310 fm.startitem()
7301 fm.startitem()
7311 fm.context(repo=repo)
7302 fm.context(repo=repo)
7312 fm.write(b'tag', b'%s', t, label=label)
7303 fm.write(b'tag', b'%s', t, label=label)
7313 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7304 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7314 fm.condwrite(
7305 fm.condwrite(
7315 not ui.quiet,
7306 not ui.quiet,
7316 b'rev node',
7307 b'rev node',
7317 fmt,
7308 fmt,
7318 repo.changelog.rev(n),
7309 repo.changelog.rev(n),
7319 hn,
7310 hn,
7320 label=label,
7311 label=label,
7321 )
7312 )
7322 fm.condwrite(
7313 fm.condwrite(
7323 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7314 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7324 )
7315 )
7325 fm.plain(b'\n')
7316 fm.plain(b'\n')
7326 fm.end()
7317 fm.end()
7327
7318
7328
7319
7329 @command(
7320 @command(
7330 b'tip',
7321 b'tip',
7331 [
7322 [
7332 (b'p', b'patch', None, _(b'show patch')),
7323 (b'p', b'patch', None, _(b'show patch')),
7333 (b'g', b'git', None, _(b'use git extended diff format')),
7324 (b'g', b'git', None, _(b'use git extended diff format')),
7334 ]
7325 ]
7335 + templateopts,
7326 + templateopts,
7336 _(b'[-p] [-g]'),
7327 _(b'[-p] [-g]'),
7337 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7328 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7338 )
7329 )
7339 def tip(ui, repo, **opts):
7330 def tip(ui, repo, **opts):
7340 """show the tip revision (DEPRECATED)
7331 """show the tip revision (DEPRECATED)
7341
7332
7342 The tip revision (usually just called the tip) is the changeset
7333 The tip revision (usually just called the tip) is the changeset
7343 most recently added to the repository (and therefore the most
7334 most recently added to the repository (and therefore the most
7344 recently changed head).
7335 recently changed head).
7345
7336
7346 If you have just made a commit, that commit will be the tip. If
7337 If you have just made a commit, that commit will be the tip. If
7347 you have just pulled changes from another repository, the tip of
7338 you have just pulled changes from another repository, the tip of
7348 that repository becomes the current tip. The "tip" tag is special
7339 that repository becomes the current tip. The "tip" tag is special
7349 and cannot be renamed or assigned to a different changeset.
7340 and cannot be renamed or assigned to a different changeset.
7350
7341
7351 This command is deprecated, please use :hg:`heads` instead.
7342 This command is deprecated, please use :hg:`heads` instead.
7352
7343
7353 Returns 0 on success.
7344 Returns 0 on success.
7354 """
7345 """
7355 opts = pycompat.byteskwargs(opts)
7346 opts = pycompat.byteskwargs(opts)
7356 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7347 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7357 displayer.show(repo[b'tip'])
7348 displayer.show(repo[b'tip'])
7358 displayer.close()
7349 displayer.close()
7359
7350
7360
7351
7361 @command(
7352 @command(
7362 b'unbundle',
7353 b'unbundle',
7363 [
7354 [
7364 (
7355 (
7365 b'u',
7356 b'u',
7366 b'update',
7357 b'update',
7367 None,
7358 None,
7368 _(b'update to new branch head if changesets were unbundled'),
7359 _(b'update to new branch head if changesets were unbundled'),
7369 )
7360 )
7370 ],
7361 ],
7371 _(b'[-u] FILE...'),
7362 _(b'[-u] FILE...'),
7372 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7363 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7373 )
7364 )
7374 def unbundle(ui, repo, fname1, *fnames, **opts):
7365 def unbundle(ui, repo, fname1, *fnames, **opts):
7375 """apply one or more bundle files
7366 """apply one or more bundle files
7376
7367
7377 Apply one or more bundle files generated by :hg:`bundle`.
7368 Apply one or more bundle files generated by :hg:`bundle`.
7378
7369
7379 Returns 0 on success, 1 if an update has unresolved files.
7370 Returns 0 on success, 1 if an update has unresolved files.
7380 """
7371 """
7381 fnames = (fname1,) + fnames
7372 fnames = (fname1,) + fnames
7382 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7373 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7383
7374
7384 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7375 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7385 return 1
7376 return 1
7386 else:
7377 else:
7387 return 0
7378 return 0
7388
7379
7389
7380
7390 @command(
7381 @command(
7391 b'unshelve',
7382 b'unshelve',
7392 [
7383 [
7393 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7384 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7394 (
7385 (
7395 b'c',
7386 b'c',
7396 b'continue',
7387 b'continue',
7397 None,
7388 None,
7398 _(b'continue an incomplete unshelve operation'),
7389 _(b'continue an incomplete unshelve operation'),
7399 ),
7390 ),
7400 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7391 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7401 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7392 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7402 (
7393 (
7403 b'n',
7394 b'n',
7404 b'name',
7395 b'name',
7405 b'',
7396 b'',
7406 _(b'restore shelved change with given name'),
7397 _(b'restore shelved change with given name'),
7407 _(b'NAME'),
7398 _(b'NAME'),
7408 ),
7399 ),
7409 (b't', b'tool', b'', _(b'specify merge tool')),
7400 (b't', b'tool', b'', _(b'specify merge tool')),
7410 (
7401 (
7411 b'',
7402 b'',
7412 b'date',
7403 b'date',
7413 b'',
7404 b'',
7414 _(b'set date for temporary commits (DEPRECATED)'),
7405 _(b'set date for temporary commits (DEPRECATED)'),
7415 _(b'DATE'),
7406 _(b'DATE'),
7416 ),
7407 ),
7417 ],
7408 ],
7418 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7409 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7419 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7410 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7420 )
7411 )
7421 def unshelve(ui, repo, *shelved, **opts):
7412 def unshelve(ui, repo, *shelved, **opts):
7422 """restore a shelved change to the working directory
7413 """restore a shelved change to the working directory
7423
7414
7424 This command accepts an optional name of a shelved change to
7415 This command accepts an optional name of a shelved change to
7425 restore. If none is given, the most recent shelved change is used.
7416 restore. If none is given, the most recent shelved change is used.
7426
7417
7427 If a shelved change is applied successfully, the bundle that
7418 If a shelved change is applied successfully, the bundle that
7428 contains the shelved changes is moved to a backup location
7419 contains the shelved changes is moved to a backup location
7429 (.hg/shelve-backup).
7420 (.hg/shelve-backup).
7430
7421
7431 Since you can restore a shelved change on top of an arbitrary
7422 Since you can restore a shelved change on top of an arbitrary
7432 commit, it is possible that unshelving will result in a conflict
7423 commit, it is possible that unshelving will result in a conflict
7433 between your changes and the commits you are unshelving onto. If
7424 between your changes and the commits you are unshelving onto. If
7434 this occurs, you must resolve the conflict, then use
7425 this occurs, you must resolve the conflict, then use
7435 ``--continue`` to complete the unshelve operation. (The bundle
7426 ``--continue`` to complete the unshelve operation. (The bundle
7436 will not be moved until you successfully complete the unshelve.)
7427 will not be moved until you successfully complete the unshelve.)
7437
7428
7438 (Alternatively, you can use ``--abort`` to abandon an unshelve
7429 (Alternatively, you can use ``--abort`` to abandon an unshelve
7439 that causes a conflict. This reverts the unshelved changes, and
7430 that causes a conflict. This reverts the unshelved changes, and
7440 leaves the bundle in place.)
7431 leaves the bundle in place.)
7441
7432
7442 If bare shelved change (without interactive, include and exclude
7433 If bare shelved change (without interactive, include and exclude
7443 option) was done on newly created branch it would restore branch
7434 option) was done on newly created branch it would restore branch
7444 information to the working directory.
7435 information to the working directory.
7445
7436
7446 After a successful unshelve, the shelved changes are stored in a
7437 After a successful unshelve, the shelved changes are stored in a
7447 backup directory. Only the N most recent backups are kept. N
7438 backup directory. Only the N most recent backups are kept. N
7448 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7439 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7449 configuration option.
7440 configuration option.
7450
7441
7451 .. container:: verbose
7442 .. container:: verbose
7452
7443
7453 Timestamp in seconds is used to decide order of backups. More
7444 Timestamp in seconds is used to decide order of backups. More
7454 than ``maxbackups`` backups are kept, if same timestamp
7445 than ``maxbackups`` backups are kept, if same timestamp
7455 prevents from deciding exact order of them, for safety.
7446 prevents from deciding exact order of them, for safety.
7456
7447
7457 Selected changes can be unshelved with ``--interactive`` flag.
7448 Selected changes can be unshelved with ``--interactive`` flag.
7458 The working directory is updated with the selected changes, and
7449 The working directory is updated with the selected changes, and
7459 only the unselected changes remain shelved.
7450 only the unselected changes remain shelved.
7460 Note: The whole shelve is applied to working directory first before
7451 Note: The whole shelve is applied to working directory first before
7461 running interactively. So, this will bring up all the conflicts between
7452 running interactively. So, this will bring up all the conflicts between
7462 working directory and the shelve, irrespective of which changes will be
7453 working directory and the shelve, irrespective of which changes will be
7463 unshelved.
7454 unshelved.
7464 """
7455 """
7465 with repo.wlock():
7456 with repo.wlock():
7466 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7457 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7467
7458
7468
7459
7469 statemod.addunfinished(
7460 statemod.addunfinished(
7470 b'unshelve',
7461 b'unshelve',
7471 fname=b'shelvedstate',
7462 fname=b'shelvedstate',
7472 continueflag=True,
7463 continueflag=True,
7473 abortfunc=shelvemod.hgabortunshelve,
7464 abortfunc=shelvemod.hgabortunshelve,
7474 continuefunc=shelvemod.hgcontinueunshelve,
7465 continuefunc=shelvemod.hgcontinueunshelve,
7475 cmdmsg=_(b'unshelve already in progress'),
7466 cmdmsg=_(b'unshelve already in progress'),
7476 )
7467 )
7477
7468
7478
7469
7479 @command(
7470 @command(
7480 b'update|up|checkout|co',
7471 b'update|up|checkout|co',
7481 [
7472 [
7482 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7473 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7483 (b'c', b'check', None, _(b'require clean working directory')),
7474 (b'c', b'check', None, _(b'require clean working directory')),
7484 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7475 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7485 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7476 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7486 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7477 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7487 ]
7478 ]
7488 + mergetoolopts,
7479 + mergetoolopts,
7489 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7480 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7490 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7481 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7491 helpbasic=True,
7482 helpbasic=True,
7492 )
7483 )
7493 def update(ui, repo, node=None, **opts):
7484 def update(ui, repo, node=None, **opts):
7494 """update working directory (or switch revisions)
7485 """update working directory (or switch revisions)
7495
7486
7496 Update the repository's working directory to the specified
7487 Update the repository's working directory to the specified
7497 changeset. If no changeset is specified, update to the tip of the
7488 changeset. If no changeset is specified, update to the tip of the
7498 current named branch and move the active bookmark (see :hg:`help
7489 current named branch and move the active bookmark (see :hg:`help
7499 bookmarks`).
7490 bookmarks`).
7500
7491
7501 Update sets the working directory's parent revision to the specified
7492 Update sets the working directory's parent revision to the specified
7502 changeset (see :hg:`help parents`).
7493 changeset (see :hg:`help parents`).
7503
7494
7504 If the changeset is not a descendant or ancestor of the working
7495 If the changeset is not a descendant or ancestor of the working
7505 directory's parent and there are uncommitted changes, the update is
7496 directory's parent and there are uncommitted changes, the update is
7506 aborted. With the -c/--check option, the working directory is checked
7497 aborted. With the -c/--check option, the working directory is checked
7507 for uncommitted changes; if none are found, the working directory is
7498 for uncommitted changes; if none are found, the working directory is
7508 updated to the specified changeset.
7499 updated to the specified changeset.
7509
7500
7510 .. container:: verbose
7501 .. container:: verbose
7511
7502
7512 The -C/--clean, -c/--check, and -m/--merge options control what
7503 The -C/--clean, -c/--check, and -m/--merge options control what
7513 happens if the working directory contains uncommitted changes.
7504 happens if the working directory contains uncommitted changes.
7514 At most of one of them can be specified.
7505 At most of one of them can be specified.
7515
7506
7516 1. If no option is specified, and if
7507 1. If no option is specified, and if
7517 the requested changeset is an ancestor or descendant of
7508 the requested changeset is an ancestor or descendant of
7518 the working directory's parent, the uncommitted changes
7509 the working directory's parent, the uncommitted changes
7519 are merged into the requested changeset and the merged
7510 are merged into the requested changeset and the merged
7520 result is left uncommitted. If the requested changeset is
7511 result is left uncommitted. If the requested changeset is
7521 not an ancestor or descendant (that is, it is on another
7512 not an ancestor or descendant (that is, it is on another
7522 branch), the update is aborted and the uncommitted changes
7513 branch), the update is aborted and the uncommitted changes
7523 are preserved.
7514 are preserved.
7524
7515
7525 2. With the -m/--merge option, the update is allowed even if the
7516 2. With the -m/--merge option, the update is allowed even if the
7526 requested changeset is not an ancestor or descendant of
7517 requested changeset is not an ancestor or descendant of
7527 the working directory's parent.
7518 the working directory's parent.
7528
7519
7529 3. With the -c/--check option, the update is aborted and the
7520 3. With the -c/--check option, the update is aborted and the
7530 uncommitted changes are preserved.
7521 uncommitted changes are preserved.
7531
7522
7532 4. With the -C/--clean option, uncommitted changes are discarded and
7523 4. With the -C/--clean option, uncommitted changes are discarded and
7533 the working directory is updated to the requested changeset.
7524 the working directory is updated to the requested changeset.
7534
7525
7535 To cancel an uncommitted merge (and lose your changes), use
7526 To cancel an uncommitted merge (and lose your changes), use
7536 :hg:`merge --abort`.
7527 :hg:`merge --abort`.
7537
7528
7538 Use null as the changeset to remove the working directory (like
7529 Use null as the changeset to remove the working directory (like
7539 :hg:`clone -U`).
7530 :hg:`clone -U`).
7540
7531
7541 If you want to revert just one file to an older revision, use
7532 If you want to revert just one file to an older revision, use
7542 :hg:`revert [-r REV] NAME`.
7533 :hg:`revert [-r REV] NAME`.
7543
7534
7544 See :hg:`help dates` for a list of formats valid for -d/--date.
7535 See :hg:`help dates` for a list of formats valid for -d/--date.
7545
7536
7546 Returns 0 on success, 1 if there are unresolved files.
7537 Returns 0 on success, 1 if there are unresolved files.
7547 """
7538 """
7548 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7539 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7549 rev = opts.get('rev')
7540 rev = opts.get('rev')
7550 date = opts.get('date')
7541 date = opts.get('date')
7551 clean = opts.get('clean')
7542 clean = opts.get('clean')
7552 check = opts.get('check')
7543 check = opts.get('check')
7553 merge = opts.get('merge')
7544 merge = opts.get('merge')
7554 if rev and node:
7545 if rev and node:
7555 raise error.InputError(_(b"please specify just one revision"))
7546 raise error.InputError(_(b"please specify just one revision"))
7556
7547
7557 if ui.configbool(b'commands', b'update.requiredest'):
7548 if ui.configbool(b'commands', b'update.requiredest'):
7558 if not node and not rev and not date:
7549 if not node and not rev and not date:
7559 raise error.InputError(
7550 raise error.InputError(
7560 _(b'you must specify a destination'),
7551 _(b'you must specify a destination'),
7561 hint=_(b'for example: hg update ".::"'),
7552 hint=_(b'for example: hg update ".::"'),
7562 )
7553 )
7563
7554
7564 if rev is None or rev == b'':
7555 if rev is None or rev == b'':
7565 rev = node
7556 rev = node
7566
7557
7567 if date and rev is not None:
7558 if date and rev is not None:
7568 raise error.InputError(_(b"you can't specify a revision and a date"))
7559 raise error.InputError(_(b"you can't specify a revision and a date"))
7569
7560
7570 updatecheck = None
7561 updatecheck = None
7571 if check or merge is not None and not merge:
7562 if check or merge is not None and not merge:
7572 updatecheck = b'abort'
7563 updatecheck = b'abort'
7573 elif merge or check is not None and not check:
7564 elif merge or check is not None and not check:
7574 updatecheck = b'none'
7565 updatecheck = b'none'
7575
7566
7576 with repo.wlock():
7567 with repo.wlock():
7577 cmdutil.clearunfinished(repo)
7568 cmdutil.clearunfinished(repo)
7578 if date:
7569 if date:
7579 rev = cmdutil.finddate(ui, repo, date)
7570 rev = cmdutil.finddate(ui, repo, date)
7580
7571
7581 # if we defined a bookmark, we have to remember the original name
7572 # if we defined a bookmark, we have to remember the original name
7582 brev = rev
7573 brev = rev
7583 if rev:
7574 if rev:
7584 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7575 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7585 ctx = logcmdutil.revsingle(repo, rev, default=None)
7576 ctx = logcmdutil.revsingle(repo, rev, default=None)
7586 rev = ctx.rev()
7577 rev = ctx.rev()
7587 hidden = ctx.hidden()
7578 hidden = ctx.hidden()
7588 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7579 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7589 with ui.configoverride(overrides, b'update'):
7580 with ui.configoverride(overrides, b'update'):
7590 ret = hg.updatetotally(
7581 ret = hg.updatetotally(
7591 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7582 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7592 )
7583 )
7593 if hidden:
7584 if hidden:
7594 ctxstr = ctx.hex()[:12]
7585 ctxstr = ctx.hex()[:12]
7595 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7586 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7596
7587
7597 if ctx.obsolete():
7588 if ctx.obsolete():
7598 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7589 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7599 ui.warn(b"(%s)\n" % obsfatemsg)
7590 ui.warn(b"(%s)\n" % obsfatemsg)
7600 return ret
7591 return ret
7601
7592
7602
7593
7603 @command(
7594 @command(
7604 b'verify',
7595 b'verify',
7605 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7596 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7606 helpcategory=command.CATEGORY_MAINTENANCE,
7597 helpcategory=command.CATEGORY_MAINTENANCE,
7607 )
7598 )
7608 def verify(ui, repo, **opts):
7599 def verify(ui, repo, **opts):
7609 """verify the integrity of the repository
7600 """verify the integrity of the repository
7610
7601
7611 Verify the integrity of the current repository.
7602 Verify the integrity of the current repository.
7612
7603
7613 This will perform an extensive check of the repository's
7604 This will perform an extensive check of the repository's
7614 integrity, validating the hashes and checksums of each entry in
7605 integrity, validating the hashes and checksums of each entry in
7615 the changelog, manifest, and tracked files, as well as the
7606 the changelog, manifest, and tracked files, as well as the
7616 integrity of their crosslinks and indices.
7607 integrity of their crosslinks and indices.
7617
7608
7618 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7609 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7619 for more information about recovery from corruption of the
7610 for more information about recovery from corruption of the
7620 repository.
7611 repository.
7621
7612
7622 For an alternative UI with a lot more control over the verification
7613 For an alternative UI with a lot more control over the verification
7623 process and better error reporting, try `hg help admin::verify`.
7614 process and better error reporting, try `hg help admin::verify`.
7624
7615
7625 Returns 0 on success, 1 if errors are encountered.
7616 Returns 0 on success, 1 if errors are encountered.
7626 """
7617 """
7627 level = None
7618 level = None
7628 if opts['full']:
7619 if opts['full']:
7629 level = verifymod.VERIFY_FULL
7620 level = verifymod.VERIFY_FULL
7630 return hg.verify(repo, level)
7621 return hg.verify(repo, level)
7631
7622
7632
7623
7633 @command(
7624 @command(
7634 b'version',
7625 b'version',
7635 [] + formatteropts,
7626 [] + formatteropts,
7636 helpcategory=command.CATEGORY_HELP,
7627 helpcategory=command.CATEGORY_HELP,
7637 norepo=True,
7628 norepo=True,
7638 intents={INTENT_READONLY},
7629 intents={INTENT_READONLY},
7639 )
7630 )
7640 def version_(ui, **opts):
7631 def version_(ui, **opts):
7641 """output version and copyright information
7632 """output version and copyright information
7642
7633
7643 .. container:: verbose
7634 .. container:: verbose
7644
7635
7645 Template:
7636 Template:
7646
7637
7647 The following keywords are supported. See also :hg:`help templates`.
7638 The following keywords are supported. See also :hg:`help templates`.
7648
7639
7649 :extensions: List of extensions.
7640 :extensions: List of extensions.
7650 :ver: String. Version number.
7641 :ver: String. Version number.
7651
7642
7652 And each entry of ``{extensions}`` provides the following sub-keywords
7643 And each entry of ``{extensions}`` provides the following sub-keywords
7653 in addition to ``{ver}``.
7644 in addition to ``{ver}``.
7654
7645
7655 :bundled: Boolean. True if included in the release.
7646 :bundled: Boolean. True if included in the release.
7656 :name: String. Extension name.
7647 :name: String. Extension name.
7657 """
7648 """
7658 if ui.verbose:
7649 if ui.verbose:
7659 ui.pager(b'version')
7650 ui.pager(b'version')
7660 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7651 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7661 fm.startitem()
7652 fm.startitem()
7662 fm.write(
7653 fm.write(
7663 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7654 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7664 )
7655 )
7665 license = _(
7656 license = _(
7666 b"(see https://mercurial-scm.org for more information)\n"
7657 b"(see https://mercurial-scm.org for more information)\n"
7667 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7658 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7668 b"This is free software; see the source for copying conditions. "
7659 b"This is free software; see the source for copying conditions. "
7669 b"There is NO\nwarranty; "
7660 b"There is NO\nwarranty; "
7670 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7661 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7671 )
7662 )
7672 if not ui.quiet:
7663 if not ui.quiet:
7673 fm.plain(license)
7664 fm.plain(license)
7674
7665
7675 if ui.verbose:
7666 if ui.verbose:
7676 fm.plain(_(b"\nEnabled extensions:\n\n"))
7667 fm.plain(_(b"\nEnabled extensions:\n\n"))
7677 # format names and versions into columns
7668 # format names and versions into columns
7678 names = []
7669 names = []
7679 vers = []
7670 vers = []
7680 isinternals = []
7671 isinternals = []
7681 for name, module in sorted(extensions.extensions()):
7672 for name, module in sorted(extensions.extensions()):
7682 names.append(name)
7673 names.append(name)
7683 vers.append(extensions.moduleversion(module) or None)
7674 vers.append(extensions.moduleversion(module) or None)
7684 isinternals.append(extensions.ismoduleinternal(module))
7675 isinternals.append(extensions.ismoduleinternal(module))
7685 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7676 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7686 if names:
7677 if names:
7687 namefmt = b" %%-%ds " % max(len(n) for n in names)
7678 namefmt = b" %%-%ds " % max(len(n) for n in names)
7688 places = [_(b"external"), _(b"internal")]
7679 places = [_(b"external"), _(b"internal")]
7689 for n, v, p in zip(names, vers, isinternals):
7680 for n, v, p in zip(names, vers, isinternals):
7690 fn.startitem()
7681 fn.startitem()
7691 fn.condwrite(ui.verbose, b"name", namefmt, n)
7682 fn.condwrite(ui.verbose, b"name", namefmt, n)
7692 if ui.verbose:
7683 if ui.verbose:
7693 fn.plain(b"%s " % places[p])
7684 fn.plain(b"%s " % places[p])
7694 fn.data(bundled=p)
7685 fn.data(bundled=p)
7695 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7686 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7696 if ui.verbose:
7687 if ui.verbose:
7697 fn.plain(b"\n")
7688 fn.plain(b"\n")
7698 fn.end()
7689 fn.end()
7699 fm.end()
7690 fm.end()
7700
7691
7701
7692
7702 def loadcmdtable(ui, name, cmdtable):
7693 def loadcmdtable(ui, name, cmdtable):
7703 """Load command functions from specified cmdtable"""
7694 """Load command functions from specified cmdtable"""
7704 overrides = [cmd for cmd in cmdtable if cmd in table]
7695 overrides = [cmd for cmd in cmdtable if cmd in table]
7705 if overrides:
7696 if overrides:
7706 ui.warn(
7697 ui.warn(
7707 _(b"extension '%s' overrides commands: %s\n")
7698 _(b"extension '%s' overrides commands: %s\n")
7708 % (name, b" ".join(overrides))
7699 % (name, b" ".join(overrides))
7709 )
7700 )
7710 table.update(cmdtable)
7701 table.update(cmdtable)
@@ -1,108 +1,126
1 # Gather code related to command dealing with configuration.
1 # Gather code related to command dealing with configuration.
2
2
3 from __future__ import annotations
3 from __future__ import annotations
4
4
5 import os
5 import os
6
6
7 from typing import Any, Dict, Optional
7 from typing import Any, Dict, Optional
8
8
9 from ..i18n import _
9 from ..i18n import _
10
10
11 from .. import (
11 from .. import (
12 cmdutil,
12 cmdutil,
13 error,
13 error,
14 requirements,
14 requirements,
15 ui as uimod,
15 ui as uimod,
16 util,
16 util,
17 vfs as vfsmod,
17 vfs as vfsmod,
18 )
18 )
19
19
20 from . import rcutil
20 from . import rcutil
21
21
22 EDIT_FLAG = 'edit'
22 EDIT_FLAG = 'edit'
23
23
24
24
25 # keep typing simple for now
25 # keep typing simple for now
26 ConfigLevelT = str
26 ConfigLevelT = str
27 LEVEL_USER = 'user' # "user" is the default level and never passed explicitly
27 LEVEL_USER = 'user' # "user" is the default level and never passed explicitly
28 LEVEL_LOCAL = 'local'
28 LEVEL_LOCAL = 'local'
29 LEVEL_GLOBAL = 'global'
29 LEVEL_GLOBAL = 'global'
30 LEVEL_SHARED = 'shared'
30 LEVEL_SHARED = 'shared'
31 LEVEL_NON_SHARED = 'non_shared'
31 LEVEL_NON_SHARED = 'non_shared'
32 EDIT_LEVELS = (
32 EDIT_LEVELS = (
33 LEVEL_USER,
33 LEVEL_USER,
34 LEVEL_LOCAL,
34 LEVEL_LOCAL,
35 LEVEL_GLOBAL,
35 LEVEL_GLOBAL,
36 LEVEL_SHARED,
36 LEVEL_SHARED,
37 LEVEL_NON_SHARED,
37 LEVEL_NON_SHARED,
38 )
38 )
39
39
40
40
41 def find_edit_level(
41 def find_edit_level(
42 ui: uimod.ui, repo, opts: Dict[str, Any]
42 ui: uimod.ui, repo, opts: Dict[str, Any]
43 ) -> Optional[ConfigLevelT]:
43 ) -> Optional[ConfigLevelT]:
44 """return the level we should edit, if any.
44 """return the level we should edit, if any.
45
45
46 Parse the command option to detect when an edit is requested, and if so the
46 Parse the command option to detect when an edit is requested, and if so the
47 configuration level we should edit.
47 configuration level we should edit.
48 """
48 """
49 if opts.get(EDIT_FLAG) or any(opts.get(o) for o in EDIT_LEVELS):
49 if opts.get(EDIT_FLAG) or any(opts.get(o) for o in EDIT_LEVELS):
50 cmdutil.check_at_most_one_arg(opts, *EDIT_LEVELS)
50 cmdutil.check_at_most_one_arg(opts, *EDIT_LEVELS)
51 for level in EDIT_LEVELS:
51 for level in EDIT_LEVELS:
52 if opts.get(level):
52 if opts.get(level):
53 return level
53 return level
54 return EDIT_LEVELS[0]
54 return EDIT_LEVELS[0]
55 return None
55 return None
56
56
57
57
58 def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None:
58 def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None:
59 """let the user edit configuration file for the given level"""
59 """let the user edit configuration file for the given level"""
60
60
61 if level == LEVEL_USER:
61 if level == LEVEL_USER:
62 paths = rcutil.userrcpath()
62 paths = rcutil.userrcpath()
63 elif level == LEVEL_GLOBAL:
63 elif level == LEVEL_GLOBAL:
64 paths = rcutil.systemrcpath()
64 paths = rcutil.systemrcpath()
65 elif level == LEVEL_LOCAL:
65 elif level == LEVEL_LOCAL:
66 if not repo:
66 if not repo:
67 raise error.InputError(_(b"can't use --local outside a repository"))
67 raise error.InputError(_(b"can't use --local outside a repository"))
68 paths = [repo.vfs.join(b'hgrc')]
68 paths = [repo.vfs.join(b'hgrc')]
69 elif level == LEVEL_NON_SHARED:
69 elif level == LEVEL_NON_SHARED:
70 paths = [repo.vfs.join(b'hgrc-not-shared')]
70 paths = [repo.vfs.join(b'hgrc-not-shared')]
71 elif level == LEVEL_SHARED:
71 elif level == LEVEL_SHARED:
72 if not repo.shared():
72 if not repo.shared():
73 raise error.InputError(
73 raise error.InputError(
74 _(b"repository is not shared; can't use --shared")
74 _(b"repository is not shared; can't use --shared")
75 )
75 )
76 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
76 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
77 raise error.InputError(
77 raise error.InputError(
78 _(
78 _(
79 b"share safe feature not enabled; "
79 b"share safe feature not enabled; "
80 b"unable to edit shared source repository config"
80 b"unable to edit shared source repository config"
81 )
81 )
82 )
82 )
83 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
83 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
84 else:
84 else:
85 msg = 'unknown config level: %s' % level
85 msg = 'unknown config level: %s' % level
86 raise error.ProgrammingError(msg)
86 raise error.ProgrammingError(msg)
87
87
88 for f in paths:
88 for f in paths:
89 if os.path.exists(f):
89 if os.path.exists(f):
90 break
90 break
91 else:
91 else:
92 if LEVEL_GLOBAL:
92 if LEVEL_GLOBAL:
93 samplehgrc = uimod.samplehgrcs[b'global']
93 samplehgrc = uimod.samplehgrcs[b'global']
94 elif LEVEL_LOCAL:
94 elif LEVEL_LOCAL:
95 samplehgrc = uimod.samplehgrcs[b'local']
95 samplehgrc = uimod.samplehgrcs[b'local']
96 else:
96 else:
97 samplehgrc = uimod.samplehgrcs[b'user']
97 samplehgrc = uimod.samplehgrcs[b'user']
98
98
99 f = paths[0]
99 f = paths[0]
100 util.writefile(f, util.tonativeeol(samplehgrc))
100 util.writefile(f, util.tonativeeol(samplehgrc))
101
101
102 editor = ui.geteditor()
102 editor = ui.geteditor()
103 ui.system(
103 ui.system(
104 b"%s \"%s\"" % (editor, f),
104 b"%s \"%s\"" % (editor, f),
105 onerr=error.InputError,
105 onerr=error.InputError,
106 errprefix=_(b"edit failed"),
106 errprefix=_(b"edit failed"),
107 blockedtag=b'config_edit',
107 blockedtag=b'config_edit',
108 )
108 )
109
110
111 def show_component(ui: uimod.ui, repo) -> None:
112 """show the component used to build the config
113
114 XXX this skip over various source and ignore the repository config, so it
115 XXX is probably useless old code.
116 """
117 for t, f in rcutil.rccomponents():
118 if t == b'path':
119 ui.debug(b'read config from: %s\n' % f)
120 elif t == b'resource':
121 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
122 elif t == b'items':
123 # Don't print anything for 'items'.
124 pass
125 else:
126 raise error.ProgrammingError(b'unknown rctype: %s' % t)
General Comments 0
You need to be logged in to leave comments. Login now